jueves, 9 de febrero de 2017

Eclipse como me gusta

Novateando con Eclipse Neon

Ok, ya van varias veces que intento usar Eclipse, pero a la fecha no nos hemos llevado demasiado bien.  Parece que las cosas van a mejorar, pero he tenido que configurar varias cosillas.
  1. Descargar e instalar Eclipse localmente.
    https://www.eclipse.org/downloads/
  2. Agregar el lanzador al menú de Xubuntu.
  3. Instalar CMakeEditor.  No se logra conectar a SourceForge, reportando un "handshake failure". 
    1. Hay que descargar el .zip de sourceforge directamente.
    2. Help->Install new software...->Add...->Archive->CMakeEd-1.3.0.zip
    3. Aparecerá la opción para instalar CMakeEd, seguir las instrucciones.
  4. Configurar a Eclipse para trabajar con mis proyectos que usan CMake.
    https://cmake.org/Wiki/CMake:Eclipse_UNIX_Tutorial
  5. Cambiarle la consola para poder imprimir a colores:
    • Instalar TM Terminal
    • Window->Preferences->Terminal->Local terminal
    • Sólo logro arrancarla con Ctrl+Alt+Shift+T porque si no abre la terminal de xubuntu, pero funciona.  Tampoco

jueves, 1 de diciembre de 2016

Kinect v2 en Linux con CUDA 7.5


  • Descargar los fuentes

$ git clone https://github.com/OpenKinect/libfreenect2.git
$ cd libfreenect2


  • Herramientas para compilar

$ sudo apt-get install build-essential cmake pkg-config

Dependencias

$ sudo apt-get install libusb-1.0-0-dev
$ sudo apt-get install libturbojpeg libjpeg-turbo8-dev
$ sudo apt-get install libglfw3-dev

Problema: OpenCL con beignet-dev elimina opencl de nvidia-opencl-dev => no instalar, instalar el de nvidia

Para generar la documentación es necesario tener también:

$ sudo apt-get install doxygen

de lo contrario se marcará el error:
-- Could NOT find Doxygen (missing:  DOXYGEN_EXECUTABLE)
al configurar con cmake.

  • Habilitar driver de nvidia

$ sudo apt-get install nvidia-cuda-toolkit

  • Descargar el .deb para Ubuntu 15.04 de la página oficial y extraer el .deb con los ejemplos (samples), sale un data.tar.gz, extraerlos de ahí e instalar ejemplos

[No recuerdo para qué utilizé la linea siguiente, pero en instalaciones siguientes no la he necesitado]
$ grep -rl "CUDA_PATH ?= /usr/local/cuda" ./ | xargs sed -i 's:CUDA_PATH ?= /usr/local/cuda:CUDA_PATH ?= /usr:g'


$ sudo apt-get install libva-dev libjpeg-dev
$ sudo apt-get install libopenni2-dev

No logreé que funcionara el código para OpenNI.

Build


  • Modificar en CMakeLists:

CUDA_INCLUDE_DIRECTORIES(
      "${MY_DIR}/include/"
      "[path_to]/CudaSamples/NVIDIA_CUDA-7.5_Samples/common/inc"    #"${CUDA_TOOLKIT_ROOT_DIR}/samples/common/inc"
      "${NVCUDASAMPLES_ROOT}/common/inc"
    )

$ mkdir compile
$ cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/Programacion/libfreenect2/build/freenect2 -DCUDA_NVCC_FLAGS="-D_FORCE_INLINES"
$ make
$ make install
$ make doc

Copiar las reglas de udev:

sudo cp platform/linux/udev/90-kinect2.rules /etc/udev/rules.d/

Probar con los demos, como Protonect, sí funciona.

OpenCV

$ sudo apt install libav-tools

$ cmake -D PYTHON3_INCLUDE_DIR=/usr/include/python3.5m -DPYTHON3_INCLUDE_DIR2=/usr/include/x86_64-linux-gnu/python3.5m -D PYTHON3_NUMPY_INCLUDE_DIRS=/home/blackzafiro/.local/lib/python3.5/site-packages/numpy/core/include -DINSTALL_PYTHON_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=/home/blackzafiro/Descargas/Programacion/opencv/opencv-3.1.0/build ..

OpenCV 3.1.0

Compilar versión estable

Cada vez que compilo OpenCV, configurarlo es todo un triunfo.  Pero uso muchas dependencias, por lo que mejor anoto aquí lo usual:

Aunque existe una página con el procedimiento y es útil pasar por ahí primero, aquí dejo mi acordeón.

Dependencias

libgtk-3-dev        ?
libgtk2.0-dev
libqt4-dev

libvtk6-dev
libopenni-dev

libav-tools
libavcodec-dev
libavformat-dev
libswscale-dev

libjpeg-dev
libpng-dev
libtiff-dev
libjasper-dev

libdc1394-22        # Caḿaras IEEE
libdc1394-22-dev

libtbb2             # Paralelismo
libtbb-dev

libgtkglext1-dev

python3-dev
python3-numpy
python-dev
python-numpy

nvidia-cuda-dev
nvidia-cuda-gdb
nvidia-cuda-toolkit

Configurar y compilar

Editar el archivo cmake/FindCUDA.cmake:

Cambiar la línea 711:

711 PATHS "/usr/lib/nvidia-current" "/usr/lib/nvidia-361"

