Compare commits
45 Commits
feature/os
...
main
Author | SHA1 | Date |
---|---|---|
Óscar M. Lage | 4033108d3d | |
Óscar M. Lage | ca0a9adea1 | |
Óscar M. Lage | eb990ce1ee | |
Óscar M. Lage | 4dd7e2417f | |
Óscar M. Lage | 68746f9cc7 | |
Óscar M. Lage | 96650575f1 | |
Óscar M. Lage | f4eed70168 | |
Óscar M. Lage | c2eb08c66f | |
Óscar M. Lage | d6b6b1e9eb | |
Óscar M. Lage | b848307f49 | |
Óscar M. Lage | f911f0558f | |
Óscar M. Lage | 0e4369d799 | |
Óscar M. Lage | 675382e546 | |
Óscar M. Lage | 2111263b2b | |
Óscar M. Lage | b2d973fd58 | |
Óscar M. Lage | 7542264e36 | |
Óscar M. Lage | d1a3aa21a9 | |
Óscar M. Lage | b13ce821c9 | |
Óscar M. Lage | edafa02d2d | |
Óscar M. Lage | a69159700d | |
Segundo Fdez | 102c3f328f | |
Segundo Fdez | 74f7bd599c | |
Óscar M. Lage | 90fe18f51c | |
Óscar M. Lage | 28b30938f4 | |
Óscar M. Lage | d72d1451ce | |
Óscar M. Lage | ce0c12efeb | |
Óscar M. Lage | 269b08bdb4 | |
Óscar M. Lage | 54468e24e3 | |
Óscar M. Lage | 45f2aca784 | |
Óscar M. Lage | 45a05ebb04 | |
Óscar M. Lage | 5b79ac10de | |
Óscar M. Lage | 64d48fcba8 | |
Óscar M. Lage | 01d9c06d02 | |
Óscar M. Lage | def4b4aa47 | |
Óscar M. Lage | a41ab078dc | |
Óscar M. Lage | 06ba4c5f49 | |
Óscar M. Lage | db849b86c3 | |
Óscar M. Lage | 7a8f03ddf9 | |
Óscar M. Lage | 2cd0501b57 | |
Óscar M. Lage | 2533b8617f | |
Óscar M. Lage | efaedf2fd5 | |
Óscar M. Lage | 9cb56d9440 | |
Óscar M. Lage | 07544a9f07 | |
Óscar M. Lage | b156ae1483 | |
Óscar M. Lage | eb462f6c61 |
9
Makefile
|
@ -12,8 +12,11 @@ bash:
|
|||
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
|
||||
|
||||
sync:
|
||||
rsync -e ssh --progress --delete -lprtvvzog src/public/ me:/home/www/oscarmlage.com/www/
|
||||
|
|
7
TODO.md
|
@ -20,6 +20,12 @@
|
|||
- [x] Review pending texts (off-screen)
|
||||
- [x] Index
|
||||
- [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
|
||||
- [ ] Some images contains a `<p>`, get rid of it.
|
||||
- Images with p in the post content (as it is html now)
|
||||
|
@ -37,3 +43,4 @@
|
|||
- [ ] Import some other posts from other years
|
||||
- [ ] Support some thing like microposting (as bebu does)
|
||||
- [ ] Setup info?
|
||||
- [ ] @adrianmg suggested webp optimization
|
||||
|
|
|
@ -5,6 +5,7 @@ services:
|
|||
build:
|
||||
# image: klakegg/hugo:0.88.0-ext-alpine
|
||||
image: oscarmlage/hugo:0.88.0-ext-alpine
|
||||
command: build
|
||||
volumes:
|
||||
- "${PWD}/src:/src"
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: "{{ replace .Name "-" " " | title }}"
|
||||
date: {{ .Date }}
|
||||
draft: true
|
||||
image:
|
||||
---
|
|
@ -33,13 +33,18 @@ menu:
|
|||
title: "Posts"
|
||||
url: "/posts/"
|
||||
weight: 10
|
||||
- identifier: "microposts"
|
||||
name: "Social"
|
||||
title: "Social"
|
||||
url: "/microposts/"
|
||||
weight: 20
|
||||
- identifier: "archive"
|
||||
name: "Archive"
|
||||
title: "Archive"
|
||||
url: "/archive/"
|
||||
weight: 20
|
||||
weight: 30
|
||||
- identifier: "about"
|
||||
name: "About"
|
||||
title: "About"
|
||||
url: "/about/"
|
||||
weight: 30
|
||||
weight: 40
|
||||
|
|
After Width: | Height: | Size: 218 KiB |
After Width: | Height: | Size: 327 KiB |
|
@ -3,7 +3,5 @@ title: "Hero1"
|
|||
date: 2022-02-28T22:25:30Z
|
||||
draft: false
|
||||
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! ❤️ ☕
|
||||
|
||||
|
|
|
@ -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" >}}
|
After Width: | Height: | Size: 1.7 MiB |
|
@ -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 <aka the-new-place> ❤️ <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" >}}
|
After Width: | Height: | Size: 256 KiB |
|
@ -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" >}}
|
After Width: | Height: | Size: 1.4 MiB |
|
@ -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" >}}
|
After Width: | Height: | Size: 305 KiB |
|
@ -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" >}}
|
After Width: | Height: | Size: 200 KiB |
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
title: 20221031-1701
|
||||
date: 2022-10-31 17:01:40 +00:00
|
||||
draft: false
|
||||
tags: [micropost]
|
||||
image:
|
||||
---
|
||||
|
||||
<p>Today’s 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" >}}
|
|
@ -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>
|
||||
|
||||
|
|
@ -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't understand a word of Turkish but you can'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>
|
||||
|
||||
|
|
@ -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'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'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>
|
||||
|
||||
|
After Width: | Height: | Size: 150 KiB |
|
@ -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'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" >}}
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: 20221108-2326
|
||||
date: 2022-11-08 23:26:26 +00:00
|
||||
draft: false
|
||||
tags: [micropost]
|
||||
image:
|
||||
---
|
||||
|
||||
<p>That’s 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'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'm exhausted. <a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a></p>
|
||||
|
||||
|
|
@ -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'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 "<a href="https://mastodon.bofhers.es/tags/micropost" class="mention hashtag" rel="tag">#<span>micropost</span></a>" 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's a pity that <a href="https://mastodon.bofhers.es/tags/gitea" class="mention hashtag" rel="tag">#<span>gitea</span></a> doesn't have a snippets section.</p>
|
||||
|
||||
|
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 73 KiB |
|
@ -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'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've bought a new -bigger- server.</p><p>- Media storage: 30Gb.<br />- Postgres storage: 400Mb.<br />- Redis storage: 20Mb.</p><p>That'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" >}}
|
After Width: | Height: | Size: 320 KiB |
|
@ -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" >}}
|
|
@ -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 can’t be deleted, they can only be yanked. A yanked package can still be used if it is in your project’s 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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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've said it before, but I'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>
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: 20221116-1124
|
||||
date: 2022-11-16 11:24:38 +00:00
|
||||
draft: false
|
||||
tags: [micropost]
|
||||
image:
|
||||
---
|
||||
|
||||
<p>I'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>
|
||||
|
||||
|
After Width: | Height: | Size: 418 KiB |
|
@ -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" >}}
|
|
@ -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've learned.</p><p>I doubt it will be helpful to anyone but just in case I'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>
|
||||
|
||||
|
After Width: | Height: | Size: 419 KiB |
|
@ -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" >}}
|
|
@ -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: 'backup' 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>
|
||||
|
||||
|
|
@ -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'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 "client_max_body_size 100m;" 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>
|
||||
|
||||
|
|
@ -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'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>
|
||||
|
||||
|
|
@ -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 "cowork mate" 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>
|
||||
|
||||
|
After Width: | Height: | Size: 954 KiB |
|
@ -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's called Secret Santa (we call it "amigo invisible" 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" >}}
|
|
@ -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>
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: 20230112-1101
|
||||
date: 2023-01-12 11:01:35 +00:00
|
||||
draft: false
|
||||
tags: [micropost]
|
||||
image:
|
||||
---
|
||||
|
||||
<p>I'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>
|
||||
|
||||
|
|
@ -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á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í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á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ía nada de un aumento considerable de visitas -más bien al contrario- y el resto de herramientas de monitorización parecían cómplices del problema (¡tener <em>tools</em> para ésto!).</p>
|
||||
<p>
|
||||
En un alarde de desesperación y viendo más o menos por dónde podían venir los tiros -a través del método de <em>prueba y error</em>- localicé el <em>VirtualHost</em> que estaba dando problemas, un código no auditado y afamado por su ausente optimización. Vamos que ya tenía precedentes, aunque ninguno de esta índole.</p>
|
||||
<p>
|
||||
Después de desactivar distintas partes del dominio en más pruebas esperando focalizar el error en algún script concreto, la conclusión es que tenía que ser algo que se incluía en todos los archivos, algo común a toda la web. Así que miramos los <em>includes</em> comunes (si, PHP) y llegamos a la conclusió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ón a <strong>3 días</strong>, definir el directorio donde se guardarán los archivos de sesión y arrancar la sesión. Probablemente el programador no esperaba tener <em>60k</em> visitas y más de <em>200k</em> páginas vistas en los 3 días que dura cada sesión, pero está claro que para <em>apache2</em> suponía un problema el acceso de lectura/escritura a un mismo directorio con más de <em>90k</em> archivos.</p>
|
||||
<p>
|
||||
La solución inicial -a falta de más tiempo para cambiar el sistema de sesiones a <em>memcache</em>, <em>Redis</em> o cualquier otra solución basada en RAM- era sencilla, reducir el tiempo de sesió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és de todo la carga se ha vuelto a estabilizar entre <em>0.30</em> y <em>0.40</em>.</p>
|
||||
<p>
|
||||
No sé si estoy para moralejas porque la solución es temporal, pero como <a href="http://twitter.com/#!/r0sk/status/100688297642311681">lo prometido es deuda</a> me gustaría terminar esta anotación advirtiendo a todo el mundo sobre la fiabilidad del código no auditado, el uso moderado de las sesiones y las endorfinas que libera uno cuando consigue resolver algo <em>"así"</em>.</p>
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
title: "Apache + Squid + Nginx"
|
||||
date: 2011-10-28T23:50:34Z
|
||||
draft: false
|
||||
tags: [ ]
|
||||
image:
|
||||
---
|
||||
|
||||
<p>
|
||||
¡Menuda combinación!. A decir verdad empecé jugando un poco con el maldito <em>slowloris</em> y al final acabé 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ón del blog - <em>que me gustaría estrenar con el décimo aniversario de este humilde rinconcito</em> -.</p>
|
||||
<p>
|
||||
En un esquema inicial analógico de esos que tantos nos gustan podemos ver la pirula (pido perdó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áfico dinámico al 81 a la vez que responde al tráfico estático de ciertos subdominios (static*) de forma automática y en la misma instancia. Pero tenía la tarde libre y me apetecía probar una configuración <em>rara</em> con Squid.</p>
|
||||
<p>
|
||||
<strong>Apache</strong></p>
|
||||
<p>
|
||||
La configuración de Apache es de lo más sencilla, lo único que he hecho ha sido ponerlo a escuchar en el puerto 81 por defecto, y a todos sus <em>Virtualhosts</em> también. No había mucho más que tocar puesto que ya tenía el <em>mod_php</em> y todas las dependencias instaladas.</p>
|
||||
<p>
|
||||
<strong>Nginx</strong></p>
|
||||
<p>
|
||||
Nunca había jugado con él y a primera vista me gustó la sencillez de sus archivos de configuración. Tampoco tenía que hacer gran cosa, ponerlo a escuchar en el puerto 82 y poco más puesto que sólo serviría contenido estático. Creé los <em>Virtualhosts</em> que atenderían las peticiones estáticas, los activé vía enlace simbólico a <em>sites-enabled</em> y poco más. La configuració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í vino la diversión, ¿cómo decirle a Squid que balanceara el tráfico dinámico al puerto 81 y el estático al puerto 82?. Después de leer la documentación y hacer varias pruebas con <em>cache_peer</em>, y <em>cache_peer_domain</em> he llegado a la conclusión que la configuración "<em>buena</em>" 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ía que cambiar <em>ip</em> por la ip pública correspondiente y los <em>fqdn</em> por los reales.</p>
|
||||
<p>
|
||||
<strong>Conclusión</strong></p>
|
||||
<p>
|
||||
He pasado una tarde agradable en compañía de mis amigos los servidores web. No, en serio, al final he conseguido reproducir el escenario que me había propuesto, (aún sabiendo que se podría mejorar), he frenado los sockets incompletos de Apache y he preparado el servidor para servir estáticos de forma independiente del contenido dinámico (que en breve cambiará de PHP a Python + Django).</p>
|
||||
<p>
|
||||
No ha estado mal :).</p>
|
After Width: | Height: | Size: 112 KiB |
|
@ -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>, </span><a href="https://twitter.com/ErrataRob/status/514839781881032705" target="_blank">Twitter</a>.</p>
|
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 155 KiB |
|
@ -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".
|
|
@ -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!.
|
|
@ -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 <span class="search_hit">OVH</span> es que los kernels que habilitan por defecto (<span class="search_hit">OVH</span> + grsec), además de venir con grsec como su propia descripción indica, no tienen soporte para instalar módulos de <span class="search_hit">kernel</span>. De forma que al intentar instalar el módulo para NFS nos dará un fantá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í que no queda otra que reemplazar el <span class="search_hit">kernel</span> por uno que ya lleve el módulo de nfs <em>builtin. </em>Llegados a este punto tenemos varias opciones: instalar un <span class="search_hit">kernel</span> desde fuentes, modificar el ya instalado o bajarnos uno de los kernels ”<em>-filer</em>” de <span class="search_hit">OVH</span>. Los kernels "<em>-filer</em>" están pensados para este tipo de servidores de ficheros. Por sencillez optaremos por esta tercera opción.</p>
|
||||
<p>Primeramente descargamos las imágenes del nuevo kernel que vamos a instalar desde el ftp oficial de <span class="search_hit">OVH</span> (<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áquina lo haga con el nuevo <span class="search_hit">kernel</span>. Lo hacemos editando el fichero <em>/etc/grub.d/06_OVHkernel</em>, en la línea que antes hacía referencia al <span class="search_hit">kernel </span><em>bzImage*64</em> ahora le agregamos un <em>-filer</em> y guardamos los cambios:</p>
|
||||
|
||||
```
|
||||
OS="Debian GNU/Linux"
|
||||
LINUX_ROOT_DEVICE=${GRUB_DEVICE}
|
||||
linux=`ls -1 -t /boot/bzImage*64-filer 2>/dev/null | head -n1`
|
||||
```
|
||||
|
||||
<p>Una vez tenemos el nuevo <span class="search_hit">kernel</span> referenciado en el archivo de plantilla <em>06_OVHkernel</em>, ejecutamos el <em>grub-mkconfig</em> para hacer efectiva la configuración, es recomendable hacer antes una copia de seguridad de la configuración anterior (sabe más el diablo por viejo que por diablo):</p>
|
||||
|
||||
```
|
||||
# cp /boot/grub/grub.cfg /boot/grub/grub.cfg.old
|
||||
# grub-mkconfig > /boot/grub/grub.cfg
|
||||
```
|
||||
|
||||
<p>Finalmente toca reiniciar, cruzar los dedos y, si todo ha ido correctamente, comprobar que ya tenemos el nuevo <span class="search_hit">kernel</span> 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ñoso pensar en montar un NFS sobre OVH como una trivial tarea de poco más de 5 minutos. </p>
|
|
@ -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ía no llego a entender ni asimilar. He pasado la mayor parte de la tarde para configurar la nueva versión 2.0 de <a href="https://github.com/philsturgeon/codeigniter-reactor/">CodeIgniter-Reactor</a> con varias librerías que, para mi forma de desarrollar, son indispensables en cualquier framework de programación orientado a web:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc">HMVC</a>: Gracias a la librería de <em>Wiredesignz</em> podemos ordenar nuestro código en módulos y simplificar la lógica de la aplicación.</li>
|
||||
<li>
|
||||
<a href="https://github.com/pyrocms/pyrocms/tree/master/system/pyrocms/modules/modules">ModulesModule</a>: Ahora que todo será un módulo, no vendría mal un módulo encargado de ejecutar las tareas más comunes de los módulos (instalar, desinstalar, actualizar...). Un módulo de módulos.</li>
|
||||
<li>
|
||||
<a href="https://github.com/pyrocms/pyrocms/tree/master/system/pyrocms/modules/settings">SettingsModule</a>: No me gusta cargar la configuración desde ficheros <em>config/*</em>, por comodidad y para que el usuario pueda cambiar cualquier parámetro ajustable de una aplicación, prefiero hacerlo en base de datos y cachearlo a disco si es necesario. Me quedo con la librerí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ística imprescindible sería tener una aplicación <em>themeable</em> y que desde un interfaz de administración se pueda cambiar tranquilamente el aspecto de la misma. Para ello podemos hacer uso de este mó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ón <em>modular</em> y <em>themeable</em> siguiendo el patrón <em>MVC</em>, un buen lenguaje de <em>template</em> para que los diseñadores no se vuelvan locos con el lenguaje dinámico sería un punto má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ía para hacer migraciones de versiones en base de datos. Gestiona los cambios entre versiones de forma sencilla.</li>
|
||||
</ul>
|
||||
<p>
|
||||
<!--more-->Como podéis ver siguiendo los enlaces, casi todo lo necesario para montar el esquema inicial de un framework PHP decente está 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ísticas pero tiene muchas otras librerí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ás o menos todo ya no tengo ganas de empezar a programar la aplicación que tenía en mente. ¿Por qué no hay *nada* con todas esas funciones de serie en PHP?. Si, ya sé 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ísticas -y más- en un par de comandos, pero tenía que desengañarme.</p>
|
||||
<p>
|
||||
En este sentido PHP sigue estando tan verde como hace años, me hace perder demasiado tiempo aú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>
|
|
@ -0,0 +1,255 @@
|
|||
---
|
||||
title: "Desarrollo web con Python: Flask"
|
||||
date: 2012-02-15T18:47:34Z
|
||||
draft: false
|
||||
tags: [ ]
|
||||
image:
|
||||
---
|
||||
|
||||
<p>
|
||||
Hace algún tiempo empecé 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é exponer un pequeño ejemplo para que os hagáis una idea de có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/">Á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ón, no quería ser menos y explicar mis aventuras y desventuras con esta otra pequeña joya de Python así que allá vamos.</p>
|
||||
<p>
|
||||
<!--more--></p>
|
||||
<p>
|
||||
<strong>Instalación </strong></p>
|
||||
<p>
|
||||
Flask está basado en <a href="http://werkzeug.pocoo.org/">Werkzeug</a>, una librerí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ón que <a href="http://www.userlinux.net/django-virtualenv-pip.html">ya he explicado en su día</a>) vemos que las dependencias de Flask son mí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>=0.6.1 (from flask)
|
||||
Downloading/unpacking Jinja2>=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 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én instalamos <a href="http://packages.python.org/Flask-WTF/">Flask-WTF</a> para tener integración con <em>WTForms</em> y hacer más sencillo el uso de formularios con funciones avanzadas (csrf, etc...). Y por último <em>Flask-SQLAlchemy </em>como complemento ORM para la base de datos.</p>
|
||||
<p>
|
||||
<strong>Requirements y configuración</strong></p>
|
||||
<p>
|
||||
A continuació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áquinas como queramos:</p>
|
||||
|
||||
```
|
||||
$ source env/bin/activate
|
||||
(env)$ pip freeze > 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ón dentro del directorio <em>src/ </em>creando un directorio para los templates, como queremos que nuestra aplicación pueda tener varios templates a elegir, creamos también el "por defecto":</p>
|
||||
|
||||
```
|
||||
(env)$ mkdir -p templates/default/
|
||||
```
|
||||
|
||||
<p>
|
||||
Ya que estamos empezando una aplicación desde cero nos gustaría tener un mínimo de configuración para la misma así 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, 'data')
|
||||
DEFAULT_TPL = 'default'
|
||||
USERNAME = 'admin'
|
||||
PASSWORD = 'default'
|
||||
SECRET_KEY = 'devel secret key'
|
||||
URL = 'http://localhost:5000/'
|
||||
TITLE = 'OurApplication'
|
||||
VERSION = '0.1'
|
||||
LANG = 'es'
|
||||
LANG_DIRECTION = 'ltr'
|
||||
YEAR = '2012'
|
||||
del os
|
||||
```
|
||||
|
||||
<p>
|
||||
Con la configuración y el entorno listos, lo siguiente será empezar la aplicación propiamente dicha, así que manos a la obra.</p>
|
||||
<p>
|
||||
<strong>Primeros pasos con Flask</strong></p>
|
||||
<p>
|
||||
Vamos a reducir el grueso de la aplicación a un solo archivo, le llamaremos <em>blog.py </em>- ya sé que no suena muy original pero imagino que será entendible -. Nuestro <em>blog.py</em> será el controlador principal, en él incluiremos de forma excepcional el modelo, los formularios y los métodos que se encargarán de la lógica y de llamar a las plantillas. Para empezar por el principio definimos el archivo como una aplicación Flask y cargamos la configuración que antes hemos creado:</p>
|
||||
|
||||
```
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
OurApplication
|
||||
~~~~~~~~~~~~~~
|
||||
:copyright: (c) 2011 by Oscar M. Lage.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
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('config')
|
||||
# Middleware to serve the static files
|
||||
from werkzeug import SharedDataMiddleware
|
||||
import os
|
||||
app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
|
||||
'/': os.path.join(os.path.dirname(__file__), 'templates', app.config['DEFAULT_TPL'])
|
||||
})
|
||||
# Index
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template(app.config['DEFAULT_TPL']+'/index.html',
|
||||
conf = app.config)
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
```
|
||||
|
||||
<p>
|
||||
* Lo más raro son esas 3 lineas que hemos incluido en el archivo, una especie de <em>Middleware</em> para poder servir archivos estáticos directamente desde el template seleccionado.</p>
|
||||
<p>
|
||||
Una vez tenemos la aplicación "preparada" 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ía ser algo así:</p>
|
||||
|
||||
```
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="{{ conf['LANG'] }}" lang="{{ conf['LANG'] }}"
|
||||
dir="{{ conf['LANG_DIRECTION'] }}">
|
||||
<head>
|
||||
<title>{% block title %}{% endblock %} [{{ conf['TITLE'] }}]</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<h1>{{ conf['TITLE'] }}</h1>
|
||||
</div>
|
||||
<div id="content">
|
||||
Contenido
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>{{ conf['TITLE'] }} - {{ conf['YEAR'] }}</p>
|
||||
</div>
|
||||
</body>
|
||||
```
|
||||
|
||||
<p>
|
||||
Y ya podríamos ejecutar por primera vez nuestra aplicación desde consola para luego comprobar que todo está correcto en navegador, así 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ón vamos a incorporar una base de datos para hacerla diná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ón para la base de datos:</p>
|
||||
|
||||
```
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///'+ os.path.join(os.path.dirname(__file__), 'database.db')
|
||||
```
|
||||
|
||||
<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__ = 'Blog'
|
||||
__mapper_args__ = dict(order_by="date desc")
|
||||
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 ú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>
|
||||
|
||||
```
|
||||
>>> from blog import db
|
||||
>>> db.create_all()
|
||||
```
|
||||
|
||||
<p>
|
||||
Ya tenemos el archivo <em>database.db</em> preparado para cargarlo de datos mediante los métodos correspondientes de <em>blog.py</em>, algunos ejemplos:</p>
|
||||
|
||||
```
|
||||
@app.route('/add', methods=['GET','POST'])
|
||||
def add():
|
||||
if request.method == 'POST':
|
||||
post = Blog(request.form['subject'], request.form['content'])
|
||||
db.session.add(post)
|
||||
db.session.commit()
|
||||
return redirect(url_for('index'))
|
||||
return render_template(app.config['DEFAULT_TPL']+'/add.html',
|
||||
conf = app.config)
|
||||
```
|
||||
|
||||
<p>
|
||||
<strong>Flask-WTForms</strong></p>
|
||||
<p>
|
||||
Una vez tenemos preparada la base de datos y el método que agregará nuevos posts tan solo falta crear el formulario que nos permitirá tal funcionalidad y crear el template, poco más de un par de lineas:</p>
|
||||
|
||||
```
|
||||
# Create Form
|
||||
class CreateForm(Form):
|
||||
subject = TextField('Subject', [validators.required()])
|
||||
content = TextAreaField('Content', [validators.required(), validators.Length(min=1)])
|
||||
```
|
||||
|
||||
<p>
|
||||
Y el template con el formulario correspondiente sería el siguiente:</p>
|
||||
|
||||
```
|
||||
<form method="post" action="">
|
||||
<dl>
|
||||
{{ form.csrf }}
|
||||
{{ form.subject.label }} {{ form.subject(style="width:100%") }}
|
||||
{% for error in form.subject.errors %} {{ error }} {% endfor %}
|
||||
<br />
|
||||
{{ form.content.label }} {{form.content(style="height:100px;width:100%") }}
|
||||
{% for error in form.content.errors %} {{ error }} {% endfor %}
|
||||
</dl>
|
||||
<p><input type="submit" value="submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
<p>
|
||||
Y ya tendrí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ás abajo), tendríamos una pequeña aplicación con <em>Flask</em> + <em>SQLAlchemy</em> + <em>WTForms</em>.</p>
|
||||
<p>
|
||||
<strong>Resumiendo</strong></p>
|
||||
<p>
|
||||
Para finalizar, además de las vistas que hemos dicho que faltaban, tendríamos que dar un poco más de colorido a los templates (css, imá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ás en el artículo, nada mejor que un pequeñ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ño y humilde ejemplo haya quedado má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>
|
After Width: | Height: | Size: 171 KiB |
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 171 KiB |
|
@ -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>
|
|
@ -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 <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> <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> 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 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>
|
After Width: | Height: | Size: 16 KiB |
|
@ -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ón suelen ser bastante diferentes. Quizás en el primero buscas la comodidad mientras que cuando se hace el <em>deploy</em> a producció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ómodo utilizar <em>sqlite </em>porque no requiere de ningún servidor adicional y está soportado de base en Django (<em>builtin</em>). Es posible que una vez acabado el desarrollo queramos cambiar a otro <em>SGBD</em> "de verdad" como pueden ser <em>MySQL</em> o <em>PostgreSQL</em>.</p>
|
||||
<p>
|
||||
Lo que podrí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 > 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> para hacer un dumpeado de todos los datos de la aplicación (sqlite) en formato json, posteriormente pasamos ese archivo al entorno de producción (en este caso pongamos de ejemplo a otro servidor) y allí 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à!</p>
|
After Width: | Height: | Size: 3.0 KiB |
|
@ -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 <a href="../../../../blog/symfony2-en-un-hosting-compartido.html">Symfony2 project in a shared hosting</a> (Spanish article) and now the big next deal is a similar task with <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 <a href="http://ailalelo.com/">Ailalelo's mates</a> (they had lot of experience with this kind of situations) I found the proper configuration.</p>
|
||||
<p>Hosting is <em>django-ready</em>, but the version they're running (<em>1.4.2</em>) is not the best choice, I want to install <em>1.6.x</em>, the one I have used to develop the project. The other big requirement is <em>virtualenv+pip</em> to retrieve the packages I'm using.</p>
|
||||
<p>Mainly I've solved it with two files, <code>project.cgi</code> and <code>.htaccess</code>.</p>
|
||||
<h2>project.cgi</h2>
|
||||
<p>The hosting structure is like many others, I have access to a <em>homedir</em> 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 <code>virtualenv</code> and all the requirements, my choice is to put the environment out of the <code>www/</code> 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 <em>mod_cgi</em> will process all the files you put in the <code>cgi-bin</code> directory, so we already know where to save our <code>project.cgi</code>. I have to tell apache to use my own <em>virtualenv</em> <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 <code>less</code> binary, required for <a href="http://django-compressor.readthedocs.org/en/latest/">django-compressor</a> package. In this particular case my user was not allowed to install <em>node/less</em> in the system, so I had to install it locally, referencing the particular <code>node_modules</code> folder.</p>
|
||||
<h2>.htaccess</h2>
|
||||
<p>Now that Apache knows what to do, we should redirect almost all the incoming traffic to the <em>cgi</em>, so let's write some<code>.htaccess</code> 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 <code>media/</code> and <code>static/</code> 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 <a href="http://stackoverflow.com/">stackoverflow</a> is to have it a half fixed ;).</li>
|
||||
</ul>
|
||||
<p> </p>
|
||||
<ul>
|
||||
</ul>
|
|
@ -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és por el <a href="http://www.vamosavidas.com/foros/">foro de VamosaVidas</a> (si, ese que rompí en su dí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í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> es un poco coñazo andar mirando en el admin el último usuario bueno y borrar manualmente uno a uno cotejando que no me equivoque, así que he pensado en un par de lineas que no deberían hacer demasiado daño si se usan con precaución. Desde la shell de nuestro proyecto podemos hacer algo así:</p>
|
||||
|
||||
```
|
||||
$ python manage.py shell
|
||||
>>> from django.contrib.auth.models import User
|
||||
>>> list(User.objects.order_by('date_joined'))
|
||||
>>> [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>
|
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
title: "Django + virtualenv + pip"
|
||||
date: 2011-02-23T21:37:56Z
|
||||
draft: false
|
||||
tags: [ "django", "code" ]
|
||||
image:
|
||||
---
|
||||
|
||||
<p>No lo tenía claro, pero cuando entendí lo que suponía y cómo se trabajaba con <em>virtualenv</em> + <em>pip</em> me decidí a probarlo. Voy a <em>intentar</em> explicar como se utilizan estas herramientas de una forma gené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ás explicació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í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ó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é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ódigo fuente (podemos tirar de repositorio o iniciar nuestro proyecto directamente ahí), 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ó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á 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íamos hacer lo mismo con la orden <em>pip freeze </em>como se muestra a continuació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á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áquina. Insisto, todos estos comandos pueden ejecutarse dentro del entorno (env) o fuera del mismo con la opción <em>-E entorno</em> de <em>pip</em>:</p>
|
||||
|
||||
```
|
||||
(env)$ cd foo/src/
|
||||
(env)$ pip freeze > 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á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á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í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é 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ón</strong></p>
|
||||
<p><em>Virtualenv</em> y <em>pip</em> forman una combinación excelente de elementos para hacer de un proyecto un <em>ente</em> sin dependencias frustradas y con todos los requisitos y versiones específicas para garantizar el correcto funcionamiento del mismo. Ahora, por lo que me han contado, deberí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>
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
title: "Dovecot, pequeñas peculiaridades"
|
||||
date: 2010-09-07T09:20:13Z
|
||||
draft: false
|
||||
tags: [ "dovecot" ]
|
||||
image:
|
||||
---
|
||||
|
||||
<p>
|
||||
Desde hace algún tiempo -y despué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áquinas en producción. Por varios motivos: la sencillez de configuración, sigue los estándares, soporta <em>mbox</em> y <em>Maildir</em> y algo muy importante, tiene un backend de autentificació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ónico es el menos agradecido y probablemente el más doloroso para el <em>sysadmin</em> pero el haber dado con esta combinación de elementos me ha ahorrado un montón de problemas.</p>
|
||||
<p>
|
||||
De todos modos en la última instalación que me ha tocado he encontrado un par de peculiaridades que me gustaría documentar por si alguien se encuentra en la misma situación.<!--more--></p>
|
||||
<p>
|
||||
Habiendo instalado el mismo O.S., las mismas versiones de software y exactamente los mismos ficheros de configuració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í sin más descripción no puedo adivinar mucho así que decido activar errores en <em>dovecot.conf</em> con la directiva de configuración <em>log_path = /var/log/<span class="search_hit">dovecot</span>.log.</em> Ahora sí podemos sacar más información del <em>dovecot.log</em>:</p>
|
||||
|
||||
```
|
||||
Fatal: postmaster_address setting not given
|
||||
```
|
||||
|
||||
<p>
|
||||
Esto ya es otra cosa, después de un poco de <em>googling</em> corrijo el fallo agregando al fichero de configuración una dirección de postmaster, sigue pareciéndome raro porque <em>/etc/aliases</em> es el mismo que otras máquinas y nunca había notificado este problema antes pero bueno, es cuestión de agregar a <em>dovecot.conf</em> 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ía siguiente me encuentro con el servicio parado, vuelvo a reiniciar y el proceso se vuelve a parar cada día, repitiendo la jugada. Volviendo a los logs -ese gran invento- veo que todos los dí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'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í me ha supuesto algo de tiempo saber el origen de los errores para poder subsanarlos así que bueno, si al menos esta entrada ayuda a alguien o le ahorra algún dolor de cabeza me daré por contento.</p>
|
|
@ -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.
|
|
@ -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ón y felicidad máximos, vuelves a casa para que la realidad trate de despertarte a golpe de pequeñas bofetadas. O eso es lo que me está pasando a mi. Pasas de preocuparte porque todo salga bien en la eco, porque no haya ninguna complicación en el momento del parto, porque todas las pruebas estén correctas, a otro tipo de minucias que, si bien no son tan importantes, acaban desgastando igualmente a ese individuo comúnmente llamado <em>neopadre</em>.</p>
|
||||
<p>Por un lado tenemos la repetitiva monotoní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íos occipitales), que ademá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 <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ás gasolina (porque <em>Lugo</em> en estas fechas, diga lo que diga <a href="http://blog.e-shell.org">Borja</a>, no está para mucha bicicleta) y tiempo que en cualquier otra cosa que se te ocurra. Y aquí es donde me quiero parar a detallar el proceso, porque el resto es algo que se aprende con el tiempo y los ríos de consejos que te darán tus más cercanos. Pero los papeles, ¡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ón entre padres e hijos. Sin embargo tienes que estar pendiente también de pedir en admisió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ás tendrás que rellenar (imagino que dependiendo de autonomías y funcionamientos internos) otros papeles correspondientes con la salud del nacido:</p>
|
||||
<ul>
|
||||
<li>Solicitud de vacunación hepatitis b.</li>
|
||||
<li>Solicitud de pruebas sordera.</li>
|
||||
<li>Pruebas metabólicas para detección prematura de enfermedades.</li>
|
||||
<li>Montón de informació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ón por los nombres con tu pareja, suegra y demás familia, tienen que acabar en un papel legal firmado sellado y timbrado. En nuestro caso, en el propio hospital te indican cómo hacer, te ofrecen El Papel Amarillo (tm) con información relativa al parto donde tendrás que cubrir poco má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ías tendrá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érminos como <em>cacahuete</em>, <em>cosito</em>, <em>renacuajo</em>, etc...</p>
|
||||
<p><strong>Certificado de empresa</strong></p>
|
||||
<p>Si estás trabajando por cuenta ajena deberás pedirle a tu empresa un certificado de que estás trabajando allí (¡curioso eh!). En ese papel van detalladas también las bases de cotizació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á de mucho. Depende de la empresa podrán pediros cierta acreditación de que realmente habé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ón</strong></p>
|
||||
<p>Aunque el "derecho a una vivienda digna" no sea tal en este país y, desgraciadamente, haya muchas personas sin hogar propio; hay que empadronar a tus hijos en algún sitio. Así 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é 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ática, antes de nada ¡mucha suerte!. Para dar de alta en la Seguridad Social y meterlo en la cartilla de alguno de los padres es interesante saber qué pediatra toca a cada uno, porque podré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ño en su cartilla llegarí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ño (recomendable llevar los 2).</li>
|
||||
</ul>
|
||||
<p><strong>Informe de Maternidad (El Papelito Azul)</strong></p>
|
||||
<p>El médico de cabecera debe expedir este informe que hará 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é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ónomo, etc... pero por lo general te pedirá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 últimos cupones de autónomo en caso de estar dado de alta en el R.E.T.A.</li>
|
||||
<li>Número de cuenta para la parte correspondiente de la nómina.</li>
|
||||
<li>Si la baja es por maternidad, ademá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ón personal, es posible que tengas derecho a ciertas ayudas que papá Estado concede (de momento) por traer un hijo a este mundo. Este tipo de ayudas se suelen tramitar también desde el INSS (Seguridad Social, Instituto Nacional de la Seguridad Social, etc...) y suelen tener requisitos variopintos, así 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 última declaración de la Renta.</li>
|
||||
<li>Número de cuenta por si eres un suertudo/a y te conceden la prestación.</li>
|
||||
</ul>
|
||||
<p>A tales momentos (<em>enero 2013</em>) creo que sigue vigente una prestación de deducción por maternidad (100€/mes durante un par de años) y alguna que otra <a href="http://www.seg-social.es/Internet_1/Trabajadores/PrestacionesPension10935/Prestacionesfamilia10967/Prestacioneconomica33761/index.htm">subvención por partos múltiples</a> (<a href="http://www.seg-social.es/prdi00/groups/public/documents/binario/097846.pdf">impreso</a>) o algo así. Más informació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á sujeto al funcionamiento de cada Comunidad Autónoma, de papá Estado e, imagino, dependerá también del año en el que se tramite puesto que estas cosas cambian tanto como el devenir del líquido elemento. Ah, ¡y las firmas!. No os olvidéis de fecha y firma en todos y cada uno de los papeles que se presenten, pero bueno, eso ya os lo recordará también el funcionario de turno.</p>
|
||||
<p>Con todo esto que os estoy contando no quiero decir que no esté encantado con este nuevo <em>status</em> parental, al contrario (ríos de babas salen diariamente de mi cansada boca), pero si os estáis planteando tener descendencia, contad también con estas situaciones, con toneladas de paciencia, gasolina en el coche, disponibilidad para hacer varios viajes a la misma ventanilla y un par de bolígrafos a mano cargados de tinta.</p>
|
|
@ -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ómodo tener un atajo de teclado para la típica orden de "<em>ir a la linea X</em>", así que en vez de escribir todo el tochaco de comando que hace falta en Emacs para ello (<em>M-x goto-line<RET>#linea<RET></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ón sin tener que salir de Emacs ejecuto lo siguiente: </p>
|
||||
|
||||
```
|
||||
M-x load-file
|
||||
~/.emacs
|
||||
```
|
||||
|
||||
<p>Y ya tengo lo que quería, mi shortcut de "<em>ir a la linea X</em>" en <em>Ctrl + L</em>. Tip básico de Emacs patrocinado por chocolate blanco Mercadona y agua de mineralización muy débil Bezoya.</p>
|
|
@ -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?.
|
|
@ -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 & development</em>. Would be great.</p>
|
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 2.4 MiB |
After Width: | Height: | Size: 2.5 MiB |
After Width: | Height: | Size: 671 KiB |
After Width: | Height: | Size: 387 KiB |
After Width: | Height: | Size: 492 KiB |
After Width: | Height: | Size: 454 KiB |
After Width: | Height: | Size: 593 KiB |
After Width: | Height: | Size: 738 KiB |
After Width: | Height: | Size: 251 KiB |
After Width: | Height: | Size: 1.4 MiB |
After Width: | Height: | Size: 813 KiB |
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 2.0 MiB |
After Width: | Height: | Size: 904 KiB |
After Width: | Height: | Size: 2.1 MiB |
After Width: | Height: | Size: 797 KiB |
After Width: | Height: | Size: 858 KiB |
After Width: | Height: | Size: 2.4 MiB |
After Width: | Height: | Size: 1.7 MiB |