Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

Nikola: Filters & Bundles

Two up­com­ing fea­tures for the next re­lease of Niko­la, my stat­ic site gen­er­a­tor, due some­time in Au­gust.

Filters

Fil­ters let you post­pro­cess your out­put. Think of it like in­sta­gram for web­sites, but use­ful. You can con­fig­ure per file ex­ten­sion a se­ries of python func­tions or shell com­mand­s, which will be ap­plied in place to the out­put file.

For ex­am­ple, sup­pose you want to ap­ply yui-­com­pres­sor to your CSS and JS files:

FILTERS = {
    ".css": [filters.yui_compressor],
    ".js": [filters.yui_compressor],
}

There, filters.yui_compressor is a simple wrapper around the command so that it applies in-place to the output files.

If you use strings there (untest­ed), they are tak­en as com­mand­s. The "%s" will be re­placed by the file­name, the usu­al crazy shell quot­ing rules ap­ply:

FILTERS = {
    ".jpg": ["jpegoptim '%s'"],
    ".png": ["pngoptim '%s'"],
}

Keep in mind that the fil­ters mod­i­fy the out­put of Niko­la, not the in­put, so your im­ages, CSS, and JS files will not be touched in any way. And of course chang­ing the fil­ters ap­plied to a file will force a re­build, so you can ex­per­i­ment freely.

Bundles

Hav­ing many sep­a­rate CSS or JS files is usu­al­ly a nono for per­for­mance rea­sons be­cause each one may in­volve a sep­a­rate HTTP trans­ac­tion. The so­lu­tion is to "bundle" those files in a sin­gle, larg­er file.

The rea­son not to do that is that usu­al­ly it means hav­ing a huge, un­com­fort­able thing to han­dle. So Niko­la tries to give you the best of both world­s, by let­ting you have sep­a­rate files, and bundling them (or not) on build.

There is a new option, USE_BUNDLES that defaults to False, and there are some changes in the theme templates so that it uses the bundled version when needed.

This was on­ly pos­si­ble thanks to We­bas­sets. How­ev­er, if you don't have We­bas­sets in­stalled, or you don't en­able USE_BUNDLES, this should cause no changes in the out­put.

Conclusion

These new fea­tures will al­low Niko­la users to im­prove their site's per­for­mance with min­i­mal tweak­ing, which is al­ways a good thing.

El Server Mínimo

En­ton­ces hoy en la ho­ra del al­muer­zo me pu­se a lim­piar la ba­su­ra. Es­te post des­cri­be con qué ter­mi­né, que es el ser­ver mí­ni­mo que me sir­ve pa­ra al­go.

Hosting

Es un VPS ba­ra­to pro­vis­to por los ami­gos de burs­t.­net que no me pa­gan pa­ra de­cir co­sas bue­nas de su ser­vi­cio. Sin em­bar­go, las di­go igua­l:

  • Muy ba­­ra­­to (U$S 5.50 pe­­ro ten­­go 20% de des­­cuen­­to pa­­ra sie­m­­pre)

  • Ba­s­­tan­­te tran­s­­fe­­ren­­cia ca­­da mes

  • Mu­­cho es­­pa­­cio

  • Buen up­­ti­­me

  • Red rá­­pi­­da

  • Muy ba­­ra­­to

  • Pe­r­­fo­r­­man­­ce de­­cen­­te

  • Ba­­ra­­to

Distribución

Ya te­nía Cen­tOS 5, y si­gue ahí. Si burst al­gu­na vez ofre­ce Ubun­tu Pre­ci­se, ca­paz que cam­bio. O, ya que es­to an­da, ca­paz que no.

Lo bue­no de Cen­tO­S: es­ta­ble y abu­rri­do.

Lo ma­lo de Cen­tO­S: es un po­co de­ma­sia­do abu­rri­do. Mon­to­nes de co­sas sim­ple­men­te no es­tán em­pa­que­ta­da­s.

Web Server

