System Configuration

I have a CentOS 7 host machine with two KVM guests:

  1. Smoothwall 3.1
  2. Ubuntu 14.04

The Smoothwall is configured RED+GREEN+ORANGE with three separate network interfaces. The RED and GREEN interfaces are connected via bridged Macvtap with virtio drivers to two separate host interfaces (enp5s0 and enp6s0) which, in turn, are connected to two physical network cards on the machine. ORANGE is connected to a guest-only virtual switch. RED is connected to another network / gateway that connects the Smoothwall to the Internet, same as the host interface on the same card (but with different IP addresses – the RED is static, entered manually and the host is dynamic – DHCP).

After a restart of the host, all machines, host and guests, have all of the expected network connectivity, and everything just works.

The Problem

Where I live we experience periodic Internet outages lasting from a second or two to several minutes. Every time there is an outage the RED interface loses all connectivity, both inbound and outbound, once connectivity to the host has been restored (and possibly during the outage).

Following the loss of connectivity, in the host Settings -> Network control panel the interface associate with RED (Macvtap0), which is normally visible and editable, is still visible but it’s options cannot be changed as the Options button is missing. Also, the ON/OFF button is missing too. Furthermore, it no longer has anything more than a MAC address (normally it has both a MAC and an IPV6 address).

Control Panel Before Outage

Macvtap working properly

Control Panel After Outage

Macvtap failing

I’ve tried changing the driver (virtio, rtl8139, e1000, etc.) and I’ve tried changing the physical hardware but neither change has altered the behavior so I’m pretty sure it’s something in the Macvtap software that’s failing (or misconfigured).

The Solution?

There are multiple articles and bug reports that seem to indicate that this can be repaired by enabling promiscuous mode on the interface, but I tried that (sudo ifconfig Macvtap0 promisc) to no avail. Maybe I needed to toggle the interface (ifup or something like that?)

Estimado Bankia:

Desde hace varias semanas me encuentro totalmente incapaz de realizar transferencias desde mi cuenta de Empresa en el portal de Empresas de bankia.es. Sospecho que es algo que estoy haciendo mal ya que, si no mal recuerdo, lo logré hacer por lo menos una vez hace aproximadamente un mes.

Publico aquí (en este foro público) los tests que he realizado porque quiero saber si otra persona en el mundo también ha tenido este problema o si realmente soy yo el único en toda España. Al ser que soy yo, sabré que es un problema con los datos que introduzco y no, como siempre sugiere el personal de apoyo técnico de Bankia, un problema de mi navegador o sistema operativo.

Entiendo que algún protocolo hay que seguir al realizar apoyo técnico a distancia pero también creo que cuando la persona al otro lado del teléfono indica claramente que ya ha intentado todo lo que le sugieren, hay que creerlo y buscar otras posibles soluciones. En mi caso me dijeron que mandara un correo electrónico a la dirección de soporte técnico de Bankia, lo cual haré con un enlace a este post.

Los pasos a seguir que siempre recomienda soporte técnico de Bankia son: “eliminar cookies, limpiar cache, actualizar navegadores, probar con otros sistemas operativos / otro equipo, etc.” En este post muestro con capturas de pantalla todos los tests que he realizado. Al realizar los tests, pongo el navegador en modo “privado” para evitar problemas de cache y cookies. También, ya que la web de Bankia lo pone, pincho en Aceptar en cada aviso de cookies.

En mis tests seguía este proceso:

  1. Ir a la página inicial de Empresas de Bankia
  2. Pinchar en Entrar
  3. Introducir datos de contrato, etc. y pinchar en Enviar

Resultado Esperado

Veo un listado de mis cuentas

Resultado Actual

Se queda estancada la web con el mensaje: Cargando aplicación (me ha pasado alguna vez, ver más abajo)

