Profile

Hola, soy Jorge Anaya

Soy desarrollador de software y este es mi blog personal. Aqu铆 encontraras fragmentos de c贸digo y gui谩s sobre tecnolog铆a con las que generalmente trabajo o que estoy aprendiendo.

ACERCA DE

Un poco m谩s de informaci贸n sobre mi
  EXPERIENCIA
Habilidades y experiencia profesional


// HABILIDADES
  • C# SQL Server Python ASP.NET MVC API WebService GraphQL NodeJS VB.NET VBA HTML CSS JS (ES6) AngularJS SvelteJS Unit-Test UX-UI MS-Test Automation Selenium Sonarqube Git TFS Docker Linux RabbitMQ


// LINEA DE TIEMPO
Azure Fundamentals
2021

Azure Fundamentals * In Progress

SOLERA
2020-*

C# SQL Server TFS MVC REST API AngularJS MS Test Python Selenium Sonarqube Entity Framework Dapper LINQ SQL SSRS SCRUM Ceremonies


C# Specialist
2019

Microsoft C# Programming Specialist

UNOSQUARE
2018-2020

C# SQL Server TFS MVC Web-API AngularJS MS Test Python Selenium Sonarqube Entity Framework Dapper LINQ SQL SSRS SCRUM Ceremonies


MCSA SQL
2017

Microsoft Certified Solutions Associate as SQL Database Development

MCPS
2016

Microsoft Certified Professional



MASTERS
2013

Master's degree in Information Technologies



BSM
2002-2018

Software Architect,
Software Developer,
SysAdmin
SQL Server VB.NET C# Windows Forms ASP.NET Git Data Analyst Design Patterns Networking Active Directory


BACHELOR
2002

Computer Science, Telematics Engineering



POST MAS RECIENTES

Desde el blog estas son las ultimas entradas, fragmentos de codigo e ideas.
  Docker enchulame la lista de contenedores
Agosto 1   |   Docker

Siempre que ejecuto docker ps para listar los contenedores me resulta dif铆cil entender donde inicia y donde termina la informaci贸n sobre cada contenedor:



隆Que carajos! ... el puerto 驴c煤al? ... siento que casi estoy viendo la matrix

Debo admitir que despu茅s de un tiempo tus ojos se acostumbran y comienzan a hacer cosas raras pero comienzas a entender el resultado. Claro que no deber铆a ser as铆, por lo que encontr茅 que tenemos algunas opciones para mejorar el resultado.

Utilizar —format

Al utilizar la opci贸n --format, podemos elegir de una serie campos disponibles e incluso despegarlos de forma mas ordenada usando la sintaxis table {{.FieldName}}\t. La opci贸n format utiliza Go templates algo que me resulta familiar1.

table incluye los encabezados y \t agrega espacio entre las columnas.

 Ejemplo usando --format

            

 docker ps --format 'table {{.Names}}\t
                           {{.Status}} : {{.RunningFor}}\t
                           {{.ID}}\t
                           {{.Image}}'
            
            
        

Y obtenemos esto:

Definitivamente resulta mucho m谩s f谩cil de comprender

Sacando provecho a los Go Templates

Nos podemos poner creativos y si necesitamos por ejemplo consultar los contenedores con informaci贸n de red utilicemos las caracter铆sticas de los GoLang Templates para detectar si hay puertos y desplegarlos en cada linea:

 Informaci贸n de red

            

docker ps --format 'table {{.Names}}
                          \t{{.Status}}
                          \t{{.Networks}}
                          \n{{.ID}}
                          {{if .Ports}}
                            {{with $p := split .Ports ", "}}
                              {{range $p}}\t\t{{println .}}{{end}}
                            {{end}}
                          {{else}}
                            \t\t{{println "No Ports"}}
                          {{end}}'
            
            
        

Como ven mucho mejor ordenado en dos columnas y con todos los datos de la red y puertos mas legibles