Ten­go que ser­vir una canti­dad de do­mi­nio­s, pe­ro con una pe­cu­lia­ri­da­d: son to­dos si­tios es­tá­ti­co­s. Lo que quie­ro es:

  • Ba­­jo uso de re­­cu­r­­sos

  • Pe­r­­fo­r­­man­­ce de­­cen­­te (con ran­­gos y ne­­go­­­cia­­ción de co­n­­te­­ni­­do­­s)

  • Es­­ta­­ble

  • Con ín­­di­­ces de di­­re­c­­to­­­rio

  • Fá­­cil de co­n­­fi­­gu­­rar

  • Do­­­mi­­nios vi­r­­tua­­les por no­m­­bre

Ca­si cual­quier ser­vi­dor an­da pa­ra es­to. Has­ta Apa­che, ex­cep­to por eso de la con­fi­gu­ra­ción sen­ci­lla. Ter­mi­né con ga­tling por­que cum­ple esos cri­te­rios bas­tan­te bien.

  • Usa al­­re­­de­­dor de 1.4MB de RAM que es­­tá bue­­no en un VP­S.

  • Es ba­s­­tan­­te rá­­pi­­do

  • Lle­­va ho­­­ras sin caer­­se

  • Ge­­ne­­ra ín­­di­­ces

  • Es­­ta es la co­n­­fi­­gu­­ra­­ció­­n: "-c /s­r­­v/www -P 2M -d -v -p 80 -F -S" (no, no hay ar­­chi­­vo de co­n­­fi­­gu­­ra­­ció­­n)

  • Los do­­­mi­­nios vi­r­­tua­­les son ca­r­­pe­­tas y sy­­m­­li­nks aden­­tro de /s­r­­v/www que es lo más fá­­cil po­­­si­­ble.

  • So­­­po­r­­ta pro­­­xy in­­ve­r­­so pa­­ra cuan­­do quie­­ro pro­­­bar una we­­ba­­pp py­­thon en la que es­­toy tra­­ba­­jan­­do.

Mail Server

No quie­ro un mail ser­ve­r. Ten­go gmail y un ser­ver de ver­dad pa­ra eso. Lo que quie­ro son los mails de cro­n. Pa­ra eso usé ss­m­tp y una cuen­ta ex­tra de gmai­l. Fun­cio­na, y es­ta es to­da la con­fi­gu­ra­ció­n:

root=roberto.alsina@gmail.com
mailhub=smtp.gmail.com:587
UseTLS=YES
UseSTARTTLS=YES
AuthMethod=LOGIN
AuthUser=roberto.alsina.3@gmail.com
AuthPass=notputtingthetrueoneheredude

Lo me­jor que pue­do de­cir es que fun­cio­na, y no in­vo­lu­cra co­rrer un ser­ve­r.

Misc

Pa­ra cuan­do ten­go que es­tar en dos lu­ga­res al mis­mo tiem­po: Open­VPN es lo má­s, y no se acep­tan dis­cu­sio­nes. Ten­go un squid co­rrien­do a ve­ce­s, y hay un Qua­ssel co­re pa­ra IR­C. Ins­ta­lé mosh pa­ra que el ssh sea me­nos do­lo­ro­so, rs­ync ha­ce de­plo­y­men­ts y guar­da ba­ckup­s, cron eje­cu­ta co­sas, y na­da má­s.

Status

Mon­to­nes de RAM y CPU li­bres (sí, esa es la lis­ta com­ple­ta de pro­ce­so­s):

