Hace 5 años que laburo en una organización de trabajo barrial. Como no recibimos aportes privados y rara vez del Estado (a veces presentamos proyectos a programas) siempre andamos buscando formas de sostener económicamente nuestras actividades.
Un recurso, no por viejo en desuso, es el del "bono contribución", que muchas veces incluye un sorteo con algún premio.
Además de la algo ingrata tarea de venderlos, hay que hacerlos. Alguno tiene uno de esos sellos numeradores (un mecanimismo que va incrementando el contador automáticamente ) pero igual cualquiera se vuelve un burócrata (más cuando hay que sellar dos veces - el bono y talón -).
Así que ayer, en 20 minutos hice Bonito, un programa feo pero efectivo.
Primero hice una plantilla en Inkscape donde entran 6 de estos bonitos en un A4.

Como el SVG es XML que es TEXTO, la marca XXXX se puede reemplazar fácilmente por el número que corresponda. Yo quería que me quedaran así:

De esta manera, simplemente tengo que meter 6 broches a la izquierda y recortar, ya quedan ordenados para repartir entre los compañeros y compañeras.
Para algunas cosas, Inkscape se puede usar por línea de comandos, por ejemplo para convertir entre los formatos que soporta. Así paso el SVG con los números reemplazados a un PDF. Después concateno todos los PDF de una tanda (por ejemplo agrupados de a 10, como en el dibujo) con Ghostscript.
Acá el código:
# -*- coding: utf-8 -*-
#
# bonito.py
#
# Copyright 2010 Martin Gaitán <gaitan(at)gmail.com>
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
import sys, os
import subprocess
import glob
def markToNum(content, num, mark='XXXX'):
num_as_string = '0' * (4 - len(str(num))) + str(num)
return content.replace(mark, num_as_string, 2)
def main():
if len(sys.argv) <= 1:
print "Modo de uso:"
print sys.argv[0] + " archivo.svg"
sys.exit(1)
else:
with open(sys.argv[1]) as input:
svg_content = input.read()
index_from = int(raw_input('Desde [0]') or 0)
number_by_page = int(raw_input('Num por pagina [6]') or 6)
grouped_by = int(raw_input('agrupar de a [20]') or 20)
planchas = int(raw_input('Planchas [1]') or 1)
for plancha in range(planchas):
counter_from = index_from + plancha*number_by_page*grouped_by
for pagina in range(grouped_by):
page_content = svg_content
for bono in range(number_by_page):
num_remplazo = counter_from + bono*grouped_by + pagina
page_content = markToNum(page_content, num_remplazo)
with open('temp.svg', 'w') as output_svg:
output_svg.write(page_content)
subprocess.call(["inkscape", "-f", 'temp.svg', '--export-dpi=150', '-A', 'temp%s.pdf' % ("0"*(4 - len(str(pagina))) + str(pagina)) ])
generator = ['gs',
'-q',
'-sPAPERSIZE=a4',
'-dNOPAUSE',
'-dBATCH',
'-sDEVICE=pdfwrite',
'-sOutputFile=%s-%i-%i.pdf' % (sys.argv[1][:-4], counter_from, num_remplazo),] + \
['temp%s.pdf' % ("0"*(4 - len(str(pagina))) + \
str(pagina)) for pagina in range(grouped_by)]
subprocess.call(generator)
for temp in glob.glob('temp*'):
os.remove(temp)
if __name__ == '__main__':
main()
Nada que no se pueda hacer con Bash, cierto, pero mucho más fácil de escribir (y de leer).
De paso, acá está la plantilla, por si a alguno le sirve.
Leemos en la web
The Django Dash is a chance for Django enthusiasts to flex their coding skills a little and put a fine point on “perfectionists with deadlines” by giving you a REAL deadline. 48 hours from start to stop to produce the best app you can and have a little fun in the process.
Suena a PyWeek [1], pero en 2 dias. ¿Será indicio de lo rápido que se programa con Django?
Atenti que la inscripción cierra el 8 de agosto (mañana).
¡A ver esos perfeccionistas!
La aplicación que estoy desarrollando, GPEC, genera muchos mensajes que pueden ser útiles para el usuario.
En softwares con GUI’s sencillas suele utilizarse la barra de estado para mostrar mensajes contextuales e información sobre el resultado de una acción. Pero si estos mensajes son muchos y de diversa índole, este espacio puede no bastar, sobre todo por la volatilidad de la información que la barra de estado muestra.
Una solución posible es usar un panel con un ListCtrl de manera de poder agregar los mensajes quedando un registro completo y cronológico; un log propiamente dicho.

