Snippets Collections
#!/bin/bash

# Colores para la salida
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# Funciones de mensajes
error() { echo -e "${RED}Error: $1${NC}" >&2; }
success() { echo -e "${GREEN}$1${NC}"; }
info() { echo -e "${BLUE}$1${NC}"; }
warning() { echo -e "${YELLOW}$1${NC}" >&2; }
process() { echo -e "${CYAN}$1${NC}"; }

# Variables globales
DOCKER_DIR="docker"
PROJECT_NAME=""
FRAMEWORK=""
PHP_VERSION=""
WEB_PORT=""
DB_PORT=""
CURRENT_DIR=$(pwd)

# Función para verificar y corregir permisos
check_and_fix_permissions() {
    local target_dir="$1"
    
    # Verificar si el directorio existe
    if [ ! -d "$target_dir" ]; then
        return 0
    fi
    
    process "Verificando permisos de $target_dir..."
    
    # Verificar si tenemos permisos de escritura
    if [ ! -w "$target_dir" ]; then
        warning "No tenemos permisos de escritura en $target_dir"
        process "Intentando corregir permisos..."
        
        # Intentar con sudo si está disponible
        if command -v sudo &> /dev/null; then
            if sudo chmod 755 "$target_dir" && sudo chown "$USER:$USER" "$target_dir" 2>/dev/null; then
                success "Permisos corregidos con sudo"
                return 0
            fi
        fi
        
        # Intentar sin sudo
        if chmod 755 "$target_dir" 2>/dev/null; then
            success "Permisos corregidos"
        else
            error "No se pueden corregir los permisos automáticamente"
            info "Por favor, ejecuta manualmente:"
            echo "  sudo chmod 755 \"$target_dir\""
            echo "  sudo chown \$USER:\$USER \"$target_dir\""
            return 1
        fi
    else
        success "Permisos correctos en $target_dir"
    fi
    
    return 0
}

# Función para limpiar directorio de forma segura
safe_clean_directory() {
    local dir_path="$1"
    
    if [ ! -d "$dir_path" ]; then
        return 0
    fi
    
    process "Limpiando directorio $dir_path..."
    
    # Verificar permisos primero
    if ! check_and_fix_permissions "$dir_path"; then
        return 1
    fi
    
    # Intentar eliminar contenido del directorio
    if [ -w "$dir_path" ]; then
        # Usar find para eliminar contenido de forma segura
        if find "$dir_path" -mindepth 1 -maxdepth 1 -exec rm -rf {} + 2>/dev/null; then
            success "Directorio limpiado correctamente"
            return 0
        else
            # Si falla, intentar con sudo
            if command -v sudo &> /dev/null; then
                if sudo rm -rf "${dir_path:?}/"* 2>/dev/null; then
                    success "Directorio limpiado con sudo"
                    return 0
                fi
            fi
        fi
    fi
    
    error "No se pudo limpiar el directorio $dir_path"
    return 1
}

# Verificar instalación de Docker y Docker Compose
check_docker_installation() {
    process "Verificando instalación de Docker..."
    if ! command -v docker &> /dev/null; then
        error "Docker no está instalado. Instala Docker primero."
        echo "Visita: https://docs.docker.com/get-docker/"
        exit 1
    fi
    success "Docker está instalado."

    process "Verificando Docker Compose..."
    if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
        error "Docker Compose no está instalado."
        echo "Visita: https://docs.docker.com/compose/install/"
        exit 1
    fi
    success "Docker Compose está instalado."
}

# Verificar permisos de Docker
check_docker_permissions() {
    process "Verificando permisos de Docker..."
    if ! docker info &> /dev/null; then
        error "No tienes permisos para acceder a Docker."
        warning "Solución:"
        echo "  sudo usermod -aG docker \$USER"
        echo "  newgrp docker"
        exit 1
    fi
    success "Permisos de Docker verificados."
}

# Verificar conexión a internet
check_internet_connection() {
    process "Verificando conexión a internet..."
    if ! curl -s --connect-timeout 10 https://packagist.org > /dev/null; then
        error "No hay conexión a internet o Packagist no está disponible"
        warning "El script requiere conexión a internet para descargar dependencias"
        read -p "¿Continuar de todos modos? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            exit 1
        fi
    else
        success "Conexión a internet verificada"
    fi
}

# Encontrar puertos disponibles
find_available_ports() {
    local web_port=8081
    local db_port=5433
    
    # Encontrar puerto web disponible
    while ss -tuln 2>/dev/null | grep -q ":${web_port} "; do
        web_port=$((web_port + 1))
    done
    
    # Encontrar puerto DB disponible (empezando desde 5433)
    while ss -tuln 2>/dev/null | grep -q ":${db_port} "; do
        db_port=$((db_port + 1))
    done
    
    WEB_PORT="$web_port"
    DB_PORT="$db_port"
    success "Puertos disponibles encontrados: Web → ${WEB_PORT}, DB → ${DB_PORT}"
}

# Seleccionar framework CON VERSIONES CORRECTAS
select_framework() {
    echo ""
    info "🎯 SELECCIÓN DE FRAMEWORK"
    echo "========================="
    echo ""
    echo "  1) Yii2 Basic - Framework tradicional (PHP 7.4)"
    echo "  2) Yii2 Advanced - Framework avanzado (PHP 7.4)"
    echo "  3) Yii3 - Framework moderno (PHP 8.4+)"  
    echo "  4) Laravel - Framework elegante (PHP 8.3+)"
    echo ""
    
    while true; do
        read -p "Selecciona el framework (1-4): " choice
        case $choice in
            1) 
                FRAMEWORK="yii2-basic"
                PHP_VERSION="7.4"
                success "Seleccionado: Yii2 Basic con PHP 7.4"
                break
                ;;
            2) 
                FRAMEWORK="yii2-advanced"
                PHP_VERSION="7.4"
                success "Seleccionado: Yii2 Advanced con PHP 7.4"
                break
                ;;
            3) 
                FRAMEWORK="yii3"
                PHP_VERSION="8.4"
                success "Seleccionado: Yii3 con PHP 8.4"
                break
                ;;
            4) 
                FRAMEWORK="laravel"
                PHP_VERSION="8.3"
                success "Seleccionado: Laravel con PHP 8.3"
                break
                ;;
            *) 
                error "Opción inválida. Por favor, selecciona 1, 2, 3 o 4"
                ;;
        esac
    done
}

# Validar nombre del proyecto
get_project_name() {
    echo ""
    info "📝 NOMBRE DEL PROYECTO"
    echo "======================"
    echo "Elige un nombre para tu proyecto:"
    echo "  - Debe comenzar con una letra"
    echo "  - Puede contener letras, números, guiones y guiones bajos"
    echo ""
    
    while true; do
        read -p "Ingresa el nombre del proyecto: " project_name
        
        if [ -z "$project_name" ]; then
            error "El nombre no puede estar vacío."
            continue
        fi
        
        if [[ ! "$project_name" =~ ^[a-zA-Z][a-zA-Z0-9_-]*$ ]]; then
            error "El nombre debe comenzar con una letra y solo puede contener letras, números, guiones y guiones bajos."
            continue
        fi
        
        PROJECT_NAME="$project_name"
        success "Nombre del proyecto validado: $PROJECT_NAME"
        break
    done
}

# Crear estructura de directorios MEJORADA con gestión de permisos
create_directory_structure() {
    process "Creando estructura de directorios en '$DOCKER_DIR'..."
    
    # Verificar y corregir permisos del directorio docker si existe
    if [ -d "$DOCKER_DIR" ]; then
        warning "El directorio $DOCKER_DIR ya existe. Verificando permisos..."
        
        if ! check_and_fix_permissions "$DOCKER_DIR"; then
            error "No se pueden corregir los permisos de $DOCKER_DIR"
            return 1
        fi
        
        # Verificar y corregir permisos de subdirectorios
        if [ -d "$DOCKER_DIR/src" ]; then
            if ! check_and_fix_permissions "$DOCKER_DIR/src"; then
                error "No se pueden corregir los permisos de $DOCKER_DIR/src"
                return 1
            fi
            
            # Limpiar el directorio src de forma segura
            if ! safe_clean_directory "$DOCKER_DIR/src"; then
                error "No se pudo limpiar el directorio $DOCKER_DIR/src"
                return 1
            fi
        else
            # Crear directorio src con permisos correctos
            if ! mkdir -p "$DOCKER_DIR/src"; then
                error "No se pudo crear el directorio $DOCKER_DIR/src"
                return 1
            fi
            chmod 755 "$DOCKER_DIR/src"
        fi
    else
        # Crear toda la estructura desde cero
        if ! mkdir -p "$DOCKER_DIR/src" "$DOCKER_DIR/apache-logs" "$DOCKER_DIR/postgres-backups"; then
            error "No se pudo crear la estructura de directorios"
            return 1
        fi
        # Establecer permisos correctos
        chmod 755 "$DOCKER_DIR" "$DOCKER_DIR/src" "$DOCKER_DIR/apache-logs" "$DOCKER_DIR/postgres-backups"
        success "Estructura de directorios creada en: $DOCKER_DIR/"
    fi
    
    # Crear subcarpeta con nombre del proyecto dentro de src
    process "Creando directorio del proyecto: $DOCKER_DIR/src/$PROJECT_NAME"
    if ! mkdir -p "$DOCKER_DIR/src/$PROJECT_NAME"; then
        error "No se pudo crear la subcarpeta del proyecto"
        return 1
    fi
    
    # Establecer permisos correctos para la carpeta del proyecto
    if ! chmod 755 "$DOCKER_DIR/src/$PROJECT_NAME"; then
        warning "No se pudieron establecer los permisos automáticamente en $DOCKER_DIR/src/$PROJECT_NAME"
        info "Puedes establecerlos manualmente después:"
        echo "  chmod 755 \"$DOCKER_DIR/src/$PROJECT_NAME\""
    fi
    
    success "Estructura de directorios creada: $DOCKER_DIR/src/$PROJECT_NAME/"
    return 0
}

# Crear archivo .env
create_env_file() {
    process "Creando archivo de configuración .env..."
    
    find_available_ports
    
    cat > "$DOCKER_DIR/.env" << EOF
# Configuración de la aplicación
APP_NAME=$PROJECT_NAME
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost:${WEB_PORT}

# Configuración de base de datos
DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432  # Puerto INTERNO del contenedor (SIEMPRE 5432)
DB_DATABASE=${PROJECT_NAME}_db
DB_USERNAME=postgres
DB_PASSWORD=password

# Configuración de PostgreSQL
POSTGRES_DB=${PROJECT_NAME}_db
POSTGRES_USER=postgres
POSTGRES_PASSWORD=password

# Configuración de Docker
PHP_VERSION=${PHP_VERSION}
WEB_PORT=${WEB_PORT}
DB_EXTERNAL_PORT=${DB_PORT}  # Puerto EXPUESTO en el host

# Configuración específica del framework
FRAMEWORK=${FRAMEWORK}
PROJECT_NAME=${PROJECT_NAME}
EOF

    # Verificar que el archivo se creó y establecer permisos
    if [ ! -f "$DOCKER_DIR/.env" ]; then
        error "No se pudo crear el archivo .env"
        return 1
    fi
    
    chmod 644 "$DOCKER_DIR/.env"
    success "Archivo .env creado con puertos: Web → ${WEB_PORT}, DB Host → ${DB_PORT}"
    return 0
}

# Crear configuración de Apache
create_apache_config() {
    process "Creando configuración de Apache..."
    
    # Configuración diferente para Yii2 Advanced
    if [ "$FRAMEWORK" = "yii2-advanced" ]; then
        cat > "$DOCKER_DIR/000-default.conf" << EOF
<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/frontend/web
    <Directory /var/www/html/frontend/web>
        AllowOverride All
        Require all granted
        Options Indexes FollowSymLinks
    </Directory>
    ErrorLog \${APACHE_LOG_DIR}/error.log
    CustomLog \${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
EOF
    else
        cat > "$DOCKER_DIR/000-default.conf" << EOF
<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/public
    <Directory /var/www/html>
        AllowOverride All
        Require all granted
        Options Indexes FollowSymLinks
    </Directory>
    ErrorLog \${APACHE_LOG_DIR}/error.log
    CustomLog \${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
EOF
    fi

    if [ ! -f "$DOCKER_DIR/000-default.conf" ]; then
        error "No se pudo crear la configuración de Apache"
        return 1
    fi
    
    chmod 644 "$DOCKER_DIR/000-default.conf"
    success "Configuración de Apache creada"
    return 0
}

# Crear Dockerfile específico para cada framework - CORREGIDO
create_dockerfile() {
    process "Creando Dockerfile para PHP $PHP_VERSION..."
    
    case "$FRAMEWORK" in
        "yii2-basic"|"yii2-advanced")
            create_yii2_dockerfile
            ;;
        "yii3")
            create_yii3_dockerfile
            ;;
        "laravel")
            create_laravel_dockerfile
            ;;
    esac
    
    if [ ! -f "$DOCKER_DIR/Dockerfile" ]; then
        error "No se pudo crear el Dockerfile"
        return 1
    fi
    
    chmod 644 "$DOCKER_DIR/Dockerfile"
    return 0
}

create_yii2_dockerfile() {
    cat > "$DOCKER_DIR/Dockerfile" << 'EOF'
ARG PHP_VERSION=7.4
FROM php:${PHP_VERSION}-apache

# Actualizar lista de paquetes y instalar dependencias
RUN apt-get update && apt-get install -y \
    libpq-dev \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    zip \
    unzip \
    git \
    curl \
    gnupg \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# Configurar extensiones de PHP para PHP 7.4 - CONFIGURACIÓN CORREGIDA
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) \
        pdo \
        pdo_pgsql \
        pgsql \
        zip \
        gd \
        bcmath \
        opcache \
    && a2enmod rewrite

# Instalar Composer
RUN curl -sS https://getcomposer.org/installer | php -- \
    --install-dir=/usr/local/bin \
    --filename=composer

# Configurar Composer para evitar timeouts
RUN composer config -g process-timeout 1200 && \
    composer config -g repo.packagist composer https://packagist.org

# Instalar extensiones adicionales necesarias para Yii2
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli

COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
RUN a2ensite 000-default.conf
RUN chown -R www-data:www-data /var/www/html
WORKDIR /var/www/html

# Configuraciones PHP optimizadas para PHP 7.4
RUN echo "memory_limit = 512M" > /usr/local/etc/php/conf.d/memory.ini && \
    echo "upload_max_filesize = 64M" >> /usr/local/etc/php/conf.d/uploads.ini && \
    echo "post_max_size = 64M" >> /usr/local/etc/php/conf.d/uploads.ini && \
    echo "max_execution_time = 300" >> /usr/local/etc/php/conf.d/timeouts.ini && \
    echo "max_input_time = 120" >> /usr/local/etc/php/conf.d/timeouts.ini

EXPOSE 80
EOF
    success "Dockerfile para Yii2 creado"
}

create_yii3_dockerfile() {
    cat > "$DOCKER_DIR/Dockerfile" << 'EOF'
ARG PHP_VERSION=8.4
FROM php:${PHP_VERSION}-apache

# Actualizar lista de paquetes y instalar dependencias
RUN apt-get update && apt-get install -y \
    libpq-dev \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    zip \
    unzip \
    git \
    curl \
    gnupg \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# Configurar extensiones de PHP - CONFIGURACIÓN CORREGIDA
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) \
        pdo \
        pdo_pgsql \
        pgsql \
        zip \
        gd \
        bcmath \
        opcache \
    && a2enmod rewrite

# Instalar Composer
RUN curl -sS https://getcomposer.org/installer | php -- \
    --install-dir=/usr/local/bin \
    --filename=composer

# Configurar Composer para evitar timeouts
RUN composer config -g process-timeout 1200 && \
    composer config -g repo.packagist composer https://packagist.org

COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
RUN a2ensite 000-default.conf
RUN chown -R www-data:www-data /var/www/html
WORKDIR /var/www/html

# Configuraciones PHP optimizadas
RUN echo "memory_limit = 512M" > /usr/local/etc/php/conf.d/memory.ini && \
    echo "upload_max_filesize = 128M" >> /usr/local/etc/php/conf.d/uploads.ini && \
    echo "post_max_size = 128M" >> /usr/local/etc/php/conf.d/uploads.ini && \
    echo "max_execution_time = 300" >> /usr/local/etc/php/conf.d/timeouts.ini && \
    echo "max_input_time = 120" >> /usr/local/etc/php/conf.d/timeouts.ini && \
    echo "opcache.enable=1" >> /usr/local/etc/php/conf.d/opcache.ini && \
    echo "opcache.memory_consumption=256" >> /usr/local/etc/php/conf.d/opcache.ini

EXPOSE 80
EOF
    success "Dockerfile para Yii3 creado"
}

create_laravel_dockerfile() {
    cat > "$DOCKER_DIR/Dockerfile" << 'EOF'
ARG PHP_VERSION=8.3
FROM php:${PHP_VERSION}-apache

# Actualizar lista de paquetes y instalar dependencias
RUN apt-get update && apt-get install -y \
    libpq-dev \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    zip \
    unzip \
    git \
    curl \
    gnupg \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# Configurar extensiones de PHP - CONFIGURACIÓN CORREGIDA
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) \
        pdo \
        pdo_pgsql \
        pgsql \
        zip \
        gd \
        bcmath \
        opcache \
    && a2enmod rewrite

# Instalar Composer
RUN curl -sS https://getcomposer.org/installer | php -- \
    --install-dir=/usr/local/bin \
    --filename=composer

# Configurar Composer para evitar timeouts
RUN composer config -g process-timeout 1200 && \
    composer config -g repo.packagist composer https://packagist.org

# Extensiones adicionales para Laravel
RUN docker-php-ext-install exif && docker-php-ext-enable exif

COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
RUN a2ensite 000-default.conf
RUN chown -R www-data:www-data /var/www/html
WORKDIR /var/www/html