[root@burst1 ~]# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1   2156   664 ?        Ss   22:01   0:00 init [3]
root      1135  0.0  0.1   2260   576 ?        S<s  22:01   0:00 /sbin/udevd -d
root      1518  0.0  0.1   1812   572 ?        Ss   22:01   0:00 syslogd -m 0
root      1594  0.0  0.1   7240  1032 ?        Ss   22:01   0:00 /usr/sbin/sshd
root      1602  0.0  0.2   4492  1112 ?        Ss   22:01   0:00 crond
root      1630  0.0  0.1   5684   716 ?        Ss   22:01   0:00 /usr/sbin/saslauthd -m /var/run/saslauthd -a pam -n 2
root      1631  0.0  0.0   5684   444 ?        S    22:01   0:00 /usr/sbin/saslauthd -m /var/run/saslauthd -a pam -n 2
root      1636  0.0  0.2   3852  1372 ?        S    22:01   0:01 /opt/diet/bin/gatling -c /srv/www -P 2M -d -v -p 80 -F -S
root      1677  0.0  0.2   4284  1232 ?        Ss   22:02   0:00 SCREEN /root/quasselcore-static-0.7.1
root      1678  0.0  2.1  36688 11148 pts/0    Ssl+ 22:02   0:03 /root/quasselcore-static-0.7.1
root      3228  1.0  0.7  12916  4196 ?        Ss   23:28   0:13 mosh-server new -s -c 8
root      3229  0.0  0.3   3848  1588 pts/2    Ss   23:28   0:00 -bash
root      3275  0.0  0.1   2532   908 pts/2    R+   23:48   0:00 ps aux
[root@burst1 ~]# w
 23:49:03 up  1:47,  1 user,  load average: 0.00, 0.01, 0.00
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/2    186.153.52.253   23:28    0.00s  0.01s  0.00s w
[root@burst1 ~]# free
             total       used       free     shared    buffers     cached
Mem:        524800      49100     475700          0          0          0
-/+ buffers/cache:      49100     475700
Swap:            0          0          0

Te­nien­do en cuen­ta to­do, bas­tan­te con­ten­to con el re­sul­ta­do.

