CRySoL : Comentarios

  • Ayuda   hace 6 años 16 semanas

    Hola!

    Para este tipo de cosas es mejor que utilices la lista de correo de CRySoL. Las peticiones de ayuda en la web pasan más desapercibidas.

    Y sí, desde GNU puedes acceder por SSH al router (si este lo tiene). De todas formas, no sé si el puerto USB que tiene puedes trastear con él. No conozco ese router y no te puedo ayudar mucho.

    Por eso te digo que escribas a la lista mejor. Arriba a la derecha (en listas) tienes un enlace.

    Un saludo,
    Cleto.

  • Atributos con tipado estático en Python (usando un descriptor)   hace 6 años 17 semanas

    Se supone que el operador % estará obsoleto en futuras versiones, aunque posiblemente podamos seguir usándolo algunos años. Personalmente no utilizo % cuando escribo código nuevo, aunque estoy de acuerdo que, para este ejemplo, la obligación de usar python2.6 solo por algo tan accesorio no merece la pena. Lo cambio.

  • Atributos con tipado estático en Python (usando un descriptor)   hace 6 años 17 semanas

    Muy interesante y completo el artículo. Pero tengo algunas observaciones/dudas.

    Como requisitos se exige python 2.2 mínimo, pero creo que es incorrecto, ya que se usan funciones como format() que solo aparecen a partir de 2.6. Luego en realidad sólo podría utilizarse a partir de 2.6.

    No se tampoco la razón de usar format(), ya que su propósito es hacer sustituciones complejas, pero en esta porción de código:

         raise TypeError("'{0}' given but '{1}' expected".format(
                        val.class.name, self.cls.name))
    

    No se hace una sustitución muy elaborada, que podría ser reemplazada con:

         raise TypeError("'%s' given but '%s' expected" %(
                        val.class.name, self.cls.name))
    

    Y con esto posiblmente si sería compatible hasta Python 2.2

  • Antiprogramación   hace 6 años 18 semanas

    ... es que yo creo que un mal diseño te conduce a esos "hacks" de manera directa.

    El problema de ese alumno es un problema de diseño, entre otros. De hecho, así lo apuntas tú mismo al mencionar "rotaciones".

    Una hoja y un boli suelen ser unos buenos elementos para programar. Otra cosa es que sólo vayas a picar código, esto es, "programming versus coding". Yo creo que codificar es parte de programar, y no al revés. Para programar hay que diseñar, para codificar no.

  • Antiprogramación   hace 6 años 18 semanas

    lo pondría aquí, pero son como 3000 líneas y el comentario iba a quedar algo largo Sticking out tongue

  • Antiprogramación   hace 6 años 18 semanas

    Tras leer esto (sacado de aquí: http://msdn.microsoft.com/en-us/library/ms682629%28v=vs.85%29.aspx):

    It is a good idea to use a large array, because it is hard to predict how many processes there will be at the time you call EnumProcesses.

    To determine how many processes were enumerated, divide the pBytesReturned value by sizeof(DWORD). There is no indication given when the buffer is too small to store all process identifiers. Therefore, if pBytesReturned equals cb, consider retrying the call with a larger array.

    ...me he quedado así: Jawdropping!

    Y ésta es la dirección del mejor compendio de antipatrones y mala programación que he visto: http://msdn.microsoft.com/en-us/library/dd162863%28v=VS.85%29.aspx

    Odio con todas mis fuerzas tener que hacer algo en el innombrable...

  • Antiprogramación   hace 6 años 18 semanas

    Hombre, estás rediseñando la solución entera, cuando en ese pequeño snippet de código, lo que te apuñala los ojos es la semántica, la forma de expresar algo. Obviamente, soluciones (diseños) hay muchas, sólo me limité a poner la que era semántica y sintácticamente más parecida (de hecho, equivalente).

    Me viene a la cabeza un caso que nos ha comentado David en alguna ocasión, y que sí que es un problema de diseño: un alumno, para resolver un juego de 3 en raya, anidó tropecientos if, de forma que en cada uno resolvía una posición particular del tablero. Y ni siquiera consideraba las posiciones equivalentes (por ejemplo, rotado 90, 180 y 270 grados).

  • Antiprogramación   hace 6 años 18 semanas

    ... validate() no está de más, pero yo no dejaría al cliente utilizarlo. Sería un método privado. Si hay que comprobar en más de un sitio, validate() evitaría la redundancia.

    My 2 cents,

    si yo tuviera que resolver el problema, usaría una clase Tablero, que encapsularía una matriz de 8 x 8. Este objeto se encargaría de validar movimientos y demás. Supongo que en la matriz estaría compuesta de objetos que representasen si una casilla tiene una ficha o no, y cuál de ellas es. Sea como sea, las casillas no tendrían row/col, y si decidiera utilizar algún tipo de clase Casilla, usaría algo parecido al patrón "pesopluma", usando la información de row/col desde el tablero, no teniendo así la información de la posición por duplicado, y evitando posibles inconsistencias de datos. Nótese que el array/matriz donde colocásemos esas "coordenadas" ya tendría esa información.

  • Antiprogramación   hace 6 años 18 semanas

    ... sí que los conocerías Eye-wink

    http://crysol.org/es/node/1393

  • The poor's man "dropbox"-thing   hace 6 años 18 semanas

    ...you can use FUSE and this to do that... Laughing out loud

  • The poor's man "dropbox"-thing   hace 6 años 18 semanas

    yep, I know it, but it is only a rsync front-end. The requirement here is transparent remote update.

  • Antiprogramación   hace 6 años 19 semanas

    Muy guapo lo de los anti-patrones, no lo conocía.

  • The poor's man "dropbox"-thing   hace 6 años 19 semanas

    Do you meet "unison"[1]?

    It is Debian package.

    [1] http://en.wikipedia.org/wiki/Anti-pattern

  • Antiprogramación   hace 6 años 19 semanas

    Mejorando aún más tu primer ejemplo ("Condición Múltiple"):

    { 
        coords.validate();
        // hacer cosas
    }
     
    //[...]
     
    class Coordinate {
       int row, col;
       public void validate() {
          if (row<1 || row>8 || col<'A' || col>'H')
              throw new InvalidCoordException(row, col);
       }
    }

    Con eso has conseguido dos cosas: ya no tienes "row" y "col", sino "Coordinates", que es más orientado a objetos. Y te has cargado un comentario que no aportaba nada, mejorando la legibilidad del código.

    Si me apuras, hasta la propia función validate es innecesaria, ya que al tener un objeto con las coordenadas puedes elevar la excepción en el momento en el que las coordenadas no sean válidas.

    Finalmente, ahí va una lista de antipatrones: http://en.wikipedia.org/wiki/Anti-pattern

  • FUSE y python: crea tu propio sistema de ficheros fácilmente   hace 6 años 19 semanas

    ...no me había parado a pensar utilidades para dictfs.py... mi idea es hacer algo como zipfs, gitfs... alguna cosa de esas... porque dictfs.py lo pensé como ejemplo, nunca como utilidad...

  • FUSE y python: crea tu propio sistema de ficheros fácilmente   hace 6 años 19 semanas

    Muy útil para hacer un mock del sistema de archivos y poder hacer pruebas de sistema con garantías de que la prueba es independiente.

  • FUSE y python: crea tu propio sistema de ficheros fácilmente   hace 6 años 19 semanas

    Está bien tener esto a mano Smiling Gracias.

  • Entrevista a Richard M. Stallman en Baquía TV   hace 6 años 21 semanas

    Eye-wink

  • Jo!
    Un pequeño script para tener un Jukebox de Modarchive.org   hace 6 años 22 semanas

    Así da gusto.

    Mi idea inicial era hacerlo en python pero llevo tanto tiempo diciendo que voy a aprender Python que ya ni me acuerdo. Y al final bash me resuelve siempre la papeleta de una u otra forma.

    Lo bueno de que funcione en python es que no se dependería de ningún programa externo. Simplemente habría que utilizar los bindings de Gstreamer y lanzar desde ahí la reproducción, ya que Gstreamer utiliza modplug para reproducir los mod.

    De todas formas, si os fijáis le he hecho unos cuantos cambios al código. Ahora ya no uso mikmod, he pasado a audacious, aunque cambiar a mikmod es relativamente simple, con poner

    PLAYER=/usr/bin/mikmod
    PLAYEROPTS="-i -hqmixer --surrond -X -noloops"

    y eliminar la comprobación de que el player esté ejecutandose.

    Ahora tarda mas al arrancar ya que recupera la búsqueda completa y de ahí crea una playlist, así nos evitamos que en una misma sesión se repitan pistas. Pero en cuanto se descarga el primer fichero ya se puede dar al play del audacious y empezar a escuchar, que el resto se van añadiendo a la cola conforme se descargan.

  • Un pequeño script para tener un Jukebox de Modarchive.org   hace 6 años 22 semanas
  • Un pequeño script para tener un Jukebox de Modarchive.org   hace 6 años 22 semanas

    gracias Eye-wink probe con <*code><*/code> pero no lo resaltaba, ¿cual era la etiqueta correcta?

  • Un pequeño script para tener un Jukebox de Modarchive.org   hace 6 años 22 semanas

    ... esto sí que es un buen background musical.

  • Un pequeño script para tener un Jukebox de Modarchive.org   hace 6 años 22 semanas

    ... editado para que se vea como código.

  • Un pequeño script para tener un Jukebox de Modarchive.org   hace 6 años 22 semanas

    Bueno, mis dos céntimos, ya que al menos lo has liberado como software libre.

    He portado el script bash de fsancho a python. Creo que requiere al menos python 2.7 ya que utiliza el módulo optparse.

    Se puede descargar de:
    http://www.shakaran.net/blog/wp-content/modarchive/modarchive.py

    Os lo pongo al final de mi comentario también.

    Ejemplo de ejecución:
    python modarchive.py -s random -d

    Resto de ejemplos en la ayuda (intentando mantener las opciones originales):
    python modarchive.py -h

    Supongo que es mejorable, no esta muy pythonico y tendrá algun bug (no he probado todas las acciones), pero es lo que he podido hacer en una horilla libre de la siesta.

    Saludos

    #!/bin/env python
    #*-* coding: utf-8 *-*
     
    """
    ###############################################################################
    #                        MODARCHIVE JUKEBOX SCRIPT
    #   
    #  Made by: Fernando Sancho AKA ‘toptnc’
    #  email: toptnc@gmail.com
    #
    #  This script plays mods from <a href="http://modarchive.org" title="http://modarchive.org">http://modarchive.org</a> in random order
    #  It can fetch files from various categories
    #
    #   This scripts needs the program mikmod installed under $PATH
    #
    #  This script is released under the terms of GNU GPL License 
    #
    ###############################################################################
     
    GPLv3 03-18-2011 
    Port to python by: Ángel Guzmán Maeso (shakaran at gmail dot com) <a href="http://shakaran.net/blog/wp-content/modarchive/modarchive.py
    " title="http://shakaran.net/blog/wp-content/modarchive/modarchive.py
    ">http://shakaran.net/blog/wp-content/modarchive/modarchive.py
    </a> 
    """
    from sys import exit
    from os import path, makedirs, mkdir, remove, system
    from urllib import urlopen
    import re
    import zipfile
     
    VERSION = '1.0'
    DEBUG = False
    MODPATH = '/tmp/modarchive'
    RANDOMSONG = None
    MIKMOD = '/usr/bin/mikmod'
    MODURL = None
     
    def get_mikmod_bin():
        return MIKMOD
     
    def check_mikmod():
        from os.path import exists as e
        return e(get_mikmod_bin())
     
    if not check_mikmod():
        print 'This scripts needs the binary MIKMOD to run. Please install it or change the script'
        exit(1)
     
    def get_url(url = None):
        try:
            return urlopen(url).read()
        except IOError, e:
            print _('Error: could not connect to the url' % url)
            return None
     
    def get_data(url = None, uregex = None):
        data = get_url(url)
        #print data
        data.replace('<>', '\n')
        if uregex:
            p = re.compile(r'(%s)' % uregex)
            m = p.search(data)
     
            if m:
                return m.group()
            else:
                print 'No se encontraron resultados'
                return None
        else:
            return data
     
    def get_mod_file(modurl, page):
        data = get_url('%s&page=%s' %(modurl, page))
        data.replace('href=', '\n')
        data.replace('>', '\n')
     
        p = re.compile(r'(http://modarchive.org/data/downloads.php\?moduleid=(.*)\#)')
        m = p.search(data)
     
        if m:
            module = m.group()[50 : -150]
            module = module[0:- (len(module) - module.find('#')) ]
            debug(module)
            return ('http://modarchive.org/data/downloads.php?moduleid=%s' % module, module)
        else:
            print 'No se encontraron resultados'
            return (None, None)
     
    def unzip_file_into_dir(file, modID, dir):
        if not path.exists(dir + '/' + modID):
            mkdir(dir + '/' + modID, 0777)
        zfobj = zipfile.ZipFile(file)
        for name in zfobj.namelist():
            if name.endswith('/'):
                if not path.exists(path.join(dir, name)):
                    mkdir(path.join(dir, name))
            else:
                outfile = open(path.join(dir + '/' + modID, name), 'wb')
                outfile.write(zfobj.read(name))
                outfile.close()
     
    def debug(string = None):
        if DEBUG:
            print 'DEBUG:', string
     
    def usage():
        return """
    Modarchive Jukebox can be used with one of the following options:
    \n\n
    Hint: Use + symbol instead blankspaces in search strings."""
     
    from argparse import ArgumentParser, RawTextHelpFormatter
     
    parser = ArgumentParser(prog='modarchive', formatter_class=RawTextHelpFormatter, add_help=True, description=usage(), version=VERSION)
    parser.add_argument('-d', '--debug', action='store_true', dest='debug', help='Enable debug mode')
     
    parser.add_argument('-s', dest='section', nargs=1, type=str, choices=('uploads', 'featured', 'favourites', 'downloads', 'topscore', 'new', 'random'),
              help="""Play from selected section: Can be one of this
    uploads     This is a list of the recent member upload activity.
    featured    These modules have been nominated by the crew for either \n\t    outstanding quality, technique or creativity (or combination of).
    favourites  These modules have been nominated by the members via their favourites.
    downloads   The top 1000 most downloaded modules, recorded since circa 2002.
    topscore    This chart lists the most revered modules on the archive.
    new         Same than uploads but using search engine.
    random      Ramdom module from entire archive.""")
     
    search_group = parser.add_argument_group('Searching')
    search_group.add_argument('-a', dest='artist', nargs=1, type=str, help='Search in artist database')        
    search_group.add_argument('-m', dest='module', nargs=1, type=str, help="Search in module database (Title and Filename)")
     
    try:
        results = parser.parse_args()
    except IOError, msg:
        parser.error(str(msg))
     
    if results.debug:
        DEBUG = True
     
    debug(results)
     
    pages = None
    if results.section:
        if results.section[0] == 'uploads':
            MODURL = 'http://modarchive.org/index.php?request=view_actions_uploads'
            pages = None
        elif results.section[0] == 'featured':
            MODURL = 'http://modarchive.org/index.php?request=view_chart&query=featured'
            pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
        elif results.section[0] == 'favourites':
            MODURL = 'http://modarchive.org/index.php?request=view_top_favourites'
            pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
        elif results.section[0] == 'downloads':
            MODURL = 'http://modarchive.org/index.php?request=view_chart&query=tophits'
            pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
        elif results.section[0] == 'topscore':
            MODURL = 'http://modarchive.org/index.php?request=view_chart&query=topscore'
            pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
        elif results.section[0] == 'new':
            MODURL = 'http://modarchive.org/index.php?request=search&search_type=new_additions'
            pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
        elif results.section[0] == 'random':
            MODURL = 'http://modarchive.org/index.php?request=view_random'
            pages = 0
    elif results.artist:
        MODURL = 'http://modarchive.org/index.php?query=%s&submit=Find&request=search&search_type=guessed_artist' % results.artist[0]
        pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
    elif results.module:
        MODURL = 'http://modarchive.org/index.php?request=search&query=%s&submit=Find&search_type=filename_or_songtitle' % results.module[0]
        res = get_data(MODURL, 'page=(\w)#mods')[5:-5]
     
    print "Starting Modarchive JukeBox Player"
    debug("Pages: %s" % pages)
     
    if not path.exists(MODPATH):
        debug('Creating dir %s' % MODPATH)
        makedirs(MODPATH)
     
    while 1:
        print 'Press Ctrl-C twice to stop'
     
        (modfile, modID) = get_mod_file(MODURL, pages)
     
        if modfile:
            zip_file = '%s/%s.zip' %(MODPATH, modID)
            print "Downloading %s to %s" %(modfile, zip_file)
            f = open(zip_file, 'w')
            f.write(get_url(modfile))
            f.close()
            unzip_file_into_dir(zip_file, modID, MODPATH)
            remove(zip_file)
     
    #   if [ ! -z $(pgrep pidgin) ];
    #   then
    #       purple-remote "setstatus?status=available&message=Modarchive JukeBox:  ${MODFILE}"
    #   fi;
    	print 'mikmod i -hqmixer --surrond X -noloops %s/%s/*' % (MODPATH, modID)
        print system('mikmod i -hqmixer --surrond X -noloops %s/%s/*' % (MODPATH, modID))
    #   if [ ! -z $(pgrep pidgin) ];
    #   then
    #       purple-remote "setstatus?status=available&message="
    #   fi;

  • Fotografía final con R.Stallman   hace 6 años 22 semanas

    Corregido Laughing out loud