Compare commits

..

45 Commits

Author SHA1 Message Date
Óscar M. Lage 4033108d3d Add: Microposts, layout and config 2023-01-23 21:18:15 +01:00
Óscar M. Lage ca0a9adea1 Update: resources 2023-01-23 21:18:00 +01:00
Óscar M. Lage eb990ce1ee New post: Snowy fun with family 2023-01-23 21:17:44 +01:00
Óscar M. Lage 4dd7e2417f New post: benchmarking with sieve 2023-01-23 21:17:35 +01:00
Óscar M. Lage 68746f9cc7 Add: microposts 2023-01-23 21:17:11 +01:00
Óscar M. Lage 96650575f1 Fix: typos in "The Van" 2022-11-09 19:40:33 +01:00
Óscar M. Lage f4eed70168 Fix: footer links 2022-11-09 19:40:01 +01:00
Óscar M. Lage c2eb08c66f New post: The Van 2022-11-07 13:05:26 +01:00
Óscar M. Lage d6b6b1e9eb Update: about and index 2022-11-07 11:41:40 +01:00
Óscar M. Lage b848307f49 Add: new twitch section (wip) 2022-10-19 20:14:38 +02:00
Óscar M. Lage f911f0558f Imp: archive little improvement 2022-10-19 20:14:26 +02:00
Óscar M. Lage 0e4369d799 Imp: about improvement 2022-10-19 20:14:12 +02:00
Óscar M. Lage 675382e546 Fix: typo in the mailto reference 2022-10-19 19:34:28 +02:00
Óscar M. Lage 2111263b2b Upadte: Wikingo 2022-09-19 20:45:19 +02:00
Óscar M. Lage b2d973fd58 Update: post images resources 2022-09-19 20:44:59 +02:00
Óscar M. Lage 7542264e36 Update: about section 2022-09-19 20:44:33 +02:00
Óscar M. Lage d1a3aa21a9 New post: Summer 2022 2022-09-19 20:44:21 +02:00
Óscar M. Lage b13ce821c9 New post: Gardening and Cleaning 2022-09-19 20:44:04 +02:00
Óscar M. Lage edafa02d2d New post: Fediverse 2022-09-19 20:43:52 +02:00
Óscar M. Lage a69159700d New post: Blood donation 2022-09-19 20:43:39 +02:00
Segundo Fdez 102c3f328f Fix header text on home 2022-05-04 21:52:55 +02:00
Segundo Fdez 74f7bd599c Fix pre on ligth mode 2022-05-04 21:01:06 +02:00
Óscar M. Lage 90fe18f51c New post: Wikingo 2022-04-25 11:27:36 +02:00
Óscar M. Lage 28b30938f4 New post: Vim, mark task as done 2022-04-25 11:27:21 +02:00
Óscar M. Lage d72d1451ce New post: Vim, mark task done 2022-04-14 13:13:25 +02:00
Óscar M. Lage ce0c12efeb Update broken link 2022-04-06 21:23:37 +02:00
Óscar M. Lage 269b08bdb4 Add: New posts from the legacy blog 2022-04-06 21:17:47 +02:00
Óscar M. Lage 54468e24e3 Add: FlowerPower Sprint post 2022-04-06 20:33:10 +02:00
Óscar M. Lage 45f2aca784 Update texts 2022-04-06 20:32:42 +02:00
Óscar M. Lage 45a05ebb04 Update texts 2022-04-01 10:57:37 +02:00
Óscar M. Lage 5b79ac10de Update texts 2022-04-01 09:43:37 +02:00
Óscar M. Lage 64d48fcba8 Add: RSS link in head and footer
RSS [is shipped with Hugo](https://gohugo.io/templates/rss/), only need to be
added to the proper places (head and footer in my case).

Fixes #4
2022-04-01 09:41:55 +02:00
Óscar M. Lage 01d9c06d02 New post: 'Hola Hugo! 2022-03-31 21:03:58 +02:00
Óscar M. Lage def4b4aa47 Fix: Image meta should work now in the index page too
This fixes the image tag not working in the index page.

Fixes #3
2022-03-31 20:38:07 +02:00
Óscar M. Lage a41ab078dc Add: `make deploy` as alias of up, sync... 2022-03-31 20:21:17 +02:00
Óscar M. Lage 06ba4c5f49 Update: texts 2022-03-31 20:17:47 +02:00
Óscar M. Lage db849b86c3 Fix: now build command builds :) 2022-03-31 20:17:19 +02:00
Óscar M. Lage 7a8f03ddf9 Update: TODO 2022-03-31 20:17:05 +02:00
Óscar M. Lage 2cd0501b57 Update: some changes in make commands
- up/sync is now for syncing the stuff
- new `buildall` command to hard-copy the build result
2022-03-31 20:15:44 +02:00
Óscar M. Lage 2533b8617f Fix: typos 2022-03-31 08:07:57 +02:00
Óscar M. Lage efaedf2fd5 Update TODO 2022-03-31 00:30:31 +02:00
Óscar M. Lage 9cb56d9440 Update: TODO 2022-03-30 22:47:20 +02:00
Óscar M. Lage 07544a9f07 Add: avatars 2022-03-30 22:44:21 +02:00
Óscar M. Lage b156ae1483
Merge pull request #2 from oscarmlage/feature/oscar-theme
Feature/oscar theme
2022-03-30 22:42:02 +02:00
Óscar M. Lage eb462f6c61
Merge pull request #1 from oscarmlage/feature/oscar-theme
Feature/oscar theme
2022-03-24 10:12:55 +01:00
1467 changed files with 2720 additions and 61 deletions

View File

@ -12,8 +12,11 @@ bash:
shell: shell:
docker-compose -f docker-compose.yml run build shell docker-compose -f docker-compose.yml run build shell
up: deploy: up
sync: up
up: build
rsync -e ssh --progress --delete -lprtvvzog src/public/ me:/home/www/oscarmlage.com/www/
buildall: build
cp -r src/public/ me:/home/www/oscarmlage.com/www cp -r src/public/ me:/home/www/oscarmlage.com/www
sync:
rsync -e ssh --progress --delete -lprtvvzog src/public/ me:/home/www/oscarmlage.com/www/

View File

@ -20,6 +20,12 @@
- [x] Review pending texts (off-screen) - [x] Review pending texts (off-screen)
- [x] Index - [x] Index
- [x] About, Colophon, CV... - [x] About, Colophon, CV...
- [x] Add dotfiles to the resume
- [x] Add segun to the colophon
- [x] Take a look to the twitter-card/og for the index page
- [x] RSS + referencee it in header
- [ ] Tags not appearing in posts
- [ ] Add vim + productivity to "hobbies" or "tools" section
- [ ] General review + Clean some stuff here and there - [ ] General review + Clean some stuff here and there
- [ ] Some images contains a `<p>`, get rid of it. - [ ] Some images contains a `<p>`, get rid of it.
- Images with p in the post content (as it is html now) - Images with p in the post content (as it is html now)
@ -37,3 +43,4 @@
- [ ] Import some other posts from other years - [ ] Import some other posts from other years
- [ ] Support some thing like microposting (as bebu does) - [ ] Support some thing like microposting (as bebu does)
- [ ] Setup info? - [ ] Setup info?
- [ ] @adrianmg suggested webp optimization

View File

@ -5,6 +5,7 @@ services:
build: build:
# image: klakegg/hugo:0.88.0-ext-alpine # image: klakegg/hugo:0.88.0-ext-alpine
image: oscarmlage/hugo:0.88.0-ext-alpine image: oscarmlage/hugo:0.88.0-ext-alpine
command: build
volumes: volumes:
- "${PWD}/src:/src" - "${PWD}/src:/src"

View File

@ -0,0 +1,6 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
image:
---

View File

@ -33,13 +33,18 @@ menu:
title: "Posts" title: "Posts"
url: "/posts/" url: "/posts/"
weight: 10 weight: 10
- identifier: "microposts"
name: "Social"
title: "Social"
url: "/microposts/"
weight: 20
- identifier: "archive" - identifier: "archive"
name: "Archive" name: "Archive"
title: "Archive" title: "Archive"
url: "/archive/" url: "/archive/"
weight: 20 weight: 30
- identifier: "about" - identifier: "about"
name: "About" name: "About"
title: "About" title: "About"
url: "/about/" url: "/about/"
weight: 30 weight: 40

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

View File

@ -3,7 +3,5 @@ title: "Hero1"
date: 2022-02-28T22:25:30Z date: 2022-02-28T22:25:30Z
draft: false draft: false
image: avatar2.jpg image: avatar2.jpg
text: Welcome to my place. I love development - in general - techie world and to try new things. Hope you enjoy the content here! ❤️ ☕
--- ---
Welcome to my place. I love development - in general - techie world and try new things. Hope you enjoy the content here! ❤️ ☕

View File

@ -0,0 +1,14 @@
---
title: 20221010-1815
date: 2022-10-10 18:15:42 +00:00
draft: false
tags: [micropost]
image:
---
<p>This afternoon I had a meeting, my mate prettified a horrible string into a tabulated and perfectly aligned json in his shinny VSCode. </p><p>Immediately felt that I needed to get the same using my tools. Literally 4 mins later in my .vimrc:</p><p>:command Format :%!jq .<br />:command Unformat :%!jq -c .</p><p><a href="https://mastodon.bofhers.es/tags/vim" class="mention hashtag" rel="tag">#<span>vim</span></a> <a href="https://mastodon.bofhers.es/tags/neovim" class="mention hashtag" rel="tag">#<span>neovim</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@ -0,0 +1,14 @@
---
title: 20221020-1011
date: 2022-10-20 10:11:21 +00:00
draft: false
tags: [micropost]
image:
---
<p>Little pleasures of 127.0.0.2 &lt;aka the-new-place&gt; ❤️ <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

View File

@ -0,0 +1,14 @@
---
title: 20221023-2036
date: 2022-10-23 20:36:18 +00:00
draft: false
tags: [micropost]
image:
---
<p>My first Rubik ever. <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -0,0 +1,14 @@
---
title: 20221024-1906
date: 2022-10-24 19:06:56 +00:00
draft: false
tags: [micropost]
image:
---
<p>That feeling of being alive again! <a href="https://mastodon.bofhers.es/tags/irons" class="mention hashtag" rel="tag">#<span>irons</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

View File

@ -0,0 +1,14 @@
---
title: 20221029-1708
date: 2022-10-29 17:08:05 +00:00
draft: false
tags: [micropost]
image:
---
<p>On the road again <a href="https://mastodon.bofhers.es/tags/vancaciones" class="mention hashtag" rel="tag">#<span>vancaciones</span></a> <a href="https://mastodon.bofhers.es/tags/van" class="mention hashtag" rel="tag">#<span>van</span></a> <a href="https://mastodon.bofhers.es/tags/trip" class="mention hashtag" rel="tag">#<span>trip</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

View File

@ -0,0 +1,14 @@
---
title: 20221031-1701
date: 2022-10-31 17:01:40 +00:00
draft: false
tags: [micropost]
image:
---
<p>Todays backyard <a href="https://mastodon.bofhers.es/tags/van" class="mention hashtag" rel="tag">#<span>van</span></a> <a href="https://mastodon.bofhers.es/tags/trip" class="mention hashtag" rel="tag">#<span>trip</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

View File

@ -0,0 +1,11 @@
---
title: 20221107-1959
date: 2022-11-07 19:59:08 +00:00
draft: false
tags: [micropost]
image:
---
<p>Little summary from our instance in numbers (20221107):</p><p>🔘 Mastodon version 3.5.3<br />🔘 Active users: 35<br />🔘 Interactions: near 1k<br />🔘 Disk: 26Gb (90% are media_attachments)<br />🔘 DB: pg_dump recently baked is about 200Mb (50Mb gzipped)</p><p>My guess is that no big investment is needed - server - for a tiny number of users, but to be honest dunno what happens if it grows as it is doing in some instances that have experienced problems lately.</p><p><a href="https://mastodon.bofhers.es/tags/mastodon" class="mention hashtag" rel="tag">#<span>mastodon</span></a> <a href="https://mastodon.bofhers.es/tags/admin" class="mention hashtag" rel="tag">#<span>admin</span></a> <a href="https://mastodon.bofhers.es/tags/sys" class="mention hashtag" rel="tag">#<span>sys</span></a> <a href="https://mastodon.bofhers.es/tags/stats" class="mention hashtag" rel="tag">#<span>stats</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20221108-0958
date: 2022-11-08 09:58:06 +00:00
draft: false
tags: [micropost]
image:
---
<p>My mate today is <a href="https://twitch.tv/usirin" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="">twitch.tv/usirin</span><span class="invisible"></span></a></p><p>I don&#39;t understand a word of Turkish but you can&#39;t imagine how it helps to see someone else working -with similar tools- same time.</p><p>Remote work is not all about pros and pleasures, it has cons too, such as being alone most of the time.</p><p><a href="https://mastodon.bofhers.es/tags/remotework" class="mention hashtag" rel="tag">#<span>remotework</span></a> <a href="https://mastodon.bofhers.es/tags/dev" class="mention hashtag" rel="tag">#<span>dev</span></a> <a href="https://mastodon.bofhers.es/tags/loneliness" class="mention hashtag" rel="tag">#<span>loneliness</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20221108-1632
date: 2022-11-08 16:32:10 +00:00
draft: false
tags: [micropost]
image:
---
<p>Some words about our little <a href="https://mastodon.bofhers.es/tags/community" class="mention hashtag" rel="tag">#<span>community</span></a>...</p><p>In the beginning I was curious about the challenge to host a <a href="https://mastodon.bofhers.es/tags/mastodon" class="mention hashtag" rel="tag">#<span>mastodon</span></a> instance, then I was a bit worried because of the data responsibility and everything. Now, after chatting and dealing with little problems here and there, I must say I&#39;m glad I did that.</p><p>And proud, because <a href="https://mastodon.bofhers.es/tags/bofhers" class="mention hashtag" rel="tag">#<span>bofhers</span></a> understand that this is a hobby and afaik they understand what <a href="https://mastodon.bofhers.es/tags/fediverse" class="mention hashtag" rel="tag">#<span>fediverse</span></a> + decentralized means + they&#39;re offering hand when some help is needed.</p><p>❤️ </p><p><a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