Todos los containers docker ps –a

Podemos revisar todos los contenedores (activos y no activos) utilizando la opci贸n -a. Aprovechando los templates a帽adamos el tama帽o en disco, como utiliza la red y la imagen de donde proviene el contenedor.

 Informaci贸n de todos los contenedores

            

docker ps -a -q --format 'table {{.Names}}\t
                                {{.Status}}\t
                                {{.Size}}\n
                                {{.ID}}\t
                                {{.Image}}
                                {{if .Ports}}
                                  {{with $p := split .Ports ", "}}\t
                                    {{len $p}} port(s) on {{end}}{{- .Networks}}
                                  {{else}}\tNo Ports on {{ .Networks }}
                                {{end}}\n'
            
            
        


De esta manera podemos ver en general el estado de nuestros contenedores.

Crear una funci贸n para reutilizar los comandos

Finalmente podemos crear una funci贸n para utilizar estos comandos (si estas utilizando WSL o Linux) dentro de nuestro .bash_aliases

 Crear una funci贸n bash que acepta par谩metros

            

# Docker PS Prettify Function
function dock() {
  if [[ "$@" == "ps" ]]; then
    command docker ps --format 'table {{.Names}}\t{{.Status}} : {{.RunningFor}}\t{{.ID}}\t{{.Image}}'
  elif [[ "$@" == "psa" ]]; then
    # docker ps -a includes all containers
    command docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Size}}\n{{.ID}}\t{{.Image}}{{if .Ports}}{{with $p := split .Ports ", "}}\t{{len $p}} port(s) on {{end}}{{- .Networks}}{{else}}\tNo Ports on {{ .Networks }}{{end}}\n'
  elif [[ "$@" == "psnet" ]]; then
    # docker ps with network information
    command docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Networks}}\n{{.ID}}{{if .Ports}}{{with $p := split .Ports ", "}}{{range $p}}\t\t{{println .}}{{end}}{{end}}{{else}}\t\t{{println "No Ports"}}{{end}}'
  else
    command docker "$@"
  fi
}
            
            
        

Para utilizarlo basta ahora con teclear:

dock ps
Contenedores en ejecuci贸n con su imag茅n
dock psa
Todos los contenedores incluyendo tama帽o en disco y datos de red
dock psnet
Contenedores en ejecuci贸n con informaci贸n de red

Campos disponibles en docker

.ID
Identificador del contenedor
.Image
Id de la imag茅n
.Command
Comando de ejecuci贸n
.CreatedAt
Tiempo cuando el contenedor se cre贸.
.RunningFor
Tiempo transcurrido desde que se inici贸 el contenedor.
.Ports
Puertos utilizados por el contenedor.
.Status
Estado del contenedor.
.Size
Espacio que ocupa en disco el contenedor.
.Names
Nombre del contenedor.
.Labels
Todas las etiquetas asignadas al contenedor.
.Label
Valor especifico para una etiqueta. Por ejemplo ‘{{.Label “com.docker.swarm.cpu”}}’
.Mounts
Nombre de los vol煤menes montados en este contenedor.
.Networks
Nombre de las redes adjuntas al contenedor.

  1. Este blog esta desarrollado con HUGO, el cual a su vez usa GoLang html y text templates. ↩︎

  Docker solucionar el nombre duplicado de red
Marzo 25   |   Docker

El Problema

Un d铆a tuve que reiniciar mi servidor linux y como Murphy no falla al regresar la instancia de docker estaba vac铆a sin ning煤n container, despu茅s de explorar un rato y revisar que todo estuviera en orden no encontr茅 la causa, hice lo que se debe hacer … reinicie nuevamente el servidor y ohh sorpresa ahi estaban de nuevo todos mis containers 隆Genial! pero … al momento de intentar iniciarlos


ERROR: network xxxx is ambiguous (2 matches found based on name)

Los porques