de modo que la segunda dirección se la del driver de nvidia, donde se encuentra el archivo libnvcuvid.so.  Dara algunas advertencias, pero funciona como debe.

En la línea 799 insertar:

799 if(CUDA_VERSION VERSION_GREATER "7.0")

800   find_cuda_helper_libs(nvcuvid)

801 endif()
Otra opción es indicar el directorio de este archivo a cmake, como se indica a continuación.

$ mkdir compile
$ mkdir build
$ cd compile
$ cmake -DCMAKE_INSTALL_PREFIX=</home/...> -DWITH_OPENGL=ON -DWITH_QT=ON -DWITH_VTK=ON -DWITH_OPENNI=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCUDA_NVCC_FLAGS="-D_FORCE_INLINES" -D PYTHON3_INCLUDE_DIR=/usr/include/python3.5m -DINSTALL_PYTHON_EXAMPLES=ON -DCUDA_cublas_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcublas.so -DWITH_CUBLAS=ON -DWITH_NVCUVID=ON -DCUDA_nvcuvid_LIBRARY:FILEPATH=/usr/lib/nvidia-367/libnvcuvid.so ..

ó

$ cmake -DCUDA_NVCC_FLAGS="-D_FORCE_INLINES" -DCMAKE_INSTALL_PREFIX:PATH= -DWITH_IPP=ON -DWITH_CUBLAS=1 -DWITH_OPENGL=ON -DWITH_NVCUVID=ON ..
$ make -j 3
$ make install

Aparecerá una advertencia por haber agregado '/usr/lib/nvidia-367'.

Ojo: Qt y Vtk no se llevan, aunque puse ambas opciones arriba, elegir sólo una.

Con ffmpeg local

Para utilizar ffmpeg compilado localmente, antes de  realizar los pasos siguientes:
$ export LD_LIBRARY_PATH=/home/.../ffmpeg.../build/lib
$ export PKG_CONFIG_PATH=/home/.../lib/pkgconfig:$PKG_CONFIG_PATH
$ export PKG_CONFIG_LIBDIR=$PKG_CONFIG_LIBDIR:/home/.../build/lib

jueves, 7 de julio de 2016

Mi acordeón de git

Inicialización

Iniciar un repositorio localmente

$ git init
$ git remote add origin https://github.com/<username>/<repo>.git
$ git remote -v                 // verificar la liga
$ git push -u origin --all      // envía todo lo agregado localmente
Más detalles en Adding an existing project to GitHub using the command line

Clonar una bifurcación (fork)

$ git clone https://github.com/<username<repo>.git

Manipular los archicos

Agregar

$ git add .     // all
$ git add -u    // update
$ git add -A    // both

Remover

$ git rm --cached somefile.ext   // no remueve el archivo original
$ git rm --cached -r somedirectory
$ git rm --cached *~             // remueve archivos de respaldo

Borrar

$ git clean -f -d                // borra todos los archivos que no siga git

Manipular los repositorios

Encomendar (commit)

Registra en el repositorio local:
$ git commit -a -m "mensaje"     // agregar todo & commit
$ git commit -m "mensaje"        // sólo encomendar
$ git commit -m "mensaje" path/to/file.ext // encomendar un archivo

Empujar (Push)

Envía los datos al repo remoto:
$ git push

Ramas (branches)

$ git checkout -b branchname     // crear
$ git branck                     // ¿en qué rama me encuentro?
$ git checkout master

Solicitud de atracción (pull request)

Es cuando se solicita la fusión de ramas en Github.

viernes, 31 de octubre de 2014

Diagramas de clases y secuencia de KinectFusionBasics-D2D y KinectFusionExplorer-D2D

Tratando de comprender los demos de Microsoft, comienzo por hacer los diagramas de clases. ¿Quién es responsable de qué en KinectFusionBasics-D2D?

Sin embargo, al hacer el diagrama del KinectFusionExplorer-D2D, no estoy muy segura de haber ganado mucha información. Tal vez es un asunto de eficiencia, pero la cantidad de atributos y métodos en cada clase me parece impresionante, mientras que el número de clases es muy pequeño.  O tal vez este programa es más un asunto de programación estructurada que de orientación a objetos. Inclusive eliminando información dentro de cada clase, este diagrama no ofrece mayor información.

El siguiente paso ha sido crear los diagramas de secuencia, para ver qué lógica sigue el programa.  Trato de eliminar la información referente a la GUI y enfocarme en el manejo del Kinect y la reconstrucción de la superficie.  Los diagramas se toman algunas libertades, por ejemplo, se escribe el nombre del archivo que contiene a funciones independientes, donde se hubiera requerido el nombre de un objeto.

Al seguir la secuencia de ejecución desde la función de entrada int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) pareciera que el verdadero trabajo inicia con LRESULT CALLBACK CKinectFusionExplorer::MessageRouter.


El diagrama siguiente muestra lo que sucede cuando se ejecuta MessageRouter() y se está inicializando la aplicación.  Aquí aparece la creación al segundo hilo de ejecución, que menciona la documentación del demo.  La clase encargada de su creación y manejo es KinectFusionProcessor

Otros dos casos relevantes dentro de DlgProc() son cuando los mensajes son WM_FRAMEREADY y WM_UPDATESENSORSTATUS.  Este último caso es el más sencillo, pero refiere una llama al objeto de tipo NuiSensorChooserUI para actualizar parámetros del sensor.
Cuando el cuadro se encuentra listo, se muestran las imágenes correspondientes en pantalla y se actualizan los elementos de la interfaz que así lo requieran.