# Configuraciones PHP optimizadas
RUN echo "memory_limit = 512M" > /usr/local/etc/php/conf.d/memory.ini && \
    echo "upload_max_filesize = 128M" >> /usr/local/etc/php/conf.d/uploads.ini && \
    echo "post_max_size = 128M" >> /usr/local/etc/php/conf.d/uploads.ini && \
    echo "max_execution_time = 300" >> /usr/local/etc/php/conf.d/timeouts.ini && \
    echo "max_input_time = 120" >> /usr/local/etc/php/conf.d/timeouts.ini && \
    echo "opcache.enable=1" >> /usr/local/etc/php/conf.d/opcache.ini

EXPOSE 80
EOF
    success "Dockerfile para Laravel creado"
}

# Crear docker-compose.yml MEJORADO
create_docker_compose() {
    process "Creando docker-compose.yml..."
    
    # Configurar volumen según el tipo de proyecto
    local volume_config="./src/${PROJECT_NAME}:/var/www/html"
    
    cat > "$DOCKER_DIR/docker-compose.yml" << EOF
version: '3.8'

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        PHP_VERSION: \${PHP_VERSION}
    ports:
      - "\${WEB_PORT}:80"
    volumes:
      - ${volume_config}
      - ./apache-logs:/var/log/apache2
    depends_on:
      db:
        condition: service_healthy
    networks:
      - backend-network
    env_file:
      - .env
    container_name: ${PROJECT_NAME}-web
    restart: unless-stopped
    dns:
      - 8.8.8.8
      - 8.8.4.4
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  db:
    image: postgres:15
    environment:
      POSTGRES_DB: \${POSTGRES_DB}
      POSTGRES_USER: \${POSTGRES_USER}
      POSTGRES_PASSWORD: \${POSTGRES_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./postgres-backups:/backups
    networks:
      - backend-network
    container_name: ${PROJECT_NAME}-db
    restart: unless-stopped
    ports:
      - "\${DB_EXTERNAL_PORT}:5432"
    dns:
      - 8.8.8.8
      - 8.8.4.4
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER} -d \${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s

networks:
  backend-network:
    driver: bridge

volumes:
  pgdata:
    driver: local
EOF

    if [ ! -f "$DOCKER_DIR/docker-compose.yml" ]; then
        error "No se pudo crear el archivo docker-compose.yml"
        return 1
    fi
    
    chmod 644 "$DOCKER_DIR/docker-compose.yml"
    success "Archivo docker-compose.yml creado"
    return 0
}

# Función para ejecutar comandos en el directorio docker
run_in_docker_dir() {
    local cmd="$1"
    
    if [ ! -d "$DOCKER_DIR" ]; then
        error "Directorio $DOCKER_DIR no encontrado"
        return 1
    fi
    
    # Verificar permisos antes de continuar
    if ! check_and_fix_permissions "$DOCKER_DIR"; then
        error "No se puede acceder a $DOCKER_DIR por problemas de permisos"
        return 1
    fi
    
    cd "$DOCKER_DIR" || { error "No se puede acceder al directorio $DOCKER_DIR"; return 1; }
    eval "$cmd"
    local result=$?
    cd "$CURRENT_DIR" || return 1
    return $result
}

# Función MEJORADA para esperar a que PostgreSQL esté listo
wait_for_postgres() {
    process "Esperando a que PostgreSQL esté listo..."
    local max_attempts=30
    local attempt=1
    
    while [ $attempt -le $max_attempts ]; do
        if run_in_docker_dir "docker-compose exec -T db pg_isready -U postgres > /dev/null 2>&1"; then
            success "PostgreSQL está listo después de $attempt intentos"
            
            # Esperar un poco más para asegurar que esté completamente listo
            sleep 5
            
            # Verificar que la base de datos específica existe, si no crearla
            process "Verificando base de datos ${PROJECT_NAME}_db..."
            if ! run_in_docker_dir "docker-compose exec -T db psql -U postgres -d ${PROJECT_NAME}_db -c 'SELECT 1' > /dev/null 2>&1"; then
                process "Creando base de datos ${PROJECT_NAME}_db..."
                if run_in_docker_dir "docker-compose exec -T db createdb -U postgres ${PROJECT_NAME}_db"; then
                    success "Base de datos ${PROJECT_NAME}_db creada exitosamente"
                else
                    error "Error creando la base de datos ${PROJECT_NAME}_db"
                    return 1
                fi
            else
                success "Base de datos ${PROJECT_NAME}_db ya existe"
            fi
            
            sleep 2
            return 0
        fi
        
        if [ $attempt -eq 1 ]; then
            process "Esperando a que PostgreSQL se inicialice..."
        else
            process "Intento $attempt/$max_attempts - PostgreSQL aún no está listo..."
        fi
        
        sleep 3
        attempt=$((attempt + 1))
    done
    
    error "PostgreSQL no está respondiendo después de $max_attempts intentos"
    run_in_docker_dir 'docker-compose logs db'
    return 1
}

# Construir y levantar contenedores CON MEJOR MANEJO DE ERRORES
build_docker_containers() {
    process "Construyendo contenedores Docker..."
    
    if [ ! -d "$DOCKER_DIR" ]; then
        error "El directorio $DOCKER_DIR no existe. No se pueden construir los contenedores."
        return 1
    fi
    
    # Verificar permisos antes de continuar
    if ! check_and_fix_permissions "$DOCKER_DIR"; then
        error "No se pueden construir los contenedores por problemas de permisos"
        return 1
    fi
    
    # Parar contenedores existentes
    process "Deteniendo contenedores existentes..."
    if ! run_in_docker_dir 'docker-compose down 2>/dev/null'; then
        warning "No se pudieron detener contenedores existentes (puede ser normal si no hay contenedores)"
    fi
    
    # Construir imágenes con mejor manejo de errores
    process "Construyendo imágenes Docker..."
    
    # Primero intentar construir sin cache para detectar errores temprano
    if run_in_docker_dir "docker-compose build --no-cache --build-arg PHP_VERSION=${PHP_VERSION} 2>&1 | tee build.log"; then
        success "Imágenes construidas exitosamente sin cache"
    else
        error "Error construyendo las imágenes Docker sin cache"
        process "Analizando errores de construcción..."
        
        # Mostrar los últimos errores del log
        if [ -f "$DOCKER_DIR/build.log" ]; then
            error "Últimas líneas del log de construcción:"
            tail -20 "$DOCKER_DIR/build.log" | while read -r line; do
                echo "  $line"
            done
        fi
        
        # Intentar con cache como fallback
        warning "Intentando construcción con cache..."
        if ! run_in_docker_dir "docker-compose build --build-arg PHP_VERSION=${PHP_VERSION}"; then
            error "Error crítico en la construcción de imágenes Docker"
            return 1
        fi
    fi
    
    # Levantar contenedores
    process "Iniciando contenedores..."
    if ! run_in_docker_dir 'docker-compose up -d'; then
        error "Error iniciando contenedores"
        run_in_docker_dir 'docker-compose logs'
        return 1
    fi
    
    # Esperar a que PostgreSQL esté listo
    if ! wait_for_postgres; then
        error "La base de datos no se inicializó correctamente"
        return 1
    fi
    
    # Verificar estado de los contenedores
    process "Verificando estado de los contenedores..."
    if run_in_docker_dir 'docker-compose ps | grep -q "Up"'; then
        success "Contenedores Docker listos y ejecutándose"
        return 0
    else
        error "Los contenedores no se iniciaron correctamente"
        run_in_docker_dir 'docker-compose ps'
        return 1
    fi
}

# Ejecutar comandos en el contenedor web con reintentos MEJORADO
exec_in_web() {
    local cmd="$1"
    local max_attempts=3
    local attempt=1
    
    sleep 10
    
    while [ $attempt -le $max_attempts ]; do
        process "Ejecutando comando (intento $attempt/$max_attempts)..."
        
        if run_in_docker_dir "docker-compose exec -T web bash -c \"$cmd\""; then
            return 0
        fi
        
        if [ $attempt -lt $max_attempts ]; then
            warning "Intento $attempt falló. Reintentando en 10 segundos..."
            sleep 10
        fi
        
        attempt=$((attempt + 1))
    done
    
    error "Error ejecutando comando después de $max_attempts intentos: $cmd"
    return 1
}

# Función MEJORADA para crear proyectos con Composer
create_project_with_composer() {
    local framework_cmd="$1"
    local project_name="$2"
    local install_dir="$3"
    
    process "Descargando proyecto $framework_cmd..."
    
    exec_in_web "composer config -g process-timeout 1200"
    exec_in_web "composer config -g repo.packagist composer https://packagist.org"
    exec_in_web "composer clear-cache"
    
    # Opciones específicas por framework
    if [[ "$FRAMEWORK" == yii2* ]]; then
        local composer_options=(
            "--prefer-dist --no-progress --no-interaction"
            "--prefer-dist --no-dev --no-progress --no-interaction"
            "--prefer-source --no-progress --no-interaction"
        )
    else
        local composer_options=(
            "--prefer-dist --no-dev --no-progress --no-interaction"
            "--prefer-dist --no-progress --no-interaction"
            "--prefer-source --no-progress --no-interaction"
        )
    fi
    
    for options in "${composer_options[@]}"; do
        process "Intentando con opciones: $options"
        
        # Limpiar directorio temporal si existe
        exec_in_web "rm -rf /tmp/${project_name} 2>/dev/null || true"
        
        if exec_in_web "composer create-project $options $framework_cmd /tmp/${project_name}"; then
            # VERIFICAR que el proyecto se creó correctamente
            if exec_in_web "[ -d /tmp/${project_name} ] && [ -f /tmp/${project_name}/composer.json ]"; then
                success "Proyecto descargado correctamente"
                
                # Mover a la ubicación final
                exec_in_web "rm -rf ${install_dir}/* 2>/dev/null || true"
                exec_in_web "sh -c 'mv /tmp/${project_name}/* ${install_dir}/ 2>/dev/null || true'"
                exec_in_web "sh -c 'mv /tmp/${project_name}/.* ${install_dir}/ 2>/dev/null || true'"
                exec_in_web "rm -rf /tmp/${project_name}"
                
                # Instalar dependencias si es necesario
                if exec_in_web "[ ! -d ${install_dir}/vendor ] && [ -f ${install_dir}/composer.json ]"; then
                    process "Instalando dependencias..."
                    if exec_in_web "cd ${install_dir} && composer install --no-dev --no-progress --no-interaction"; then
                        success "Dependencias instaladas correctamente"
                    else
                        warning "No se pudieron instalar las dependencias automáticamente"
                    fi
                fi
                
                return 0
            fi
        fi
        
        warning "Intento falló con opciones: $options"
        exec_in_web "rm -rf /tmp/${project_name} 2>/dev/null || true"
    done
    
    return 1
}

# Crear proyecto Yii2 Basic
create_yii2_basic_project() {
    process "Creando proyecto Yii2 Basic: ${PROJECT_NAME}"
    
    if ! create_project_with_composer "yiisoft/yii2-app-basic" "${PROJECT_NAME}" "/var/www/html"; then
        error "Error al crear proyecto Yii2 Basic después de múltiples intentos"
        return 1
    fi
    
    # Configuraciones adicionales para Yii2 Basic
    exec_in_web "chown -R www-data:www-data /var/www/html"
    exec_in_web "chmod -R 755 /var/www/html/runtime"
    exec_in_web "chmod -R 755 /var/www/html/web/assets"
    
    success "Proyecto Yii2 Basic '${PROJECT_NAME}' creado correctamente"
    return 0
}

# Crear proyecto Yii2 Advanced
create_yii2_advanced_project() {
    process "Creando proyecto Yii2 Advanced: ${PROJECT_NAME}"
    
    if ! create_project_with_composer "yiisoft/yii2-app-advanced" "${PROJECT_NAME}" "/var/www/html"; then
        error "Error al crear proyecto Yii2 Advanced después de múltiples intentos"
        return 1
    fi
    
    # Configuraciones adicionales para Yii2 Advanced
    exec_in_web "chown -R www-data:www-data /var/www/html"
    exec_in_web "chmod -R 755 /var/www/html/frontend/runtime"
    exec_in_web "chmod -R 755 /var/www/html/backend/runtime"
    exec_in_web "chmod -R 755 /var/www/html/frontend/web/assets"
    exec_in_web "chmod -R 755 /var/www/html/backend/web/assets"
    
    # Inicializar el proyecto advanced
    process "Inicializando Yii2 Advanced..."
    if exec_in_web "cd /var/www/html && php init --env=Development --overwrite=All"; then
        success "Yii2 Advanced inicializado correctamente"
    else
        warning "No se pudo inicializar Yii2 Advanced automáticamente"
    fi
    
    success "Proyecto Yii2 Advanced '${PROJECT_NAME}' creado correctamente"
    return 0
}

# Crear proyecto Yii3
create_yii3_project() {
    process "Creando proyecto Yii3: ${PROJECT_NAME}"
    
    if ! create_project_with_composer "yiisoft/yii-project-template" "${PROJECT_NAME}" "/var/www/html"; then
        error "Error al crear proyecto Yii3 después de múltiples intentos"
        return 1
    fi
    
    exec_in_web "chown -R www-data:www-data /var/www/html"
    
    success "Proyecto Yii3 '${PROJECT_NAME}' creado correctamente"
    return 0
}

# Crear proyecto Laravel
create_laravel_project() {
    process "Creando proyecto Laravel: ${PROJECT_NAME}"
    
    if ! create_project_with_composer "laravel/laravel" "${PROJECT_NAME}" "/var/www/html"; then
        error "Error al crear proyecto Laravel después de múltiples intentos"
        return 1
    fi
    
    exec_in_web "chown -R www-data:www-data /var/www/html"
    exec_in_web "chmod -R 775 /var/www/html/storage"
    exec_in_web "chmod -R 775 /var/www/html/bootstrap/cache"
    
    # Configurar .env para Laravel
    process "Configurando Laravel..."
    exec_in_web "cd /var/www/html && cp .env.example .env 2>/dev/null || true"
    
    exec_in_web "cd /var/www/html && cat > .env << 'ENDFILE'
APP_NAME=${PROJECT_NAME}
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:${WEB_PORT}

DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432
DB_DATABASE=${PROJECT_NAME}_db
DB_USERNAME=postgres
DB_PASSWORD=password

LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

MEMCACHED_HOST=127.0.0.1

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME=\"\${APP_NAME}\"
ENDFILE"
    
    exec_in_web "cd /var/www/html && php artisan key:generate"
    
    success "Proyecto Laravel '${PROJECT_NAME}' creado correctamente"
    return 0
}

# Crear el proyecto según el framework seleccionado
create_framework_project() {
    process "Iniciando creación del proyecto ${PROJECT_NAME} con ${FRAMEWORK}..."
    
    process "Probando conexión a internet desde el contenedor..."
    if ! exec_in_web "curl -s --connect-timeout 30 https://packagist.org > /dev/null"; then
        warning "El contenedor no puede conectarse a Packagist. Esto puede causar problemas."
        exec_in_web "cat /etc/resolv.conf"
    else
        success "Conexión a internet verificada desde el contenedor"
    fi
    
    case "$FRAMEWORK" in
        "yii2-basic")
            create_yii2_basic_project
            ;;
        "yii2-advanced")
            create_yii2_advanced_project
            ;;
        "yii3")
            create_yii3_project
            ;;
        "laravel")
            create_laravel_project
            ;;
        *)
            error "Framework no válido: $FRAMEWORK"
            return 1
            ;;
    esac
}

# Configuración MEJORADA de base de datos
configure_database() {
    process "Configurando base de datos para $FRAMEWORK..."
    
    sleep 10
    
    case "$FRAMEWORK" in
        "yii2-basic")
            configure_yii2_basic_db
            ;;
        "yii2-advanced")
            configure_yii2_advanced_db
            ;;
        "yii3")
            configure_yii3_db
            ;;
        "laravel")
            configure_laravel_db
            ;;
    esac
}

configure_laravel_db() {
    process "Configurando base de datos para Laravel..."
    
    process "Verificando conexión a la base de datos..."
    if exec_in_web "cd /var/www/html && php -r \"
try {
    \\\$pdo = new PDO('pgsql:host=db;port=5432;dbname=${PROJECT_NAME}_db', 'postgres', 'password');
    \\\$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo 'Conexión a BD exitosa' . PHP_EOL;
} catch (PDOException \\\$e) {
    echo 'Error de conexión: ' . \\\$e->getMessage() . PHP_EOL;
    exit(1);
}
\""; then
        success "Conexión a la base de datos verificada"
    else
        error "No se pudo conectar a la base de datos"
        return 1
    fi
    
    process "Ejecutando migraciones de Laravel..."
    if exec_in_web "cd /var/www/html && php artisan migrate --force"; then
        success "Migraciones de Laravel ejecutadas correctamente"
    else
        warning "Las migraciones de Laravel fallaron o no son necesarias"
    fi
    return 0
}

configure_yii3_db() {
    process "Configurando base de datos para Yii3..."
    if exec_in_web "cd /var/www/html && php ./yii migrate/up --interactive=0"; then
        success "Migraciones de Yii3 ejecutadas correctamente"
    else
        warning "Las migraciones de Yii3 fallaron o no son necesarias"
    fi
    return 0
}

