Artículos de diciembre 2009

Colorea los logs de Symfony

Si eres uno de esos desarrolladores a los que nos gusta hacer un “tail -f” y ver los logs de tus aplicaciones vía shell, esta clase te puede ayudar con tus logs de Symfony.

Se trata de una clase con un par de métodos estáticos que colorearán los mensajes que vayas a añadir al log en función de su tipo o severidad. Está implementado de una manera muy guarrilla funcional y seguro que se puede modificar fácilmente para extender Symfony como dios manda usando un poco de herencia.

No la he probado aun con Symfony 1.3 ó 1.4, pero no creo que falle y si os causa algún problema solo hay que corregir una línea (teóricamente), por lo que lo publico tal cual. La única pega que tiene esta clase es que ensuciará un poco los logs cuando los veáis a través del debug web ya que veréis los códigos ANSI. Como he dicho antes, esta clase es sobre todo para los que inspeccionamos los logs en shell.

Logger.class.php:

/**
 * This class will use Symfony's logging system adding some ANSI color codes
 * depending on the severity/type of the message. The goal is to provide a quick
 * visual recognition of log lines on shell.
 *
 * TODO:
 * Actually do some inheritance here and extend Symonfy intself
 *
 * WARNING:
 * By using this class you will find some weird codes in the web debug interface.
 *
 * @author Guillermo Gutiérrez [email protected]
 */
class Logger {
        // These are the log levels defined in Symfony
        const EMERG = 0; // System is unusable
        const ALERT = 1; // Immediate action required
        const CRIT = 2; // Critical conditions
        const ERR = 3; // Error conditions
        const WARNING = 4; // Warning conditions
        const NOTICE = 5; // Normal but significant
        const INFO = 6; // Informational
        const DEBUG = 7; // Debug-level messages
 
        const ANSI_END = "\033[0m";
 
        /**
         * Adds a message to the log
         *
         * @param string $msg The message to be added
         * @param string $module The module that is producing this message. Default: _DEBUG_
         * @param string $severity The severity of the message. Must be one of the class constants
         */
        public static function log($msg, $module = '_DEBUG_', $severity = self::DEBUG) {
                // I'm sure that there is a more elegant way to do this
                if (!in_array($severity, array(
                        self::EMERG,
                        self::ALERT,
                        self::CRIT,
                        self::ERR,
                        self::WARNING,
                        self::NOTICE,
                        self::INFO,
                        self::DEBUG
                        ))) {
                        throw new Exception(__METHOD__ . " requires a valid severity code");
                }
                switch ($severity) {
                        case self::EMERG:
                        case self::ALERT:
                                $style = "\033[0;49;31;1m";
                                break;
                        case self::CRIT:
                        case self::ERR:
                                $style = "\033[0;49;31m";
                                break;
                        case self::WARNING:
                                $style = "\033[0;49;33;1m";
                                break;
                        case self::NOTICE:
                        case self::INFO:
                                $style = "\033[0;49;32m";
                                break;
                        case self::DEBUG:
                                $style = "\033[0;49;36m";
                                break;
                }
                $msg = $style."{".$module."} ".$msg.self::ANSI_END;
                try {
                        sfContext::getInstance()->getLogger()->log($msg, $severity);
                } catch (Exception $e) {
                        // Replace this with something else in production environments!
                        echo $msg."\n";
                }
        }
 
        /**
         * This method is a shortcut for self::log(print_r($someArray, true), $module, $severity);
         * @param Array $array Array to be logged
         * @param string $module The module that is producing this message. Default: _DEBUG_
         * @param string $severity The severity of the message. Must be one of the class constants
         */
        public static function printR($array, $module = '_DEBUG_', $severity = self::DEBUG) {
                self::log(print_r($array, true), $module, $severity);
        }
}
Retweet
Publicado el : 29 diciembre 2009
Categorías: General
Etiquetas: , , ,
Comentarios: Ningún comentario

Inyección de dependencia en PHP5

La gracia de tener en marcha proyectos personales es que puedes permitirte perder un poco de tiempo para hacer cosas nuevas o darle a tu código esa “vuelta de tuerca” que en tu trabajo te ahorras por no tener tiempo para virguerías.

Una de las últimas con las que me he entretenido mucho ha sido con la inyección de dependencia, a partir de un magnífico artículo sobre ello del creador de Symfony, Fabien Potencier.