Encontr茅 que es valido duplicar el nombre de la red en docker, mi sospecha es que al no encontrar la configuraci贸n docker gener贸 nuevamente toda las redes porque como pueden ver se duplicaron las redes y los drivers

 docker network list

            

$ docker network ls
NETWORK ID NAME DRIVER SCOPE
27b6c27fdc2b bridge bridge local
33f2a0c04878 bridge bridge local
c4247d693521 host host local
9b95be563bf7 host host local
590102262bb5 none null local
25e1bf9dc86 none null local
            
            
        

Asi que la solucion parece simple eliminar la red duplicada y ya esta docker network rm [ID], lo intente pero ….


Error : bridge is a pre-defined network and cannot be removed

La soluci贸n no parece ser tan trivial, en alg煤n foro encontr茅 que para poder eliminar la red:

  1. El servicio de docker debe estar detenido
  2. No debe existir un contenedor usando la red
  3. No tener ning煤n contenedor creado

Por cierto para ver cuales containers est谩n usando la red puedes usar:

 Inspect network ID of a container

            

# Como bridge esta repetido necesitas hacerlo por Id y revisar la secci贸n de "Containers"
docker network inspect [id || name]

"Internal": false,
{ "Network": "" },
"ConfigOnly": false,
"Containers": {},

            
            
        

La opci贸n uno y dos no funcionaron y no pod铆a darme el lujo de eliminar los containers y volverlos a crear pues ya los tenia configurados con sus vol煤menes y otras cosas asi que la soluci贸n es:

Soluci贸n

  1. Crear una nueva red con -d especificamos el driver

docker network create -d bridge [nuevo-nombre-de-red]

  1. Desconectar el o los containers de la red ambigua

    docker network disconnect bridge [contenedor]

  2. Conectar el o los containers hacia la nueva red

    docker network connect [nuevo-nombre-de-red] [contenedor]

  3. Opcional. Purgar nuestra red para eliminar aquellas redes que no estamos utilizando.

docker network rm $(docker network ls -q)

Listo ya con esto podemos iniciar nuestro container


docker start my-happy-container

  React aplicaci贸n en 100 lineas de c贸digo
Febrero 2   |   React

El siguiente c贸digo permite entender como se construye aplicaci贸n muy simple en React

Pon atenci贸n a los comentarios en el c贸digo
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>React JS Search Results</title>
  <!-- Add React and Babel References -->
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>

<body>
  <section>
    <!-- Every React app must have what鈥檚 known as an entry point. 
    The entry point is an HTML element where we insert our React application into the page. -->
    <div id="root">
    </div>

    <!-- Our Script must have type="text/babel" for Babel to work-->
    <script type="text/babel"> //React code will go here
      // Babel converts this code that looks like HTML into valid JavaScript (JSX: JavaScript XML)
      // The functions in react must be Capitalize to differentiate from normal javascript functions
      // React Functions became Components
      // The Component must return JSX code between parenthesis function ComponentName() { return ( ...JSX Code ... ) }
      // Every React Component must return either JSX elements or other React components.

      /* PROPS (Passing data to the components)
        We can pass data to the function components using attributes and it is passed to the Link function as an argument
        <Link attributeName="value" />

        React collects and organizes the data passed to a given component as a single object.
        The name for data passed to a component, such as title, is props.
        All prop values exist within the function component itself on a props object.
      */

      /* SEPARATE DATA FROM UI
          Make and array of objects and pass down the link components through props.
          Since this is a common pattern in React, it has its own method .map() that works with JSX
          (don't confuse with JS array.map() it's similar but Reacts works only for JXS)
      */

      const linkData = [
        {
          title: "React - A JavaScript Library for Building User Interfaces",
          url: "https://reactjs.org",
          shortUrl: "reactjs.org",
          excerpt: "React makes it painless to create interactive UIs."
        },
        {
          title: "Jorge Anaya's Blog",
          url: "https://www.jorgeanaya.dev",
          shortUrl: "jorgeanaya.dev",
          excerpt: "Personal insights about coding and life"
        },
        {
          title: "Google",
          url: "https://www.google.com",
          shortUrl: "google.com",
          excerpt: "When everything fails then Google is your friend, GoogleIt!"
        }
      ]

      function Link(props) {
        // We use {} curly braces to insert or interpolate dynamic values wherever we need.
        return (
          <div>
            <a href="{props.url}">{props.title}</a>
            <div>
              <h3>{props.shortUrl}</h3>
            </div>
            <div> {props.excerpt}
            </div>
          </div>
        )
      }
      // Since React components can return other React components, we can make an App Component
      // The entire JSX expression is surrounded by curly braces
      // JSX allows us to insert any valid JavaScript expression between curly braces.
      function App() {
        return (
          <section>
            {linkData.map(function (link) {
              return (
                <Link
                  key={link.url} // Each child in a list should have a unique "key" prop
                  title={link.title}
                  url={link.url}
                  shortUrl={link.shortUrl}
                  excerpt={link.excerpt} />
              ); // return end, function, map() & expression end */
            })}
          </section>
        )
      }
      ReactDOM.render(<App />, document.getElementById('root'))
    </script>