# Configuración MEJORADA para Yii2 Basic
configure_yii2_basic_db() {
    process "Configurando base de datos para Yii2 Basic..."
    
    # Primero verificar que Yii2 esté instalado correctamente
    process "Verificando instalación de Yii2 Basic..."
    if ! exec_in_web "[ -f /var/www/html/vendor/yiisoft/yii2/Yii.php ]"; then
        error "Yii2 Basic no está instalado correctamente. No se puede configurar la base de datos."
        info "Instala las dependencias manualmente:"
        echo "  cd $DOCKER_DIR && docker-compose exec web composer install"
        return 1
    fi
    
    process "Configurando conexión a base de datos para Yii2 Basic..."
    exec_in_web "cd /var/www/html && cp config/db.php config/db.php.backup 2>/dev/null || true"
    
    exec_in_web "cd /var/www/html && cat > config/db.php << 'ENDFILE'
<?php

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'pgsql:host=db;port=5432;dbname=${PROJECT_NAME}_db',
    'username' => 'postgres',
    'password' => 'password',
    'charset' => 'utf8',
];
ENDFILE"
    
    # Deshabilitar GII en producción o si no está instalado
    exec_in_web "cd /var/www/html && cp config/web.php config/web.php.backup 2>/dev/null || true"
    exec_in_web "cd /var/www/html && sed -i \"s/'modules' => \[/'modules' => \[\\n    /*\\n    'gii' => [\\n        'class' => 'yii\\\gii\\\Module',\\n    ],\\n    */\\n/g\" config/web.php 2>/dev/null || true"
    
    process "Intentando ejecutar migraciones de Yii2 Basic..."
    if exec_in_web "cd /var/www/html && php yii migrate/up --interactive=0"; then
        success "Migraciones de Yii2 Basic ejecutadas correctamente"
    else
        warning "Las migraciones de Yii2 Basic fallaron o no son necesarias"
    fi
    
    return 0
}

# Configuración para Yii2 Advanced
configure_yii2_advanced_db() {
    process "Configurando base de datos para Yii2 Advanced..."
    
    # Verificar instalación
    if ! exec_in_web "[ -f /var/www/html/vendor/yiisoft/yii2/Yii.php ]"; then
        error "Yii2 Advanced no está instalado correctamente."
        return 1
    fi
    
    # Configurar base de datos común
    exec_in_web "cd /var/www/html && cat > common/config/main-local.php << 'ENDFILE'
<?php
return [
    'components' => [
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'pgsql:host=db;port=5432;dbname=${PROJECT_NAME}_db',
            'username' => 'postgres',
            'password' => 'password',
            'charset' => 'utf8',
        ],
    ],
];
ENDFILE"
    
    # Configurar base de datos para frontend y backend
    for app in frontend backend; do
        exec_in_web "cd /var/www/html && cat > ${app}/config/main-local.php << 'ENDFILE'
<?php
return [
    'components' => [
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'pgsql:host=db;port=5432;dbname=${PROJECT_NAME}_db',
            'username' => 'postgres',
            'password' => 'password',
            'charset' => 'utf8',
        ],
    ],
];
ENDFILE"
    done
    
    process "Ejecutando migraciones de Yii2 Advanced..."
    if exec_in_web "cd /var/www/html && php yii migrate/up --interactive=0"; then
        success "Migraciones de Yii2 Advanced ejecutadas correctamente"
    else
        warning "Las migraciones de Yii2 Advanced fallaron o no son necesarias"
    fi
    
    return 0
}

# Mostrar resumen final MEJORADO
show_final_summary() {
    echo ""
    success "🎉 ¡PROYECTO CREADO EXITOSAMENTE!"
    echo "=================================="
    echo ""
    info "📊 RESUMEN FINAL:"
    echo "-----------------"
    echo "  📂 Proyecto: $PROJECT_NAME"
    echo "  🚀 Framework: $FRAMEWORK"
    echo "  🐘 PHP: $PHP_VERSION"
    echo "  🌐 URL: http://localhost:${WEB_PORT}"
    echo "  🗄️  Base de datos: localhost:${DB_PORT}"
    echo "  📁 Directorio: $DOCKER_DIR/src/$PROJECT_NAME/"
    echo ""
    
    # Información específica por framework
    case "$FRAMEWORK" in
        "yii2-advanced")
            info "🌐 URLs de Yii2 Advanced:"
            echo "  Frontend: http://localhost:${WEB_PORT}"
            echo "  Backend: http://localhost:${WEB_PORT}/backend/web"
            ;;
        *)
            info "🌐 URL de la aplicación:"
            echo "  http://localhost:${WEB_PORT}"
            ;;
    esac
    echo ""
    
    info "🚀 COMANDOS ÚTILES:"
    echo "------------------"
    echo "  Iniciar proyecto: cd $DOCKER_DIR && docker-compose up -d"
    echo "  Detener proyecto: cd $DOCKER_DIR && docker-compose down"
    echo "  Ver logs: cd $DOCKER_DIR && docker-compose logs"
    echo "  Acceder a la consola: cd $DOCKER_DIR && docker-compose exec web bash"
    echo ""
    
    info "🔗 CONEXIÓN A LA BASE DE DATOS:"
    echo "------------------------------"
    echo "  Host: localhost"
    echo "  Puerto: ${DB_PORT}"
    echo "  Base de datos: ${PROJECT_NAME}_db"
    echo "  Usuario: postgres"
    echo "  Contraseña: password"
    echo ""
    
    # Instrucciones específicas por framework
    case "$FRAMEWORK" in
        "yii2-basic"|"yii2-advanced")
            info "🔧 INSTRUCCIONES ESPECÍFICAS PARA YII2:"
            echo "-------------------------------------"
            echo "  Si hay problemas con dependencias:"
            echo "    cd $DOCKER_DIR && docker-compose exec web composer install"
            if [ "$FRAMEWORK" = "yii2-advanced" ]; then
                echo "  Para inicializar el proyecto:"
                echo "    cd $DOCKER_DIR && docker-compose exec web php init"
            fi
            echo "  Para ejecutar migraciones:"
            echo "    cd $DOCKER_DIR && docker-compose exec web php yii migrate/up --interactive=0"
            echo "  Para instalar módulos de desarrollo:"
            echo "    cd $DOCKER_DIR && docker-compose exec web composer require --dev yiisoft/yii2-gii"
            echo "    cd $DOCKER_DIR && docker-compose exec web composer require --dev yiisoft/yii2-debug"
            echo ""
            ;;
        "yii3")
            info "🔧 INSTRUCCIONES ESPECÍFICAS PARA YII3:"
            echo "-------------------------------------"
            echo "  Para ejecutar migraciones: cd $DOCKER_DIR && docker-compose exec web php ./yii migrate/up --interactive=0"
            echo ""
            ;;
        "laravel")
            info "🔧 INSTRUCCIONES ESPECÍFICAS PARA LARAVEL:"
            echo "----------------------------------------"
            echo "  Para ejecutar migraciones: cd $DOCKER_DIR && docker-compose exec web php artisan migrate"
            echo "  Para generar key: cd $DOCKER_DIR && docker-compose exec web php artisan key:generate"
            echo ""
            ;;
    esac
    
    info "📝 PRÓXIMOS PASOS:"
    echo "-----------------"
    echo "  1. Accede a la URL mostrada arriba para ver tu aplicación"
    echo "  2. Configura la base de datos si es necesario"
    echo "  3. ¡Comienza a desarrollar!"
    echo ""
}