En este caso, necesitaba dotar a una clase de la posibilidad de atacar a un servicio externo por curl. Además necesitaba poder activar y desactivar la utilización de un proxy para la transmisión y el uso de caché en función de la situación, por lo que la inyección de dependencia parecía un método adecuado para la ocasión.

Inicialmente, planteé un escenario con tres clases: IO, IOProxied e IOCached, pero por un lado no se puede desligar de una manera elegante el manejo de proxies de la clase que realiza finalmente la llamada curl y, por otro lado, es matar moscas a cañonazos.

Finalmente, el escenario que decidí desarrollar contiene la clase IO, con el core de la funcionalidad: realiza llamadas curl vía proxy si es necesario. Después está la clase IOCached, que implementa la capa de caché extendiendo IO. Por último, tengo la clase Armory que, vía inyección de dependencia, realiza sus llamadas con o sin cache, en función de cómo instanciemos sus objetos.

Al final, el código queda así:

...
$ioParams = array(
        'proxy' => array(
                'ip' => sfConfig::get('curl_proxy_ip'),
                'port' => sfConfig::get('curl_proxy_port')
        ),
        'userAgent' => true,
        'language' => $request->getParameter('language'),
        'due' => 30
);
$armory = new Armory(new IOCached($ioParams));
...

o, sencillamente, así:

...
$ioParams = array(
        'proxy' => array(
                'ip' => sfConfig::get('curl_proxy_ip'),
                'port' => sfConfig::get('curl_proxy_port')
        ),
        'userAgent' => true,
        'language' => $request->getParameter('language')
);
$armory = new Armory(new IO($ioParams));
...

La diferencia está en la instancia que le pasamos a Armory en su constructor.

Como bola extra, aquí va el código de estas clases. No las he revisado demasiado, así que disculpad cualquier fallito que podáis encontrar. Si intentáis hacer un copy pasteo de este código seguramente no funcione directamente en vuestras aplicaciones ya que hace llamadas a métodos de otras clases que no incluyo.

Clase IO:

/**
 * Input Output class
 *
 * This class implements an abstraction layer for curl HTTP calls
 *
 * TODO:
 *  - Change behavior of user agent configuration option to let the string itself to be set
 *  - Implement dependency injection for log and debug
 *
 * @author     Guillermo Gutiérrez [email protected]
 */
class IO {
        /**
         * Stores the description for connection errors using curl. Connection errors come from connection timeouts and DNS resolution errores from curl interaction with the remote host or the proxy
         * @var string
         */
        const IO_CONNECTION_ERROR = "Host/proxy resolutionor connection error";
        /**
         * Stores the description for remote host error response codes
         * @var string
         */
        const IO_HOST_ERROR = "Received an error from the host";
        /**
         * Stores the description for timeouts after connection is established
         * @var string
         */
        const IO_TIMEOUT = "Timeout error";
        /**
         * Stores the description for a generic error
         * @var string
         */
        const IO_ERROR = "Generic error";
 
        /**
         * Stores the User Agent string to be used in the HTTP headers if needed
         * @var unknown_type
         */
        const USER_AGENT = "Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.8) Gecko/2009032712 Ubuntu/8.10 (intrepid) Firefox/3.0.8";
 
        /**
         * Stores the IP for the proxy
         * @var string with format: www.xxx.yyy.zzz
         */
        protected $proxyIp;
        /**
         * Stores the port number for the proxy
         * @var integer
         */
        protected $proxyPort;
        /**
         * Stores a boolean flag to tell this instance if it has to include User Agent HTTP header or not
         * @var boolean
         */
        protected $userAgent;
        /**
         * Stores the language for the communication
         * @var string with 2 or 5 character code
         */
        protected $language;
        /**
         * Stores the maximum number of tries to be perfomed before giving up
         * @var integer
         */
        protected $maxTries;
        /**
         * Stores the maximum number of seconds to wait for connection to the remote host or proxy before giving up
         * @var integer
         */
        protected $connectionTimeout;
        /**
         * Stores the maximum number of seconds to wait for data before giving up
         * @var integer
         */
        protected $timeout;
 
