martes, 26 de febrero de 2019

Configuraciòn de Combinacion de Teclas en Ubuntu Mate

El sistema operativo que utilizo desde hace 4 años, es el GNU/Linux Ubuntu Mate. Lo he elegido y aùn sigo un firme usuario de este sistema por su simplicidad, practicidad y eficiencia.

Obviamente este sistema operativo trae consigo mismo todas las ventajas del GNU/Linux Debian. Con respecto a las caracterìsticas relacionadas con el entorno de escritorio, Mate es una versiòn ligera del Gnome 2 optimizada para lograr un sistema operativo sencillo y funcional.

Entre las caracterìsticas del entorno de escritorio, una que utilizo muy a menudo, son las Combinaciones de Teclas personalizadas. Las mismas se podrìan configurar de infinitas maneras para realizar cualquier tipo de tarea tanto en el entorno de escritorio asì como tambien en otros àmbitos del sistema operativo mediante accesos directos por vìa de estas combinaciones de teclas que ejecutan lineas de comandos, scripts etc.

Cuando estoy programando un nuevo modulo QtQuick en QML para Unik, independientemente para cuàl o para què sistema sistema operativo sea la aplicaciòn final, la gran mayorìa del còdigo lo puedo programar utilizando VIM y ejecutando Unik desde este Ubuntu Mate que generalmente utilizamos.

El ùnico cambio que debo realizar para ganar tiempo y productividad, es modificar la funcionalidad de la combinaciòn de teclas para ejecutar Unik de tal modo que cargue y ejecute el còdigo fuente QML que estoy editando.

Por ejemplo si estoy programando un proyecto que està en la carpeta /home/nextsigner/miApp y allì se encuentra el archivo main.qml, para ir modificando el còdigo e ir viendo los cambios al instante, en principio debo ir al Menu->Sistema->Centro de Control->Combinaciòn de Teclas y allì crear un nuevo item de combinaciòn de teclas perzonalidas que ejecute Unik con el paràmetro -folder=/home/nextsigner/miApp para que Unik funcione sobre dicha carpeta.

El problema es que hay modulos QML para Unik a los cuales les dedico un par de horas diarias, a otros les dedico 1 o 2 semanas seguidas y voy saltando de un proyecto a otro, ya sea que estoy creando mòdulos nuevos u optimizando otro. Entonces cada vez que quiero comenzar a editar un mòdulo debo ir a la secciòn de Centro de Control mencionada para cambiar la carpeta en donde Unik debe buscar còdigo QML cuando es llamado mediante el acceso ràpido por medio de la combinaciòn de teclas.

Por lo general la combinaciòn que prefiero utilizar el Shift+Crtl+r . La letra "r" es por RUN.

Para hacer todo el cambio de la manera màs ràpida posible, lo que he creado es un script Bash que estè preparado para cambiar una combinaciòn de tecla en el entorno MATE.

Atenciòn! El siguiente script està orientado solo para el entorno MATE.

Archivo ct.sh //CT significarìa Combinaciòn de Tecla

#!/bin/bash
dconf write /org/mate/desktop/keybindings/custom0/action "'$1'"
dconf write /org/mate/desktop/keybindings/custom0/command "'$1'"
dconf write /org/mate/desktop/keybindings/custom0/binding "'$2'"
dconf write /org/mate/desktop/keybindings/custom0/name "'$1'"

Explicaciòn de uso

Este script requiere 2 paràmetros. Ambos deben estar escritos entre comillas simples.

  1. Lìnea de Comando que deseamos ejecutar.
  2. Combinaciòn de Teclas 

Ejemplo

Como usuario comùn, no es necesario ejecutar con privilegios de administrador, si ejecutamos el siguiente comando.

$: ct.sh 'unik -folder=/home/nextsigner/miApp' '<Shift><Ctrl>r'

En este caso, si presionamos las teclas Control màs Shift màs r, Unik se ejecutarà cargando còdigo QML desde la carpeta /home/nextsigner/miApp

En cambio si queremos utilizar el script ct.sh para otro fìn, por ejemplo ejecutar nuestro navegador web en un sitio espacìfico al iniciar, la lìnea de comando que deberiamos ejecutar serìa la siguente.

$: ct.sh 'chromium-browser http://www.unikode.org' '<Shift><Ctrl>c'

