Preguntas de entrevista de Google (con respuestas) II

Seguimos con otras diez preguntas de entrevista de Google tras la primera entrega de esta serie. Insisto en que si conoceis mejores respuestas o soluciones las pongais en los comentarios.

#11 ¿Cómo se pasan las cookies en el protocolo HTTP?

Bueno, esta me parece bastante fácil. Las cookies, que no son más que pares clave=valor se pasan como texto plano en las cabeceras de cualquier petición o respuesta HTTP. Cuando el explorador realiza una petición, pasa las cookies tal cual se las mandó el servidor simulando así una suerte de «estado persistente».

Puede encontrarse información sobre el protocolo HTTP y las cookies en particular en Wikipedia.

#12 Escribe una expresión regular que acepte direcciones de correo

Divide y vencerás: la estructura de un correo electrónico es [usuario]@[host] así que ya podemos hacer una versión inicial de la expresión regular:

()@()

Tenemos que rellenar esos corchetes. Vamos con el host que tiene una forma como [subdominio].[dominio]. Ese punto final es optativo (se supone que todos los FQDN lo llevan en su normalización) así que la expresión regular para el host será algo como:

([a-zA-Z0-9][a-zA-Z0-9-]*\.)+[a-zA-Z]+(\.)?

Es más o menos correcto. El primer grupo entre corchetes obliga a que el nombre del dominio empiece por un carácter alfanumérico. El segundo acepta el resto de caracteres (alfanuméricos y el guión) y hace terminar la cadena en punto. Todo esto podemos repetirlo indefinidamente (en realidad un nombre de dominio sólo puede tener hasta 253 caracteres). Debemos terminar con una extensión que representa un dominio de primer nivel formado por caracteres alfabéticos (al menos, uno) y el punto optativo final. Los puntos están precedidos de la barra para que no sean considerados caracteres especiales.

Ahora, el nombre de usuario depende. Pongamos algunas reglas. Supongamos que solo permitimos caracteres alfanuméricos, guiones bajos, puntos y símbolos de sumar y restar y que debe comenzar por un carácter alfanumérico o guión bajo . Su longitud mínima será de 1 caracter. Tenemos pues:

[_a-zA-Z0-9][_a-zA-Z0-9-+.]*

Ahora, combinando las tres, tenemos:

([_a-zA-Z0-9][_a-zA-Z0-9-+.]*)@(([a-zA-Z0-9][a-zA-Z0-9-]*\.)+[a-zA-Z]+(\.)?)

Y listo, ese churro valida direcciones email.

Os invito a probarlo en RegexPal.

#13 Escribe una función f(a, b) que toma dos cadenas de caracteres y devuelve otra sólo con los caracteres comunes en el orden en el que aparecen en a. Escribe una versión que ejecute en orden N cuadrado y otra en orden N.

Vamos a suponer caracteres alfabeticos y en minúscula:

La primera solución que se nos puede ocurrir es algo como esto (en Python).

def f(a,b):
  r = ''
  for c in a:
    if c in b and c not in r:
    r += c

  return r

Esta solución es N cuadrado pues el hecho de comprobar si el caracter c está o no en b supone un recorrido por los caracteres de b. Así que tenemos un bucle de longitud(b) dentro de otro de longitud(a) luego longitud(a)*longitud(b) pertenece a O(N^2). Esto es notación O que supongo que a cualquier ingeniero le sonará de algo.

La solución N es también muy fácil. Para ello necesitamos una función auxiliar que haga a=0, b=1, c=2…

def alpha_to_index(c):
  return ord(c)-ord('a')

def f(a,b):
  l = [0]*26
  for c in b:
    i = alpha_to_index(c)
    if not l[i]:
      l[i] = 1 # Indica aparición en b

  r = ""
  for c in a:
    i = alpha_to_index(c)
    if l[i] == 1:
      r += c
      l[i] = 2 # Indica ya añadida al resultado

  return r