Segundo hilo

Aquí es donde realmente se realiza el procesamiento de la información del Kinect y la reconstrucción de la superficie.  La función enviada como parámetro al crear este hilo DWORD WINAPI KinectFusionProcessor::ThreadProc(LPVOID lpParameter), devuelve una referencia al método MainLoop() de la misma clase.  Aquí también hay un ciclo atendiendo eventos: fin del procesamiento, cuadro (de profundidad) siguiente y cambio de estado del sensor.  El diagrama siguiente ilustra qué hace esta función cuando se tiene disponible el siguiente cuadro.

Cada vez que es necesario reiniciar la reconstrucción del volumen, se manda llamar a la función HRESULT KinectFusionProcessor::RecreateVolume().  El diagrama siguiente ilustra la secuencia principal de llamadas.

Por último, la parte más pesada del procesamiento se encuentra en la función void KinectFusionProcessor::ProcessDepth().  Me interesa especialmente la reconstrucción con captura de color, por lo que sigo esa línea de ejecución.

Como se puede ver, esta es la función encargada de llamar a todas las demás funciones que realizan alguna parte del procesamiento.  Una vez alcanzado este punto ya es mucho más natural saber qué función realiza qué tarea y en qué orden.

Sincronización de hilos

Existen regiones críticas en las que se modifica el valor de variables, que deben se bloqueadas antes de re-escribirlas (las solicitudes para realizar estos bloqueos fueron ilustradas en los diagramas de secuencia de arriba).  Para los bloqueos se definen tres candados: m_lockParams, m_lockFrame y m_lockVolume.

Varias funciones dentro de KinectFusionProcessor revisan si fueron llamadas desde el segundo hilo creado o desde otro hilo.  Para ello utilizan el valor del atributo m_threadId, cuyo valor es asignado al crear el hilo con la llamada a la función CreateThread.

Las funciones que solicitan ser llamadas desde su propio hilo (segundo hilo creado, (AssertOwnThread())), se encargan del manejo del Kinect y el procesamiento de la información recibida.  Estas son:
  • MainLoop()
  • ShutdownSensor()
  • CreateFirstConnected()
  • InitializeKinectFusion()
  • RecreateVolume()
  • CopyExtendedDepth(NUI_IMAGE_FRAME &imageFrame)
  • ProcessDepth()
  • UpdateCameraPoseFinder()
  • StoreImageToFrameBuffer(const NUI_FUSION_IMAGE_FRAME* imageFrame, BYTE* buffer)
  • InternalResetReconstruction()
  • SetStatusMessage(WCHAR * szMessage)
  • NotifyFrameReady()
  • NotifyEmptyFrame()
Las funciones que solicitan ser llamadas desde otro hilo (AssertOtherThread()), reciben información desde la interfaz de usuario y almacenan los valores correspondientes en los atributos que podrá revisar el hilo encargado del procesamiento.  Antes y después de asignar estos valores, deben solicitar la aplicación de los candados correspondiente.  Estas funciones son:
  • ~KinectFusionProcessor()
  • StartProcessing(): Crea el segundo hilo.
  • StopProcessing()
  • ResolveSensorConflict()
  • IsVolumeInitialized()
  • SetWindow(HWND hWnd, UINT msgFrameReady, UINT msgUpdateSensorStatus)
  • SetParams(const KinectFusionParams& params)
  • LockFrame(KinectFusionProcessorFrame const** ppFrame)
  • UnlockFrame()
  • ResetReconstruction(): Llamada cuando el usuario selecciona alguna opción en la interfaz que provoca que se reinicie la reconstrucción.
  • CalculateMesh(INuiFusionColorMesh** ppMesh)

martes, 28 de octubre de 2014

Hola mundo Kinect con wxWidgets

Como paso inicial para un proyecto de visión por computadora, fue necesario separar claramente el código que controla el Kinect en DepthBasics-D2D © Microsoft, del código de la interfaz gráfica, que utiliza las Microsoft Foundation Classes (MFC). Con este objetivo, creé un pequeño programa que utiliza wxWidgets, el Kinect Developer Toolkit y Kinect SDK con los drivers oficiales para controlar el Kinect, que pueden ser descargados gratuitamente del sitio de Microsoft. Este programa únicamente lee la información de profundidad y la muestra en pantalla, manteniendo al mínimo el código requerido. La conexión al Kinect y lectura de información se realizan dentro de la clase definida en el archivo KinectManager.h. Las otras clases se encargan de crear y manejar la interfaz gráfica. Como wxWidgets requiere, se utiliza un timer para generar eventos que obliguen al programa a leer la información del Kinect. El proyecto de Visual Studio 2012 (Express) puede ser descargado de aquí.

domingo, 6 de julio de 2014

Cómo crear TabControl en CEGUI sólo con el archivo .layout