View File

@ -0,0 +1,14 @@
---
title: 20221108-1945
date: 2022-11-08 19:45:45 +00:00
draft: false
tags: [micropost]
image:
---
<p>Tokyo Night seems a good choice to move away from Gruvbox. I have no problem with <a href="https://mastodon.bofhers.es/tags/gruvbox" class="mention hashtag" rel="tag">#<span>gruvbox</span></a> but feel like I need a change, I&#39;m tired of the orange-ranges and seems like blue tones fit better for now. Will see.</p><p><a href="https://mastodon.bofhers.es/tags/vim" class="mention hashtag" rel="tag">#<span>vim</span></a> <a href="https://mastodon.bofhers.es/tags/neovim" class="mention hashtag" rel="tag">#<span>neovim</span></a> <a href="https://mastodon.bofhers.es/tags/colorscheme" class="mention hashtag" rel="tag">#<span>colorscheme</span></a> <a href="https://mastodon.bofhers.es/tags/themes" class="mention hashtag" rel="tag">#<span>themes</span></a> <a href="https://mastodon.bofhers.es/tags/tokyonight" class="mention hashtag" rel="tag">#<span>tokyonight</span></a> <a href="https://mastodon.bofhers.es/tags/dev" class="mention hashtag" rel="tag">#<span>dev</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

View File

@ -0,0 +1,11 @@
---
title: 20221108-2326
date: 2022-11-08 23:26:26 +00:00
draft: false
tags: [micropost]
image:
---
<p>Thats it for today. Let me just write down the <a href="https://mastodon.bofhers.es/tags/crates" class="mention hashtag" rel="tag">#<span>crates</span></a> I&#39;m using in order to properly read the <a href="https://mastodon.bofhers.es/tags/rss" class="mention hashtag" rel="tag">#<span>rss</span></a> with this <a href="https://mastodon.bofhers.es/tags/rust" class="mention hashtag" rel="tag">#<span>rust</span></a> 🦀 thing:</p><p>- 🔘 <a href="https://docs.rs/rss/latest/rss/" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="">docs.rs/rss/latest/rss/</span><span class="invisible"></span></a><br />- 🔘 <a href="https://docs.rs/reqwest/latest/reqwest/blocking/" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="ellipsis">docs.rs/reqwest/latest/reqwest</span><span class="invisible">/blocking/</span></a></p><p>As today it was so and so, maybe tomorrow I can move forward in a more success way, I&#39;m exhausted. <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20221109-1857
date: 2022-11-09 18:57:35 +00:00
draft: false
tags: [micropost]
image:
---
<p>After some tries with <a href="https://mastodon.bofhers.es/tags/golang" class="mention hashtag" rel="tag">#<span>golang</span></a> and <a href="https://mastodon.bofhers.es/tags/rust" class="mention hashtag" rel="tag">#<span>rust</span></a>, I&#39;ve opted to have some fun with <a href="https://mastodon.bofhers.es/tags/python" class="mention hashtag" rel="tag">#<span>python</span></a> too.</p><p>And there it is, the script that picks all the &quot;<a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a>&quot; toots and converts them into the proper markdown thing for my <a href="https://mastodon.bofhers.es/tags/hugo" class="mention hashtag" rel="tag">#<span>hugo</span></a> web, media elements are also included.</p><p>Not sure if it can be helpful out there but...</p><p><a href="https://gist.github.com/oscarmlage/bfe9adabad3c2679cb00935f3922ad96" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="ellipsis">gist.github.com/oscarmlage/bfe</span><span class="invisible">9adabad3c2679cb00935f3922ad96</span></a></p><p>note: it&#39;s a pity that <a href="https://mastodon.bofhers.es/tags/gitea" class="mention hashtag" rel="tag">#<span>gitea</span></a> doesn&#39;t have a snippets section.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -0,0 +1,17 @@
---
title: 20221110-1944
date: 2022-11-10 19:44:52 +00:00
draft: false
tags: [micropost]
image:
---
<p>The other day a friend of mine asked if I&#39;d noted some problem or high load in our little <a href="https://mastodon.bofhers.es/tags/mastodon" class="mention hashtag" rel="tag">#<span>mastodon</span></a> instance. I said no, but then I took a look at <a href="https://mastodon.bofhers.es/tags/sidekiq" class="mention hashtag" rel="tag">#<span>sidekiq</span></a>, and it seemed that -definitely- something was occurring in the background.</p><p>This instance has been installed on 2022-05-26 in a little server, on 2022-09-09 it was migrated to v.3.5.3 and on 2022-09-24 I&#39;ve bought a new -bigger- server.</p><p>- Media storage: 30Gb.<br />- Postgres storage: 400Mb.<br />- Redis storage: 20Mb.</p><p>That&#39;s the toy. <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

View File

@ -0,0 +1,14 @@
---
title: 20221112-2041
date: 2022-11-12 20:41:55 +00:00
draft: false
tags: [micropost]
image:
---
<p>November 12, 2022. Walking wearing t-shirt at night. Unbelievable.</p><p><a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

View File

@ -0,0 +1,11 @@
---
title: 20221112-2146
date: 2022-11-12 21:46:50 +00:00
draft: false
tags: [micropost]
image:
---
<p>The <a href="https://mastodon.bofhers.es/tags/rust" class="mention hashtag" rel="tag">#<span>rust</span></a> solution with buggy / outdated <a href="https://mastodon.bofhers.es/tags/crates" class="mention hashtag" rel="tag">#<span>crates</span></a>: </p><p>Package versions cant be deleted, they can only be yanked. A yanked package can still be used if it is in your projects lock file so existing projects will not break.</p><p>But new projects can not use a buggy version, <a href="https://mastodon.bofhers.es/tags/cargo" class="mention hashtag" rel="tag">#<span>cargo</span></a> will display an error and advise an upgrade. Backwards compatibility without compromising new features.</p><p>🦀 <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p><p><a href="https://youtu.be/oY0XwMOSzq4" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="">youtu.be/oY0XwMOSzq4</span><span class="invisible"></span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20221115-1150
date: 2022-11-15 11:50:10 +00:00
draft: false
tags: [micropost]
image:
---
<p>In software engineering, <a href="https://mastodon.bofhers.es/tags/rubberduck" class="mention hashtag" rel="tag">#<span>rubberduck</span></a> debugging (or <a href="https://mastodon.bofhers.es/tags/rubberducking" class="mention hashtag" rel="tag">#<span>rubberducking</span></a>) is a method of debugging code by articulating a problem in spoken or written natural language.</p><p>The name is a reference to a story in the book «The Pragmatic Programmer» in which a programmer would carry around a rubber duck and debug their code by forcing themselves to explain it, line-by-line, to the duck.</p><p>🔈🦆 <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20221116-1046
date: 2022-11-16 10:46:31 +00:00
draft: false
tags: [micropost]
image:
---
<p>I think I&#39;ve said it before, but I&#39;m totally **in love** with <a href="https://mastodon.bofhers.es/tags/gitlab" class="mention hashtag" rel="tag">#<span>gitlab</span></a> <a href="https://mastodon.bofhers.es/tags/cicd" class="mention hashtag" rel="tag">#<span>cicd</span></a> procedure, even being a yml-based thing</p><p>❤️ <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20221116-1124
date: 2022-11-16 11:24:38 +00:00
draft: false
tags: [micropost]
image:
---
<p>I&#39;ve read you can use <a href="https://mastodon.bofhers.es/tags/cicd" class="mention hashtag" rel="tag">#<span>cicd</span></a> with <a href="https://mastodon.bofhers.es/tags/gitea" class="mention hashtag" rel="tag">#<span>gitea</span></a> too via <a href="https://mastodon.bofhers.es/tags/drone" class="mention hashtag" rel="tag">#<span>drone</span></a> (and also <a href="https://mastodon.bofhers.es/tags/jenkins" class="mention hashtag" rel="tag">#<span>jenkins</span></a> works). It may probably be worth giving it a try.</p><p><a href="https://dev.to/ruanbekker/self-hosted-cicd-with-gitea-and-drone-ci-200l" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="ellipsis">dev.to/ruanbekker/self-hosted-</span><span class="invisible">cicd-with-gitea-and-drone-ci-200l</span></a></p><p><a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

View File

@ -0,0 +1,14 @@
---
title: 20221117-1034
date: 2022-11-17 10:34:33 +00:00
draft: false
tags: [micropost]
image:
---
<p>Boost morning! <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

View File

@ -0,0 +1,11 @@
---
title: 20221117-2106
date: 2022-11-17 21:06:44 +00:00
draft: false
tags: [micropost]
image:
---
<p>I had a little whim, wanted to import all the toots from <a href="https://mastodon.bofhers.es/tags/mastodon" class="mention hashtag" rel="tag">#<span>mastodon</span></a> tagged as <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a> in my web (a static site generated by <a href="https://mastodon.bofhers.es/tags/hugo" class="mention hashtag" rel="tag">#<span>hugo</span></a> <a href="https://mastodon.bofhers.es/tags/go" class="mention hashtag" rel="tag">#<span>go</span></a> <a href="https://mastodon.bofhers.es/tags/golang" class="mention hashtag" rel="tag">#<span>golang</span></a>).</p><p>It was a perfect excuse to practice a bit of <a href="https://mastodon.bofhers.es/tags/rust" class="mention hashtag" rel="tag">#<span>rust</span></a> and enjoy all the little lessons I&#39;ve learned.</p><p>I doubt it will be helpful to anyone but just in case I&#39;ve published the repo:</p><p><a href="https://git.oscarmlage.com/oscarmlage/masto-rss" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="ellipsis">git.oscarmlage.com/oscarmlage/</span><span class="invisible">masto-rss</span></a></p><p>I know there is quite room for improvement but feel free to give some feedback ;)</p><p>🦀</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

View File

@ -0,0 +1,14 @@
---
title: 20221118-0954
date: 2022-11-18 09:54:54 +00:00
draft: false
tags: [micropost]
image:
---
<p>Morning vibes, Friday vibes... 127.0.0.2 gives me so nice pictures :) <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

View File

@ -0,0 +1,11 @@
---
title: 20221118-2224
date: 2022-11-18 22:24:02 +00:00
draft: false
tags: [micropost]
image:
---
<p>From time to time I get an error like this trying to execute a <a href="https://mastodon.bofhers.es/tags/make" class="mention hashtag" rel="tag">#<span>make</span></a> custom command:</p><p>$ make backup<br />make: &#39;backup&#39; is up to date</p><p>I thought that something was wrong with that backup command but it seems the error is because there is a `backup/` directory sibling to the `Makefile`.</p><p>If you change the directory name or the command name, the error is gone. Weird, indeed.</p><p><a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a> <a href="https://mastodon.bofhers.es/tags/makefile" class="mention hashtag" rel="tag">#<span>makefile</span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20221124-1619
date: 2022-11-24 16:19:16 +00:00
draft: false
tags: [micropost]
image:
---
<p>Maybe your <a href="https://mastodon.bofhers.es/tags/mastodon" class="mention hashtag" rel="tag">#<span>mastodon</span></a> instance is playing tricks while uploading GIF files (dunno why it&#39;s not happening with other image formats):</p><p>413 Entity too large.</p><p>In our case this is a dockerized instance with `jwilder/nginx-proxy` in the middle, the fix is easy:</p><p>1. Use a nginx config volume: `./data/conf:/etc/nginx/conf.d`<br />2. create a `client_max_body_size.conf`file in the volume with &quot;client_max_body_size 100m;&quot; inside.<br />3. Restart the instance</p><p><a href="https://mastodon.bofhers.es/tags/docker" class="mention hashtag" rel="tag">#<span>docker</span></a> <a href="https://mastodon.bofhers.es/tags/nginx" class="mention hashtag" rel="tag">#<span>nginx</span></a> <a href="https://mastodon.bofhers.es/tags/jwilder" class="mention hashtag" rel="tag">#<span>jwilder</span></a> <a href="https://mastodon.bofhers.es/tags/nginxproxy" class="mention hashtag" rel="tag">#<span>nginxproxy</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a> <a href="https://mastodon.bofhers.es/tags/repost" class="mention hashtag" rel="tag">#<span>repost</span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20221126-1153
date: 2022-11-26 11:53:00 +00:00
draft: false
tags: [micropost]
image:
---
<p>Day in Developer&#39;s Life: Mugcake in 2 mins</p><p><a href="https://youtu.be/mhjnttmri0E" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="">youtu.be/mhjnttmri0E</span><span class="invisible"></span></a></p><p>Follow me for more recipes 🤣 <br /><a href="https://mastodon.bofhers.es/tags/youtube" class="mention hashtag" rel="tag">#<span>youtube</span></a> <a href="https://mastodon.bofhers.es/tags/video" class="mention hashtag" rel="tag">#<span>video</span></a> <a href="https://mastodon.bofhers.es/tags/short" class="mention hashtag" rel="tag">#<span>short</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20221202-0924
date: 2022-12-02 09:24:59 +00:00
draft: false
tags: [micropost]
image:
---
<p>One of the first things I do in my working morning routine is to open twitch and start watching someone else working (to feel some company). Today my &quot;cowork mate&quot; is <a href="https://twitch.tv/ppy" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="">twitch.tv/ppy</span><span class="invisible"></span></a>.</p><p>Man, I love to see the way he works!</p><p><a href="https://mastodon.bofhers.es/tags/cowork" class="mention hashtag" rel="tag">#<span>cowork</span></a> <a href="https://mastodon.bofhers.es/tags/remotework" class="mention hashtag" rel="tag">#<span>remotework</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 KiB

View File