Como alguna vez he logrado sobrepasar esta página, continúo con el proceso:

  1. Pinchar en la cuenta de la cual quiero transferir dinero
  2. Pinchar en la pestaña Favoritos para ahorrar tiempo
  3. Pinchar en el plus (+) para expandir la lista de favoritos (por cierto, interfaz totalmente no necesario en mi opinión)
  4. Pinchar en el favorito deseado
  5. Rellenar el formulario resultante con todos los datos necesarios para realizar la transferencia
  6. Pinchar en Continuar

Resultado Esperado

La transferencia se realiza con éxito y la web lo confirma con un mensaje de éxito.

Resultado Actual

Nada. La página no responde.

Hace unas semanas a través de twitter, avisé de este problema pero la respuesta dejó algo que desear.

Capturas de pantalla

Lo que sigue son las capturas de pantalla para los siguientes navegadores y sistemas operativos:

  1. Apple Macintosh
    • Google Chrome Chrome Mac About
      Chrome Mac Empresas Home
      Aquí falla – Pincho en Continuar y no responde la página ni muestra errores Chrome Mac Broken Continuar
    • Google Canary (open source version of Chrome) Canary Chrome About
      Aquí falla – Pincho en Continuar y no responde la página ni muestra errores Canary Chrome Broken Continuar
    • Firefox FF Mac About
      FF Mac Empresas Home
      Aquí falla – No llega a cargarse, da igual el tiempo que esté abierto FF Mac Cargando aplicacion
    • Safari Safari Mac About
      Safari Mac Empresas Home
      Aquí falla – Pincho en Continuar y no responde la página ni muestra errores Safari Mac Broken Continuar
  2. Linux Mint (Debian)
    • Firefox FF Linux About
      FF Linux Empresas Home
      Aquí falla – No llega a cargarse, da igual el tiempo que esté abierto FF Linux Cargando aplicacion
  3. Windows 8.1
    • Internet Explorer IE Win About
      IE Win Empresas Home
      Aquí falla – Pincho en Continuar y no responde la página ni muestra errores IE Win Broken Continuar

Ahora, como se imaginarán, preparar este informe detallado me ha costado un par de horas. Agradecería que Bankia tuviera el detalle de reconocer que sí que hay un problema y que no es ni mi navegador ni mi sistema operativo, etc., pero no lo harán. No lo harán porque no es su cultura. Lástima, lástima… Que sepa Bankia que a mi me ha costado un par de horas preparar este informe inútil pero a ellos les ha costado un cliente. Recomiendo a los directivos de Bankia que lean The Cluetrain Manifesto y que se actualicen sus maneras y que mejoren su apoyo técnico, nivel 1, pero tampoco me harán no creo que me harán caso así que adiós Bankia. ¡Adiós!

PD: Me pregunto que si su web funciona con estos errores, qué otros sistemas informáticos tendrán con errores?

Actualización (4 horas después de publicar esto): Recibí una llamada (tras un par de correos de Bankia pidiendo más información) de un tal Miguel. La verdad es que me trató muy bien: nada de actitud, pidiendo disculpas por la mala gestión de la incidencia y reconociendo que en efecto era un problema de Bankia. En concreto, la funcionalidad de Favoritos no funciona correctamente. Le comenté a Miguel que para mí, un botón o enlace, para los usuarios, es como una promesa y si no funciona o funciona de una manera no esperada, crea en ella una emoción parecido a la frustración. Le recomendé que quitaran la funcionalidad hasta que funcionara y dijo que lo anotaría en su informe.

Al final seguramente me han perdido como cliente por muchas razones (entre ellas si quiero cancelar mi cuenta tengo que ir a la oficina donde la abrí – que me lo expliquen…) pero agradezco mucho la llamada y la ayuda. Pena que no cuenten con 100 Migueles en Bankia para atenderte tan amablemente como fue conmigo.

In about 2006 Fer Torres (one of the members of our dev team), who was studying English, suggested we speak in English on Fridays as a way for him and the others in the office to practice in real-world situations. We did it for a few months and honestly it was not only fun but very beneficial for the non-native staff.