</body>

</html>
  FFmpeg concatenar videos sin recodificar
Enero 12   |   Terminal

Para concatenar varios videos usando ffmpeg necesitamos tener un archivo de texto que contenga en cada linea un path a los videos:

 VideoList.txt

            

# Se pueden utilizar rutas absolutas o relativas

file '/path/to/video1.mp4'
file '/path/to/video2.mp4'
file '/path/to/video3.mp4'
            
            
        

 Ejecutar

            

# Si se utilizan rutas absolutas agremamos el parametro -safe 0
ffmpeg -f concat -safe 0 -i videolist.txt -c copy output.mp4
            
            
        

 Para generar en automatico un archivo con la lista de videos

            


# Windows
(for %i in (\*.mp4) do @echo file '%i') > videolist.txt
ffmpeg -f concat -i videolist.txt -c copy output.mp4

# Bash
for f in ./\*.mp4; do echo "file '\$f'" >> videolist.txt; done
ffmpeg -f concat -i videolist.txt -c copy output.mp4

# Zsh - Todo en una linea
ffmpeg -f concat -safe 0 -i <(for f in ./\*.mp4; do echo "file '$PWD/$f'"; done) -c copy output.mp4
            
            
        

 Repetir mismo el video

            


# Windows ... in (start,step,end)
(for /l %i in (1,1,10) do @echo file './videoloop.mp4') > mylist.txt
ffmpeg -f concat -i list.txt -c copy output.mp4

# Bash
for i in {1..4}; do printf "file '%s'\n" input.mp4 >> list.txt; done
ffmpeg -f concat -i list.txt -c copy output.mp4
            
            
        

REFERENCIAS:

  Terminal verificar si una cadena esta vacia
Enero 5   |   Terminal

Una de las tareas b谩sicas cuando haces scripting es verificar si una cadena esta o no vac铆a (puede venir de un par谩metro, un input de usuario, etc). Lo hacemos con los operadores -n y -z

 Cadena vacia

            

#!/bin/bash

VAR=''
if [[ -z $VAR ]]; then
echo "String is empty."
fi
            
            
        

 Cadena no vacia

            

#!/bin/bash

VAR='Linuxize'
if [[ -n $VAR ]]; then
echo "String is not empty."
fi
            
            
        

REFERENCIA: Linuxize

  SQL Studio ejecutar como usuario remoto
Septiembre 1   |   Mssql

Conectarte a SQL Server Management Studio utilizando credenciales de windows diferentes, resulta muy util cuando te conectas por VPN a otras redes o dominios y requieres utilizar un usuario de otro dominio.

La clave es utilizar el comando runas con los par谩metros /user y /netonly desde un acceso directo al cual le indicaremos la ruta del ejecutable del SQL Server Management Studio a帽adiendo la opci贸n nosplash al final.

 SSMS run as

            