Este algoritmo se ejecuta en longitud(a)+longitud(b) que pertenece a O(n) Para quitar las restricciones de minúscula y caracteres alfabéticos, en vez de un array se usa un hashmap (un diccionario en Python) para albergar el estado de los caracteres.

En breve dedicaré un post a la notación O y a cómo calcular el coste de un algoritmo.

#14 Te dan un código fuente que se rompe en cada ejecución. Tras ejecutarlo 10 veces en un depurador te das cuenta de que nunca se rompe dos veces por el mismo sitio. El código fuente sólo usa un hilo y la biblioteca estándar de C. ¿Qué errores de programación podrían estar causando los problemas? ¿Cómo podrías probar cada uno?

A mi se me ocurre que las causas pueden ser principalmente dos:

  1. Desbordamientos (y son un caso particular del segundo)
  2. Comportamientos indefinidos

Para probarlos cogería un lista de comportamientos indefinidos y probaría que no se están ralizando asunciones erroneas. Para los desbordamientos comprobaría los casos típicos (desbordamiento de array, de paso de parámetro, copia de arrays…).

#15 Explica cómo funciona el control de congestión en el protocolo TCP

La verdad es que este no es mi fuerte así que si alguien se sabe otra forma más sencilla de explicarlo, estaré encantdo de rectificar la respuesta. Entre lo que recuerdo de redes y lo que he sacado de la Wikipedia, la explicación se parece a esto:

El típico (porque hay varios) consiste en variar el tamaño de la llamada ventana de congestión mediante un algoritmo llamado Slow-Start. La necesidad del protocolo surge porque los extremos de una conexión TCP no tienen manera de saber a priori la calidad la red. En principio, no pueden saber el tamaño máximo del datgrama (los datos enviados en TCP)  que causaría la mayor tasa de transferencia sin desbordar la capacidad de la ruta seleccionada.

Encontrar este óptimo es tarea del algoritmo de control de congestión. Para ello, el emisor cuenta con una ventana de congestion que especifica cuántos datagramas enviará de golpe. La ventana comienza al tamaño máximo de un datagrama y cada vez que se acusa un recibo se dobla. Eventualmente se superará un umbral llamado sstresh que hará que la ventana aumente linealmente. En el momento en que la cantidad de datagramas satura la red se comienzan a perder paquetes y se produce una de las siguientes situaciones:

  • Si se detecta un timeout, la ventana se reestablece al tamaño máximo de un datagrama.
  • Si en vez de un timeout, se detectan tres acuses iguales, la ventana se reduce a la mitad del mínimo entre la ventana de congestión y la ventana de recepción (el tamaño máximo del datagrama que el nodo está dispuesto a aceptar por vez).

#16 En Java, ¿cuál es la diferencia entre final, finally y finalize?

Yo me sabía dos (final y finally):

  • final es un modificador de tipo. En variables indica que, una vez inicializada en el constructos, no puede volver a ser modificada. En clases indica que no se puede heredar de ella.
  • finally es una clusula del bloque try / catch que indica qué se debe hacer finalmente, antes de continuar la ejecución
  • finalize es el método al que invoca el recolector de basura al ir a destruir un objeto

Fuente: http://www.janeg.ca/scjp/gc/finalize.html

#17 ¿Qué es la programación multihilo? ¿Qué es un deadlock?

La programación multihilo hace referencia a distintas líneas de ejecución dentro de un programa. Cada línea de ejecución es un subprograma que mantiene su propio estado y es independiente de los demás. La comunicación se realiza mediante el traspaso de mensajes o a través de recursos compartidos. El acceso a estos recursos compartidos promueve toda una nueva serie de problemas relaccionados con el acceso simultáneo a los mísmos.

Un deadlock o interbloqueo es un problema de sincronización que se da cuando el hilo A se encuentra esperando un recurso del hilo B y viceversa. He encontrado un ejemplo muy claro de interbloqueo en el blog de JASoft.org