- Ejemplo
- Panel de log de Mayavi2
Surge acá un detalle: si los mensajes se generan desde "cualquier parte" del programa, todas esas "partes" deberían tener referencia de la instancia del panel/widget de log.
Un ejemplo: todos las demostraciones de la aplicación de demo de wxPython tienen la siguiente estructura:
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
...
self.log.WriteText(' message ... ')
Esto vuelve la aplicación muy acoplada: la instancia log (que es un caja de texto en el demo) se pasea por distintos namespaces para estar disponible en todos lados.
Denotemos la falta de flexibilidad: ¿que pasa si queremos ’loggear’ mensajes desde un objeto donde no estaba previsto? ¿qué pasa si queremos cambiar el widget que muestra los mensajes y el método para anexar mensajes tiene otro nombre? ¿y si además de mostrarlos, con algunos los mensajes queremos hacer alguna otra cosa (ejecutar un simple sonido de alarma, por ejemplo) ?
PubSub
Una manera más elegante y eficiente es utilizar PubSub una implentación en Python del paradigma de publicación-suscripción.

Su implementación es trivial. Incluso viene incorporado dentro de wxPython.
El Publisher (generalmente importado como pub) envía mensajes (cualquier objeto python) asociados a un tópico (una cadena)
pub.sendMessage('log', ('ok', 'Ready! You can send any message from anywhere.') )
En este ejemplo, el tópico, que elegí arbritrariamente, es ’log’, y el mensaje es la tupla ('ok', 'Ready! You can send any message from anywhere.')
Del otro lado del mostrador, cualquiera puede suscribirse a los mensajes con determinado tópico y asociarlos a un método/función.
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
pub.subscribe(self.OnAppendLog, 'log')
def OnAppendLog(self, msg):
data = msg.data<img105|center>
#do your things with the data!
pub.subscribe bindea los mensajes con tópico ’log’ al método OnAppendLog pasando un objeto msg. Nuestro mensaje real, la tupla que enviamos, está en msg.data
Nada impide que sean muchos los objetos que envien mensajes con tópico ’log’ y muchos otros estén suscriptos a él. Y esto funciona sin importar dónde ocurra cada cosa! [1].
Como ejemplo completo dejo el panel log. Podés probarlo creando otro frame independiente que envie mensajes de log.
#
# Copyright 2010 Martin Gaitán <gaitan(at)gmail.com>
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
import wx
from wx.lib.pubsub import Publisher as pub
import time
import sys
from wx.lib.embeddedimage import PyEmbeddedImage
icons = {}
icons['ok'] = PyEmbeddedImage(
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAAXNSR0IArs4c6QAAAK5QTFRF"
"AAAA////2vO/+P3z+f31VJkEVJcEU5UEUpQEcc0GcMsGcMkGb8gGbcYGbcQGbMEGZLYFXKYF"
"UJAET48ETo0ETYwEasAGddALd9ANeNERetETe9IVfdIXfdMZftMbf9Mci9cwlNpAlttElttF"
"l9xHmtxLm91NnN1Pnd1Rnt5ToN9Xod9ZpuFhp+FjqOFlquJnr+RyseR0veiKwuqSy+2j4PTI"
"9vzv9/zxidYs3fPCGN7g1AAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAAsT"
"AAALEwEAmpwYAAAAB3RJTUUH2gcMBC0Irn+MQAAAAINJREFUGNNjYCAJ6Bui8vXkpAxQ+LJa"
"ylx6CL6utKYGJyszkGVpAuZLaahzsYH4phYKxgwMOpJqatzsID6ThbIGt5G+hKoKDweIz8Ai"
"YaGtIiOnrMIrxAwxjJlXXl1VSYlPmBlmPLOAuLIivwgzwkJzQV4xUWZkJ5mzi7CgOtqMBbcH"
"AVouCiZO5Tf/AAAAAElFTkSuQmCC")
#----------------------------------------------------------------------
icons['error'] = PyEmbeddedImage(
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAAAAAAAD5Q7t/AAAA"
"CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QsKCTIOk1O0sAAAAhpJREFUOMudk71Pk1EU"
"xn/3bQvlo76gxBpNoGibArYLxJREh466MmnSgRH+IjsydGYjspBAWEQHMJIWmmhj+LAkpC1N"
"Wyj2PcfhfUsQiRpPcnOTm/P8nuQ59xhuVA5SwDyQBsa95xKwDixlYOt6v7khfjscCi1MJpME"
"w2F8AwOoKp2zM87LZYqFAtVmM5uBxd8AOXg3nUy+HJmZ4XJ7G+f0FBwHVUUMWEN38U9NUt3d"
"5VOxuJqBVwC+rvN0Mvn6XixGe3MTbTRABFVBRUEEabboHHyjPxbDtqzoi2r1wTKsmBykhkOh"
"98/m5rhYW0OdDqqKKqh6YgXFhakxBFMpPm9sUGu1Zi1gfjKR4HJnB3UcEFABFXEP6oEUVMFx"
"uMjneTwWAZj3A+lg+D4/PnxERRkrf+dPtW/fQao1Ag8fAaT9wLjVP4iKG9jfSkRR7WB6AgDj"
"FnCV9r8A8PpUBQA/UOrUzyYUg6rDl5ERt0HEvVE3PDdVRN0gtdkCKFnA+vnJCcYeuiL/Iu46"
"iidWwRocpF2rAaxbwNL+3h6BeNwly3WRNzrtTkNQY/BHIpQODwGWrAxs1VqtbKWQp2fqqQu5"
"5op3qygYQ080RuPggHq7nc3Alg9gGVaeVyqzts8XHUgkcBoN5KJ99RMVMHaI3vgEjXKZwvHx"
"agbe3LpMdl/fwpPRUQK2jentRUVwmk069Tpfj466zou3buP/rPNPwkdmHrlYdncAAAAASUVO"
"RK5CYII=")
#----------------------------------------------------------------------
icons['info'] = PyEmbeddedImage(
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAAAAAAAD5Q7t/AAAA"
"CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QMCBiAyOlCc9wAAADV0RVh0Q29tbWVudAAo"
"YykgMjAwNCBKYWt1YiBTdGVpbmVyCgpDcmVhdGVkIHdpdGggVGhlIEdJTVCQ2YtvAAACq0lE"
"QVQ4y5WSS0hUcRTGv//cO+O9OtdHJllqZlI+CEUiE8ShBiXUpKKQbGLKcGG0CBOyRcsQMapF"
"j02ii4igAgMDJcgQSXQmSkrNijSVTJ1xdJy5d6739W/loDURfqtz4Pt+nHM4BBFUXNnUTCkc"
"BiUpIISYiDHLEPq0/2Vr459edn1TVN6UwTCk72JtZVq5vQBxAg9VN+DxBVN7ej9cISbmLKV6"
"SX9X69eIAJYlb++11G/fk7ljLBBSRmd9khJaVVlF06NtJflZ6enJe1tuPXYBiF/LMGtFSdXV"
"2/Xnj5YVH8z5rKi6m7eYFQBEpyCqTg3vSmiWi+YQzXM7dSYlc3L8bScAmMIkhj1Xbi9AIKSO"
"sSxDLWbGIIRQUBiabiiUwuganOwuKswBw3Kn1nJhwKpC4wUrD1nRV1XNSDQzpguJsZxzV7Lg"
"yN+91QElkDrlEf08zyEgqVxtXYNpww0IIUTRdEiyajIMKiZYo+D1Sy5RCjErQUkbnpaGFUU3"
"qaqxFuEBiGFADM9KXl8gRpRVy4qk+jOSYzH6w/deVHQ6tyQp7m+LHsFqSfD6g4gTeLWjrVnc"
"sIKZ0QZ63gyDj2JzJ34tiwDw0yfqHye8/t7hmYUlUTZX7E+rGHKNwcph4q8bbBNCxzu7+uWZ"
"6fnstCTroWvtAzfPHM665P4yH2JYkui0Z1X7F5dy3IMjqsD6SsOrr/+DY6cbq2QqPC8rLbIU"
"HshGNM9B1XX4lkUMucbxzjWixXHS5SftNx5EBABAbV1DYohucQVkpDtOJDGEACwLdHXPBRnN"
"v6+j7c4U/qeaGrvV6bRRz2IfFWUX/T75jDqdNhrJy/6DoQLA/bsPkZ2bjempaWxaTqeNzsy+"
"MgLSEP00+sLY7AQAUFV98nqNIMQfWVhYeJ2XF/sokuk3Vkw2XnyKHQQAAAAASUVORK5CYII=")
#----------------------------------------------------------------------
icons['warning'] = PyEmbeddedImage(
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAA"
"CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1gIQDictt+6SdwAAAehJREFUOMuVk8FKG2EU"
"hb87mc40iTODEJlK7UZDxCCGQUqaMASCSGODdBe6ECJddOcwG/EJXBt0ZcBCwEVJVgWtr1AI"
"PoBQXAQKhRZc1EBJMX831hLItPbAvYvL4Ttnc4UIhfDIgLcAA3jdgC/jfHoUwISjeXgOcAFH"
"QHWcT4tI91KwWlhY0J6kUloKVkPw7g0wYS8NemJ3l0yzSRp0E/buBQihOAXFbLksej6Pns+T"
"LZdlCoohFPmXdqB7AsNep6M8z1Oe56lep6NOYLgD3b82CGHFhaWM74vh+ziOg+M4GL5PxvfF"
"haUQViIBJuxnwUgEAaJpWJaFZVmIppEIArJgmLA/FhDC+jSk5woFjFIJEcG2bWzbRkQwSiXm"
"CgWmIR3C+gggBDGgsXibruk6IvKngQiarpMIAhbBMKARgsDtCuHVLLReLC8bk2dnEIuhlKLf"
"7wOQTCYREbi54WptjQ/n54NLqDfgnYQQewxXT8GaPz7mYbWKUgqlFLVaDYB2u42IICL8OD3l"
"YmODLnz/DJOawGYczJlcjnilcmcUEVzXxXXdkVu8UmEmlyMOpsCmbMPXl5CaPThgol6/S/89"
"wAhARLhutbjc2uI9fJNDGD4DecD/6SfwEZT+CQ4H8GYi4i+idA3DHjR/AZfefQgctOETAAAA"
"AElFTkSuQmCC")
class LogMessagesPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
self.list = wx.ListCtrl(self, -1, style= wx.LC_REPORT|wx.SUNKEN_BORDER)
self.setupList()
sizer = wx.BoxSizer()
sizer.Add(self.list, 1, wx.EXPAND)
self.SetSizerAndFit(sizer)
pub.subscribe(self.OnAppendLog, 'log')
def setupList(self):
"""sets columns and append a imagelist """
#setup first column (which accept icons)
info = wx.ListItem()
info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
info.m_image = -1
info.m_format = 0
info.m_text = "Message"
self.list.InsertColumnInfo(0, info)
self.list.SetColumnWidth(0, 550)
#insert second column
self.list.InsertColumn(1, 'Time')
self.list.SetColumnWidth(1, 70)
#setup imagelist and an associated dict to map status->image_index
imgList = wx.ImageList(16, 16)
self.icon_map = {}
for key, bitmap in icons.iteritems():
indx = imgList.Add( bitmap.GetBitmap() )
self.icon_map[key] = indx
self.list.AssignImageList(imgList, wx.IMAGE_LIST_SMALL)
def OnAppendLog(self, msg):
ico = self.icon_map[msg.data[0]]
message = msg.data[1]
index = self.list.InsertImageStringItem(sys.maxint, message, ico)
self.list.SetStringItem(index, 1, time.strftime('%H:%M:%S'))
self.list.EnsureVisible(index) #keep scroll at bottom
class TestFrame(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, "Log Panel demo")
self.log = LogMessagesPanel(self, -1)
self.SetSize((620,150))
self.SetMinSize((620,150))
if __name__ == "__main__":
app = wx.PySimpleApp(0)
wx.InitAllImageHandlers()
main_frame = TestFrame(None, -1)
app.SetTopWindow(main_frame)
main_frame.Show()
pub.sendMessage('log', ('ok', 'Ready! You can send any message from anywhere.') )
pub.sendMessage('log', ('info', "Just import pubsub.Publisher and send a 'log' message") )
pub.sendMessage('log', ('warning', "The message data is a tuple ('icon', 'message') ") )
app.MainLoop()
Un típico uso de un ListCtrl es usarlo para mostrar un Log de la aplicación que muestra mensajes al usuario, similar a lo que puede hacer la barra de estada, pero con la ventaja (complementaria, si se quiere), de mantener un historial de los eventos ocurridos.