En este caso, si presionamos la combinaciòn de teclas Ctrl màs Shift y la letra c, se abrirà el navegador chromium directamente en este sitio web.

No està demàs aclarar, para aquellos que son novatos, que puedes modificar el script a tu gusto para ejecutar tu browser o navegador o cualquier aplicaciòn con la combinaciòn de teclas que desees.

Por ùltimo, cabe aclarar que la ejecuciòn del script siempre reescribirà el mismo item de combinaciòn de teclas modificàndola en cada vez. Si quieres utilizar el script para crear nuevos y diferentes combinaciones de teclas, entonces deberàs modificar el script para que acepte un nuevo paràmetro, serìa el tercero, el cuàl se encargue de reemplazar el nombre "custom0" por el nombre que tu envìes por la lìnea de comandos.

Para los que quieran hacerlo aquì les dejo el script cuyo uso serìa el siguiente.

Archivo ct2.sh //CT significarìa Combinaciòn de Tecla

#!/bin/bash
dconf write /org/mate/desktop/keybindings/$3/action "'$1'"
dconf write /org/mate/desktop/keybindings/$3/command "'$1'"
dconf write /org/mate/desktop/keybindings/$3/binding "'$2'"
dconf write /org/mate/desktop/keybindings/$3/name "'$1'"

Explicaciòn de uso

Este script requiere 3 paràmetros. Todos deben estar escritos entre comillas simples.

  1. Lìnea de Comando que deseamos ejecutar.
  2. Combinaciòn de Teclas 
  3. Nombre del item a crear o reescribir

Ejemplo

Como usuario comùn, no es necesario ejecutar con privilegios de administrador, si ejecutamos el siguiente comando.

$: ct2.sh 'chromium-browser https://www.youtube.com/' '<Shift><Ctrl>y' 'micombinacionperzonalizada1'

Nota: En mi caso el ejecutable de Unik de llama solamente escribiendo la comando "unik" debido a que si bien el ejecutable de unik en primera instancia se llama unik_vX.x.x.AppImage y generalmente lo suelo tener en el escritorio. Cuando estoy utilizando el terminal y quiero ejecutar Unik, al estar en el escritorio deberìa escribir /home/nextsigner/Escritorio/unik_vX.x.x.AppImage. Para evitarme ese asunto y asì poder llamar a Unik desde donde sea tan solo escribiendo "unik", lo que hago es crear un enlace duro del AppImage de unik hacia la carpeta /usr/local/bin con el comando sudo ln unik_v3.5.2.AppImage /usr/local/bin/unik















viernes, 22 de febrero de 2019

Hemos solucionado un error crìtico en Unik Qml Engine

Desde hace unas semanas, hemos publicado nuevas actualizaciones de Unik. Las versiones anteriores, si bien siempre fueron compatibles con Windows, GNU/Linux y Macos, dichas versiones menores a la versiòn 3.x, no eran compatibles con Android 7 o superior. Las actualizaciones superiores a la versiòn 3.x, cuentan con la compatibilidad y funcionalidad plena sobre los sistemas operativos mencionados pero ademàs tambien lo son para los OS Android 5/6/7/8/9.

Todo o casi todo funcionaba segùn lo esperado, excepto la funciòn log(QByteArray) de unik. Èsta funciòn, no estaba funcionando en Unik para sistemas Android con arquitectura armeabi-v7a. Èsta falla estaba provocando un cierre inesperado de la aplicaciòn. Un error terriblemente crìtico que nos ha obligado a anular dicha funciòn para dicha arquitectura, por lo menos hasta que encontremos una soluciòn.

El gran problema, era que dicho error estaba presente y los que formamos parte del la parte dura del desarrollo de bajo nivel en el equipo de unikode.org, tenìamos pasaje para vacacionar. Lamentablemente no ha quedado otro camino que intentar una soluciòn al regreso.

Regresamos el 19/02/2019. El calor era insoportable. Con una sensaciòn tèrmica de 41 grados en el exterior, por razones de fuerza mayor nuestros estudios estaban algo condicionados y no podìamos lograr la climatizaciòn dentro del ambiente de programaciòn. Fuè asì que luego de 4 dìas intensos de programar, probar, depurar, instalar, desinstalar, etc, hemos dado con la soluciòn.