@ -0,0 +1,14 @@
---
title: 20221202-1236
date: 2022-12-02 12:36:28 +00:00
draft: false
tags: [micropost]
image:
---
<p>There is this kind of tradition with a group of friends that you gift each other anonymously a low-budget thing. I think it&#39;s called Secret Santa (we call it &quot;amigo invisible&quot; in .es).</p><p>Well, I received mine this morning, and the game is over, my Secret Santa won the game!</p><p><a href="https://mastodon.bofhers.es/tags/bofhers" class="mention hashtag" rel="tag">#<span>bofhers</span></a> <a href="https://mastodon.bofhers.es/tags/lart" class="mention hashtag" rel="tag">#<span>lart</span></a> <a href="https://mastodon.bofhers.es/tags/gift" class="mention hashtag" rel="tag">#<span>gift</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
{{< gallery match="gallery/*" sortOrder="asc"
rowHeight="150" margins="5" thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur" embedPreview="true" >}}

View File

@ -0,0 +1,11 @@
---
title: 20221229-1935
date: 2022-12-29 19:35:32 +00:00
draft: false
tags: [micropost]
image:
---
<p>Wrote a blog post - and had lot of fun - about benchmarking an API endpoint with different stacks:</p><p>🔘 golang+gorm+custom-router<br />🔘 golang+gorm+echo<br />🔘 golang+gorm+gin<br />🔘 php+laravel<br />🔘 php+vanilla-mysqli_*</p><p><a href="https://oscarmlage.com/posts/benchmarking-with-siege/" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="ellipsis">oscarmlage.com/posts/benchmark</span><span class="invisible">ing-with-siege/</span></a></p><p><a href="https://mastodon.bofhers.es/tags/go" class="mention hashtag" rel="tag">#<span>go</span></a> <a href="https://mastodon.bofhers.es/tags/golang" class="mention hashtag" rel="tag">#<span>golang</span></a> <a href="https://mastodon.bofhers.es/tags/gorm" class="mention hashtag" rel="tag">#<span>gorm</span></a> <a href="https://mastodon.bofhers.es/tags/gingonic" class="mention hashtag" rel="tag">#<span>gingonic</span></a> <a href="https://mastodon.bofhers.es/tags/gin" class="mention hashtag" rel="tag">#<span>gin</span></a> <a href="https://mastodon.bofhers.es/tags/echoserver" class="mention hashtag" rel="tag">#<span>echoserver</span></a> <a href="https://mastodon.bofhers.es/tags/echo" class="mention hashtag" rel="tag">#<span>echo</span></a> <a href="https://mastodon.bofhers.es/tags/php" class="mention hashtag" rel="tag">#<span>php</span></a> <a href="https://mastodon.bofhers.es/tags/laravel" class="mention hashtag" rel="tag">#<span>laravel</span></a> <a href="https://mastodon.bofhers.es/tags/mysql" class="mention hashtag" rel="tag">#<span>mysql</span></a> <a href="https://mastodon.bofhers.es/tags/blog" class="mention hashtag" rel="tag">#<span>blog</span></a> <a href="https://mastodon.bofhers.es/tags/post" class="mention hashtag" rel="tag">#<span>post</span></a> <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

View File

@ -0,0 +1,11 @@
---
title: 20230112-1101
date: 2023-01-12 11:01:35 +00:00
draft: false
tags: [micropost]
image:
---
<p>I&#39;m nearly in love with <a href="https://mastodon.bofhers.es/tags/go" class="mention hashtag" rel="tag">#<span>go</span></a> + <a href="https://mastodon.bofhers.es/tags/echo" class="mention hashtag" rel="tag">#<span>echo</span></a> + <a href="https://mastodon.bofhers.es/tags/gorm" class="mention hashtag" rel="tag">#<span>gorm</span></a> + <a href="https://mastodon.bofhers.es/tags/testify" class="mention hashtag" rel="tag">#<span>testify</span></a> + <a href="https://mastodon.bofhers.es/tags/fresh" class="mention hashtag" rel="tag">#<span>fresh</span></a>. Trying now to upgrade fresh to <a href="https://mastodon.bofhers.es/tags/air" class="mention hashtag" rel="tag">#<span>air</span></a> and add <a href="https://mastodon.bofhers.es/tags/delve" class="mention hashtag" rel="tag">#<span>delve</span></a> to the equation. As a side note, the stack seems more complicated to set if you use containers.</p><p><a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>

View File

@ -0,0 +1,24 @@
---
title: "Apache: Alta carga de CPU"
date: 2011-08-09T10:27:52Z
draft: false
tags: [ "sysadmin" ]
image:
---
<p>
Llevo desde el fin de semana con la mosca detr&aacute;s de la oreja. Uno de los servidores que administro ha visto incrementada de forma inexperada su carga media de CPU sin motivo aparente. Donde el <em>load average</em> normal de 1 minuto variaba entre <em>0.40</em> y <em>0.80</em> de repente supon&iacute;a cargas tan elevadas como <em>60</em> o <em>100</em> unidades.</p>
<p>
En esos momentos puntuales que llegaban a dejar la m&aacute;quina <em>zombie</em> el proceso que abarcaba un consumo de entre el <em>60%</em> y el <em>90%</em> de CPU era <em>apache2</em>. Intrigante que ni <em>error.log</em> ni <em>slow-queries.log</em> de MySQL (lo que normalmente suele ser cuello de botella) dieran ninguna pista.<!--more--></p>
<p>
<em>Analytics</em> tampoco dec&iacute;a nada de un aumento considerable de visitas -m&aacute;s bien al contrario- y el resto de herramientas de monitorizaci&oacute;n parec&iacute;an c&oacute;mplices del problema (&iexcl;tener <em>tools</em> para &eacute;sto!).</p>
<p>
En un alarde de desesperaci&oacute;n y viendo m&aacute;s o menos por d&oacute;nde pod&iacute;an venir los tiros -a trav&eacute;s del m&eacute;todo de <em>prueba y error</em>- localic&eacute; el <em>VirtualHost</em> que estaba dando problemas, un c&oacute;digo no auditado y afamado por su ausente optimizaci&oacute;n. Vamos que ya ten&iacute;a precedentes, aunque ninguno de esta &iacute;ndole.</p>
<p>
Despu&eacute;s de desactivar distintas partes del dominio en m&aacute;s pruebas esperando focalizar el error en alg&uacute;n script concreto, la conclusi&oacute;n es que ten&iacute;a que ser algo que se inclu&iacute;a en todos los archivos, algo com&uacute;n a toda la web. As&iacute; que miramos los <em>includes</em> comunes (si, PHP) y llegamos a la conclusi&oacute;n de que era <strong>problema de sesiones</strong>, sin exculpar al programador.</p>
<p>
Una de las primeras acciones de todos los scripts es definir el tiempo de sesi&oacute;n a <strong>3 d&iacute;as</strong>, definir el directorio donde se guardar&aacute;n los archivos de sesi&oacute;n y arrancar la sesi&oacute;n. Probablemente el programador no esperaba tener <em>60k</em> visitas y m&aacute;s de <em>200k</em> p&aacute;ginas vistas en los 3 d&iacute;as que dura cada sesi&oacute;n, pero est&aacute; claro que para <em>apache2</em> supon&iacute;a un problema el acceso de lectura/escritura a un mismo directorio con m&aacute;s de <em>90k</em> archivos.</p>
<p>
La soluci&oacute;n inicial -a falta de m&aacute;s tiempo para cambiar el sistema de sesiones a <em>memcache</em>, <em>Redis</em> o cualquier otra soluci&oacute;n basada en RAM- era sencilla, reducir el tiempo de sesi&oacute;n, vaciar el directorio donde se guardan las sesiones, comprobar de nuevo el <em>load average</em> durante un intervalo representativo y una tarea programada que monitorice el contenido de ese directorio. Despu&eacute;s de todo la carga se ha vuelto a estabilizar entre <em>0.30</em> y <em>0.40</em>.</p>
<p>
No s&eacute; si estoy para moralejas porque la soluci&oacute;n es temporal, pero como <a href="http://twitter.com/#!/r0sk/status/100688297642311681">lo prometido es deuda</a> me gustar&iacute;a terminar esta anotaci&oacute;n advirtiendo a todo el mundo sobre la fiabilidad del c&oacute;digo no auditado, el uso moderado de las sesiones y las endorfinas que libera uno cuando consigue resolver algo <em>&quot;as&iacute;&quot;</em>.</p>

View File

@ -0,0 +1,54 @@
---
title: "Apache + Squid + Nginx"
date: 2011-10-28T23:50:34Z
draft: false
tags: [ ]
image:
---
<p>
&iexcl;Menuda combinaci&oacute;n!. A decir verdad empec&eacute; jugando un poco con el maldito <em>slowloris</em> y al final acab&eacute; montando este batiburrillo de servidores, primero para <em>paliar</em> el efecto del dichoso gusano y segundo para preparar el servidor para la inminente nueva versi&oacute;n del blog - <em>que me gustar&iacute;a estrenar con el d&eacute;cimo aniversario de este humilde rinconcito</em> -.</p>
<p>
En un esquema inicial anal&oacute;gico de esos que tantos nos gustan podemos ver la pirula (pido perd&oacute;n de antemano por la calidad de la foto):<!--more--></p>
<p style="text-align: center;">
<img alt="" src="gallery/apache-squid-nginx.jpg" style="width: 300px; height: 305px;" /></p>
<p>
Probablemente no sea necesario tener 3 servidores para este entorno, seguro que puedo poner a escuchar Nginx en el puerto 80 y redirigir todo el tr&aacute;fico din&aacute;mico al 81 a la vez que responde al tr&aacute;fico est&aacute;tico de ciertos subdominios (static*) de forma autom&aacute;tica y en la misma instancia. Pero ten&iacute;a la tarde libre y me apetec&iacute;a probar una configuraci&oacute;n <em>rara</em> con Squid.</p>
<p>
<strong>Apache</strong></p>
<p>
La configuraci&oacute;n de Apache es de lo m&aacute;s sencilla, lo &uacute;nico que he hecho ha sido ponerlo a escuchar en el puerto 81 por defecto, y a todos sus <em>Virtualhosts</em> tambi&eacute;n. No hab&iacute;a mucho m&aacute;s que tocar puesto que ya ten&iacute;a el <em>mod_php</em> y todas las dependencias instaladas.</p>
<p>
<strong>Nginx</strong></p>
<p>
Nunca hab&iacute;a jugado con &eacute;l y a primera vista me gust&oacute; la sencillez de sus archivos de configuraci&oacute;n. Tampoco ten&iacute;a que hacer gran cosa, ponerlo a escuchar en el puerto 82 y poco m&aacute;s puesto que s&oacute;lo servir&iacute;a contenido est&aacute;tico. Cre&eacute; los <em>Virtualhosts</em> que atender&iacute;an las peticiones est&aacute;ticas, los activ&eacute; v&iacute;a enlace simb&oacute;lico a <em>sites-enabled</em> y poco m&aacute;s. La configuraci&oacute;n de un <em>Virtualhost</em> cualquiera:</p>
```
server {
listen 82;
server_name static.dominio.com;
root /home/www/dominio/sd/static/;
autoindex on;
}
```
<p>
<strong>Squid</strong></p>
<p>
Aqu&iacute; vino la diversi&oacute;n, &iquest;c&oacute;mo decirle a Squid que balanceara el tr&aacute;fico din&aacute;mico al puerto 81 y el est&aacute;tico al puerto 82?. Despu&eacute;s de leer la documentaci&oacute;n y hacer varias pruebas con <em>cache_peer</em>,&nbsp; y <em>cache_peer_domain</em> he llegado a la conclusi&oacute;n que la configuraci&oacute;n &quot;<em>buena</em>&quot; es la siguiente:</p>
```
cache_peer ip parent 81 0 no-query originserver name=server_1
cache_peer_domain server_1 dominio.com www.dominio.com
cache_peer ip parent 82 0 no-query originserver name=server_2
cache_peer_domain server_2 static.dominio.com
```
<p>
Como se puede ver, habr&iacute;a que cambiar <em>ip</em> por la ip p&uacute;blica correspondiente y los <em>fqdn</em> por los reales.</p>
<p>
<strong>Conclusi&oacute;n</strong></p>
<p>
He pasado una tarde agradable en compa&ntilde;&iacute;a de mis amigos los servidores web. No, en serio, al final he conseguido reproducir el escenario que me hab&iacute;a propuesto, (a&uacute;n sabiendo que se podr&iacute;a mejorar), he frenado los sockets incompletos de Apache y he preparado el servidor para servir est&aacute;ticos de forma independiente del contenido din&aacute;mico (que en breve cambiar&aacute; de PHP a Python + Django).</p>
<p>
No ha estado mal :).</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View File

@ -0,0 +1,33 @@
---
title: "Bash shellshock bug update: loving Fabric"
date: 2014-09-26T08:36:17Z
draft: false
tags: [ ]
image: shellshock.jpg
---
<p>When you wake up in the morning with a new like the <a href="http://www.troyhunt.com/2014/09/everything-you-need-to-know-about.html">bash shellshock bug</a> you should get away your lazy part and update all your servers to new patched version. This is ssh every single server, check the vulnerability, update the package, check again that all is ok and move on to next host.</p>
<p>If you have tons of servers the task becomes tedious. To get a bit of fun you can choose to develop a <a href="http://www.fabfile.org/">Fabric</a> module that makes the job instead of you. The fun:</p>
```
def make_me_a_bashandwich():
puts(red('Checking bash vulnerability'))
out = sudo("env x='() { :;}; echo vulnerable' bash -c 'echo this is a test'")
if "vulnerable" in out:
puts(red('Vulnerable'))
puts(red('Updating bash'))
sudo('apt-get update')
sudo('apt-get install --only-upgrade %s' % package)
else:
puts(green('OK'))
```
<p>Your only job is to run that piece of code in all your servers and take a deep look to the screen:</p>
```
$ fab -H server1,server2,server3 -u root make_me_a_bashandwich
```
<p><img style="display: block; margin-left: auto; margin-right: auto; width: 100%; height: auto;" src="gallery/bash-shellshock.png" alt="" /></p>
<p>In my humble opinion, it's more fun than the old way, isn't it?</p>
<p><span>Image credit: <em>Robert Graham</em>,&nbsp;</span><a href="https://twitter.com/ErrataRob/status/514839781881032705" target="_blank">Twitter</a>.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

View File

@ -0,0 +1,41 @@
---
title: "Benchmarking with Siege"
date: 2022-12-29T18:28:43Z
draft: false
tags: []
image:
---
If you ask me, I enjoy starting a new project, that fresh feeling during the first steps is usually becoming into a not-so-fresh thing with time. Life is so :).
In this concrete case, we're talking about an API, I needed to research and make some benchmarking work to take the best decision possible for the stack. It needs to be as fast as we can, so we can take advantage of some tools like `ab` or `siege` to measure some kinds of requests and scenarios.
With those tools in one hand and some languages in the other (`go-lang` and `php` mainly, in fact, the benchmark would be go-lang using different libraries but I was curious about a compiled language vs the fastest interpreted one I know so I added some php code), let's start having fun!.
All the tests were done in the same machine (macbook pro intel i9-9980hk) + docker containers + a dockerized mysql. The API endpoint makes a couple of SQL queries to return about 50 rows of data from a table, the response is being `jsonized`. There is no auth and no more logic steps, just an endpoint that makes a sql query and returns the data as json.
- Go-Lang + [Gorm](https://gorm.io) + Custom Router: the custom router uses the golang stdlib `"net/http"` to serve GET petitions.
- Go-Lang + [Gorm](https://gorm.io) + [Echo Server](https://echo.labstack.com).
- Go-Lang + [Gorm](https://gorm.io) + [Gin](https://github.com/gin-gonic/gin).
- Laravel + DB raw: as Laravel was the slowest, decided to use raw sql instead Eloquent to balance a bit the results :P, queries were done with `DB::Select()`.
- PHP "vanilla": some memories came to my mind using `mysqli_connect()`, `mysqli_query()`, and `mysqli_fetch_array()`.
I've run `siege` 3 times in different scenarios and calculated the average:
- 100 requests, only 1 concurrent
- 100 requests, 2 concurrents (50x2)
- 100 requests, 5 concurrents (20x5)
- 100 requests, 10 concurrents (10x10)
- 1000 requests, 10 concurrents (100x10)
- 10000 requests, 100 concurrents (100x100)
- Max requests in 30 seconds, 10 concurrents
- Max requests in 30 seconds, 100 concurrents
- Max requests in 30 seconds, 150 concurrents: I got some errors here, so it doesn't matter for the graphics
And the result is quite interesting:
{{< gallery match="gallery/*" sortOrder="asc" rowHeight="150" margins="5" thumbnailResizeOptions="752x436 q90 Lanczos" previewType="blur" embedPreview="true" >}}
In this benchmark **Go+Gorm+Echo** is the clear winner, closely followed by **Go+Gorm+Gin**. About PHP, dunno if I did something wrong but there is a lot of difference between vanilla PHP (the results are kinda acceptable) and Laravel, still dunno why.
I had so much fun with this "exercise".

View File

@ -0,0 +1,15 @@
---
title: "Blood Donation"
date: 2022-05-03T07:46:40Z
draft: false
tags: []
image:
---
I've always wanted to contribute -in a way- to help others and years ago something happened that I made a promise to myself to donate blood as soon as I could. As time went by I hadn't made it due lack of time or a kind of internal afraid and I was a bit angry with myself. Even had called several times in order to arrange a visit but in the end it never happened.
The other day had to go to the hospital and forced myself to pay a visit to the Donor Unity. A friendly nurse attended me and explained all the proccess, I bet she noticed that I was a bit nervous because she kept talking all the time, during the interview, extraction and after that, thanking me for being there when really I was the one grateful of being treated in such a nice way.
Yesterday I received a totally unexpected SMS saying that three patients could be transfused thanks to my donation. I mean, I knew what the blood was for, but this kind of «gamification» thing... wow!.
I've already set a task in the calendar every 3 months (the time you should wait between donations) in order to make it a habit. If you're in doubt - as I was for years- please, don't be afraid and make it happen, you won't regret it!.

View File

@ -0,0 +1,51 @@
---
title: "Cambiar kernel en ovh con grub (nfs)"
date: 2013-03-11T07:59:44Z
draft: false
tags: [ ]
image:
---
<p>El principal problema que existe para montar un servidor NFS en&nbsp;<span class="search_hit">OVH</span>&nbsp;es que los kernels que habilitan por defecto (<span class="search_hit">OVH</span>&nbsp;+ grsec), adem&aacute;s de venir con grsec como su propia descripci&oacute;n indica, no tienen soporte para instalar m&oacute;dulos de&nbsp;<span class="search_hit">kernel</span>. De forma que al intentar instalar el m&oacute;dulo para NFS nos dar&aacute; un fant&aacute;stico y maravilloso error. Por defecto tenemos el siguiente escenario:</p>
```
# uname -a
Linux ns302399.ovh.net 3.2.13-grsec-xxxx-grs-ipv6-64 #1 SMP Thu Mar 29 09:48:59 UTC 2012 x86_64 GNU/Linux
```
<p>As&iacute; que no queda otra que reemplazar el&nbsp;<span class="search_hit">kernel</span>&nbsp;por uno que ya lleve el m&oacute;dulo de nfs&nbsp;<em>builtin. </em>Llegados a este punto tenemos varias opciones: instalar un&nbsp;<span class="search_hit">kernel</span>&nbsp;desde fuentes, modificar el ya instalado o bajarnos uno de los kernels &rdquo;<em>-filer</em>&rdquo; de&nbsp;<span class="search_hit">OVH</span>. Los kernels "<em>-filer</em>" est&aacute;n pensados para este tipo de servidores de ficheros. Por sencillez optaremos por esta tercera opci&oacute;n.</p>
<p>Primeramente descargamos las im&aacute;genes del nuevo kernel que vamos a instalar desde el ftp oficial de&nbsp;<span class="search_hit">OVH</span>&nbsp;(<a class="urlextern" title="ftp://ftp.ovh.net/made-in-ovh/bzImage/" rel="nofollow" href="ftp://ftp.ovh.net/made-in-ovh/bzImage/">ftp://ftp.<span class="search_hit">ovh</span>.net/made-in-<span class="search_hit">ovh</span>/bzImage/</a>):</p>
```
# cd /boot/
# wget ftp://ftp.ovh.net/made-in-ovh/bzImage/3.2.13/bzImage-3.2.13-xxxx-grs-ipv6-64-filer
# wget ftp://ftp.ovh.net/made-in-ovh/bzImage/3.2.13/System.map-3.2.13-xxxx-grs-ipv6-64-filer
# ls
bzImage-3.2.13-xxxx-grs-ipv6-64 System.map-3.2.13-xxxx-grs-ipv6-64
bzImage-3.2.13-xxxx-grs-ipv6-64-filer System.map-3.2.13-xxxx-grs-ipv6-64-filer
grub
```
<p>Ahora tendremos que modificar <em>grub</em> para que al arrancar la m&aacute;quina lo haga con el nuevo&nbsp;<span class="search_hit">kernel</span>. Lo hacemos editando el fichero&nbsp;<em>/etc/grub.d/06_OVHkernel</em>, en la l&iacute;nea que antes hac&iacute;a referencia al&nbsp;<span class="search_hit">kernel&nbsp;</span><em>bzImage*64</em>&nbsp;ahora le agregamos un&nbsp;<em>-filer</em>&nbsp;y guardamos los cambios:</p>
```
OS="Debian GNU/Linux"
LINUX_ROOT_DEVICE=${GRUB_DEVICE}
linux=`ls -1 -t /boot/bzImage*64-filer 2&gt;/dev/null | head -n1`
```
<p>Una vez tenemos el nuevo&nbsp;<span class="search_hit">kernel</span>&nbsp;referenciado en el archivo de plantilla&nbsp;<em>06_OVHkernel</em>, ejecutamos el&nbsp;<em>grub-mkconfig</em>&nbsp;para hacer efectiva la configuraci&oacute;n, es recomendable hacer antes una copia de seguridad de la configuraci&oacute;n anterior (sabe m&aacute;s el diablo por viejo que por diablo):</p>
```
# cp /boot/grub/grub.cfg /boot/grub/grub.cfg.old
# grub-mkconfig &gt; /boot/grub/grub.cfg
```
<p>Finalmente toca reiniciar, cruzar los dedos y, si todo ha ido correctamente, comprobar que ya tenemos el nuevo&nbsp;<span class="search_hit">kernel</span>&nbsp;listo para hacer funcionar nuestro servidor NFS:</p>
```
# uname -a
Linux ns302399.ovh.net 3.2.13-grsec-xxxx-grs-ipv6-64-filer #1 SMP Thu Mar 29 11:26:19 UTC 2012 x86_64 GNU/Linux
```
<p>No es complicado, pero es enga&ntilde;oso pensar en montar un NFS sobre OVH como una trivial tarea de poco m&aacute;s de 5 minutos.&nbsp;</p>

View File

@ -0,0 +1,30 @@
---
title: "¿Codeigniter-Reactor + esteroides?"
date: 2011-02-04T20:09:38Z
draft: false
tags: [ "php", "code" ]
image:
---
<p>
Es algo que todav&iacute;a no llego a entender ni asimilar. He pasado la mayor parte de la tarde para configurar la nueva versi&oacute;n 2.0 de <a href="https://github.com/philsturgeon/codeigniter-reactor/">CodeIgniter-Reactor</a> con varias librer&iacute;as que, para mi forma de desarrollar, son indispensables en cualquier framework de programaci&oacute;n orientado a web:</p>
<ul>
<li>
<a href="https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc">HMVC</a>: Gracias a la librer&iacute;a de <em>Wiredesignz</em> podemos ordenar nuestro c&oacute;digo en m&oacute;dulos y simplificar la l&oacute;gica de la aplicaci&oacute;n.</li>
<li>
<a href="https://github.com/pyrocms/pyrocms/tree/master/system/pyrocms/modules/modules">ModulesModule</a>: Ahora que todo ser&aacute; un m&oacute;dulo, no vendr&iacute;a mal un m&oacute;dulo encargado de ejecutar las tareas m&aacute;s comunes de los m&oacute;dulos (instalar, desinstalar, actualizar...). Un m&oacute;dulo de m&oacute;dulos.</li>
<li>
<a href="https://github.com/pyrocms/pyrocms/tree/master/system/pyrocms/modules/settings">SettingsModule</a>: No me gusta cargar la configuraci&oacute;n desde ficheros <em>config/*</em>, por comodidad y para que el usuario pueda cambiar cualquier par&aacute;metro ajustable de una aplicaci&oacute;n, prefiero hacerlo en base de datos y cachearlo a disco si es necesario. Me quedo con la librer&iacute;a de <a href="http://pyrocms.com">PyroCMS</a>.</li>
<li>
<a href="https://github.com/pyrocms/pyrocms/tree/master/system/pyrocms/modules/themes">ThemesModule</a>: Otra caracter&iacute;stica imprescindible ser&iacute;a tener una aplicaci&oacute;n <em>themeable</em> y que desde un interfaz de administraci&oacute;n se pueda cambiar tranquilamente el aspecto de la misma. Para ello podemos hacer uso de este m&oacute;dulo capaz de instalar y desinstalar themes.</li>
<li>
<a href="https://github.com/pyrocms/pyrocms/blob/master/system/pyrocms/libraries/Template.php">TemplateLibrary</a> y <a href="https://github.com/pyrocms/pyrocms/blob/master/system/pyrocms/libraries/Tags.php">TagsLibrary</a>: Una vez hemos decidido hacer la aplicaci&oacute;n <em>modular</em> y <em>themeable</em> siguiendo el patr&oacute;n <em>MVC</em>, un buen lenguaje de <em>template</em> para que los dise&ntilde;adores no se vuelvan locos con el lenguaje din&aacute;mico ser&iacute;a un punto m&aacute;s.</li>
<li>
<a href="https://github.com/philsturgeon/codeigniter-migrations/">MigrationsLibrary</a>: Una vez lo pruebas se convierte en <em>musthave</em>. Se trata de una librer&iacute;a para hacer migraciones de versiones en base de datos. Gestiona los cambios entre versiones de forma sencilla.</li>
</ul>
<p>
<!--more-->Como pod&eacute;is ver siguiendo los enlaces, casi todo lo necesario para montar el esquema inicial de un framework PHP decente est&aacute; en los repositorios de <a href="https://www.philsturgeon.co.uk/">Phil Sturgeon</a> (<a href="https://bitbucket.org/philsturgeon/">bitbucket</a> y <a href="https://github.com/philsturgeon/">github</a>). Su <a href="http://www.pyrocms.org">PyroCMS</a> cuenta con todas estas caracter&iacute;sticas pero tiene muchas otras librer&iacute;as que no son necesarias -a mi modo de ver- para tomarlo como base para cualquier otro tipo de proyecto.</p>
<p>
Demasiado complejo de ensamblar, una vez he conseguido hacerlo funcionar m&aacute;s o menos todo ya no tengo ganas de empezar a programar la aplicaci&oacute;n que ten&iacute;a en mente. &iquest;Por qu&eacute; no hay *nada* con todas esas funciones&nbsp; de serie en PHP?. Si, ya s&eacute; que con <a href="http://www.rubyonrails.org/">Ruby on Rails</a> o <a href="http://djangoproject.org">Django</a> hubiera tenido todas estas caracter&iacute;sticas -y m&aacute;s- en un par de comandos, pero ten&iacute;a que desenga&ntilde;arme.</p>
<p>
En este sentido PHP sigue estando tan verde como hace a&ntilde;os, me hace perder demasiado tiempo a&uacute;n conociendo la estructura del lenguaje. Todos sabemos como es la curva de aprendizaje al principio, pero -aunque duela- ha llegado el momento de invertir en otra cosa. <em>Shame on me</em>?</p>

View File

@ -0,0 +1,255 @@
---
title: "Desarrollo web con Python: Flask"
date: 2012-02-15T18:47:34Z
draft: false
tags: [ ]
image:
---
<p>
Hace alg&uacute;n tiempo empec&eacute; a utilizar <a href="http://flask.pocoo.org/">Flask</a> para un proyecto personal. Flask es un mini framework de desarrollo en python que me ha convencido desde el principio por su sencillez. Intentar&eacute; exponer un peque&ntilde;o ejemplo para que os hag&aacute;is una idea de c&oacute;mo funciona.</p>
<p style="text-align: center; ">
<img alt="" src="gallery/flask.png" style="width: 200px; height: 78px; " /></p>
<p>
Y como <a href="http://toporojo.es/blog/">&Aacute;lex</a> ha escrito un <a href="http://toporojo.es/blog/2012/02/11/desarrollo-web-con-python-pylons/">completo tutorial sobre Pylons/Pyramid</a> con un ejemplo de aplicaci&oacute;n, no quer&iacute;a ser menos y explicar mis aventuras y desventuras con esta otra peque&ntilde;a joya de Python as&iacute; que all&aacute; vamos.</p>
<p>
<!--more--></p>
<p>
<strong>Instalaci&oacute;n&nbsp;</strong></p>
<p>
Flask est&aacute; basado en &nbsp;<a href="http://werkzeug.pocoo.org/">Werkzeug</a>, una librer&iacute;a WSGI para Python. Si usamos <a href="http://pypi.python.org/pypi/pip">pip</a> y <a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a> para crear el entorno virtual y comenzar a trabajar (situaci&oacute;n que <a href="http://www.userlinux.net/django-virtualenv-pip.html">ya he explicado en su d&iacute;a</a>) vemos que las dependencias de Flask son m&iacute;nimas:</p>
```
$ sudo easy_install pip
$ pip install virtualenv
$ mkdir -p flaskblog/{src,env}
$ cd flaskblog/
$ virtualenv --distribute --no-site-packages env/
$ pip -E env/ install flask
Downloading Flask-0.8.tar.gz
Downloading/unpacking Werkzeug&gt;=0.6.1 (from flask)
Downloading/unpacking Jinja2&gt;=2.4 (from flask)
Installing collected packages: flask, Jinja2, Werkzeug
$ pip -E env/ install flask-wtf
Downloading Flask-WTF-0.5.2.tar.gz
Downloading/unpacking WTForms (from flask-wtf)
Installing collected packages: flask-wtf, WTForms
$ pip -E env/ install flask-sqlalchemy
```
<p>
Una &nbsp;vez creado el entorno virtual instalamos <em>Flask</em>, que depende de <em>Werkzeug</em> y de <em>Jinja2</em> como sistema de templates. Tambi&eacute;n instalamos <a href="http://packages.python.org/Flask-WTF/">Flask-WTF</a>&nbsp;para tener integraci&oacute;n con <em>WTForms</em> y hacer m&aacute;s sencillo el uso de formularios con funciones avanzadas (csrf, etc...). Y por &uacute;ltimo <em>Flask-SQLAlchemy </em>como complemento ORM para la base de datos.</p>
<p>
<strong>Requirements y configuraci&oacute;n</strong></p>
<p>
A continuaci&oacute;n vamos a entrar por primera vez en el entorno y crear el fichero de requisitos - yo normalmente le llamo <em>requirements.txt</em> - para poder regenerar el entorno virtual tantas veces y en tantas m&aacute;quinas como queramos:</p>
```
$ source env/bin/activate
(env)$ pip freeze &gt; src/requirements.txt
```
<p>
Si luego queremos regenerar el entorno a partir del fichero lo haremos ejecutando el siguiente comando:</p>
```
$ pip install -E nuevo_env/ -r src/requirements.txt
```
<p>
Empezamos a montar el esqueleto de la aplicaci&oacute;n dentro del directorio <em>src/&nbsp;</em>creando un directorio para los templates, como queremos que nuestra aplicaci&oacute;n pueda tener varios templates a elegir, creamos tambi&eacute;n el &quot;por defecto&quot;:</p>
```
(env)$ mkdir -p templates/default/
```
<p>
Ya que estamos empezando una aplicaci&oacute;n desde cero nos gustar&iacute;a tener un m&iacute;nimo de configuraci&oacute;n para la misma as&iacute; que vamos a usar un fichero para que guarde ciertos valores variables:</p>
```
(env)$ cat config.py
import os
DEBUG = True
_basedir = os.path.abspath(os.path.dirname(__file__))
DATA_PATH = os.path.join(_basedir, &#39;data&#39;)
DEFAULT_TPL = &#39;default&#39;
USERNAME = &#39;admin&#39;
PASSWORD = &#39;default&#39;
SECRET_KEY = &#39;devel secret key&#39;
URL = &#39;http://localhost:5000/&#39;
TITLE = &#39;OurApplication&#39;
VERSION = &#39;0.1&#39;
LANG = &#39;es&#39;
LANG_DIRECTION = &#39;ltr&#39;
YEAR = &#39;2012&#39;
del os
```
<p>
Con la configuraci&oacute;n y el entorno listos, lo siguiente ser&aacute; empezar la aplicaci&oacute;n propiamente dicha, as&iacute; que manos a la obra.</p>
<p>
<strong>Primeros pasos con Flask</strong></p>
<p>
Vamos a reducir el grueso de la aplicaci&oacute;n a un solo archivo, le llamaremos <em>blog.py </em>- ya s&eacute; que no suena muy original pero imagino que ser&aacute; entendible -. Nuestro <em>blog.py</em> ser&aacute; el controlador principal, en &eacute;l incluiremos de forma excepcional el modelo, los formularios y los m&eacute;todos que se encargar&aacute;n de la l&oacute;gica y de llamar a las plantillas. Para empezar por el principio definimos el archivo como una aplicaci&oacute;n Flask y cargamos la configuraci&oacute;n que antes hemos creado:</p>
```
# -*- coding: utf-8 -*-
&quot;&quot;&quot;
OurApplication
~~~~~~~~~~~~~~
:copyright: (c) 2011 by Oscar M. Lage.
:license: BSD, see LICENSE for more details.
&quot;&quot;&quot;
import os
from flask import Flask, render_template, request, redirect
from werkzeug.routing import Rule
# Flask application and config
app = Flask(__name__)
app.config.from_object(&#39;config&#39;)
# Middleware to serve the static files
from werkzeug import SharedDataMiddleware
import os
app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
&#39;/&#39;: os.path.join(os.path.dirname(__file__), &#39;templates&#39;, app.config[&#39;DEFAULT_TPL&#39;])
})
# Index
@app.route(&#39;/&#39;)
def index():
return render_template(app.config[&#39;DEFAULT_TPL&#39;]+&#39;/index.html&#39;,
conf = app.config)
if __name__ == &#39;__main__&#39;:
app.run()
```
<p>
* Lo m&aacute;s raro son esas 3 lineas que hemos incluido en el archivo, una especie de <em>Middleware</em>&nbsp;para poder servir archivos est&aacute;ticos directamente desde el template seleccionado.</p>
<p>
Una vez tenemos la aplicaci&oacute;n &quot;preparada&quot; hemos de crear la plantilla para que se pueda ejecutar sin errores, para ello dentro del directorio templates/default/ creamos el archivo index.html al que referenciamos en el controlador, el contenido del archivo podr&iacute;a ser algo as&iacute;:</p>
```
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;
xml:lang=&quot;{{ conf[&#39;LANG&#39;] }}&quot; lang=&quot;{{ conf[&#39;LANG&#39;] }}&quot;
dir=&quot;{{ conf[&#39;LANG_DIRECTION&#39;] }}&quot;&gt;
&lt;head&gt;
&lt;title&gt;{% block title %}{% endblock %} [{{ conf[&#39;TITLE&#39;] }}]&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id=&quot;header&quot;&gt;
&lt;h1&gt;{{ conf[&#39;TITLE&#39;] }}&lt;/h1&gt;
&lt;/div&gt;
&lt;div id=&quot;content&quot;&gt;
Contenido
&lt;/div&gt;
&lt;div id=&quot;footer&quot;&gt;
&lt;p&gt;{{ conf[&#39;TITLE&#39;] }} - {{ conf[&#39;YEAR&#39;] }}&lt;/p&gt;
&lt;/div&gt;
&lt;/body&gt;
```
<p>
Y ya podr&iacute;amos ejecutar por primera vez nuestra aplicaci&oacute;n desde consola para luego comprobar que todo est&aacute; correcto en navegador, as&iacute; que vamos a ello:</p>
```
$ python blog.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader
```
<p>
Si abrimos el navegador en la url proporcionada (http://127.0.0.1:5000/) obtendremos una pantalla similar a la de la siguiente figura:</p>
<p style="text-align: center; ">
<img alt="" src="gallery/flask001.png" style="width: 300px; height: 219px; " /></p>
<p>
<strong>SQLAlchemy</strong></p>
<p>
Una vez tenemos la base y el esqueleto de la aplicaci&oacute;n vamos a incorporar una base de datos para hacerla din&aacute;mica. Para ello usaremos <a href="http://packages.python.org/Flask-SQLAlchemy/">Flask-SQLAlchemy</a>. Para trabajar con SQLAlchemy agregamos una nueva variable de configuraci&oacute;n para la base de datos:</p>
```
SQLALCHEMY_DATABASE_URI = &#39;sqlite:///&#39;+ os.path.join(os.path.dirname(__file__), &#39;database.db&#39;)
```
<p>
Y le decimos a <em>blog.py</em> el esquema que vamos a utilizar:</p>
```
from flaskext.sqlalchemy import SQLAlchemy
...
db = SQLAlchemy(app)
...
# Model
class Blog(db.Model):
__tablename__ = &#39;Blog&#39;
__mapper_args__ = dict(order_by=&quot;date desc&quot;)
id = db.Column(db.Integer, primary_key=True)
subject = db.Column(db.Unicode(255))
author = db.Column(db.Unicode(255))
date = db.Column(db.DateTime())
content = db.Column(db.Text())
```
<p>
Por &uacute;ltimo creamos la base de datos desde una consola python para poder usarla desde cualquier parte del controlador, tan simple como entrar a python desde el directorio src/ donde tenemos blog.py y ejecutar lo siguiente:</p>
```
&gt;&gt;&gt; from blog import db
&gt;&gt;&gt; db.create_all()
```
<p>
Ya tenemos el archivo <em>database.db</em> preparado para cargarlo de datos mediante los m&eacute;todos correspondientes de <em>blog.py</em>, algunos ejemplos:</p>
```
@app.route(&#39;/add&#39;, methods=[&#39;GET&#39;,&#39;POST&#39;])
def add():
if request.method == &#39;POST&#39;:
post = Blog(request.form[&#39;subject&#39;], request.form[&#39;content&#39;])
db.session.add(post)
db.session.commit()
return redirect(url_for(&#39;index&#39;))
return render_template(app.config[&#39;DEFAULT_TPL&#39;]+&#39;/add.html&#39;,
conf = app.config)
```
<p>
<strong>Flask-WTForms</strong></p>
<p>
Una vez tenemos preparada la base de datos y el m&eacute;todo que agregar&aacute; nuevos posts tan solo falta crear el formulario que nos permitir&aacute; tal funcionalidad y crear el template, poco m&aacute;s de un par de lineas:</p>
```
# Create Form
class CreateForm(Form):
subject = TextField(&#39;Subject&#39;, [validators.required()])
content = TextAreaField(&#39;Content&#39;, [validators.required(), validators.Length(min=1)])
```
<p>
Y el template con el formulario correspondiente ser&iacute;a el siguiente:</p>
```
&lt;form method=&quot;post&quot; action=&quot;&quot;&gt;
&lt;dl&gt;
{{ form.csrf }}
{{ form.subject.label }} {{ form.subject(style=&quot;width:100%&quot;) }}
{% for error in form.subject.errors %} {{ error }} {% endfor %}
&lt;br /&gt;
{{ form.content.label }} {{form.content(style=&quot;height:100px;width:100%&quot;) }}
{% for error in form.content.errors %} {{ error }} {% endfor %}
&lt;/dl&gt;
&lt;p&gt;&lt;input type=&quot;submit&quot; value=&quot;submit&quot;&gt;
&lt;/form&gt;
```
<p>
Y ya tendr&iacute;amos un formulario para agregar posts totalmente funcional. Entre esta vista, la de un listado de posts y la del detalle de los mismos (ver repositorio m&aacute;s abajo), tendr&iacute;amos una peque&ntilde;a aplicaci&oacute;n con <em>Flask</em> + <em>SQLAlchemy</em> + <em>WTForms</em>.</p>
<p>
<strong>Resumiendo</strong></p>
<p>
Para finalizar, adem&aacute;s de las vistas que hemos dicho que faltaban, tendr&iacute;amos que dar un poco m&aacute;s de colorido a los templates (css, im&aacute;genes...), crear un <em>layout.html</em> que se pueda extender desde el resto de plantillas y poner un poco de orden en todo lo explicado, pero como no quiero extenderme mucho m&aacute;s en el art&iacute;culo, nada mejor que un peque&ntilde;o repositorio en el que se pueden ir viendo los avances:</p>
<ul>
<li>
<a href="https://bitbucket.org/r0sk/flaskblog">Flaskblog (bitbucket)</a></li>
</ul>
<p>
Espero que con este peque&ntilde;o y humilde ejemplo haya quedado m&aacute;s o menos claro el uso de este framework. Siempre es divertido probar cosas nuevas y cuando se trata de piezas tan sencillas y bien documentadas como las tratadas el placer es doble.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

View File

@ -0,0 +1,10 @@
---
title: "Disconnecting a bit"
date: 2013-06-13T06:52:10Z
draft: false
tags: [ ]
image:
---
<p>Yesterday we had a great afternoon. From time to time it's recommended to turn off the computer world and enjoy with family and friends. Yesterday we did. I was really tired and needing fresh air on my mind.</p>
<p>We must repeat, almost, once a week!</p>

View File

@ -0,0 +1,143 @@
---
title: "Django and memcache: clear cache keys"
date: 2014-02-05T13:35:54Z
draft: false
tags: [ "django", "code" ]
image: web-accelerators-memcached.jpg
---
<p>Let's play&nbsp;<a href="https://www.djangoproject.com/">Django</a> with <a href="http://memcached.org/">Memcached</a>. As the great framework Django is, it's so easy to activate <a href="https://docs.djangoproject.com/en/dev/topics/cache/">any kind of cache</a> in your project. <em>Memcached</em> is one of the options, but you can also work with <em>DatabaseCache</em>, <em>FileBasedCache</em>, <em>LocMemCache</em>, <em>MemcachedCache,</em>&nbsp;<em>DummyCache</em> (a kind of non-cache very useful for devel/test enviroments) or - of course - your own <em>CustomCache</em> if you want.</p>
<p><strong>Activating cache</strong></p>
<p>It's too easy to activate the cache feature, it's enough to set the preferences in settings, install <a href="https://pypi.python.org/pypi/python-memcached/">python-memcached</a>&nbsp;in your enviroment (in case you will use <em>MemcachedCache</em>), and not much more to do. A couple of examples:</p>
<p>1. Basic <em>FileBasedCache</em> settings:</p>
```
# settings.py
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}
```
<p>2. <em>MemcachedCache</em> settings:</p>
```
# settings.py
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
```
<p>3. Depending on the enviroment you can use <em>MemcachedCache</em> and <em>DummyCache</em>:</p>
```
# settings.devel.py
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}
```
```
# settings.production.py
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
```
<p><strong>Setting the places where cache will act</strong></p>
<p>Now that we have our project with a configured kind of cache, we must to say where and when to activate it. There are multiple ways to do it (on the <a href="https://docs.djangoproject.com/en/dev/topics/cache/#the-per-site-cache">whole site</a>, <a href="https://docs.djangoproject.com/en/dev/topics/cache/#the-per-view-cache">views</a>, <a href="https://docs.djangoproject.com/en/dev/topics/cache/#template-fragment-caching">templates</a>, <a href="https://docs.djangoproject.com/en/dev/topics/cache/#specifying-per-view-cache-in-the-urlconf">urls</a>...). I'm going to use... let's say urls. So, in our <em>urls.py</em> we have to set a time and activate the cache:</p>
```
# urls.py
from django.views.decorators.cache import cache_page
ctime = (60 * 24) # A day
urlpatterns = patterns('',
url(r'^$',
cache_page(ctime)(BlogIndexView.as_view()),
{},
'blog-index'
),
...
)
```
<p>A simple server reload will be enough to have cache running. We can see it on action with <a href="https://github.com/django-debug-toolbar/django-debug-toolbar">django-debug-toolbar</a>, <a href="https://github.com/bartTC/django-memcache-status">django-memcache-status</a> or something like that.</p>
<p><strong>Clean a specific key cache</strong></p>
<p>And now the funniest part. For example, talking about a blog tool, when you write a new post (or editing older one) the software should be able to remove some cache keys, i.e. the <em>blog-index</em> one (because you have a new post) and the <em>post-detail</em> other (because you must be able to inmediately see the changes in the post you're editting).</p>
<p>Following <a href="http://stackoverflow.com/questions/2268417/expire-a-view-cache-in-django">this link</a> I've created a cache.py with this content:</p>
```
# cache.py
# -*- coding: utf-8 -*-
def expire_view_cache(
view_name,
args=[],
namespace=None,
key_prefix=None,
method="GET"):
"""
This function allows you to invalidate any view-level cache.
view_name: view function you wish to invalidate or it's named url pattern
args: any arguments passed to the view function
namepace: optioal, if an application namespace is needed
key prefix: for the @cache_page decorator for the function (if any)
http://stackoverflow.com/questions/2268417/expire-a-view-cache-in-django
added: method to request to get the key generating properly
"""
from django.core.urlresolvers import reverse
from django.http import HttpRequest
from django.utils.cache import get_cache_key
from django.core.cache import cache
from django.conf import settings
# create a fake request object
request = HttpRequest()
request.method = method
if settings.USE_I18N:
request.LANGUAGE_CODE = settings.LANGUAGE_CODE
# Loookup the request path:
if namespace:
view_name = namespace + ":" + view_name
request.path = reverse(view_name, args=args)
# get cache key, expire if the cached item exists:
key = get_cache_key(request, key_prefix=key_prefix)
if key:
if cache.get(key):
cache.set(key, None, 0)
return True
return False
```
<p>And last step is to call the&nbsp;expire_view_cache function on model form save hook (<em>admin.py</em> in this case):</p>
```
# admin.py
from cache import expire_view_cache
class PostAdminForm(admin.ModelAdmin):
...
def save_model(self, request, obj, form, change):
expire_view_cache("blog-index")
expire_view_cache("post-detail", [obj.slug])
```
<p>And that's all, we are able to <em>clean/purge/remove</em> the cache when a new post is added or edited. As you can see in the code, cache is fun but you have to be careful to set it on the right way.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,25 @@
---
title: "Django: Cambiando de DB Engine"
date: 2012-04-28T18:42:31Z
draft: false
tags: [ "code", "django" ]
image:
---
<p>
Normalmente las especificaciones de un entorno de desarrollo y las de un entorno en producci&oacute;n suelen ser bastante diferentes. Quiz&aacute;s en el primero buscas la comodidad mientras que cuando se hace el <em>deploy</em> a producci&oacute;n priman otras cosas. Este suele ser el caso del motor de base de datos cuando trabajas con <a href="http://djangoproject.org">Django</a>.</p>
<p>
Durante el proceso de desarrollo es muy c&oacute;modo utilizar <em>sqlite </em>porque no requiere de ning&uacute;n servidor adicional y est&aacute; soportado de base en Django (<em>builtin</em>). Es posible que una vez acabado el desarrollo queramos cambiar a otro <em>SGBD</em> &quot;de verdad&quot; como pueden ser <em>MySQL</em> o <em>PostgreSQL</em>.</p>
<p>
Lo que podr&iacute;a suponer un quebradero de cabeza en otras arquitecturas, en nuestro caso utilizando <em>dumpdata</em> y <em>loaddata</em>, se reduce a las siguientes tres lineas:</p>
```
$ python manage.py dumpdata --indent=4 --format=json &gt; fixtures.json
$ scp fixtures.json user@remote:/path/project/
(remote)$ python manage.py loaddata fixtures.json
```
<p>
En la primera usamos <a href="https://docs.djangoproject.com/en/dev/ref/django-admin/#dumpdata-appname-appname-appname-model">dumpdata</a>&nbsp;para hacer un dumpeado de todos los datos de la aplicaci&oacute;n (sqlite) en formato json, posteriormente pasamos ese archivo al entorno de producci&oacute;n (en este caso pongamos de ejemplo a otro servidor) y all&iacute; finalmente (con el conector apuntando al nuevo gestor) ejecutamos el <a href="https://docs.djangoproject.com/en/dev/ref/django-admin/#loaddata-fixture-fixture">loaddata</a> para insertar los datos.</p>
<p>
Et voil&agrave;!</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,97 @@
---
title: "Django deploy: problems with limited hosting"
date: 2014-07-21T21:51:18Z
draft: false
tags: [ "django", "code" ]
image: django.png
---
<p>Some months ago I had to deal with a&nbsp;<a href="../../../../blog/symfony2-en-un-hosting-compartido.html">Symfony2 project in a shared hosting</a>&nbsp;(Spanish article) and now the big next deal is a similar task with&nbsp;<a href="https://www.djangoproject.com/">Django</a>.</p>
<p>The project is almost done and I have the hosting credentials, once I'm in I noticed that there is no chance to configure anything (Apache, WSGI or whatever) so I was a bit lost. Thanks to my&nbsp;<a href="http://ailalelo.com/">Ailalelo's mates</a>&nbsp;(they had lot of experience with this kind of situations) I found the proper configuration.</p>
<p>Hosting is&nbsp;<em>django-ready</em>, but the version they're running (<em>1.4.2</em>) is not the best choice, I want to install&nbsp;<em>1.6.x</em>, the one I have used to develop the project. The other big requirement is&nbsp;<em>virtualenv+pip</em>&nbsp;to retrieve the packages I'm using.</p>
<p>Mainly I've solved it with two files,&nbsp;<code>project.cgi</code>&nbsp;and&nbsp;<code>.htaccess</code>.</p>
<h2>project.cgi</h2>
<p>The hosting structure is like many others, I have access to a&nbsp;<em>homedir</em>&nbsp;with the following directories:</p>
```
myhome/
logs/
tmp/
www/
cgi-bin/
index.html
```
<p>Before to say Apache what to do with our project, let's install&nbsp;<code>virtualenv</code>&nbsp;and all the requirements, my choice is to put the environment out of the&nbsp;<code>www/</code>&nbsp;directory:</p>
```
myhome/
env/
logs/
tmp/
www/
cgi-bin/
project/
index.html
```
```
$ virtualenv env
$ . env/bin/activate
$ pip install -r www/project/requirements/production.txt
```
<p>Seems to be that apache's&nbsp;<em>mod_cgi</em>&nbsp;will process all the files you put in the&nbsp;<code>cgi-bin</code>&nbsp;directory, so we already know where to save our&nbsp;<code>project.cgi</code>. I have to tell apache to use my own&nbsp;<em>virtualenv</em>&nbsp;<code>python</code>, where the environment and the project are. And finally set some environment variables:</p>
```
#!/home/myhome/env/bin/python
import os
from os.path import abspath, dirname
from sys import path
actual = os.path.dirname(__file__)
path.insert(0, os.path.join(actual, "..", "project/project"))
path.insert(0, os.path.join(actual, "..", "env"))
# Set the DJANGO_SETTINGS_MODULE environment variable.
os.environ['PATH'] = os.environ['PATH'] + ':/home/myhome/www/project/node_modules/less/bin'
os.environ['SECRET_KEY'] = 'SECRETKEY'
os.environ['DJANGO_SETTINGS_MODULE'] = "project.settings.production"
from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")
```
<p>Note that I modified the PATH because I have to be able to use&nbsp;<code>less</code>&nbsp;binary, required for&nbsp;<a href="http://django-compressor.readthedocs.org/en/latest/">django-compressor</a>&nbsp;package. In this particular case my user was not allowed to install&nbsp;<em>node/less</em>&nbsp;in the system, so I had to install it locally, referencing the particular&nbsp;<code>node_modules</code>&nbsp;folder.</p>
<h2>.htaccess</h2>
<p>Now that Apache knows what to do, we should redirect almost all the incoming traffic to the&nbsp;<em>cgi</em>, so let's write some<code>.htaccess</code>&nbsp;rules:</p>
```
AddHandler fcgid-script .fcgi
RewriteEngine On
RewriteRule ^static/(.*)$ project/project/static/$1 [L]
RewriteRule ^media/(.*)$ project/project/media/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ cgi-bin/project.cgi/$1 [QSA,L]
AddDefaultCharset UTF-8
```
<p>The&nbsp;<code>media/</code>&nbsp;and&nbsp;<code>static/</code>&nbsp;dirs are redirected to the proper location, because they didn't work as is. Not much more to say with this file, it's easy to understand I think.</p>
<h2>Remember</h2>
<ul>
<li>To properly install the environment.</li>
<li>Set up this two files (cgi and .htaccess).</li>
<li>Take care with node tools (bower, npm, less, node_modules...).</li>
<li>Most of times django-compressor is a PITA in shared hostings.</li>
<li>Take double care with static/media settings.</li>
<li>Set the proper permissions in the .cgi file.</li>
<li>Having a bit of patience and access to&nbsp;<a href="http://stackoverflow.com/">stackoverflow</a>&nbsp;is to have it a half fixed ;).</li>
</ul>
<p>&nbsp;</p>
<ul>
</ul>

View File

@ -0,0 +1,20 @@
---
title: "Django: limpiando usuarios desde shell"
date: 2013-09-12T23:03:29Z
draft: false
tags: [ "django", "code" ]
image:
---
<p>Es tal el inter&eacute;s por el <a href="http://www.vamosavidas.com/foros/">foro de VamosaVidas</a> (si, ese que romp&iacute; en su d&iacute;a y <a href="http://www.vamosavidas.com/los-duendes-del-foro-nos-lo-han-devuelto.html">he vuelto a arreglar</a>) que todos los d&iacute;as tenemos cientos de registros. Realmente se trata de robots que se dedican a hacer spam, pero eso es lo de menos :P.</p>
<p>Mientras no actualizo y arreglo <a href="https://github.com/pennersr/django-allauth">django-authall</a>&nbsp;es un poco co&ntilde;azo andar mirando en el admin el &uacute;ltimo usuario bueno y borrar manualmente uno a uno cotejando que no me equivoque, as&iacute; que he pensado en un par de lineas que no deber&iacute;an hacer demasiado da&ntilde;o si se usan con precauci&oacute;n. Desde la shell de nuestro proyecto podemos hacer algo as&iacute;:</p>
```
$ python manage.py shell
&gt;&gt;&gt; from django.contrib.auth.models import User
&gt;&gt;&gt; list(User.objects.order_by('date_joined'))
&gt;&gt;&gt; [user.delete() for user in list(User.objects.order_by('date_joined'))[100:]]
```
<p>Primero estamos listando todos los usuarios por orden de fecha de registro, los convertimos en lista para que no salgan los datos "<em>truncados</em>". Y en segundo lugar estamos eliminando todos excepto los 100 primeros.</p>
<p>Esta es la sencillez y potencia de Python.</p>

View File

@ -0,0 +1,151 @@
---
title: "Django + virtualenv + pip"
date: 2011-02-23T21:37:56Z
draft: false
tags: [ "django", "code" ]
image:
---
<p>No lo ten&iacute;a claro, pero cuando entend&iacute; lo que supon&iacute;a y c&oacute;mo se trabajaba con <em>virtualenv</em> + <em>pip</em> me decid&iacute; a probarlo. Voy a <em>intentar</em> explicar como se utilizan estas herramientas de una forma gen&eacute;rica, para hacernos una idea de lo que significa y los casos en los que se pueden aplicar. A grandes rasgos:</p>
<ul>
<li class="level1">
<div class="li"><a href="http://djangoproject.org">Django</a>: Framework en <em>python</em>, creo que no necesita mucha m&aacute;s explicaci&oacute;n.</div>
</li>
<li class="level1">
<div class="li"><a href="http://pypi.python.org/pypi/virtualenv">Virtualenv</a>: Herramienta necesaria para crear un entorno virtual de <em>python</em>, con las versiones espec&iacute;ficas de los paquetes y/o dependencias que hagan falta para el proyecto.</div>
</li>
<li class="level1">
<div class="li"><a href="http://pypi.python.org/pypi/pip">Pip</a>: Gestor/Instalador de esos paquetes (similar a <em>easy_install</em>).</div>
</li>
</ul>
<p>Con estas herramientas intentaremos instalar un entorno virtual independiente para gestionar todas las dependencias de nuestro proyecto.<!--more--></p>
<p><strong>Instalaci&oacute;n del entorno virtualenv + pip</strong></p>
<p>Primero instalamos <em>pip</em>, que como hemos mencionado anteriormente, es el gestor de <em>paquetes</em> con el que vamos a instalar el resto de componentes. Tiramos de <em>easy_install</em> para instalarlo. Una vez instalado <em>pip</em>, instalamos tambi&eacute;n <em>virtualenv</em> y tendremos la base necesaria para seguir trabajando:</p>
```
$ sudo easy_install pip
$ pip install virtualenv
```
<p>Vamos a crear el entorno. Supongamos 2 directorios de trabajo, <em>src/</em> y <em>env/</em>. El directorio <em>src/</em> lo destinaremos al c&oacute;digo fuente (podemos tirar de repositorio o iniciar nuestro proyecto directamente ah&iacute;), en <em>env/</em> meteremos todos los paquetes y dependencias del proyecto, osea el entorno:</p>
```
$ mkdir -p foo/{env,src}
$ cd foo/
$ virtualenv --distribute --no-site-packages env/
New python executable in env/bin/python
Installing distribute........................................done.
```
<p>Ahora ya estamos preparados para instalar las aplicaciones/dependencias dentro del entorno de trabajo, lo haremos "desde fuera" con la opci&oacute;n <em>-E</em>:</p>
```
$ pip -E env/ install django
Downloading/unpacking django
Downloading Django-1.2.4.tar.gz (6.4Mb): 6.4Mb downloaded
Running setup.py egg_info for package django
[...]
Successfully installed django
Cleaning up...
```
```
$ sudo pip -E env/ install -e hg+https://bitbucket.org/ubernostrum/django-registration#egg=django-registration
$ sudo pip -E env/ install -e git+https://github.com/flashingpumpkin/django-socialregistration.git#egg=django-socialregistration
[instalamos el resto de dependencias]
```
<p>Vamos a comprobar que todo est&aacute; correcto, para ello utilizamos una herramienta que se llama <em>yolk</em>, capaz de listar todos los paquetes que tenemos instalados en el entorno, primero instalamos esa herramienta, luego entramos en el entorno y la ejecutamos (aunque podr&iacute;amos hacer lo mismo con la orden <em>pip freeze </em>como se muestra a continuaci&oacute;n):</p>
```
$ pip -E env/ install yolk
$ source env/bin/activate
(env)$ yolk -l
Django - 1.2.4 - active
Python - 2.6.6 - active development (/usr/lib/python2.6/lib-dynload)
distribute - 0.6.14 - active
pip - 0.8.1 - active
wsgiref - 0.1.2 - active development (/usr/lib/python2.6)
yolk - 0.4.1 - active
```
<p><strong>Nota</strong>: Como se puede ver en el ejemplo de arriba, para entrar en el entorno que hemos creado usamos el comando <em>source env/bin/activate</em>, para salir del mismo usamos el comando <em>deactivate</em>.</p>
```
(env)$ pip freeze
Django==1.2.4
distribute==0.6.14
wsgiref==0.1.2
yolk==0.4.1
```
<p>Ahora que tenemos m&aacute;s o menos clara la forma de actuar, vamos a hacer un <em>freeze</em> y guardar el archivo de requisitos dentro del repositorio para poder volver a reproducirlo en cualquier otra m&aacute;quina. Insisto, todos estos comandos pueden ejecutarse dentro del entorno (env) o fuera del mismo con la opci&oacute;n <em>-E entorno</em> de <em>pip</em>:</p>
```
(env)$ cd foo/src/
(env)$ pip freeze &gt; requirements.txt
(env)$ cat requirements.txt
Django==1.2.4
South==0.7.3
distribute==0.6.14
wsgiref==0.1.2
yolk==0.4.1
(env)$ deactivate
$
```
<p>Y ya podemos empezar a programar el proyecto en dentro de <em>src/</em>.</p>
<p><strong>Replicando el entorno</strong></p>
<p>Suponemos ahora que estamos en otra m&aacute;quina -aunque en el ejemplo seguimos en la misma- donde queremos montar de nuevo todo el entorno. Primero creamos de nuevo la estructura anterior y luego hacemos un <em>pull</em> del repositorio la carpeta <em>src/</em> (como estamos en la misma m&aacute;quina lo simulando haciendo un <em>cp</em> :P):</p>
```
$ mkdir -p bar/{env,src}
$ cp -r foo/src/* bar/src
```
<p>Y ahora procuramos recrear el entorno, primero hacemos un entorno nuevo y vac&iacute;o en <em>bar/env/</em> y luego instalamos todo lo que hemos <em>logueado</em> en el <em>requirements.txt</em>:</p>
```
$ virtualenv --distribute --no-site-packages bar/env/
$ pip install -E bar/env/ -r bar/src/requirements.txt
...
Successfully installed Django South ... yolk
Cleaning up...
```
<p>Comprobamos que todo est&eacute; correcto:</p>
```
$ source bar/env/bin/activate
(env)$ pip freeze
Django==1.2.4
distribute==0.6.14
wsgiref==0.1.2
yolk==0.4.1
(env)$ deactivate
$
```
<p><strong>Conclusi&oacute;n</strong></p>
<p><em>Virtualenv</em> y <em>pip</em> forman una combinaci&oacute;n excelente de elementos para hacer de un proyecto un <em>ente</em> sin dependencias frustradas y con todos los requisitos y versiones espec&iacute;ficas para garantizar el correcto funcionamiento del mismo. Ahora, por lo que me han contado, deber&iacute;a interesarme en <a href="http://fabfile.org/">Fabric</a> para automatizar los <em>deploys</em> y seguir haciendo magia.</p>
<p><strong>Referencias</strong></p>
<div class="level2 section_highlight">
<ul>
<li class="level1">
<div class="li"><a class="urlextern" title="http://www.saltycrane.com/blog/2009/05/notes-using-pip-and-virtualenv-django/" rel="nofollow" href="http://www.saltycrane.com/blog/2009/05/notes-using-pip-and-virtualenv-django/">Saltycrane</a></div>
</li>
<li class="level1">
<div class="li"><a class="urlextern" title="http://ryanwilliams.org/2009/Jun/09/deploying-django-sites-fabric-pip-and-virtualenv" rel="nofollow" href="http://ryanwilliams.org/2009/Jun/09/deploying-django-sites-fabric-pip-and-virtualenv">Ryanwilliams</a></div>
</li>
<li class="level1">
<div class="li"><a class="urlextern" title="http://techylinguist.com/how-to/python-and-django-dev-environment-virtualenv-and-pip" rel="nofollow" href="http://techylinguist.com/how-to/python-and-django-dev-environment-virtualenv-and-pip">Techylinguist.com</a></div>
</li>
<li class="level1">
<div class="li"><a class="urlextern" title="http://www.sebasmagri.com/2010/aug/12/pip-fabric-y-virtualenv-herramientas-para-el-desar/" rel="nofollow" href="http://www.sebasmagri.com/2010/aug/12/pip-fabric-y-virtualenv-herramientas-para-el-desar/">Sebasmagri 1</a></div>
</li>
<li class="level1">
<div class="li"><a class="urlextern" title="http://www.sebasmagri.com/2010/aug/14/esqueleto-para-proyectos-django-porque-la-forma-im/" rel="nofollow" href="http://www.sebasmagri.com/2010/aug/14/esqueleto-para-proyectos-django-porque-la-forma-im/">Sebasmagri 2</a></div>
</li>
</ul>
</div>

View File

@ -0,0 +1,48 @@
---
title: "Dovecot, pequeñas peculiaridades"
date: 2010-09-07T09:20:13Z
draft: false
tags: [ "dovecot" ]
image:
---
<p>
Desde hace alg&uacute;n tiempo -y despu&eacute;s de haber lidiado con <a href="http://www.cyrusimap.org/">Cyrus</a> y <a href="http://www.courier-mta.org/">Courier</a>- he optado por <a href="http://dovecot.org/">Dovecot</a> como servidor <em>POP3</em> e <em>IMAP</em> para m&aacute;quinas en producci&oacute;n. Por varios motivos: la sencillez de configuraci&oacute;n, sigue los est&aacute;ndares, soporta <em>mbox</em> y <em>Maildir</em> y algo muy importante, tiene un backend de autentificaci&oacute;n <em>SMTP</em> compatible con <a href="http://www.postfix.org/">Postfix</a> (entre otros).</p>
<p>
Sin duda el servicio de correo electr&oacute;nico es el menos agradecido y probablemente el m&aacute;s doloroso para el <em>sysadmin</em> pero el haber dado con esta combinaci&oacute;n de elementos me ha ahorrado un mont&oacute;n de problemas.</p>
<p>
De todos modos en la &uacute;ltima instalaci&oacute;n que me ha tocado he encontrado un par de peculiaridades que me gustar&iacute;a documentar por si alguien se encuentra en la misma situaci&oacute;n.<!--more--></p>
<p>
Habiendo instalado el mismo O.S., las mismas versiones de software y exactamente los mismos ficheros de configuraci&oacute;n a la hora de despachar correos me encuentro con un error inexperado en <em>mail.log</em>:</p>
```
... status=bounced (local configuration error)
```
<p>
As&iacute; sin m&aacute;s descripci&oacute;n no puedo adivinar mucho as&iacute; que decido activar errores en <em>dovecot.conf</em> con la directiva de configuraci&oacute;n <em>log_path = /var/log/<span class="search_hit">dovecot</span>.log.</em> Ahora s&iacute; podemos sacar m&aacute;s informaci&oacute;n del <em>dovecot.log</em>:</p>
```
Fatal: postmaster_address setting not given
```
<p>
Esto ya es otra cosa, despu&eacute;s de un poco de <em>googling</em> corrijo el fallo agregando al fichero de configuraci&oacute;n una direcci&oacute;n de postmaster, sigue pareci&eacute;ndome raro porque <em>/etc/aliases</em> es el mismo que otras m&aacute;quinas y nunca hab&iacute;a notificado este problema antes pero bueno, es cuesti&oacute;n de agregar a <em>dovecot.conf</em>&nbsp; lo siguiente:</p>
```
protocol lda {
postmaster_address = tu-postmaster@tu-dominio.com
}
```
<p>
Reinicio el servicio y a funcionar... pero no por mucho tiempo puesto que al d&iacute;a siguiente me encuentro con el servicio parado, vuelvo a reiniciar y el proceso se vuelve a parar cada d&iacute;a, repitiendo la jugada. Volviendo a los logs -ese gran invento- veo que todos los d&iacute;as a eso de las <em>6:00am</em> suelta el siguiente mensaje:</p>
```
dovecot: 2010-09-05 05:59:53 Fatal: Time just moved backwards by 9 seconds. This might cause a lot of problems, so I&#39;ll just kill myself now. http://wiki.dovecot.org/TimeMovedBackwards
```
<p>
Justo a esa hora tengo una tarea programada que sincroniza la hora del servidor con <em>rdate</em>. Al parecer Dovecot detecta que la hora ha cambiado y para no entrar en conflictos se hace el <em>harakiri.</em> Interesante, es algo que tienen documentado en <a href="http://wiki.dovecot.org/TimeMovedBackwards">su wiki</a> y te animan a que cambies <em>rdate/ntpdate</em> por <em>ntpd</em>, <em>clockspeed</em> o <em>chrony.</em></p>
<p>
Nada del otro mundo pero s&iacute; me ha supuesto algo de tiempo saber el origen de los errores para poder subsanarlos as&iacute; que bueno, si al menos esta entrada ayuda a alguien o le ahorra alg&uacute;n dolor de cabeza me dar&eacute; por contento.</p>

View File

@ -0,0 +1,20 @@
---
title: "El mejor firewall"
date: 2010-02-11T16:16:22Z
draft: false
tags: [ ]
image:
---
Lo he visto <a href="http://www.puntogeek.com/2010/02/10/humor-el-mejor-firewall-p/">en puntogeek</a> a través del <a href="http://twitter.com/demogar/status/8960593725">twitter de demogar</a> y me ha parecido tan gracioso que he caido en el <em>burdo</em> copy-paste:
<br /><br />
<ol>
<li>Una célula humana contiene 75MB de información génetica.</li>
<li>Un espermatozoide contiene la mitad; eso significa 37.5MB.</li>
<li>Un ml de semen contiene 100 millones de espermatozoides.</li>
<li>En promedio la eyaculación dura 5 segundos y contiene 2.24 ml de semen</li>
<li>Esto significa que la producción del miembro de un hombre equivale 37.5MB x 100,000,000 x 2.25)/5 = 1,687,500,000,000,000 bytes/segundo = 1,6875 Terabytes/seg.</li>
<br />
Esto quiere decir que el óvulo femenino soporta este ataque DDoS a 1,5 terabytes por segundo, y solo permite que pase un solo paquete de información lo que la hace el mejor hardware firewall del mundo.
<br /><br />
La mala noticia de esto, es que ese paquete de información que deja pasar, cuelga el sistema por aproximadamente nueve meses.

View File

@ -0,0 +1,85 @@
---
title: "El papeleo de ser padre"
date: 2013-01-08T18:41:27Z
draft: false
tags: [ ]
image:
---
<p>Pasados esos primeros momentos de tensi&oacute;n y felicidad m&aacute;ximos, vuelves a casa para que la realidad trate de despertarte a golpe de peque&ntilde;as bofetadas. O eso es lo que me est&aacute; pasando a mi. Pasas de preocuparte porque todo salga bien en la eco, porque no haya ninguna complicaci&oacute;n en el momento del parto, porque todas las pruebas est&eacute;n correctas, a otro tipo de minucias que, si bien no son tan importantes, acaban desgastando igualmente a ese individuo com&uacute;nmente llamado <em>neopadre</em>.</p>
<p>Por un lado tenemos la repetitiva monoton&iacute;a de las tomas cada 3 horas (creo que cualquiera que haya sido padre y vuelva a escuchar esas palabras - "<em>cada 3 horas</em>" - debe sentir escalofr&iacute;os occipitales), que adem&aacute;s, si tienes la suerte de contar con gemelos (<em>double win!</em>), se multiplican por doble trabajo y mitad de descanso, a menos que cuentes con la ayuda del encomiable&nbsp;<em>Dr. Octopus</em>.</p>
<p>Y por otro lado viene el jaleo de los papeleos, la oficialidad de los renacuajos pasa por gastar m&aacute;s gasolina (porque <em>Lugo</em> en estas fechas, diga lo que diga&nbsp;<a href="http://blog.e-shell.org">Borja</a>, no est&aacute; para mucha bicicleta) y tiempo que en cualquier otra cosa que se te ocurra. Y aqu&iacute; es donde me quiero parar a detallar el proceso, porque el resto es algo que se aprende con el tiempo y los r&iacute;os de consejos que te dar&aacute;n tus m&aacute;s cercanos. Pero los papeles, &iexcl;Ay los papeles!...</p>
<p><strong>Hospital</strong></p>
<p>En el hospital lo principal es (que todo salga bien, obviamente) estar tranquilo y disfrutar del mayor tiempo posible con tu(s) hijo(s), esas primeras horas son muy importantes y (por lo que dicen) marcan el lazo de uni&oacute;n entre padres e hijos. Sin embargo tienes que estar pendiente tambi&eacute;n de pedir en admisi&oacute;n del propio hospital (o en la propia planta, depende del funcionamiento) ciertos documentos:</p>
<ul>
<li>Justificante de ingreso de la madre.</li>
<li>Certificado de nacimiento.</li>
<li>Informe de alta de la madre.</li>
</ul>
<p>Adem&aacute;s tendr&aacute;s que rellenar (imagino que dependiendo de autonom&iacute;as y funcionamientos internos) otros papeles correspondientes con la salud del nacido:</p>
<ul>
<li>Solicitud de vacunaci&oacute;n hepatitis b.</li>
<li>Solicitud de pruebas sordera.</li>
<li>Pruebas metab&oacute;licas para detecci&oacute;n prematura de enfermedades.</li>
<li>Mont&oacute;n de informaci&oacute;n sobre lactancia y otras fases venideras.</li>
</ul>
<p><strong>Registro civil</strong></p>
<p>Una de las primeras cosas que se te pasan por la cabeza es registrar al/los renacuajos. Toda esa discusi&oacute;n por los nombres con tu pareja, suegra y dem&aacute;s familia, tienen que acabar en un papel legal firmado sellado y timbrado. En nuestro caso, en el propio hospital te indican c&oacute;mo hacer, te ofrecen El Papel Amarillo (tm) con informaci&oacute;n relativa al parto donde tendr&aacute;s que cubrir poco m&aacute;s que los datos de los progenitores y los nombres de los chavales. Todo esto se ha de entregar en el Registro Civil junto con el libro de familia, por lo que:</p>
<ul>
<li>El Papel Amarillo.</li>
<li>Encuesta del INE.</li>
<li>Libro de familia (en caso de no estar casados la chicha es mayor, pero la desconozco).</li>
<li>Fotocopia del DNI de ambos progenitores.</li>
<li>Firmar un par de documentos.</li>
</ul>
<p>En un par de d&iacute;as tendr&aacute;s que volver a recoger el libro de familia actualizado. Oficialmente a partir de ese momento ya les puedes llamar por su nombre, antes recomiendo t&eacute;rminos como <em>cacahuete</em>, <em>cosito</em>, <em>renacuajo</em>, etc...</p>
<p><strong>Certificado de empresa</strong></p>
<p>Si est&aacute;s trabajando por cuenta ajena deber&aacute;s pedirle a tu empresa un certificado de que est&aacute;s trabajando all&iacute; (&iexcl;curioso eh!). En ese papel van detalladas tambi&eacute;n las bases de cotizaci&oacute;n, necesarias para tramitar tu baja por maternidad/paternidad. Ojo, aseguraos de que el certificado de empresa va firmado y sellado por la empresa o no valdr&aacute; de mucho. Depende de la empresa podr&aacute;n pediros cierta acreditaci&oacute;n de que realmente hab&eacute;is tenido un hijo, aseguraos de llevar encima:</p>
<ul>
<li>Justificante del ingreso de la madre.</li>
<li>Informe del alta de la madre.</li>
<li>Libro de familia debidmente actualizado.</li>
</ul>
<p><strong>Padr&oacute;n</strong></p>
<p>Aunque el "derecho a una vivienda digna" no sea tal en este pa&iacute;s y, desgraciadamente, haya muchas personas sin hogar propio; hay que empadronar a tus hijos en alg&uacute;n sitio. As&iacute; que toca ir al Ayuntamiento de turno y rellenar los correspondientes formularios, para ello debemos llevar de casa:</p>
<ul>
<li>Libro de familia debidamente actualizado (y fotocopias por si acaso).</li>
<li>DNI de los progenitores.</li>
</ul>
<p><strong>Alta del beb&eacute; en la Seguridad Social</strong></p>
<p>Se tramita en la Seguridad Social y, como todo lo que se tramita en el <em>INSS</em>, dependiendo del funcionario de turno se puede contar como una experiencia maravillosa o maravillosamente traum&aacute;tica, antes de nada &iexcl;mucha suerte!. Para dar de alta en la Seguridad Social y meterlo en la cartilla de alguno de los padres es interesante saber qu&eacute; pediatra toca a cada uno, porque podr&eacute;is escoger la cartilla del padre o de la madre. Documentos imprescindibles a presentar con el correspondiente impreso:</p>
<ul>
<li>DNI de los progenitores (llevando el del que va a acoger al ni&ntilde;o en su cartilla llegar&iacute;a, pero por si las moscas llevad los 2).</li>
<li>Libro de familia debidamente actualizado.</li>
<li>Tarjeta Sanitaria del progenitor que va a acoger al ni&ntilde;o (recomendable llevar los 2).</li>
</ul>
<p><strong>Informe de Maternidad (El Papelito Azul)</strong></p>
<p>El m&eacute;dico de cabecera debe expedir este informe que har&aacute; falta posteriormente para presentar la baja por maternidad. Para ello debemos llevar:</p>
<ul>
<li>El informa de alta de la madre del hospital.</li>
<li>Libro de familia debidamente actualizado.</li>
<li>DNI de la madre.</li>
<li>Tarjeta Sanitaria de la madre.</li>
</ul>
<p><strong>Baja por paternidad/maternidad</strong></p>
<p>Tambi&eacute;n se tramita en la Seguridad Social (Instituto Nacional de la Seguridad Social, INSS, etc...). Y normalmente tiene tela porque depende de cada caso, no es lo mismo cuenta ajena que aut&oacute;nomo, etc... pero por lo general te pedir&aacute;n:</p>
<ul>
<li>DNI de los progenitores (y fotocopia del mismo).</li>
<li>Libro de familia debidamente actualizado (y fotocopia del mismo).</li>
<li>Certificado de empresa en caso de estar trabajando por cuenta ajena (y fotocopia del mismo).</li>
<li>Los 2 &uacute;ltimos cupones de aut&oacute;nomo en caso de estar dado de alta en el R.E.T.A.</li>
<li>N&uacute;mero de cuenta para la parte correspondiente de la n&oacute;mina.</li>
<li>Si la baja es por maternidad, adem&aacute;s hace falta el informe de maternidad aka El Papelito Azul (y fotocopia del mismo).</li>
</ul>
<p><strong>Solicitud de prestaciones</strong></p>
<p>Dependiendo del caso, del embarazo, del parto y de la situaci&oacute;n personal, es posible que tengas derecho a ciertas ayudas que pap&aacute; Estado concede (de momento) por traer un hijo a este mundo. Este tipo de ayudas se suelen tramitar tambi&eacute;n desde el INSS (Seguridad Social, Instituto Nacional de la Seguridad Social, etc...) y suelen tener requisitos variopintos, as&iacute; que por norma general diremos que hace falta:</p>
<ul>
<li>DNI del interesado (y fotocopia del mismo).</li>
<li>Tarjeta Sanitaria del interesado.</li>
<li>Copia de la la &uacute;ltima&nbsp;declaraci&oacute;n de la Renta.</li>
<li>N&uacute;mero de cuenta por si eres un suertudo/a y te conceden la prestaci&oacute;n.</li>
</ul>
<p>A tales momentos (<em>enero 2013</em>) creo que sigue vigente una prestaci&oacute;n de deducci&oacute;n por maternidad (100&euro;/mes durante un par de a&ntilde;os) y alguna que otra <a href="http://www.seg-social.es/Internet_1/Trabajadores/PrestacionesPension10935/Prestacionesfamilia10967/Prestacioneconomica33761/index.htm">subvenci&oacute;n por partos m&uacute;ltiples</a>&nbsp;(<a href="http://www.seg-social.es/prdi00/groups/public/documents/binario/097846.pdf">impreso</a>) o algo as&iacute;. M&aacute;s informaci&oacute;n en la propia <a href="http://www.seg-social.es/">web de la Seguridad Social</a>.</p>
<p><strong>En definitiva...</strong></p>
<p>Decir antes de nada que todo este rollo que acabo de soltar est&aacute; sujeto al funcionamiento de cada Comunidad Aut&oacute;noma, de pap&aacute; Estado e, imagino, depender&aacute; tambi&eacute;n del a&ntilde;o en el que se tramite puesto que estas cosas cambian tanto como el devenir del l&iacute;quido elemento. Ah, &iexcl;y las firmas!. No os olvid&eacute;is de fecha y firma en todos y cada uno de los papeles que se presenten, pero bueno, eso ya os lo recordar&aacute; tambi&eacute;n el funcionario de turno.</p>
<p>Con todo esto que os estoy contando no quiero decir que no est&eacute; encantado con este nuevo <em>status</em> parental, al contrario (r&iacute;os de babas salen diariamente de mi cansada boca), pero si os est&aacute;is planteando tener descendencia, contad tambi&eacute;n con estas situaciones, con&nbsp;toneladas de paciencia, gasolina en el coche, disponibilidad para hacer varios viajes a la misma ventanilla y un par de bol&iacute;grafos a mano cargados de tinta.</p>

View File

@ -0,0 +1,23 @@
---
title: "Emacs go to line y reload sin salir de Emacs"
date: 2012-08-13T19:39:29Z
draft: false
tags: [ ]
image:
---
<p>Se me hace muy c&oacute;modo tener un atajo de teclado para la t&iacute;pica orden de "<em>ir a la linea X</em>", as&iacute; que en vez de escribir todo el tochaco de comando que hace falta en Emacs para ello (<em>M-x goto-line&lt;RET&gt;#linea&lt;RET&gt;</em>) voy a hacer un binding. Abro el archivo .emacs y agrego lo siguiente:</p>
```
;; Goto-line
short-cut key(global-set-key "C-l" 'goto-line)
```
<p>Una vez guardado y para hacer efectiva la configuraci&oacute;n sin tener que salir de Emacs ejecuto lo siguiente:&nbsp;</p>
```
M-x load-file
~/.emacs
```
<p>Y ya tengo lo que quer&iacute;a, mi shortcut de "<em>ir a la linea X</em>" en <em>Ctrl + L</em>. Tip b&aacute;sico de Emacs patrocinado por chocolate blanco Mercadona y agua de mineralizaci&oacute;n muy d&eacute;bil Bezoya.</p>

View File

@ -0,0 +1,19 @@
---
title: "Fediverse"
date: 2022-05-26T07:47:24Z
draft: false
tags: []
image:
---
There is always a trigger or a reason -hidden or not- for a change. In this case it was a mix of things but it finished by discovering a totally unexpected part of Internet (to me).
Every year's resolution one of the first things that comes to mind is the desire of mitigate as much as I can the monkey scrolling (monkey? donkey?), and lately I felt that Twitter was the first candidate to be removed. Timeline was full of negative stuff, plus all the advertisements, recommendations, interests... it seemed that «the algorithm» wanted to write my present and future much better than me. And -besides that- the trigger in this case was the recently ownership changes in there.
That ended with me -and many other users- reactivating the forgotten Mastodon account -from 2017- and reading a bit more about it, what is, how it works, what's that «federation» thing, etc...
- [oscarmlage@mastodon.social](https://mastodon.social/@oscarmlage), but the next logical step is to finish the setup of [my own instance](https://mastodon.oscarmlage.com), I guess.
That's how I've discovered **the fediverse**, a really nice movement for sharing information in any kind of support (posts, microposts, images, audios, videos, etc...) but on the other hand it is about a kind of figh against the data-market that big tech companies does with our digital identities too. One of the great points on this *fedi-thing* is that you can run -and own- your instance of whatever (mastodon, peertube, pixelfed, matrix, synapse...) and be responsible about the ownership of your data. That's amazing!.
For a moment I felt that spark again when -in the late nineties- we were playing with *nix operating systems in order to have something else not owned by *that-big-company*. Great memories indeed. Now I'm wondering if is there a part of Internet shining again or maybe it was me that have been eaten by the mass media all this time?.

View File

@ -0,0 +1,11 @@
---
title: "Feeling an old techie"
date: 2015-03-25T19:00:19Z
draft: false
tags: [ ]
image: old-techie.jpg
---
<p>I was thinking about that feeling lately. It seems that I can not follow the wave out there, there are many things escaping from my comprehension due lack of time. Starting to talk about anything not related to my <em>day-by-day</em> is starting to feeling myself out of date.</p>
<p>Last days I could get some short time to read about a couple of topics - <em>frontend</em> related this time - and I felt like I was using <em>cobol</em> (nothing against <em>cobol</em> here). It's a fact you can not focus in every new brilliant and recently released piece of technology, but it's like there was an interestellar space between what I thought it was the right way and recent developments or best practices.</p>
<p>Probably have to go back to the old habit of taking Friday afternoons (or any other shift) as <em>research &amp; development</em>. Would be great.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Some files were not shown because too many files have changed in this diff Show More