{"id":337,"date":"2006-07-09T03:10:42","date_gmt":"2006-07-09T10:10:42","guid":{"rendered":"http:\/\/www.gubatron.com\/blog\/?p=337"},"modified":"2006-07-09T03:10:42","modified_gmt":"2006-07-09T10:10:42","slug":"porque-el-podcast-de-esta-semana-se-ha-tardado","status":"publish","type":"post","link":"https:\/\/www.gubatron.com\/blog\/porque-el-podcast-de-esta-semana-se-ha-tardado\/","title":{"rendered":"Porque el podcast de esta semana se ha tardado."},"content":{"rendered":"<p>Si existe un ser humano que esta haciendole seguimiento al proyecto SnowRSS, aqui puede ver los cambios realizados desde anoche.<br \/>\n&#8211; Agregamos una tabla para almacenar informacion relacionada a los enclosures de los posts RSS. Es decir, soportaremos videocasts y podcasts.<br \/>\n&#8211; Acomodamos de manera radical (refactoring) la forma en que haciamos las conexiones a la BD. Ahora todas las conexiones son simples instancias<br \/>\nde MySQLdb.cursor, como variables que se crean en la pila de cada metodo, se usan, se desconectan y listo. El servidor estaba teniendo problemas con<br \/>\nmuchas conexiones abiertas, ahora conexion que no usamos, conexion que desechamos. Este approach nos ha servidor muy bien con nuestra BD de lyrics en PHP<br \/>\ny el overhead de conexion y desconexion parece ser minimo ya que el servidor es local.<br \/>\n&#8211; Muchos otros fixes, limpieza, mayor busqueda del uso de OO en el codigo.<\/p>\n<p><code>Index: sql\/snowrss.sql<br \/>\n===================================================================<br \/>\n--- sql\/snowrss.sql\t(revision 20684)<br \/>\n+++ sql\/snowrss.sql\t(revision 20690)<br \/>\n@@ -53,3 +53,15 @@<br \/>\n   `BL_fk_lang_code` text,<br \/>\n   PRIMARY KEY (`BL_fk_blog_id`,`BL_fk_lang_code` (2))<br \/>\n ) ENGINE=MyISAM DEFAULT CHARSET=utf8;<br \/>\n+<br \/>\n+DROP TABLE IF EXISTS `ENCLOSURES`;<br \/>\n+CREATE TABLE `ENCLOSURES` (<br \/>\n+  `Enc_pk_id` int(11) NOT NULL auto_increment,<br \/>\n+  `Enc_fk_post_id` int(11) NOT NULL,<br \/>\n+  `Enc_url` text NOT NULL,<br \/>\n+  `Enc_creation_timestamp` double default 0,<br \/>\n+  `Enc_update_timestamp` double default 0,<br \/>\n+  `Enc_length` double default 0,<br \/>\n+  `Enc_type` text,<br \/>\n+  PRIMARY KEY (`Enc_pk_id`)<br \/>\n+) ENGINE=MyISAM DEFAULT CHARSET=utf8;<br \/>\nIndex: snowrss.py<br \/>\n===================================================================<br \/>\n--- snowrss.py\t(revision 20684)<br \/>\n+++ snowrss.py\t(revision 20690)<br \/>\n@@ -1,11 +1,12 @@<br \/>\n import MySQLdb<br \/>\n from MySQLdb import MySQLError<br \/>\n-from snowrss_config import getDBCon<br \/>\n+from snowrss_config import *<br \/>\n import feedparser,sys,os,time<br \/>\n from threading import Thread<\/p>\n<p> class Post:<br \/>\n     '''Receives a dictionary with<br \/>\n+    [id]:<br \/>\n     blog_id:<br \/>\n     post_title:<title><br \/>\n     post_author:<br \/>\n@@ -14,43 +15,58 @@<br \/>\n     post_timestamp:<br \/>\n     post_tags:[]<br \/>\n     '''<br \/>\n-    def __init__(self,props,cursor):<br \/>\n+    def __init__(self,props):<br \/>\n         self.properties = props<br \/>\n-        self.cursor = cursor<\/p>\n<p>     def setBlogId(self,id=None):<br \/>\n         self.blog_id = id<\/p>\n<p>-    def __reconnect(self):<br \/>\n-        \"\"\"Reconnects to the database\"\"\"<br \/>\n-        self.con.ping() # = getDBCon()<br \/>\n-        #self.cursor = self.con.cursor(MySQLdb.cursors.DictCursor)<br \/>\n-<br \/>\n     def save(self):<br \/>\n         sql = 'insert into BLOG_POSTS '<br \/>\n         sql += '(BP_fk_blog_id,BP_title,BP_author,BP_link,BP_summary,BP_timestamp) '<br \/>\n         sql += \"values (%d,'%s','%s','%s','%s',%d);\"<\/p>\n<p>         sql = sql % (self.properties['blog_id'],<br \/>\n-          self.properties['post_title'] .replace(\"'\",\"&quot;\").encode('utf8'),<br \/>\n-          self.properties['post_author'].replace(\"'\",\"&quot;\").encode('utf8'),<br \/>\n-          self.properties['post_link'].replace(\"'\",\"&quot;\").encode('utf8'),<br \/>\n-          self.properties['post_summary'].replace(\"'\",\"&quot;\").encode('utf8'),<br \/>\n+          self.properties['post_title'] .replace(\"'\",\"\\'\").encode('utf8'),<br \/>\n+          self.properties['post_author'].replace(\"'\",\"\\'\").encode('utf8'),<br \/>\n+          self.properties['post_link'].replace(\"'\",\"\\'\").encode('utf8'),<br \/>\n+          self.properties['post_summary'].replace(\"'\",\"\\'\").encode('utf8'),<br \/>\n           self.properties['post_timestamp'])<\/p>\n<p>         try:<br \/>\n-            self.cursor.execute(sql)<br \/>\n+            cursor = getDbCursor()<br \/>\n+            cursor.execute(sql)<br \/>\n+            cursor.connection.close()<br \/>\n         except Exception, e:<br \/>\n             #MySQL has gone away<br \/>\n-            if (e[0] == 2006):<br \/>\n-                self._reconnect()<br \/>\n-                self.save()<br \/>\n-                print 'Post.save(): ' + sql<br \/>\n-                print e<br \/>\n-                print \"RECONNECTING\"<br \/>\n-                print<br \/>\n+            print 'Post.save(): ' + sql<br \/>\n+            print e<\/p>\n<p>-    def wasUpdated(ignoreme,cursor,post_link,post_timestamp):<br \/>\n+        self.setIdFromTitle()<br \/>\n+<br \/>\n+    def setIdFromTitle(self):<br \/>\n+        #we fetch the id of the post.<br \/>\n+        sql = \"SELECT BP_pk_id FROM BLOG_POSTS WHERE BP_link = '%s'\"<br \/>\n+        sql = sql %  self.properties['post_link']<br \/>\n+<br \/>\n+        cursor = None<br \/>\n+        try:<br \/>\n+            cursor = getDbCursor()<br \/>\n+            cursor.execute(sql)<br \/>\n+            cursor.connection.close()<br \/>\n+        except Exception, e:<br \/>\n+            print<br \/>\n+            print \"Post.setIdFromTitle(): \" + sql<br \/>\n+            print e<br \/>\n+            print<br \/>\n+<br \/>\n+        data = cursor.fetchone()<br \/>\n+        self.properties['id'] = int(data['BP_pk_id'])<br \/>\n+<br \/>\n+    def getId(self):<br \/>\n+        return int(self.properties['id'])<br \/>\n+<br \/>\n+    def wasUpdated(ignoreme,post_link,post_timestamp):<br \/>\n         '''Returns true if the post identified by the post_link has an older timestamp than the given one.'''<\/p>\n<p>         sql='select BP_timestamp  1:<br \/>\n             #If there are many repetitions, delete all but one.<br \/>\n             appearances = int(data['posted_before'])<br \/>\n@@ -120,8 +144,9 @@<br \/>\n             print detail<\/p>\n<p>             try:<br \/>\n-                cursor.connection.ping()<br \/>\n+                cursor = getDbCursor()<br \/>\n                 cursor.execute(sql)<br \/>\n+                cursor.connection.close()<br \/>\n             except MySQLdb.Error, e:<br \/>\n                 print \"Post.exists() Error cleaning posts [%s] - %d: %s\" % (post_link,<br \/>\n                                                                             e.args[0],<br \/>\n@@ -130,18 +155,25 @@<br \/>\n                 sys.exit()<br \/>\n             return True<\/p>\n<p>-<br \/>\n         if int(data['posted_before']) &gt;= 1:<br \/>\n             return True<br \/>\n         return False<br \/>\n     exists = classmethod(exists)<\/p>\n<p>-    def load(self,id):<br \/>\n-        '''Loads all the post data given the post id'''<br \/>\n+    def hasEnclosure(self):<br \/>\n+        \"\"\"Tells if there's an enclosure on the database related to this post\"\"\"<br \/>\n+        #TODO<br \/>\n+        return True<br \/>\n+<br \/>\n+    def getEnclosure(self):<br \/>\n+        \"\"\"Returns an enclosure if this post has one.\"\"\"<br \/>\n+        #TODO<br \/>\n+        if self.hasEnclosure():<br \/>\n+            return True<\/p>\n<p> class Blog:<br \/>\n-    def __init__(self,con,props=None):<br \/>\n+    def __init__(self,props=None):<br \/>\n         '''Receives a dictionary<br \/>\n         id:<br \/>\n         blog_name:<br \/>\n@@ -158,32 +190,13 @@<\/p>\n<p>         if self.props == None:<br \/>\n             self.props = {}<br \/>\n-<br \/>\n-        self.setConnection(con)<br \/>\n-        self.setRunsAsThread(False)<\/p>\n<p>-    def setConnection(self, con):<br \/>\n-        self.con = con<br \/>\n-        self.setCursor(self.con.cursor(MySQLdb.cursors.DictCursor))<br \/>\n+    def getId(self):<br \/>\n+        return self.props['id']<\/p>\n<p>-    def setRunsAsThread(self, isThread=True):<br \/>\n-        '''To determine if this Blog will fetch its posts on a separate thread or not'''<br \/>\n-        self.props['is_thread'] = isThread<br \/>\n-<br \/>\n-    def runsAsThread(self):<br \/>\n-        return self.props['is_thread']<br \/>\n-<br \/>\n-    def setCursor(self, cursor):<br \/>\n-        self.cursor = cursor<br \/>\n-<br \/>\n     def __str__(self):<br \/>\n         return str(self.props['id']) + ' - ' + self.props['blog_name']<\/p>\n<p>-    def __reconnect(self):<br \/>\n-        \"\"\"Reconnects to the database\"\"\"<br \/>\n-        self.con = getDBCon()<br \/>\n-        self.cursor = self.con.cursor(MySQLdb.cursors.DictCursor)<br \/>\n-<br \/>\n     def getUrl(self):<br \/>\n         return self.props['blog_url']<\/p>\n<p>@@ -199,14 +212,14 @@<br \/>\n         sql = sql % (self.props['blog_url'], int(self.props['id']))<\/p>\n<p>         try:<br \/>\n-            self.cursor.execute(sql)<br \/>\n+            cursor = getDbCursor()<br \/>\n+            cursor.execute(sql)<br \/>\n+            cursor.connection.close()<br \/>\n         except Exception, e:<br \/>\n             print<br \/>\n+            print 'Blog.updateUrl(): ' + sql<br \/>\n             print e<br \/>\n-            print 'Blog.updateUrl(): ' + sql<br \/>\n-            print \"RECONNECTING\"<br \/>\n-            self.__reconnect()<br \/>\n-            self.updateUrl(url)<br \/>\n+            print<\/p>\n<p>     def getRssUrl(self):<br \/>\n         return self.props['blog_rss_url']<br \/>\n@@ -223,14 +236,15 @@<br \/>\n         sql = sql % (self.props['blog_rss_url'], int(self.props['id']))<\/p>\n<p>         try:<br \/>\n-            self.cursor.execute(sql)<br \/>\n+            cursor = getDbCursor()<br \/>\n+            cursor.execute(sql)<br \/>\n+            cursor.connection.close()<br \/>\n         except Exception, e:<br \/>\n             print<br \/>\n+            print 'Blog.updateRssUrl(): ' + sql<br \/>\n             print e<br \/>\n-            print 'Blog.updateRssUrl(): ' + sql<br \/>\n-            print \"RECONNECTING\"<br \/>\n-            self.__reconnect()<br \/>\n-            self.updateRssUrl(rssUrl)<br \/>\n+            print<br \/>\n+<\/p>\n<p>     def hasLanguageCode(self,lang_code,refresh=False):<\/p>\n<p>@@ -263,10 +277,14 @@<br \/>\n         sql = \"INSERT INTO BLOG_LANGUAGES VALUES (%d,'%s');\" % (self.props['id'],<br \/>\n                                                                 lang_code)<br \/>\n         try:<br \/>\n-            self.cursor.execute(sql)<br \/>\n+            cursor = getDbCursor()<br \/>\n+            cursor.execute(sql)<br \/>\n+            cursor.connection.close()<br \/>\n         except MySQLdb.Error, e:<br \/>\n+            print<br \/>\n             print \"Blog.addLanguageCodes() Error: %d: %s\" % (e.args[0],e.args[1])<br \/>\n             print sql<br \/>\n+            print<br \/>\n             sys.exit()<\/p>\n<p>         self.getLanguageCodes(True) #Refresh<br \/>\n@@ -279,10 +297,14 @@<br \/>\n         sql = \"DELETE FROM BLOG_LANGUAGES WHERE BL_fk_blog_id = %d\" % (self.props['id'])<\/p>\n<p>         try:<br \/>\n-            self.cursor.execute(sql)<br \/>\n+            cursor = getDbCursor()<br \/>\n+            cursor.execute(sql)<br \/>\n+            cursor.connection.close()<br \/>\n         except MySQLdb.Error, e:<br \/>\n+            print<br \/>\n             print \"Blog.clearLanguageCodes() Error: %d: %s\" % (e.args[0],e.args[1])<br \/>\n             print sql<br \/>\n+            print<br \/>\n             sys.exit()<\/p>\n<p>         return True<br \/>\n@@ -306,10 +328,14 @@<br \/>\n         sql = sql % (self.props['id'],lang_code)<\/p>\n<p>         try:<br \/>\n-            self.cursor.execute(sql)<br \/>\n+            cursor = getDbCursor()<br \/>\n+            cursor.execute(sql)<br \/>\n+            cursor.connection.close()<br \/>\n         except MySQLdb.Error, e:<br \/>\n+            print<br \/>\n             print \"Blog.removeLanguageCodes() Error: %d: %s\" % (e.args[0],e.args[1])<br \/>\n             print sql<br \/>\n+            print<br \/>\n             sys.exit()<\/p>\n<p>         #clear and reload current languages from the database<br \/>\n@@ -333,13 +359,17 @@<br \/>\n         sql += 'WHERE BL_fk_blog_id = ' + str(self.props['id'])<\/p>\n<p>         try:<br \/>\n-            self.cursor.execute(sql)<br \/>\n+            cursor = getDbCursor()<br \/>\n+            cursor.execute(sql)<br \/>\n+            cursor.connection.close()<br \/>\n         except MySQLdb.Error, e:<br \/>\n+            print<br \/>\n             print \"Blog.getLanguageCodes() Error: %d: %s\" % (e.args[0],e.args[1])<br \/>\n             print sql<br \/>\n+            print<br \/>\n             sys.exit()<\/p>\n<p>-        result_set = self.cursor.fetchall()<br \/>\n+        result_set = cursor.fetchall()<\/p>\n<p>         if len(result_set) = max_threads:<br \/>\n-#                for t in threads:<br \/>\n-#                    t.join()<br \/>\n-#                    threads.remove(threads[0])<br \/>\n-#                    if len(threads) &gt; ((max_threads\/2) + 1):<br \/>\n-                       #print \"We can continue without waiting now\"<br \/>\n-#                        break<br \/>\n+        if parallel_fetching==False:<br \/>\n+            # LINEAL FETCHING<br \/>\n+            blog.fetchPosts()<br \/>\n+            print blog.getName()<br \/>\n+        else:<br \/>\n+            #PARALLEL FETCHING<br \/>\n+            if (len(threads) = max_threads:<br \/>\n+                    for t in threads:<br \/>\n+                        t.join()<br \/>\n+                        threads.remove(threads[0])<br \/>\n+<br \/>\n+                        if len(threads) &gt; ((max_threads\/2) + 1):<br \/>\n+                            #print \"We can continue without waiting now\"<br \/>\n+                            break<br \/>\nIndex: util\/check_who_applied.py<br \/>\n===================================================================<br \/>\n--- util\/check_who_applied.py\t(revision 20684)<br \/>\n+++ util\/check_who_applied.py\t(revision 20690)<br \/>\n@@ -8,10 +8,8 @@<br \/>\n     print \"Could not import snowrss_config\"<br \/>\n     sys.exit()<\/p>\n<p>-con = snowrss_config.getDBCon()<br \/>\n+cursor = getDbCursor()<\/p>\n<p>-cursor = con.cursor()<br \/>\n-<br \/>\n sql = \"SELECT * FROM BLOGS WHERE Blog_active != 1;\"<br \/>\n cursor.execute(sql)<\/p>\n<p>@@ -26,9 +24,7 @@<br \/>\n     print \"Status: %s\" % b['Blog_active']<br \/>\n     print \"Podcast: %s\" % b['Blog_is_podcast']<\/p>\n<p>-    blog = Blog(con)<br \/>\n+    blog = Blog()<br \/>\n     blog.load(int(b['Blog_pk_id']))<br \/>\n     print \"Languages: %s\" % str(blog.getLanguageCodes())<br \/>\n     print<br \/>\n-<br \/>\n-con.close()<br \/>\nIndex: util\/fetch_enclosures.py<br \/>\n===================================================================<br \/>\n--- util\/fetch_enclosures.py\t(revision 0)<br \/>\n+++ util\/fetch_enclosures.py\t(revision 20690)<br \/>\n@@ -0,0 +1,23 @@<br \/>\n+import sys<br \/>\n+sys.path.append('\/home\/wedoit4y\/www\/news4you\/SnowRSS\/')<br \/>\n+<br \/>\n+try:<br \/>\n+    import snowrss_config<br \/>\n+    from snowrss import *<br \/>\n+except Exception,e:<br \/>\n+    print \"Could not import snowrss_config [%s]\" % e<br \/>\n+    sys.exit()<br \/>\n+<br \/>\n+blogs = Blog.getBlogs()<br \/>\n+podcasts = []<br \/>\n+<br \/>\n+for blog in blogs:<br \/>\n+    if blog.isPodcast():<br \/>\n+        podcasts.append(blog)<br \/>\n+<br \/>\n+print \"Let's work with %d podcasts\" % len(podcasts)<br \/>\n+<br \/>\n+for podcast in podcasts:<br \/>\n+    print \"Scanning %s\" % podcast.getName()<br \/>\n+<br \/>\n+    podcast.updateEnclosures()<br \/>\nIndex: util\/check_stats.py<br \/>\n===================================================================<br \/>\n--- util\/check_stats.py\t(revision 20684)<br \/>\n+++ util\/check_stats.py\t(revision 20690)<br \/>\n@@ -7,18 +7,18 @@<br \/>\n     print \"Could not import snowrss_config\"<br \/>\n     sys.exit()<\/p>\n<p>-con = snowrss_config.getDBCon()<br \/>\n+con = snowrss_config.g<\/p>\n<p> cursor = con.cursor()<\/p>\n<p>-sql = \"select BP_fk_blog_id, COUNT(BP_fk_blog_id) as post_count, SUM(PH_hits) as hits, BLOGS.* FROM BLOG_POSTS JOIN BLOGS ON BP_fk_blog_id = Blog_pk_id JOIN POST_HITS ON BP_pk_id = PH_fk_post_id WHERE Blog_active=1 GROUP BY BP_fk_blog_id ORDER BY hits DESC;\"<br \/>\n+sql = \"select BP_fk_blog_id, COUNT(BP_fk_blog_id) as post_count, SUM(PH_hits) as hits, Blog_active, BLOGS.* FROM BLOG_POSTS JOIN BLOGS ON BP_fk_blog_id = Blog_pk_id JOIN POST_HITS ON BP_pk_id = PH_fk_post_id GROUP BY BP_fk_blog_id ORDER BY hits DESC;\"<\/p>\n<p> cursor.execute(sql)<\/p>\n<p> rows = cursor.fetchall()<br \/>\n i=1<br \/>\n-print \"PlacetHitstPoststBlog\"<br \/>\n+print \"PlacetHitstPoststBlogtIDtActive\"<br \/>\n for b in rows:<br \/>\n-    print \"%dt%st%st%s\" % (i,b['hits'],b['post_count'],b['Blog_name'])<br \/>\n+    print \"%dt%st%st%st%dt%s\" % (i,b['hits'],b['post_count'],b['Blog_name'],b['BP_fk_blog_id'],b['Blog_active'])<br \/>\n     i+=1<br \/>\n con.close()<br \/>\nIndex: util\/blog_is_podcast.py<br \/>\n===================================================================<br \/>\n--- util\/blog_is_podcast.py\t(revision 20684)<br \/>\n+++ util\/blog_is_podcast.py\t(revision 20690)<br \/>\n@@ -20,7 +20,7 @@<br \/>\n     print \"The ID of the blog needs to be an int\"<br \/>\n     sys.exit()<\/p>\n<p>-blog = Blog(getDBCon())<br \/>\n+blog = Blog()<br \/>\n blog.load(int(sys.argv[1]))<\/p>\n<p> if blog.isPodcast()==False:<br \/>\nIndex: util\/activate_blog.py<br \/>\n===================================================================<br \/>\n--- util\/activate_blog.py\t(revision 20684)<br \/>\n+++ util\/activate_blog.py\t(revision 20690)<br \/>\n@@ -8,8 +8,6 @@<br \/>\n     print \"Could not import snowrss_config [%s]\" % e<br \/>\n     sys.exit()<\/p>\n<p>-<br \/>\n-<br \/>\n if len(sys.argv) <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Si existe un ser humano que esta haciendole seguimiento al proyecto SnowRSS, aqui puede ver los cambios realizados desde anoche. &#8211; Agregamos una tabla para almacenar informacion relacionada a los enclosures de los posts RSS. Es decir, soportaremos videocasts y podcasts. &#8211; Acomodamos de manera radical (refactoring) la forma en que haciamos las conexiones a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[15,33],"tags":[],"class_list":["post-337","post","type-post","status-publish","format-standard","hentry","category-code","category-gubatron"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p5Unzf-5r","jetpack-related-posts":[{"id":159,"url":"https:\/\/www.gubatron.com\/blog\/wedoit4youcom-is-back\/","url_meta":{"origin":337,"position":0},"title":"wedoit4you.com is back.","author":"gubatron","date":"May 25, 2005","format":false,"excerpt":"Finalmente voy a poder dormir tranquilo (cualquiera cae que no duermo) wedoit4you.com esta montado en el nuevo servidor. Ahora tenemos practicamente ancho de banda ilimitado y absoluto control sobre el servidor, somos root. Haciendo valer un poco la cuna, vamos a dar ahora hosting con todas las de la ley.\u2026","rel":"","context":"In &quot;Gubatron&quot;","block_context":{"text":"Gubatron","link":"https:\/\/www.gubatron.com\/blog\/category\/gubatron\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":117,"url":"https:\/\/www.gubatron.com\/blog\/el-que-persevera-compila\/","url_meta":{"origin":337,"position":1},"title":"El que persevera\u2026 Compila!","author":"gubatron","date":"March 9, 2005","format":false,"excerpt":"Desde que me pase a Linux, he querido actualizar mi version de The Gimp. The Gimp,en su nueva version requiere Gtk 2.6.0, que a su vez requiere Glib > 2.6.0 (creo), y mi Linux SuSE trae Glib 1.2.23. Total que logico, uno empieza por lo de mas abajo. Me baje\u2026","rel":"","context":"In &quot;Gubatron&quot;","block_context":{"text":"Gubatron","link":"https:\/\/www.gubatron.com\/blog\/category\/gubatron\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":140,"url":"https:\/\/www.gubatron.com\/blog\/fotos-de-la-semana\/","url_meta":{"origin":337,"position":2},"title":"Fotos de la semana","author":"gubatron","date":"April 17, 2005","format":false,"excerpt":"Este post va a ser un poco grafico, pq el tiempo no alcanza mucho para escribir. En resumen, aqui tienen los enlaces para ver: http:\/\/dev.wedoit4you.com\/images\/16_inicio_primavera\/index.php http:\/\/dev.wedoit4you.com\/images\/abriendo_ipod\/index.php? http:\/\/dev.wedoit4you.com\/images\/mi_oficina\/index.php? (Si no se ven unas fotos dentro de este post, quiere decir que el servidor donde tengo las fotos esta caido, vuelvan mas\u2026","rel":"","context":"In &quot;Gubatron&quot;","block_context":{"text":"Gubatron","link":"https:\/\/www.gubatron.com\/blog\/category\/gubatron\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":411,"url":"https:\/\/www.gubatron.com\/blog\/i-love-my-internet-connection-optimum-online-brooklyn\/","url_meta":{"origin":337,"position":3},"title":"I love my internet connection (Optimum online, Brooklyn)","author":"gubatron","date":"December 14, 2006","format":false,"excerpt":"La prueba la hice en dslreports.com, tienen un applet java. Hice la prueba conectado de aqui de Brooklyn a un servidor en New Jersey, a unas 50 millas de aqui. Tasa de bajada 11.59 mbps, Tasa de subida 1752 Kbps. Luego hice otra prueba a un servidor en Palo Alto,\u2026","rel":"","context":"In &quot;Diary&quot;","block_context":{"text":"Diary","link":"https:\/\/www.gubatron.com\/blog\/category\/diary\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":566,"url":"https:\/\/www.gubatron.com\/blog\/apache2-enablesendfile\/","url_meta":{"origin":337,"position":4},"title":"Apache2: EnableSendFile","author":"gubatron","date":"August 7, 2007","format":false,"excerpt":"Aunque no recomiendo apache para servir archivos estaticos (demasiado overhead, es mejor que le eches un ojo a nginx o a lighttpd), encontre hoy una directiva que puede eliminar un poco el overhead al hacer una llamada directa al sistema -> sendfile. De momento lo que hice en uno de\u2026","rel":"","context":"In &quot;Geeklife&quot;","block_context":{"text":"Geeklife","link":"https:\/\/www.gubatron.com\/blog\/category\/geeklife\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":409,"url":"https:\/\/www.gubatron.com\/blog\/mi-escritorio-hoy\/","url_meta":{"origin":337,"position":5},"title":"Mi escritorio hoy","author":"gubatron","date":"December 7, 2006","format":false,"excerpt":"My office desk today Originally uploaded by Gubatron. 2 maquinas a veces no es suficiente. La primera de la izquierda tiene Ubuntu Edgy, ahi corro Eclipse para desarrollar en Java, y corro un servidor web de desarrollo (Jetty) - IBM T43 Es ahi tambien donde se desarrolla FrostWire cuando no\u2026","rel":"","context":"In &quot;Geeklife&quot;","block_context":{"text":"Geeklife","link":"https:\/\/www.gubatron.com\/blog\/category\/geeklife\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.gubatron.com\/blog\/wp-json\/wp\/v2\/posts\/337","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gubatron.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gubatron.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gubatron.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gubatron.com\/blog\/wp-json\/wp\/v2\/comments?post=337"}],"version-history":[{"count":0,"href":"https:\/\/www.gubatron.com\/blog\/wp-json\/wp\/v2\/posts\/337\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.gubatron.com\/blog\/wp-json\/wp\/v2\/media?parent=337"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gubatron.com\/blog\/wp-json\/wp\/v2\/categories?post=337"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gubatron.com\/blog\/wp-json\/wp\/v2\/tags?post=337"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}