CEGUI incluye un buen ejemplo de cómo utilizar el TabControl, sin embargo require código.  Si se desea crear todas las pestañas con un .layout no hay instrucciones a la vista.  El orden correcto para insertar los elementos es:
<Window type="TaharezLook/TabControl" name="TabControl" >
           <Property name="TooltipText" value="This is the tab control" />
           <Property name="TabHeight" value="{0,-1}" />
           <Property name="MaxSize" value="{{1,0},{1,0}}" />
           <Property name="TabPanePosition" value="Top" />
           <Property name="Area" value="{{0.5,0},{0.15,0},{0.95,0},{0.95,0}}" />
           <Window name="PageArmor" type="TaharezLook/TabButtonPane">
                <Property name="Area" value="{{0.05,0},{0.05,0},{0.95,0},{0.95,0}}" />
                <Property name="Text" value="Armadura" />
           </Window>
           <Window name="PageItems" type="TaharezLook/TabButtonPane">
                <Property name="Area" value="{{0.05,0},{0.05,0},{0.95,0},{0.95,0}}" />
                <Property name="Text" value="Artículos" />
           </Window>
           <Window name="PageSkills" type="TaharezLook/TabButtonPane">
                <Property name="Area" value="{{0.05,0},{0.05,0},{0.95,0},{0.95,0}}" />
                <Property name="Text" value="Habilidades" />
           </Window>
</Window>
Ahora sí, dentro del TabButtonPane se puede incluir cualquier elemento que se necesite en el panel de esa pestaña.

sábado, 28 de junio de 2014

Cómo compilar CEGUI 8.3 con Ogre 1.9 localmente en linux

Compilar Ogre

Después de pelearme con la instalación de apt-get en Debian, he terminado por compilarlo desde la fuente.
  1. Instalar los Prerrequisitos. (Aguas con nvidia-cg-toolkit, si ya estaba instalado, tener cuidado de no arruinar lo que ya estaba, asegurarse de que todos los elementos de nvidia tengan la misma versión el comando nvidia-smi falla si hay inconsistencias, se puede usar para probar).
  2. En esta ocación me tocó descargar el código del repo en Mercurial, por lo que tuve que instalar la herramienta para crear el clon:sudo apt-get install hgsvn
  3. Se crea el clon con:
    hg clone https://bitbucket.org/sinbad/ogre
  4. cd ogre
    mkdir build
    mkdir compile
    cd compile
  5. cmake -D CMAKE_INSTALL_PREFIX=[/home/.../ogre/build/] ..
    make                  # Se puede usar make -j2 si el procesador tiene dos nucleos
    make install
  6. Intentar correr algunos ejemplos.Para ejecutar las aplicaciones, es necesario indicar dónde se encuentran las bibliotecas (dado que instalé en un directorio inusual).
    export LD_LIBRARY_PATH=/home/.../ogre/build/lib:$LD_LIBRARY_PATH
    Para no repetir este paso cada vez que se abre una terminal, se puede agregar esta línea al final del archivo ~/.bashrc. Ejecutar:
    ./SampleBrowser
  7. Si aparece el error
    terminate called after throwing an instance of 'std::runtime_error'
    what(): locale::facet::_S_create_c_locale name not valid
    Instalar:
    sudo apt-get install locales
    sudo dpkg-reconfigure locales   # Seleccionar alguno en inglés, aunque se puede dejar el español como locale por defecto

Compilar CEGUI

CEGUI utiliza cmake para encontrar una instalación a nivel sistema de Ogre, por lo que hay que indicar dónde encontrar los archivos que dicen dónde está y qué necesita Ogre.  Además, FindFreetype.cmake tiene un error.

  1. Primero hay que arreglar FindFreetype.cmake como se indica en https://bbs.archlinux.org/viewtopic.php?id=174300, para evitar el error:
    CEGUI was compiled without freetype support
  2. Luego, al utilizar cmake para compilar CEGUI se indica la ubicación de ogre:
    cd <CEGUI directory>
    mkdir compile
    mkdir build
    cd compile
    cmake -D CMAKE_INSTALL_PREFIX=/home/../cegui-0.8.3/build -D OGRE_HOME=/home/.../ogre/build ..
    make
    make install

CEGUI 0.8.4

En esta versión es necesario agregar específicamente en qué directorios se encuentran las bibliotecas de Ogre.  Afortunadamente lo indica con:

-- Could NOT find OGRE (missing:  OGRE_LIB)

La secuencia de comandos queda entonces:
cd <CEGUI directory>
mkdir compile
mkdir build
cd compile
cmake -D CMAKE_INSTALL_PREFIX=/home/../cegui-0.8.4/build -D OGRE_HOME=/home/.../ogre/build -D OGRE_LIB=/home/.../ogre/build/lib/libOgreMain.so ..
make
make install


lunes, 23 de junio de 2014

Cómo utilizar SmallCaps en latex, con fuente SansSerif

En varias ocasiones se me ha indicado que es mejor escribir mis reportes con un tipo de letra SansSerif, utilizando:

\renewcommand{\familydefault}{\sfdefault} % Mucha gente considera que las fuentes tipo sans son más fáciles de leer.
\renewcommand*{\sfdefault}{cmss}

Sin embargo cuando combino esto con títulos en SmallCaps inmediatamente surge el error:

Font shape `OTI/cms/m/sc'

ó, si no uso cmss:

Font shape `OTI/lmss/m/sc' in size <10.95> not available(Font) Font shape `OTI/lmr/m/sc' tried instead on input line...

Existen dos formas sencillas para resolverlo:
La primera es utilizar la fuente Helvetica.

\usepackage{Helvetic}

Sin embargo, a mí me agrada más utilizar lmss o cms para el texto.  Si sólo quiero cambiar de fuente para conseguir el efecto SmallCaps, la solución es redefinir únicamente el comando para este estilo, utilizando Helvetica (phv):