# Función principal
main() {
    clear
    echo "========================================"
    echo "  GENERADOR DE PROYECTOS CON DOCKER v1.1"
    echo "========================================"
    echo ""
    
    check_docker_installation
    check_docker_permissions
    check_internet_connection
    
    select_framework
    
    get_project_name
    
    if ! create_directory_structure; then
        error "Error creando la estructura de directorios"
        exit 1
    fi
    
    if ! create_env_file; then
        error "Error creando el archivo .env"
        exit 1
    fi
    
    if ! create_apache_config; then
        error "Error creando la configuración de Apache"
        exit 1
    fi
    
    if ! create_dockerfile; then
        error "Error creando el Dockerfile"
        exit 1
    fi
    
    if ! create_docker_compose; then
        error "Error creando docker-compose.yml"
        exit 1
    fi
    
    if build_docker_containers; then
        process "Esperando inicialización completa de servicios..."
        sleep 20
        
        if create_framework_project; then
            process "Configurando la aplicación..."
            if configure_database; then
                show_final_summary
            else
                warning "Proyecto creado pero la configuración de BD tuvo problemas menores"
                show_final_summary
            fi
        else
            error "Error al crear el proyecto del framework"
            exit 1
        fi
    else
        error "Error al construir los contenedores Docker"
        exit 1
    fi
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi
// Definición de la interfaz
interface Encendible {
    public function encender();
    public function apagar();
}

// Clase que implementa la interfaz
class Bombilla implements Encendible {
    public function encender() {
        echo "La bombilla está encendida\n";
    }

    public function apagar() {
        echo "La bombilla está apagada\n";
    }
}

// Uso
$miBombilla = new Bombilla();
$miBombilla->encender();  // Salida: La bombilla está encendida
$miBombilla->apagar();    // Salida: La bombilla está apagada
Ctrl+Mayús+P" para que aparezca la instancia de "Paleta de comandos" y empiece a escribir "display" para filtrar y mostrar el comando "Configure Display Language"
Para solucionar esto, siga estos pasos de instalación manual:

Asegúrese de que su sistema esté actualizado e instale los paquetes necesarios:

texto
sudo apt update
sudo apt upgrade
sudo apt install build-essential git dkms linux-headers-$(uname -r)
Clone la fuente del controlador rtl8188fu desde el repositorio oficial de GitHub:

texto
git clone https://github.com/kelebek333/rtl8188fu.git
Cambiar el directorio al repositorio clonado:

texto
cd rtl8188fu
Agregue el controlador a DKMS:

texto
sudo dkms add .
Construya el controlador:

texto
sudo dkms build rtl8188fu/1.0
Instalar el controlador:

texto
sudo dkms install rtl8188fu/1.0
Copiar el archivo de firmware:

texto
sudo cp ./firmware/rtl8188fufw.bin /lib/firmware/rtlwifi/
Cargar el controlador:

texto
sudo modprobe rtl8188fu
Reinicie su sistema.
settings.json

{
    "php.docblock.propertySnippet": {},
    "editor.fontFamily": "'Fira Code'",
    "editor.fontLigatures": true,
    "editor.fontSize": 14,                      // Tamaño de fuente cómodo para lectura
    "editor.lineHeight": 22,                    // Espaciado entre líneas para mejor claridad
    "editor.fontWeight": "400",                 // Peso regular de la fuente
    "editor.renderWhitespace": "all",          // Muestra espacios y tabulaciones para mejor control del código
    "editor.cursorSmoothCaretAnimation": "on",// Animación suave del cursor
    "editor.minimap.enabled": false,            // Desactiva minimapa para menos distracciones (opcional)
    "workbench.colorTheme": "Default Dark+",   // Tema oscuro para menos fatiga visual (puedes cambiarlo)
    "editor.smoothScrolling": true,
    "sqltools.connections": [
        {
            "previewLimit": 50,
            "server": "localhost",
            "port": 5432,
            "driver": "PostgreSQL",
            "name": "indicadires_jobran",
            "username": "jdrodriguezg",
            "database": "indicadores_jobran"
        },
        {
            "previewLimit": 50,
            "server": "localhost",
            "port": 5432,
            "driver": "PostgreSQL",
            "database": "indicadores_jobran",
            "username": "postgres",
            "name": "Localhost-jobran"
        }
    ],
    "editor.guides.indentation": true // Muestra guías de indentación para mejor estructura visual
}

###Inicializacion

git init 			 			#inicializa un nuevo repositorio
git clone <repo-url> 			#clona desde una url

###desarrollo diario
git status 			 			#Muestra el estado de la rama
git add <archivo>	 			#a~adir cambios al area de preparacion
git commit -m "mensaje"			#confirma los cambios con un mensaje

###Gestion de ramas
git branch						#lista las ramas
git branch <nombre-rama>		#crea una rama nueva
git switch <nombre-rama>		#cambia a una rama
git branch -d <nombre-rama>		#elimina una rama

###Integracion y colaboracion
git merge <rama>				#fusiona los cambios de una rama
git remote add <nombre> <url> 	#a~ade un repositorio remoto
git push <remoto> <rama>
git pull <remoto> <rama>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Manejo de Eventos en HTML y JavaScript</title>
    <script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
    <style>
        :root {
            --primary: #2563eb;
            --secondary: #4b5563;
            --accent: #10b981;
            --light: #f3f4f6;
            --dark: #1f2937;
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background-color: #f9fafb;
            color: var(--dark);
            line-height: 1.6;
            padding: 20px;
        }
        
        header {
            text-align: center;
            margin-bottom: 40px;
            padding: 20px;
            background: linear-gradient(135deg, var(--primary), var(--accent));
            color: white;
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        
        h1 {
            font-size: 2.5rem;
            margin-bottom: 10px;
        }
        
        .description {
            max-width: 800px;
            margin: 0 auto 30px;
            font-size: 1.1rem;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        
        .download-btn {
            display: inline-block;
            background-color: var(--accent);
            color: white;
            padding: 12px 24px;
            border-radius: 5px;
            text-decoration: none;
            font-weight: bold;
            margin: 20px 0;
            cursor: pointer;
            border: none;
            transition: background-color 0.3s;
        }
        
        .download-btn:hover {
            background-color: #059669;
        }
        
        .events-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
            gap: 20px;
            margin-bottom: 40px;
        }
        
        .event-card {
            background-color: white;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            transition: transform 0.3s, box-shadow 0.3s;
        }
        
        .event-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
        }
        
        .event-card h3 {
            color: var(--primary);
            margin-bottom: 15px;
            border-bottom: 2px solid var(--light);
            padding-bottom: 10px;
        }
        
        .event-card p {
            margin-bottom: 15px;
        }
        
        .code-example {
            background-color: var(--light);
            padding: 12px;
            border-radius: 5px;
            font-family: monospace;
            font-size: 0.9rem;
            overflow-x: auto;
            margin-bottom: 15px;
        }
        
        .demo-area {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            margin-bottom: 40px;
        }
        
        .demo-area h2 {
            color: var(--primary);
            margin-bottom: 20px;
            text-align: center;
        }
        
        .demo-buttons {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            justify-content: center;
        }
        
        .demo-btn {
            padding: 10px 20px;
            background-color: var(--primary);
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        
        .demo-btn:hover {
            background-color: #1d4ed8;
        }
        
        .demo-output {
            margin-top: 20px;
            padding: 15px;
            background-color: var(--light);
            border-radius: 5px;
            min-height: 100px;
        }
        
        footer {
            text-align: center;
            margin-top: 40px;
            padding: 20px;
            color: var(--secondary);
        }
        
        @media (max-width: 768px) {
            .events-grid {
                grid-template-columns: 1fr;
            }
            
            h1 {
                font-size: 2rem;
            }
        }
    </style>
</head>
<body>
    <header>
        <h1>Manejo de Eventos en HTML y JavaScript</h1>
        <p class="description">Guía completa de todas las formas de manejar eventos en HTML y JavaScript con ejemplos prácticos y la posibilidad de descargar la información en formato Excel.</p>
    </header>

    <div class="container">
        <button class="download-btn" onclick="exportToExcel()">Descargar en Excel</button>

        <div class="events-grid">
            <div class="event-card">
                <h3>Atributos HTML inline</h3>
                <p>Manejo de eventos directamente en los elementos HTML usando atributos como onclick, onmouseover, etc.</p>
                <div class="code-example">
                    &lt;button onclick="miFuncion()"&gt;Click me&lt;/button&gt;
                </div>
            </div>

            <div class="event-card">
                <h3>Propiedades del objeto DOM</h3>
                <p>Asignación de eventos mediante propiedades del objeto DOM como element.onclick.</p>
                <div class="code-example">
                    element.onclick = function() {<br>
                    &nbsp;&nbsp;console.log('Click detectado');<br>
                    };
                </div>
            </div>

            <div class="event-card">
                <h3>addEventListener()</h3>
                <p>Método moderno y recomendado para manejar eventos. Permite múltiples manejadores para el mismo evento.</p>
                <div class="code-example">
                    element.addEventListener('click', function() {<br>
                    &nbsp;&nbsp;console.log('Click con addEventListener');<br>
                    });
                </div>
            </div>

            <div class="event-card">
                <h3>removeEventListener()</h3>
                <p>Elimina manejadores de eventos previamente agregados con addEventListener().</p>
                <div class="code-example">
                    element.removeEventListener('click', miFuncion);
                </div>
            </div>

            <div class="event-card">
                <h3>Delegación de eventos</h3>
                <p>Manejo eficiente de eventos para múltiples elementos mediante un ancestro común.</p>
                <div class="code-example">
                    parent.addEventListener('click', function(e) {<br>
                    &nbsp;&nbsp;if (e.target.tagName === 'LI') {<br>
                    &nbsp;&nbsp;&nbsp;&nbsp;console.log('Item clickeado');<br>
                    &nbsp;&nbsp;}<br>
                    });
                </div>
            </div>

            <div class="event-card">
                <h3>Eventos personalizados</h3>
                <p>Creación y despacho de eventos personalizados según las necesidades de la aplicación.</p>
                <div class="code-example">
                    const evento = new CustomEvent('miEvento', {<br>
                    &nbsp;&nbsp;detail: { mensaje: 'Hola' }<br>
                    });<br>
                    element.dispatchEvent(evento);
                </div>
            </div>

            <div class="event-card">
                <h3>Eventos de teclado</h3>
                <p>Manejo de eventos relacionados con el teclado como keydown, keyup y keypress.</p>
                <div class="code-example">
                    document.addEventListener('keydown', function(e) {<br>
                    &nbsp;&nbsp;console.log('Tecla presionada:', e.key);<br>
                    });
                </div>
            </div>

            <div class="event-card">
                <h3>Eventos de formulario</h3>
                <p>Manejo de eventos específicos de formularios como submit, change, input, focus y blur.</p>
                <div class="code-example">
                    form.addEventListener('submit', function(e) {<br>
                    &nbsp;&nbsp;e.preventDefault();<br>
                    &nbsp;&nbsp;console.log('Formulario enviado');<br>
                    });
                </div>
            </div>

            <div class="event-card">
                <h3>Eventos de mouse</h3>
                <p>Manejo de eventos del ratón como click, dblclick, mousemove, mouseover, mouseout, etc.</p>
                <div class="code-example">
                    element.addEventListener('mouseover', function() {<br>
                    &nbsp;&nbsp;console.log('Mouse sobre el elemento');<br>
                    });
                </div>
            </div>
        </div>

        <div class="demo-area">
            <h2>Zona de Demostración</h2>
            <div class="demo-buttons">
                <button class="demo-btn" onclick="demoClick()">onclick</button>
                <button class="demo-btn" id="domEvent">DOM Event</button>
                <button class="demo-btn" id="listenerEvent">addEventListener</button>
                <button class="demo-btn" onmouseover="demoMouseOver()" onmouseout="demoMouseOut()">Mouse Over/Out</button>
            </div>
            <div class="demo-output" id="demoOutput">
                El resultado de las demostraciones aparecerá aquí.
            </div>
        </div>
    </div>

    <footer>
        <p>Guía completa de manejo de eventos en HTML y JavaScript</p>
    </footer>

    <script>
        // Datos para exportar a Excel
        const eventosData = [
            ["Método", "Descripción", "Ejemplo"],
            ["Atributos HTML inline", "Manejo de eventos directamente en los elementos HTML", "&lt;button onclick=\"miFuncion()\"&gt;Click me&lt;/button&gt;"],
            ["Propiedades del objeto DOM", "Asignación de eventos mediante propiedades del objeto DOM", "element.onclick = function() { console.log('Click detectado'); };"],
            ["addEventListener()", "Método moderno y recomendado para manejar eventos", "element.addEventListener('click', function() { console.log('Click con addEventListener'); });"],
            ["removeEventListener()", "Elimina manejadores de eventos previamente agregados", "element.removeEventListener('click', miFuncion);"],
            ["Delegación de eventos", "Manejo eficiente de eventos para múltiples elementos", "parent.addEventListener('click', function(e) { if (e.target.tagName === 'LI') { console.log('Item clickeado'); } });"],
            ["Eventos personalizados", "Creación y despacho de eventos personalizados", "const evento = new CustomEvent('miEvento', { detail: { mensaje: 'Hola' } }); element.dispatchEvent(evento);"],
            ["Eventos de teclado", "Manejo de eventos relacionados con el teclado", "document.addEventListener('keydown', function(e) { console.log('Tecla presionada:', e.key); });"],
            ["Eventos de formulario", "Manejo de eventos específicos de formularios", "form.addEventListener('submit', function(e) { e.preventDefault(); console.log('Formulario enviado'); });"],
            ["Eventos de mouse", "Manejo de eventos del ratón", "element.addEventListener('mouseover', function() { console.log('Mouse sobre el elemento'); });"]
        ];

        // Función para exportar a Excel
        function exportToExcel() {
            const wb = XLSX.utils.book_new();
            const ws = XLSX.utils.aoa_to_sheet(eventosData);
            
            XLSX.utils.book_append_sheet(wb, ws, "Manejo de Eventos");
            XLSX.writeFile(wb, "Manejo_Eventos_HTML_JavaScript.xlsx");
        }

        // Configuración de demostraciones
        document.getElementById('domEvent').onclick = function() {
            document.getElementById('demoOutput').innerHTML += '<p>Evento manejado mediante propiedad DOM</p>';
        };

        document.getElementById('listenerEvent').addEventListener('click', function() {
            document.getElementById('demoOutput').innerHTML += '<p>Evento manejado con addEventListener</p>';
        });

        // Funciones de demostración
        function demoClick() {
            document.getElementById('demoOutput').innerHTML += '<p>Evento onclick ejecutado</p>';
        }

        function demoMouseOver() {
            document.getElementById('demoOutput').innerHTML += '<p>Mouse sobre el botón</p>';
        }

        function demoMouseOut() {
            document.getElementById('demoOutput').innerHTML += '<p>Mouse fuera del botón</p>';
        }

        // Evento de teclado para demostración
        document.addEventListener('keydown', function(e) {
            document.getElementById('demoOutput').innerHTML += `<p>Tecla presionada: ${e.key}</p>`;
        });
    </script>
</body>
</html>
#!/bin/bash
#Jobran Rodriguez
day_name=$(LC_TIME=es_ES.UTF-8 date -d "$year-$month-$day" +%A)
fecha_es=$(LC_TIME=es_ES.UTF-8 date -d "$year-$month-$day" +"%A %d de %B de %Y")


# Definir lista de personas (en orden) con 7 nombres (sin Aguedo)
persons=("Juan" "Jobran" "Luis" "Jose" "Gabriel" "Jonathan" "brian" "robert")

# Detectar carpeta de escritorio válida (prioriza "Escritorio" si existe, si no "Desktop")
if [ -d "$HOME/Escritorio" ]; then
    DESKTOP_DIR="$HOME/Escritorio"
elif [ -d "$HOME/Desktop" ]; then
    DESKTOP_DIR="$HOME/Desktop"
else
    # No existe ninguna, crear "Escritorio"
    DESKTOP_DIR="$HOME/Escritorio"
    mkdir -p "$DESKTOP_DIR"
    echo "No se encontró carpeta de escritorio, se ha creado '$DESKTOP_DIR'."
fi

# Crear carpeta asignacion
A="$DESKTOP_DIR/asignacion"
mkdir -p "$A"

# Definir archivo de salida
OUTPUT_FILE="$A/asignacion_caja.txt"

echo "Hola! Este script te dirá qué días te toca buscar la caja de comida este mes."
read -p "Por favor, ingresa tu nombre: " name

# Validar mes
while true; do
    read -p "Ingresa el número del mes (1-12): " month
    if [[ "$month" =~ ^[0-9]+$ ]] && (( month >= 1 && month <= 12 )); then
        break
    else
        echo "Error: Debes ingresar un número válido entre 1 y 12 para el mes."
    fi
done

# Validar año
while true; do
    read -p "Ingresa el año actual (2025): " year
    if [[ "$year" =~ ^[0-9]{4}$ ]] && (( year >= 1900 && year <= 3000 )); then
        break
    else
        echo "Error: Debes ingresar un año válido de 4 dígitos (por ejemplo, 2023)."
    fi
done

# Verificar nombre con mensaje específico
index=-1
for i in "${!persons[@]}"; do
    if [[ "${persons[$i],,}" == "${name,,}" ]]; then
        index=$i
        break
    fi
done
if [ $index -eq -1 ]; then
    echo "Error: Debes ingresar un nombre válido de las personas que trabajan en la oficina de sistemas y usan el servicio del comedor."
    exit 1
fi

# Fecha actual
current_year=$(date +%Y)
current_month=$(date +%m)
current_day=$(date +%d)

show_individual=1
if (( year < current_year )) || { (( year == current_year )) && (( month < 10#$current_month )); }; then
    show_individual=0
fi

days_in_month() {
    case $1 in
        1|3|5|7|8|10|12) echo 31 ;;
        4|6|9|11) echo 30 ;;
        2)
            if (( ($2 % 400 == 0) || (($2 % 4 == 0) && ($2 % 100 != 0)) )); then
                echo 29
            else
                echo 28
            fi
            ;;
        *)
            echo 30
            ;;
    esac
}

total_days=$(days_in_month $month $year)

# PRE-CALCULAR días laborales y asignados para evitar múltiples llamadas
declare -a laboral_days
declare -a asignacion_personas
laboral_count=0

for (( day=1; day<=total_days; day++ )); do
    wd=$(date -d "$year-$month-$day" +%u)
    if (( wd >= 1 && wd <= 5 )); then
        laboral_days[laboral_count]=$day
        assign_index=$(( laboral_count % 7 ))
        asignacion_personas[laboral_count]=${persons[$assign_index]}
        ((laboral_count++))
    fi
done

# Crear o sobreescribir archivo
echo "Asignación de búsqueda de caja para $month/$year" > "$OUTPUT_FILE"
echo "--------------------------------------------" >> "$OUTPUT_FILE"

assigned_days=()

for (( i=0; i<laboral_count; i++ )); do
    day=${laboral_days[i]}
    assigned_person=${asignacion_personas[i]}

    # Nombre del día en español, solo llamar una vez por día
    day_name=$(LC_TIME=es_ES.UTF-8 date -d "$year-$month-$day" +%A)

    # Filtrar fechas desde hoy en adelante para archivo y asignación individual
    if (( year > current_year )) || \
       { (( year == current_year )) && (( month > 10#$current_month )); } || \
       { (( year == current_year )) && (( month == 10#$current_month )) && (( day >= 10#$current_day )); }; then
        echo "$day_name $day/$month/$year : $assigned_person" >> "$OUTPUT_FILE"

        # Mostrar solo asignación individual para el usuario si corresponde
        if [[ $assigned_person == "${persons[$index]}" && show_individual -eq 1 ]]; then
            assigned_days+=("$day_name $day/$month/$year")
        fi
    fi
done

if (( show_individual == 1 )); then
    echo
    echo "¡Hola, $name! 🎉 Aquí están los días que te toca buscar la caja de comida este mes:"
    if [ ${#assigned_days[@]} -eq 0 ]; then
        echo "¡Nada esta vez! Pero recuerda estar listo para la próxima ronda. 😉"
    else
        for d in "${assigned_days[@]}"; do
            echo "  - $d"
        done
    fi
else
    echo
    echo "Tu asignación individual no se mostrará porque el mes seleccionado ($month/$year) ya pasó."
fi

echo
echo "Además, se ha creado o actualizado el archivo con la asignación completa en:"
echo "  $OUTPUT_FILE"
echo
echo "¡Gracias por colaborar con el equipo! 💪🍱"

exit 0
#!/bin/bash

# Colores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# Función para mostrar mensajes de error
error() {
    echo -e "${RED}Error: $1${NC}" >&2
}

# Función para mostrar mensajes de éxito
success() {
    echo -e "${GREEN}$1${NC}"
}

# Función para mostrar advertencias
warning() {
    echo -e "${YELLOW}Advertencia: $1${NC}"
}

# Función para mostrar información
info() {
    echo -e "${BLUE}$1${NC}"
}

# Función para mostrar detalles
detail() {
    echo -e "${CYAN}$1${NC}"
}

# Función para normalizar nombres (remover guiones bajos y convertir a minúsculas)
normalizar_nombre() {
    echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/_//g'
}

# Función para obtener migraciones existentes
obtener_migraciones_existentes() {
    local migraciones=()
    if [ -d "database/migrations" ]; then
        while IFS= read -r -d '' archivo; do
            # Extraer el nombre de la tabla del archivo de migración
            local nombre_archivo=$(basename "$archivo")
            # Buscar varios patrones comunes de migraciones
            if [[ "$nombre_archivo" =~ create_(.*)_table\.php ]] ||
               [[ "$nombre_archivo" =~ _(.*)_table\.php ]] ||
               [[ "$nombre_archivo" =~ create_(.*)\.php ]] ||
               [[ "$nombre_archivo" =~ _(.*)\.php ]]; then
                migraciones+=("${BASH_REMATCH[1]}")
            fi
        done < <(find database/migrations -name "*.php" -print0 2>/dev/null)
    fi
    echo "${migraciones[@]}"
}

# Función para verificar si una migración ya existe (comparación normalizada)
migracion_existe() {
    local tabla="$1"
    local migraciones_existentes=($(obtener_migraciones_existentes))
    
    # Normalizar el nombre de la tabla a verificar
    local tabla_normalizada=$(normalizar_nombre "$tabla")
    
    for migracion in "${migraciones_existentes[@]}"; do
        # Normalizar el nombre de la migración existente
        local migracion_normalizada=$(normalizar_nombre "$migracion")
        
        if [ "$migracion_normalizada" == "$tabla_normalizada" ]; then
            return 0 # true - existe
        fi
    done
    return 1 # false - no existe
}

# Función para obtener el nombre real del archivo de migración existente
obtener_nombre_archivo_existente() {
    local tabla="$1"
    local migraciones_existentes=($(obtener_migraciones_existentes))
    
    local tabla_normalizada=$(normalizar_nombre "$tabla")
    
    for migracion in "${migraciones_existentes[@]}"; do
        local migracion_normalizada=$(normalizar_nombre "$migracion")
        
        if [ "$migracion_normalizada" == "$tabla_normalizada" ]; then
            # Encontrar el archivo real
            archivo_existente=$(find database/migrations -name "*${migracion}*" -print -quit 2>/dev/null)
            if [ -n "$archivo_existente" ]; then
                echo "$(basename "$archivo_existente")"
                return
            fi
        fi
    done
    echo ""
}

# Función para verificar si una palabra está en plural (inglés y español)
es_plural() {
    local palabra="$1"
    local palabra_lower=$(echo "$palabra" | tr '[:upper:]' '[:lower:]')
    
    # Reglas para plural en inglés
    local plural_ingles=(
        "s$" "es$" "ies$" "ves$" "xes$" "zes$" "ches$" "shes$"
    )
    
    # Reglas para plural en español
    local plural_espanol=(
        "s$" "es$" "ces$" "ses$" "res$" "nes$"
    )
    
    # Verificar reglas en inglés
    for regla in "${plural_ingles[@]}"; do
        if [[ "$palabra_lower" =~ $regla ]]; then
            return 0 # true - es plural
        fi
    done
    
    # Verificar reglas en español
    for regla in "${plural_espanol[@]}"; do
        if [[ "$palabra_lower" =~ $regla ]]; then
            return 0 # true - es plural
        fi
    done
    
    # Palabras comunes que son plurales
    local plurales_comunes=(
        "people" "children" "men" "women" "feet" "teeth" "mice" "geese"
        "data" "criteria" "phenomena" "personas" "gentes" "naciones"
        "usuarios" "personas" "productos" "categorias" "articulos"
    )
    
    for plural in "${plurales_comunes[@]}"; do
        if [ "$palabra_lower" == "$plural" ]; then
            return 0 # true - es plural
        fi
    done
    
    return 1 # false - no es plural
}

# Función para sugerir plural en inglés (convención Laravel)
sugerir_plural() {
    local palabra="$1"
    local idioma="${2:-en}" # default inglés
    
    # Convertir a minúsculas para procesamiento
    local palabra_lower=$(echo "$palabra" | tr '[:upper:]' '[:lower:]')
    local resultado=""
    
    if [ "$idioma" == "en" ]; then
        # Reglas de pluralización en inglés
        if [[ "$palabra_lower" =~ y$ ]] && ! [[ "$palabra_lower" =~ [aeiou]y$ ]]; then
            resultado="${palabra_lower%y}ies"
        elif [[ "$palabra_lower" =~ f$ ]]; then
            resultado="${palabra_lower%f}ves"
        elif [[ "$palabra_lower" =~ fe$ ]]; then
            resultado="${palabra_lower%fe}ves"
        elif [[ "$palabra_lower" =~ s$ ]] || [[ "$palabra_lower" =~ x$ ]] || [[ "$palabra_lower" =~ z$ ]] || 
             [[ "$palabra_lower" =~ ch$ ]] || [[ "$palabra_lower" =~ sh$ ]]; then
            resultado="${palabra_lower}es"
        else
            resultado="${palabra_lower}s"
        fi
    else
        # Reglas básicas de pluralización en español
        if [[ "$palabra_lower" =~ [áéíóú]$ ]]; then
            resultado="${palabra_lower}es"
        elif [[ "$palabra_lower" =~ z$ ]]; then
            resultado="${palabra_lower%z}ces"
        elif [[ "$palabra_lower" =~ [aeiou]$ ]]; then
            resultado="${palabra_lower}s"
        elif [[ "$palabra_lower" =~ [bcdfghjklmnpqrstvwxyz]$ ]]; then
            resultado="${palabra_lower}es"
        else
            resultado="${palabra_lower}s"
        fi
    fi
    
    # Mantener capitalización original si la palabra comenzaba con mayúscula
    if [[ "$palabra" =~ ^[A-Z] ]]; then
        resultado="$(echo "${resultado:0:1}" | tr '[:lower:]' '[:upper:]')${resultado:1}"
    fi
    
    echo "$resultado"
}

# Mostrar migraciones existentes
mostrar_migraciones_existentes() {
    local migraciones_existentes=($(obtener_migraciones_existentes))
    
    if [ ${#migraciones_existentes[@]} -eq 0 ]; then
        info "No hay migraciones existentes en la carpeta database/migrations"
    else
        info "Migraciones existentes:"
        for migracion in "${migraciones_existentes[@]}"; do
            detail "  - $migracion"
        done
        echo ""
    fi
}

# Función para solicitar nombre de tabla con todas las validaciones
solicitar_nombre_tabla() {
    local numero_tabla="$1"
    local tablas_existentes=("$2") # Tablas ya ingresadas en esta sesión
    
    while true; do
        read -p "Ingrese el nombre de la tabla $numero_tabla: " nombre_tabla
        
        # Validar que no esté vacío
        if [ -z "$nombre_tabla" ]; then
            error "El nombre no puede estar vacío."
            continue
        fi
        
        # Validar formato
        if [[ ! "$nombre_tabla" =~ ^[a-zA-Z0-9_áéíóúÁÉÍÓÚñÑ]+$ ]]; then
            error "El nombre contiene caracteres no válidos."
            continue
        fi
        
        # Verificar si está en plural
        if ! es_plural "$nombre_tabla"; then
            warning "El nombre '$nombre_tabla' parece estar en singular."
            
            # Ofrecer sugerencias en inglés y español
            sugerencia_en=$(sugerir_plural "$nombre_tabla" "en")
            sugerencia_es=$(sugerir_plural "$nombre_tabla" "es")
            
            echo "Sugerencias:"
            echo "  1) Inglés (recomendado): $sugerencia_en"
            echo "  2) Español: $sugerencia_es"
            echo "  3) Mantener '$nombre_tabla'"
            
            read -p "Seleccione una opción (1/2/3): " opcion_plural
            
            case $opcion_plural in
                1) nombre_tabla="$sugerencia_en" ;;
                2) nombre_tabla="$sugerencia_es" ;;
                3) info "Manteniendo: $nombre_tabla" ;;
                *) 
                    error "Opción no válida. Manteniendo nombre original."
                    ;;
            esac
        fi
        
        # Verificar si la migración ya existe en el sistema (comparación normalizada)
        if migracion_existe "$nombre_tabla"; then
            warning "¡La migración para '$nombre_tabla' ya existe!"
            
            # Mostrar el archivo existente
            archivo_existente=$(obtener_nombre_archivo_existente "$nombre_tabla")
            if [ -n "$archivo_existente" ]; then
                detail "Archivo existente: $archivo_existente"
            fi
            
            # Pedir nuevo nombre inmediatamente
            read -p "Por favor, ingrese un nombre diferente: " nombre_tabla
            
            # Continuar el ciclo para validar el nuevo nombre
            continue
        fi
        
        # Verificar si ya fue ingresado en esta misma sesión (comparación normalizada)
        for tabla_existente in "${tablas_existentes[@]}"; do
            if [ "$(normalizar_nombre "$tabla_existente")" == "$(normalizar_nombre "$nombre_tabla")" ]; then
                warning "El nombre '$nombre_tabla' ya fue ingresado en esta sesión."
                read -p "Por favor, ingrese un nombre diferente: " nombre_tabla
                continue 2
            fi
        done
        
        # Si llegamos aquí, el nombre es válido, no existe y no es duplicado
        echo "$nombre_tabla"
        break
    done
}

# Validar que estamos en un proyecto Laravel
if [ ! -f "artisan" ]; then
    error "No se encontró el archivo artisan. Asegúrate de estar en el directorio raíz de un proyecto Laravel."
    exit 1
fi

# Validar que PHP está disponible
if ! command -v php &> /dev/null; then
    error "PHP no está instalado o no está en el PATH."
    exit 1
fi

# Mostrar migraciones existentes al inicio
mostrar_migraciones_existentes

# Solicitar y validar la cantidad de tablas
while true; do
    read -p "Ingrese la cantidad de tablas que desea crear: " cantidad_tablas
    
    if [[ ! "$cantidad_tablas" =~ ^[0-9]+$ ]]; then
        error "Por favor, ingrese un número válido."
        continue
    fi
    
    if [ "$cantidad_tablas" -lt 1 ]; then
        error "La cantidad debe ser al menos 1."
        continue
    fi
    
    break
done

# Inicializar arreglo para almacenar los nombres de las tablas
tablas=()

info "Convenciones de Laravel:"
info "- Nombres de tablas en PLURAL (inglés preferido)"
info "- Ejemplos: users, products, categories, posts, comments"
info "- También se acepta español: usuarios, productos, categorías"

# Solicitar los nombres de las tablas con validación inmediata
for ((i=1; i<=cantidad_tablas; i++)); do
    nombre_tabla=$(solicitar_nombre_tabla $i "${tablas[@]}")
    
    tablas+=("$nombre_tabla")
    success "Tabla agregada: $nombre_tabla"
done

if [ ${#tablas[@]} -eq 0 ]; then
    warning "No se agregaron tablas para crear migraciones."
    exit 0
fi

# Mostrar resumen antes de proceder
echo -e "\n${YELLOW}Resumen de migraciones a crear:${NC}"
for table in "${tablas[@]}"; do
    echo "  - create_${table}_table"
done

# Confirmar antes de ejecutar
read -p $'\n¿Desea continuar con la creación de las migraciones? (s/N): ' confirmar

if [[ ! "$confirmar" =~ ^[SsYy]$ ]] && [ -n "$confirmar" ]; then
    warning "Operación cancelada por el usuario."
    exit 0
fi

# Crear las migraciones
echo -e "\nCreando migraciones..."
for table in "${tablas[@]}"; do
    echo "Creando migración para: $table"
    
    if php artisan make:migration "create_${table}_table" --quiet; then
        success "✓ Migración para '$table' creada exitosamente."
    else
        error "✗ Error al crear la migración para '$table'"
    fi
done

# Mostrar migraciones actualizadas
echo -e "\n"
mostrar_migraciones_existentes

success "¡Proceso completado! Se crearon ${#tablas[@]} migraciones."
``` php-yii2 botón bootstrap
<div>
<?= Html::a('Crear', ['create'], ['class' => 'btn btn-success', 'style' => 'background-color: #4A49C0; border: 1px solid #4A49C0;']) ?>
</div> 
```
La opción -d en un comando Docker significa "modo detached" o "modo desacoplado".

Cuando usas docker run -d, el contenedor se ejecuta en segundo plano (background). No se muestra la salida del contenedor en la terminal, ni se queda "pegada" a ella. Esto es útil para servicios y aplicaciones que quieres que sigan corriendo sin que ocupen tu terminal.

Si no usas -d (modo foreground o primer plano), el contenedor se ejecuta conectado a tu terminal y verás los logs y la salida en tiempo real. La terminal queda ocupada con el proceso del contenedor hasta que lo detengas. Esto es útil para tareas interactivas o para depurar.

Resumiendo:

-d: contenedor en segundo plano, terminal libre para otras tareas.

Sin -d: contenedor en primer plano, salida visible en la terminal.

Esta es una diferencia clave para controlar cómo interactúas con los contenedores al ejecutarlos con Docker.

¿Importa el tipo de red (bridge vs overlay) para elegir entre uno y otro?
-Sí, el tipo de red en Docker se relaciona con el modo de ejecución.
-Las redes bridge suelen ser para contenedores que corren en el mismo host (nodo local). Por eso se usa con docker run.
-Las redes overlay permiten la comunicación segura entre contenedores que corren en diferentes nodos en un clúster Docker Swarm. Por eso se usan con docker service create en modo swarm.

1. Red Bridge (puente) - red local para contenedores en un mismo host
bash
docker network create --driver bridge mi_red_bridge

docker run -d --name postgres_bridge --network mi_red_bridge -e POSTGRES_PASSWORD=contraseña postgres
docker run -d --name php_bridge --network mi_red_bridge php

2. Red Host - el contenedor comparte la red del host (sin aislamiento)
bash
docker run -d --name postgres_host --network host -e POSTGRES_PASSWORD=contraseña postgres
docker run -d --name php_host --network host php

3. Red Overlay - permite que contenedores en diferentes hosts se comuniquen (requiere Docker Swarm)
bash
docker swarm init

docker network create --driver overlay mi_red_overlay

docker service create --name postgres_overlay --network mi_red_overlay -e POSTGRES_PASSWORD=contraseña postgres
docker service create --name php_overlay --network mi_red_overlay php

4. Red Macvlan - contenedores tienen IP propia en la red física del host (requiere configuración de red)
bash
docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 mi_red_macvlan

docker run -d --name postgres_macvlan --network mi_red_macvlan -e POSTGRES_PASSWORD=contraseña postgres
docker run -d --name php_macvlan --network mi_red_macvlan php
Nota: Cambia 192.168.1.0/24, 192.168.1.1 y eth0 según tu red física.

5. Red None - el contenedor no tiene red ni acceso a otros contenedores
bash
docker run -d --name postgres_none --network none -e POSTGRES_PASSWORD=contraseña postgres
docker run -d --name php_none --network none php
Con estos comandos tienes ejemplos prácticos de cómo crear y conectar contenedores PHP y PostgreSQL en los distintos tipos de redes Docker.

docker start <nombre_o_id_del_contenedor>

docker stop <nombre_o_id_del_contenedor>
  
docker restart <nombre_o_id_del_contenedor>
docker start <nombre_o_id_del_contenedor>

docker stop <nombre_o_id_del_contenedor>
Ver contenedores en ejecución:
docker ps
Este comando muestra solo los contenedores que están en ejecución actualmente.

Ver todos los contenedores (en ejecución y detenidos):
docker ps -a
o
docker container ls -a
1.-Eliminar el contenedor detenido que está usando esa imagen con:
docker rm 8850ff9258c0

1.1-podrás eliminar la imagen normalmente:
docker rmi 1b44b5a3e06a

3.-Forzar la eliminación de la imagen junto con los contenedores detenidos que la usan con:
docker rmi -f 1b44b5a3e06a

Listar y eliminar todos los contenedores en estado "exited" (detenidos) con este comando combinado:

docker rm $(docker ps -a -f status=exited -q)

os parámetros significan lo siguiente:

-a (o --all): En el comando docker ps, muestra todos los contenedores, incluyendo tanto los que están en ejecución como los que están detenidos. Sin esta opción, solo se muestran los contenedores en ejecución.

-f (o --filter): Permite filtrar la lista de contenedores según una condición. En este caso, status=exited filtra para mostrar solo los contenedores que están en estado "exited", es decir, detenidos.

-q (o --quiet): Devuelve solo los IDs de los contenedores, sin mostrar toda la información adicional.

status=exited: Es la condición para el filtro -f, indica que queremos los contenedores cuyo estado es "exited" (detenidos).

docker container prune



En informática, la tabla DMI se refiere principalmente al Desktop Management Interface (DMI). Es un estándar que proporciona un framework común para la gestión y seguimiento de los componentes de hardware en un ordenador de sobremesa, portátil o servidor

sudo dmidecode [opciones] | todo
ejemplo: sudo dmidecode -t 
  bios
  system
  baseboard
  chassis
  processor
  memory
  cache
  connector
  slot

lscpu:
El comando lscpu en Linux se utiliza para mostrar información detallada sobre la unidad central de procesamiento (CPU) del sistema. Proporciona datos estructurados como:

Arquitectura de la CPU (por ejemplo, x86_64)
Número de núcleos y subprocesos (threads)
Modelo y nombre de la CPU
Velocidad de reloj actual (frecuencia MHz)
Modos operativos soportados (32-bit, 64-bit)
Topología de la CPU: núcleos por socket, hilos por núcleo, sockets
Tamaño de caché (L1, L2, L3)
Información sobre soportes de virtualización (VT-x, AMD-V)
Otros detalles técnicos relevantes para la CPU
-Es una herramienta esencial para administradores de sistemas, desarrolladores y usuarios técnicos que quieran conocer la configuración y capacidades del procesador sin necesidad de privilegios de superusuario.

sudo dmidecode [opciones]
Las opciones principales que se pueden usar con el comando sudo dmidecode son:

-t o --type: Muestra solo la información de un tipo específico de hardware o sección de la tabla DMI. Puede recibir el nombre o número del tipo. Ejemplos de tipos:

bios (0 o 13): Información de la BIOS.
system (1, 12, 15, 23, 32): Información general del sistema.
baseboard (2, 10, 41): Información de la placa base.
chassis (3): Información del chasis o carcasa.
processor (4): Información del procesador.
memory (5, 6, 16, 17): Información de la memoria RAM.
cache (7): Información de la memoria cache.
connector (8): Información de conectores.
slot (9): Información de ranuras de expansión.
-q o --quiet: Ejecuta el comando en modo silencioso, suprimiendo la mayoría de mensajes de advertencia y errores para una salida más limpia, útil para scripts.
-s o --string: Muestra solo el valor de una cadena específica DMI que se especifique.
Sin opciones, muestra toda la información disponible en la tabla DMI.
Ejemplo de uso para obtener solo información de la memoria RAM en modo silencioso:
Estructura general:

xmlelement(name libros, ...): crea un elemento XML raíz llamado <libros>.

xmlagg(...): agrega múltiples elementos XML dentro del elemento raíz.

xmlelement(name libro, xmlforest(...)): crea un elemento <libro> con varios subelementos para los campos del libro.

SELECT
  xmlelement(
    name libros,
    xmlagg(
      xmlelement(
        name libro,
        xmlforest(
          id,
          titulo,
          autor,
          anio
        )
      )
    )
  ) AS libros_xml
FROM libros;
$conn = pg_connect("host=localhost dbname=mi_base user=usuario password=clave");

$sql = "SELECT
  xmlelement(
    name libros,
    xmlagg(
      xmlelement(
        name libro,
        xmlforest(
          id,
          titulo,
          autor,
          anio
        )
      )
    )
  ) AS libros_xml
FROM libros";

$result = pg_query($conn, $sql);
$row = pg_fetch_assoc($result);

$xmlStr = $row['libros_xml'];
$xml = simplexml_load_string($xmlStr);
Cómo funciona cada uno para obtener datos:
XML es un formato de datos estructurado que puede estar almacenado en un archivo local o servido desde un servidor remoto (por ejemplo, desde una API REST).

XPath es un lenguaje para navegar y seleccionar partes específicas dentro de un documento XML.

XQuery es un lenguaje de consulta más avanzado para extraer, transformar y manipular datos XML, que puede usarse para consultar documentos XML o bases de datos XML alojadas en servidores, locales o remotos.

JSON es otro formato muy popular para transmitir datos, especialmente en APIs web modernas, y se pueden consultar y manipular fácilmente con lenguajes como JavaScript o PHP.
Un ejemplo sencillo y representativo de una base de datos XML podría ser un conjunto de documentos XML que almacenan información estructurada, como un catálogo de libros o una lista de contactos.

Aquí tienes una estructura básica de un archivo XML que simula la información en una base de datos de libros:

<?xml version="1.0" encoding="UTF-8"?>
<biblioteca>
  <libro id="1">
    <titulo>El Quijote</titulo>
    <autor>Miguel de Cervantes</autor>
    <anio>1605</anio>
    <genero>Novela</genero>
  </libro>
  <libro id="2">
    <titulo>Cien Años de Soledad</titulo>
    <autor>Gabriel García Márquez</autor>
    <anio>1967</anio>
    <genero>Realismo mágico</genero>
  </libro>
  <libro id="3">
    <titulo>La Sombra del Viento</titulo>
    <autor>Carlos Ruiz Zafón</autor>
    <anio>2001</anio>
    <genero>Novela negra</genero>
  </libro>
</biblioteca>
Base de datos PostgreSQL con datos XML

<biblioteca>
  <libro>
    <titulo>El Quijote</titulo>
    <autor>Miguel de Cervantes</autor>
  </libro>
  <libro>
    <titulo>Cien Años de Soledad</titulo>
    <autor>Gabriel García Márquez</autor>
  </libro>
</biblioteca>
json_encode(): convierte un array u objeto PHP en una cadena JSON.

json_decode(): convierte una cadena JSON en un objeto o array PHP.

// Array PHP a JSON
$array = ['nombre' => 'Juan', 'edad' => 30];
$json = json_encode($array);
echo $json; // {"nombre":"Juan","edad":30}

// JSON a array PHP
$jsonString = '{"nombre":"Ana","edad":25}';
$arrayPHP = json_decode($jsonString, true);
echo $arrayPHP['nombre']; // Ana
convertir una tabla postgres en json en yii2:
<?php
namespace app\controllers;

use yii\web\Controller;
use yii\web\Response;
use app\models\Libro; // Suponiendo que tienes un modelo Libro

class LibroController extends Controller
{
    public function actionLista()
    {
        // Obtener datos como array usando asArray()
        $libros = Libro::find()->asArray()->all();

        \Yii::$app->response->format = Response::FORMAT_JSON;

        // Devolver los datos directamente como JSON
        return $libros;
    }
}


convertir una tabla postgres en json en  laravel:
<?php

namespace App\Http\Controllers;

use App\Models\Libro;
use Illuminate\Http\JsonResponse;

class LibroController extends Controller
{
    public function lista(): JsonResponse
    {
        // Obtener todos los registros como array
        $libros = Libro::all();

        // Devolver los datos como JSON
        return response()->json($libros);
    }
}
Cómo definir la ruta para acceder a este método (en routes/web.php o routes/api.php):
use App\Http\Controllers\LibroController;
Route::get('/libro/lista', [LibroController::class, 'lista']);

javascript:
1. Con promesas (.then)
Cómo consumirlo con JavaScript sería igual que en Yii2-laravel:
fetch('/libro/lista')
  .then(response => response.json())
  .then(data => {
    data.forEach(libro => {
      console.log(libro.titulo);
    });
  });

2. Con async/await (más legible)
Cómo consumirlo en JavaScript sería igual que en Yii2-laravel:
async function obtenerLibros() {
  try {
    const response = await fetch('/libro/lista');
    const data = await response.json();
    data.forEach(libro => {
      console.log(libro.titulo);
    });
  } catch (error) {
    console.error('Error:', error);
  }
}

obtenerLibros();

3. Con callback (usando XMLHttpRequest)
Cómo consumirlo en JavaScript sería igual que en Yii2-laravel:
function obtenerLibrosConCallback(callback) {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', '/libro/lista');
  xhr.onload = function() {
    if (xhr.status === 200) {
      const data = JSON.parse(xhr.responseText);
      callback(null, data);
    } else {
      callback(new Error('Error en la solicitud: ' + xhr.status));
    }
  };
  xhr.onerror = function() {
    callback(new Error('Error de red'));
  };
  xhr.send();
}

// Usando la función con callback
obtenerLibrosConCallback(function(error, data) {
  if (error) {
    console.error(error);
  } else {
    data.forEach(libro => {
      console.log(libro.titulo);
    });
  }
});

jquery:
1.-Ejemplo usando $.getJSON()

<!DOCTYPE html>
<html>
<head>
  <title>Consumir API con jQuery</title>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>

<ul id="lista-libros"></ul>

<script>
$(document).ready(function() {
  $.getJSON('/libro/lista')
    .done(function(data) {
      // data es un array de objetos libros
      $.each(data, function(index, libro) {
        $('#lista-libros').append('<li>' + libro.titulo + '</li>');
      });
    })
    .fail(function(jqxhr, textStatus, error) {
      console.error('Error al consumir la API:', textStatus, error);
    });
});
</script>

</body>
</html>

2.-Ejemplo usando $.ajax():
$.ajax({
  url: '/libro/lista',
  type: 'GET',
  dataType: 'json',
  success: function(data) {
    data.forEach(function(libro) {
      console.log(libro.titulo);
    });
  },
  error: function(jqxhr, textStatus, error) {
    console.error('Error:', error);
  }
});

laravel:
use Illuminate\Support\Facades\Http;

$response = Http::get('https://api.example.com/data');

if ($response->successful()) {
    $data = $response->json(); // decodifica JSON automáticamente a array
    // procesar $data
} else {
    // manejar error
}

yii2:
Formas comunes de consumir APIs en PHP / Yii2:
1. Usar cURL directamente (funciona en cualquier PHP)

use yii\httpclient\Client;

$client = new Client();
$response = $client->get('https://api.ejemplo.com/data')->send();

if ($response->isOk) {
    $data = $response->getData(); // Obtienes array o json decodificado automáticamente
}

2. Usar la clase yii\httpclient\Client que trae Yii2 (más moderno y elegante)
use yii\httpclient\Client;

$client = new Client();
$response = $client->get('https://api.ejemplo.com/data')->send();

if ($response->isOk) {
    $data = $response->getData(); // Obtienes array o json decodificado automáticamente
}




php-nativo:
php -S 192.168.1.50:9000
php -S localhost:9000
php -S 127.0.0.1:9000 //localhost

php-yii2
php -S localhost:8001 -t backend/web
php -S 172.xx.xx.xx:8081 -t backend/web

php-laravel
php artisan serve --port=8080
php -S 192.168.1.50:9000 -t public

laravel
php artisan serve
php artisan serve --host=172.xx.xx.xx:8081 --port=8000
php artisan serve --host=localhost --port=8000


yii2
php yii serve --port=8080
php yii serve --docroot="backend/web"
php yii serve --docroot="backend/web" --address=192.168.1.50 --port=9000
docker-compose down --rmi all --volumes --remove-orphans

--rmi all: elimina todas las imágenes creadas por docker-compose.
--volumes: elimina los volúmenes asociados.
--remove-orphans: elimina contenedores no definidos en el .yml actual.
# Eliminar volúmenes sin uso
docker volume prune -f

# Eliminar redes sin uso
docker network prune -f
Este comando elimina todas las imágenes de Docker del sistema (solo si no hay contenedores activos que las usen).

docker rmi $(docker images -a -q)
Estos comandos buscan todos los contenedores (activos y detenidos) y los detienen/eliminan automáticamente.

# Detener todos los contenedores
docker stop $(docker ps -a -q)

# Eliminar todos los contenedores
docker rm $(docker ps -a -q)
2. Archivo docker-compose.yml
¿Qué es un docker-compose.yml?
Es un archivo de configuración en formato YAML que permite definir y ejecutar múltiples contenedores Docker como un solo servicio, facilitando la orquestación de aplicaciones complejas.

Estructura básica de un docker-compose.yml
version: Define la versión de la sintaxis de Docker Compose.

services: Define los diferentes servicios o contenedores a levantar.

build: Ruta para construir la imagen Docker (opcional cuando se usa imagen pública).

image: Nombre de la imagen a usar.

ports: Puertos que se exponen y mapean al host.

volumes: Para montar volúmenes o carpetas locales dentro del contenedor.

environment: Variables de entorno para los contenedores.

Ejemplo básico:
version: '3'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
    environment:
      - NODE_ENV=development
  db:
    image: postgres:13
    environment:
      POSTGRES_USER: usuario
      POSTGRES_PASSWORD: contraseña
      POSTGRES_DB: mibase
    ports:
      - "5432:5432"
¿Cómo ejecutar un archivo docker-compose.yml?
Abrir una terminal.
Navegar a la carpeta donde está el archivo docker-compose.yml.

Ejecutar el comando:
docker-compose up
Esto creará y arrancará todos los servicios definidos en el archivo.

Para detener los servicios:
docker-compose down


Dockerfile
Qué es: Un archivo de texto que contiene una serie de instrucciones para construir una imagen Docker. Funciona como una "receta" para crear una imagen personalizada.

Para qué sirve: Define cómo se debe construir una imagen de contenedor, especificando la base del sistema operativo, las aplicaciones que se deben instalar, variables de entorno, archivos que se copian, comandos que se deben ejecutar para preparar la imagen, entre otros.

Cómo se arma: Se escribe paso a paso con comandos Docker (por ejemplo, FROM, COPY, RUN, CMD) que instruyen cómo se debe crear la imagen.

1. Dockerfile
¿Qué es un Dockerfile?
Un Dockerfile es un archivo de texto que contiene instrucciones para construir una imagen de Docker personalizada. Esta imagen luego se puede usar para crear contenedores.

Estructura básica de un Dockerfile
FROM: Define la imagen base desde la cual se construirá la nueva imagen.

WORKDIR: Define el directorio de trabajo dentro del contenedor.

COPY: Copia archivos o directorios desde tu sistema local hacia la imagen.

RUN: Ejecuta comandos en la imagen mientras se construye.

CMD: Define el comando que se ejecutará cuando se inicie un contenedor a partir de esta imagen.

Ejemplo básico:

# Imagen base
FROM node:14

# Directorio de trabajo
WORKDIR /app

# Copiar archivos al contenedor
COPY package*.json ./

# Instalar dependencias
RUN npm install

# Copiar el resto del código
COPY . .

# Puerto que se expondrá
EXPOSE 3000

# Comando para iniciar la aplicación
CMD ["npm", "start"]

¿Cómo ejecutar un Dockerfile?
Abrir una terminal.

Navegar a la carpeta donde está el Dockerfile.

Construir la imagen con el comando:
docker build -t nombre_de_la_imagen .

Ejecutar el contenedor con:
docker run -p 3000:3000 nombre_de_la_imagen
Las diferencias entre imágenes y contenedores en Docker son las siguientes:

Una imagen de Docker es una plantilla de solo lectura que contiene las bibliotecas, dependencias, archivos y el entorno necesario para ejecutar una aplicación. Es un archivo reutilizable e inmutable que sirve para crear contenedores. Las imágenes se crean generalmente a partir de un archivo Dockerfile que contiene todas las instrucciones para construir la imagen.

Un contenedor de Docker es una instancia en ejecución creada a partir de una imagen de Docker. Es un entorno aislado que incluye todo lo necesario para ejecutar la aplicación. Los contenedores tienen una capa adicional que permite escritura y cambios durante su ejecución, pero estos cambios no afectan la imagen original.

En resumen:

| Aspecto      | Imagen de Docker                             | Contenedor de Docker                       |
|--------------|---------------------------------------------|-------------------------------------------|
| Qué es       | Archivo de solo lectura que contiene la plantilla | Instancia en ejecución de una imagen      |
| Mutabilidad  | Inmutable, no se modifica después de creada | Mutable, permite cambios durante la ejecución |
| Función      | Plantilla para crear contenedores            | Ejecutar la aplicación de forma aislada   |
| Creación    | Creada a partir de un Dockerfile              | Creado a partir de una imagen              |
| Uso          | Almacenar y compartir la configuración y software | Ejecutar la aplicación en runtime          |

**Comandos específicos para imágenes:**


docker build -t nombre_imagen . — crea una imagen a partir de un Dockerfile.

docker images — lista las imágenes disponibles.

docker rmi nombre_imagen — elimina una imagen.

Comandos específicos para contenedores:

docker run nombre_imagen — crea y ejecuta un contenedor a partir de una imagen.

docker ps — lista los contenedores en ejecución.

docker ps -a — lista todos los contenedores (incluyendo los detenidos).

docker stop nombre_contenedor — detiene un contenedor en ejecución.

docker start nombre_contenedor — inicia un contenedor detenido.

docker rm nombre_contenedor — elimina un contenedor.

Por ejemplo, para crear y ejecutar un contenedor con un terminal bash usando una imagen llamada "MyImage":

text
docker run -it MyImage bash
En conclusión, las imágenes son las plantillas estáticas usadas para crear y ejecutar contenedores, mientras que los contenedores son las instancias activas que ejecutan realmente las aplicaciones, y se manejan con comandos diferentes conforme a su función. Esto permite portar software de forma consistente y escalable en diferentes entornos.
Un ejemplo real donde puedes usar Promise.all con async/await es cuando necesitas hacer múltiples operaciones asíncronas en paralelo y esperar a que todas terminen antes de continuar. Por ejemplo, en el caso de una aplicación que debe obtener información de varios usuarios desde diferentes endpoints de una API y luego procesar todos esos datos juntos.

Imagina que tienes que traer datos de dos usuarios distintos al mismo tiempo. Usando Promise.all con async/await puedes lanzar ambas solicitudes al mismo tiempo y esperar a que ambas terminen antes de continuar:

javascript
async function obtenerDatosUsuarios() {
  async function getUser(userId) {
    const response = await fetch(`https://api.miapi.com/user/${userId}`);
    const userData = await response.json();
    return userData;
  }

  try {
    const [usuario1, usuario2] = await Promise.all([getUser(1), getUser(2)]);
    console.log('Datos de usuario 1:', usuario1);
    console.log('Datos de usuario 2:', usuario2);
    // Aquí puedes trabajar con ambos datos al mismo tiempo
  } catch (error) {
    console.error('Error al obtener datos de usuarios:', error);
  }
}

obtenerDatosUsuarios();
En esta situación, si alguna de las dos solicitudes falla, el Promise.all se rechaza inmediatamente y entras en el bloque catch para manejar el error. Esto es eficiente porque no esperas a terminar una solicitud para empezar la otra, sino que ambas se pagan en paralelo y el programa espera a que las dos terminen para continuar. Además, puedes manejar fácilmente el error si alguna de las solicitudes falla.

Otro caso real puede ser enviar un lote de correos electrónicos a muchos usuarios en paralelo, procesándolos por lotes para no saturar el servidor. En cada lote usas Promise.all para esperar que se terminen de enviar los correos antes de pasar al siguiente grupo.

Así, Promise.all con async/await es útil para operaciones asíncronas que pueden ejecutarse en paralelo y donde se requiere que todas concluyan satisfactoriamente para continuar.
1. Promise.all con async/await:Espera a que todas las promesas se resuelvan. Si alguna promesa es rechazada, se rechaza inmediatamente con el motivo del primer error.

async function ejemploPromiseAll() {
  const p1 = Promise.resolve(3);
  const p2 = 1337; // valor normal, se acepta directamente
  const p3 = new Promise(resolve => setTimeout(resolve, 100, "foo"));

  try {
    const resultados = await Promise.all([p1, p2, p3]);
    console.log(resultados); // [3, 1337, "foo"]
  } catch (error) {
    console.error("Error:", error);
  }
}
ejemploPromiseAll();

2. Promise.any con async/await: Resuelve cuando la primera promesa se resuelve exitosamente. Rechaza solo si todas las promesas son rechazadas.

async function ejemploPromiseAny() {
  const p1 = Promise.reject("Error 1");
  const p2 = new Promise(resolve => setTimeout(resolve, 100, "Éxito 2"));
  const p3 = new Promise(resolve => setTimeout(resolve, 200, "Éxito 3"));

  try {
    const resultado = await Promise.any([p1, p2, p3]);
    console.log(resultado); // "Éxito 2"
  } catch (error) {
    console.error("Todas las promesas fallaron:", error);
  }
}
ejemploPromiseAny();

3. Promise.race con async/await: Resuelve o rechaza tan pronto como la primera promesa se resuelva o rechace.
async function ejemploPromiseRace() {
  const p1 = new Promise(resolve => setTimeout(resolve, 500, "Resultado p1"));
  const p2 = new Promise((_, reject) => setTimeout(reject, 100, "Error p2"));

  try {
    const resultado = await Promise.race([p1, p2]);
    console.log(resultado);
  } catch (error) {
    console.error("Error del primero en terminar:", error); // "Error p2"
  }
}
ejemploPromiseRace();

4. Promise.allSettled con async/await: Espera a que todas las promesas terminen (resueltas o rechazadas) y devuelve un array con el estado y valor o razón de cada promesa.

async function ejemploPromiseAllSettled() {
  const p1 = Promise.resolve("Éxito p1");
  const p2 = Promise.reject("Error p2");
  const p3 = Promise.resolve("Éxito p3");

  const resultados = await Promise.allSettled([p1, p2, p3]);

  resultados.forEach((result, index) => {
    if (result.status === "fulfilled") {
      console.log(`Promesa ${index + 1} cumplida con valor: ${result.value}`);
    } else {
      console.log(`Promesa ${index + 1} rechazada con razón: ${result.reason}`);
    }
  });
}
ejemploPromiseAllSettled();
Antes de la introducción de async y await en JavaScript, el manejo de operaciones asíncronas con promesas se hacía principalmente usando los métodos .then() y .catch() de las promesas. Estos métodos permitían encadenar funciones que se ejecutaban cuando la promesa se resolvía o se rechazaba, respectivamente. Por ejemplo:
miPromesa()
  .then(resultado => {
    // manejar resultado exitoso
  })
  .catch(error => {
    // manejar error
  });
1. Promise.all
Espera a que todas las promesas se resuelvan. Si alguna promesa es rechazada, se rechaza inmediatamente con el motivo del primer error.

const p1 = Promise.resolve(3);
const p2 = 1337; // No es promesa, se acepta tal cual en el array de resultados
const p3 = new Promise((resolve) => setTimeout(resolve, 100, "foo"));

Promise.all([p1, p2, p3]).then(values => {
  console.log(values); // [3, 1337, "foo"]
}).catch(error => {
  console.error(error);
});

2. Promise.any
Resuelve cuando la primera promesa se resuelve exitosamente. Rechaza solo si todas las promesas son rechazadas.

const p1 = Promise.reject("Error 1");
const p2 = new Promise((resolve) => setTimeout(resolve, 100, "Éxito 2"));
const p3 = new Promise((resolve) => setTimeout(resolve, 200, "Éxito 3"));

Promise.any([p1, p2, p3]).then(value => {
  console.log(value); // "Éxito 2"
}).catch(error => {
  console.error(error); // Se ejecutaría si todas las promesas fallan
});

3.-3. Promise.race
Resuelve o rechaza tan pronto como la primera promesa se resuelva o rechace.
const p1 = new Promise((resolve) => setTimeout(resolve, 500, "Resultado p1"));
const p2 = new Promise((_, reject) => setTimeout(reject, 100, "Error p2"));

Promise.race([p1, p2]).then(value => {
  console.log(value);
}).catch(error => {
  console.error(error); // "Error p2", ya que es la primera en finalizar con rechazo
});

4. Promise.allSettled
Espera a que todas las promesas terminen (resueltas o rechazadas) y devuelve un array con el estado y valor o razón de cada promesa.

const p1 = Promise.resolve("Éxito p1");
const p2 = Promise.reject("Error p2");
const p3 = Promise.resolve("Éxito p3");

Promise.allSettled([p1, p2, p3]).then(results => {
  results.forEach((result, index) => {
    if (result.status === "fulfilled") {
      console.log(`Promesa ${index + 1} cumplida con valor: ${result.value}`);
    } else {
      console.log(`Promesa ${index + 1} rechazada con razón: ${result.reason}`);
    }
  });
});
<style>
        .dialog {
            display: none;
            position: fixed;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            z-index: 1000;
        }
        .dialog-content {
            background-color: white;
            margin: 15% auto;
            padding: 20px;
            border-radius: 5px;
            width: 80%;
            max-width: 500px;
        }
    </style>
1.-<dialog id="myDialog" class="dialog">
      <div class="dialog-content">
          <h2>Dialog Title</h2>
          <p>This is a dialog box.</p>
          <button onclick="myDialog.close()">Close</button>
          <button onclick="myDialog.showModal()">Abrir Modal</button>
      </div>
	</dialog>
<script>
  const myDialog = document.getElementById('myDialog');
</script>

<button onclick="myDialog.showModal()">abrir Modal</button>
    
2.-<button id="openDialog">Abrir diálogo</button>

<dialog id="myDialog">
  <p>Este es un cuadro de diálogo</p>
  <button id="closeDialog">Cerrar</button>
</dialog>

<script>
  const openDialogButton = document.getElementById("openDialog");
  const dialog = document.getElementById("myDialog");
  const closeDialogButton = document.getElementById("closeDialog");

  openDialogButton.addEventListener("click", () => {
    dialog.showModal(); // Muestra el cuadro de diálogo en modo modal
  });

  closeDialogButton.addEventListener("click", () => {
    dialog.close(); // Cierra el cuadro de diálogo
  });
</script>
Aquí tienes ejemplos específicos para cada paso de crear contenedores Docker y conectarlos, explicados de forma que sea fácil recordarlos:

1.-Descargar la imagen
Comando:
docker pull nginx:latest
Esto descarga la imagen oficial de Nginx con la etiqueta "latest" desde Docker Hub. Si no especificas la etiqueta, se toma "latest" por defecto.

2.-Crear una red personalizada
Comando:

docker network create mired
Aquí creas una red llamada "mired" de tipo bridge, donde podrás conectar varios contenedores para que se comuniquen entre sí.

3.-Crear el contenedor con configuración
Comando ejemplo:

docker run -d --name mi_nginx -p 8080:80 -e "ENV=production" --network mired nginx:latest
Explicación:

-d: ejecuta el contenedor en segundo plano.
--name mi_nginx: asigna el nombre "mi_nginx" al contenedor.
-p 8080:80: expone el puerto 80 del contenedor en el puerto 8080 del host.
-e "ENV=production": define la variable de entorno ENV con valor production.
--network mired: conecta el contenedor a la red personalizada creada.
nginx:latest: usa la imagen nginx con la etiqueta latest.

4.-Conectar contenedores entre sí
Supongamos que creas dos contenedores en la red "mired":

docker run -d --name webapp --network mired nginx
docker run -d --name db --network mired mysql -e MYSQL_ROOT_PASSWORD=password
Ambos están en la misma red, por lo que el contenedor "webapp" puede acceder al "db" usando el nombre "db" como hostname.

Si quieres conectar un contenedor ya existente a la red después de crearlo:

docker network connect mired nombre_contenedor
Para recordar mejor cada paso, piensa:

"Pull" es traer la imagen al disco.

"Network create" es como hacer una calle para que los contenedores se hablen.

"Run" es poner en marcha el contenedor con nombre, puertos, y variables.

Ponerlos en la misma red es para que cooperen sin problemas.
Aquí tienes un resumen detallado y ordenado de los pasos para crear contenedores Docker y conectarlos, incluyendo descarga de imágenes, creación de redes, configuración de contenedores con puertos, nombres, variables de entorno y asignación de redes:

Descargar la imagen

Usar el comando docker pull nombre_imagen:etiqueta para descargar una imagen desde un repositorio (como Docker Hub).

Si no se especifica etiqueta, se descarga la etiqueta "latest" por defecto.

También puedes dejar que Docker la descargue automáticamente al crear un contenedor si la imagen no está local.

Crear una red personalizada (opcional)

Los contenedores por defecto se conectan a una red bridge predeterminada, pero puedes crear una red propia para una mejor gestión.

Comando para crear red tipo bridge: docker network create nombre_red

Esta red permitirá luego conectar contenedores entre sí fácilmente.

Crear el contenedor con configuración

Usar docker run para crear y ejecutar un contenedor.

Algunos parámetros útiles para configurar al crear el contenedor:

-p puerto_local:puerto_contenedor: Asigna y mapea puertos del host al contenedor.

--name nombre_contenedor: Asigna un nombre legible y gestionable al contenedor.

-e VAR=valor: Define variables de entorno para configurar la aplicación dentro del contenedor.

--network nombre_red: Conecta el contenedor a la red creada previamente o a la red deseada.

imagen:etiqueta: Especifica la imagen y la etiqueta (versión) que se usará.

Ejemplo del comando completo para crear un contenedor con esos parámetros:

bash
docker run -d --name mi_contenedor -p 8080:80 -e "API_KEY=abc123" --network mired mi_imagen:1.0
Esto creará un contenedor en segundo plano (-d), con nombre mi_contenedor, exponiendo el puerto 80 del contenedor en el puerto 8080 del host, definiendo una variable de entorno API_KEY, conectándolo a la red mired y usando la imagen mi_imagen con etiqueta 1.0.

Conectar contenedores entre sí

Si los contenedores están en la misma red personalizada, podrán comunicarse mediante sus nombres.

Para conectar contenedores existentes a una red, usar docker network connect nombre_red nombre_contenedor.

Estos pasos te permiten crear y configurar contenedores Docker con la flexibilidad para gestionar puertos, entornos, nombres y redes, lo cual es esencial para proyectos que involucren múltiples contenedores y servicios interconectados.
Opciones comunes incluyen:
-a o --all: Muestra todas las imágenes, incluidas las intermedias.
-q o --quiet: Muestra solo los IDs de las imágenes.
--filter: Filtra las imágenes según condiciones específicas.
--format: Formatea la salida de acuerdo con una plantilla personalizada.

si te sale este error hacer:
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
significa que tu usuario no tiene permiso para acceder al socket del daemon de Docker. Esto es común cuando Docker se instala y se usa sin permisos elevados o sin configurar el usuario adecuadamente.

Para solucionar esto, tienes dos opciones:
1.-Usar sudo temporalmente para ejecutar comandos Docker, por ejemplo:
sudo docker images
Esto funciona pero no es lo ideal a largo plazo porque cada comando Docker requeriría sudo.

2.-Configurar tu usuario para que pertenezca al grupo "docker", que tiene acceso al socket de Docker. Ejecuta estos comandos:

-Crea el grupo docker si no existe:
sudo groupadd docker

-Agrega tu usuario al grupo docker (reemplaza ${USER} por tu nombre de usuario o mantén la variable si estás en una terminal):
sudo usermod -aG docker ${USER}

-Para que los cambios tengan efecto, cierra la sesión de tu usuario y vuelve a iniciarla, o ejecuta:
su - ${USER}

-Ahora deberías poder ejecutar comandos Docker sin sudo, por ejemplo:
docker images

-Si sigues teniendo problemas, asegúrate de que el permiso del directorio .docker en tu home sea correcto con:
sudo chown "$USER":"$USER" ~/.docker -R
sudo chmod g+rwx ~/.docker -R
Con este procedimiento, el acceso al socket Docker debe quedar configurado para tu usuario y el error desaparecerá.
1.-Preparar el entorno base:
Instala Docker y Docker Compose en tu sistema para poder construir y manejar contenedores.

2.-Crear estructura de proyecto Laravel:
Puedes crear el proyecto Laravel localmente o usar un contenedor PHP con Composer para generarlo.
Si ya tienes un proyecto Laravel, colócalo en una carpeta donde trabajes con Docker.

3.-Crear archivo Dockerfile para PHP + Apache2 + extensiones relevantes:
Usarás la imagen base oficial de PHP 8.4 con Apache.
Instalarás las extensiones necesarias para Laravel y PostgreSQL, por ejemplo: pdo_pgsql, pgsql, zip, curl, xml, mbstring.
Copiarás el código fuente Laravel al contenedor.
Ejemplo básico de Dockerfile:
FROM php:8.4-apache

RUN apt-get update && apt-get install -y \
    libpq-dev \
    libzip-dev \
    zip \
    unzip \
    && docker-php-ext-install pdo_pgsql pgsql zip bcmath

COPY . /var/www/html/

RUN chown -R www-data:www-data /var/www/html \
    && a2enmod rewrite
    
4.-Configurar Docker Compose para los servicios:
Define servicios para PHP-Apache y PostgreSQL.
Vincula volúmenes para código y datos persistentes.
Configura variables de entorno para Laravel (DB connection).
Ejemplo básico de docker-compose.yml:
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:80"
    volumes:
      - ./:/var/www/html
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      POSTGRES_DB: laravel
      POSTGRES_USER: laraveluser
      POSTGRES_PASSWORD: laravelpass
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

5.-Configurar archivo .env de Laravel:
Ajusta las variables para conectarse a la base de datos PostgreSQL dentro del contenedor:

DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432
DB_DATABASE=laravel
DB_USERNAME=laraveluser
DB_PASSWORD=laravelpass

6.-Construir e iniciar los contenedores Docker:
En la terminal, ejecutar:
docker-compose up --build
Esto facilita manejar dependencias y la base de datos dentro del entorno Docker.

Resumen y conceptos clave:
Dockerfile: define cómo construir la imagen personalizada PHP+Apache con las extensiones necesarias.
Docker Compose: orquesta múltiples contenedores (app y db), redes y volúmenes.
Volúmenes: aseguran que tu código y los datos de la base de datos persistan fuera de los contenedores.
Laravel .env: configura la conexión a la base de datos PostgreSQL dentro de la red Docker.
Comandos Artisan dentro del contenedor mantienen el entorno controlado y consistente.
Este proceso modular te permite entender cómo Docker puede contenerizar un proyecto web completo con backend, webserver y base de datos separados pero comunicados, facilitando el desarrollo y pruebas locales sin alterar tu sistema nativo.
nohup celery -A mysite worker --loglevel=info > celery_worker.log &
nohup celery -A mysite beat --loglevel=info > celery_beat.log &
docker system prune [OPTIONS]
--all , -a		Remove all unused images not just dangling ones
--filter		API 1.28+
Provide filter values (e.g. 'label=<key>=<value>')
--force , -f		Do not prompt for confirmation
--volumes		Prune volumes
docker-compose run --rm frontend sh -c 'npx create-react-app プロジェクト名 --template typescript'
q
//show images
docker images

//show volumes
docker volume ls

//check if the volume is attached to any container:
docker ps -a --filter volume=<volume_name>
  
// remove volume
docker volume rm <volume_name>
  
//automatically delete unused volumes
docker volume prune

//upack mongo.tar with volume to the directory
tar -xvf mongo.tar -C /path/to/mongo-data

//run docker container from image with attached volume
//mongodb_dm - volume name
//mongo - container name
docker run -d --name mongo -v mongodb_dm:/data/db -p 27017:27017 mongo:latest
docker run -d --name mongo -v mongodb_dm:/data/db -p 27017:27017 mongo:4.4
// with attached volume
docker run -d --name mongo -v /path/to/mongo-data:/data/db -p 27017:27017 mongo:4.4
docker run -d --name mongo -v mongo:/data/db -p 27017:27017 mongo:4.4

// run shel inside the container
docker exec -it mongo mongo
// with attached volume and auth
docker run -d --name mongo -v /path/to/mongo-data:/data/db -p 27017:27017 mongo:4.4 --auth
docker exec -it mongo mongo -u "admin" -p "yourpassword" --authenticationDatabase "admin"

docker inspect <container_id>

//enter into container
docker exec -it <container ID> bash

//build daemon
docker-compose up --build -d

docker stop <container ID>
docker rm <container ID>


//postgres with attached volume(directory)
docker run -d --name postgres -e POSTGRES_USER=<user> -e POSTGRES_PASSWORD=<password> -p 5432:5432 -v /path/to/postgres:/var/lib/postgresql/data postgres:14


FROM php:8.2-fpm

# Arguments defined in docker-compose.yml
ARG user
ARG uid

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    libzip-dev \
    zip \
    unzip \
    && docker-php-ext-install zip

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
    chown -R $user:$user /home/$user

# Set working directory
WORKDIR /var/www

USER $user
// show dir inside image
docker run --rm -it --entrypoint=/bin/bash imagename
FROM python:3.11-slim


# Create a non-root user to run the app as
RUN addgroup --system app && adduser --system --group app

# Environment variables
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=off \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_DEFAULT_TIMEOUT=100 \
    POETRY_VIRTUALENVS_IN_PROJECT=true \
    # Set Poetry to NOT install the dependencies into a virtual environment, instead install them into the system's Python environment
    POETRY_VIRTUALENVS_CREATE=false \
    POETRY_NO_INTERACTION=1 \
    PYTHONPATH=${PYTHONPATH}:${PWD}

# Make a directory for the project
RUN mkdir /app

# Change to the `/app` directory
WORKDIR /app

# Copy the project files over to the container
COPY pyproject.toml /app
COPY . /app

# Chown all the files to the app user
RUN chown -R app:app /app

# Install Poetry
RUN pip3 install poetry

# Export the Poetry pack list to another format
RUN poetry export -f requirements.txt > requirements.txt

# Install the Python dependencies
RUN poetry install --only main

# Become the `app` user
USER app

# Expose port 8000 on the container
EXPOSE 8000

#CMD ["poetry", "run", "gunicorn"]
CMD ["gunicorn"]
docker exec -it <container_id> bash
docker run --privileged -idt kindest/node:v1.21.2
docker build -t imagename bath dockerfilename
FROM golang:alpine as builder

label "maintainer"="amirabbasmehvari@gmail.com"
RUN mkdir /app
WORKDIR /app/
COPY . /app/
RUN go build -o main .

FROM alpine
COPY --from=builder /app/main /app/
WORKDIR /app/
CMD ["./main"]
FROM php:8.1-fpm

RUN apt-get update

COPY . /app
RUN ls -l
RUN php -v
CMD php /app/index.php




















docker image ls
docker images
docker image history imagename
docker build -t imagename:version path
FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y curl

COPY . /app

RUN ls -l

CMD python /app/app.py










docker build -t imagename:version path
create mysql container
for find server of the mysql run command :
docker container inspect mysql
find Networks.brigde.IpAddress
copy ip address and use 
docker container ls -a
docker images
docker pull image
docker container run -exec -it --rm --name container-name image bash
docker container run -exec -it --name container-name image bash
docker container exec -it container-name bash
docker ps
docker container inspect container-name
docker container stats
docker container top container-name
docker container pause container-name
docker container unpause container-name
docker container stop
docker container cp file-path container-name:path

// The mysql container is reading from the wrong DB port.

// While 127.0.0.1 might work in the DB client, Docker might have trouble with this. 

// Change the DB_HOST value to your local network's IP as returned by the ifconfig command
// Docker is unable to map the mysql folder containing the socket file.

// Change the following line in the volumes property of your db container in the docker-compose.yml from
- 'sail-mysql:/var/lib/mysql' 

// to 
'- '${MYSQL_DOCKER_FOLDER}:/var/lib/mysql'

// The corresponding env variable might hold something like MYSQL_DOCKER_FOLDER=./mysql

// Create the "mysql" folder at the root of the file
// Follow the instructions in the following video: https://www.youtube.com/watch?v=iHad9TH9mOA&ab_channel=Tuto1902

// Then add the following to your /docker/8.2/ext-xdebug.ini
xdebug.log=/var/log/xdebug.log
xdebug.log_level=3

// Add the following to the Dockerfile
RUN touch /var/log/xdebug.log \
    && chmod 766 /var/log/xdebug.log

docker run -d -p 80 --restart unless-stopped nginx
docker ps # current containers
docker run # create and start the container
docker create # create container
dokcer exec # to run commnads in container for once
docker volume # create a docker volume
docker network # create a docker network
docker rm # remove container 
docker images # list the images
docker rmi # remove image
docker build # build a new image from dockerfile
docker push # push your image to docker repo
docker pull # download an image from docker repo
docker commit # create an image from container
docker-compose down # Stop container on current dir if there is a docker-compose.yml
docker rm -fv $(docker ps -aq) # Remove all containers
sudo lsof -i -P -n | grep <port number> # List who's using the port
# sudo kill -9 <process id> (macOS)
# sudo kill <process id> (Linux)
docker run -d \
   -v /etc/timezone:/etc/timezone:ro \  
   -v /etc/localtime:/etc/localtime:ro \
   ...
#Copy the image

$ docker pull doctorkirk/oracle-19c

#Create local directory

$ mkdir -p /your/custom/path/oracle-19c/oradata
$ cd /your/custom/path/
$ sudo chown -R 54321:54321 oracle-19c/

#Run the Container

docker run --name oracle-19c \
  -p 1521:1521 \
  -e ORACLE_SID=[ORACLE_SID] \
  -e ORACLE_PWD=[ORACLE_PASSWORD] \
  -e ORACLE_CHARACTERSET=[CHARSET] \
  -v /your/custom/path/oracle-19c/oradata/:/opt/oracle/oradata \
doctorkirk/oracle-19c

#Charset: WE8MSWIN1252(*default), AL16UTF8, US7ASCI
#* If omitted in docker run , the default characterset for this build will be WE8MSWIN1252.
docker run -d --restart=always \
        --name oracle \
        --privileged  \
        -e ORACLE_SID=<custom sid> \
        -v /srv/oradata:/u01/app/oracle \
        -p 8080:8080 -p 1521:1521 \
 absolutapps/oracle-12c-ee
docker run -e 'ACCEPT_EULA=Y' \
    -e 'MSSQL_SA_PASSWORD=<YourStrong!Passw0rd>' \
    -p 1433:1433 -v <host directory>/data:/var/opt/mssql/data \
    -v <host directory>/log:/var/opt/mssql/log \
    -v <host directory>/secrets:/var/opt/mssql/secrets \
    -d mcr.microsoft.com/mssql/server:2019-latest
sudo mkdir -p /your/custom/path/oracle-19c/oradata/
sudo chmod -R 777 /your/custom/path/

docker run -d --name oracle19db \
  -p 1521:1521 \
  -e ORACLE_SID=ORCL \
  -e ORACLE_PDB=ORCLDB \
  -e ORACLE_PWD=Oracle123 \
  -e ORACLE_CHARSET=AL32UTF8 \
  -v /your/custom/path/oracle-19c/oradata:/opt/oracle/oradata \
  banglamon/oracle193db:19.3.0-ee

# Charset Value: WE8MSWIN1252, AL16UTF8

# ALTER SESSION SET NLS_DATE_FORMAT = 'RRRR-MM-DD';
# ALTER SESSION SET NLS_TIME_FORMAT = 'HH24:MI:SS';
# ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'RRRR-MM-DD HH24:MI:SS';
# ALTER SESSION SET NLS_TIME_TZ_FORMAT = 'HH24:MI:SS TZR';
# ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'RRRR-MM-DD HH24:MI:SS TZR';

# docker exec -it oracle19db bash -c "source /home/oracle/.bashrc; sqlplus /nolog”
# connect sys as sysdba;

# alter session set "_ORACLE_SCRIPT"=true;
# create user sistemas identified by las36horas;
# GRANT CONNECT, RESOURCE, DBA TO sistemas;
# GRANT UNLIMITED TABLESPACE TO sistemas;
$> docker pull haskell
$> docker run -it haskell stack <parameters>


$> git clone https://github.com/jean-lopes/dfm-to-json.git

$> cd dfm-to-json

$> stack setup
$> stack install
$> dfm-to-json --version
#put your databases on /svr/fb-databases

docker run -d --name fb -p 3050:3050 -v /srv/fb-databases:/db almeida/firebird

#connect using localhost:3050:db/<database file>.gdb
:> docker run -it --name fb --rm -v ~/tmp:/tmp almeida/firebird gbak -b -v 192.168.1.251:c:/host/path/database.fdb /tmp/backup.bak -user sysdba -pass XXXXX
Dozzle for Docker, error view
docker exec -it mongo <command>
# RUN TO CREATE A NEW PROJECT
# docker run --rm -v `pwd`:/var/www/html pimcore/pimcore:PHP8.0-fpm composer create-project pimcore/skeleton my-project

cd ./{NAME_OF_THE_PROJECT_FOLDER}

docker-compose up -d

# TO RUN ONLY WITH A LOCAL DATABASE.
# docker-compose exec php-fpm vendor/bin/pimcore-install --mysql-host-socket=db --mysql username=pimcore --mysql-password=pimcore --mysql-database=pimcore

docker-compose exec php-fpm composer install

docker-compose exec php-fpm chown -R www-data:www-data var

docker inspect -f '{{range $key, $value := .NetworkSettings.Networks}}{{$key}} {{end}}' [container]
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id
version: '3.8'

services:
  fastapi_api:
    build:
      context: ./<path to Dockerfile>
    # the 'app.main' part of the next line assumes your main.py file is in a folder named 'app'
    command: gunicorn app.main:app --bind 0.0.0.0:5000 -w 2 -k uvicorn.workers.UvicornWorker
    ports:
      # host:container
      - "8000:5000"
FROM python:3.11-rc-slim

ENV WORKDIR=/usr/src/app
ENV USER=app
ENV APP_HOME=/home/app/web
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1

WORKDIR $WORKDIR

RUN pip install --upgrade pip
COPY ./requirements.txt $WORKDIR/requirements.txt
RUN pip install -r requirements.txt

RUN adduser --system --group $USER
RUN mkdir $APP_HOME
WORKDIR $APP_HOME

COPY . $APP_HOME
RUN chown -R $USER:$USER $APP_HOME
USER $USER
/* clone repo */
git clone ...

/* docker up */
docker-compose up -d

/* Install pimcore dependencies*/
docker exec -it php-fpm /bin/bash
composer install

/* Install pimcore and define local db */
docker-compose exec php-fpm vendor/bin/pimcore-install --mysql-host-socket=db --mysql-username=pimcore --mysql-password=pimcore --mysql-database=pimcore

/* change owner to ./var folder */
docker-compose exec php-fpm chown -R www-data:www-data var
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
REWRITERULE ^(.*)$ http://dockerbackend/$1 [P]
//Commmand prompt 
wsl --list -v

//Expected output
//  NAME                   STATE           VERSION
//* docker-desktop         Running         2
//  docker-desktop-data    Running         2

wsl  --shutdown

mkdir D:\Docker\wsl\data\ //your path

wsl --export docker-desktop-data "D:\Docker\wsl\data\docker-desktop-data.tar"

wsl --unregister docker-desktop-dat

awsl --import docker-desktop-data "D:\Docker\wsl\data" "D:\Docker\wsl\data\docker-desktop-data.tar" --version 2


//Delete the exported .tar file: D:\Docker\wsl\data\docker-desktop-data.tar and nothing more!
docker ps //List running containers
docker ps --all //List all containers
docker system prune //Remove unused data
docker system prune --all //Remove all unused images not just dangling ones
docker run {IMAGE} //combining 'docker create' & 'docker start'
docker run -d {IMAGE} // Run container in background and print container ID
docker run -p {systemport}:{dockerport} {IMAGE} // Map Port of the OS to the dockerport
docker run -it {IMAGE} //Input output
docker run -it {IMAGE} sh //Run docker container and shell into it
docker exec -it {IMAGE} sh //Shell into running docker container
docker build . //Build docker image with random id 
docker build -t {REPO}/{TAGNAME} . //Build docker image with random id 
docker stop {IMAGE} //Stop container from running

docker-compose up //Execute docker compose
docker-compose up --build // Rebuild Docker container and execute docker compose
docker-compose -d {IMAGE} // Run container in background and print container ID
docker-compose down //Stop container from running
kubectl rollout restart deploy -n cnext-di-demo
## Dockerfile
FROM php:7.4-fpm

# Arguments defined in docker-compose.yml
ARG user
ARG uid

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
    chown -R $user:$user /home/$user

# Set working directory
WORKDIR /var/www

USER $user

## EOF Dockerfile

## docker-compose.yaml
# Docker compose for PHP, Composer and nginx
# Check Dockerfile to create app image, PHP 7.4 and Composer
# Run: docker-compose up
# After mounted, open container cli 
# 
# Update laravel packages:
##### composer update
# Restart container to apply nginx configuration
##### docker compose restart 

version: "3.7"
services:
  app:
    build:
      args:
        user: sammy
        uid: 1000
      context: ./
      dockerfile: Dockerfile
    image: my-app
    container_name: myapp-php
    restart: always
    working_dir: /var/www/
    volumes:
      - ./:/var/www
    networks:
      - webdev

  nginx:
    image: nginx:alpine
    container_name: myapp-nginx
    restart: unless-stopped
    ports:
      - 8000:80
    volumes:
      - ./:/var/www
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    networks:
      - webdev

networks:
  webdev:
    driver: bridge
    
## EOF docker-compose.yml

## create a nginx.conf file in the root of your app
## nginx.conf

server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}

## EOF nginx.conf


Run: 
docker-compose up

When container is up open container console (cli)
composer update
docker compose restart

docker build -t <image-name>
  
docker run -d -p <public-port>:<image-port> <image-name>
  
docker run -it <image-name> sh
docker ps //List running containers
docker ps --all //List all containers
docker system prune //Remove unused data
docker system prune --all //Remove all unused images not just dangling ones
docker run {IMAGE} //combining 'docker create' & 'docker start'
docker run -d {IMAGE} // Run container in background and print container ID
docker run -p {systemport}:{dockerport} {IMAGE} // Map Port of the OS to the dockerport
docker run -it {IMAGE} //Input output
docker run -it {IMAGE} sh //Run docker container and shell into it
docker exec -it {IMAGE} sh //Shell into running docker container
docker build . //Build docker image with random id 
docker build -t {REPO}/{TAGNAME}. //Build docker image with random id 
docker stop {IMAGE} //Stop container from running

docker-compose up //Execute docker compose
docker-compose up --build // Rebuild Docker container and execute docker compose
docker-compose -d {IMAGE} // Run container in background and print container ID
docker-compose down //Stop container from running
docker login -u AWS -p <password> -e none https://<aws_account_id>.dkr.ecr.<region>.amazonaws.com
docker build -t imagename -f Dockerfile2 .
# install docker
sudo apt-get install docker.io

# create and run a container from an image from the Docker Hub
sudo docker run --name firstContainer ubuntu:latest # where firstContainer is the name of the container

# list locally available docker containers
sudo docker ps -a

# open a docker container in interactive mode in the terminal
sudo docker run -it --name myContainer ubuntu:latest # where myContainer is the container name
# you can exit the container by pressing CTRL+P and CTRL+Q

# attach container to terminal
sudo docker attach myContainer # the container will now stay open in the background even after exiting via CTRL+P and CTRL+Q

# execute commands in the container running in the background
sudo docker exec myContainer echo $PATH

# delete containers
sudo docker rm -f firstContainer myContainer

# create new docker image based on your local environment/container
sudo docker commit myNginx docker_id/image_name # where myNginx is the name of your currently running container

# create new docker container from an image from a previously committed image
sudo docker run -it --name nginxNew docker_id/image_name

# list images on your machine
sudo docker image ls

# login to your docker hub account from the terminal
sudo docker login # you will be prompted to enter your id and password

# push an image to docker hub when logged into your docker account
sudo docker push docker_id/image_name

# run a docker container in the background
sudo docker run -d --name myApp nginx

# start an interactive bash terminal for the container running in the background
sudo docker exec -it myApp bashapt-get

# stop a running container
sudo docker stop myApp

# start a stopped container again
sudo docker start myApp
docker exec -it postgres psql -U postgres -d postgres -c 'SELECT * FROM "dataelement"'
-- create the databases
CREATE DATABASE IF NOT EXISTS projectone;

-- create the users for each database
CREATE USER 'projectoneuser'@'%' IDENTIFIED BY 'somepassword';
GRANT CREATE, ALTER, INDEX, LOCK TABLES, REFERENCES, UPDATE, DELETE, DROP, SELECT, INSERT ON `projectone`.* TO 'projectoneuser'@'%';

FLUSH PRIVILEGES;
rsync через docker'овский туннель гонять вот так: rsync -e 'docker exec -i' --blocking-io -rv CONTAINER_NAME:/data ., главное не забыть добавить --blocking-io.
version: '2.1'

services:
  zoo1:
    image: zookeeper:3.4.9
    hostname: zoo1
    ports:
      - "2181:2181"
    environment:
        ZOO_MY_ID: 1
        ZOO_PORT: 2181
        ZOO_SERVERS: server.1=zoo1:2888:3888
    volumes:
      - ./zk-single-kafka-single/zoo1/data:/data
      - ./zk-single-kafka-single/zoo1/datalog:/datalog

  kafka1:
    image: confluentinc/cp-kafka:5.5.0
    hostname: kafka1
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_LISTENERS: LISTENER_DOCKER_INTERNAL://kafka1:19092,LISTENER_DOCKER_EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: LISTENER_DOCKER_INTERNAL:PLAINTEXT,LISTENER_DOCKER_EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: LISTENER_DOCKER_INTERNAL
      KAFKA_ZOOKEEPER_CONNECT: "zoo1:2181"
      KAFKA_BROKER_ID: 1
      KAFKA_LOG4J_LOGGERS: "kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO"
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
    volumes:
      - ./zk-single-kafka-single/kafka1/data:/var/lib/kafka/data
    depends_on:
      - zoo1
$ docker run -d \
  --name realopinsight \
  --network host \
  --publish 4583:4583 \
  rchakode/realopinsight
star

Thu Sep 18 2025 16:01:46 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Sep 03 2025 18:15:09 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Sep 03 2025 15:30:58 GMT+0000 (Coordinated Universal Time)

#docker
star

Mon Sep 01 2025 17:03:05 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Aug 28 2025 16:56:26 GMT+0000 (Coordinated Universal Time)

#docker
star

Tue Aug 26 2025 20:27:16 GMT+0000 (Coordinated Universal Time)

#docker
star

Tue Aug 26 2025 18:44:04 GMT+0000 (Coordinated Universal Time)

#docker
star

Tue Aug 26 2025 17:20:47 GMT+0000 (Coordinated Universal Time)

#docker
star

Tue Aug 26 2025 16:13:26 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 22 2025 17:29:48 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 22 2025 15:41:50 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 22 2025 15:27:46 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 22 2025 15:25:19 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 22 2025 15:22:18 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 22 2025 15:06:03 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 22 2025 15:02:06 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 22 2025 13:51:40 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Aug 20 2025 17:41:01 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Aug 20 2025 17:35:40 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Aug 20 2025 17:33:07 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Aug 20 2025 17:32:22 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Aug 20 2025 17:30:15 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Aug 20 2025 17:21:47 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Aug 20 2025 14:18:20 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 15 2025 17:50:19 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 15 2025 17:31:01 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 15 2025 17:29:03 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 15 2025 17:28:09 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 15 2025 17:27:35 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 15 2025 17:15:05 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 15 2025 16:38:54 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Aug 14 2025 20:07:56 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Aug 14 2025 19:51:58 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Aug 14 2025 19:47:04 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Aug 14 2025 18:45:07 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Aug 14 2025 14:05:02 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Aug 14 2025 14:00:35 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Aug 14 2025 13:46:48 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Aug 14 2025 13:10:31 GMT+0000 (Coordinated Universal Time)

#php #laravel #docker #compose
star

Mon May 19 2025 02:29:47 GMT+0000 (Coordinated Universal Time)

#seid #docker #rust
star

Thu Sep 05 2024 07:12:34 GMT+0000 (Coordinated Universal Time) https://www.google.com/search?q

#shell #docker
star

Wed Jul 31 2024 08:02:28 GMT+0000 (Coordinated Universal Time) https://qiita.com/91works-i-kato/items/9f9ad03fee32d42ed547

#react #type #docker
star

Thu Apr 18 2024 19:38:43 GMT+0000 (Coordinated Universal Time)

#docker #mongodb #postgres
star

Tue Jan 16 2024 03:13:04 GMT+0000 (Coordinated Universal Time)

#docker
star

Sat Jan 13 2024 08:09:40 GMT+0000 (Coordinated Universal Time)

#docker
star

Sat Jul 22 2023 23:20:25 GMT+0000 (Coordinated Universal Time)

#python #fastapi #poetry #docker
star

Thu Jun 08 2023 16:59:03 GMT+0000 (Coordinated Universal Time) https://chat.openai.com/

#k8s #docker #bash
star

Thu Jun 08 2023 16:58:09 GMT+0000 (Coordinated Universal Time) https://chat.openai.com/

#bash #k8s #docker
star

Tue Mar 28 2023 07:53:37 GMT+0000 (Coordinated Universal Time)

#docker
star

Tue Mar 28 2023 07:52:34 GMT+0000 (Coordinated Universal Time)

#docker #multi-builder
star

Mon Mar 27 2023 09:27:56 GMT+0000 (Coordinated Universal Time)

#docker #php
star

Mon Mar 27 2023 09:13:54 GMT+0000 (Coordinated Universal Time)

#docker #php
star

Mon Mar 27 2023 08:33:41 GMT+0000 (Coordinated Universal Time)

#docker #wordpress
star

Mon Mar 27 2023 08:29:05 GMT+0000 (Coordinated Universal Time)

#docker #wordpress
star

Mon Mar 27 2023 08:28:32 GMT+0000 (Coordinated Universal Time)

#docker #wordpress
star

Sun Mar 26 2023 05:01:38 GMT+0000 (Coordinated Universal Time)

#docker #wordpress
star

Sat Mar 25 2023 10:25:48 GMT+0000 (Coordinated Universal Time)

#docker
star

Thu Feb 09 2023 20:35:12 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/65213171/disable-xdebug-3-could-not-connect-message-in-cli

#docker
star

Mon Jan 23 2023 09:12:00 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/51445846/elasticsearch-max-virtual-memory-areas-vm-max-map-count-65530-is-too-low-inc

#elasticsearch #docker #kibana
star

Fri Oct 28 2022 03:43:40 GMT+0000 (Coordinated Universal Time) https://www.educative.io/module/page/LgoqGKFl7YxO2wNDm/10370001/5453871022342144/5091147352375296

#docker #restart #fail
star

Tue Oct 25 2022 16:12:41 GMT+0000 (Coordinated Universal Time) https://www.educative.io/

#docker #run #port
star

Thu Sep 08 2022 22:33:02 GMT+0000 (Coordinated Universal Time) https://www.google.com/search?q

#whatever #docker #grepper #google-search
star

Thu Sep 08 2022 18:14:59 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/37971961/docker-error-bind-address-already-in-use

#bash #docker
star

Tue Aug 30 2022 13:55:53 GMT+0000 (Coordinated Universal Time)

#docker
star

Mon Aug 29 2022 19:51:25 GMT+0000 (Coordinated Universal Time)

#bash #docker #oracle
star

Mon Aug 29 2022 19:08:02 GMT+0000 (Coordinated Universal Time)

#bash #docker
star

Mon Aug 29 2022 18:38:18 GMT+0000 (Coordinated Universal Time)

#bash #docker
star

Mon Aug 29 2022 18:33:43 GMT+0000 (Coordinated Universal Time)

#sql #bash #docker
star

Mon Aug 29 2022 18:30:27 GMT+0000 (Coordinated Universal Time)

#bash #docker #delphi
star

Mon Aug 29 2022 18:29:43 GMT+0000 (Coordinated Universal Time)

#docker
star

Mon Aug 29 2022 18:13:16 GMT+0000 (Coordinated Universal Time)

#bash #docker
star

Wed Jul 06 2022 09:34:01 GMT+0000 (Coordinated Universal Time)

#docker
star

Tue Jul 05 2022 23:30:51 GMT+0000 (Coordinated Universal Time)

#docker
star

Wed Mar 23 2022 14:56:15 GMT+0000 (Coordinated Universal Time)

#pimcore #docker #docker-compose
star

Thu Mar 03 2022 16:05:26 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/41928729/docker-failed-to-register-layer

#commandline #docker
star

Thu Mar 03 2022 16:05:05 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/41928729/docker-failed-to-register-layer

#commandline #docker
star

Wed Feb 02 2022 21:40:50 GMT+0000 (Coordinated Universal Time) https://maximorlov.com/4-reasons-why-your-docker-containers-cant-talk-to-each-other/

#docker #networking
star

Wed Feb 02 2022 21:40:14 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/17157721/how-to-get-a-docker-containers-ip-address-from-the-host

#docker #networking
star

Wed Feb 02 2022 21:24:13 GMT+0000 (Coordinated Universal Time)

#docker #ssh
star

Mon Jan 31 2022 02:16:16 GMT+0000 (Coordinated Universal Time)

#python #fastapi #docker
star

Mon Jan 31 2022 02:15:50 GMT+0000 (Coordinated Universal Time)

#python #fastapi #docker
star

Mon Jan 17 2022 08:34:07 GMT+0000 (Coordinated Universal Time)

#docker #pimcore
star

Tue Jan 04 2022 21:27:35 GMT+0000 (Coordinated Universal Time)

#ssl #letsencrypt #linux #cyberpanel #docker
star

Thu Dec 23 2021 09:36:46 GMT+0000 (Coordinated Universal Time)

#docker #win10
star

Mon Dec 06 2021 20:40:02 GMT+0000 (Coordinated Universal Time)

#docker
star

Mon Dec 06 2021 11:49:55 GMT+0000 (Coordinated Universal Time) https://blog.codetitans.pl/post/howto-docker-over-wsl2-location/

#docker #wsl2
star

Wed Dec 01 2021 08:41:07 GMT+0000 (Coordinated Universal Time)

#powershell #docker #pods #restart
star

Tue Nov 16 2021 11:37:21 GMT+0000 (Coordinated Universal Time)

#docker #nginx #php #phpfm
star

Thu Oct 07 2021 12:02:59 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Oct 01 2021 11:30:05 GMT+0000 (Coordinated Universal Time)

#docker
star

Fri Aug 13 2021 08:16:38 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/29600369/starting-and-populating-a-postgres-container-in-docker

#docker
star

Tue Jul 20 2021 07:40:25 GMT+0000 (Coordinated Universal Time) https://www.youtube.com/watch?v

#zeet #deploy #docker
star

Wed Jul 07 2021 19:25:34 GMT+0000 (Coordinated Universal Time)

#docker #aws
star

Wed Apr 28 2021 08:20:00 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/32997269/copying-a-file-in-a-dockerfile-no-such-file-or-directory

#docker
star

Sat Apr 10 2021 05:55:14 GMT+0000 (Coordinated Universal Time)

#linux #docker
star

Fri Mar 19 2021 15:46:23 GMT+0000 (Coordinated Universal Time)

#docker #psql
star

Wed Feb 24 2021 20:06:09 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/43322033/create-database-on-docker-compose-startup

#sql #docker
star

Sun Nov 29 2020 16:44:07 GMT+0000 (Coordinated Universal Time) https://forums.docker.com/t/start-a-gui-application-as-root-in-a-ubuntu-container/17069

#bash #docker #ubuntu
star

Wed Oct 14 2020 17:12:11 GMT+0000 (Coordinated Universal Time) https://habr.com/ru/post/277699/

#docker #shell
star

Wed Oct 07 2020 20:56:30 GMT+0000 (Coordinated Universal Time) https://github.com/zircote/swagger-php

#docker #swagger #php
star

Sun Jun 21 2020 12:42:52 GMT+0000 (Coordinated Universal Time) https://github.com/simplesteph/kafka-stack-docker-compose

#kafka #docker
star

Sat Jun 20 2020 22:57:14 GMT+0000 (Coordinated Universal Time) https://github.com/rchakode/realopinsight

#k8s #docker #tools

Save snippets that work with our extensions

Available in the Chrome Web Store Get Firefox Add-on Get VS Code extension