Lateral Opinion

Lateral Opinion

eBooks and PyQt: a good match

Introducing Aranduka

Very pythonic progress dialogs.

The first english Issue of PET (our Python Magazine) is out!

Making deployment of desktop Python apps trivial: an idea

Why we are here.

Goodreads+webcam+python+zbar == hackfun!

PET: English Translation Issue 1 has a date

I'm a nerd, but I Have a Cheap Phone

Spain is much bigger than you think!

Things I learned publishing a magazine

Come see me in BahÃa Blanca next weekend!

It's coming: PET - Python Entre Todos

Extending rst2pdf: easy and powerful

This is why Qt (and PyQt) are cool

Desktop apps and clouds (with video)

Discutiendo con cualquiera parte III: Darwin y porquÃ© se le diÃ³ una difusiÃ³n mundial.

Slow-Slow and Fast-Fast (video)

Capturing a webpage as an image using Pyhon and Qt

Learn python! For free! With me! (in part)

eBooks and PyQt: a good match

I have been putting lots of love into Aranduka an eBook manager, (which is looking very good lately, thanks!), and I didn't want it to also be an eBook reader.

But then I thought... how hard can it be to read ePub? Well, it's freaking easy!

Here's a good start at stackoverflow.com but the short of it is... it's a zip with some XML in it.

One of those XML files tells you where things are, one of them is the TOC, the rest is just a small static collection of HTML/CSS/images.

So, here are the ingredients to roll-your-own ePub reader widget in 150 LOC:

Use python's zipfile library to avoid exploding the zip (that's lame)

Use Element Tree to parse said XML files.

Use PyQt's QtWebKit to display said collection of XML/CSS/Images

Use this recipe to make QtWebKit tell you when it wants something from the zipfile.

Plug some things to others, shake vigorously, and you end up with this:

Here's the code (as of today) and the UI file you need.

Missing stuff:

It doesn't display the cover.

It only shows the top level of the table of contents.

I only tested it on two books ;-)

It sure can use a lot of refactoring!

Neither should be terribly hard to do.

Introducing Aranduka

Yes, it's yet another program I am working on. But hey, the last few I started are actually pretty functional already!

And... I am not doing this one alone, which should make it more fun.

It's an eBook (or just any book?) manager, that helps you keep your PDF/Mobi/FB2/whatever organized, and should eventually sync them to the device you want to use to read them.

What works now? See the video!

In case that makes no sense to you:

You can get books from FeedBooks. Those books will get downloaded, added to your database, tagged, the cover fetched, etc. etc.

You can import your current folder of books in bulk.

Aranduka will use google and other sources to try to guess (from the filename) what book that is and fill in the extra data about it.

You can "guess" the extra data.

By marking certain data (say, the title) as reliable, Aranduka will try to find some possible books that match then you can choose if it's right.

Of course you can also edit that data manually.

And that's about it. Planned features:

Way too many to list.

The goals are clear:

It should be beautiful (I know it isn't!)

It should be powerful (not yet!)

It should be better than the "competition"

If those three goals are not achieved, it's failure. It may be a fun failure, but it would still be a failure.

Very pythonic progress dialogs.

Sometimes, you see a piece of code and it just feels right. Here's an example I found when doing my "Import Antigravity" session for PyDay Buenos Aires: the progressbar module.

Here's an example that will teach you enough to use progressbar effectively:

progress = ProgressBar()
for i in progress(range(80)):
    time.sleep(0.01)

Yes, that's it, you will get a nice ASCII progress bar that goes across the terminal, supports resizing and moves as you iterate from 0 to 79.

The progressbar module even lets you do fancier things like ETA or fie transfer speeds, all just as nicely.

Isn't that code just right? You want a progress bar for that loop? Wrap it and you have one! And of course since I am a PyQt programmer, how could I make PyQt have something as right as that?

Here'show the output looks like:

You can do this with every toolkit, and you probably should!. It has one extra feature: you can interrupt the iteration. Here's the (short) code:

# -*- coding: utf-8 -*-
import sys, time
from PyQt4 import QtCore, QtGui

def progress(data, *args):
    it=iter(data)
    widget = QtGui.QProgressDialog(*args+(0,it.__length_hint__()))
    c=0
    for v in it:
        QtCore.QCoreApplication.instance().processEvents()
        if widget.wasCanceled():
            raise StopIteration
        c+=1
        widget.setValue(c)
        yield(v)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    # Do something slow
    for x in progress(xrange(50),"Show Progress", "Stop the madness!"):
        time.sleep(.2)

Have fun!

The first english Issue of PET (our Python Magazine) is out!

Hell yeah! It has been a lot of work but it's out at http://revista.python.org.ar

Some articles:

PyAr, The History

from gc import commonsense - Finish Him!

Painless Concurrency: The multiprocessing Module

Introduction to Unit Testing with Python

Taint Mode in Python

Applied Dynamism

Decorating code (Part 1)

Web2Py for Everybody

It's available in pretty much every format anyone can read, and if your favourite is not there, we will make it for you or may I be smote by the flying spaghetti monster's noodly appendage!

AFAIK there is no other Python magazine being published (feel free to correct me), so it's kind of a big thing for us in PyAr (the Argentina Python community) that we are doing one, and in two languages.

But why stop here? Want it to be available in your language? Contact us at revistapyar@netmanagers.com.ar it may be doable!

And of course, very soon there will be a call for articles for Issue 2, and trust me: that one's going to be epic: this one was just a warmup.

Making deployment of desktop Python apps trivial: an idea

Here's what I'm thinking: how hard could it be to make PyQt app deployment absolutely easy? Well, I am guessing: not very hard.

Here's the trick: see what works in the real world, and adopt it.

Question: what has deployed billions of apps and has its users happy? Answer: phones app stores.

Question: how do they work? Answer: well, that's not that short, so let's start explaining.

As I see it, a reasonable app store has the following components:

A Stable Deployment Target

You can't deploy from the store if you don't know what you are deploying into. If the target platform is shaky, you just can't know how to deploy without user assistance, and we are trying to make this easy for the user, which means that's not acceptable.

So, what's a stable deployment target we can provide?

PyQt (so we can deploy GUIs to all major desktop platforms)

Python standard library

Selected modules

What can be (and should be) bundled with the app?

Pure python modules

Artwork and other resources

What may be bundled:

Python modules written in C/C++, but you then have to redo the app for each platform, and that kinda sucks.

Deployment Services

Apps should be able to check if there is a new version of them in the store, to ask for upgrades.

Apps should be added by the deployment platform nicely into the host system's menus, desktop, etc.

Monetization Services

Some way to charge for apps. Even for open source apps, you could ask for U$S0.99 if you install them through the store. Optional, of course, and up to the app owner.

Ad platform? There must be a good one for desktop apps somewhere?

The Store Itself

A website that downloads a "package" associated with a local deployment application.

A app store app. Install things not via web, but via a desktop application.

I don't expect a functional version of this would take me more than a week working fulltime to implement. Of course then there are all sorts of usability, looks, etc. things to consider.

And... I am going to do something I very rarely do. I am going to ask for money.

As an experiment, I have setup a project at http://www.indiegogo.com/Qt-Shop and set a funding goal of U$S 600.

There you can fund me. I promise that if the project is totally funded, I will deliver. If it isn't, I may deliver anyway. I would prefer to have the money though.

The platform would be released under GPLv2 or later.

Why we are here.

Warning: rant ahead.

Yesterday the government of Argentina announced that they are giving way 3 million netbooks to students. They also announced that they are giving them the option of Ubuntu or Windows 7.

There was, of course, the typical reaction from the FLOSS side: why are they giving Windows to the students when Linux is better? It's unfair that the government pays for Windows!

I am here to tell you to grow up and stop being a baby. I am here to tell you to stop treating others like babies.

I think I can do this because I am immune to criticism from the FLOSS crowd: I am a member of that crowd. I have an awesome FLOSS pedigree, I have used nothing but Linux for over 15 years. And I have a thick skin and I don't care much what other people say, in principle, unless they give me good reasons to care. And I am telling you to stop complaining.

I am telling you that if the only reason to use a specific piece of software is because it's cheaper, you are accepting that piece of software sucks.

I want people not to just use Linux, I want them to want to use Linux. I want them to wait anxiously for the next release of Ubuntu or Firefox or whatever.

And the first step towards excellence is wanting to be excellent. If having to pay nothing for Windows or Ubuntu there is a certainty that Windows will win, then Ubuntu freaking sucks and needs to improve. People are not adopting it even if it's free? Then something is wrong, and figuring out what is important.

But even more important than finding the missing piece is knowing a piece is missing. Open source has grown complacent. It's grown self righteous. It's become adolescent, sure of its awesomeness and immortality.

I don't believe in many things, but I do believe in free will. I believe that people are not morons, I believe that if they prefer Windows, it's because it does something better, and I believe that whatever that is (and I don't really know what it may be), it can be found, and can be improved, and can be replaced, and other things can be added, and people will want to use the better product.

And if they don't... well, at least we fought an honest fight, and we did our best, and we (hopefully) had fun in the process, and pushed the envelope, and created nice things, and the users are better off in the end even if our babies are not the chosen ones, because we raised the level of everything.

For example, before Linux, Windows sucked much, much more than it does now, and I think many of those improvements were because of Linux, and I am happy that today Windows users have a OS that doesn't stink.

I want free and open source software to be used because it's awesome, not because it's cheap. Awesome and cheap I can live with. Just cheap? That sucks.

And the constant "they use windows because they don't know better"? That's patronizing and condescending, and very, very annoying. And if it annoys me, who is not the target of the lame condescending, trust me, it annoys the crap out of Windows users.

Grow a spine, get your asses into gear, start making awesome stuff, kick ass with quality. That's why we are here. Not to be the cheapest date in town.

Goodreads+webcam+python+zbar == hackfun!

I am a big fan of GoodReads a social network for people who read books.

I read a lot, and I like that I can see what other people think before starting a book, and I can put my short reviews, and I can see what I have been reading, and lots more.

In fact, goodreads is going to be a big part of a project I am starting with some PyAr guys.

One thing I have been lazy about is adding my book list to goodreads, because it's a bit of a chore.

Well, chore no more!

Here's how to do it, the hacker way...

Get zbar

Get a cheap webcam

Get a book

Get a 7-line python program (included below)

Now watch the video...

Cute, isn't it?

Here's the code:

import os

p=os.popen('/usr/bin/zbarcam','r')
while True:
    code = p.readline()
    print 'Got barcode:', code
    isbn = code.split(':')[1]
    os.system('chromium http://www.goodreads.com/search/search?q=%s'%isbn)

PET: English Translation Issue 1 has a date

Because it worked once, let's do it again. I have just set a completely arbitrary, and probably too early date for the release of the first english Issue of "PET: Python Entre Todos" magazine.

The english version is called PET, which means "Python Entre Todos: English Translation".

It will have the same contents as the first spanish Issue and... it will be the last Issue done like this.

From now on, both versions will be published at the same time, if we can.

So, there will be a very short gap between the english first Issue and the second one (less than a month, we hope).

So, stay tuned

I'm a nerd, but I Have a Cheap Phone

I just got a new phone because my old one disappeared. I got a Samsung Star, which is not a smartphone, but what they call a featurephone, which seems to mean "it does a lot of things but is cheap, can only be coded in Java and doesn't run android".

Here's some of the features of this baby:

Touchscreen, 400x240

Fake GPS (gives you a 400 meters radius of your location. Good enough for me in the city)

Webkit-based browser that works surprisingly well (it comes with the LGPL as a document and you can't delete it :-)

Accelerometer

FM radio

A 2GB micro-SD card

3.2MP camera (takes video at 320x240).

The camera can take decent photos in good conditions:

And it even has some "advanced" features (by which I mean: things my cheap dedicated camera doesn't do), like smile shutter and panoramic shots:

Other that that... well, it's a phone, what can I say. It was "cheap", which means "it costs more than I want to pay for it, but less than the alternatives".

So, how am I taking advantage of it...

First: I have not had a decent pocket-sized ebook reader since my last Clie died. So, I looked for software to do that.

It turns out that the world of Midlets, as feature phone apps are often called, is aweird place, where things are quite hard to find for the uninitiated.

There is a sort of "app shop" at http://getjar.com but it's by no means comprehensive, and often things are quite hard to find.

After lots of looking, I found a good (I may even say very good) program called Foliant. Here's their home page, russian only ... it's weird, my favourite Palm ebook reader, Palm Fiction also has a russian-only site!

Of course, the fonts sucked (way too large) but it turns out you can convert TTF fonts using this tool so I am now back to the lovely Droid Sans I am used to.

Another nice thing about the new phone is that it can actually play media (yes, my previous phone was so crappy it didn't even play mp3). But... not every kind of media. For audio, just use mp3. For video... it's a bit more complicated.

Here's the short version:

Convert using HandBrake, ffmpeg MP4 video, AAC audio.

Always use the .mp4 extension, the phone is not smart enough to know what a .m4v is.

Don't make the video larger than 320x240.

Number 3 is a problem. For example, you may have a video in a wide screen format, like 640x272, which is a 2.35:1 ratio.

The obvious thing is to cap the width to 320, and that would give you a 320x136 video.

Well, that's wrong. What you should do is find the right height, keeping aspect ratio, for a 400px width. In this case, that would be a 400x170.

But you can't use a 400x170 video! which is why you will use 320x170, and on playback tell the phone to stretch it and ignore aspect ratio. And voila, 400x170 and the correct aspect ratio.

The difference? 320x130 has only 41600 pixels, while 320*170 has 54400, which means you get a 30% better picture.

Yes, it's tiny (3 inches) but it looks pretty sharp, and depending on the kind of material you are watching, it works.

UPDATE: Foliant is better than I thought, once you get the Samsung-specific version. It's fullscreen (no silly soft buttons) and the screen rotates automatically using the accelerometer. It's a pleasure to use, and the UI is very nice.

Spain is much bigger than you think!

On the news today (the newspaper is Tiempo Argentino, sorry about the unreadable photo):ï¿¼

It says "In Spain it amounts to less than 340 thousand customers a month, or 0.006% of the total".

This is talking about cellphone users. Now, how many cell phone users are there in Spain?

According to this newspaper, 340000 are 0.006% of the total, so... 5 666 666 667 (aprox.), therefore, Spain has roughly one cell phone for each man, woman and child in the world.

Things I learned publishing a magazine

Today at 00:00:00 GMT-3 PET: Python entre todos was indeed launched, in time (arbitrary but forced) and in budget ($0).

So, what did I learn? I learned a lot!

The only thing you need to publish an e-mag is time and content.

Time can be converted into content, but if you write everything yourself it's a blog, not a magazine. Luckily, PET found great contributors.

If you want utilitarian design, rst2pdf can do the job

In fact, it can do it better than other tools in some ways

I can push a fixed version of the PDFs in 5 minutes for all layouts. How much would it take me using Scribus or other DTP? In a magazine where correctness matters, that's a big deal.

TOCs are better than in most amateur PDF magazines I've seen. The in-content-TOC is clickable, and the PDF TOC is perfect.

Page numbers in the PDF TOC make sense (no, the cover is not page 1)

I am producing 6 PDF versions: A4(bw, colour), A5(bw,colour), Booklet(bw, colour) and I could add any other I want in a few minutes.

I learned about PDF imposition!

Let's explain the last one:

Suppose you want to print a small booklet, and you have 32 pages of content. How do you do that?

The easiest way is to print it 2-up double-sided in A4 paper so that you can stack the pages, fold them down the middle, staple them, and get a nice A5 booklet.

The problem is that the page ordering is hard to get right. For example, for a 4-page booklet, you need to print one A4 page with pages 4-1 on one side and 2-3 on the other. For an 8 page booklet it's 8-1,2-7,3-6,4-5.

Lucklily there's a way to get this done automatically:

1. Install podofo 3. Get booklet-A4.plan (see below) 2. Run this:

podofoimpose my-A5-pages.pdf my-booklet.pdf booklet-A4.plan lua

booklet-A4.plan is this:

---Generic Booklet (A4)
---
---It is said generic as it will try to determine
---automatically how to fit the booklet onto A4
---paper sheets, scaling pages if necessary.
---it is well suited for office documents for
---which you do not care too much about resulting
---imposition artefacts since it manages to save
---paper!
---
-- print("Booklet")
-- We output an A4 booklet
PageWidth = 595.27559
PageHeight = 841.88976

print("PageCount",PageCount)

-- We assume that H > W
-- Argh, we now can do better since we have "if" ;-)
-- Scale = PageHeight / (2*SourceWidth)
if(SourceWidth <= SourceHeight)
then
--  If you A5 pages are not really A5, uncomment the next line
--  Scale = PageHeight / (2*SourceWidth)
    Scale = 1
    rot = 90
        xof = SourceHeight
        yofRA = 0
        yofRB = SourceWidth
        yofVA = 0
        yofVB = SourceWidth
else
--  If you A5 pages are not really A5, uncomment the next line
--  Scale = PageHeight / (2*SourceHeight)
    Scale = 1
    rot = 0
        xof = 0;
        yofRA = 0
        yofRB = SourceHeight
        yofVA = SourceHeight
        yofVB = 0
end

do
    rest = PageCount % 4
    totp = PageCount
    if rest ~= 0
        then
        totp = totp + ( 4 - rest)
        end
    inc = 0
    count = 0
    imax = totp/4
    while count < imax
        do
--          We assume that podofoimpose will discard invalid records
--          such as those with source page greater than PageCount
--          print(totp, inc, rot, xof,yofRA, yofRA, yofVA, yofVB)
-- Recto
        PushRecord(totp - inc , inc + 1 , rot, xof , yofRA)
        PushRecord(inc + 1 , inc + 1 , rot, xof , yofRB)
-- Verso
        PushRecord(inc + 2 , inc + 2 , rot, xof , yofVA)
        PushRecord(totp-(inc + 1) , inc + 2 , rot, xof, yofVB)

        count = count + 1
        inc = inc + 2
        end
end

That code is taken from here: http://www.oep-h.com/impose/

And voilÃ¡, you get a scrambled PDF with the pages in exactly the right order (and empty pages added as needed).

Come see me in BahÃa Blanca next weekend!

I will be speaking at the Jornadas del Sur in BahÃa Blanca this weekend (August 14/15 and 16).

For a change, I will not be giving my old tired talks, but a brand new one, called "The Amateur", and probably a lightning talk or something else.

The usual offer of free beer will not be possible this year, so: If you mention this blog in the QA session, you get... free candy!

After that, I will be speaking at FM La Tribu on saturday August 21st in the Charlas Abiertas 2010 where I will be speaking about a lot of things between virtualenv and nose and tox and other testing-related topics.

It's coming: PET - Python Entre Todos

Edited

I removed the countdown because it was wrong (timezone problem). Check http://revista.python.org.ar for one that works :-)

I have been dragged into YAP (Yet Another Project) and in this case it's the first-issue-ever of PET - Python Entre Todos a python online magazine in spanish.

This is an emergent output of PyAr the online Python community of Argentina, and it may never have a second issue unless we get a lot of help, so pay attention to the first one :-)

I have been doing webmastering, editing and PDF production, Emiliano Dalla Verde Marcozzi has been helping everywhere and getting articles.

The first issue is some 45 A5 pages (or 23 A4 ones) in small type, so it's not exactly huge, but it has half a dozen articles aimed at different python levels.

It has been a lot of fun so far, I hope it's well received!

Extending rst2pdf: easy and powerful

I do almost all my business writing (and my book) using restructured text. And when I want to produce print-quality output, I tend to use my own tool, rst2pdf.

It's popular, surely my most popular program, but very few know it's also extremely easy to extend (hat tip to Patrick Maupin, who wrote this part!). And not only that, but you can make it do some amazing stuff with a little effort.

To show that, let's create the most dazzling section headings known to man ( Let's see you do what this baby can do in LaTeX ;-).

First: define the problem.

The titles rst2pdf can produce are boring. If you pull every lever and push every button, you may end with the title text, in a Comic Sans, right-aligned, in pink lettering, with avocado-green background and a red border.

And that's as far as the customization capabilities go using stylesheets. That's usually enough, because rst2pdf is not meant for brochures or something like that (but I have done it).

The real problem is that when you get all graphic-designer on rst2pdf, you lose document structure, because you are not being semantic.

Second: define the goal.

So, imagine you want to make a heading that looks like this:

The image is taken from the library of congress with some light (and bad) gimping by me to leave that empty space at the left, and the title was added using Inkscape.

Can you do that with rst2pdf? Hell no you can't. Not without coding. So let's code an extension that lets you create any heading you like within the limits of Inkscape!

First, we create a SVG template for the headings (it's a bit big because it has the bitmap embedded).

Three: the image-heading flowable

Suppose you have an image of the heading just like the one above. How would you draw that in a PDF? In reportlab, you do that using flowables which are elements that compose the story that is your document. These flowables are arranged in pages, and that's your PDF.

If you are doing a heading, there's a bit more, in that you need to add a bookmark, so it appears on the PDF table of contents.

So, here's a flowable that does just that. It's cobbled from pieces inside rst2pdf, and is basically an unholy mix of Heading and MyImage:

class FancyHeading(MyImage):
  '''This is a cross between the Heading flowable, that adds outline
  entries so you have a PDF TOC, and MyImage, that draws images'''

  def __init__(self, *args, **kwargs):
      # The inicialization is taken from rst2pdf.flowables.Heading
      self.stext = kwargs.pop('text')
      # Cleanup title text
      self.stext = re.sub(r'<[^>]*?>', '', unescape(self.stext))
      self.stext = self.stext.strip()

      # Stuff needed for the outline entry
      self.snum = kwargs.pop('snum')
      self.level = kwargs.pop('level')
      self.parent_id= kwargs.pop('parent_id')

      MyImage.__init__(self, *args, **kwargs)

  def drawOn(self,canv,x,y,_sW):

      ## These two lines are magic.
      #if isinstance(self.parent_id, tuple):
          #self.parent_id=self.parent_id[0]

      # Add outline entry. This is copied from rst2pdf.flowables.heading
      canv.bookmarkHorizontal(self.parent_id,0,0+self.image.height)

      if canv.firstSect:
          canv.sectName = self.stext
          canv.firstSect=False
          if self.snum is not None:
              canv.sectNum = self.snum
          else:
              canv.sectNum = ""

      canv.addOutlineEntry(self.stext.encode('utf-8','replace'),
                                self.parent_id.encode('utf-8','replace'),
                                int(self.level), False)

      # And let MyImage do all the drawing
      MyImage.drawOn(self,canv,x,y,_sW)

And how do we tell rst2df to use that instead of a regular Heading? by overriding the TitleHandler class. Here's where the extension magic kicks in.

If you define, in an extension, a class like this:

class FancyTitleHandler(genelements.HandleParagraph, docutils.nodes.title):

Then that class will handle all docutils nodes of class docutils.nodes.title. Here, I just took rst2pdf.genelements.HandleTitle and changed how it works for level-1 headings, making it generate a FancyHeading instead of a Heading... and that's all there is to it.

class FancyTitleHandler(genelements.HandleParagraph, docutils.nodes.title):
  '''
  This class will handle title nodes.

  It takes a "titletemplate.svg", replaces TITLEGOESHERE with
  the actual title text, and draws that using the FancyHeading flowable
  (see below).

  Since this class is defined in an extension, it
  effectively replaces rst2pdf.genelements.HandleTitle.
  '''

  def gather_elements(self, client, node, style):
      # This method is copied from the HandleTitle class
      # in rst2pdf.genelements.

      # Special cases: (Not sure this is right ;-)
      if isinstance(node.parent, docutils.nodes.document):
          #node.elements = [Paragraph(client.gen_pdftext(node),
                                      #client.styles['title'])]
          # The visible output is now done by the cover template
          node.elements = []
          client.doc_title = node.rawsource
          client.doc_title_clean = node.astext().strip()
      elif isinstance(node.parent, docutils.nodes.topic):
          node.elements = [Paragraph(client.gen_pdftext(node),
                                      client.styles['topic-title'])]
      elif isinstance(node.parent, docutils.nodes.Admonition):
          node.elements = [Paragraph(client.gen_pdftext(node),
                                      client.styles['admonition-title'])]
      elif isinstance(node.parent, docutils.nodes.table):
          node.elements = [Paragraph(client.gen_pdftext(node),
                                      client.styles['table-title'])]
      elif isinstance(node.parent, docutils.nodes.sidebar):
          node.elements = [Paragraph(client.gen_pdftext(node),
                                      client.styles['sidebar-title'])]
      else:
          # Section/Subsection/etc.
          text = client.gen_pdftext(node)
          fch = node.children[0]
          if isinstance(fch, docutils.nodes.generated) and \
              fch['classes'] == ['sectnum']:
              snum = fch.astext()
          else:
              snum = None
          key = node.get('refid')
          maxdepth=4
          if reportlab.Version > '2.1':
              maxdepth=6

          # The parent ID is the refid + an ID to make it unique for Sphinx
          parent_id=(node.parent.get('ids', [None]) or [None])[0]+u'-'+unicode(id(node))
          if client.depth > 1:
              node.elements = [ Heading(text,
                      client.styles['heading%d'%min(client.depth, maxdepth)],
                      level=client.depth-1,
                      parent_id=parent_id,
                      node=node,
                      )]
          else: # This is an important title, do our magic ;-)
              # Hack the title template SVG
              tfile = open('titletemplate.svg')
              tdata = tfile.read()
              tfile.close()
              tfile = tempfile.NamedTemporaryFile(dir='.', delete=False, suffix='.svg')
              tfname = tfile.name
              tfile.write(tdata.replace('TITLEGOESHERE', text))
              tfile.close()

              # Now tfname contains a SVG with the right title.
              # Make rst2pdf delete it later.
              client.to_unlink.append(tfname)

              e = FancyHeading(tfname, width=700, height=100,
                  client=client, snum=snum, parent_id=parent_id,
                  text=text, level=client.depth-1)

              node.elements = [e]

          if client.depth <= client.breaklevel:
              node.elements.insert(0, MyPageBreak(breakTo=client.breakside))
      return node.elements

The full extension is in SVN and you can try it this way:

[fancytitles]$ rst2pdf -e fancytitles -e inkscape demo.txt -b1

You need to enable the Inkscape extension so the SVG will look nice. And here's the output:

You can override how any element is handled. That's being extensible :-)

This is why Qt (and PyQt) are cool

Alejandro Dolina once wrote (and this is from memory that's probably 25 years old) of a round table discussing "What's Tango?", and how after two hours of discussing the nature, characteristics and history of tango, one of the members of the panel picked up a bandoneÃ³n, played "El apache argentino" stood up and left without saying a word.

So, why are Qt and PyQt cool?

Audio player widget:

# -*- coding: utf-8 -*-

import sys, os
from PyQt4 import QtCore, QtGui, uic
from PyQt4.phonon import Phonon
import icons_rc

class AudioPlayer(QtGui.QWidget):
    def __init__(self, url, parent = None):

        self.url = url

        QtGui.QWidget.__init__(self, parent)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding,
            QtGui.QSizePolicy.Preferred)

        self.player = Phonon.createPlayer(Phonon.MusicCategory,
            Phonon.MediaSource(url))
        self.player.setTickInterval(100)
        self.player.tick.connect(self.tock)

        self.play_pause = QtGui.QPushButton(self)
        self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))
        self.play_pause.clicked.connect(self.playClicked)
        self.player.stateChanged.connect(self.stateChanged)

        self.slider = Phonon.SeekSlider(self.player , self)

        self.status = QtGui.QLabel(self)
        self.status.setAlignment(QtCore.Qt.AlignRight |
            QtCore.Qt.AlignVCenter)

        self.download = QtGui.QPushButton("Download", self)
        self.download.clicked.connect(self.fetch)

        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.play_pause)
        layout.addWidget(self.slider)
        layout.addWidget(self.status)
        layout.addWidget(self.download)

    def playClicked(self):
        if self.player.state() == Phonon.PlayingState:
            self.player.pause()
        else:
            self.player.play()

    def stateChanged(self, new, old):
        if new == Phonon.PlayingState:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_pause.svg'))
        else:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))

    def tock(self, time):
        time = time/1000
        h = time/3600
        m = (time-3600*h) / 60
        s = (time-3600*h-m*60)
        self.status.setText('%02d:%02d:%02d'%(h,m,s))

    def fetch(self):
        print 'Should download %s'%self.url