\usepackage{letltxmacro}
\LetLtxMacro{\oldtextsc}{\textsc}
\renewcommand{\textsc}[1]{{\fontfamily{phv}\selectfont\oldtextsc{#1}}} % Usa Helvetica para las small caps, ya que cmss no tiene esa opción.

jueves, 29 de enero de 2009

Java Sun en Ubuntu

Es trivial, pero hay que conocer los comandos:

sudo apt-get install sun-java6-jdk (para desarrolladores)
sudo apt-get install sun-java6-jre (si sólo se quiere ejecutar la JVM)
sudo apt-get install sun-java6-bin (no es necesario si se usó el primero)

Ahora, para que ésta sea la versión que se ejecuta por defecto [2]:

sudo update-alternatives --config java
sudo update-alternatives --config keytool

Resuelve:

Signing Key Creation: keytool error: java.lang.IllegalArgumentException: java.io.IOException: Invalid char:

[1] Ya no me acuerdo :(
[2] http://groups.google.com/group/android-developers/browse_thread/thread/398b4bedaaa3df3d

miércoles, 27 de febrero de 2008

Actualizando Glut

¡Hey! Esto sí está lejos de ser una solución oficial, pero funciona suficientemente bien.

Resulta que algunas personas hemos intentado utilizar la vieja biblioteca GLUT con versiones actuales del Visual Studio, díganse, 2003, 2005 o 2008. En el momento en el que uno intenta compilar alguna aplicación que dependa de GLUT, aparece el siguiente error:

c:\program files\microsoft visual studio 9.0\vc\include\stdlib.h(371) : error C2381: 'exit' : nueva definición; __declspec(noreturn) es diferente
c:\documents and settings\...\gl\glut.h(146) : vea la declaración de 'exit'

o una versión en inglés:

C:\Program Files\Microsoft Visual Studio 9.0\VC\include\stdlib.h(371) : error C2381: 'exit' : redefinition; __declspec(noreturn) differs
c:\Documents and Settings\Owner\Desktop\FG WIN32 compile\3rdparty\include\GL/glut.h(146) : see declaration of 'exit'

Bueno, resulta que algunas definiciones en stdlib.h han sido actualizadas.

Lo primero que se me ocurrió fue recompilar GLUT, bajándo el código fuente de la liga citada arriba, sin embargo, apareció el mismo error, acompañado de otras advertencias. La solución es simple, hay que modificar la línea 146 de glut.h:

Cambiar:
extern _CRTIMP void __cdecl exit(int);

Por:
extern _CRTIMP __declspec(noreturn) void __cdecl exit(int);

Con esto, en lugar de error, se obtendrá otra advertencia, pero las aplicaciones compilan y corren. (También aparece el error de que no logra instalar glut.lib y glut.h en los directorios indicados, que son del visual studio viejo, pero es pecata minuta, en el peor de los casos se pueden copiar a mano.) Sospecho que incluso basta con hacer esta modificación en glut.h y no es necesario recompilar toda la biblioteca.

Sin embargo ojo, al compilar la biblioteca recuerdo haber visto inclusive advertencias sobre funciones deprecadas, por lo que puede que este parche no dure mucho y haya que hacer una revisión más cuidadosa de glut.

martes, 19 de febrero de 2008

Mesa OpenGL - cannot restore segment prot after reloc

Descargué y compilé Mesa en mi directorio local y quise usarlo localmente, para no afectar lo que ya tenía instalado en el sistema. Todo iba perfecto, hasta que intenté ejecutar uno de los ejemplos: ./gears, tal y como indican las instrucciones bajo "Running the demos". El error que apareció fue el siguiente:

./gears: error while loading shared libraries: /home/[...]/Mesa-7.0.2/lib/libGL.so.1: cannot restore segment prot after reloc: Permission denied

No fue difícil encontrar en la red que este error se debe a SELinux. Lo que tomó un poco más fue encontrar cómo repararlo y resultó extremadamente sencillo. Entrando al directorio lib/ de Mesa, se modifica el contexto de las bibliotecas con el comando siguiente:

chcon -t texrel_shlib_t *.so

Al utilizar ls -lZ, podremos ver el nuevo contexto de las bibliotecas:

lrwxrwxrwx _______ _______ user_u:object_r:user_home_t libGL.so -> libGL.so.1
lrwxrwxrwx _______ _______ user_u:object_r:user_home_t libGL.so.1 -> libGL.so.1.5.070002
-rwxrwxr-x _______ _______ user_u:object_r:textrel_shlib_t libGL.so.1.5.070002
lrwxrwxrwx _______ _______ user_u:object_r:user_home_t libGLU.so -> libGLU.so.1
lrwxrwxrwx _______ _______ user_u:object_r:user_home_t libGLU.so.1 -> libGLU.so.1.3.070002
-rwxrwxr-x _______ _______ user_u:object_r:textrel_shlib_t libGLU.so.1.3.070002
...
Después de esto las bibliotecas recién compiladas de Mesa pueden ser utilizadas asignando la variable de ambiente LD_LIBRARY_PATH, tal y como se indica.

miércoles, 30 de enero de 2008

Páginas centradas con divs y css

¡Al fin lo logré!

Después de una cantidad increíble de intentos he encontrado dos formas verdaderamente sencillas de hacer páginas centradas.

El caso más trivial es cuando el tamaño del contenido es variable, como en esta página. Aquí basta con poner un margen simétrico para body:
body { padding-right: 30%, padding-left: 30%}
Puede hacerse con porcentajes o pixeles. No recuerdo si funciona igual con magin, para el caso, el problema está resuelto.

El problema se vuelve algo más complicado si lo que se quiere centrar tiene un ancho fijo. Este blog tiene esa propiedad, aunque no encontré entre todo el css una forma clara de cómo lo lograron. Encontré la mía. Funciona perfectamente en Firefox (linux y windows) pero desafortunademente, por alguna ilógica razón, alinea a la derecha en IE. El sitio resultante se encontrará aquí.

Se requiere crear dos divs (y un tercero por simetría). La primera funciona como una especie de marco, se usará para calcular el centro de la pantalla; la otra es para el contenido. La tercera es para rellenar el espacio vacío a la derecha. Algunos navegadores pueden pintar esta mitad de otro color si no se la rellena con algo.

El html deberá quedar así:
<body>
<div id="izquieda">
<div id="centro"> ...
</div>
</div>
<div id="der"/>
</div>
</body>
El css correspondiente es:
body { background:black; color:cyan; padding: 0px; margin: 0px;  font-family:arial; }
#izquierda { padding: 0; margin: 0; width:50%; position:relative; left:374px; }
#centro { padding: 0; margin: 0; float:right; width:748px; }
#der { padding: 0; margin: 0; float:right; }
Todos los margin y padding igual a cero están ahí porque no quiero márgenes, en otros diseños alguien podría querer experimentar con otros valores.

Ahora veamos porqué funciona:

Nótese que se desea que la región central mida 748 pixels. Con izquierda, al 50% de ancho, se obtiene la mitad de la pantalla. Ahora, lo que uno querría es utilizar la coordenada del centro de la pantalla para calcular e indicar alguna de las esquinas de la región central. Prové con varias combinaciones, pero la única que funcionó fue esta:

Con float:right, el lado derecho de la región central es alineada con el lado derecho de "izquierda", que se encuentra a la mitad de la pantalla. Lo que resta, es recorrerla 374 pixeles más a la derecha (la mitad de su tamaño). Sin embargo, los navegadores no entienden la petición si las cosas se salen de sus nodos padres. Por ello la solución fue empujar la región izquierda esta cantidad. Concecuentemente, su borde derecho se recorre y la región "centro" queda, efectivamente, en el centro.

jueves, 4 de octubre de 2007

Django, mod_python y SELinux

Hoy pasé algunas horas buscando una forma fácil de configurar mis aplicaciones de Django con Apache. Algo que me permitiera agregar aplicaciones sencillas y mantenerlas funcionando como si fueran scripts de php.

Lo más sencillo fue usar mod_python. Mi Apache ya lo cargaba y las instrucciones en la documentación de Django son claras. Como me agrada usar anfitriones virtuales, basta tener:


ServerName midominio.net
DocumentRoot /var/www/html

MaxRequestsPerChild 1 #Sólo para pruebas, si no es una grosería.

ServerName subdominio.dominio.net

SetHandler python-program
PythonHandler django.core.handlers.modpython
PythonPath "['camino_a_un_directorio_arriba_del_proyecto', 'camino_uno_arriba_de_las_aplicaciones'] + sys.path"
SetEnv DJANGO_SETTINGS_MODULE [proyecto].settings
PythonDebug On


SetHandler None


SetHandler None



La parte truculenta vino de SELinux. Los proyectos de Django (y sus aplicaciones) no deben ir en la ruta de Apache, lo cual lo hace especialmente seguros. Sin embargo, al tener mis archivos, inocentemente, en algún profundo lugar de mi hogar, aunque agregara el directorio con PythonPath, me aparecía un error indicando que el módulo [proyecto].seetings no existía:

EnvironmentError: Could not import settings '____.settings'
(Is it on sys.path? Does it have syntax errors?): No module named wap.settings

El verdadero problema es que, no sólo apache debe tener los permisos normales de lectura, sino que toda la ruta hasta el proyecto (y todos los archivos de éste) deben tener el contexto para la web:

user_u:object_r:httpd_sys_content_t

Copiar mis archivos a un directorio en el que pudiera otorgar dichos permisos con

$ chcon -R user_u:object_r:httpd_sys_content_t [directorio]

resolvió el problema.

martes, 24 de julio de 2007

Script que obtiene el nombre del día de ayer

Por increíble que parezca, este ejemplo no es una ociosidad, lo utilicé el vida real para nombrar carpetas de archivos de respaldo:



#!/bin/bash
# +++++++++
# Calcula el dia de ayer.
# +++++++++

#
# Obtiene el nombre del dia de la semana almacenado en $NDIA.
#
getDia () {
case $1 in
1) DIA=lunes ;;
2) DIA=martes ;;
3) DIA=miercoles ;;
4) DIA=jueves ;;
5) DIA=viernes ;;
6) DIA=sabado ;;
7) DIA=domingo ;;
*) echo "$1 No es un dia de la semana valido"
exit $DIA_MAL
;;
esac
}