Now that I’m back doing development and helping to run a team of developers (all of whom are non-native) and now that I’m working in a shared office space (known as a coworking space here) where there are many non-native speakers of English, I suggested we take up the tradition anew. Much to my surprise, nearly everyone enthusiastically agreed.

Here’s how it works:

  1. On Fridays, speak in English whenever you can. The only rule is that it has to be fun. Play with the language…
  2. Use social media to help promote the idea. I like to post translations of common phrases in Spanish into English, phrases that might be a bit unusual or funny. I always include the #EnglishFriday hash tag.
  3. Whenever you text or write an email, try doing it in English! You might be surprised how much fun it can be.

Obviously, if you’re at work, there will be times when you simply need to revert to Spanish (or whatever your native language is). That’s fine, of course, because if it isn’t fun, people won’t do it.

I’m new to WordPress development and recently found myself needing to create a secondary query using WP_Query. The Codex has a pretty good introduction to querying WordPress using WP_Query but no where, not even in the new Developer documentation, do they say that you MUST call the_post() inside the loop. If you fail to call the_post(), you may get the error “Fatal error: Maximum function nesting level of ‘100’ reached, aborting!”

To the documentation team’s credit, they do point out that if you fail to call the_post(), many template tags will fail to function as expected. Also, in a few places they do mention that the_post() increments the internal counter by one. It makes me wonder why have_posts() doesn’t just call the_post() internally and be done with it…

I lost hours trying to figure this out. And just for the sake of completeness, here is a full example of what WordPress needs to properly execute a loop as a secondary query (and it matters not that this is against a custom post type):

$my_query = new WP_Query( $args );

while( $my_query->have_posts() ) {

$my_query->the_post(); // does nothing visual, just sets some variables and advances the internal pointer

the_title(); // note that we do NOT use $my_query->the_title(), I have no idea why not…

}

wp_reset_postdata(); // reset the main post variable, $wp_the_post to the main query

And it should be noted that all those posts about the problem being XDebug are all just wrong. The problem is not the limit placed on the number of nested function calls (100 seems far, far more than adequate) but the fact that you’ve reach 100 in the first place.

I sincerely hope this helps others in the same situation.

Current version of saywire.com.

Current version of saywire.com.

Highlights

  • Among the first social Network for Minors
  • Live in 2007

Description

Saywire is one of the first social networks for minors complying in large part with COPPA. In fact, it was started even before the term social network came into common use. My company was hired to provide remote web application development services, both front and back ends. We set up and maintained the code repository and automated deployment into staging and production environments, including the ability to roll back if needed. We provided PHP and corresponding MySQL, HTML, and JavaScript for large portions of early versions of the web site and provided input on how best to use the Fusebox web application framework.

Technical

Early versions of saywire.com were based on Fusebox in a LAMP environment. We used Subversion as our code repository and incorporated a variety of client-side technologies (CSS2 and JavaScript).

 

Although I’ve been using XSLT on a variety of projects for nearly 10 years now, I’m still stuck using XSLT version 1.0 only processors and frequently turn to “keys” to solve complex grouping problems. A few weeks ago I was presented with a grouping problem that put my knowledge to the test and forced me to fully understand how keys work and how best to set them up. Thanks to the fabulous people on the XSL mailing list, I was given lots of valuable feedback and pointed in the right direction. I feel it’s only fair to share what I learned: the USE attribute is the XPath to the node whose data you want to use as the key (the “grouper” if you will). Furthermore, the XPath is relative to the ELEMENT in the MATCH attribute.

Normally it’s as easy as specifying an attribute to use as the key but let’s consider an example in which all the elements are the same and the only thing that uniquely identifies them is their location relative to each other. Consider a table with the following structure (TD elements with nothing below them have ROWSPANs set):

td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td td