Por momentos la situaciòn se tornò realmente agotadora. Hay que admitir que el desànimo por momentos nos empujò a creer que todo estaba perdido, a pensar negativamente sobre todo lo relacionado al proyecto unik, sus funcionalidades, propòsitos, estrategias, mòdulos, etc, fueron momentos durìsimos.

La paciencia es lo que un programador debe conservar, mucho màs aùn en momentos crìticos. La falta de resultados y el agotamiento nos llevò a estados de ànimo no muy adecuados, esos que nos impulsan a intentar mètodos o maneras descabelladas. Hemos dudado mucho, hemos cambiado y probado de todos los modos posibles, compilando con todos los NDK, el r10e, el r16b, el r17b y el r18b. Pasando de compilaciones con el API 26 y volviendo al API 28, probando còdigo una y otra vez. Tantas variaciones casi nos hace perder el rumbo de tanto desformar el còdigo.

Por fortuna, existen ciertas herramientas que nos salvan para esta situaciones. Por ejemplo Git. Hemos ido retrocediendo en el tiempo, buscando la versiòn del còdigo que màs estabilidad y respuesta nos provea, una vez que hemos vuelto a un punto de partida por vez nùmero 10 en la busqueda de esta soluciòn, como estrategia salvadora hemos recurrido a la creaciòn de una clase C++ llamada UnikLogObject, tal como lo dice su nombre es un objeto que administra o mejor dicho sirve de puente o nexo para conectar la funcion estàtica C++ encargada del manejo de los mensajes de salida estandar en android dependientes de las cabeceras log.h de android.

Expliquemos mejor esto ùltimo. En Qt, cuando programamos en C++, en la funciòn principal o en otras partes, pero generalmente en la funciòn main, en el caso que sea necesario o ùtil, allì podemos especificarle a nuestra aplicaciòn, cuàl serà la funciòn encargada de gestionar los mensajes de la salida de la aplicaciòn relacionados con mensajes crìticos, fatales, de depuraciòn, de informaciòn etc. Esto Qt lo hace con la previa declaraciòn de una funciòn del tipo static llamada por ejemplo myMessageHandler(), la cuàl se utiliza en nuestra aplicaciòn llamando al mètodo qInstallMessageHandler().

Ejemplo

Archivo main.cpp

static void myMessageHandler(QtMsgType type,
                                    const QMessageLogContext &context,
                                    const QString &message)
{
    android_LogPriority priority = ANDROID_LOG_DEBUG;
    switch (type) {
    case QtDebugMsg: priority = ANDROID_LOG_DEBUG; break;
    case QtWarningMsg: priority = ANDROID_LOG_WARN; break;
    case QtCriticalMsg: priority = ANDROID_LOG_ERROR; break;
    case QtFatalMsg: priority = ANDROID_LOG_FATAL; break;
    };
    __android_log_print(priority, "Qt", "%s", qPrintable(message));
}
int main(int argc, char *argv[])
{
...
qInstallMessageHandler(myMessageHandler);
...
}

El problema es que dicha funciòn estàtica no puede llamar funciones de objetos previamente declarados a la funciòn main. Esto en un principio se solucionò creando variables del objeto de unik que se encarga de mostrar la salida en QML, dicha variable se crea al principio de todo el còdigo, es decir antes que la funcion main y antes que la funcion estàtica mencionada. Esa soluciòn funcionò en las versiones anteriores, funcionaba para todos los sistemas en cualquier arquitectura, pero lamentablemente cuando escalamos APIs de Android arriba llegando a la versiòn 28, esta estrategia comenzò a provocar un apagado inesperado de unik, un error fatal.
¿Como lo hemos solucionado? Lo solucionamos con la creaciòn del objeto UnikLogObject que hemos mencionado. Gracias a los benditos SIGNAL Y SLOT de Qt, hemos conectado nuestro nuevo objeto desde dentro del main hasta la funciòn estàtica. Lo hemos hecho del siguiente modo.

Archivo main.cpp