def main():
    app = QtGui.QApplication(sys.argv)
    window=AudioPlayer(sys.argv[1])
    window.show()
    # It's exec_ because exec is a reserved word in Python
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

Video player widget:

import sys, os
from PyQt4 import QtCore, QtGui, uic
from PyQt4.phonon import Phonon
import icons_rc

class VideoPlayer(QtGui.QWidget):
    def __init__(self, url, parent = None):

        self.url = url

        QtGui.QWidget.__init__(self, parent)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding,
            QtGui.QSizePolicy.Preferred)

        self.player = Phonon.VideoPlayer(Phonon.VideoCategory,self)
        self.player.load(Phonon.MediaSource(self.url))
        self.player.mediaObject().setTickInterval(100)
        self.player.mediaObject().tick.connect(self.tock)

        self.play_pause = QtGui.QPushButton(self)
        self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))
        self.play_pause.clicked.connect(self.playClicked)
        self.player.mediaObject().stateChanged.connect(self.stateChanged)

        self.slider = Phonon.SeekSlider(self.player.mediaObject() , self)

        self.status = QtGui.QLabel(self)
        self.status.setAlignment(QtCore.Qt.AlignRight |
            QtCore.Qt.AlignVCenter)

        self.download = QtGui.QPushButton("Download", self)
        self.download.clicked.connect(self.fetch)
        topLayout = QtGui.QVBoxLayout(self)
        topLayout.addWidget(self.player)
        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.play_pause)
        layout.addWidget(self.slider)
        layout.addWidget(self.status)
        layout.addWidget(self.download)
        topLayout.addLayout(layout)
        self.setLayout(topLayout)

    def playClicked(self):
        if self.player.mediaObject().state() == Phonon.PlayingState:
            self.player.pause()
        else:
            self.player.play()

    def stateChanged(self, new, old):
        if new == Phonon.PlayingState:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_pause.svg'))
        else:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))

    def tock(self, time):
        time = time/1000
        h = time/3600
        m = (time-3600*h) / 60
        s = (time-3600*h-m*60)
        self.status.setText('%02d:%02d:%02d'%(h,m,s))

    def fetch(self):
        print 'Should download %s'%self.url