        /**
         * Class constructor. It may receive an array of optional configuration options:
         *
         *  - proxy: An array with IP and port indexes specifying the information to use a proxy for calls. Optional
         *  - userAgent: Boolean that will tell the instance to use User Agent header in the calls or not. Default: true
         *  - language: 2 or 5 character culture code. Default: es
         *  - maxTries: Integer with the number of tries before throwing an IO_CONNECTION_ERROR exception. Default: 3
         *  - connectionTimeout: Integer with the number of seconds to wait establishing the connection to the remote host before throwing an IO_CONNECTION_ERROR. Default: 5
         *  - timeout: Integer with the number of seconds to wait for data from the remote host before throwing an IO_TIMEOUT. Default: 15
         *
         * @param $options array with options to be set
         */
        public function __construct($options = array()) {
                if (array_key_exists('proxy', $options)) {
                        $this->proxyIp = $options['proxy']['ip'];
                        $this->proxyPort = $options['proxy']['port'];
                }
                if (array_key_exists('userAgent', $options)) {
                        $this->userAgent = $options['userAgent'];
                } else {
                        $this->userAgent = true;
                }
                if (array_key_exists('language', $options)) {
                        $this->language = $options['language'];
                } else {
                        $this->language = 'es';
                }
                if (array_key_exists('maxTries', $options)) {
                        $this->maxTries = max(1, $options['maxTries']);
                } else {
                        $this->maxTries = 3;
                }
                if (array_key_exists('connectionTimeout', $options)) {
                        $this->connectionTimeout = max(1, $options['connectionTimeout']);
                } else {
                        $this->connectionTimeout = 5;
                }
                if (array_key_exists('timeout', $options)) {
                        $this->timeout = max(1, $options['timeout']);
                } else {
                        $this->timeout = 15;
                }
        }
 
        /**
         * Returns the language for this instance
         */
        public function getLanguage() {
                return $this->language;
        }
 
        /**
         * Returns the proxy's IP for this instance
         */
        public function getProxyIp() {
                return $this->proxyIp;
        }
 
        /**
         * Returns the proxy's port for this instance
         */
        public function getProxyPort() {
                return $this->proxyPort;
        }
 
        /**
         * Returns the user agent for this instance
         */
        public function getUserAgent() {
                return $this->userAgent;
        }
 
        /**
         * Sets the proxy's IP for this instance
         *
         * @param string $proxyIp with the IP to be used (xxx.xxx.xxx.xxx format)
         */
        public function setProxyIp($proxyIp) {
                $this->proxyIp = $proxyIp;
        }
 
        /**
         * Sets the proxy's port for this instance
         *
         * @param integer $proxyPort with the port number to be used
         */
        public function setProxyPort($proxyPort) {
                $this->proxyPort = $proxyPort;
        }
 
        /**
         * Sets the user agent for this instance
         *
         * @param bool $userAgent with a boolean that will decide if we use user agent header or not
         */
        public function setUserAgent($userAgent) {
                $this->userAgent = $userAgent;
        }
 
        /**
         * Sets the language for this instance
         *
         * @param string $language with the language (culture) to be used (2 or 5 character code)
         */
        public function setLanguage($language) {
                $this->language = $language;
        }
 