En él se nos invita a pensar en un proceso que transfiere dinero entre dos cuentas. Obviamente el proceso trata de obtener un acceso exclusivo a cada cuenta al comienzo de su ejecución por si ya hay otro proceso manipulando dicha cuenta. Si una cuenta está en uso, el hilo que la requiere esperará (haciendo nada) hasta que sea liberada.

Ahora supongamos que se producen dos transferencias en sentidos contrarios. Ambos procedimientos comenzarán por bloquear sus cuentas origen pero al tratar de bloquear las cuentas destino se encontraran con que tal cuenta ya se encuentra bloqueada. Y lo que es peor, de esta situación no saldrán nunca.

Fuente: http://geeks.ms/blogs/jalarcon/archive/2011/04/29/191-qu-233-es-un-deadlock-o-interbloqueo.aspx

#18 Escribe una función toExcel(v) que coja el valor de una columna excel (A, B, C, …, AA, AB, …, AAA) y devuelva su valor entero (A=1, B=2, C=3, …, AA=27…)

Este ejercicio es muy interesante pero aun lo es más el contrario. Para abordarlo, vamosa reducir al conjunto de letras a A, B y C. Ahora tenemos que A=1, B=2 y C=3 y la secuencia es A, B, C, AA, AB, AC, BA, BB, BC, CA, CB, CC…

Si recordais el post con el que (casi) abrimos el blog, relacionado con las bases de numeración y con el hecho de que la suma de 1 y 1 sea 10 en binario, vereis que esto se acerca mucho a contar en base 3. El problema es que los dígitos en base 3 son 0, 1 y 2; y no 1, 2 y 3 (o A, B y C) como ocurre en este caso. Resulta que en este problema no contamos con ningún dígito que represente el 0 pero sí con uno que representa la base.

Bien, vayamos primero con el problema contrario. Transformemos, por ejmplo, 12 en CC.

El número 12, escrito en base tres tiene la siguiente pinta: 110 dado que puede expresarse como 1*3^2 + 1*3^1 + 0*3^0 Ahora bien, como no contamos con ningún símbolo para representar el 0 pero sí par representar el 3, vamos a ajustar 110 tratando de quitar los 0s. Podemos quitar una «decena» y añadir 3 unidades lo que resulta en 103 cuya descomposición sería 1*3^2 + 0*3^1 + 3*3^0 que sigue siendo 12. Ahora tenemos un 0 más así que quitamos 1 «centena» y ponermos 3 «decenas» quedando 033. Como los 0s a la izquierda no importan pues ya hemos terminado y su descomposición es 0*3^2 + 3*3^1 + 3*3^0 que sigue siendo 12. Ahora reemplazamos cada dígito por su letra quedando CC.

De aquí puede inferirse fácilmente el algoritmo de transformación que nos piden y puede resumirse en dos sencillos pasos:

  1. Reemplazar cada letra por el dígito correspondiente (A=1, B=2, C=3…)
  2. Interpretar en base 3 (o, generalmente, en base la longitud del conjunto de símbolos)
def char_to_index(c):
  return ord(c) - ord('A') + 1

def toExcel(v):
  l = len(v)
  r = 0
  for i in range(l):
    c = v[i]
    r += char_to_index(c) * (26**(l-i))

  return r

El caso contrario requiere el estudio de un caso más. Pongamos que queremos transformar 9 en BC. 9 en base tres es 100. Empezamos quitando 0 de más a la derecha: quitamos 1 «decena» y añadimos 3 unidades resultando en 1-13 cuya descomposición sería 1*3^2 – 1*3^1 + 3*3^0 que sigue siendo 9. Como tampoco tenemos símbolos para números negativos quitamos 1 «centena» y añadimos 3 «decenas» quedando 023 cuya descomposición es 0*3^2 + 2*3^1 + 3*3^0 que sigue siendo 9. Ahora reemplazamos cada dígito por su letra lo que nos lleva a BC.