def main():
    app = QtGui.QApplication(sys.argv)
    window=VideoPlayer(sys.argv[1])
    window.show()
    # It's exec_ because exec is a reserved word in Python
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

...

Desktop apps and clouds (with video)

I enjoy creating desktop applications. That means I may be a member of a dying breed, since web apps are going to make us all obsolete next week, but I do enjoy doing it.

The bad side of it is, of course that sometimes it's much more convenient to use a web application. For example, I have abandoned my own baby (uRSSus) because google reader is just easier and more convenient to use.

But then I thought... what bothers me of uRSSus? And there are quite a few things!

It's not in all computers I may use

That means I will not ever be able to use it exclusively.

It's pretty useless without an Internet connection (but so is google reader mostly)

Since I can't use it exclusively, I end with feeds on uRSSus that are not on google reader and viceversa.

It's freaking slow

So, I decided to see what I could do about that without giving up the good side of uRSSus:

It looks much nicer than a web app, because it looks like a desktop app

It does things like opening the site instead of showing the feed item (great for partial content feeds)

I wrote it (yes, that's a feature for me. I like self-made programs)

So, this attempt at rewriting the desktop RSS reader produced this:

As you can see in the above video, this reader syncs the subscription list to google reader. It will also eventually sync your read/unread posts.

It still can open full sites instead of feed items, it has/will have a heck of an offline mode (full pages captured as images, for example), and... it's very very fast.

It's much faster than google reader in Chromium, and hella faster than uRSSus. That was done via smarter coding, so it probably means I was braindead before and experienced a minor recovery.

The code is not fit for release (for example, the database schema will change) but you can try it: http://code.google.com/p/kakawana/source/checkout

Discutiendo con cualquiera parte III: Darwin y porquÃ© se le diÃ³ una difusiÃ³n mundial.

Once more for any english-reading audience, this is only in spanish because I don't want to translate the nonsense I'm replying to.

Bienvenidos al capÃtulo III de mi serie "Discutiendo con cualquiera", donde analizo el contenido de Â¿Por quÃ© creo en Dios cientÃficamente? . El menÃº del dÃa es...

Â» CapÃtulo III â Darwin y porquÃ© se le diÃ³ una difusiÃ³n mundial.

Ya en el capÃtulo II el autor demuestra su total ignorancia del mÃ©todo cientÃfico y su absoluta incomprensiÃ³n de la teorÃa de Darwin y sus modificaciones. Veamos ahora como sigue la cosa...

Si bien desde niÃ±o ya intuitivamente descreÃa la teorÃa de la evoluciÃ³n y luego fui comprobando su falsedad, siempre me admirÃ³ el porquÃ© se difundiÃ³ tanto.

Claro, si es una cosa tan obviamente falsa para el autor, su popularidad entre el resto de la gente probablemente sea... Â¡una conspiraciÃ³n!

Siempre ha habido cientÃficos que la aceptaban y quienes la rechazaban, pero avanzÃ³ con tal fuerza para ser una teorÃa que todo debÃa decirse en tÃ©rminos de evoluciÃ³n.

No. Hay montones de teorÃas no evolutivas de las cosas. AÃºn suponiendo que estemos hablando Ãºnicamente de biologÃa, esto no es cierto. Pero dÃ©mosle el beneficio de la duda al autor y supongamos que estÃ¡ aplicando hipÃ©rbole.

Cuando el ganso necesitÃ³ volar le crecieron las alas, cuando el ser humano necesitÃ³ pensar obtuvo su inteligencia.

Este error viene de arrastre. La evoluciÃ³n no es una fuerza dirigida a satisfacer las necesidades de nadie. Es un enfoque completamente errÃ³neo.

Por ridÃcula que fuera la frase siempre tenÃa que aludir a la teorÃa de la evoluciÃ³n. Para los evolucionistas si un animal tiene un ojo era que lo necesitaba. AsÃ quedaron cosas ridÃculas de establecer como el radar de los murciÃ©lagos. Pero todo el tiempo lo puede segÃºn ellos.

Poner palabras en boca de los demÃ¡s no es buena educaciÃ³n, sobre todo si son inventos suyos.

Para describir a una ballena, se debe decir que tienen extremidades anteriores que han evolucionado hasta convertirse en aletas, aunque sus huesos todavÃa muestran reminiscencias de elementos Ã³seos articulados en dedos y con extremidades posteriores que se han perdido por completo y sin ninguna conexiÃ³n entre estas y la cola. Para el humano comÃºn bastaba decir que la ballena tiene aletas y cola y nada mÃ¡s.

Para el humano comÃºn esta computadora es grande y gris. Para mÃ es un P4 2.6Ghz con 2GB de RAM corriendo Arch Linux actualizado a ayer con driver legacy nVidia. Las descripciones de las cosas varÃan de acuerdo a quien las hace y para quÃ© las hace.

Si un biÃ³logo describiera una ballena como un bicho grande con aletas y cola es un ganso (el biÃ³logo, no la ballena).

Siempre me maravillÃ³ esta persistencia en describir todo como si alguna vez alguien hubiera desenterrado una ballena con 4 patas y que la comparaciÃ³n algo mÃ¡s real que la imaginaciÃ³n totalmente fuera de la ciencia del relator.

Â¡Bueno, pero resulta que sÃ se han desenterrado ballenas con patas!

Veamos algunos ejemplos:

MÃ¡s informaciÃ³n en http://tinyfrog.wordpress.com/2008/02/01/pz-myers-vs-geoffrey-simmons-discovery-institute/

Que interesante no? Se puede ver como los miembros posteriores se reducen comenzando con Rodhocetus, casi no existen en Dorudon y desaparecen en Basilosaurus.

Esto no fue mas que otro ejemplo de el autor creyendo que su ignorancia es prueba de algo. Ãl no conoce fÃ³siles de protoballenas, entonces las protoballenas son un mito.

Esta manÃa de todo explicarlo como si realmente hubiera sucedido, que sÃ³lo tiene un paralelo en los polÃticos que pueden disfrazar la estafa mÃ¡s burda como una necesidad del pueblo.

Demagogia barata.

Cuando leÃ el excelente libro de Harun Yanya, el engaÃ±o del evolucionismo, no sÃ³lo encontrÃ© un libro que reflejaba la mayor parte de mis ideas sino que a su vez me dio una razÃ³n valedera de que la teorÃa de la evoluciÃ³n que era por lo menos muy discutible y con innumerables problemas que el mismo Darwin no podÃa resolver, haya evolucionado a tal punto de ser usada como verdad absoluta en gran parte de los escritos.

La teorÃa de la evoluciÃ³n tiene problemas y antes ha tenido otros. Es la naturaleza de la ciencia que todas las "verdades" son provisorias y sujetas a correcciÃ³n. Obrar de otra manera o aceptar otra cosa es apartarse de la ciencia y entrar en el dogma religioso, tentaciÃ³n a la que el autor no se resiste en ningÃºn momento.

Algo sin ninguna base cientÃfica, con problemas desde el origen, no deberÃa âevolucionarâ tan fÃ¡cilmente en una teorÃa universalmente aceptada. Â¿PorquÃ© los detractores de la teorÃa no tuvieron difusiÃ³n?

Â¿QuÃ© detractor no tuvo difusiÃ³n? Cuando Darwin publicÃ³ su libro, fue ridiculizado en los medios por montones de personas hoy casi olvidadas, excepto por la referencia de "este es el que se reÃa de Darwin".

Y siendo una teorÃa tan difundida tambiÃ©n me llamaba la atenciÃ³n que no se difundiera todos los arreglos a la teorÃa de lo que se denomina neodarwinismo que pretende mantener algunas pocas bases de los postulados y a la vez subsanar los problemas insalvables con nuevas teorÃas Â¿porquÃ© enseÃ±ar la teorÃa que hasta sus defensores consideran equivocada?

Â¿A quÃ© se refiere con que no se difunden? Dawkins vendiÃ³ muchÃsimas copias de "El relojero ciego", Gould vendiÃ³ muchÃsimas de sus libros de divulgaciÃ³n. Que el autor no haya oÃdo acerca de los cambios posteriores a 1870 habla mal de Ã©l solamente.

Harun introduce un concepto bÃ¡sico. La difusiÃ³n de la teorÃa de la evoluciÃ³n tiene un objetivo claro, apuntalar la filosofÃa âmaterialistaâ que sostiene que lo Ãºnico que existe es la materia, esencia para ellos de todo lo orgÃ¡nico e inorgÃ¡nica negando un Dios creador.

Â¿A quiÃ©nes se supone que se acusa de querer hacer eso? Cuando se firmÃ³ ese acuerdo, y porquÃ© no me pagan mi parte para ser miembro de la conspiraciÃ³n, es lo que yo quiero saber.

Al no tener mas que el nivel de materia, el hombre repara solamente en Ã©l, y no necesita de valores morales, y va mas allÃ¡ al abolir cualquier valor bÃ¡sico de Ã©tica y sociedad.

Para ser este un escrito que pretende probar la existencia de dios de forma cientÃfica, el autor parece simplemente asumir que no sÃ³lo dios existe, sino que es la fuente de toda moral y Ã©tica. Estas payasadas de primaria no merecen mayor respuesta que: soy ateo y soy moral, chupÃ¡te esa mandarina.

El resultado polÃtico de la filosofÃa materialista es el comunismo. El cual entre sus premisas siempre fue netamente antirreligioso.

Uhhhhh los comunistas, yo sabÃa que los comunistas tenÃan algo que ver con esto.

Es un hecho que Marx escribiera en el libro para Engels âEl origen de las Especies"Â¨ lo siguiente âeste es el libro que contiene los fundamentos de la historia natural para nuestros puntos de vistaâ. Tanto Marx como Engels, declaradamente ateos, tienen en su base el terminar con las creencias religiosas. El comunismo en su lucha de la guerra frÃa fue el mayor impulsor de las teorÃas de evoluciÃ³n dado que Ã©stas confrontan directamente con bases de la religiÃ³n

Por adonde empiezo... el bloque comunista era anti darwinista. La teorÃa "oficial" de la UniÃ³n SoviÃ©tica era el LysenkoÃsmo, o Lysenko-Michurinismo, que es una variante de la evoluciÃ³n Lamarckiana de la heredabilidad de los caracteres adquiridos. Es muy distinta de todas las cosas que el autor ha mencionado hasta ahora, y era ya una teorÃa perimida en occidente a fines del siglo XIX.

Por ejemplo, una de las teorÃas de Lysenko era que si uno arrancaba las hojas de las plantas de algodÃ³n producirÃa plantas sin hojas por herencia.

O sea, el autor no sÃ³lo no tiene idea, no tiene idea de que no tiene idea.

sugiriendo que Dios no es necesario para la creaciÃ³n. Esta es sin duda uno de los pilares de la aprobaciÃ³n de una teorÃa ridÃcula y sin bases como la de la evoluciÃ³n.

Desde ya que es imposible hacer ciencia si uno tiene (literalmente) un deus ex machina preparado para cada cosa que le cueste. JÃ¡, no tenemos una teorÃa completa para la abiogÃ©nesis => Dios lo hizo!

TambiÃ©n Harun dÃ¡ otras razones de la feroz defensa de las teorÃas de Darwin explicadas en que los cientÃficos son primeros materialistas y luego cientÃficos, por lo que estÃ¡n obligados a crear un aparato de investigaciÃ³n y un conjunto que produzcan explicaciones materialistas sin poder permitirse poner un pie en el umbral divino.

Por supuesto que los cientÃficos deben buscar una explicaciÃ³n materialista a los fenÃ³menos observables, ese es su trabajo. Si Mendel hubiera dicho "estas arvejas son marrones porque dios asÃ lo dispone" entonces los libros de genÃ©tica serÃan muy cortos.

Harun destaca que el evolucionismo no es capaz ni siquiera de explicar una simple proteÃna y va mas allÃ¡ en explicar lo que llama las fÃ¡bulas de transiciÃ³n del agua a la tierra, de la tierra al aire y otras interpretaciones falaces y falsificaciones de los evolucionistas. Recomiendo la lectura que es libre en www.harunyahya.org

Un delirante por vez. Ya le tocarÃ¡ a Harun mÃ¡s adelante.

Es cierto que los mayores defensores de la teorÃa de la evoluciÃ³n y todas las teorias posteriores que intentan explicar lo inexplicable son ateos o agnÃ³sticos, entonces su defensa es tambiÃ©n una religiÃ³n.

No se sigue una cosa de la otra. La compulsiÃ³n de decir que cualquier cosa que no le gusta a un creyente es la religiÃ³n de los ateos es irritante.

Desde el punto de vista cientÃfico es muy buena la tenacidad de demostrar lo indemostrable pues contribuye al conocimiento. Muchos cientÃficos, paleontÃ³logos, investigadores, etc. se encontrarÃan sin trabajo si simplemente se aceptara que la creaciÃ³n fue hecha indubitablemente por Dios.

Obviamente. Igual que los mÃ©dicos, quÃmicos, fÃsicos, y cualquier otro cientÃfico. Es mÃ¡s, permÃtame afirmar que hasta los directores tÃ©cnicos de fÃºtbol verÃan su trabajo reducido:

"Vamos perdiendo 1 a 0 y faltan 15 minutos, hay que hacer un cambio" -- "No, si vamos perdiendo es porque dios indubitablemente asÃ lo dispuso".

AsÃ que ya sea por intereses puntuales de desarrollar un proyecto, por premisas del comunismo, por premisas de ateos o agnÃ³sticos, por intereses econÃ³micos y por la ciencia misma las teorÃas de la evoluciÃ³n tienen que seguir fingiendo ser una ciencia y festejar todo hallazgo esclarecedor sobre los estudios hechos.

Desde ya que cada hallazgo esclarecedor merece ser festejado. Para eso se estudia y se investiga, para lograr esclarecer cosas. Me pregunto, si el autor desprecia tanto la ciencia, Â¿porquÃ© se ha tomado la molestia de escribir toda esta parva de sandeces "cientÃficas" segÃºn Ã©l?

Como el gradualismo es totalmente descartado aÃºn por los mas acÃ©rrimos defensores de Darwin, las nuevas teorÃas quieren mantener todo el esquema de la evoluciÃ³n pero sin gradualismo.

SÃ, se descarta lo que parece no funcionar, se mantiene lo que parece funcionar. Eso se llama pensar.

Dicho de manera compleja puede ser atendido los postulados, pero cuando uno los resume para que quede claro la teorÃa finalmente dice que de un reptil un dÃa naciÃ³ un ave, o de un ratÃ³n naciÃ³ un dÃa un murciÃ©lago.

No, eso es una pavada. Creo distinguir un problema en el entendimiento del autor (bah, uno de tantos). No hay sÃ³lo dos puntos en la escala. No es "cambios infinitesimales o pasamos de un ratÃ³n a un murciÃ©lago". Es posible tener cambios grandes, cambios chicos, cambios muy chiquititos y cambios imperceptibles.

Por ejemplo, estÃ¡ determinado como una mutaciÃ³n provocÃ³ el desarrollo de la visiÃ³n tricromÃ¡tica en primates americanos (los africanos no la tienen). Se sabe cual es el gen que provoca el cambio y todo. No es que de golpe hubo un simio volador, es que con algunos cambios menores en el genoma hay un simio que ve distinto.

Todo adornado con una fÃ¡bula para niÃ±os, como que el ratÃ³n se veÃa perseguido asi que necesitaba alas, y bueno un dÃa le crecieron, e iba perdiendo la vista y necesitaba no chocarse con los objetos y entonces un dÃa naciÃ³ un murciÃ©lago con radar y de ahÃ todos los murciÃ©lagos aprendieron a nacer u usar el radar. Falta el hada madrina de los cuentos de niÃ±os, pero seriamente un cientÃfico no puede decir cosas asÃ.

"Un dÃa le crecieron [las alas]" me suena mÃ¡s a una pelÃcula de Capra que a biologÃa evolutiva. El autor expresa una caricatura para poder sentirse inteligente mostrando que la caricatura que crea no es correcta. Es un recurso retÃ³rico transparente y deshonesto.

Cada vez que aparece un texto de algÃºn hallazgo me tomo el trabajo de leerlo para ver si en algo pudiera cambiar el 0% de probabilidad de las teorÃas de la evoluciÃ³n puedan alguna vez demostrarse en alguna especie.

Bueno, que opina de una bacteria que de golpe puede digerir un nutriente que antes no podÃa, eso le gusta como evoluciÃ³n en una especie? lealo aquÃ (cuidado, contiene autÃ©ntica ciencia!)

AsÃ, por ejemplo leo un descubrimiento que trata de contestar lo que Darwin se preguntaba, Â¿de dÃ³nde habÃa salido el murciÃ©lago?, una criatura nocturna, voladora y ciega que parecÃa desafiar las leyes de la selecciÃ³n natural.

El articulo increÃblemente sigue dando como cierta la evoluciÃ³n gradual, teorÃa que ya ha sido abandonada y pasa a preguntarse Â¿QuÃ© surgiÃ³ antes, la capacidad de volar o la de orientarse en la noche por sonidos?, como si ello pudiera ser cierto.

Â¿QuÃ© artÃculo? Uno de los conceptos bÃ¡sicos es que si uno tiene referencias debe compartirlas, para que el lector pueda comparar lo que dice realmente con lo que el autor proclama que dice.

Luego relata la apariciÃ³n en un yacimiento de Wyoming del fÃ³sil de una nueva especie de murciÃ©lago, y entonces ya define la respuesta buscada: âprimero aprendieron a volar, despuÃ©s desarrollaron su peculiar sentido de radar.â

Bueno, si hay un murciÃ©lago anterior a los conocidos que volaba y no tenÃa ecolocaciÃ³n es medio obvio llegar a esa conclusiÃ³n.

âLo real es que se encontrÃ³ casi intacto y con 52 millones de aÃ±os, el murciÃ©lago mÃ¡s antiguo que se conoce. TenÃa alas capaces de hacerle volar, lo que se cree que hacÃa batiÃ©ndolas y planeando alternativamente, pero no tenÃa una cÃ³clea (o caracol) en el oÃdo interno lo bastante grande como para detectar obstÃ¡culos mediante el rebote del sonido.â

Parece bastante razonable.

Luego saca conclusiones exquisitas que tienen 100% de fÃ¡bula y 0%de posibilidad de ajustarse a la realidad, por ejemplo lo nombra antecesor de los murciÃ©lagos actuales, aun cuando es una especie distinta y nada hace presumir una relaciÃ³n mÃ¡s que la que a la fÃ¡bula le conviene.

Bueno, si a priori vamos a asumir que no es posible que sea un ancestro de los murciÃ©lagos actuales va a ser difÃcil mostrar evidencia que te convenza. Veamos porquÃ© podrÃa ser un ancestro de los otros murciÃ©lagos.

Tiene 52 millones de aÃ±os

Los otros fÃ³siles de murciÃ©lago son mÃ¡s recientes

Es claramente un murciÃ©lago

Entonces o creÃ©s que dios creÃ³ murciÃ©lagos parecidos una y otra vez, y no te vamos a poder convencer sin importar los fÃ³siles que se encuentren.... o es un ancestro de los murciÃ©lagos mÃ¡s modernos.

O, por supuesto, no lo era, sino que era otra rama y ambos tienen un ancestro comÃºn, pero para el caso es mÃ¡s o menos lo mismo, o es algo que era muy muy muy parecido a un murciÃ©lago por evoluciÃ³n convergente, pero eso serÃa muy raro.

âAgrega que debieron ser diurnos y tener una visiÃ³n normal en algÃºn momento de su evoluciÃ³nâ, la fÃ¡bula es llevada al desvarÃo, pues como se verÃ¡ luego la parte de la visiÃ³n es una fantasÃa, y la definiciÃ³n de murciÃ©lago, por su origen del latÃn es de ratÃ³n ciego. (al menos sin la visiÃ³n normal de otros animales)

Ah, bueno, decidir quÃ© es y quÃ© no es un murciÃ©lago en base a la etimologÃa de la palabra es nuevo. Es una idiotez, pero es nuevo por lo menos para mÃ.

Los murciÃ©lagos no son todos ciegos. Hay variedades que ven mÃ¡s, y otras que ven menos. Los murciÃ©lagos frugÃvoros suelen tener capacidad de visiÃ³n similar a la de las ratas, por ejemplo.

AsÃ que segÃºn la novedosa clasificaciÃ³n del seÃ±or que cito, la mayorÃa de los murciÃ©lagos... no son murciÃ©lagos.

MÃ¡s incoherente es que segÃºn su propio relato, al menos en la traducciÃ³n, se afirma que mirando el esqueleto no se puede deducir cientÃficamente que era diurno.

Y serÃ¡ que no se puede, no es culpa del paleontÃ³logo que no se pueda.

Hasta inventan una mejor teorÃa, âque algo, probablemente la amenaza de un depredador, les obligÃ³ a meterse en las cuevas y fueron perdiendo este sentido (la vista), para aprender a vivir en la oscuridad de dos formas: mediante una potente visiÃ³n nocturna, o desarrollando el sentido de la eco colocaciÃ³n, es decir, la capacidad de orientarse por sonidos como hace un radar.â SegÃºn el artÃculo esta fue esta Ãºltima adaptaciÃ³n la que originÃ³ a los actuales murciÃ©lagos, animales de los que existe una inmensa variedad de especies.

Dado que no tengo acceso al artÃculo no puedo opinar sobre la parÃ¡frasis presentada.

AdemÃ¡s agrega "Era claramente un murciÃ©lago, pero no se parecÃa a ninguno antes conocido. En muchos aspectos, es el eslabÃ³n perdido entre los murciÃ©lagos y sus ancestros no voladores".

Â¿Pero no era que no habÃa eslabones perdidos, que en todo el registro fÃ³sil no habÃa nada como eso? Â¡Seguramente ahora el autor va a demoler esta aseveraciÃ³n!

La realidad frÃa es que todo es una fÃ¡bula para niÃ±os. Los murciÃ©lagos son miles de especies que fueron diseÃ±adas para vivir en las cuevas y volar de noche y regular la cantidad de insectos entre otras funciones.

Ah no, en vez de refutar, simplemente califica de fÃ¡bula y pasa a otra cosa. Los murciÃ©lagos no fueron diseÃ±ados. El autor estÃ¡ asumiendo sus propias tesis.

No son ciegos tampoco.

Â¡Â¡Â¡Â¡Pero acabÃ¡s de decir "la definiciÃ³n de murciÃ©lago, por su origen del latÃn es de ratÃ³n ciego"!!!! Â¡Hace tres renglones lo dijiste!

aunque su mayor visiÃ³n es acÃºstica. Aunque lo que hayan encontrado sea realmente un murciÃ©lago muy diferente, al ser de una familia tan numerosa Â¿como probar que es antecesor del resto de las especies y no un primo mas?

Porque el registro fÃ³sil no muestra murciÃ©lagos con capacidad de ecolocalizaciÃ³n anteriores a Ã©se, por ejemplo (no me consta).

Â¿SÃ³lo los depredadores atacaban los murciÃ©lagos, y atacaban a todos? Â¿En las cuevas todas las especies perdieron la vista y todas desarrollaron el radar?

La disminuciÃ³n de la capacidad visual de los animales que viven en espacios completamente oscuros estÃ¡ documentada en muchas especies.

Cuando la teorÃa de la evoluciÃ³n de las especies estaba en sus primeros tiempos, por decirlo de alguna manera en un perÃodo romÃ¡ntico, podÃa ser a primeras luces ser algo posible. Con lo que sabemos ahora de que lo gradual no puede ser posible, cada especie actual deberÃa ser creada por un accidente biolÃ³gico.

De hecho, por varios accidentes.

Un dato interesante de las nuevas teorÃas es que el dios âtiempoâ ya no existe como tal, ya no son necesarios miles de aÃ±os. AsÃ segÃºn las nuevas teorÃas el ADN de un murciÃ©lago con vista y sin radar deberÃa haber mutado a uno con radar sin vista, para transformarlo en una nueva especie.

No, las "nuevas teorÃas" no dicen eso. El autor estÃ¡ escuchando voces.

Algo asÃ como los cruzamientos dentro de la misma especie, algo como la uniÃ³n entre yegua y burro para formar una mula, solo que generando una nueva especie.

Los caballos y los burros son distintas especies, tienen hasta un nÃºmero distinto de cromosomas.

Este tipo de accidente tendrÃa que darse para cada especie existente y en una cantidad de casos que permitiera la reproducciÃ³n sin degradaciÃ³n genÃ©tica, algo cuya probabilidad es cero. A eso por supuesto hay que sumarle la casualidad de que este accidente biolÃ³gico justo sÃ³lo le sucediera a los murciÃ©lagos, porque ya vivÃan en cuevas y ya estarÃan perdiendo la vista.

DesvarÃos, afirmaciones sin base, refutaciÃ³n de posiciones que sÃ³lo Ã©l presenta...

La genÃ©tica no se altera por acciones del individuo. 100% fÃ¡bula y 0% de ciencia en algo que por supuesto ni podrÃamos tratar de demostrar de cÃ³mo se gana la funciÃ³n de radar justo cuando se la necesitaba.

De nuevo se aprecia gran confusiÃ³n. La evoluciÃ³n no te da las cosas cuando las querÃ©s. No es "llego tarde al laburo, necesito mutar para mejorar mi glicÃ³lisis". No es X-Men. Demuestra ignorancia completa de los mecanismos propuestos para la variabilidad genÃ©tica y del rol que cumple la selecciÃ³n natural.

Lo real, es que sin base cientÃfica, sin demostraciÃ³n, las teorÃas son sÃ³lo fÃ¡bulas. Teniendo en cuenta que el 20% de las especies vivientes de mamÃferos son murciÃ©lagos, como lo reconoce el mismo artÃculo y que aun hoy aparecen frecuentemente nuevas variedades de murciÃ©lagos vivos aun no identificadas, poco puede afirmarse sobre una nueva especie fosilizada.

SÃ, puede afirmarse que parecÃa capaz de volar, incapaz de usar ecolocalizaciÃ³n, y que parece ser mÃ¡s antiguo que los demÃ¡s. Que es lo que hicieron. Y con eso uno puede suponer algo mÃ¡s, que es lo que hicieron. No probarlo, pero sÃ suponerlo.

Lo que descubrieron no tiene que ver con los actuales y de hecho presumen que no tenÃa radar. Las extremidades traseras mÃ¡s largas y las delanteras mÃ¡s cortas que los actuales murciÃ©lagos, âsugieren que viviÃ³ en los Ã¡rboles y que era un buen trepador, parecido en este sentido a los gibones (monos arborÃcolas) o a los perezosos (mamÃferos desdentados de la AmÃ©rica tropical).â

El mismo articulo aunque decÃa que era diurno se contradice afirmando que no ha quedado aÃºn claro es si esta especie vivÃa de dÃa o de noche. "Un examen de las cuencas de los ojos podrÃa ayudar, ya que los animales nocturnos sin eco-colocaciÃ³n tienen ojos mÃ¡s grandes y, por tanto, cuencas mÃ¡s grandes, Por desgracia, esa zona del crÃ¡neo es de lo poco que ha quedado daÃ±ado del fÃ³sil sin posibilidad de reconstrucciÃ³n, asÃ que habrÃ¡ que esperar nuevas evidencias. â

Â¿CÃ³mo probar que es un antecesor? Â¿u otra especie? Â¿o simplemente otro individuo de la misma familia?

Â¿Como probamos que un chimpancÃ© no es un gorila ni un mono titÃ? Â¿Como probamos que el que escribe estas cosas no es un mandril? Con un cuidadoso estudio morfolÃ³gico, porque leyÃ©ndolo no estoy seguro.

Por supuesto que si no encontraran cada tanto algo para hacer un rimbombante anuncio, Â¿como seguirÃan obteniendo presupuesto? En favor de la ciencia, la fÃ¡bula debe continuar con el mayor agregado posible. Por supuesto los cientÃficos pueden salir del nivel mundano de la fÃ¡bula y explicar con razonamientos cientÃficos tan complejos que puede uno lejos perderse sin poder refutar nada, pero bastarÃ¡ que lo haga, para que otros cientÃficos se encarguen de refutar cientÃficamente la propuesta.

"Mami mami, la ciencia es complicada y me hace doler la cabeza, hacÃ© que los hombres malos se vayan".

Las teorÃas de la mutaciÃ³n beneficiosa de una especie en otra son hermosas pero nunca abandonan el porcentaje de cero de probabilidad de que ocurran. Ni hay casos observados de la creaciÃ³n de una nueva especie.

SÃ, si hay. Ver http://www.talkorigins.org/faqs/faq-speciation.html

Por otro lado no hay ninguna teorÃa que supere el 0% de probabilidad de ser cierta que explique cÃ³mo un ser orgÃ¡nico puede ser hecho de sustancias inorgÃ¡nicas, ni como una nueva especie sin ningÃºn antecesor puede haber sido creada de especies inferiores.

Eso es un problema distinto. La teorÃa de la evoluciÃ³n no resuelve el problema de la abiogÃ©nesis. Tampoco me ayuda a conseguir donde estacionar en el centro. Son problemas separados.

No hay forma de demostrar o siquiera enunciar una teorÃa de accidentes biolÃ³gicos que permitan pasar de una especie a otra.

SÃ la hay, y tiene hasta resultados experimentales.

Cuando uno llega a entender la complejidad del ADN es totalmente imposible hoy mantener alguna teorÃa que permita pensar en que la casualidad, o un accidente realmente pueda crear un ADN nuevo con todas las virtudes de poder ser la guÃa del nacimiento y reproducciÃ³n de la nueva especie y que se produzca repetidamente para crear tal cantidad de nuevos organismos que por genÃ©tica luego logren desarrollarse.

El autor parece creer que es necesario que se produzca la misma idÃ©ntica mutaciÃ³n en N individuos para que se cree una nueva especie con una poblaciÃ³n inicial que le permita mantenerse.

Es un placer para mÃ aclararle que no funciona asÃ. Se produce una mutaciÃ³n en un individuo, que no evita la reproducciÃ³n con los otros miembros de la poblaciÃ³n. Si esa mutaciÃ³n es "beneficiosa" entonces se propaga en la poblaciÃ³n.

Al separarse y aislarse grupos, esta "deriva genÃ©tica" aumenta hasta que llega a ser imposible la reproducciÃ³n entre grupos. AhÃ se produce uno de los tipos posibles de especiaciÃ³n (hay otros tipos de especiaciÃ³n, por ejemplo por cambios de comportamiento).

Mientras mas se estudia, mayor es la cantidad de eventos simultÃ¡neos al azar que deberÃa suceder para que la teorÃa pudiera ser verdad. Sin aÃºn agregar el componente vida soslayado sistemÃ¡ticamente, se considera que la naturaleza en su azar deberÃa poder disponer de 100 proteÃnas diferentes en un mismo lugar para formar una cÃ©lula.

Formar una proteÃna tampoco es un evento fÃ¡cil de imaginar por azar. Si hoy un laboratorio no puede crear una cÃ©lula viva, aun teniendo todos los componentes Â¿como creer en una teorÃa que diga que la naturaleza si pudo?. Mucho se ha investigado a partir de los "ladrillos biolÃ³gicos de Miller" Pero por mucho que se ha intentado no hay una teorÃa vÃ¡lida.

Â¿Y? Â¿Que hay que hacer? Â¿Decir no saliÃ³, abandono, debe ser dios? Eso es ser cobarde.

En sus conclusiones, Dean Kenyon dice que es difÃcil comprender por quÃ© unos cientÃficos estÃ¡n dispuestos a admitir el pensamiento de que una inteligencia de alguna clase (dentro o fuera del universo) estuvo involucrada en la apariciÃ³n de la primera vida, mientras que otros aparentemente no lo estÃ¡n. Hay un margen de posiciones intermedias que cubren la distancia intelectual entre investigadores como Fox o Miller, y otros como Hoyle, Kenyon o Wilder-Smith.

Por ello, no es necesario salir del mundo racional para dirigirse en direcciÃ³n de una comprensiÃ³n cientÃfica francamente Â«teÃstaÂ» del origen de la vida, a no ser, naturalmente, que uno considere cualquier desviaciÃ³n del Â«optimismo naturalistaÂ» como irracional y anti-intelectual.

Bueno, es que lo es, por lo menos este que vengo leyendo y comentando. Aunque debo agradecer que todavÃa no haya usado la palabra "matemÃ¡ticamente" en este capÃtulo.

Kenyon concluye de que la vida demanda una creaciÃ³n sobrenatural (o al menos una inteligencia creadora dentro del universo) les parecerÃ¡ prematura a muchos, incluso si se conceden algunos mÃ©ritos a las principales crÃticas y argumentaciones positivas creacionistas.

La horrenda gramÃ¡tica me impide opinar. Literalmente no sÃ© que dice ahÃ.

Y seguirÃ¡ habiendo los que querrÃ¡n proseguir con sus actuales enfoques, sin importar lo que muestren los resultados. Siempre podrÃ¡n decir: Â«TodavÃa no hemos encontrado las condiciones experimentales correctasÂ». O, Â«SÃ³lo hemos estado haciendo experimentos especÃficamente relacionados con el problema del origen de la vida durante 30 aÃ±os. Dadnos tiempo. A fin de cuentas, se trata de un problema muy difÃcil. Al final encontraremos una descripciÃ³n evolucionista quÃmica plausibleÂ». O, Â«Es muy poco lo que se conoce actualmente del sistema genÃ©tico molecularÂ».

Bueno, sÃ, si se sabe poco hay que seguir estudiando. Ese siempre es buen consejo. OjalÃ¡ el autor lo hubiera seguido en vez de decidir que no valÃa la pena aprender nada y que su intuiciÃ³n es mejor que la ciencia.

Kenyon finaliza con una lista de seis problemas en el tratar de demostrar el origen de la vida.

Supongamos por un momento que todo lo que dice sea cierto...

No hay demostraciÃ³n de transiciÃ³n de lo inanimado a materia viviente en ausencia de sustancias preexistentes portadoras de informaciÃ³n genÃ©tica.

Â¿Y quÃ©?

No hay demostraciÃ³n en laboratorio de estados precursores realistas.

Â¿Y quÃ©?

No hay ninguna descripciÃ³n teÃ³rica convincente de posibles estados precursores.

Â¿Y quÃ©?

No hay registro fÃ³sil de estados precursores, incluyendo la inexistencia de evidencia geoquÃmica de un Â«caldo orgÃ¡nico prebiÃ³ticoÂ»

Â¿Y quÃ©?

No hay neo-biogÃ©nesis (origen de la vida hoy dÃa).

Â¿Y quÃ©?

No hay evidencia de vida extra-terrestre ni de estados materiales precursores encontrados en la exploraciÃ³n espacial hasta el dÃa de hoy.

Bueno, estÃ¡ ese meteorito marciano que mencionaste en el capÃtulo 1...

De nuevo, la ausencia de prueba no es prueba de la ausencia. Decir "no sÃ©" no es lo mismo que "debe haber sido dios". Una cosa no sigue de la otra, no es lÃ³gico, no es cientÃfico, es religiÃ³n maquillada. Y recordemos que se supone que estamos tratando de encontrar a dios "cientÃficamente".

Comentando acerca de la evidencia de un propÃ³sito inteligente inmanente en el universo, y la desgana de muchos cientÃficos a aceptar tal perspectiva, Hoyle a su vez escribÃa: "Esto es precisamente lo que los cientÃficos ortodoxos no estÃ¡n dispuestos a admitir. Porque podrÃa resultar que hubiera âa falta de una palabra mejorâ connotaciones religiosas, y porque los cientÃficos ortodoxos estÃ¡n mÃ¡s interesados en impedir un regreso a los excesos religiosos del pasado que en buscar la verdadâ

Hoyle dijo:

"La religiÃ³n no es mÃ¡s que un intento desesperado para escapar de la horrible posiciÃ³n en que nos encontramos. AquÃ estamos, en este universo maravilloso y no tenemos idea de si nuestra existencia tiene algÃºn significado. No es de extraÃ±ar que muchos sientan la necesidad de tener alguna creencia que les dÃ© una sensaciÃ³n de seguridad, y no es extraÃ±o que se enojen con gente como yo, que les decimos que eso es una ilusiÃ³n".

—"The Nature of the Universe" publicado en 1950.

Ya llevamos tres capÃtulos y no veo nada de ciencia, mucho menos ciencia aplicada a probar la existencia de dios. Los argumentos del autor parecen reducirse a ignorancia y declamaciÃ³n. Sospecho que no va a mejorar...

Slow-Slow and Fast-Fast (video)

My previous post explained how to cache whole web pages as images. Now see it in action. This is a lightweight RSS reader, optimized for comic books (but it works for any feed) and for offline use (but it works online too, of course).

Not ready for public use yet, but if you look around you can find the code somewhere ;-)