Wild Cards (Wild Cards, #1)

Review:

I liked this book enough, but the idea of it be­ing part of a 20+ book se­ries is daunt­ing enough that I may not con­tin­ue it.

Christians say the funniest things!

This is a res­pon­se to a res­pon­se to this we­b­co­mic ti­tled "How to su­ck at your re­li­gio­n". Whi­le Oat­mea­l's co­mic is cra­ss and pain­ts things in broad ter­ms, it's a freaking we­b­co­mic. So it's su­ppo­sed to do tha­t. Bu­tthe res­pon­se is so fu­ll of pha­lla­cies (and la­cking in we­b­co­mi­c-­ness) that it may de­ser­ve a res­pon­se.

I ha­ve pro­mi­s­ed not to be a tro­ll (an­y­mo­re) so I wi­ll try to an­swer in a sen­si­ble man­ne­r.

He­re's the arti­cle I am re­pl­ying to go read it if you wan­t. I wi­ll not re­ply to all of it, but wi­ll ins­tead che­rr­y­pi­ck a cou­ple of pa­ra­gra­phs.

In res­pon­se to the "for­cing dog­ma" pa­ne­l:

So­... re­li­gion is fi­ne, un­le­ss you ac­tua­lly be­lie­ve in it? Should pa­ren­ts not pa­ss their po­li­ti­ca­l, ethi­cal or mo­ral views on to their chil­dren as we­ll? What par­ts of pa­ren­ting would be le­ft if pa­ren­ts we­re to avoid pa­s­sing their views on to their ki­d­s? The irony he­re is that si­len­ce is itself a sta­te­men­t. Avoi­ding any men­tion of God to your ki­ds sen­ds as clear a me­ss­age as ta­lking about Go­d: spe­ci­fi­ca­ll­y, it te­lls your ki­ds that Go­d's exis­ten­ce is ei­ther un­true, unk­no­wn, or unim­por­tan­t. Be­cau­se if you knew Him to exis­t, su­re­ly you'd sha­re that kno­w­le­dge, ri­gh­t?

Le­t's start from the to­p: you do­n't know god exis­ts. You ha­ve fai­th that he exis­ts, but you do­n't know it for a fac­t. If you knew for a fact that he exis­ts, you could not po­s­si­bly ha­ve fai­th be­cau­se fai­th ex­clu­des cer­tain­ty. As your bi­ble sa­ys, fai­th is "the subs­tan­ce of things ho­ped fo­r, the evi­den­ce of things not seen."

So, do I te­ll my son god does­n't exis­t? No­pe. I te­ll him I thi­nk he does­n't exis­t, and that I ha­ve ne­ver seen r heard of any re­lia­ble evi­den­ce or da­tum that poin­ts to­war­ds his exis­ten­ce, but al­so that so­me peo­ple do be­lie­ve he does exis­t. I told him that be­cau­se I feel tha­t's a ho­nest an­swe­r. If your ho­nest an­swer is "god exis­ts", then bu­lly for you, but from the point of view of a no­n-­be­lie­ver you are te­lling your son a lie, or at best a hal­f-­tru­th. And if you rea­lly do­n't know he exis­ts for a fact then you are just lyin­g.

No­w, are you sa­yin that you know god exis­ts fac­tua­ll­y? Ba­sed on wha­t? Tha­t's the usual sli­ppe­ry slo­pe for this ar­gu­men­t. The re­li­gious are the ones making sta­te­men­ts of fact ba­sed on tra­di­tio­n. To the rest of us, they just seem to be pla­ying loose wi­th what "fac­t" mean­s, or what "go­d" means or what "k­no­w" mean­s.

So, no, do­n't avoid men­tions of go­d, just avoid lying to your ki­ds if you can.

This next sec­tion is pro­ba­bly the wors­t, be­cau­se it's just an in­co­he­rent ar­gu­men­t. A kid asks, “Da­d, what ha­ppens to us after we die?” The au­thor com­pa­res pro­vi­ding the Ch­ris­tian an­swer to this ques­tion wi­th co­rrec­ting your kid for ha­ving green as a fa­vo­ri­te co­lo­r. Wha­t?? That just is­n’t a co­he­rent ar­gu­men­t. In what world are tho­se two ideas pa­ra­lle­l, or even com­pa­ra­ble?

Ac­cor­ding to the we­b­co­mi­c, good pa­ren­ting is to pre­tend to be ag­nos­ti­c, and say that “no one rea­lly kno­ws for su­re.” Of cour­se, if the Re­su­rrec­tion is true, that claim is fal­se. So to be a good pa­ren­t, you appa­ren­tly ha­ve to deny the Re­su­rrec­tion and em­bra­ce ag­nos­ti­cis­m, trea­ting be­lie­fs about the after­li­fe as me­re ma­tters of per­so­nal pre­fe­ren­ce like ha­ving a fa­vo­ri­te co­lo­r. This is jus­t… stu­pi­d. The­re’s just no other way of des­cri­bing it. Ima­gi­ne if we treated eve­r­y­thing that wa­y. “Da­d, wha­t’s 3 x 3?” “No one rea­lly kno­ws for su­re. What do YOU thi­nk 3 x 3 is?”

So, com­pa­ring li­fe after dea­th wi­th co­lor pre­fe­ren­ce is stu­pid and in­co­he­ren­t, but com­pa­ring it the ch­ris­tian be­lief of re­su­rrec­tion wi­th ba­sic ari­th­me­thi­cs is a-o­k? That must ha­ve taken so­me effort to wri­te wi­th a strai­ght fa­ce, I'm su­re.

So, le­t's go slo­w­ly on this one. Be­lie­fs about the after­li­fe are, like most other be­lie­fs, pro­ba­bly not a per­so­nal pre­fe­ren­ce, but just so­me­thing you ha­ve, be­cau­se of, in most ca­ses, in­doc­tri­na­tion ear­ly in li­fe, peer pres­su­re, and just be­cau­se you li­ve in a so­cie­ty whe­re that be­lief is nor­mal and appro­ved of.

But what is it your be­lief in the after­li­fe is not?

  • It's not inhe­­rent to "you". If you we­­re born in ano­­­ther pla­­ce or ti­­me, you would pro­­­ba­­bly be­­­lie­­ve so­­­me­­thing el­­se.

  • It's not un­­dis­­pu­te­­d. Be­­­cau­­se the­­re exis­­ts a ma­­jo­­­ri­­ty of peo­­­ple who do­­n't be­­­lie­­ve the sa­­me thi­n­­g, ei­­­ther by de­­tails or en­­ti­­re­­l­­y.

  • It's not uni­­que. Be­­­cau­­se other re­­li­­gions ha­­ve had si­­mi­­lar re­­su­­rre­c­­tion be­­­lie­­fs.

  • It's not re­­lia­­ble. Even if we we­­re to ac­­cept eve­­r­­y­­thing the bi­­ble sa­­ys as true that would not mean we know what wi­­ll ha­­ppen to you or to me after we die. We would ha­­ve a tes­­ti­­mony about what ha­­ppe­­ned in a few da­­ys in the afte­r­­li­­fe of a spe­­ci­­fic pe­r­­so­­n, at a point in the pa­s­­t, as told to so­­­meo­­­ne by so­­­meo­­­ne. Is that the sa­­me as kno­­wing what wi­­ll ha­­ppen? No it's no­­­t.

Le­t's com­pa­re that to 3x3 as the au­thor attemp­te­d:

  • If I was a chi­­ne­­se in the 12­­th cen­­tu­­r­­y: 3x3 is 9.

  • The­­re is no group of peo­­­ple that be­­­lie­­ves 3x3 is 8 or 10.

  • The­­re has not been in the past any real di­s­a­­gree­­ment about the va­­lue of 3x3. We ha­­ve not achie­­ved that re­­sult via a gra­­dual im­­pro­­­ve­­men­­t.

  • We re­­ly on 3x3 being 9 eve­­ry day in our li­­ve­s. If you dri­­ve a ca­­r, use a pho­­­ne, or zip your pan­­ts, you are agreeing 3x3 is 9.

  • We do­­n't ex­­pect 3x3 not to be 9 in the fu­­tu­­re.

No­ti­ce any di­ffe­ren­ce­s? Ye­s, me too.

Per­so­na­ll­y, I con­si­der your fai­th in god mo­re akin my liking Queen (the ban­d, not the ru­le­r). I was ex­po­sed to Queen at the ri­ght ti­me, it was appro­ved by my peer­s, and I like it. On the other han­d, I un­ders­tand that Queen is not eve­r­yo­ne's cup of tea, and I do­n't claim Queen to be the "ri­gh­t" ban­d.

The who­le "if the Re­su­rrec­tion is true, that claim is fal­se" li­ne of thou­ght is not lo­gi­ca­l. If my cat had wings, then the claim that win­ged ca­ts are awe­so­me is fal­se. But my cat does­n't ha­ve wings. Does it make the win­ged ca­ts le­ss or mo­re awe­so­me that he does­n'­t? It's not that it's not ri­gh­t, it's that it's not even wron­g.

Al­so, Oat­mea­l, sha­me on you about Ga­li­leo, rea­ll­y, look it up ;-)