C:\Windows\System32\runas.exe /user:domain\username /netonly "C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\Ssms.exe -nosplash"

            
            
        

Al ejecutar el SSMS usando el acceso directo, se abrir谩 una ventana de comando preguntando por tu contrase帽a del usuario REMOTO.

NOTA: Al momento de conectarte a un servidor en la ventana de conexi贸n te aparecer谩n las credenciales de la maquina local, pero el usuario que en realidad se estar谩 utilizando es el que hayas definido en el comando runas.
  Git reset para modificar el ultimo commit
Agosto 1   |   Git

En ocasiones requerimos de eliminar el 煤ltimo commit realizado pero sin perder los cambios. Esto por muchas razones, en ocasiones es un commit prematuro, o se nos olvido agregar/eliminar un archivo, etc.

IMPORTANTE: Todo esto en nuestro entorno local sin haber realizado la publicaci贸n/sync a un origen remoto

git reset: Mueve el branch actual hacia X commit as铆 que utilizamos HEAD~1 o "HEAD^" (ambos son validos), ejemplo:

 git reset

            

\$git reset HEAD~1
            
            
        

Incluyendo --soft como par谩metro dejara los archivos marcados para commit

 Usando --soft

            

\$git reset --soft HEAD~1
            
            
        

Ahora bien en ocasiones solo requerimos hacer alg煤n peque帽o cambio o corregir el mensaje del commit para ello utilizamos git commit --amend esto abre nuestro editor por lo que es importante tenerlo configurado

 Usando amend

            

$git rm private.key
$git commit --amend
            
            
        


Escenario corregir el autor despu茅s de 2 commits

 Corregir autor

            

$git reset HEAD~1
$git commit --amend --author="Jorge Anaya "
$git add .
$git commit -m "Fix bla bla bla"
            
            
        
  Limpiar la papelera de reciclaje de todos los usuarios
Julio 20   |   Windows

La emergencia 馃敂

Notificaci贸n 馃敂, urge que te conectes al servidor remoto para ejecutar una script de SQL, te conectas y 馃挜


An error occurred while executing batch. Error message is: There is not enough space on the disk....

Revisas y te das cuenta que no hay espacio en la unidad C -nada, 0, no cabe un bit mas- Resulta que el SSMS de SQL necesita espacio en C:\Users\...\AppData\Local\Temp para los resultados de un Query


Revisas archivos temporales, tu papelera, etc. luego ejecutas el asistente de limpieza de windows, nada ayuda, cuando mucho ganas unos pocos megas

WinDirStat

De pronto recuerdas esta maravillosa herramienta WinDirStat y la dejas analizar la unidad. Gracias a ella te das cuenta de dos carpetas que se estan comiendo tu espacio en el disco:

Limpia la papelera de todos los usuarios


1. Tus compa帽eros no son muy cuidadosos con su papelera de reciclaje

Asi que abres el terminal en modo administrador y ejecutas lo siguiente:

 Vaciar la papelara de reciclaje de todos los usuarios

            

rd /s c:\$Recycle.Bin
            
            
        
Si alguien te reclama despu茅s, puedes decirle !ey, no me culpes隆, por algo estaban en la papelera

Carpeta de instalaci贸n de Windows


2. Windows no es bueno limpiando su propio folder de instalaciones \Windows\Installer

Esto debe de abordarse con cuidado, es un error conocido que la carpeta de Windows Installer crece con el tiempo sobre todo si estas instalando muchas aplicaciones (Ahora imaginate si esta PC se comparte con mas usuarios cada uno instalando y actualizando sus propias aplicaciones). En resumen, el problema es que cuando se desinstala una app, estas no eliminan de forma correcta sus paquetes de instalaci贸n/actualizaci贸n. Se supone que no deber铆amos de tocar esta directorio, pero como en todo debemos de proceder con cuidado.