Capturing a webpage as an image using Pyhon and Qt

For a small project I am doing I wanted the capability to see web pages offline. So, I started thinking of a way to do that, and all solutions were annoying or impractical.

So, I googled and found CutyCapt which uses Qt and WebKit to turn web pages into images. Good enough for me!

Since I wanted to use this from a PyQt app, it makes sense to do the same thing CutyCapt does, but as a python module/script, so here's a quick implementation that works for me, even if it lacks a bunch of CutyCapt's features.

With a little extra effort, it can even save as PDF or SVG, which would let you use it almost like a real web page.

You just use it like this:

python  capty.py http://www.kde.org kde.png

And here's the code [download capty.py]

# -*- coding: utf-8 -*-

"""This tries to do more or less the same thing as CutyCapt, but as a
python module.

This is a derived work from CutyCapt: http://cutycapt.sourceforge.net/

////////////////////////////////////////////////////////////////////
//
// CutyCapt - A Qt WebKit Web Page Rendering Capture Utility
//
// Copyright (C) 2003-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// $Id$
//
////////////////////////////////////////////////////////////////////

"""

import sys
from PyQt4 import QtCore, QtGui, QtWebKit

class Capturer(object):
    """A class to capture webpages as images"""

    def __init__(self, url, filename):
        self.url = url
        self.filename = filename
        self.saw_initial_layout = False
        self.saw_document_complete = False

    def loadFinishedSlot(self):
        self.saw_document_complete = True
        if self.saw_initial_layout and self.saw_document_complete:
            self.doCapture()

    def initialLayoutSlot(self):
        self.saw_initial_layout = True
        if self.saw_initial_layout and self.saw_document_complete:
            self.doCapture()

    def capture(self):
        """Captures url as an image to the file specified"""
        self.wb = QtWebKit.QWebPage()
        self.wb.mainFrame().setScrollBarPolicy(
            QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
        self.wb.mainFrame().setScrollBarPolicy(
            QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)

        self.wb.loadFinished.connect(self.loadFinishedSlot)
        self.wb.mainFrame().initialLayoutCompleted.connect(
            self.initialLayoutSlot)

        self.wb.mainFrame().load(QtCore.QUrl(self.url))

    def doCapture(self):
        self.wb.setViewportSize(self.wb.mainFrame().contentsSize())
        img = QtGui.QImage(self.wb.viewportSize(), QtGui.QImage.Format_ARGB32)
        painter = QtGui.QPainter(img)
        self.wb.mainFrame().render(painter)
        painter.end()
        img.save(self.filename)
        QtCore.QCoreApplication.instance().quit()

if __name__ == "__main__":
    """Run a simple capture"""
    app = QtGui.QApplication(sys.argv)
    c = Capturer(sys.argv[1], sys.argv[2])
    c.capture()
    app.exec_()

Learn python! For free! With me! (in part)

I'm one of the speakers for the free python courses in FM La Tribu, in Buenos Aires.

Every saturday you can learn something from one of the best python programmers in a thousand miles, or from me.

I'll be teaching about virtualenv, buildout, nose and other things on August 21, about GUI stuff on September 25 and October 2, and about PyQt in October 30.

This is all for free, and I hope lots of people show up!

The full schedule is here.