UnikLogObject ulo;
static void myMessageHandler(QtMsgType type,
                                    const QMessageLogContext &context,
                                    const QString &message)
{
    android_LogPriority priority = ANDROID_LOG_DEBUG;
    switch (type) {
    case QtDebugMsg: priority = ANDROID_LOG_DEBUG; break;
    case QtWarningMsg: priority = ANDROID_LOG_WARN; break;
case QtCriticalMsg: priority = ANDROID_LOG_ERROR; break;
    case QtFatalMsg: priority = ANDROID_LOG_FATAL; break;
    };
    __android_log_print(priority, "Qt", "%s", qPrintable(message));
    ulo.setLog(message.toUtf8());
}
int main(int argc, char *argv[])
{
    ...
    qInstallMessageHandler(myMessageHandler);
    UK u;
    QObject::connect(&ulo, SIGNAL(logReceived(QByteArray)),
                                &u, SLOT(log(QByteArray)));
...
}

Hemos conectado mediante el mètodo connect() de la clase QObject a el objeto de la clase UnikLogObject mediante su señal logReceived() hacia el objeto principal de unik de la clase UK llamada "u" hacia su mètodo o slot log(). De este modo lo hemos resuelto. Ahora ya hemos publicado en el sitio oficial de descargas de unik y en la Google Play Store, el archivo instalador de Unik Qml Engina para Android 5/6/7/8/9 para la arquitectura armeabi-v7a. Se trata del APK de Unik versiòn 3.7.1 que nos permite ver la salida estandar en nuestros proyectos QML. El fallo està solucionado, ahora la aplicaciòn no se cierra inesperadamente, cada vez que se reinicia para cargar algùn mòdulo especìfico o se solicita el cierre con el mètod Qt.quit() o qApp->quit(), en ningùno de los casos se apaga inadecuadamente.




martes, 12 de febrero de 2019

Para Desarrollo de Apps Android recomendamos Framework Qt

Como todos sabemos, este universo de la informàtica va en constante expansiòn, a veces a una velocidad que nos supera. Por momentos es difìcil, casi imposible, seguir su ritmo y estar a la altura de las circunstancias.

En este àmbito relacionado con el desarrollo de software, existe un mundo aparte, un espacio, un entorno, un sistema, un medio ambiente, el cuàl llama la atenciòn de todos. Es un planeta en donde todos en algùn momento debemos aterrizar, debemos ir de paseo, a trabajar, a disfrutar o a vivir. Este es un lugar maravilloso, lleno de luces y sombras, colores y sabores, ese lugar se llama Android.

Android es mucho màs que un Sistema Operativo. Es una parte màs, una extensiòn de nuestros sentidos, cada vez està màs y màs presente, casi de manera omniciente, en todas partes.

Los usuarios de Android, llegan a este mundo por medio de las aplicaciones. Permanentemente, un sin fin de aplicaciones permiten que este lugar sea màs y màs popular, el lugar màs conocido y al que millones y millones de usuarios van y vuelven. En su transito por Android, en la interacciòn, en la costumbre y en el ritual de encender y utilizar aplicaciones, este mundo va creando y consolidando una cultura, un modo de vivir, una manera de percibir y proyectar la realidad que nos rodea, la realidad que està màs allà e incluso nos conecta y nos acerca como nunca antes con los sueños.

Esas aplicaciones, las que dìa a dìa nos invitan a visitar Android, son creadas por Programadores, Desarrolladores de Software. Estas personas, estàn acostumbradas a visitar otros mundos. Para ir de un lugar a otro, diferentes de Android, crean aplicaciones especìficas, una aplicaciòn diferente para ir a cada lugar diferente. Esto implica un esfuerzo enorme y resulta ser un desafìo durìsimo, mucho màs aùn para aquellos programadores que no cuentan con muchos recursos.

A todo creador, vièndolo desde un punto de vista relativo, se lo puede considerar como un Dios. Serà considerado como tàl hasta que se logre conocer al creador de esa entidad llamada Dios. En ciertas culturas suelen llamar Dios a una entidad que posibilita que las cosas sean posibles, la que protege, la que ayuda, todo esto independientemente de si ha sido o no un creador. Muchos afirman que el Dios es el creador que los ha arrojado a esta existencia, otros afirman que Dioses son los que nos protegen o castigan en esta ya circunstancial e inexplicable existencia.