El algoritmo supone modificar ligeramente el clásico de las divisiones y restos utilizado para transformar a una base dada (comprobado que funciona):

def char_to_index(c):
  return ord(c) - ord('A') + 1

def index_to_char(i):
  if not i:
    return ''

  return chr(ord('A') + i - 1)

def fromExcel(n):
  res = []
  d = n
  fixmode = False # Indica que estamos en modo ajuste (restar 1 al siguiente resto y añadir 26 al actual)
  while d >= 26:
    r = d%26

    # Si estamos ajustando los restos, asumimos que ya hemos añadido 3 al anterior y le quitamos uno a este
    if fixmode:
      r -= 1

    # Si es (o queda) negativo, le sumamos veintiseis y pasamos (o conservamos) el modo de ajuste
    if r<=0:
      r += 26
      fixmode = True

    # Si no lo es, dejamos el modo de ajuste
    else:
      fixmode = False

    res.insert(0, r)

    d = int(d/26)

  res.insert(0, d)
  return ''.join(map(index_to_char, res))

#19 Si tienes 1 millon de enteros. ¿Cómo los ordenarías eficientemente? Modifica un algoritmo conocido para hacerlo.

Dedicaremos en breve otro post a los algoritmos de ordenación. Baste decir que para tal cantidad de datos se prefieren estrategias «divide y vencerás». Primeramente el milllón de datos puede separarse en tramos (digamos de 10000 ó 100000) enteros y ordenarse separadamente mediante qsort. Luego pueden mezclarse con merge sort.

También se podría haber aplicado merge sort directamente.

Ojo, si nos dan límites de memoria entonces tendremos que ir poco a poco. Leer unos cuantos, aplicar una técnica anterior, escribir el resultados; leer otros pocos, volver a aplicar una técnica y volver a escribir el resultado… Al final, habrá que mezclar los archivos ordenados.

Fuente: teneis aquí una solución por Guido van Rossum con código en Python 3.0

#20 Tienes un flujo continuo e infinito de consultas (las consultas de Google que la gente introduce). Describe como podrías tomar una buena estimación de 1000 muestras de este conjunto inagotable de datos.

Esta pregunta no la entiendo y, sencillamente, preguntaría por más información. ¿Qué característica tienen que cumplir estas mil muestras? Supongo que se referirá a las 1000 consultas más solicitadas. Para ello se puede usar una estructura de datos (que acabo de descubrir) llamada splay-tree o árbol biselado que no es otra cosa que un árbol binario con la propiedad de que los elementos más recientemente accedidos pueden recuperarse más rápidamente.

Esta solución del árbol biselado requiere alguna normalización que convierta las consultas en números. Se podría utilizar alguna función hash.

Si esta no es la característica que deben cumplir las muestras, entonces la solución cambia. Por ejemplo si tiene que ser aleatoria se puede dividir el conjunto de consultas en 1000 segmentos y seleccionar un elemento al azar de cada uno.

EDIT: Según un comentario (con el que estoy de acuerdo) de Jisakiel en Facebook, la muestra debería cumplir normalidad. Ahora bien, estamos en las mismas, normalidad sí pero ¿respecto de qué? Si nos asaltan con esta pregunta, es nuestra obligación fusilar al entrevistador con aclaraciones hast que sepamos exactamente las propiedades de la muestra.

Preguntas de entrevista de Google (con respuestas)

Bueno, ayer me rechazaron en Gameloft. Pero vamos, estoy en tropocientos procesos de selección y no me precoupa demasiado. Al parecer uno de ellos parace que será con Google. Alguien de Google Careers se puso en contacto conmigo y me dijo que había pasado mi CV (del que tenéis una versión recién actualizada en el blog). Así que supongo que en me llamarán en breve. ¡Y voy a hacer trampas!