NDIA=`date +%u`
getDia $NDIA
echo Hoy es $DIA

let "NAYER=$NDIA - 1"
if [ $NAYER -eq 0 ]
then
NAYER=7
fi
getDia $NAYER
echo Ayer fue $DIA

sábado, 19 de mayo de 2007

Capturas de pantalla - VLC

Dejo esto como un recordatorio:
* Tomado en parte del FAQ de VLC

Para poder tomar capturas de un video en ejecución se require:
(Linux)
  1. Iniciar con vlc -V x11
  2. Seleccionar Opciones -> Preferencias... En la pestaña Video, inidicar el directorio y el formato donde se guardarán las imágenes y el formato.
  3. Presionar "Captura de pantalla" cada vez que quiera :)
Si no se cumple el paso 1, los otros dos no bastan, no se guarda nada. Sin embargo, tampoco es recomendable dejar vlc con -V x11 por defecto, pues la reproducción pierde calidad.

jueves, 12 de abril de 2007

MVC. Datos, lógica y vista.

Las vistas no tienen objetos, los objetos tienen forma de ser vistos.

Llevo un rato tratando de programar un manejador de contenido para páginas en la red. No es la primera vez que intento separar las tres famosas capas "datos, lógica y vista". Tradicionalmente, o al menos eso entendí en ingeniería de software, la capa de lógica se monta sobre la de los datos, y la vista sobre ésta. Sin embargo, surge de modo más natural escribir en los objetos cómo se ven estos, en lugar de tener una vista genérica que pueda mostrar a cualquier objeto y creo que la razón es sencilla: la forma en que se ven los objetos depende de sus propiedades. Entonces, una de dos, o no he logrado entender el concepto de las tres capas, o algo está chueco en su concepción. ¿Cómo puedo separar la presentación? Es claro que, el cómo se ve una cosa depende fundamentalmente de qué tipo de atributos tiene; si no conozco sus atributos y más aún, la semántica de esos atributos, es imposible que decida cómo debe verse.