Los Desarrolladores de Software, algunos de manera conciente y otros sin nisiquiera pensarlo, dependemos de ciertas entidades, de ciertos agentes, de ciertos factores, sistemas o de ciertos Dioses para poder crear las aplicaciones. La interacciòn que tengamos con esas entidades depende de cuàl sea el lenguaje que utiliza ese pseudo-dios y si los desarrolladores o progrmadores han aprendido a dominar ese lenguaje. Se los podrìa considerar Dioses porque necesitas aprender un lenguaje, conocer su bibliografìa, sus dogmas, sus reglas, adaptarte a sus mandamientos y repetar sus pautas para ser bendecido por èl.

En el universo de la informàtica, los programas, aplicaciones o sistemas que crean programas, aplicaciones o sistemas, siguiendo la analogìa, podemos decir que ocupan el rol de Dioses. Lo que los podrìa definir como tal, es que son creadores, posibilitan el desarrollo o crecimiento de las cosas creadas, pueden clonar, eliminar o dar larga vida a todo lo que han creado. Entonces cada aplicaciòn que los usuarios utilizan para o desde un sistema, fuè creado por los desarrolladores y estos a su vez han dependido de otras programas, aplicaciones o sistemas creadores. Todo esto serìa imposible sin el conocimiento y entendimiento de un lenguaje especìfico para orarle al creador y pedirle què y còmo lo queremos lograr.

Muchos desarrolladores, talvez por razones obvias y comprensibles, se aferran a ciertas doctrinas. Esto sucede por lo general porque no es muy fàcil aprender un lenguaje, avanzar de lleno y de manera profunda en toda su bibliografìa. Se puede aprender un poco de cada lenguaje para hacer un vuelo rasante por encima de otras doctrinas, para conocer por encima sus reglas o caracterìsticas, pero para llamarse desarrollador, hay que si o si especializarse de manera profunda en una doctrina. Esto conlleva a que los desarrolladores se aboquen a difundir y predicar cuàl si fuese una religiòn, ùnicamente aquellos lenguajes y doctrinas que ha ellos les ha resultado beneficiosa, negando de manera necia que existen otras posibilidades y mejores opciones en otros contextos, con otras reglas y con otros lenguajes.

Allà por el año 1992, la empresa Noruega Trolltech, ha creado un sistema que consiste en aplicaciones y programas que sirven para crear programas. Han creado el entorno de trabajo o framework Qt. Este entorno permite crear aplicaciones en muchos lenguajes para todos los mundos! Esto quiere decir que no importa que doctrina, lenguaje o reglas haya aprendido un desarrollador, el entorno Qt permite a los que hablan el idioma C++, C#, PHP, Python, Java, Ruby, Pascal y otros, les permite crear aplicaciones desde el sistema GNU/Linux, Windows, Macos u otros, para GNU/Linux, Windows, Macos, iOS o Android.

Fuè asì que utilizando el mismo lenguaje, escribiendo las mismas instrucciones, gracias al Dios Qt, ademàs de crear aplicaciones para todos los mundos, tambien se puede crear aplicaciones para el mundo Android en sus versiones 5,6,7,8 y 9. 

Muchos soñadores se han ilusionado con un mundo en el cuàl todos los que piensan, escriben o se expresan de maneras diferentes, todos puedan unirse y convivir sin problemas. Sueñan con un universo equilibrado, multicultural, plural y diverso pero en armonìa. En el universo de la informàtica todos estos sueños talvez puedan ser posibles gracias a Qt. Muchos han soñado aùn de manera màs ambiciosa. Quisieran que todas las diferencias se reduscan a su mìnima expresiòn, que a travès de nuevos y viejos lenguajes, de una nueva cultura, de nuevas metodologìas, todos confluyan en un sòlo àmbito desde donde crear todo y de todo para todos los sistemas.

Qt està haciendo todo esto posible. Crear una aplicaciòn en Qt, permite a los desarrolladores, crear aplicaciones con una practicidad y eficiencia ùnica. Logrando que la aplicaciòn desarrollada en Qt pueda aterrizar como una nave ùnica en todos los planetas existentes.

Los desarrolladores que intentan crear aplicaciones para GNU/Linux, tienen muchas opciones al momento de elegir sus herramientas para el desarrollo. Asì mismo los desarrolladores que desarrollan aplicaciones para Windows, Macos, iOS o Android. Pero al momento de seleccionar una herramienta que permita desarrollar aplicaciones para todos los sistemas, utilizando practicamente el mìsmo còdigo fuente, para esto no existe mejor opcciòn u herramienta que Qt.