No, ahora en serio. Sencillamente se ha presentado una muy buena escusa para coger una lista de preguntas que Google acostumbra a preguntar y responderlas. Evidentemente no me las sé todas y la mayoría están buscadas por ahí pero espero que sirvan para el enriquecimiento personal y profesional de todo programador. Por supuesto, si alguien quiere proporcionar una respuesta mejor, que lo haga. Yo voy a intentar ser sencillo, abstracto e independiente de la implementación. A ver si hay suerte. Aquí van las 10 primeras:

Seguir leyendo «Preguntas de entrevista de Google (con respuestas)»

Todo lo que un programador de C debería saber sobre el comportamiento indefinido

Hace unos días descubrí un enlace al blog del proyecto LLVM (del que hablaremos en otro momento) sobre el comportamiento indefinido de C, sus ventajas e inconvenientes. Me parece muy interesante de cara a producir código rápido y portable. De hecho, me gustó tanto que voy a colgaros su traducción tras estas líneas. No obstante se trata de una serie de tres artículos así que comienzo por el principio con este primer post que habla sobre las ventajas de no asumir ciertos comportamientos en C y por qué esto supone una ventaja en cuanto a optimización.

Seguir leyendo «Todo lo que un programador de C debería saber sobre el comportamiento indefinido»

Arch Linux ¡y Gnome3! sobre Virtual Box

Los que sigais este blog sabreis que ya publiqué esta guía antes. Pero como Arch Linux es una distribución muy volátil, que trata siempre de estar a la última, os dejo aquí una buena puesta al día de la Guía de Instalación de Arch Linux sobre Virtual Box cuya principal novedad es que incluye la instalación de GNOME 3.

  1. Arch Linux sobre Virtual Box 1/5: cubre las partes I y II, descripción y configuración de Virtual Box respectivamente.
  2. Arch Linux sobre Virtual Box 2/5: sólo la parte III. Trata de la instalación de Arch Linux.
  3. Arch Linux sobre Virtual Box 3/5: partes IV y V, primera ejecución y gestión de paquetes con pacman.
  4. Arch Linux sobre Virtual Box 4/5: parte VI, aplicación sudo y entorno de escritorio GNOME 3.
  5. Arch Linux sobre Virtual Box 5/5: parte VII, explicación de AUR, el gestor de paquetes yaourt y el entorno gráfico Awesome.

Teneis más información acerca de la instalación en la wiki de Arch Linux.

El lenguaje de programación C++: conclusiones sobre las referencias

En los últimos post, referencias y cuándo usar referencias, hemos hablado sobre esta construcción del lenguaje C++.

En C++ una referencia no es algo trivial como ocurre en Java o en C#. En C++ una referencia es otra herramienta junto con las variables y los punteros para gestionar la memoria.

Siguiendo con la idea original de realizar una crítica al libro de Stroustup… ¿qué podemos concluir? ¿se explica mal el texto? ¿resulta confuso o difícil de entender? A mi juicio, no. Todo está bastante claro.

Si bien, el único punto remarcable es el por qué sólo se permiten literales en referencias constantes. Acerca de esto, el texto de Stroustup, en el aparatado 5.5, afirma:

Las referencias a variables y las referencias constantes se diferencian debido a que la introducción de un temporal en el caso de la variable es altamente conducente a errores; una asignación a la variable se convertiría en una asignación al temporal, que desaparecerá próximamente. No existe dicho problema para las referencias a constantes, y las referencias a constantes suelen ser importantes como parámetros de función (…).

En mi opinión era más fácil explicarlo como un problema de incompatibilidad de tipos (los literales son const luego la referencia debe ser const) pero esto no es lo que Stroustup quiere decir con el párrafo anterior. De hecho, yo tardé bastante en entenderlo y no fue hasta mucho después, al final del aparatado 7.2, que me dieron un argumento para entenderlo:

La prohibición de las conversiones para parámetros por referencia no-const (…) evita la posibilidad de errores tontos derivados de la introducción de temporales. Por ejemplo:

void actualiza(float &i);

void g(double d, float r)
{
actualiza(2.0f);    // error: parámtro const
actualiza(r);       // pasa por referencia r
actualiza(d);       // error: se requiere conversión de tipos
}

Si se hubiesen permitido estas llamadas, actualiza() habría actualizado silenciosamente temporales que se borrarían inmediatamente. Habitualmente, esto sería una sorpresa desagradable para el programador.

El caso de actualiza(2.0f) hubiese resultado un tanto extraño.

¿Cómo narices actualizas un literal? Es más, ¿qué significa actualizar un literal?
O____O

Ahí la primera inconsistencia. El temporal se hubiese creado, hubiera tomado el valor 2.0 y luego podría haberse modificado en la función pero… ¿cómo se transmitiría ese cambio fuera de la función? Opino que lo más sencillo hubiera sido aludir a la incompatibilidad de tipos.

En el caso de actualiza(d), se hubiera creado el temporal e inicializado (por copia del valor, no enlace) con el valor de float(d). Luego la referencia i se hubiese enlazado con el temporal pero no con el parámetro d. Los accesos a i hubiesen resultado en accesos al temporal por lo que tras modificarse en el cuerpo de la función y destruirse al cabo de la misma, d habría quedado invariable.

¿Se podría haber solucionado de otra forma? ¿Es la introducción de temporales la mejor forma de lidiar con estas situaciones?

No lo sé, pero sí sé que la explicación por incompatibilidad de tipos era consistente y mucho más sencilla.

usuario ALL=ALL(ALL) ALL

¿Qué significa usuario ALL=ALL (ALL) ALL?  Esta línea es muy común en las configuraciones de Linux pero qué pinta tanto ALL y qué quiere decir son cosas que poca gente sabe.

Sudo es una aplicacion de Linux que permimte ejecutar comandos como si fuéramos otros usuarios, de hecho sudo viene de «substitute user do«. La configuración de sudo, es decir, qué podemos hacer como otros usuarios y dónde, se refleja en un archivo llamado sudoers normalmente situado en el directorio /etc aunque tal archivo sólo debería modificarse mediante la aplicación visudo.

La sintaxis del archivo sudoers no es complicada pero sí bastante extensa. Podeis leerla online en el enlace anterior o en vuestros equipos consultando el manual. Aquí, sólo voy a indicar qué significa la línea que da título al post:

La clave para leer la especificación de usuarios es saber qué significa cada parte. Podríamos resumirlo en:

fulanito, en ciertos equipos, puede ejecutar los siguientes comandos como si fuera menganito; o puede ejecutar estos otros como si fuera jaimito

Traducido a la sintaxis de sudoers:

fulanito ciertos_equipos=(menganito) comandos, (jaimito) estos_otros_comandos

En definitiva:

usuario hosts=(como_quién) qué_comandos [, (como_quién) otros_comandos]...

A veces, la coma se omite pues el paréntesis de apertura sirve como separador. Si el como_quien también, indica que nos referimos a nosotros mismos.

Así que cuando especificamos usuario ALL=ALL (ALL) ALL lo que estamos diciendo es:

usuario, en todos los equipos, puede ejecutar cualquier comando (siendo nosotros mismos) y todos los comandos como si fuera cualquier usuario

Y así de fácil es la cosa.

El lenguaje de programación C++: Declaraciones y One Definition Rule

El capítulo 4 del libro El Lenguaje de programación C++ versa sobre los tipos y declaraciones. Como comentaba ayer, ya en este capítulo se presentan algunos problemas al explicarnos características típicas de C++ como la conocida One Definition Rule o Regla de la Definición Única que resulta de especial interés para los más novatos y que al entenderla como se debería ahorra muchos dolores de cabeza derivados de la compilación separada de módulos.