En todo caso, se me ocurre que la idea de que las tres capas son independientes en, realidad, una falasia. A lo más, pensándolo como una pila, le concedo que la capa de datos sea independiente, ésta no requiere ser modificada si hay cambios en la lógica (control), ni en la vista. Pero a la inversa en ningún modo se cumple, por el contrario, si modifico el modelo, debo modificar la lógica que lo controla y la forma en que se ve. En el siguiente nivel: si modifico en control, lo más seguro es que tenga que modificar la vista. Por último, puedo modificar la vista (la puritita presentación gráfica, auditiva, etc.) sin tocar el control, ni el modelo.


Tal vez alguien más familiar con la técnica me diga ¡felicidades! ¡acabas de entender cómo se hace el hilo negro!

Sin embargo toda esta preocupación surge de un caso muy concreto: la intefaz de administración de django. Leyendo entre los correos de usuarios y desarrolladores, hay cierta molestia por el hecho de que el código que define la presentación en la administración está dentro de los modelos, siendo que estas dos capas no debieran trabar contacto.

El problema, como he llegado a verlo, es que los modelos (tablas en una base de datos) no representan más que una manera de hacer persistentes a los objetos, pero las bases de datos no pueden incluir toda la lógica de sus interacciones, ésta en realidad se mantiene en la capa siguiente (gracias al artículo de la Wikipedia). El problema es que ¿quién puede saber de antemano lo que será puesto en la capa lógica? Las implementaciones en las bases de datos limitan claramente qué puede ser almacenado ahí (tipos de datos, relaciones, etc.), pero en la lógica uno puede escribir prácticamente lo que sea. ¿Cómo podría entonces crearse una vista genérica, sin descender a los modelos?

Peor aún, y aquí viene mi muy particular dilema: ¿qué pasa cuando uno requiere hacer persistente cómo se ven los objetos? Es decir, que la forma en que los modelos son vistos en pantalla, también forma parte de los datos. ¿Cómo mantener aquí la consistencia sin que la capa lógica se convierta en una locura?

Por el momento intento que cada nuevo elemento contenga 3 cosas: su propia forma de ser persistido, su lógica y ... opciones para ser visto pero... éstas son las que ya me cuesta más trabajo definir en una manera consistente para todos los elementos (evitando abundar en los códigos especializados a cada caso), esto debe ser lo más general posible.

Me gustaría que los elementos que están contenidos dentro de otros simplemente extendiesen la presentación de sus contenedores, como funcionan los css y evitando persistir la información de la presentación en los mismos modelos (tablas) que el contenido en sí del objeto. De modo que, hasta donde voy ahora... mi modelo parece quedar igual que la administración de django: el objeto tiene la liga a "cómo se ve". ¿pero qué no es eso lo natural? ¿que las cosas tengan una apariencia y no la apariencia a las cosas?

miércoles, 4 de abril de 2007

Juegos II y pygtk