En tal caso, primero, hay una decisión de diseño que hacer: ¿los nuevos mensajes se agregan al inicio (como un blog) o al final de la lista (como los comentarios) ?
No sé si existe una respuesta canónica a la cuestión, pero infiriendo (de los pelos) el sentido de lectura occidental (de izquierda a derecha y de arriba hacia abajo) decidí que "un nuevo contenido" debe estar abajo del anterior.
Eso trae aparejado un nuevo problema: si se agrega un nuevo item a ListCtrl al final y ya hay más de los que caben en el espacio visible del control, el último (el más importante) no se verá en pantalla y el usuario debería hacer un scroll hasta el final para verlo. Es decir, para un panel de Log, el scroll vertical siempre debería mantenerse abajo.
Por suerte no hay que liarse con generar eventos programaticamente, ni manipular el scroll, ni obtener dimensiones del widget. He aquí una solución "fits your brain": el método EnsureVisible(index)
Por ejemplo:
ico = self.icon_map[msg.data[0]]
message = msg.data[1]
index = self.list.InsertImageStringItem(sys.maxint, message, ico)
self.list.SetStringItem(index, 1, time.strftime('%H:%M:%S'))
self.list.EnsureVisible(index) #keep scroll at bottom
Al agregar un nuevo mensaje de log, obtenemos el índice y wx nos asegura que la fila con ese índice estará visible en pantalla.
Hace aproximadamente dos meses que estoy trabajando en lo que será mi proyecto final, para recibir el título de ingeniero en computación.
El proyecto es una aplicación de uso "científico y académico" implementada en Python que sirve para obtener diagramas de equilibro termodinámico entre fases fluidas de sistemas binarios. Toda la batahola está en este repo.
En concreto, el proyecto se circunscribe a la generación y [análisis sintáctico] de archivos de texto con el que la aplicación se comunica con los programas que implementan los algoritmos de cálculo, que están implementados en Fortran, y son, literalmente, unas cajas negras. [1]. Se procesan esos archivos para obtener arrays con los que se plotean las distintas curvas.
Utilizo principalmente wxPython, Matplotlib y Numpy. Vale destacar, ya que mucho de un trabajo final es documentación, que escribo en restructuredText, renderizando con Sphinx y el genial rst2pdf
Esta perorata para contar que iré apuntando en este abandonado blog (no más que el otro, y en general, el resto de mi vida) algunos descubrimientos informáticos y de otro tipo, si es que ocurren, en el desarrollo de este proyecto.
Python es un gran lenguaje de programación, y como tal se merece la comunidad que tiene, donde expertos y novatos se sienten parte.
![]()
Para los trabajadores online freelance (programadores, diseñadores, traductores, etc) trabajar para el exterior es un objetivo primordial. Aunque en algunos sectores la competencia es leonina y se pauperizan los honorarios, el tipo de cambio del peso respecto a otra monedas fuertes hace que siga siendo muy provechoso.
En traducción, que tiene un sistema de presupuesto lineal basado en cantidad de palabras del texto del idioma origen, es fácil cuantificar la diferencia. En Argentina se cobra entre $0,10 y $0,15 (pesos argentinos) por palabra, mientras que en europa se cobra entre 0.05 € y 0.07€. O sea, se gana hasta el triple por realizar el mismo trabajo.
El problema, al menos desde Argentina, es cobrar. Aquí comparto mi experiencia esperando ayudar a otros.
De Adsense a la billetera
Una forma simple y rápida pero bastante onerosa es Western Union. Es un servicio de transferencias de dinero persona a persona (física o jurídica), con sedes en casi todo el mundo. Tiene dos tipos de servicio: Quick Cash y 24 horas.
Western Union tiene multiples instancias de lucro, que lo vuelven un ser. Se le cobra entre el 2.5 y 5% al emisor (desde Europa a Argentina el límite de transferencia es 500€) y además, el receptor cobra en moneda local a un tipo de cambio definido por WU que siempre está entre un 3 y 6% por debajo del tipo de cambio del dia. Sobre todo los días que hay corridas en suba, el tipo de cambio queda desfasado (tiene una actualización muy lenta) y es un mal momento para cobrar.
Existe una forma de salvar este cargo solapado para el receptor: si el envío es tipo Quick Cash y en dólares estadounidenses, se puede retirar en dólares en los locales Western Union de los supermercados Walmart (que es el representante oficial de WU en Argentina). Este servicio no tiene costo para el receptor.
Esto es muy útil para quienes utilizan Google Adsense en sus sitios web, ya que Google ofrece este servicio de pago. Basta anotar el número de transferencia (MCU) y documento en mano aclarar en Wester Union de Walmart que queremos cobrar en dólares.
Mucho más fácil, rápido y sin perder un sope que pedir el cheque y venderlo en una financiera.
Cobrar del extranjero
Internacionalmente está casi estandarizado el uso de Paypal como medio de pago de honorarios (y casi cualquier otro tipo de transacción en internet) pero este sistema no tiene integración con el sistema bancario argentino lo cual complica la tarea de monetizar los fondos.
Además, un usuario no puede cargar crédito a su cuenta paypal con una tarjeta de crédito, aunque esta sea válida internacionalmente. Un detalle que complica a quienes quieren comprar o donar en el extranjero.
Sin embargo, Paypal sigue siendo interesante para todos los que necesitamos cobrar desde el extranjero. Además de facilitarle la vida al emisor (cliente) que seguramente ya está acostumbrado a este sistema, la transferencia entre cuentas paypal personales no tiene costo. Esto significa que si el cliente tiene una cuenta paypal con fondos (que en la mayoría de los paises pudo haber cargado con tarjeta o desde su cuenta bancaria sin costo) la transacción total es gratuita. Además, la operación es instantánea.
Si el cliente envia el dinero a través de paypal pero habiendolo cargado desde una cuenta bancaria o tarjeta de crédito específicamente para dicha transacción, el costo de la operanción es 3,4% + 0,30 USD. El emisor decide quien abona este cargo.
Una observación importante es que predeterminadamente las cuentas PayPal son en una moneda principal (en dólares estadounidenses para Argentina) y al recibir un pago en otra moneda (euros, por ejemplo) la conversión de divisa se realiza al tipo de cambio del día con una retención del 2.5%. El tipo de cambio es actualizado 2 veces por día.
Una sólución es abrir cuentas en distintas monedas. En vez de convertir el pago a la divisa principal, se mantiene en nuestra cuenta en la moneda en que se recibió. Cuando necesitamos realizar un pago o transferencia en esta moneda, nos ahorraremos tener que reconvertirla nuevamente (ahorrando un 5% en total). Claro que a la hora de monetizar los fondos se deberán convertir, pero esto se puede hacer en cualquier momento que creamos conveniente.
Paypal aclara que ofrece este servicio (Multiples divisas) para facilitar el comercio electrónico internacional y no debe utilizarse con fines especulativos. Pero los timberos decidirán.
De Paypal a la billetera
Pero, como decía un amigo, la plata no es plata hasta que no sirve para comprar fernet en la despensa.
Como dije más arriba, no se puede asociar una cuenta bancaria argentina una cuenta Paypal (ni para añadir ni para retirar fondos). Esto deja como única alternativa oficial para retirar fondos el envio de un cheque.
Paypal envia un cheque via correo postal certificado por el monto que solicitemos con un costo de u$s 15 fijo, independientemente del monto retirado. El envío para Argentina se realiza a través de Ocasa, y tiene una demora aproximada de 10 días hábiles.
El problema es que este cheque tampoco se puede cobrar en ningún banco, por lo que hay que venderlo en una financiera o agencia de viajes, que cobran una comisión de entre el 2 y el 5%.
Por suerte existe xoom.com. Es un servicio de transferencia de dinero que intenta competir con Western Union, pero a diferencia de este, la operación se realiza únicamente online, el destino puede ser una cuenta bancaria argentina o efectivo en pesos o dólares, y, hete aquí la clave, el origen de los fondos puede ser una cuenta Paypal.
Problema solucionado: nos hacemos una transferencia a nosotros mismos, retirando fondos de Paypal y enviandolos a nuestra cuenta bancaria, o mejor, en dólares que se cobran en cualquier sucursal de Banco Francés.
A diferencia de Wester Union, los cargos de servicio no son porcentuales fijos sino que están tabulados en rangos del monto enviado lo que significa un ahorro considerable en montos grandes. Para cifras montos menores a u$s500, el costo de servicio ronda le 4.5%
Además hay que considerar que al cobrar en pesos, Xoom realiza una conversión de divisa a un tipo de cambio que, al igual que Wester Union, está un par de puntos por debajo de la cotización de mercado. La opción de cobrar en dolares evita esta pérdida, pero tiene un cargo de servicio un 40% mayor, lo que significa un costo de operación real del más de 6%.
Pero hay una forma de salvar esta plata, que convertida a pesos seguramente significarán varios fernés: conseguir un código de descuento. Retailmenot suele tener cupones válidos, ¡de hasta el 100%!
Conclusión: si cobramos desde Paypal (entre cuentas personales) y retiramos los fondos a través de Xoom.com en dólares consiguiendo un cupón del 100%, tendremos toda nuestra platita en el bolsillo, en dólares y sin perder nada en el camino.
¡Espero sirva!
Learning Python de Mark Lutz, ha sido, desde su primera versión en 1999, uno de los libros de cabecera para aprender Python.
Hace unos días salió la 4ta edición, adaptada a las versiones 2.6 y 3.1 de Python y ampliada en varios capítulos.
Lamentablemente, tardará mucho en llegar a la librerías argentinas, pero podés ir leyendo la versión en PDF.
El problema nº 2 pide obtener la suma de todos los números impares pertenencientes a la sucesión de Fibonacci menores a 4 millones.
El código con el que lo resolví es este:
a, b = 0, 1
n = a + b
while n < max:
yield n
a, b = b, n
n = a + b
sum([i for i in fibo(4000000) if i%2 == 0])
El resultado es 4613732.
Explicación
Fibonacci es el "hola mundo matemático" y Python luce su elegancia con este problema.
El aspecto interesante de la función fibo() definida en el código de arriba es que no se trata de una función común sino de un generador. Sintácticamente la diferencia está en que no utiliza la sentencia return sino yield .
La definición de yield. en su acepción de verbo, dice «end resistance, especially under pressure or force;». Ceder, no oponer resistencia.
La diferencia sustancial entre un yield y un return es que el yield devuelve el resultado parcial de cada iteración y hace una "marca de entrada" desde donde se comenzará a ejecutar la próxima vez que la función (el generador) sea invocado.
Esto permite una recursividad con "evaluación perezosa", mucho más eficiente en términos computacionales.
El Filtrado de los numeros impares de la sucesión y la sumatoria es la misma solución que se apliqué en el problema 1.
A través del blog de Juanjo Conti descubrí Project Euler, una serie de desafíos matemáticos de enunciación sencilla para resolver con computadoras.
Juanjo estuvo resolviendo los primeros problemas, y yo quise hacer mi intento. El primero plantea obtener la suma de todos los multiplos de 3 o de 5 menores a 1000.
Lo resolví con esta pythonica (lo es?) línea:
El resultado es 233168.
Breve explicación
Se basa en el uso de list comprehensions, una de las "joyas de la corona" de las características de Python.
Es una manera de generar listas de una manera concisa, compuesta por una expresión seguida de uno a más for y una condicionalidad al final
La lista [i for i in range(1000) if (i % 3 == 0 or i % 5==0)] se lee así: crear una lista con todos los elementos (expresión i) en el rango de 0 a 999 (for) cuyo resto de dividirlo por 3 o 5 sea 0 (if).
La función builtin sum() hace la sumatoria de esa lista y... listo. ;-)
Para suscribirse a la lista de Pyar, una de las tareas (opcional, pero muy bienvenida) es enviar tu "Hola Mundo".
El 17 de enero de 2007 yo me suscribí y mandé el siguiente mensaje.
Estimada gente:
Cumpliendo solemnemente con el paso 2 de las indicaciones de suscripción a la lista, haciendo alarde de mi nerdismo, les dejo mi "hola mundo" (mi primero programa en python!). Se trata de humilde juego via consola que implemento en cada lenguaje en el que intento incursionar. Hete aqui:
Dicha sea la verdad: vengo con muchas ganas de aprender, y por ahora muy poco que aportar (pago solidaridad con sinceridad).
Decidir aprender un nuevo lenguaje es una gran decisión y creo que no me he equivocado con mi elección. Es que son mis primeros pinitos en la programación orientada a objetos, y aunque la facu exige Java (pero no enseña Java), creo que Python es una herramienta mucho mas versatil, accesible y apropiada para el nivel de software que tengo intención/necesidad de desarrollar.
Ahora la parte aburrida. Me llamo Martin, soy de Neuquen y estudio Ingenieria en computacion en Cordoba. Soy programador PHP (uno del montón, que bah) y en particular laburo con un CMS/framework llamado SPIP, que me da de comer y beber. Tengo un weblog, aunque no sobre cuestiones técnicas. www.textosypretextos.com.ar . Y lo más importante: soy hincha de boca.
saludos desde Neuquén a 32ºC. (quien dijo que en el sur hace frio?)
Martín
Mi "Hola Mundo" fue El Número.
Mi primer juego
El Número es un juego de lógica y habilidad mental. Consiste en encontrar el número escondido (generado aleatoriamente) a través de la información
que brinda la máquina en cada intento. El número escondido tiene 4 cifras no repetidas.
Un digito ’bien’ significa que el hay un acierto en número y posición.
Un digito ’regular’ significa que el digito existe en el número incógnita, pero no está en
la posición correcta.
Por ejemplo si el numero incógnita fuese el 1234 y se arriesga el 2031 el resultado será de dos dígitos regulares (el 2 y el 1) y 1 dígito bien (el 3).
Descarga e instrucciones
Sobre Linux podés copiar y pegar este listado de comandos en la consola:
Sobre Windows, asegurate tener instalado Python (cualquier versión < 3) y dale hacé doble click sobre elnumero.py
¡Que lo disfrutes!
Python es un lenguaje de programación interpretado, interactivo y multiplataforma, que con su facilidad y potencia hace las delicias de miles de programadores (y sin saberlo, también de los usuarios de los programas que estos desarrollan) alrededor del mundo.
La comunidad de Python Argentina es particularmente activa, solidaria y muy capaz técnicamente.
Esta charla fue dada por Facundo Batista, uno de los fundadores de PyAr, en las 7mas Jornada Regionales de Software Libre realizadas en Córdoba, Argentina, en 2007.
Aquí la presentación
Si te interesa saber un poco más, instala Python en tu computadora (en caso de que no esté ya instalado, claro) y lee el tutorial. Luego podés ver las recomendaciones de la comunidad para saber como seguir. Y por supuesto, ¡inscribite en la lista de correo!