Seguir leyendo «El lenguaje de programación C++: Declaraciones y One Definition Rule»

El lenguaje de programación C++ (versión comentada)

El lenguaje de programación C++ es un libro escrito por el creador de C++, Bjarne Stroustrup, en el que, según puede leerse en su contraportada:

El libro presenta el lenguaje C++ al completo: desde una visión global de sus conceptos y características básicas y su biblioteca estándar hasta todos los aspectos del diseño y desarrollo de tecnicas específicas de programación en C++.

No es que me entere ahora, por supuesto; de hecho, el libro lo adquirí en 2005 pero no ha sido hasta ahora que he decidido reconciliarme con C++ que lo he vuelto a abrir.

¿Y por qué reconciliarme con C++? Bueno, porque, sin lugar a dudas, se trata de un lenguaje importante y muy popular y bastante necesario para entrar en (por ejemplo) la industria del videojuego sin ir más lejos. Además, de utilizar Java, C# y Python le había cogido tirria a su sintáxis (de hecho, sigo pensando que es confusa y ambigua).

Llevo ya un par de capítulos del librito (son más de 1000 páginas) y conforme leo me convenzo más de mi juicio original. Aunque quizá también tenga que ver el cómo el señor Stroustrup nos enseña las distintas características del lenguaje, cometiendo contradicciones a cada página que no son más que montones de «excepciones a la regla» y vestigios de la «compatibilidad con C».

No obstante, para quien conozca C, el libro es un buen manual de programación y a lo largo de esta nueva serie voy a resaltar, comentar y tratar de corregir cada aspecto ambiguo o contradictorio que descubra en el libro por el bien del equilibrio mental de quienes, como yo, decidan seguir el camino de C++. Serán comentarios cortos, dónde se describirá un problema concreto y se tratará de arrojar luz sobre el mismo, para que sirvan de pequeñas lecciones individuales.

A favor del señor Stroustrup, de su lenguaje de programación y de su libro he de decir que cuanto más se sabe de C, peor se tiende a programar en C++ o mejor dicho, peor se aprovecha C++ tal y como él afirma diciendo:

Cuanto más C se sabe, más difícil parece evitar escribir C++ al estilo de C, prediendo por tanto algunos de los beneficioes potenciales de C++.

Como sé que C++ tiene un ejército de defensores, espero que haya movimiento en los comentarios. Una esperanza vana viendo la cantidad de visitas diarias pero oye, por intentarlo…

Bueno, primeras notas en el próximo post.

Arch Linux sobre Virtual Box 5/5

¿Que qué es AUR? Bueno, AUR es un concepto conocido entre los usuarios de Arch Linux pero es totalmente nuevo en este manual. Nuevo e interesante.

AUR significa Arch User Repository o Repositorio de Usuarios de Arch. Es aquí donde nacen los paquetes que serán incluidos en el repositorio [community] . Sin embargo AUR no contiene paquetes, es decir, no contiene archivos que puedan ser instalados mediante pacman sino que contiene archivos que son «esqueletos de paquetes» o «instrucciones para crear paquetes» llamados PKGBUILDs.

AUR está disponible via web para realizar búsquedas y descargar PKGBUILDs.

Interfaz web de AUR para la búsqueda y descarga de PKGBUILDs
Interfaz web de AUR para la búsqueda y descarga de PKGBUILDs.

Seguir leyendo «Arch Linux sobre Virtual Box 5/5»

Arch Linux sobre Virtual Box 4/5

Esta versión actualizada del artículo contiene cambios sustanciales respecto de las primeras versiones.

En este capítulo de la serie vamos a instalar dos aplicaciones:

  • sudo. Que nos permitirá ejecutar comandos como si fuéramos superusuarios.
  • GNOME3. La última versión del popular escritorio.

Seguir leyendo «Arch Linux sobre Virtual Box 4/5»