Clavando un clavo con un zapato I: Do-Sheet.

  1. Te ha­­ce pen­sar di­­fe­­ren­­te.

  2. Es di­­ve­r­­ti­­do.

Lo ma­lo es, por su­pues­to, que el con­te­ni­do de la char­la tie­ne que ser se­cre­to, o no tie­ne nin­gu­na gra­cia. Co­mo el pro­ce­so de re­view pa­ra char­las de Py­Co­nAr es pú­bli­co, no te­nía ma­ne­ra de ex­pli­car de qué se tra­ta­ba.

Co­mo eso sig­ni­fi­ca que pon­go a los re­vi­so­res en el com­pro­mi­so de te­ner que acep­tar mi pa­la­bra de que es­ta char­la es al­go in­te­re­san­te, y eso es injus­to pa­ra ellos y los de­más char­la­ri­nes, can­ce­lé la pro­pues­ta.

La (tal ve­z) bue­na no­ti­cia es que aho­ra to­dos van a po­der ver de qué se tra­ta­ba la char­la. Acá es­tá el cla­vo nú­me­ro 1: Es­cri­bir una ho­ja de cál­cu­lo usan­do doi­t.

Es­ta no es mi pri­me­ra "ho­ja de cál­cu­lo­". To­do em­pe­zó ha­ce mu­cho, mu­cho tiem­po con una fa­mo­sa re­ce­ta de Ra­y­mond He­ttin­ger que he usa­do una y otra y otra vez (ca­paz que fal­ta al­gu­na).