El fix en si es identificar los paquetes de instalaci贸n/actualizaci贸n que pertenecen a aplicaciones que ya se desinstalaron del sistema.

Manualmente puedes ejecutar el siguiente VBA Script el cual genera un archivo que contiene los archivos que est谩n instalados y que DEBEMOS de mantener en el sistema, lo dem谩s puede ser borrado

 VBA Script

            

'' Identify which patches are registered on the system, and to which
'' products those patches are installed.
''
'' Copyright (C) Microsoft Corporation. All rights reserved.
''
'' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
'' KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
'' IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
'' PARTICULAR PURPOSE.

'Option Explicit

Dim msi : Set msi = CreateObject("WindowsInstaller.Installer")

'Output CSV header
WScript.Echo "The data format is ProductCode, PatchCode, PatchLocation"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("output.txt", True)
objFile.WriteLine "ProductCode, PatchCode, PatchLocation"
objFile.WriteLine ""
' Enumerate all products
Dim products : Set products = msi.Products
Dim productCode

For Each productCode in products
' For each product, enumerate its applied patches
Dim patches : Set patches = msi.Patches(productCode)
Dim patchCode

    For Each patchCode in patches
    	' Get the local patch location
    	Dim location : location = msi.PatchInfo(patchCode, "LocalPackage")
        objFile.WriteLine productCode & ", " & patchCode & ", " & location

    Next

Next
WScript.Echo "Data written to output.txt, these are the registered objects and SHOULD be kept!"
            
            
        

Agradecimientos a Raymond.cc en su post se detallan ademas de el script anterior algunas otras formas de limpiar este directorio.


Suerte espero que estos dos tips te ayuden a recuperar valioso espacio en tu sistema.

  Configurar vscode para trabajar en entornos remotos
Julio 1   |   Vs

Recientemente, vscode libero una extensi贸n llamada Remote Development la cual te permite conectarte remotamente a proyectos en SSH, Containers y WSL.

Actualmente lo utilizo con un servidor local linux al cual me conecto via SSH.

  1. Instalar la extensi贸n Remote Development

  2. Configurar el acceso al servidor via SSH

    Para configurarlo desde Mac OS (~/rs_pub.id):

                
    
       ssh-keygen -t rsa -b 4096
       sh-copy-id jorgeanaya@host-fqdn-or-ip-goes-here
                   
                
            

  3. Configurar un acceso al servidor SHIFT+CMD+P

    • 3.1 Remote SSH: Connect to Host
    • 3.2 Configure SSH Hosts …
    • 3.3 Select ~/.ssh/config

            

Host server-name
HostName 192.168.1.10
User jorgeanaya
            
            
        
  Utilizar cmder como terminal por default en vscode
Abril 4   |   Vs

Cmder es un console emulator que proporciona todo aquello que le hace falta a la terminal por default de windows. Desde que la conoc铆 siempre la cargo para todas mis instalaciones y equipos. Y como siempre olvido como configurar el vscode para que use esta terminal por default, aqu铆 los pasos para lograrlo

  1. Generar el siguiente archivo en C:\Cmder\vscode.bat

       @echo off
       SET CurrentWorkingDirectory=%CD%
       SET CMDER_ROOT=C:\cmder
       CALL "%CMDER_ROOT%\vendor\init.bat"
       CD /D %CurrentWorkingDirectory%
       

  2. En las configuraciones de vscode Ctrl + , (settings.json)

       "terminal.integrated.shell.windows": "C:\\WINDOWS\\System32\\cmd.exe",
       "terminal.integrated.shellArgs.windows": ["/K", "C:\\cmder\\vscode.bat"],
       "terminal.integrated.fontFamily": "Fira Mono for Powerline",
       
    

CONTINUA LEYENDO TODOS LOS POST EN LA SECCI脫N DEL BLOG ...



PROYECTOS

Informaci贸n de proyectos, novedades en general