        /**
         * Performs a curl call to a given url, using the given method and post payload if it is present
         *
         * @param string $url with the url to be called
         * @param string $method with the method to be used (get or post). Default: get
         * @param string $postPayload (optional) with the post payload to be sent (for form simulation)
         */
        public function call($url, $method = 'get', $postPayload = null) {
                $stop = false;
                $tries = 0;
                while(!$stop) {
                        $tries++;
                        Logger::log(vsprintf("Performing try #%s to %s", array($tries, $url)));
                        $ch = curl_init($url);
                        curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
                        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectionTimeout);
                        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
                        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                        curl_setopt($ch, CURLOPT_HTTPHEADER, array(sprintf('Accept-Language: %s', $this->language)));
                        if ($method == 'post') {
                                curl_setopt($ch, CURLOPT_POST, true);
                                curl_setopt($ch, CURLOPT_POSTFIELDS, $postPayload);
                        }
                        if ($this->userAgent) {
                                curl_setopt($ch, CURLOPT_USERAGENT, self::USER_AGENT);
                        }
                        if ($this->proxyIp != null && $this->proxyPort != null) {
                                curl_setopt($ch, CURLOPT_PROXY, vsprintf("%s:%s", array($this->proxyIp, $this->proxyPort)));
                        }
                        $result = curl_exec($ch);
                        switch(curl_errno($ch)) {
                                case CURLE_OK:
                                        $stop = true;
                                        break;
                                case CURLE_COULDNT_RESOLVE_PROXY:
                                case CURLE_COULDNT_RESOLVE_HOST:
                                case CURLE_COULDNT_CONNECT:
                                        Logger::log($url." => ".curl_error($ch), __METHOD__, Logger::CRIT);
                                        if ($tries == $this->maxTries) {
                                                throw new Exception(self::IO_CONNECTION_ERROR);
                                        }
                                        break;
                                case CURLE_HTTP_RETURNED_ERROR:
                                        Logger::log($url." => ".curl_error($ch), __METHOD__, Logger::WARNING);
                                        if ($tries == $this->maxTries) {
                                                throw new Exception(self::IO_HOST_ERROR);
                                        }
                                        break;
                                case CURLE_OPERATION_TIMEDOUT:
                                        Logger::log($url." => ".curl_error($ch), __METHOD__, Logger::WARNING);
                                        if ($tries == $this->maxTries) {
                                                throw new Exception(self::IO_TIMEOUT);
                                        }
                                        break;
                                default:
                                        Logger::log($url." => ".curl_error($ch), __METHOD__, Logger::WARNING);
                                        throw new Exception(self::IO_ERROR);
                                        break;
                        }
                        $stop = ($stop || $tries == $this->maxTries);
                }
                curl_close($ch);
                return $result;
        }
 
        /**
         * Prepares params to be added to a url for a get call
         *
         * @param mixed $params Array or string with params
         */
        public static function prepareParams($params) {
                $newParams = "";
                if (is_array($params) && count($params) > 0) {
                        foreach ($params as $name => $value) {
                                $newParams .= "$name=$value&";
                        }
                        $newParams = substr($newParams, 0, -1);
                } else {
                        $newParams .= trim($params);
                }
                return $newParams;
        }
}

Clase IOCached:

/**
 * Input Output class, cached flavour
 *
 * This class is used to abstract curl calls and implements a cache layer to economize network usage
 *
 * TODO:
 *  - Adapt log and debug when it's implemented in IO
 *
 * @author     Guillermo Gutiérrez [email protected]
 */
class IOCached extends IO {
        protected $due;
 
        /**
         * Class constructor. It may receive an array of optional configuration options:
         *
         *  - due: Integer with the timestamp for the date and time that the cache will due for the calls this instance will perform
         *  - and everyone defined in IO class
         *
         * @param $options array with options to be set
         * @see IO
         */
        public function __construct($options = array()) {
                parent::__construct($options);
                if (array_key_exists('due', $options)) {
                        $this->due = $options['due'];
                } else {
                        throw new Exception(__CLASS__." constructor needs a 'due' option to be set");
                }
        }
 
        /**
         * Performs a curl call to a given url, using the given method and post payload if it is present
         *
         * @param string $url with the url to be called
         * @param string $method with the method to be used (get or post). Default: get
         * @param string $postPayload (optional) with the post payload to be sent (for form simulation)
         */
        public function call($url, $method = 'get', $postPayload = null) {
                $postPayload = IO::prepareParams($postPayload);
                $hash = $this->getHash($url, $postPayload);
                $ioCache = IoCachePeer::retrieveByPK($hash);
                /* @var ioCache IoCache */
                if (!($ioCache instanceof IoCache)) {
                        Logger::log("Creating cache for {".$method."} $url", __METHOD__, Logger::INFO);
                        $ioCache = new IoCache();
                        $ioCache->setHash($hash);
                        $ioCache->setInfo(vsprintf(
                                "{%s} %s (%s) - User Agent: %s",
                                array(
                                        $method,
                                        $url,
                                        ($postPayload != "") ? $postPayload : "no payload",
                                        ($this->getUserAgent()) ? "ON" : "OFF"
                                )
                        ));
                } else {
                        Logger::log("Found cache for {".$method."} $url", __METHOD__, Logger::INFO);
                }
                if ($ioCache->getTs('U') < (time() - $this->due)) {
                        $ioCache->setContent(parent::call($url, $method, $postPayload));
                        $ioCache->setTs(time());
                        $ioCache->save();
                        Logger::log("Cache updated with fresh content", __METHOD__, Logger::INFO);
 
                }
                return $ioCache->getContent();
        }
 
        /**
         * Returns the calculated hash that identifies the given url and param string pair
         *
         * @param $url string
         * @param $params string
         */
        private function getHash($url, $params) {
                return sha1($this->getUserAgent().$url.$params);
        }
}

La estructura de datos para la versión cacheada es super sencilla:

CREATE TABLE  `tdg_delta`.`io_cache` (
  `hash` varchar(255) NOT NULL,
  `info` varchar(255) NOT NULL,
  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `content` longtext,
  PRIMARY KEY  (`hash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Y como bola extra, la clase Armory, que hace un par de operaciones sencillas contra la Armería (ojo, sin comentarios: you’re on your own):

class Armory {
        protected $io;
 
        public function __construct($io) {
                $this->io = $io;
        }
 
        public function searchItems($name) {
                $url = sfConfig::get('armory_eu_url') . "/" . sprintf(sfConfig::get('armory_query_search_item'), $name);
                $data = new SimpleXMLElement($this->io->call($url));
                $itemXMLList = $data->xpath('//item');
                $itemList = array();
                foreach ($itemXMLList as $itemXML) {
                        $item = array();
                        $item['id'] = (int)$itemXML['id'];
                        $item['name'] = (string)$itemXML['name'];
                        $item['rarity'] = (int)$itemXML['rarity'];
                        $item['icon'] = (string)$itemXML['icon'];
                        $itemList[] = $item;
                        self::getArmoryIcon($item['icon']);
                }
                return array_slice($itemList, 0, 25);
        }
 
        public static function getArmoryIcon($image) {
                $localPath = sfConfig::get('sf_root_dir') . "/web" . sfConfig::get('armory_icon_local_path') . "/$image.png";
                if (!file_exists($localPath)) {
                        $remotePath = sfConfig::get('armory_eu_url') . sfConfig::get('armory_icon_remote_path') . "/$image.png";
                        $io = new IO(array('proxy' => array('ip' => sfConfig::get('curl_proxy_ip'), 'port' => sfConfig::get('curl_proxy_port'))));
                        file_put_contents($localPath, $io->call($remotePath));
                }
        }
 
        public function searchChars($name, $wowServerGroupId = 1) {
                if (trim($name) == "") {
                        $name = "Donald";
                }
 
                $wowServerGroup = WowServerGroupPeer::retrieveByPK($wowServerGroupId);
                if (!($wowServerGroup instanceof WowServerGroup)) {
                        Logger::log("Received server group doesn't exist", __METHOD__, Logger::CRIT);
                        throw new Exception("Wrong server group selected");
                }
 
                // Get content from armory
                $url = $wowServerGroup->getArmoryUrl()."/".sprintf(sfConfig::get('armory_query_search_char'), $name);
                $data = new SimpleXMLElement($this->io->call($url));
                $characterXMLList = $data->xpath('//character');
 
                // Realms and guilds
                $criteria = new Criteria();
                $wowRealms = array();
                foreach($wowServerGroup->getWowRealms($criteria) as $wowRealm) {
                        $wowRealms[$wowRealm->getName()] = $wowRealm;
                }
                $wowGuilds = WowGuildPeer::doSelectIndexedByPK($criteria);
 
                // Parse chars
                $wowChars = array();
                foreach($characterXMLList as $char) {
                        $wowChar = new WowChar();
                        $wowChar->setWowClassId((int)$char['classId']);
                        $wowChar->setWowGenderId((int)$char['genderId']);
                        if (!array_key_exists((string)$char['realm'], $wowRealms)) {
                                $wowRealm = new WowRealm();
                                $wowRealm->setName((string)$char['realm']);
                                $wowRealm->setWowServerGroupId($wowServerGroup->getWowServerGroupId());
                                $wowRealm->save();
                                $wowRealms[$wowRealm->getName()] = $wowRealm;
                        }
                        if ((int)$char['guildId'] != 0) {
                                if (!array_key_exists((int)$char['guildId'], $wowGuilds)) {
                                        $wowGuild = new WowGuild();
                                        $wowGuild->setWowGuildId((int)$char['guildId']);
                                        $wowGuild->setName((string)$char['guild']);
                                        $wowGuild->setWowRealmId($wowRealms[(string)$char['realm']]);
                                        $wowGuild->save();
                                        $wowGuilds[$wowGuild->getWowGuildId()] = $wowGuild;
                                }
                                $wowChar->setWowGuildId((int)$char['guildId']);
                        }
                        $wowChar->setWowRealmId($wowRealms[(string)$char['realm']]->getWowRealmId());
                        $wowChar->setLevel((int)$char['level']);
                        $wowChar->setName((string)$char['name']);
                        $wowChar->setWowRaceId((int)$char['raceId']);
                        $wowChars[] = $wowChar;
                }
                return $wowChars;
        }
 
}
Retweet
Publicado el : 28 diciembre 2009
Categorías: Desarrollo
Etiquetas: , ,
Comentarios: Ningún comentario

¡Zas, en toca la boca!

Así quedó ayer el cavaliere después de que un iluminado perturbado mental le propinara un crochet en toa la cepa la oreja.

¡Zas, en toda la boca!

¡Zas, en toda la boca!

En el hostipal le realizaron un TAC para detectar posibles daños cerebrales”

Chiste fácil: “Digo yo que se lo podrían haber ahorrado, ¿no?”

Retweet
Publicado el : 14 diciembre 2009
Categorías: Chorradas
Etiquetas: ,
Comentarios: Ningún comentario

Manifiesto ‘En defensa de los derechos fundamentales en Internet’

Ante la inclusión en el Anteproyecto de Ley de Economía sostenible de modificaciones legislativas que afectan al libre ejercicio de las libertades de expresión, información y el derecho de acceso a la cultura a través de Internet, los periodistas, bloggers, usuarios, profesionales y creadores de internet manifestamos nuestra firme oposición al proyecto, y declaramos que…

1.- Los derechos de autor no pueden situarse por encima de los derechos fundamentales de los ciudadanos, como el derecho a la privacidad, a la seguridad, a la presunción de inocencia, a la tutela judicial efectiva y a la libertad de expresión.

2.- La suspensión de derechos fundamentales es y debe seguir siendo competencia exclusiva del poder judicial. Ni un cierre sin sentencia. Este anteproyecto, en contra de lo establecido en el artículo 20.5 de la Constitución, pone en manos de un órgano no judicial -un organismo dependiente del ministerio de Cultura-, la potestad de impedir a los ciudadanos españoles el acceso a cualquier página web.

3.- La nueva legislación creará inseguridad jurídica en todo el sector tecnológico español, perjudicando uno de los pocos campos de desarrollo y futuro de nuestra economía, entorpeciendo la creación de empresas, introduciendo trabas a la libre competencia y ralentizando su proyección internacional.

4.- La nueva legislación propuesta amenaza a los nuevos creadores y entorpece la creación cultural. Con Internet y los sucesivos avances tecnológicos se ha democratizado extraordinariamente la creación y emisión de contenidos de todo tipo, que ya no provienen prevalentemente de las industrias culturales tradicionales, sino de multitud de fuentes diferentes.

5.- Los autores, como todos los trabajadores, tienen derecho a vivir de su trabajo con nuevas ideas creativas, modelos de negocio y actividades asociadas a sus creaciones. Intentar sostener con cambios legislativos a una industria obsoleta que no sabe adaptarse a este nuevo entorno no es ni justo ni realista. Si su modelo de negocio se basaba en el control de las copias de las obras y en Internet no es posible sin vulnerar derechos fundamentales, deberían buscar otro modelo.

6.- Consideramos que las industrias culturales necesitan para sobrevivir alternativas modernas, eficaces, creíbles y asequibles y que se adecuen a los nuevos usos sociales, en lugar de limitaciones tan desproporcionadas como ineficaces para el fin que dicen perseguir.

7.- Internet debe funcionar de forma libre y sin interferencias políticas auspiciadas por sectores que pretenden perpetuar obsoletos modelos de negocio e imposibilitar que el saber humano siga siendo libre.

8.- Exigimos que el Gobierno garantice por ley la neutralidad de la Red en España, ante cualquier presión que pueda producirse, como marco para el desarrollo de una economía sostenible y realista de cara al futuro.

9.- Proponemos una verdadera reforma del derecho de propiedad intelectual orientada a su fin: devolver a la sociedad el conocimiento, promover el dominio público y limitar los abusos de las entidades gestoras.

10.- En democracia las leyes y sus modificaciones deben aprobarse tras el oportuno debate público y habiendo consultado previamente a todas las partes implicadas. No es de recibo que se realicen cambios legislativos que afectan a derechos fundamentales en una ley no orgánica y que versa sobre otra materia.

Este manifiesto, elaborado de forma conjunta por varios autores (entre los cuales no me encuentro, pero con los que estoy completamente de acuerdo), es de todos y de ninguno. Se ha publicado en multitud de sitios web. Si estás de acuerdo y quieres sumarte a él, difúndelo por Internet.

Retweet
Publicado el : 2 diciembre 2009
Categorías: General
Etiquetas:
Comentarios: 1 comentario