La mejor opciòn, la mejor manera, la mejor herramienta para crear aplicaciones para Android, sin importar què tipo conocimientos previos o què lenguaje tenga previamente el desarrollador, sin duda alguna, la mejor opciòn es Qt. Es por esto y por muchas razones màs, es que desde aquì predicamos en su nombre. No somos fanàticos, somos realistas. Nos parece un buen dogma y unas buenas reglas que exista el modo de que todas las diferencias se unan en un solo camino.

Existen muchos sistemas operativos, cuando hablamos de Android, de manera romàntica nos referimos a èl como un mundo màgico, en donde la infinidad de oportunidades y posibilidades, gracias a su infinita cantidad de usuarios, hacen de Android algo mucho màs que todos los demàs. Por eso insistimos, desde aquì recomendamos, que si los desarrolladores quieren crear aplicaciones bendecidas por la palabra màgia COMPATIBILIDAD, a todos ellos les recomendamos que utilicen Qt. Si desean crear aplicaciones para un solo sistema, pueden lograrlo seguramente con otras herramientas, pero si lo que desean en crear aplicaciones que puedan aterrizar en todos los planetas, para ello recomendamos Qt.

En este sitio, tenemos la costumbre de publicar detalles tècnicos sobre estos asuntos o relacionados. Tambièn es bueno expresar de un modo genuino y propio nuestras impresiones. Es bueno dejar un agradecimiento y una bendiciòn a nuestros dioses y nuestros paraìsos. Se agradece al Dios GNU, Open Source, Android, Qt, QtQuick y sus lenguajes C++, QML y JavaScript.
































lunes, 4 de febrero de 2019

Entorno de Desarrollo de Unik 3.5

Información Actualizada 04/02/2019

GNU/LInux

OS Host: GNU/Linux Ubuntu 16.04 LTS
Qt Open Source: Qt 5.9.1
Compiler: gcc version 5.5.0 20171010 (Ubuntu 5.5.0-12ubuntu1~16.04)
Última Versión de Instalador: unik_v3.5.2.AppImage

Asunto linuxdeployqt

1) Descargar linuxdeployqt
     versiòn linuxdeployqt 6 (commit 7789123), build 634 built on 2019-01-27 22:20:46 UTC
     o superior.

2) Configurar la variable de entorno PATH de tal modo que se incluya la ubicaciòn del ejecutable qmake con el cuàl se ha compilado unik. Por ejemplo, si se ha compilado con el Qt 5.9.1, deberìamos setear la variable de entorno PATH del siguiente modo.

$:export PATH=/home/nextsigner/Qt5.9.1/5.9.1/gcc_64/bin:$PATH

Qudando asì

$: echo $PATH
/home/nextsigner/Qt5.9.1/5.9.1/gcc_64/bin:/home/nextsigner/bin:/home/nextsigner/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/ssl/bin:/snap/bin

3) Ejecutar el linuxdeployqt
$: /home/nextsigner/Descargas/linuxdeployqt-continuous-x86_64.AppImage  /media/nextsigner/ZONA-A1/nsp/build_unik_linux_5_11/unik -qmldir=/media/nextsigner/ZONA-A1/nsp/unik -appimage



Nota 1: El error libnssutil3.so se soluciona copiando /usr/lib/x86_64-linux-gnu/nss a build_unik_linux/lib/nss .

Nota 2: Copiar manualmente los archivos lib*.so.5.x.x a la carpeta lib del ejecutable de nuestra aplicaciòn.

Windows

OS Host: Windows 8.1
Qt Open Source: Qt 5.9.6
Compiler: MSVC2015 32bit
Última Versión de Instalador: unik_v3.5.1

Android

OS Host: GNU/Linux Ubuntu 16.04 LTS
Qt Open Source: Qt 5.11.3
Compiler: gcc version 5.5.0 20171010 (Ubuntu 5.5.0-12ubuntu1~16.04)
Última Versión de Instalador: org.unikode.unik unik_v3.5.3_armeabi-v7a
Android Build SDK: android-28
API min: 21 Android 5.0
API Target: 26 Android 8.0
Google Play Publication: 3.5.2

Entrada destacada

Algunos Script Ùtiles GNU/Linux

Còmo crear un alias con funcion y paràmetros alias gs='gitSubir "$1"' function gitSubir() {     git add *;     git co...