Da­do que ven­go usan­do doit pa­ra Niko­la es­toy im­pre­sio­na­do con lo po­ten­te que es. En bre­ve, doit te per­mi­te crear ta­rea­s, y esas ta­reas de­pen­den de otra­s, ope­ran en da­to­s, dan re­sul­ta­dos que otras ta­reas usan, etc.

¿Se ve adon­de va es­to?

Acá va el có­di­go, con ex­pli­ca­cio­nes:

cells es nuestra hoja. Podés poner cualquier cosa, pero usá siempre el formato "nombre=formula" y la fórmula tiene que ser Python válido ¿ok?

from tokenize import generate_tokens

cells = ["A1=A3+A2", "A2=2", "A3=4"]
values = {}

task_calculate crea una tarea para cada celda, llamada calculate:NOMBRE. La acción que esa tarea realiza es evaluar la fórmula. Pero para hacer eso de manera exitosa, necesitamos saber qué otras celdas hay que evaluar primero.

Eso lo im­ple­men­té usan­do las cal­cu­lated de­pen­den­cies de doi­t, con la ta­rea "ge­t_­de­p:­FOR­MU­LA" pa­ra la fór­mu­la de es­ta cel­da.

def evaluate(name, formula):
    value = eval(formula, values)
    values[name] = value
    print "%s = %s" % (name, value)

def task_calculate():
    for cell in cells:
        name, formula = cell.split('=')
        yield {
            'name':name,
            'calc_dep': ['get_dep:%s' % formula],
            'actions': [(evaluate, (name, formula))],
            }

Por ejemplo, nuestra A1 depende de A3 y A2 que no dependen de nada. Para parsear esto, usé el módulo tokenize, y tomo nota de cuales cosas son "nombres". Existen maneras más soisticadas ;-)

la función task_get_dep es una tarea de doit que crea tareas llamadas "get_dep:NOMBRE" para cada nombre de celda en cells.

A su vez, get_dep devuelve una lista de tareas de doit. Para nuestra celda A1, eso sería ["calculate:A2", "calculate:A3"] o sea que para poder calcular A1 primero tenemos que terminar esas tareas.

def get_dep(formula):
    """Given a formula, return the names of the cells referenced."""
    deps = {}
    try:
        for token in generate_tokens([formula].pop):
            if token[0] == 1:  # A variable
                deps[token[1]] = None
    except IndexError:
        # It's ok
        pass
    return {
        'result_dep': ['calculate:%s' % key for key in deps.keys()]
        }

def task_get_dep():
    for cell in cells:
        name, formula = cell.split('=')
        yield {
            'name': formula,
            'actions': [(get_dep, (formula,))],
            }

Y eso es todo. Veámoslo en acción. Podés obtener tu propia copia acá y probarlo instalando doit, editando cells y usándolo así:

ralsina@perdido:~/dosheet$ doit -v2 calculate:A3
.  get_dep:4
{}
.  calculate:A3
A3 = 4
ralsina@perdido:~/dosheet$ doit -v2 calculate:A2
.  get_dep:2
{}
.  calculate:A2
A2 = 2
ralsina@perdido:~/dosheet$ doit -v2 calculate:A1
.  get_dep:A3+A2
{'A3': None, 'A2': None}
.  get_dep:4
{}
.  calculate:A3
A3 = 4
.  get_dep:2
{}
.  calculate:A2
A2 = 2
.  calculate:A1
A1 = 6

Co­mo po­dés ve­r, siem­pre ha­ce el mí­ni­mo es­fuer­zo po­si­ble pa­ra cal­cu­lar el re­sul­ta­do de­sea­do. Si que­ré­s, hay al­gu­nas co­sas me­jo­ra­ble­s, que de­jo co­mo ejer­ci­cio pa­ra el lec­to­r. Por ejem­plo:

  1. Usar up­­to­­­da­­te pa­­ra no re­­ca­l­­cu­­lar de­­pen­­den­­cias inu­­ti­l­­men­­te.

  2. Eli­mi­nar la va­ria­ble glo­bal va­lues y usar los com­puted va­lues de doit en su lu­ga­r.

Acá es­tá el lis­ta­do com­ple­to, buen pro­ve­cho!


Contents © 2000-2021 Roberto Alsina