Se me ocurrió actualizar python, pasándome a la versión 2.5. Obvio, tuve que reinstalar todo lo que ya tenía :( django, psycopg, etc., etc. y pygame!

Siguiendo el procedimiento de Juegos I, ahora debí bajar Numeric, ojo, debe ser el viejito (el del 2005), Numpy no satisface los requerimientos.

También hubo que reinstalar OpenGL y pygtk. Este último fue el más problemático: hubo que instalar un nuevo pyobject, en Fedora 5, éste quedó en /usr/local/lib/python2.5/site-packages/gtk-2.0/gobject pero al hacerlo aún detectaba la versión anterior (Requested 'pygobject-2.0 >= 2.12.1' but version of PyGObject is 2.8.4). Tal parece que esto es porque no se instaló como biblioteca del sistema, de hecho, al instalar, aparece el siguiente mensaje:

/usr/bin/install -c -m 644 'pygobject.h' '/usr/local/include/pygtk-2.0/pygobject.h'
...
----------------------------------------------------------------------
Libraries have been installed in:
/usr/local/lib/python2.5/site-packages/gtk-2.0/gobject
...
----------------------------------------------------------------------

configure usa libtool, por lo que debe bastar con indicarle este directorio de alguna manera.

Entonces, antes de invocar .configure, intento exportar las variables:

# export PYGOBJECT_CFLAGS="-I/usr/local/include/pygtk-2.0/"
# export PYGOBJECT_LIBS=/usr/local/lib/python2.5/site-packages/gtk-2.0/gobject

Pero aún falta pycairo (intenté compilar sin él, pero sigue habiendo errores).
Con cairo es la misma historia: compilo e instalo cairo 1.4.2 y queda en:

----------------------------------------------------------------------
Libraries have been installed in:
/usr/local/lib
...
----------------------------------------------------------------------
/usr/bin/install -c -m 644 'cairo.h' '/usr/local/include/cairo/cairo.h'
...

Así que, para pycairo asigno:
# export CAIRO_CFLAGS="-I/usr/local/include/cairo"
# export CAIRO_LIBS="-I/usr/local/lib"

Y sigo las instrucciones de instalación... Dice que sí... ¡pero pygtk sigue sin funcionar! Y ya me cansé... me voy a dormir y ya mañana veo.

martes, 6 de marzo de 2007

Django con Fast-Cgi II

Después de varios intentos, logré configurar Django para ser servido a trevés de un vhost de Apache y FastCGI.

Primero, el proyecto de Django existe en algún lugar de mi PC, fuera del camino de Apache y sin preocuparse por su existencia. Se utiliza:

python manage.py runfcgi daemonize=true method=threaded host=$FCGIHOST port=$FCGIPORT pidfile=$FCGIPIDFILE

para ejecutar el servidor FastCGI.

Para versiones anteriores de Apache, basta con bajar mod_fastcgi del sitio de FastCgi, pero para Apache 2.2, hay que parchar el código. Craic ofrece una muy buena guía para arreglar el mod_fastcgi.c:271: error: 'ap_null_cleanup' undeclared (first use in this function) que aparece al intentar compilar.

Después de haber instalado mod_fastcgi, dentro de http.conf coloqué las siguientes indicaciones:

# Al final de los módulos a incluir:

LoadModule fastcgi_module modules/mod_fastcgi.so

# Fastcgi va después de estas líneas

User apache
Group apache
<IfModule mod_fastcgi.c>
FastCgiIpcDir /tmp/fcgi_ipc/
AddHandler fastcgi-script .fcgi

# Servidor externo para usar django con fastcgi.
FastCGIExternalServer /var/www/fastcgi/fastcgi.fcgi -host 127.0.0.1:3033

# En Apache 2.2 es necesario especificar permisos de acceso.
<Directory "/usr/local/apache2/fastcgi">
Order allow,deny
Allow from all
</Directory>
</IfModule>

Como (por motivos particulares de mi proyecto) quiero acceder a FastCGI desde diferentes vhosts hice que FastCGIExternalServer apunta a alguna dirección neutra, en este caso /var/www/fastcgi/fastcgi.fcgi.

Dentro de la configuración de vhost indico:


DocumentRoot "/sudomain_path/dynamic_docs"
Options +FollowSymLinks

RewriteEngine On
#Todas aquellas direcciones, menos '/', que no correspondan a un archivo en disco, serán atendidas por el servidor FastCGI.

RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -!f #Si el archivo estático existe en DocumentRoot, se sirve ese.
RewriteCond %{REQUEST_URI} !(/var/www/fastcgi/fastcgi.fcgi) #El 'pseudo archivo' de FastCGI.
RewriteCond %{REQUEST_URI} !(/media) #No quiero que FastCGI sirva imágenes, css, etc.
RewriteCond %{REQUEST_URI} !(/static) #Un lugar para httpdocs :)
RewriteRule ^/(.+)$ /var/www/fastcgi/fastcgi.fcgi/$1 [QSA,L] #Ojo: '/' no es para FastCGI, así preservo index como valor por defecto estático. Si quiero que django sirva '/' también, uso RewriteRule ^(.+)$ /var/www/fastcgi.fcgi$1 [QSA,L]

Alias "/static" "/subdomain_path/httpdocs"
<Directory subdomain_path/httpdocs>
# Aquí insisto en usar scripts de python dentro de httpdocs. Sólo si el archivo acaba en .py :)
<IfModule mod_python.c>
<Files ~ (\.py$)>
SetHandler python-program
PythonHandler mod_python.publisher
</Files>
</IfModule>
</Directory>

Demasiados semáforos

Hoy Apache murió súbitamente cuando intenté configurar algunas cosas que ya había modificado antes. Obtuve:

[emerg] (28)No space left on device: Couldn't create accept lock

Seguido de algunos errores más. Afortunadamente la solución estaba a la mano: Apache había sobrepoblado al sistema de semáforos. Aún me pregunto porqué hizo tantos. La parte importante es utilizar:

[]$ for semid in `ipcs -s | grep apache | cut -f2 -d" "`; do ipcrm -s $semid; done

Cuando apache ya no esté siendo ejecutado, para eliminar a los semáforos fantasmas.