In a KEY element, you identify the source element you wish to capture (TR in this case) in the MATCH attribute. In the USE attribute you specify an XPath statement indicating the node the matched element will belong to (be grouped by). This is fairly straight forward when the input is well defined, but in a situation like ours, where structure is the only thing we can key off of, and the structure itself is somewhat amorphous, it can be quite difficult to write the proper XPath.

Let’s say the first row is the header row. It should not be included in the output as it simply contains labels for the columns. Rather than accounting for it in the key element, we’ll simply skip it when applying templates (select="//tr[position() > 1]").

The key (or group name) for the matched elements will come from rows containing 6 or more TD elements. Specifically, the data will come from the first TD element in those rows. The XPath would be something like this ancestor-or-self::tr[count(td) >= 6]/td[1]. Unfortunately, this code only groups rows in which there are 6 or more TD elements. Rows with 5 or less TD elements are left out of the result set. For rows with 5 or less TD elements we will need to look up in document order and stop at the first row above them containing 6 or more TD elements. This is where it gets complicated… This could be solved with some sort of IF-THEN-ELSE construct but since we’re using XSLT, that’s not the best approach.

Instead, we’re going to capture ALL the potential keys above the current row and filter out the ones we don’t need.

To “look up” we use preceding-sibling: ancestor-or-self::tr/preceding-sibling::tr[count(td) >= 6]. This will give us ALL the rows with 6 TD elements preceding the currently matched row. However, we only want the row [with 6 TD elements] that immediately precedes the currently matched row, and not all of the preceding siblings. Thus we append: [position() = count(.)] which gives us the last item in the set (not exactly sure why last() doesn’t work here, but it doesn’t) followed by the first TD element in the row: /td[1].

Finally we filter out the nodes we don’t need. We do this by joining the statements via the pipe character | and enclosing the whole thing in parentheses, and from that result set we take the very last element: [last()], which is exactly the key we are looking for. Here is the final key element:

 

<xsl:key 
	name="ports-by-ship" 
	match="tr" 
	use="(ancestor-or-self::tr[count(td) &gt;= 6]/td[1] 
		| ancestor-or-self::tr/preceding-sibling::tr[count(td) &gt;= 6][position() = count(.)]/td[1])[last()]" 
/>

 

Because it’s hard to see the result of such a complex XPath, I first run the transformation using a template match on TR elements and copy-of the results to the output. That way I can see what my XPath is actually producing. Once I’ve got the set I’m looking for, I move it into a key element.

They say you don’t really know something until you can explain it to someone else. I’m not sure if I’ve succeeded in explaining it or not, but I feel like I’m much, much closer than I was when I was presented with this problem a few weeks ago.

My XML input.

My XML output.

My XSLT.

CarolanHighlights

  • More than 10,000 items online
  • Highly SEO Optimized
    • SEO Friendly URLs
    • Main content delivered first in document order, navigation last
    • Extensive use of CSS sprites
    • All HTML, JavaScript, and CSS files minified and gzipped
  • Fully automated integration with backend database, including roll-back capabilities
  • Fully automated connection between products and their images
  • Fully automated watermarking of images
  • Custom store administration interface for new items

Description

Carolanfiestas.com is a “bricks to clicks” solution for Carolan, a party supply store in the Canary Islands. With more than 40,000 items in their inventory, Carolan needed a online store to expand their presence to other parts of Spain. Furthermore, they wanted to improve their ranging in the search engines and sell, sell, sell!

Technical

Carolanfiestas.com was a Zen Cart store with a custom theme and a few minor tweaks to improve search engine optimization. On the back end, the server would receive updates to articles in XML and update the Zen Cart database every few minutes with the changes. Likewise, whenever an item was sold, an XML file was sent to the backend database to keep inventory accurate. This site made extensive use of Bash scripts to move the data from XML to MySQL and to manage the creation of images with their watermarks (a minimum of 4 sizes per image). During the busy season, the site was very busy with more than 10,000 visits per day. You can read more about this project here (in Spanish).