commit 57684a8a83f136273bfeb1e3072af69cbd239e0c Author: admin Date: Fri May 30 12:43:55 2025 -0600 inital commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..793b3ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/configs/code-server/.local/* +!/configs/code-server/.local/.gitkeep + +/configs/code-server/.config/* +!/configs/code-server/.config/.gitkeep + +.env +.env* \ No newline at end of file diff --git a/Dockerfile.code-server b/Dockerfile.code-server new file mode 100644 index 0000000..b922a07 --- /dev/null +++ b/Dockerfile.code-server @@ -0,0 +1,84 @@ +FROM codercom/code-server:latest + +USER root + +# Install Python and dependencies +RUN apt-get update && apt-get install -y \ + python3 \ + python3-pip \ + python3-venv \ + python3-full \ + pipx \ + # Dependencies for CairoSVG and Pillow (PIL) + libcairo2-dev \ + libfreetype6-dev \ + libffi-dev \ + libjpeg-dev \ + libpng-dev \ + libz-dev \ + python3-dev \ + pkg-config \ + # Additional dependencies for advanced image processing + libwebp-dev \ + libtiff5-dev \ + libopenjp2-7-dev \ + liblcms2-dev \ + libxml2-dev \ + libxslt1-dev \ + # PDF generation dependencies + weasyprint \ + fonts-roboto \ + # Git for git-based plugins + git \ + # For lxml + zlib1g-dev \ + # Required for some plugins + build-essential \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Switch to non-root user (coder) +USER coder + +# Set up a virtual environment for mkdocs +RUN mkdir -p /home/coder/.venv +RUN python3 -m venv /home/coder/.venv/mkdocs + +# Install mkdocs-material in the virtual environment with all extras +RUN /home/coder/.venv/mkdocs/bin/pip install "mkdocs-material[imaging,recommended,git]" + +# Install additional useful MkDocs plugins +RUN /home/coder/.venv/mkdocs/bin/pip install \ + mkdocs-minify-plugin \ + mkdocs-git-revision-date-localized-plugin \ + mkdocs-glightbox \ + mkdocs-redirects \ + mkdocs-awesome-pages-plugin \ + mkdocs-blog-plugin \ + mkdocs-rss-plugin \ + mkdocs-meta-descriptions-plugin \ + mkdocs-swagger-ui-tag \ + mkdocs-macros-plugin \ + mkdocs-material-extensions \ + mkdocs-section-index \ + mkdocs-table-reader-plugin \ + mkdocs-pdf-export-plugin \ + mkdocs-mermaid2-plugin \ + pymdown-extensions \ + pygments \ + pillow \ + cairosvg + +# Add the virtual environment bin to PATH +ENV PATH="/home/coder/.venv/mkdocs/bin:${PATH}" + +# Add shell configuration to activate the virtual environment in .bashrc +RUN echo 'export PATH="/home/coder/.venv/mkdocs/bin:$PATH"' >> ~/.bashrc +RUN echo 'export PATH="/home/coder/.local/bin:$PATH"' >> ~/.bashrc + +# Create a convenience script to simplify running mkdocs commands +RUN mkdir -p /home/coder/.local/bin \ + && echo '#!/bin/bash\ncd /home/coder/mkdocs\nmkdocs "$@"' > /home/coder/.local/bin/run-mkdocs \ + && chmod +x /home/coder/.local/bin/run-mkdocs + +WORKDIR /home/coder diff --git a/README.md b/README.md new file mode 100644 index 0000000..69fc0c8 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# Changemaker Lite + +Changemaker Lite is a streamlined documentation and development platform featuring essential self-hosted services for creating, managing, and automating content workflows. + +## Features + +- **Homepage**: Modern dashboard for accessing all services +- **Code Server**: VS Code in your browser for remote development +- **MkDocs Material**: Beautiful documentation with live preview +- **Static Site Server**: High-performance hosting for built sites +- **Listmonk**: Self-hosted newsletter and email campaign management +- **PostgreSQL**: Reliable database backend +- **n8n**: Workflow automation and service integration +- **NocoDB**: No-code database platform and smart spreadsheet interface + +## Quick Start + +```bash +# Clone the repository +git clone https://git.albertademocracytaskforce.org/admin/ab.dem.tf.changemaker.git +cd changemaker.lite + +# Configure environment (creates .env file) +./config.sh + +# Start all services +docker compose up -d +``` + +## Service Access + +After starting, access services at: + +- **Homepage Dashboard**: http://localhost:3010 +- **Documentation (Dev)**: http://localhost:4000 +- **Documentation (Built)**: http://localhost:4001 +- **Code Server**: http://localhost:8888 +- **Listmonk**: http://localhost:9000 +- **n8n**: http://localhost:5678 +- **NocoDB**: http://localhost:8090 + +## Documentation + +Complete documentation is available in the MkDocs site, including: + +- Service configuration guides +- Integration examples +- Workflow automation tutorials +- Troubleshooting guides + +Visit http://localhost:4000 after starting services to access the full documentation. \ No newline at end of file diff --git a/add-cname-records.sh b/add-cname-records.sh new file mode 100755 index 0000000..5e26427 --- /dev/null +++ b/add-cname-records.sh @@ -0,0 +1,290 @@ +#!/bin/bash +echo "#############################################################" +echo "# " +echo "# DNS Setup for Changemaker.lite Services " +echo "# " +echo "# This script will ADD DNS records for your services. " +echo "# Existing DNS records will NOT be deleted. " +echo "# " +echo "#############################################################" +echo "" +echo "-------------------------------------------------------------" +echo "Cloudflare Credentials Required" +echo "Please ensure your .env file contains the following variables:" +echo " CF_API_TOKEN=your_cloudflare_api_token" +echo " CF_ZONE_ID=your_cloudflare_zone_id" +echo " CF_TUNNEL_ID=your_cloudflared_tunnel_id" +echo " CF_DOMAIN=yourdomain.com" +echo "" +echo "You can find these values in your Cloudflare dashboard:" +echo " - API Token: https://dash.cloudflare.com/profile/api-tokens (Create a token with Zone:DNS:Edit and Access:Apps:Edit permissions for your domain)" +echo " - Zone ID: On your domain's overview page" +echo " - Tunnel ID: In the Zero Trust dashboard under Access > Tunnels" +echo " - Domain: The domain you want to use for your services" +echo "" +echo "-------------------------------------------------------------" +echo "" +read -p "Type 'y' to continue or any other key to abort: " consent +if [[ "$consent" != "y" && "$consent" != "Y" ]]; then + echo "Aborted by user." + exit 1 +fi + +# Source environment variables from the .env file in the same directory +ENV_FILE="$(dirname "$0")/.env" +if [ -f "$ENV_FILE" ]; then + export $(grep -v '^#' "$ENV_FILE" | xargs) +else + echo "Error: .env file not found at $ENV_FILE" + exit 1 +fi + +# Check if required Cloudflare variables are set +if [ -z "$CF_API_TOKEN" ] || [ -z "$CF_ZONE_ID" ] || [ -z "$CF_TUNNEL_ID" ] || [ -z "$CF_DOMAIN" ]; then + echo "Error: One or more required Cloudflare environment variables (CF_API_TOKEN, CF_ZONE_ID, CF_TUNNEL_ID, CF_DOMAIN) are not set in $ENV_FILE." + exit 1 +fi + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is required but not installed. Please install jq to continue." + echo "On Debian/Ubuntu: sudo apt-get install jq" + echo "On RHEL/CentOS: sudo yum install jq" + exit 1 +fi + +# Array of subdomains that need DNS records - updated to match our active services +SUBDOMAINS=( + "dashboard" + "code" + "listmonk" + "docs" + "n8n" + "db" + "git" +) + +# Function to check if DNS record already exists +record_exists() { + local subdomain=$1 + local records=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records?name=$subdomain.$CF_DOMAIN" \ + -H "Authorization: Bearer $CF_API_TOKEN" \ + -H "Content-Type: application/json") + + local count=$(echo $records | jq -r '.result | length') + [ "$count" -gt 0 ] +} + +# Add CNAME records for each subdomain (only if they don't exist) +echo "Adding DNS records for services..." + +for subdomain in "${SUBDOMAINS[@]}"; do + if record_exists "$subdomain"; then + echo "DNS record for $subdomain.$CF_DOMAIN already exists, skipping..." + else + echo "Adding CNAME record for $subdomain.$CF_DOMAIN..." + + response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \ + -H "Authorization: Bearer $CF_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data "{ + \"type\": \"CNAME\", + \"name\": \"$subdomain\", + \"content\": \"$CF_TUNNEL_ID.cfargotunnel.com\", + \"ttl\": 1, + \"proxied\": true + }") + + success=$(echo $response | jq -r '.success') + if [ "$success" == "true" ]; then + echo "✓ Successfully added CNAME record for $subdomain.$CF_DOMAIN" + else + echo "✗ Failed to add CNAME record for $subdomain.$CF_DOMAIN" + echo "Error: $(echo $response | jq -r '.errors[0].message')" + fi + fi +done + +# Add root domain record if it doesn't exist +if record_exists "@"; then + echo "Root domain DNS record already exists, skipping..." +else + echo "Adding root domain CNAME record..." + response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \ + -H "Authorization: Bearer $CF_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data "{ + \"type\": \"CNAME\", + \"name\": \"@\", + \"content\": \"$CF_TUNNEL_ID.cfargotunnel.com\", + \"ttl\": 1, + \"proxied\": true + }") + + success=$(echo $response | jq -r '.success') + if [ "$success" == "true" ]; then + echo "✓ Successfully added root domain CNAME record" + else + echo "✗ Failed to add root domain CNAME record" + echo "Error: $(echo $response | jq -r '.errors[0].message')" + fi +fi + +echo "" +echo "DNS records setup complete!" +echo "" + +# Prompt for admin email for secured services +echo "-------------------------------------------------------------" +echo "Setting up Cloudflare Access Protection" +echo "-------------------------------------------------------------" +echo "" +echo "The following services will be protected with authentication:" +echo " - dashboard.$CF_DOMAIN" +echo " - code.$CF_DOMAIN" +echo "" +echo "Please enter the admin email address that should have access:" +read ADMIN_EMAIL + +# Validate email format +if [[ ! "$ADMIN_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then + echo "Error: Invalid email format. Please provide a valid email address." + exit 1 +fi + +# Services that require authentication - updated for our use case +PROTECTED_SERVICES=("dashboard" "code") + +# Services that should have bypass policies (public access) - updated for our use case +BYPASS_SERVICES=("listmonk" "docs" "n8n" "db" "git") + +# Function to create access application with email authentication +create_protected_app() { + local service=$1 + echo "Setting up authentication for $service.$CF_DOMAIN..." + + app_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps" \ + -H "Authorization: Bearer $CF_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data "{ + \"name\": \"$service $CF_DOMAIN\", + \"domain\": \"$service.$CF_DOMAIN\", + \"type\": \"self_hosted\", + \"session_duration\": \"24h\", + \"app_launcher_visible\": true, + \"skip_interstitial\": true + }") + + app_id=$(echo $app_response | jq -r '.result.id') + + if [ -z "$app_id" ] || [ "$app_id" == "null" ]; then + echo "✗ Error creating access application for $service" + return 1 + fi + + echo "✓ Created access application for $service (ID: $app_id)" + + # Create authentication policy + policy_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps/$app_id/policies" \ + -H "Authorization: Bearer $CF_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data "{ + \"name\": \"Admin Access\", + \"decision\": \"allow\", + \"include\": [{ + \"email\": { + \"email\": \"$ADMIN_EMAIL\" + } + }], + \"require\": [], + \"exclude\": [] + }") + + policy_success=$(echo $policy_response | jq -r '.success') + + if [ "$policy_success" == "true" ]; then + echo "✓ Created authentication policy for $service" + else + echo "✗ Failed to create authentication policy for $service" + fi +} + +# Function to create bypass application (public access) +create_bypass_app() { + local service=$1 + echo "Setting up public access for $service.$CF_DOMAIN..." + + app_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps" \ + -H "Authorization: Bearer $CF_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data "{ + \"name\": \"$service $CF_DOMAIN\", + \"domain\": \"$service.$CF_DOMAIN\", + \"type\": \"self_hosted\", + \"session_duration\": \"24h\", + \"app_launcher_visible\": false, + \"skip_interstitial\": true + }") + + app_id=$(echo $app_response | jq -r '.result.id') + + if [ -z "$app_id" ] || [ "$app_id" == "null" ]; then + echo "✗ Error creating access application for $service" + return 1 + fi + + echo "✓ Created access application for $service (ID: $app_id)" + + # Create bypass policy + policy_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps/$app_id/policies" \ + -H "Authorization: Bearer $CF_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data "{ + \"name\": \"Public Access\", + \"decision\": \"bypass\", + \"include\": [{ + \"everyone\": {} + }], + \"require\": [], + \"exclude\": [] + }") + + policy_success=$(echo $policy_response | jq -r '.success') + + if [ "$policy_success" == "true" ]; then + echo "✓ Created public access policy for $service" + else + echo "✗ Failed to create public access policy for $service" + fi +} + +echo "Creating Cloudflare Access applications..." +echo "" + +# Create protected applications +for service in "${PROTECTED_SERVICES[@]}"; do + create_protected_app "$service" + echo "" +done + +# Create bypass applications for public services +for service in "${BYPASS_SERVICES[@]}"; do + create_bypass_app "$service" + echo "" +done + +echo "-------------------------------------------------------------" +echo "Setup Complete!" +echo "-------------------------------------------------------------" +echo "" +echo "Protected services (require authentication with $ADMIN_EMAIL):" +for service in "${PROTECTED_SERVICES[@]}"; do + echo " - https://$service.$CF_DOMAIN" +done +echo "" +echo "Public services (no authentication required):" +for service in "${BYPASS_SERVICES[@]}"; do + echo " - https://$service.$CF_DOMAIN" +done +echo "" +echo "All services should be accessible through your Cloudflare tunnel." diff --git a/config.sh b/config.sh new file mode 100755 index 0000000..6878738 --- /dev/null +++ b/config.sh @@ -0,0 +1,724 @@ +#!/bin/bash + +cat << "EOF" + ██████╗██╗ ██╗ █████╗ ███╗ ██╗ ██████╗ ███████╗ + ██╔════╝██║ ██║██╔══██╗████╗ ██║██╔════╝ ██╔════╝ + ██║ ███████║███████║██╔██╗ ██║██║ ███╗█████╗ + ██║ ██╔══██║██╔══██║██║╚██╗██║██║ ██║██╔══╝ + ╚██████╗██║ ██║██║ ██║██║ ╚████║╚██████╔╝███████╗ + ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ + + ███╗ ███╗ █████╗ ██╗ ██╗███████╗██████╗ + ████╗ ████║██╔══██╗██║ ██╔╝██╔════╝██╔══██╗ + ██╔████╔██║███████║█████╔╝ █████╗ ██████╔╝ + ██║╚██╔╝██║██╔══██║██╔═██╗ ██╔══╝ ██╔══██╗ + ██║ ╚═╝ ██║██║ ██║██║ ██╗███████╗██║ ██║ + ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ + Configuration Wizard +EOF + +# Get the absolute path of the script directory +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ENV_FILE="$SCRIPT_DIR/.env" +MKDOCS_YML="$SCRIPT_DIR/mkdocs/docs/mkdocs.yml" +TUNNEL_CONFIG_DIR="$SCRIPT_DIR/configs/cloudflare" +TUNNEL_CONFIG_FILE="$TUNNEL_CONFIG_DIR/tunnel-config.yml" +SERVICES_YAML="$SCRIPT_DIR/configs/homepage/services.yaml" +MAIN_HTML="$SCRIPT_DIR/mkdocs/docs/overrides/main.html" + +echo "Looking for .env file at: $ENV_FILE" + +# Function to generate a random secure password +generate_password() { + local length=${1:-16} + openssl rand -base64 48 | tr -dc 'a-zA-Z0-9!@#$%^&*()-_=+' | head -c "$length" +} + +# Function to safely update environment variables in .env file +update_env_var() { + local key=$1 + local value=$2 + + # More robust method to handle special characters in passwords + if grep -q "^$key=" "$ENV_FILE"; then + # Create a temporary file + local tmpfile=$(mktemp) + + # Process the .env file line by line + while IFS= read -r line; do + if [[ "$line" =~ ^$key= ]]; then + echo "$key=$value" >> "$tmpfile" + else + echo "$line" >> "$tmpfile" + fi + done < "$ENV_FILE" + + # Replace the original file with the temporary file + mv "$tmpfile" "$ENV_FILE" + echo "Updated $key in .env file" + else + # Add new key-value pair if it doesn't exist + echo "$key=$value" >> "$ENV_FILE" + echo "Added $key to .env file" + fi +} + +# Function to create a timestamped backup of the .env file +backup_env_file() { + if [ -f "$ENV_FILE" ]; then + local timestamp=$(date +"%Y%m%d_%H%M%S") + local backup_file="$ENV_FILE.backup_$timestamp" + + echo "Creating backup of current .env file to: $backup_file" + if cp "$ENV_FILE" "$backup_file"; then + echo "Backup created successfully!" + return 0 + else + echo "Failed to create backup file. Proceeding with caution..." + return 1 + fi + fi +} + +# Function to initialize the .env file with default values +initialize_env_file() { + echo "Initializing new .env file with default values..." + + cat > "$ENV_FILE" << EOL +# Never share this file publicly. It contains sensitive information. +# This file is used to configure various applications and services. +# Generated by Changemaker Config Wizard on $(date) + +# User and Group Configuration +USER_NAME=coder +USER_ID=1000 +GROUP_ID=1000 + +# Port Configuration +CODE_SERVER_PORT=8888 +LISTMONK_PORT=9000 +LISTMONK_DB_PORT=5432 +MKDOCS_PORT=4000 +MKDOCS_SITE_SERVER_PORT=4001 +N8N_PORT=5678 +NOCODB_PORT=8090 +HOMEPAGE_PORT=3010 +GITEA_WEB_PORT=3030 +GITEA_SSH_PORT=2222 + +# Domain Configuration +BASE_DOMAIN=https://changeme.org +DOMAIN=changeme.org +LISTMONK_HOSTNAME=listmonk.changeme.org +N8N_HOST=n8n.changeme.org +GITEA_DOMAIN=git.changeme.org +GITEA_ROOT_URL=https://git.changeme.org + +# Cloudflare Configuration +CF_API_TOKEN=your_cloudflare_api_token +CF_ZONE_ID=your_cloudflare_zone_id +CF_TUNNEL_ID=your_cloudflared_tunnel_id +CF_DOMAIN=changeme.org + +# Database Configuration (PostgreSQL for Listmonk) +POSTGRES_USER=listmonk +POSTGRES_PASSWORD=changeMe +POSTGRES_DB=listmonk + +# Listmonk Database Performance Settings +LISTMONK_DB_MAX_OPEN=25 +LISTMONK_DB_MAX_IDLE=25 +LISTMONK_DB_MAX_LIFETIME=300s + +# Listmonk Admin Configuration +LISTMONK_ADMIN_USER=admin +LISTMONK_ADMIN_PASSWORD=changeMe + +# N8N Configuration +N8N_USER_EMAIL=admin@example.com +N8N_USER_PASSWORD=changeMe +N8N_ENCRYPTION_KEY=changeMe +GENERIC_TIMEZONE=UTC + +# Nocodb Configuration +NOCODB_JWT_SECRET=changeMe +NOCODB_DB_NAME=nocodb +NOCODB_DB_USER=noco +NOCODB_DB_PASSWORD=changeMe +HOMEPAGE_VAR_BASE_URL=https://changeme.org +EOL + + echo "New .env file created with default values." +} + +# Function to update the site_url in mkdocs.yml +update_mkdocs_yml() { + local new_domain=$1 + + if [ ! -f "$MKDOCS_YML" ]; then + echo "Warning: mkdocs.yml not found at $MKDOCS_YML" + return 1 + fi + + echo "Updating site_url in mkdocs.yml..." + + # Create a backup of the mkdocs.yml file + local timestamp=$(date +"%Y%m%d_%H%M%S") + local backup_file="${MKDOCS_YML}.backup_${timestamp}" + cp "$MKDOCS_YML" "$backup_file" + echo "Created backup of mkdocs.yml at $backup_file" + + # Update the site_url value + sed -i "s|^site_url:.*|site_url: https://$new_domain|" "$MKDOCS_YML" + + if grep -q "site_url: https://$new_domain" "$MKDOCS_YML"; then + echo "Updated site_url in mkdocs.yml to: https://$new_domain" + return 0 + else + echo "Warning: Failed to update site_url in mkdocs.yml" + return 1 + fi +} + +# Function to update service URLs in services.yaml +update_services_yaml() { + local new_domain=$1 + + if [ ! -f "$SERVICES_YAML" ]; then + echo "Warning: services.yaml not found at $SERVICES_YAML" + return 1 + fi + + echo "Updating service URLs in services.yaml..." + + # Create a backup of the services.yaml file + local timestamp=$(date +"%Y%m%d_%H%M%S") + local backup_file="${SERVICES_YAML}.backup_${timestamp}" + cp "$SERVICES_YAML" "$backup_file" + echo "Created backup of services.yaml at $backup_file" + + # Update the commented URLs to use the new domain + sed -i "s|# href: \"https://code\.changeme\.org\"|# href: \"https://code.$new_domain\"|g" "$SERVICES_YAML" + sed -i "s|# href: \"https://listmonk\.changeme\.org\"|# href: \"https://listmonk.$new_domain\"|g" "$SERVICES_YAML" + sed -i "s|# href: \"https://db\.changeme\.org\"|# href: \"https://db.$new_domain\"|g" "$SERVICES_YAML" + sed -i "s|# href: \"https://docs\.changeme\.org\"|# href: \"https://docs.$new_domain\"|g" "$SERVICES_YAML" + sed -i "s|# href: \"https://n8n\.changeme\.org\"|# href: \"https://n8n.$new_domain\"|g" "$SERVICES_YAML" + sed -i "s|# href: \"https://test\.com\"|# href: \"https://$new_domain\"|g" "$SERVICES_YAML" + + # Also update any remaining changeme.org references + sed -i "s|changeme\.org|$new_domain|g" "$SERVICES_YAML" + + echo "Updated service URLs in services.yaml to use domain: $new_domain" + return 0 +} + +# Function to update the login URL in main.html +update_main_html() { + local new_domain=$1 + + if [ ! -f "$MAIN_HTML" ]; then + echo "Warning: main.html not found at $MAIN_HTML" + return 1 + fi + + echo "Updating login URL in main.html..." + + # Create a backup of the main.html file + local timestamp=$(date +"%Y%m%d_%H%M%S") + local backup_file="${MAIN_HTML}.backup_${timestamp}" + cp "$MAIN_HTML" "$backup_file" + echo "Created backup of main.html at $backup_file" + + # Update the login button href to use the new domain + sed -i "s|href=\"https://homepage\.test\.com\"|href=\"https://homepage.$new_domain\"|g" "$MAIN_HTML" + + # Also update any other test.com references + sed -i "s|homepage\.test\.com|homepage.$new_domain|g" "$MAIN_HTML" + + echo "Updated login URL in main.html to: https://homepage.$new_domain" + return 0 +} + +# Function to check if a port is in use +check_port() { + local port=$1 + if command -v ss >/dev/null 2>&1; then + ss -tuln | grep -q ":$port " + elif command -v netstat >/dev/null 2>&1; then + netstat -tuln | grep -q ":$port " + else + # Fallback to lsof if available + if command -v lsof >/dev/null 2>&1; then + lsof -i ":$port" >/dev/null 2>&1 + else + echo "Warning: Cannot check port availability. Please ensure ports are free manually." + return 1 + fi + fi +} + +# Function to check all service ports for conflicts +check_port_conflicts() { + echo "Checking for port conflicts..." + + local ports_to_check=( + "${CODE_SERVER_PORT:-8888}:Code Server" + "${LISTMONK_PORT:-9000}:Listmonk" + "${LISTMONK_DB_PORT:-5432}:Listmonk Database" + "${MKDOCS_PORT:-4000}:MkDocs" + "${MKDOCS_SITE_SERVER_PORT:-4001}:MkDocs Site Server" + "${N8N_PORT:-5678}:N8N" + "${NOCODB_PORT:-8090}:NocoDB" + "${HOMEPAGE_PORT:-3010}:Homepage" + "${GITEA_WEB_PORT:-3030}:Gitea Web" + "${GITEA_SSH_PORT:-2222}:Gitea SSH" + ) + + local conflicts_found=false + + for port_info in "${ports_to_check[@]}"; do + local port=$(echo "$port_info" | cut -d: -f1) + local service=$(echo "$port_info" | cut -d: -f2) + + if check_port "$port"; then + echo "⚠️ Port conflict detected: $port is already in use (assigned to $service)" + conflicts_found=true + else + echo "✅ Port $port is available for $service" + fi + done + + if [ "$conflicts_found" = true ]; then + echo "" + echo "Port conflicts detected! Please choose alternative ports or stop conflicting services." + read -p "Do you want to configure alternative ports? [Y/n]: " configure_ports + + if [[ "$configure_ports" =~ ^[Nn]$ ]]; then + echo "Configuration cancelled. Please resolve port conflicts and try again." + exit 1 + else + configure_alternative_ports + fi + else + echo "✅ All ports are available!" + fi +} + +# Function to configure alternative ports +configure_alternative_ports() { + echo "" + echo "---- Port Configuration ----" + + # Code Server + if check_port "${CODE_SERVER_PORT:-8888}"; then + read -p "Enter alternative port for Code Server [current: ${CODE_SERVER_PORT:-8888}]: " new_code_port + if [ ! -z "$new_code_port" ]; then + update_env_var "CODE_SERVER_PORT" "$new_code_port" + fi + fi + + # Listmonk + if check_port "${LISTMONK_PORT:-9000}"; then + read -p "Enter alternative port for Listmonk [current: ${LISTMONK_PORT:-9000}]: " new_listmonk_port + if [ ! -z "$new_listmonk_port" ]; then + update_env_var "LISTMONK_PORT" "$new_listmonk_port" + fi + fi + + # Listmonk DB + if check_port "${LISTMONK_DB_PORT:-5432}"; then + read -p "Enter alternative port for Listmonk Database [current: ${LISTMONK_DB_PORT:-5432}]: " new_db_port + if [ ! -z "$new_db_port" ]; then + update_env_var "LISTMONK_DB_PORT" "$new_db_port" + fi + fi + + # MkDocs + if check_port "${MKDOCS_PORT:-4000}"; then + read -p "Enter alternative port for MkDocs [current: ${MKDOCS_PORT:-4000}]: " new_mkdocs_port + if [ ! -z "$new_mkdocs_port" ]; then + update_env_var "MKDOCS_PORT" "$new_mkdocs_port" + fi + fi + + # MkDocs Site Server + if check_port "${MKDOCS_SITE_SERVER_PORT:-4001}"; then + read -p "Enter alternative port for MkDocs Site Server [current: ${MKDOCS_SITE_SERVER_PORT:-4001}]: " new_site_port + if [ ! -z "$new_site_port" ]; then + update_env_var "MKDOCS_SITE_SERVER_PORT" "$new_site_port" + fi + fi + + # N8N + if check_port "${N8N_PORT:-5678}"; then + read -p "Enter alternative port for N8N [current: ${N8N_PORT:-5678}]: " new_n8n_port + if [ ! -z "$new_n8n_port" ]; then + update_env_var "N8N_PORT" "$new_n8n_port" + fi + fi + + # NocoDB + if check_port "${NOCODB_PORT:-8090}"; then + read -p "Enter alternative port for NocoDB [current: ${NOCODB_PORT:-8090}]: " new_nocodb_port + if [ ! -z "$new_nocodb_port" ]; then + update_env_var "NOCODB_PORT" "$new_nocodb_port" + fi + fi + + # Homepage + if check_port "${HOMEPAGE_PORT:-3010}"; then + read -p "Enter alternative port for Homepage [current: ${HOMEPAGE_PORT:-3010}]: " new_homepage_port + if [ ! -z "$new_homepage_port" ]; then + update_env_var "HOMEPAGE_PORT" "$new_homepage_port" + fi + fi + + # Gitea Web + if check_port "${GITEA_WEB_PORT:-3030}"; then + read -p "Enter alternative port for Gitea Web [current: ${GITEA_WEB_PORT:-3030}]: " new_gitea_web_port + if [ ! -z "$new_gitea_web_port" ]; then + update_env_var "GITEA_WEB_PORT" "$new_gitea_web_port" + fi + fi + + # Gitea SSH + if check_port "${GITEA_SSH_PORT:-2222}"; then + read -p "Enter alternative port for Gitea SSH [current: ${GITEA_SSH_PORT:-2222}]: " new_gitea_ssh_port + if [ ! -z "$new_gitea_ssh_port" ]; then + update_env_var "GITEA_SSH_PORT" "$new_gitea_ssh_port" + fi + fi + + echo "Port configuration completed." +} + +# Function to create Cloudflare tunnel configuration file +create_tunnel_config() { + local domain=$1 + local tunnel_id=$2 + + # Ensure the tunnel config directory exists + if [ ! -d "$TUNNEL_CONFIG_DIR" ]; then + echo "Creating Cloudflare tunnel config directory at $TUNNEL_CONFIG_DIR" + mkdir -p "$TUNNEL_CONFIG_DIR" + fi + + echo "Creating Cloudflare tunnel configuration file..." + + # Generate the tunnel configuration file with simpler format + cat > "$TUNNEL_CONFIG_FILE" << EOL +# filepath: /home/bunker-admin/changemaker.lite/configs/cloudflare/tunnel-config.yml +# Cloudflare Tunnel Configuration +# Auto-generated by Changemaker Configuration Wizard + +tunnel: $tunnel_id # e.g. 1234567890abcdef +credentials-file: /home/coder/.cloudflared/$tunnel_id.json # e.g. /home/coder/.cloudflared/[insert tunnel number].json +ingress: + + - hostname: homepage.$domain + service: http://localhost:${HOMEPAGE_PORT:-3010} + + - hostname: code.$domain + service: http://localhost:${CODE_SERVER_PORT:-8888} + + - hostname: listmonk.$domain + service: http://localhost:${LISTMONK_PORT:-9000} + + - hostname: docs.$domain + service: http://localhost:${MKDOCS_PORT:-4000} + + - hostname: $domain + service: http://localhost:${MKDOCS_SITE_SERVER_PORT:-4001} + + - hostname: n8n.$domain + service: http://localhost:${N8N_PORT:-5678} + + - hostname: db.$domain + service: http://localhost:${NOCODB_PORT:-8090} + + - hostname: git.$domain + service: http://localhost:${GITEA_WEB_PORT:-3030} + + # Catch-all rule (required) + - service: http_status:404 +EOL + + echo "✅ Tunnel configuration file created at: $TUNNEL_CONFIG_FILE" + + # If the tunnel ID is a placeholder, provide instructions + if [[ "$tunnel_id" == "\${CF_TUNNEL_ID}" ]]; then + echo "NOTE: You need to replace ${CF_TUNNEL_ID} with your actual Cloudflare Tunnel ID" + echo " once you create a tunnel in the Cloudflare Zero Trust dashboard." + fi +} + +# Function to show tunnel setup instructions +show_tunnel_instructions() { + local domain=$1 + + echo "" + echo "=== Cloudflare Tunnel Setup Instructions ===" + echo "" + echo "To complete the tunnel setup:" + echo "" + echo "1. Install cloudflared on your server:" + echo " https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation" + echo "" + echo "2. Create a tunnel using the Cloudflare dashboard or run:" + echo " cloudflared tunnel create changemaker-tunnel" + echo "" + echo "3. Copy the credentials file to the correct location:" + echo " mkdir -p /home/coder/.cloudflared" + echo " cp ~/.cloudflared/[TUNNEL-ID].json /home/coder/.cloudflared/" + echo "" + echo "4. Update your .env with the correct CF_TUNNEL_ID if not already done" + echo "" + echo "5. Start the tunnel with your configuration file:" + echo " cloudflared tunnel --config $TUNNEL_CONFIG_FILE run" + echo "" + echo "6. After verifying it works, you can create a systemd service for automatic startup:" + echo " sudo cloudflared service install" + echo "" + echo "7. Your services will be available at the following URLs:" + echo " - Documentation: https://$domain" + echo " - Homepage: https://homepage.$domain" + echo " - Code Server: https://code.$domain" + echo " - Listmonk: https://listmonk.$domain" + echo " - N8N: https://n8n.$domain" + echo " - NocoDB: https://db.$domain" + echo " - MkDocs Dev: https://docs.$domain" + echo " - Gitea: https://git.$domain" + echo "" +} + +# Function to load environment variables from .env file +load_env_vars() { + if [ -f "$ENV_FILE" ]; then + # Load variables from .env file, ignoring comments and empty lines + while IFS= read -r line; do + if [[ "$line" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then + export "$line" + fi + done < <(grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$ENV_FILE") + fi +} + +# Initialize a new .env file if it doesn't exist +if [ ! -f "$ENV_FILE" ]; then + echo "No .env file found. Creating a new one from scratch." + touch "$ENV_FILE" + initialize_env_file +else + echo "Found existing .env file. Will update values." + backup_env_file +fi + +# Load existing environment variables +load_env_vars + +echo -e "\n\nWelcome to Changemaker Config!\n" +echo "This script will help you configure your .env file for Changemaker." +echo "Please provide the following information:" + +# Domain configuration +read -p "Enter your domain name (without protocol, e.g., example.com): " domain_name + +if [ -z "$domain_name" ]; then + echo "Domain name cannot be empty. Using default: changeme.org" + domain_name="changeme.org" +fi + +echo -e "\nUpdating domain settings in .env file..." + +# Update main domain settings +update_env_var "DOMAIN" "$domain_name" +update_env_var "BASE_DOMAIN" "https://$domain_name" +update_env_var "HOMEPAGE_VAR_BASE_URL" "https://$domain_name" +update_env_var "LISTMONK_HOSTNAME" "listmonk.$domain_name" +update_env_var "N8N_HOST" "n8n.$domain_name" +update_env_var "CF_DOMAIN" "$domain_name" +update_env_var "GITEA_DOMAIN" "git.$domain_name" +update_env_var "GITEA_ROOT_URL" "https://git.$domain_name" + +echo "Domain settings updated successfully!" + +# Cloudflare Configuration +echo -e "\n---- Cloudflare Configuration ----" +echo "To use the DNS setup script, you'll need Cloudflare credentials." +echo "You can find these values in your Cloudflare dashboard:" +echo " - API Token: https://dash.cloudflare.com/profile/api-tokens" +echo " (Create a token with Zone:DNS:Edit and Access:Apps:Edit permissions)" +echo " - Zone ID: On your domain's overview page" +echo " - Tunnel ID: In the Zero Trust dashboard under Access > Tunnels" +echo "" + +read -p "Do you want to configure Cloudflare settings now? [Y/n]: " configure_cf + +if [[ ! "$configure_cf" =~ ^[Nn]$ ]]; then + echo "" + echo "Please enter your Cloudflare credentials:" + + # CF API Token + read -p "Enter your Cloudflare API Token: " cf_api_token + if [ ! -z "$cf_api_token" ]; then + # Basic validation for API token format + if [[ "$cf_api_token" =~ ^[A-Za-z0-9_-]{40}$ ]]; then + update_env_var "CF_API_TOKEN" "$cf_api_token" + echo "✅ Cloudflare API Token updated" + else + echo "⚠️ Warning: API Token format seems incorrect (should be 40 characters)" + update_env_var "CF_API_TOKEN" "$cf_api_token" + fi + else + echo "⚠️ Cloudflare API Token left unchanged" + fi + + # CF Zone ID + read -p "Enter your Cloudflare Zone ID: " cf_zone_id + if [ ! -z "$cf_zone_id" ]; then + # Basic validation for Zone ID format + if [[ "$cf_zone_id" =~ ^[a-f0-9]{32}$ ]]; then + update_env_var "CF_ZONE_ID" "$cf_zone_id" + echo "✅ Cloudflare Zone ID updated" + else + echo "⚠️ Warning: Zone ID format seems incorrect (should be 32 hex characters)" + update_env_var "CF_ZONE_ID" "$cf_zone_id" + fi + else + echo "⚠️ Cloudflare Zone ID left unchanged" + fi + + # CF Tunnel ID + read -p "Enter your Cloudflare Tunnel ID: " cf_tunnel_id + if [ ! -z "$cf_tunnel_id" ]; then + # Basic validation for Tunnel ID format (UUID) + if [[ "$cf_tunnel_id" =~ ^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$ ]]; then + update_env_var "CF_TUNNEL_ID" "$cf_tunnel_id" + echo "✅ Cloudflare Tunnel ID updated" + + # Create tunnel configuration with the provided tunnel ID + create_tunnel_config "$domain_name" "$cf_tunnel_id" + else + echo "⚠️ Warning: Tunnel ID format seems incorrect (should be UUID format)" + update_env_var "CF_TUNNEL_ID" "$cf_tunnel_id" + + # Still create the config file even with potentially incorrect format + create_tunnel_config "$domain_name" "$cf_tunnel_id" + fi + else + echo "⚠️ Cloudflare Tunnel ID left unchanged" + # Create template config without tunnel ID + create_tunnel_config "$domain_name" "\${CF_TUNNEL_ID}" + fi + + echo "" + echo "Cloudflare configuration completed!" + echo "You can now run './add-cname-records.sh' to set up DNS records." + + # Show tunnel setup instructions + show_tunnel_instructions "$domain_name" +else + echo "Skipping Cloudflare configuration. You can run this script again later to configure it." + # Still create a template tunnel config + echo "" + read -p "Do you want to create a template tunnel configuration anyway? [Y/n]: " create_template + if [[ ! "$create_template" =~ ^[Nn]$ ]]; then + create_tunnel_config "$domain_name" "\${CF_TUNNEL_ID}" + echo "Template tunnel configuration created. Update CF_TUNNEL_ID in .env and regenerate if needed." + fi +fi + +# Update the site_url in mkdocs.yml +echo -e "\nUpdating site_url in mkdocs.yml..." +update_mkdocs_yml "$domain_name" + +# Update service URLs in services.yaml +echo -e "\nUpdating service URLs in services.yaml..." +update_services_yaml "$domain_name" + +# Update the login URL in main.html +echo -e "\nUpdating login URL in main.html..." +update_main_html "$domain_name" + +# Listmonk Admin Credentials configuration +echo -e "\n---- Listmonk Admin Credentials ----" +read -p "Enter Listmonk admin email/username [default: admin@example.com]: " listmonk_user +read -sp "Enter Listmonk admin password [default: changeMe]: " listmonk_password +echo # Add new line after password input + +if [ -z "$listmonk_user" ]; then + listmonk_user="admin@example.com" +fi + +if [ -z "$listmonk_password" ]; then + listmonk_password="changeMe" +fi + +update_env_var "LISTMONK_ADMIN_USER" "$listmonk_user" +update_env_var "LISTMONK_ADMIN_PASSWORD" "$listmonk_password" + +echo "Listmonk admin credentials updated." + +# N8N User Credentials configuration +echo -e "\n---- N8N Admin Credentials ----" +read -p "Enter N8N admin email [default: admin@example.com]: " n8n_email +read -sp "Enter N8N admin password [default: changeMe]: " n8n_password +echo # Add new line after password input + +if [ -z "$n8n_email" ]; then + n8n_email="admin@example.com" +fi + +if [ -z "$n8n_password" ]; then + n8n_password="changeMe" +fi + +update_env_var "N8N_USER_EMAIL" "$n8n_email" +update_env_var "N8N_USER_PASSWORD" "$n8n_password" + +echo "N8N admin credentials updated." + +# Generate secure passwords for database and encryption +echo -e "\n---- Generating Secure Passwords ----" +echo "Generating secure passwords for database and encryption keys..." + +# Generate and update database password +postgres_password=$(generate_password 20) +update_env_var "POSTGRES_PASSWORD" "$postgres_password" + +# Generate and update N8N encryption key +n8n_encryption_key=$(generate_password 32) +update_env_var "N8N_ENCRYPTION_KEY" "$n8n_encryption_key" + +# Generate and update NocoDB passwords +nocodb_jwt_secret=$(generate_password 32) +update_env_var "NOCODB_JWT_SECRET" "$nocodb_jwt_secret" + +nocodb_db_password=$(generate_password 20) +update_env_var "NOCODB_DB_PASSWORD" "$nocodb_db_password" + +# Generate and update Gitea passwords +gitea_db_password=$(generate_password 20) +update_env_var "GITEA_DB_PASSWD" "$gitea_db_password" + +gitea_db_root_password=$(generate_password 20) +update_env_var "GITEA_DB_ROOT_PASSWORD" "$gitea_db_root_password" + +echo "Secure passwords generated and updated." + +echo -e "\n✅ Configuration completed successfully!" +echo "Your .env file has been configured with:" +echo "- Domain: $domain_name" +echo "- Listmonk Admin: $listmonk_user" +echo "- N8N Admin Email: $n8n_email" +echo "- Secure random passwords for database, encryption, and NocoDB" +if [[ ! "$configure_cf" =~ ^[Nn]$ ]]; then + echo "- Cloudflare credentials for DNS management" +fi +echo -e "\nYour .env file is located at: $ENV_FILE" +echo "A backup of your original .env file was created before modifications." +echo -e "\nNext steps:" +echo "1. Run 'docker-compose up -d' to start your services" +if [[ ! "$configure_cf" =~ ^[Nn]$ ]]; then + echo "2. Run './add-cname-records.sh' to set up DNS records and access policies" +fi diff --git a/configs/cloudflare/tunnel-config.yml b/configs/cloudflare/tunnel-config.yml new file mode 100644 index 0000000..6f12ad1 --- /dev/null +++ b/configs/cloudflare/tunnel-config.yml @@ -0,0 +1,35 @@ +# filepath: /home/bunker-admin/ab.dem.tf.changemaker/configs/cloudflare/tunnel-config.yml +# filepath: /home/bunker-admin/changemaker.lite/configs/cloudflare/tunnel-config.yml +# Cloudflare Tunnel Configuration +# Auto-generated by Changemaker Configuration Wizard + +tunnel: dce04dd0-1165-4d35-ad0a-880322e36c83 # e.g. 1234567890abcdef +credentials-file: /home/bunker-admin/.cloudflared/dce04dd0-1165-4d35-ad0a-880322e36c83.json # e.g. /home/coder/.cloudflared/[insert tunnel number].json +ingress: + + - hostname: homepage.albertademocracytaskforce.org + service: http://localhost:3021 + + - hostname: code.albertademocracytaskforce.org + service: http://localhost:8889 + + - hostname: listmonk.albertademocracytaskforce.org + service: http://localhost:9001 + + - hostname: docs.albertademocracytaskforce.org + service: http://localhost:4050 + + - hostname: albertademocracytaskforce.org + service: http://localhost:4051 + + - hostname: n8n.albertademocracytaskforce.org + service: http://localhost:5679 + + - hostname: db.albertademocracytaskforce.org + service: http://localhost:8091 + + - hostname: git.albertademocracytaskforce.org + service: http://localhost:3034 + + # Catch-all rule (required) + - service: http_status:404 diff --git a/configs/code-server/.config/.gitkeep b/configs/code-server/.config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/configs/code-server/.local/.gitkeep b/configs/code-server/.local/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/configs/homepage/bookmarks.yaml b/configs/homepage/bookmarks.yaml new file mode 100755 index 0000000..8dd2fd9 --- /dev/null +++ b/configs/homepage/bookmarks.yaml @@ -0,0 +1,53 @@ +--- +# For configuration options and examples, please see: +# https://gethomepage.dev/configs/bookmarks + +- Documentation: + - Code Server: + - abbr: CS + href: https://github.com/coder/code-server + - MkDocs Material: + - abbr: MD + href: https://squidfunk.github.io/mkdocs-material/ + - Homepage: + - abbr: HP + href: https://gethomepage.dev/ + - Gitea: + - abbr: GT + href: https://docs.gitea.io/ + +- Services: + - Listmonk: + - abbr: LM + href: https://listmonk.app/docs/ + - NocoDB: + - abbr: NC + href: https://docs.nocodb.com/ + - n8n: + - abbr: N8 + href: https://docs.n8n.io/ + - PostgreSQL: + - abbr: PG + href: https://www.postgresql.org/docs/ + - Gitea: + - abbr: GT + href: https://gitea.io/ + +- Resources: + - Docker: + - abbr: DC + href: https://docs.docker.com/ + - Docker Compose: + - abbr: DCC + href: https://docs.docker.com/compose/ + - Nginx: + - abbr: NG + href: https://nginx.org/en/docs/ + +- Development: + - GitHub: + - abbr: GH + href: https://github.com/ + - Stack Overflow: + - abbr: SO + href: https://stackoverflow.com/ diff --git a/configs/homepage/custom.css b/configs/homepage/custom.css new file mode 100755 index 0000000..e69de29 diff --git a/configs/homepage/custom.js b/configs/homepage/custom.js new file mode 100755 index 0000000..e69de29 diff --git a/configs/homepage/docker.yaml b/configs/homepage/docker.yaml new file mode 100755 index 0000000..1916e18 --- /dev/null +++ b/configs/homepage/docker.yaml @@ -0,0 +1,6 @@ +--- +# For configuration options and examples, please see: +# https://gethomepage.dev/configs/docker/ + +my-docker: + socket: /var/run/docker.sock diff --git a/configs/homepage/kubernetes.yaml b/configs/homepage/kubernetes.yaml new file mode 100755 index 0000000..aca6e82 --- /dev/null +++ b/configs/homepage/kubernetes.yaml @@ -0,0 +1,2 @@ +--- +# sample kubernetes config diff --git a/configs/homepage/logs/homepage.log b/configs/homepage/logs/homepage.log new file mode 100644 index 0000000..0a49432 --- /dev/null +++ b/configs/homepage/logs/homepage.log @@ -0,0 +1,1224 @@ +[2025-05-28T14:48:05.173Z] error: Error getting services from Docker server 'my-docker': [Error: connect EACCES /var/run/docker.sock] { + errno: -13, + code: 'EACCES', + syscall: 'connect', + address: '/var/run/docker.sock' +} +[2025-05-28T14:48:05.221Z] error: Error getting services from Docker server 'my-docker': [Error: connect EACCES /var/run/docker.sock] { + errno: -13, + code: 'EACCES', + syscall: 'connect', + address: '/var/run/docker.sock' +} +[2025-05-28T14:48:05.445Z] error: Error getting services from Docker server 'my-docker': [Error: connect EACCES /var/run/docker.sock] { + errno: -13, + code: 'EACCES', + syscall: 'connect', + address: '/var/run/docker.sock' +} +[2025-05-28T14:48:05.568Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.585Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.585Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.586Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.586Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.587Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.601Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.601Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.602Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.602Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.602Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.603Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.622Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.622Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.623Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.623Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.623Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:48:05.624Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.099Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.111Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.116Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.128Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.129Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.137Z] error: Error getting services from Docker server 'my-docker': [Error: connect EACCES /var/run/docker.sock] { + errno: -13, + code: 'EACCES', + syscall: 'connect', + address: '/var/run/docker.sock' +} +[2025-05-28T14:56:53.138Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.158Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.159Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.160Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.176Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.177Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.177Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.178Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.188Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.189Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.190Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.201Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:53.202Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.868Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.876Z] error: Error getting services from Docker server 'my-docker': [Error: connect EACCES /var/run/docker.sock] { + errno: -13, + code: 'EACCES', + syscall: 'connect', + address: '/var/run/docker.sock' +} +[2025-05-28T14:56:56.877Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.878Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.890Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.891Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.891Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.891Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.896Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.906Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.907Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.907Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.908Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.919Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.920Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.920Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.922Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.936Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-28T14:56:56.936Z] error: Error: connect EACCES /var/run/docker.sock + at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) + at PipeConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) +[2025-05-29T17:31:03.991Z] error: undefined +[2025-05-29T17:31:03.998Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:31:14.006Z] error: undefined +[2025-05-29T17:31:14.008Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:31:34.022Z] error: undefined +[2025-05-29T17:31:34.023Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:31:54.321Z] error: undefined +[2025-05-29T17:31:54.322Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:32:44.225Z] error: undefined +[2025-05-29T17:32:44.226Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:32:55.064Z] error: undefined +[2025-05-29T17:32:55.065Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:34:23.351Z] error: undefined +[2025-05-29T17:34:23.353Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:34:33.642Z] error: undefined +[2025-05-29T17:34:33.643Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:35:19.357Z] error: undefined +[2025-05-29T17:35:19.358Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:35:25.076Z] error: undefined +[2025-05-29T17:35:25.077Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:36:01.739Z] error: undefined +[2025-05-29T17:36:01.740Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:36:07.377Z] error: undefined +[2025-05-29T17:36:07.378Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:36:17.264Z] error: undefined +[2025-05-29T17:36:17.266Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:36:22.395Z] error: undefined +[2025-05-29T17:36:22.396Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:37:09.957Z] error: undefined +[2025-05-29T17:37:09.958Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:37:15.463Z] error: undefined +[2025-05-29T17:37:15.464Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:37:29.627Z] error: undefined +[2025-05-29T17:37:29.628Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:37:37.983Z] error: undefined +[2025-05-29T17:37:37.984Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:37:48.328Z] error: undefined +[2025-05-29T17:37:48.329Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:47:18.591Z] error: undefined +[2025-05-29T17:47:18.592Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:47:28.703Z] error: undefined +[2025-05-29T17:47:28.704Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:47:43.596Z] error: undefined +[2025-05-29T17:47:43.597Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:47:47.287Z] error: undefined +[2025-05-29T17:47:47.288Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:47:48.789Z] error: undefined +[2025-05-29T17:47:48.790Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:47:52.792Z] error: undefined +[2025-05-29T17:47:52.793Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:53:03.453Z] error: undefined +[2025-05-29T17:53:03.454Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T17:53:14.352Z] error: undefined +[2025-05-29T17:53:14.354Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:02:10.347Z] error: undefined +[2025-05-29T18:02:10.350Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:02:16.174Z] error: undefined +[2025-05-29T18:02:16.175Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:02:32.409Z] error: undefined +[2025-05-29T18:02:32.410Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:02:42.494Z] error: undefined +[2025-05-29T18:02:42.495Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:02:51.754Z] error: undefined +[2025-05-29T18:02:51.755Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:02:53.103Z] error: undefined +[2025-05-29T18:02:53.104Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:03:02.208Z] error: undefined +[2025-05-29T18:03:02.209Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:23:32.849Z] error: undefined +[2025-05-29T18:23:32.850Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:23:43.659Z] error: undefined +[2025-05-29T18:23:43.660Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:44:45.858Z] error: undefined +[2025-05-29T18:44:45.859Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T18:44:56.592Z] error: undefined +[2025-05-29T18:44:56.593Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:10:39.671Z] error: undefined +[2025-05-29T19:10:39.672Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:10:49.940Z] error: undefined +[2025-05-29T19:10:49.941Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:14:20.402Z] error: undefined +[2025-05-29T19:14:20.404Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:14:25.817Z] error: undefined +[2025-05-29T19:14:25.818Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:24:16.542Z] error: undefined +[2025-05-29T19:24:16.544Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:24:35.735Z] error: undefined +[2025-05-29T19:24:35.737Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:24:41.629Z] error: undefined +[2025-05-29T19:24:41.630Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:29:23.277Z] error: undefined +[2025-05-29T19:29:23.278Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:29:28.379Z] error: undefined +[2025-05-29T19:29:28.381Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:29:53.474Z] error: undefined +[2025-05-29T19:29:53.475Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:30:48.561Z] error: undefined +[2025-05-29T19:30:48.562Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:31:48.635Z] error: undefined +[2025-05-29T19:31:48.636Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:32:59.472Z] error: undefined +[2025-05-29T19:32:59.474Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:33:10.471Z] error: undefined +[2025-05-29T19:33:10.472Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:34:18.778Z] error: undefined +[2025-05-29T19:34:18.779Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:34:59.665Z] error: undefined +[2025-05-29T19:34:59.666Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:35:09.975Z] error: undefined +[2025-05-29T19:35:09.976Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:37:27.999Z] error: undefined +[2025-05-29T19:37:28.000Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:37:38.885Z] error: undefined +[2025-05-29T19:37:38.886Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:41:54.134Z] error: undefined +[2025-05-29T19:41:54.135Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:41:59.432Z] error: undefined +[2025-05-29T19:41:59.433Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T19:59:56.754Z] error: undefined +[2025-05-29T19:59:56.755Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:00:07.676Z] error: undefined +[2025-05-29T20:00:07.677Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:00:08.597Z] error: undefined +[2025-05-29T20:00:08.598Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:00:19.476Z] error: undefined +[2025-05-29T20:00:19.477Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:04:41.199Z] error: undefined +[2025-05-29T20:04:41.201Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:04:46.693Z] error: undefined +[2025-05-29T20:04:46.694Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:05:24.973Z] error: undefined +[2025-05-29T20:05:24.974Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:05:30.080Z] error: undefined +[2025-05-29T20:05:30.081Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:06:43.913Z] error: undefined +[2025-05-29T20:06:43.914Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:06:49.755Z] error: undefined +[2025-05-29T20:06:49.756Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:08:02.209Z] error: undefined +[2025-05-29T20:08:02.210Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:08:12.630Z] error: undefined +[2025-05-29T20:08:12.631Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:10:56.769Z] error: undefined +[2025-05-29T20:10:56.770Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:11:02.840Z] error: undefined +[2025-05-29T20:11:02.842Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:11:50.991Z] error: undefined +[2025-05-29T20:11:50.992Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:11:56.918Z] error: undefined +[2025-05-29T20:11:56.918Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:18:08.854Z] error: undefined +[2025-05-29T20:18:08.856Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:18:19.249Z] error: undefined +[2025-05-29T20:18:19.250Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:18:46.550Z] error: undefined +[2025-05-29T20:18:46.551Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:18:57.177Z] error: undefined +[2025-05-29T20:18:57.177Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:19:40.285Z] error: undefined +[2025-05-29T20:19:40.286Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:19:50.891Z] error: undefined +[2025-05-29T20:19:50.892Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:44:56.439Z] error: undefined +[2025-05-29T20:44:56.440Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:48:00.767Z] error: undefined +[2025-05-29T20:48:00.768Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:48:10.926Z] error: undefined +[2025-05-29T20:48:10.927Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:48:26.002Z] error: undefined +[2025-05-29T20:48:26.004Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) +[2025-05-29T20:48:28.278Z] error: undefined +[2025-05-29T20:48:28.279Z] error: TypeError: Invalid URL + at new URL (node:internal/url:818:25) + at d (/app/.next/server/pages/api/releases.js:1:5329) + at h (/app/.next/server/pages/api/services/proxy.js:1:18161) + at async X (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:18441) + at async z.render (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/next-server/pages-api.runtime.prod.js:20:19237) + at async NextNodeServer.runApi (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:664:9) + at async NextNodeServer.handleCatchallRenderRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/next-server.js:301:37) + at async NextNodeServer.handleRequestImpl (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/base-server.js:895:17) + at async invokeRender (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:235:21) + at async handleRequest (/app/node_modules/.pnpm/next@15.2.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/server/lib/router-server.js:426:24) diff --git a/configs/homepage/services.yaml b/configs/homepage/services.yaml new file mode 100644 index 0000000..b4e6562 --- /dev/null +++ b/configs/homepage/services.yaml @@ -0,0 +1,80 @@ +--- +# For public access, replace "http://localhost" with your subdomain URLs + +- Essential Tools: + - Code Server: + href: "https://code.albertademocracytaskforce.org" # Uncomment for public access + description: VS Code in the browser + icon: mdi-code-braces + widget: + type: docker + container: code-server-changemaker-lite + server: my-docker + - Listmonk: + href: "https://listmonk.albertademocracytaskforce.org" # Uncomment for public access + description: Newsletter & mailing list manager + icon: mdi-email-newsletter + widget: + type: docker + container: listmonk_app-lite + server: my-docker + - NocoDB: + href: "https://db.albertademocracytaskforce.org" # Uncomment for public access + description: No-code database platform + icon: mdi-database + widget: + type: docker + container: ab.dem.tf.changemaker-nocodb-1 + server: my-docker + - Gitea: + href: "https://git.albertademocracytaskforce.org" # Uncomment for public access + description: Git repository hosting + icon: mdi-git + widget: + type: docker + container: gitea_changemaker-lite + server: my-docker + +- Content & Documentation: + - MkDocs (Live): + href: "https://docs.albertademocracytaskforce.org" # Uncomment for public access + description: Live documentation server with hot reload + icon: mdi-book-open-page-variant + widget: + type: docker + container: mkdocs-changemaker-lite + server: my-docker + - Static Site: + href: "https://albertademocracytaskforce.org" # Uncomment for public access + description: Built documentation hosting + icon: mdi-web + widget: + type: docker + container: mkdocs-site-server-changemaker-lite + server: my-docker + +- Automation & Infrastructure: + - n8n: + href: "https://n8n.albertademocracytaskforce.org" # Uncomment for public access + description: Workflow automation platform + icon: mdi-workflow + widget: + type: docker + container: n8n-changemaker-lite + server: my-docker + - PostgreSQL (Listmonk): + href: "#" + description: Database for Listmonk + icon: mdi-database-outline + widget: + type: docker + container: listmonk_db-lite + server: my-docker + - PostgreSQL (NocoDB): + href: "#" + description: Database for NocoDB + icon: mdi-database-outline + widget: + type: docker + container: ab.dem.tf.changemaker-root_db-1 + server: my-docker diff --git a/configs/homepage/settings.yaml b/configs/homepage/settings.yaml new file mode 100755 index 0000000..3ed96b3 --- /dev/null +++ b/configs/homepage/settings.yaml @@ -0,0 +1,41 @@ +--- +# For configuration options and examples, please see: +# https://gethomepage.dev/configs/settings/ + +title: Changemaker Lite +description: Self-hosted platform for documentation, development, and automation +theme: dark # or light +color: purple + +background: + image: /images/background.png + blur: xs # sm, "", md, xl... see https://tailwindcss.com/docs/backdrop-blur + saturate: 100 # 0, 50, 100... see https://tailwindcss.com/docs/backdrop-saturate + brightness: 75 # 0, 50, 75... see https://tailwindcss.com/docs/backdrop-brightness + opacity: 50 # 0-100 + +cardBlur: xl # xs, md, +headerStyle: boxed + +layout: + style: columns + columns: 3 + +quicklaunch: + searchDescriptions: true + hideInternetSearch: true + showSearchSuggestions: true + hideVisitURL: true + provider: duckduckgo + +showStats: true + +bookmarks: + showCategories: true + showIcons: true + target: _blank + columns: 3 + pinned: + - Essential Tools:Code Server + - Content & Documentation:MkDocs (Live) + - Automation & Infrastructure:n8n \ No newline at end of file diff --git a/configs/homepage/widgets.yaml b/configs/homepage/widgets.yaml new file mode 100644 index 0000000..9dc75b4 --- /dev/null +++ b/configs/homepage/widgets.yaml @@ -0,0 +1,24 @@ +--- +# For configuration options and examples, please see: +# https://gethomepage.dev/configs/info-widgets/ + +- resources: + cpu: true + memory: true + disk: / + +- greeting: + text_size: xl + text: "Welcome to Alberta Democracy Taskforce Changemaker Lite" + +- datetime: + text_size: xl + format: + dateStyle: short + timeStyle: short + hour12: true + +- search: + provider: duckduckgo + target: _blank + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d0265c2 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,243 @@ +x-db-credentials: &db-credentials + POSTGRES_USER: &db-user ${POSTGRES_USER} + POSTGRES_PASSWORD: &db-password ${POSTGRES_PASSWORD} + POSTGRES_DB: &db-name ${POSTGRES_DB} + +services: + code-server: + build: + context: . + dockerfile: Dockerfile.code-server + container_name: code-server-changemaker-lite + environment: + - DOCKER_USER=${USER_NAME:-coder} + - DEFAULT_WORKSPACE=/home/coder/mkdocs/ + user: "${USER_ID:-1000}:${GROUP_ID:-1000}" + volumes: + - ./configs/code-server/.config:/home/coder/.config + - ./configs/code-server/.local:/home/coder/.local + - ./mkdocs:/home/coder/mkdocs/ + ports: + - "${CODE_SERVER_PORT:-8888}:8080" + restart: unless-stopped + networks: + - changemaker-lite + + listmonk-app: + image: listmonk/listmonk:latest + container_name: listmonk_app-lite + restart: unless-stopped + ports: + - "${LISTMONK_PORT:-9000}:9000" + networks: + - changemaker-lite + hostname: ${LISTMONK_HOSTNAME} + depends_on: + - listmonk-db + command: [sh, -c, "./listmonk --install --idempotent --yes --config '' && ./listmonk --upgrade --yes --config '' && ./listmonk --config ''"] + environment: + LISTMONK_app__address: 0.0.0.0:9000 + LISTMONK_db__user: *db-user + LISTMONK_db__password: *db-password + LISTMONK_db__database: *db-name + LISTMONK_db__host: listmonk-db + LISTMONK_db__port: 5432 + LISTMONK_db__ssl_mode: disable + LISTMONK_db__max_open: 25 + LISTMONK_db__max_idle: 25 + LISTMONK_db__max_lifetime: 300s + TZ: Etc/UTC + LISTMONK_ADMIN_USER: ${LISTMONK_ADMIN_USER:-} + LISTMONK_ADMIN_PASSWORD: ${LISTMONK_ADMIN_PASSWORD:-} + volumes: + - ./assets/uploads:/listmonk/uploads:rw + + listmonk-db: + image: postgres:17-alpine + container_name: listmonk_db-lite + restart: unless-stopped + ports: + - "127.0.0.1:${LISTMONK_DB_PORT:-5432}:5432" + networks: + - changemaker-lite + environment: + <<: *db-credentials + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] + interval: 10s + timeout: 5s + retries: 6 + volumes: + - type: volume + source: listmonk-data + target: /var/lib/postgresql/data + + mkdocs: + image: squidfunk/mkdocs-material + container_name: mkdocs-changemaker-lite + volumes: + - ./mkdocs:/docs:rw + - ./assets/images:/docs/assets/images:rw + user: "${USER_ID:-1000}:${GROUP_ID:-1000}" + ports: + - "${MKDOCS_PORT:-4000}:8000" + environment: + - SITE_URL=${BASE_DOMAIN:-https://changeme.org} + command: serve --dev-addr=0.0.0.0:8000 --watch-theme --livereload + networks: + - changemaker-lite + restart: unless-stopped + + mkdocs-site-server: + image: lscr.io/linuxserver/nginx:latest + container_name: mkdocs-site-server-changemaker-lite + environment: + - PUID=${USER_ID:-1000} # Uses USER_ID from your .env file, defaults to 1000 + - PGID=${GROUP_ID:-1000} # Uses GROUP_ID from your .env file, defaults to 1000 + - TZ=Etc/UTC + volumes: + - ./mkdocs/site:/config/www # Mounts your static site to Nginx's web root + ports: + - "${MKDOCS_SITE_SERVER_PORT:-4001}:80" # Exposes Nginx's port 80 to host port 4001 + restart: unless-stopped + networks: + - changemaker-lite + + n8n: + image: docker.n8n.io/n8nio/n8n + container_name: n8n-changemaker-lite + restart: unless-stopped + ports: + - "${N8N_PORT:-5678}:5678" + environment: + - N8N_HOST=${N8N_HOST:-n8n.${DOMAIN}} + - N8N_PORT=5678 + - N8N_PROTOCOL=https + - NODE_ENV=production + - WEBHOOK_URL=https://${N8N_HOST:-n8n.${DOMAIN}}/ + - GENERIC_TIMEZONE=${GENERIC_TIMEZONE:-UTC} + - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY:-changeMe} + - N8N_USER_MANAGEMENT_DISABLED=false + - N8N_DEFAULT_USER_EMAIL=${N8N_USER_EMAIL:-admin@example.com} + - N8N_DEFAULT_USER_PASSWORD=${N8N_USER_PASSWORD:-changeMe} + volumes: + - n8n_data:/home/node/.n8n + - ./local-files:/files + networks: + - changemaker-lite + + nocodb: + depends_on: + root_db: + condition: service_healthy + environment: + NC_DB: "pg://root_db:5432?u=postgres&p=password&d=root_db" + image: "nocodb/nocodb:latest" + ports: + - "${NOCODB_PORT:-8090}:8080" + restart: always + volumes: + - "nc_data:/usr/app/data" + networks: + - changemaker-lite + root_db: + environment: + POSTGRES_DB: root_db + POSTGRES_PASSWORD: password + POSTGRES_USER: postgres + healthcheck: + interval: 10s + retries: 10 + test: "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\"" + timeout: 2s + image: postgres:16.6 + restart: always + volumes: + - "db_data:/var/lib/postgresql/data" + networks: + - changemaker-lite + + # Homepage App + homepage-changemaker: + image: ghcr.io/gethomepage/homepage:latest + container_name: homepage-changemaker-lite + ports: + - "${HOMEPAGE_PORT:-3010}:3000" + volumes: + - ./configs/homepage:/app/config + - ./assets/icons:/app/public/icons + - ./assets/images:/app/public/images + - /var/run/docker.sock:/var/run/docker.sock + environment: + - PUID=${USER_ID:-1000} + - PGID=${DOCKER_GROUP_ID:-984} + - TZ=Etc/UTC + - HOMEPAGE_ALLOWED_HOSTS=* + - HOMEPAGE_VAR_BASE_URL=${HOMEPAGE_VAR_BASE_URL:-http://localhost} + restart: unless-stopped + networks: + - changemaker-lite + + # Gitea - Git service + gitea-app: + image: gitea/gitea:1.23.7 + container_name: gitea_changemaker-lite + environment: + - USER_UID=${USER_ID:-1000} + - USER_GID=${GROUP_ID:-1000} + - GITEA__database__DB_TYPE=${GITEA_DB_TYPE:-mysql} + - GITEA__database__HOST=${GITEA_DB_HOST:-gitea-db:3306} + - GITEA__database__NAME=${GITEA_DB_NAME:-gitea} + - GITEA__database__USER=${GITEA_DB_USER:-gitea} + - GITEA__database__PASSWD=${GITEA_DB_PASSWD} + - GITEA__server__ROOT_URL=${GITEA_ROOT_URL} + - GITEA__server__HTTP_PORT=3000 + - GITEA__server__PROTOCOL=http + - GITEA__server__DOMAIN=${GITEA_DOMAIN} + - GITEA__server__ENABLE_GZIP=true + - GITEA__server__PROXY_PROTOCOL=true + - GITEA__server__PROXY_PROXY_PROTOCOL_TLS=true + - GITEA__server__PROXY_ALLOW_SUBNET=0.0.0.0/0 + restart: unless-stopped + networks: + - changemaker-lite + volumes: + - gitea_data:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "${GITEA_WEB_PORT:-3030}:3000" + - "${GITEA_SSH_PORT:-2222}:22" + depends_on: + - gitea-db + + gitea-db: + image: mysql:8 + container_name: gitea_mysql_changemaker-lite + restart: unless-stopped + environment: + - MYSQL_ROOT_PASSWORD=${GITEA_DB_ROOT_PASSWORD} + - MYSQL_USER=${GITEA_DB_USER:-gitea} + - MYSQL_PASSWORD=${GITEA_DB_PASSWD} + - MYSQL_DATABASE=${GITEA_DB_NAME:-gitea} + networks: + - changemaker-lite + volumes: + - mysql_data:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "${GITEA_DB_USER:-gitea}", "-p${GITEA_DB_PASSWD}"] + interval: 10s + timeout: 5s + retries: 5 + +networks: + changemaker-lite: + driver: bridge + +volumes: + listmonk-data: + n8n_data: + nc_data: + db_data: + gitea_data: + mysql_data: \ No newline at end of file diff --git a/mkdocs/.cache/plugin/social/0abb4cb0b56b80f3a9ce2388a76b413f.png b/mkdocs/.cache/plugin/social/0abb4cb0b56b80f3a9ce2388a76b413f.png new file mode 100644 index 0000000..8f14daa Binary files /dev/null and b/mkdocs/.cache/plugin/social/0abb4cb0b56b80f3a9ce2388a76b413f.png differ diff --git a/mkdocs/.cache/plugin/social/0b55e7897874ca8de1bfe30265aef42e.png b/mkdocs/.cache/plugin/social/0b55e7897874ca8de1bfe30265aef42e.png new file mode 100644 index 0000000..1358ef4 Binary files /dev/null and b/mkdocs/.cache/plugin/social/0b55e7897874ca8de1bfe30265aef42e.png differ diff --git a/mkdocs/.cache/plugin/social/0ee943db87dfa39f1d8b8882384425da.png b/mkdocs/.cache/plugin/social/0ee943db87dfa39f1d8b8882384425da.png new file mode 100644 index 0000000..5263f14 Binary files /dev/null and b/mkdocs/.cache/plugin/social/0ee943db87dfa39f1d8b8882384425da.png differ diff --git a/mkdocs/.cache/plugin/social/1345f63ac767939fb6429ccf170f1e5f.png b/mkdocs/.cache/plugin/social/1345f63ac767939fb6429ccf170f1e5f.png new file mode 100644 index 0000000..c1e9d28 Binary files /dev/null and b/mkdocs/.cache/plugin/social/1345f63ac767939fb6429ccf170f1e5f.png differ diff --git a/mkdocs/.cache/plugin/social/13b7450908684a452205d94a249e3e4d.png b/mkdocs/.cache/plugin/social/13b7450908684a452205d94a249e3e4d.png new file mode 100644 index 0000000..237bb71 Binary files /dev/null and b/mkdocs/.cache/plugin/social/13b7450908684a452205d94a249e3e4d.png differ diff --git a/mkdocs/.cache/plugin/social/1931a5be0487b18cdd3a1c0ddeb68e09.png b/mkdocs/.cache/plugin/social/1931a5be0487b18cdd3a1c0ddeb68e09.png new file mode 100644 index 0000000..e644b7a Binary files /dev/null and b/mkdocs/.cache/plugin/social/1931a5be0487b18cdd3a1c0ddeb68e09.png differ diff --git a/mkdocs/.cache/plugin/social/1ba54b15aedf0426dba781e37512dce1.png b/mkdocs/.cache/plugin/social/1ba54b15aedf0426dba781e37512dce1.png new file mode 100644 index 0000000..420d8e2 Binary files /dev/null and b/mkdocs/.cache/plugin/social/1ba54b15aedf0426dba781e37512dce1.png differ diff --git a/mkdocs/.cache/plugin/social/1f7db51025c379f324852dcda65e7887.png b/mkdocs/.cache/plugin/social/1f7db51025c379f324852dcda65e7887.png new file mode 100644 index 0000000..bc68b41 Binary files /dev/null and b/mkdocs/.cache/plugin/social/1f7db51025c379f324852dcda65e7887.png differ diff --git a/mkdocs/.cache/plugin/social/237553615f5a06f3712aaba6bb3a7ffb.png b/mkdocs/.cache/plugin/social/237553615f5a06f3712aaba6bb3a7ffb.png new file mode 100644 index 0000000..a1c34ef Binary files /dev/null and b/mkdocs/.cache/plugin/social/237553615f5a06f3712aaba6bb3a7ffb.png differ diff --git a/mkdocs/.cache/plugin/social/260a1c90a2b4cd55ee26d2479458825c.png b/mkdocs/.cache/plugin/social/260a1c90a2b4cd55ee26d2479458825c.png new file mode 100644 index 0000000..2a94099 Binary files /dev/null and b/mkdocs/.cache/plugin/social/260a1c90a2b4cd55ee26d2479458825c.png differ diff --git a/mkdocs/.cache/plugin/social/28d05a95b492b49a865d6e7c037f4a99.png b/mkdocs/.cache/plugin/social/28d05a95b492b49a865d6e7c037f4a99.png new file mode 100644 index 0000000..8af1f04 Binary files /dev/null and b/mkdocs/.cache/plugin/social/28d05a95b492b49a865d6e7c037f4a99.png differ diff --git a/mkdocs/.cache/plugin/social/2b564a56ae420375695ce06cf8beede5.png b/mkdocs/.cache/plugin/social/2b564a56ae420375695ce06cf8beede5.png new file mode 100644 index 0000000..aada6b0 Binary files /dev/null and b/mkdocs/.cache/plugin/social/2b564a56ae420375695ce06cf8beede5.png differ diff --git a/mkdocs/.cache/plugin/social/2bdc81b931c7b76d4bfc172a28af3c32.png b/mkdocs/.cache/plugin/social/2bdc81b931c7b76d4bfc172a28af3c32.png new file mode 100644 index 0000000..26f71c6 Binary files /dev/null and b/mkdocs/.cache/plugin/social/2bdc81b931c7b76d4bfc172a28af3c32.png differ diff --git a/mkdocs/.cache/plugin/social/2d3cf2d42c43e6e706e01669ea7b47d7.png b/mkdocs/.cache/plugin/social/2d3cf2d42c43e6e706e01669ea7b47d7.png new file mode 100644 index 0000000..10ace26 Binary files /dev/null and b/mkdocs/.cache/plugin/social/2d3cf2d42c43e6e706e01669ea7b47d7.png differ diff --git a/mkdocs/.cache/plugin/social/32ef6c8195741823ddec0fa6e9a9f3eb.png b/mkdocs/.cache/plugin/social/32ef6c8195741823ddec0fa6e9a9f3eb.png new file mode 100644 index 0000000..a0b3417 Binary files /dev/null and b/mkdocs/.cache/plugin/social/32ef6c8195741823ddec0fa6e9a9f3eb.png differ diff --git a/mkdocs/.cache/plugin/social/3361679ccc4e968c67cd73402e9aab81.png b/mkdocs/.cache/plugin/social/3361679ccc4e968c67cd73402e9aab81.png new file mode 100644 index 0000000..a31e039 Binary files /dev/null and b/mkdocs/.cache/plugin/social/3361679ccc4e968c67cd73402e9aab81.png differ diff --git a/mkdocs/.cache/plugin/social/359a00add05c04970048e0a8be38f335.png b/mkdocs/.cache/plugin/social/359a00add05c04970048e0a8be38f335.png new file mode 100644 index 0000000..c56523d Binary files /dev/null and b/mkdocs/.cache/plugin/social/359a00add05c04970048e0a8be38f335.png differ diff --git a/mkdocs/.cache/plugin/social/380d7c2b0fe08b493118f7e3e813d619.png b/mkdocs/.cache/plugin/social/380d7c2b0fe08b493118f7e3e813d619.png new file mode 100644 index 0000000..1d6edb7 Binary files /dev/null and b/mkdocs/.cache/plugin/social/380d7c2b0fe08b493118f7e3e813d619.png differ diff --git a/mkdocs/.cache/plugin/social/39d5d9e743d460c873cdf972697a0dd0.png b/mkdocs/.cache/plugin/social/39d5d9e743d460c873cdf972697a0dd0.png new file mode 100644 index 0000000..991f2e9 Binary files /dev/null and b/mkdocs/.cache/plugin/social/39d5d9e743d460c873cdf972697a0dd0.png differ diff --git a/mkdocs/.cache/plugin/social/3a2fd3f826d2a906ed92c3970b25cb7d.png b/mkdocs/.cache/plugin/social/3a2fd3f826d2a906ed92c3970b25cb7d.png new file mode 100644 index 0000000..4971e61 Binary files /dev/null and b/mkdocs/.cache/plugin/social/3a2fd3f826d2a906ed92c3970b25cb7d.png differ diff --git a/mkdocs/.cache/plugin/social/3d6d2c6d670fab67a7f8b37a36b1f14c.png b/mkdocs/.cache/plugin/social/3d6d2c6d670fab67a7f8b37a36b1f14c.png new file mode 100644 index 0000000..6fcf47d Binary files /dev/null and b/mkdocs/.cache/plugin/social/3d6d2c6d670fab67a7f8b37a36b1f14c.png differ diff --git a/mkdocs/.cache/plugin/social/3ee478cafa95963d945be030289a0159.png b/mkdocs/.cache/plugin/social/3ee478cafa95963d945be030289a0159.png new file mode 100644 index 0000000..e4ff164 Binary files /dev/null and b/mkdocs/.cache/plugin/social/3ee478cafa95963d945be030289a0159.png differ diff --git a/mkdocs/.cache/plugin/social/3f18fd6addada8d9deb60bbad32514fa.png b/mkdocs/.cache/plugin/social/3f18fd6addada8d9deb60bbad32514fa.png new file mode 100644 index 0000000..f380d91 Binary files /dev/null and b/mkdocs/.cache/plugin/social/3f18fd6addada8d9deb60bbad32514fa.png differ diff --git a/mkdocs/.cache/plugin/social/431ab4f4662987971222ad7fc4583df8.png b/mkdocs/.cache/plugin/social/431ab4f4662987971222ad7fc4583df8.png new file mode 100644 index 0000000..1b798d8 Binary files /dev/null and b/mkdocs/.cache/plugin/social/431ab4f4662987971222ad7fc4583df8.png differ diff --git a/mkdocs/.cache/plugin/social/44a679a39915b848994bc5eb7c771084.png b/mkdocs/.cache/plugin/social/44a679a39915b848994bc5eb7c771084.png new file mode 100644 index 0000000..ac94bdf Binary files /dev/null and b/mkdocs/.cache/plugin/social/44a679a39915b848994bc5eb7c771084.png differ diff --git a/mkdocs/.cache/plugin/social/4764c5a1bcc778ffcddc0a795f1139c7.png b/mkdocs/.cache/plugin/social/4764c5a1bcc778ffcddc0a795f1139c7.png new file mode 100644 index 0000000..cbf6eca Binary files /dev/null and b/mkdocs/.cache/plugin/social/4764c5a1bcc778ffcddc0a795f1139c7.png differ diff --git a/mkdocs/.cache/plugin/social/4b0aa135e76f6b9e18ebdd24b1552da6.png b/mkdocs/.cache/plugin/social/4b0aa135e76f6b9e18ebdd24b1552da6.png new file mode 100644 index 0000000..23df58c Binary files /dev/null and b/mkdocs/.cache/plugin/social/4b0aa135e76f6b9e18ebdd24b1552da6.png differ diff --git a/mkdocs/.cache/plugin/social/4dbd1b187dc8ffc02bbd3ee4ed2f63b8.png b/mkdocs/.cache/plugin/social/4dbd1b187dc8ffc02bbd3ee4ed2f63b8.png new file mode 100644 index 0000000..b783851 Binary files /dev/null and b/mkdocs/.cache/plugin/social/4dbd1b187dc8ffc02bbd3ee4ed2f63b8.png differ diff --git a/mkdocs/.cache/plugin/social/4e95f2e36cd0bb6a7ad665beb497ac83.png b/mkdocs/.cache/plugin/social/4e95f2e36cd0bb6a7ad665beb497ac83.png new file mode 100644 index 0000000..61f3da4 Binary files /dev/null and b/mkdocs/.cache/plugin/social/4e95f2e36cd0bb6a7ad665beb497ac83.png differ diff --git a/mkdocs/.cache/plugin/social/4eb95c3f3f9893da99dee3b68b137595.png b/mkdocs/.cache/plugin/social/4eb95c3f3f9893da99dee3b68b137595.png new file mode 100644 index 0000000..a92554e Binary files /dev/null and b/mkdocs/.cache/plugin/social/4eb95c3f3f9893da99dee3b68b137595.png differ diff --git a/mkdocs/.cache/plugin/social/502ad9b1f18fe233f6ee41cacd812429.png b/mkdocs/.cache/plugin/social/502ad9b1f18fe233f6ee41cacd812429.png new file mode 100644 index 0000000..32864b9 Binary files /dev/null and b/mkdocs/.cache/plugin/social/502ad9b1f18fe233f6ee41cacd812429.png differ diff --git a/mkdocs/.cache/plugin/social/56f27d3fe6ed0435d9bfce3d8d1ab049.png b/mkdocs/.cache/plugin/social/56f27d3fe6ed0435d9bfce3d8d1ab049.png new file mode 100644 index 0000000..9297dad Binary files /dev/null and b/mkdocs/.cache/plugin/social/56f27d3fe6ed0435d9bfce3d8d1ab049.png differ diff --git a/mkdocs/.cache/plugin/social/5b8437d363c52abd31123bd3d5bf82e2.png b/mkdocs/.cache/plugin/social/5b8437d363c52abd31123bd3d5bf82e2.png new file mode 100644 index 0000000..0bf2734 Binary files /dev/null and b/mkdocs/.cache/plugin/social/5b8437d363c52abd31123bd3d5bf82e2.png differ diff --git a/mkdocs/.cache/plugin/social/5c8282bc8e15c5e47e91f2c2266a5dbc.png b/mkdocs/.cache/plugin/social/5c8282bc8e15c5e47e91f2c2266a5dbc.png new file mode 100644 index 0000000..3d3cd04 Binary files /dev/null and b/mkdocs/.cache/plugin/social/5c8282bc8e15c5e47e91f2c2266a5dbc.png differ diff --git a/mkdocs/.cache/plugin/social/5d4583bbd8388c720bff551fd35a1ac6.png b/mkdocs/.cache/plugin/social/5d4583bbd8388c720bff551fd35a1ac6.png new file mode 100644 index 0000000..5a75775 Binary files /dev/null and b/mkdocs/.cache/plugin/social/5d4583bbd8388c720bff551fd35a1ac6.png differ diff --git a/mkdocs/.cache/plugin/social/609232be2b0ead3ecefbc6b21d45653f.png b/mkdocs/.cache/plugin/social/609232be2b0ead3ecefbc6b21d45653f.png new file mode 100644 index 0000000..651b012 Binary files /dev/null and b/mkdocs/.cache/plugin/social/609232be2b0ead3ecefbc6b21d45653f.png differ diff --git a/mkdocs/.cache/plugin/social/61ada07d673e75ab5d383772efa3e386.png b/mkdocs/.cache/plugin/social/61ada07d673e75ab5d383772efa3e386.png new file mode 100644 index 0000000..7ea7fc4 Binary files /dev/null and b/mkdocs/.cache/plugin/social/61ada07d673e75ab5d383772efa3e386.png differ diff --git a/mkdocs/.cache/plugin/social/665a7a652a8a7d093192df525fe984b9.png b/mkdocs/.cache/plugin/social/665a7a652a8a7d093192df525fe984b9.png new file mode 100644 index 0000000..878cca7 Binary files /dev/null and b/mkdocs/.cache/plugin/social/665a7a652a8a7d093192df525fe984b9.png differ diff --git a/mkdocs/.cache/plugin/social/668c246629c618cf956e7cea78d4037d.png b/mkdocs/.cache/plugin/social/668c246629c618cf956e7cea78d4037d.png new file mode 100644 index 0000000..42681cc Binary files /dev/null and b/mkdocs/.cache/plugin/social/668c246629c618cf956e7cea78d4037d.png differ diff --git a/mkdocs/.cache/plugin/social/680dbad20ecfbdfa00d309b192263291.png b/mkdocs/.cache/plugin/social/680dbad20ecfbdfa00d309b192263291.png new file mode 100644 index 0000000..9723f12 Binary files /dev/null and b/mkdocs/.cache/plugin/social/680dbad20ecfbdfa00d309b192263291.png differ diff --git a/mkdocs/.cache/plugin/social/687fb766b8846fd05f5c0bb69a9edf84.png b/mkdocs/.cache/plugin/social/687fb766b8846fd05f5c0bb69a9edf84.png new file mode 100644 index 0000000..1f24b49 Binary files /dev/null and b/mkdocs/.cache/plugin/social/687fb766b8846fd05f5c0bb69a9edf84.png differ diff --git a/mkdocs/.cache/plugin/social/690d82aedba9d262454729e29c356b3c.png b/mkdocs/.cache/plugin/social/690d82aedba9d262454729e29c356b3c.png new file mode 100644 index 0000000..cd7376a Binary files /dev/null and b/mkdocs/.cache/plugin/social/690d82aedba9d262454729e29c356b3c.png differ diff --git a/mkdocs/.cache/plugin/social/70175cd9d7212ffcc59fbc9c7f0d4440.png b/mkdocs/.cache/plugin/social/70175cd9d7212ffcc59fbc9c7f0d4440.png new file mode 100644 index 0000000..7bc5a52 Binary files /dev/null and b/mkdocs/.cache/plugin/social/70175cd9d7212ffcc59fbc9c7f0d4440.png differ diff --git a/mkdocs/.cache/plugin/social/704e77577bf1d6afce98437ea2866a83.png b/mkdocs/.cache/plugin/social/704e77577bf1d6afce98437ea2866a83.png new file mode 100644 index 0000000..24044f9 Binary files /dev/null and b/mkdocs/.cache/plugin/social/704e77577bf1d6afce98437ea2866a83.png differ diff --git a/mkdocs/.cache/plugin/social/721bd151e1ec0d1e48006634b8ff2e38.png b/mkdocs/.cache/plugin/social/721bd151e1ec0d1e48006634b8ff2e38.png new file mode 100644 index 0000000..321a1b9 Binary files /dev/null and b/mkdocs/.cache/plugin/social/721bd151e1ec0d1e48006634b8ff2e38.png differ diff --git a/mkdocs/.cache/plugin/social/731847eb1db30740c72d6a0f1bc79a71.png b/mkdocs/.cache/plugin/social/731847eb1db30740c72d6a0f1bc79a71.png new file mode 100644 index 0000000..61da28b Binary files /dev/null and b/mkdocs/.cache/plugin/social/731847eb1db30740c72d6a0f1bc79a71.png differ diff --git a/mkdocs/.cache/plugin/social/740e1015f23d88c791e7cd6c726e1081.png b/mkdocs/.cache/plugin/social/740e1015f23d88c791e7cd6c726e1081.png new file mode 100644 index 0000000..d10dcd9 Binary files /dev/null and b/mkdocs/.cache/plugin/social/740e1015f23d88c791e7cd6c726e1081.png differ diff --git a/mkdocs/.cache/plugin/social/7a03c2a41a22d644330b1b7bc2b58d3d.png b/mkdocs/.cache/plugin/social/7a03c2a41a22d644330b1b7bc2b58d3d.png new file mode 100644 index 0000000..971350c Binary files /dev/null and b/mkdocs/.cache/plugin/social/7a03c2a41a22d644330b1b7bc2b58d3d.png differ diff --git a/mkdocs/.cache/plugin/social/7db31f564bab29ce21afe0a7feae7012.png b/mkdocs/.cache/plugin/social/7db31f564bab29ce21afe0a7feae7012.png new file mode 100644 index 0000000..962df15 Binary files /dev/null and b/mkdocs/.cache/plugin/social/7db31f564bab29ce21afe0a7feae7012.png differ diff --git a/mkdocs/.cache/plugin/social/7ec96f86a1cb836cbe60f2d539a79d77.png b/mkdocs/.cache/plugin/social/7ec96f86a1cb836cbe60f2d539a79d77.png new file mode 100644 index 0000000..9f0f21a Binary files /dev/null and b/mkdocs/.cache/plugin/social/7ec96f86a1cb836cbe60f2d539a79d77.png differ diff --git a/mkdocs/.cache/plugin/social/83db91be2c8770ec6e0cad47805127ef.png b/mkdocs/.cache/plugin/social/83db91be2c8770ec6e0cad47805127ef.png new file mode 100644 index 0000000..6120273 Binary files /dev/null and b/mkdocs/.cache/plugin/social/83db91be2c8770ec6e0cad47805127ef.png differ diff --git a/mkdocs/.cache/plugin/social/86bc017f81fe2395e0c53430488feb8e.png b/mkdocs/.cache/plugin/social/86bc017f81fe2395e0c53430488feb8e.png new file mode 100644 index 0000000..0f9f2ab Binary files /dev/null and b/mkdocs/.cache/plugin/social/86bc017f81fe2395e0c53430488feb8e.png differ diff --git a/mkdocs/.cache/plugin/social/8bd313bb897682b9a393f2f76f55c593.png b/mkdocs/.cache/plugin/social/8bd313bb897682b9a393f2f76f55c593.png new file mode 100644 index 0000000..dd3b3d7 Binary files /dev/null and b/mkdocs/.cache/plugin/social/8bd313bb897682b9a393f2f76f55c593.png differ diff --git a/mkdocs/.cache/plugin/social/8dfb08c0f74e953a0fd4a26db905370a.png b/mkdocs/.cache/plugin/social/8dfb08c0f74e953a0fd4a26db905370a.png new file mode 100644 index 0000000..c142aeb Binary files /dev/null and b/mkdocs/.cache/plugin/social/8dfb08c0f74e953a0fd4a26db905370a.png differ diff --git a/mkdocs/.cache/plugin/social/919b2121a7b47fe2cdad12febff6359a.png b/mkdocs/.cache/plugin/social/919b2121a7b47fe2cdad12febff6359a.png new file mode 100644 index 0000000..d5d90fd Binary files /dev/null and b/mkdocs/.cache/plugin/social/919b2121a7b47fe2cdad12febff6359a.png differ diff --git a/mkdocs/.cache/plugin/social/91b8d7383fe2e54c00b38a0f26e3b770.png b/mkdocs/.cache/plugin/social/91b8d7383fe2e54c00b38a0f26e3b770.png new file mode 100644 index 0000000..2769dd8 Binary files /dev/null and b/mkdocs/.cache/plugin/social/91b8d7383fe2e54c00b38a0f26e3b770.png differ diff --git a/mkdocs/.cache/plugin/social/96a422da08dcb28205d2e584a7c620ca.png b/mkdocs/.cache/plugin/social/96a422da08dcb28205d2e584a7c620ca.png new file mode 100644 index 0000000..c6dd85d Binary files /dev/null and b/mkdocs/.cache/plugin/social/96a422da08dcb28205d2e584a7c620ca.png differ diff --git a/mkdocs/.cache/plugin/social/9b8aa203f6bb9d837c1bc398fb6cf8ec.png b/mkdocs/.cache/plugin/social/9b8aa203f6bb9d837c1bc398fb6cf8ec.png new file mode 100644 index 0000000..5fb13fa Binary files /dev/null and b/mkdocs/.cache/plugin/social/9b8aa203f6bb9d837c1bc398fb6cf8ec.png differ diff --git a/mkdocs/.cache/plugin/social/9dabdb58ebfab640f34444d6ab1dbf91.png b/mkdocs/.cache/plugin/social/9dabdb58ebfab640f34444d6ab1dbf91.png new file mode 100644 index 0000000..9b854e6 Binary files /dev/null and b/mkdocs/.cache/plugin/social/9dabdb58ebfab640f34444d6ab1dbf91.png differ diff --git a/mkdocs/.cache/plugin/social/9ef625b1724cd11a5b589b7482507f1b.png b/mkdocs/.cache/plugin/social/9ef625b1724cd11a5b589b7482507f1b.png new file mode 100644 index 0000000..ee10bc2 Binary files /dev/null and b/mkdocs/.cache/plugin/social/9ef625b1724cd11a5b589b7482507f1b.png differ diff --git a/mkdocs/.cache/plugin/social/9f9f9e07a4f4ee67a035cea72d494e21.png b/mkdocs/.cache/plugin/social/9f9f9e07a4f4ee67a035cea72d494e21.png new file mode 100644 index 0000000..ddb6c82 Binary files /dev/null and b/mkdocs/.cache/plugin/social/9f9f9e07a4f4ee67a035cea72d494e21.png differ diff --git a/mkdocs/.cache/plugin/social/9fdd03d6602a201cef87a201f27fc715.png b/mkdocs/.cache/plugin/social/9fdd03d6602a201cef87a201f27fc715.png new file mode 100644 index 0000000..ea5947b Binary files /dev/null and b/mkdocs/.cache/plugin/social/9fdd03d6602a201cef87a201f27fc715.png differ diff --git a/mkdocs/.cache/plugin/social/a0bccd2b0770e49326ded4080b1052bd.png b/mkdocs/.cache/plugin/social/a0bccd2b0770e49326ded4080b1052bd.png new file mode 100644 index 0000000..61673c9 Binary files /dev/null and b/mkdocs/.cache/plugin/social/a0bccd2b0770e49326ded4080b1052bd.png differ diff --git a/mkdocs/.cache/plugin/social/a1fd1179cb1dcbb6751321e1f87069e3.png b/mkdocs/.cache/plugin/social/a1fd1179cb1dcbb6751321e1f87069e3.png new file mode 100644 index 0000000..0b158aa Binary files /dev/null and b/mkdocs/.cache/plugin/social/a1fd1179cb1dcbb6751321e1f87069e3.png differ diff --git a/mkdocs/.cache/plugin/social/a42db1f8972fbbd7ab92c9fa6e91d45e.png b/mkdocs/.cache/plugin/social/a42db1f8972fbbd7ab92c9fa6e91d45e.png new file mode 100644 index 0000000..acd5a48 Binary files /dev/null and b/mkdocs/.cache/plugin/social/a42db1f8972fbbd7ab92c9fa6e91d45e.png differ diff --git a/mkdocs/.cache/plugin/social/a5775bbacaf158405defcb68416ea8bd.png b/mkdocs/.cache/plugin/social/a5775bbacaf158405defcb68416ea8bd.png new file mode 100644 index 0000000..9615bd6 Binary files /dev/null and b/mkdocs/.cache/plugin/social/a5775bbacaf158405defcb68416ea8bd.png differ diff --git a/mkdocs/.cache/plugin/social/aa0707be07fb7b02ab3372711d954d83.png b/mkdocs/.cache/plugin/social/aa0707be07fb7b02ab3372711d954d83.png new file mode 100644 index 0000000..1a02082 Binary files /dev/null and b/mkdocs/.cache/plugin/social/aa0707be07fb7b02ab3372711d954d83.png differ diff --git a/mkdocs/.cache/plugin/social/ac04f515d128c1a7e264e731162351fb.png b/mkdocs/.cache/plugin/social/ac04f515d128c1a7e264e731162351fb.png new file mode 100644 index 0000000..5b67877 Binary files /dev/null and b/mkdocs/.cache/plugin/social/ac04f515d128c1a7e264e731162351fb.png differ diff --git a/mkdocs/.cache/plugin/social/acfa7c461bffcaec0d19de3983eff13d.png b/mkdocs/.cache/plugin/social/acfa7c461bffcaec0d19de3983eff13d.png new file mode 100644 index 0000000..270d11d Binary files /dev/null and b/mkdocs/.cache/plugin/social/acfa7c461bffcaec0d19de3983eff13d.png differ diff --git a/mkdocs/.cache/plugin/social/af754735b566f6d264e3f21b80a2d139.png b/mkdocs/.cache/plugin/social/af754735b566f6d264e3f21b80a2d139.png new file mode 100644 index 0000000..8bc5d08 Binary files /dev/null and b/mkdocs/.cache/plugin/social/af754735b566f6d264e3f21b80a2d139.png differ diff --git a/mkdocs/.cache/plugin/social/b2ea8eabbd3acb20839c119ed422a96c.png b/mkdocs/.cache/plugin/social/b2ea8eabbd3acb20839c119ed422a96c.png new file mode 100644 index 0000000..90fb89b Binary files /dev/null and b/mkdocs/.cache/plugin/social/b2ea8eabbd3acb20839c119ed422a96c.png differ diff --git a/mkdocs/.cache/plugin/social/b3ed80eec9045cdbd3f44be9560ed73f.png b/mkdocs/.cache/plugin/social/b3ed80eec9045cdbd3f44be9560ed73f.png new file mode 100644 index 0000000..13f702b Binary files /dev/null and b/mkdocs/.cache/plugin/social/b3ed80eec9045cdbd3f44be9560ed73f.png differ diff --git a/mkdocs/.cache/plugin/social/ba7ec4e9e95e59b7a38a3d5ad9a6258a.png b/mkdocs/.cache/plugin/social/ba7ec4e9e95e59b7a38a3d5ad9a6258a.png new file mode 100644 index 0000000..e645683 Binary files /dev/null and b/mkdocs/.cache/plugin/social/ba7ec4e9e95e59b7a38a3d5ad9a6258a.png differ diff --git a/mkdocs/.cache/plugin/social/bbf330d53ce8ec46ba998fef04e7afb4.png b/mkdocs/.cache/plugin/social/bbf330d53ce8ec46ba998fef04e7afb4.png new file mode 100644 index 0000000..c8fba66 Binary files /dev/null and b/mkdocs/.cache/plugin/social/bbf330d53ce8ec46ba998fef04e7afb4.png differ diff --git a/mkdocs/.cache/plugin/social/bcbb6631bf869d006e39f0f32c222578.png b/mkdocs/.cache/plugin/social/bcbb6631bf869d006e39f0f32c222578.png new file mode 100644 index 0000000..6bb2ba0 Binary files /dev/null and b/mkdocs/.cache/plugin/social/bcbb6631bf869d006e39f0f32c222578.png differ diff --git a/mkdocs/.cache/plugin/social/c10edc50e6bd3027ed2b503e6447a103.png b/mkdocs/.cache/plugin/social/c10edc50e6bd3027ed2b503e6447a103.png new file mode 100644 index 0000000..50789cd Binary files /dev/null and b/mkdocs/.cache/plugin/social/c10edc50e6bd3027ed2b503e6447a103.png differ diff --git a/mkdocs/.cache/plugin/social/c46f702e72488776dc207dd3ee60403d.png b/mkdocs/.cache/plugin/social/c46f702e72488776dc207dd3ee60403d.png new file mode 100644 index 0000000..9a31c00 Binary files /dev/null and b/mkdocs/.cache/plugin/social/c46f702e72488776dc207dd3ee60403d.png differ diff --git a/mkdocs/.cache/plugin/social/c581111ffc8ac6c7e3d5b4c02da0c3b5.png b/mkdocs/.cache/plugin/social/c581111ffc8ac6c7e3d5b4c02da0c3b5.png new file mode 100644 index 0000000..29114e1 Binary files /dev/null and b/mkdocs/.cache/plugin/social/c581111ffc8ac6c7e3d5b4c02da0c3b5.png differ diff --git a/mkdocs/.cache/plugin/social/c86e8855647c3a781563d3e68227bae0.png b/mkdocs/.cache/plugin/social/c86e8855647c3a781563d3e68227bae0.png new file mode 100644 index 0000000..5beb6eb Binary files /dev/null and b/mkdocs/.cache/plugin/social/c86e8855647c3a781563d3e68227bae0.png differ diff --git a/mkdocs/.cache/plugin/social/c9d7d185f1027eb87ca3f660e74ff361.png b/mkdocs/.cache/plugin/social/c9d7d185f1027eb87ca3f660e74ff361.png new file mode 100644 index 0000000..63d6563 Binary files /dev/null and b/mkdocs/.cache/plugin/social/c9d7d185f1027eb87ca3f660e74ff361.png differ diff --git a/mkdocs/.cache/plugin/social/ca7a35746e5b24c6195659a5ce3f5a0d.png b/mkdocs/.cache/plugin/social/ca7a35746e5b24c6195659a5ce3f5a0d.png new file mode 100644 index 0000000..f46cc75 Binary files /dev/null and b/mkdocs/.cache/plugin/social/ca7a35746e5b24c6195659a5ce3f5a0d.png differ diff --git a/mkdocs/.cache/plugin/social/cf07b7c75795438c349c45ddf52194e6.png b/mkdocs/.cache/plugin/social/cf07b7c75795438c349c45ddf52194e6.png new file mode 100644 index 0000000..444e349 Binary files /dev/null and b/mkdocs/.cache/plugin/social/cf07b7c75795438c349c45ddf52194e6.png differ diff --git a/mkdocs/.cache/plugin/social/d0a27ef53dbcc9d66ec1c5d78a3a7b1a.png b/mkdocs/.cache/plugin/social/d0a27ef53dbcc9d66ec1c5d78a3a7b1a.png new file mode 100644 index 0000000..3557dd0 Binary files /dev/null and b/mkdocs/.cache/plugin/social/d0a27ef53dbcc9d66ec1c5d78a3a7b1a.png differ diff --git a/mkdocs/.cache/plugin/social/d3ccf9899de49dc91a1530ba5ddd0d63.png b/mkdocs/.cache/plugin/social/d3ccf9899de49dc91a1530ba5ddd0d63.png new file mode 100644 index 0000000..5446103 Binary files /dev/null and b/mkdocs/.cache/plugin/social/d3ccf9899de49dc91a1530ba5ddd0d63.png differ diff --git a/mkdocs/.cache/plugin/social/d6a59651ce14d60618f2379e9256b991.png b/mkdocs/.cache/plugin/social/d6a59651ce14d60618f2379e9256b991.png new file mode 100644 index 0000000..eab9da1 Binary files /dev/null and b/mkdocs/.cache/plugin/social/d6a59651ce14d60618f2379e9256b991.png differ diff --git a/mkdocs/.cache/plugin/social/d988b15f28c148e32971e4f12f707389.png b/mkdocs/.cache/plugin/social/d988b15f28c148e32971e4f12f707389.png new file mode 100644 index 0000000..91be978 Binary files /dev/null and b/mkdocs/.cache/plugin/social/d988b15f28c148e32971e4f12f707389.png differ diff --git a/mkdocs/.cache/plugin/social/d9e8d1c13d99951d8b781b1a085c84db.png b/mkdocs/.cache/plugin/social/d9e8d1c13d99951d8b781b1a085c84db.png new file mode 100644 index 0000000..1d853a9 Binary files /dev/null and b/mkdocs/.cache/plugin/social/d9e8d1c13d99951d8b781b1a085c84db.png differ diff --git a/mkdocs/.cache/plugin/social/dc743ff10385e2b8e9c5dc9bb08c9896.png b/mkdocs/.cache/plugin/social/dc743ff10385e2b8e9c5dc9bb08c9896.png new file mode 100644 index 0000000..816767c Binary files /dev/null and b/mkdocs/.cache/plugin/social/dc743ff10385e2b8e9c5dc9bb08c9896.png differ diff --git a/mkdocs/.cache/plugin/social/df19479988ef5ec8728ec0c57b86dad3.png b/mkdocs/.cache/plugin/social/df19479988ef5ec8728ec0c57b86dad3.png new file mode 100644 index 0000000..b28e06f Binary files /dev/null and b/mkdocs/.cache/plugin/social/df19479988ef5ec8728ec0c57b86dad3.png differ diff --git a/mkdocs/.cache/plugin/social/e17258471021bfa7cd4ee65f6ada69a7.png b/mkdocs/.cache/plugin/social/e17258471021bfa7cd4ee65f6ada69a7.png new file mode 100644 index 0000000..ffa9332 Binary files /dev/null and b/mkdocs/.cache/plugin/social/e17258471021bfa7cd4ee65f6ada69a7.png differ diff --git a/mkdocs/.cache/plugin/social/e2b6d45c55bda1eeb0c78c74aec619c9.png b/mkdocs/.cache/plugin/social/e2b6d45c55bda1eeb0c78c74aec619c9.png new file mode 100644 index 0000000..10d6ac8 Binary files /dev/null and b/mkdocs/.cache/plugin/social/e2b6d45c55bda1eeb0c78c74aec619c9.png differ diff --git a/mkdocs/.cache/plugin/social/e98f199756a08ab21b5b96938e0ffe75.png b/mkdocs/.cache/plugin/social/e98f199756a08ab21b5b96938e0ffe75.png new file mode 100644 index 0000000..a18f362 Binary files /dev/null and b/mkdocs/.cache/plugin/social/e98f199756a08ab21b5b96938e0ffe75.png differ diff --git a/mkdocs/.cache/plugin/social/eb01905c6cdcb959907c71a8a644c988.png b/mkdocs/.cache/plugin/social/eb01905c6cdcb959907c71a8a644c988.png new file mode 100644 index 0000000..7c6643c Binary files /dev/null and b/mkdocs/.cache/plugin/social/eb01905c6cdcb959907c71a8a644c988.png differ diff --git a/mkdocs/.cache/plugin/social/eba279a8d5f2e38806993cf23591e58b.png b/mkdocs/.cache/plugin/social/eba279a8d5f2e38806993cf23591e58b.png new file mode 100644 index 0000000..cf140fe Binary files /dev/null and b/mkdocs/.cache/plugin/social/eba279a8d5f2e38806993cf23591e58b.png differ diff --git a/mkdocs/.cache/plugin/social/ecaf9eb65147a5b060613c7219ad2114.png b/mkdocs/.cache/plugin/social/ecaf9eb65147a5b060613c7219ad2114.png new file mode 100644 index 0000000..712882f Binary files /dev/null and b/mkdocs/.cache/plugin/social/ecaf9eb65147a5b060613c7219ad2114.png differ diff --git a/mkdocs/.cache/plugin/social/ee01f05b2511823c8b63a62c48514671.png b/mkdocs/.cache/plugin/social/ee01f05b2511823c8b63a62c48514671.png new file mode 100644 index 0000000..c07e616 Binary files /dev/null and b/mkdocs/.cache/plugin/social/ee01f05b2511823c8b63a62c48514671.png differ diff --git a/mkdocs/.cache/plugin/social/ee2f7087ddaa67e80832afd3c6579770.png b/mkdocs/.cache/plugin/social/ee2f7087ddaa67e80832afd3c6579770.png new file mode 100644 index 0000000..25ef54f Binary files /dev/null and b/mkdocs/.cache/plugin/social/ee2f7087ddaa67e80832afd3c6579770.png differ diff --git a/mkdocs/.cache/plugin/social/ef443dff411ebec179759f5575b1305c.png b/mkdocs/.cache/plugin/social/ef443dff411ebec179759f5575b1305c.png new file mode 100644 index 0000000..910cb2e Binary files /dev/null and b/mkdocs/.cache/plugin/social/ef443dff411ebec179759f5575b1305c.png differ diff --git a/mkdocs/.cache/plugin/social/f0b6352ed80a87ed1216e282251ad5fb.png b/mkdocs/.cache/plugin/social/f0b6352ed80a87ed1216e282251ad5fb.png new file mode 100644 index 0000000..5b2e76e Binary files /dev/null and b/mkdocs/.cache/plugin/social/f0b6352ed80a87ed1216e282251ad5fb.png differ diff --git a/mkdocs/.cache/plugin/social/f8ededcb7ae741748289b8994e237c17.png b/mkdocs/.cache/plugin/social/f8ededcb7ae741748289b8994e237c17.png new file mode 100644 index 0000000..6c5f4e4 Binary files /dev/null and b/mkdocs/.cache/plugin/social/f8ededcb7ae741748289b8994e237c17.png differ diff --git a/mkdocs/.cache/plugin/social/f9388a84f13a90eda97b9b6d78214558.png b/mkdocs/.cache/plugin/social/f9388a84f13a90eda97b9b6d78214558.png new file mode 100644 index 0000000..9f848c4 Binary files /dev/null and b/mkdocs/.cache/plugin/social/f9388a84f13a90eda97b9b6d78214558.png differ diff --git a/mkdocs/.cache/plugin/social/fb97f0bfe74bea4659ea90c0a851c2ec.png b/mkdocs/.cache/plugin/social/fb97f0bfe74bea4659ea90c0a851c2ec.png new file mode 100644 index 0000000..9be948c Binary files /dev/null and b/mkdocs/.cache/plugin/social/fb97f0bfe74bea4659ea90c0a851c2ec.png differ diff --git a/mkdocs/.cache/plugin/social/fd2be9ceef639e8833d19f9f1ec7e9a4.png b/mkdocs/.cache/plugin/social/fd2be9ceef639e8833d19f9f1ec7e9a4.png new file mode 100644 index 0000000..2066522 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fd2be9ceef639e8833d19f9f1ec7e9a4.png differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Black Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Black Italic.ttf new file mode 100644 index 0000000..c71c549 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Black Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Black.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Black.ttf new file mode 100644 index 0000000..d51221a Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Black.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Bold Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Bold Italic.ttf new file mode 100644 index 0000000..f73d681 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Bold Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Bold.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Bold.ttf new file mode 100644 index 0000000..9d7cf22 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Bold.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Black Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Black Italic.ttf new file mode 100644 index 0000000..0c31e9f Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Black Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Black.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Black.ttf new file mode 100644 index 0000000..7529d1b Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Black.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Bold Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Bold Italic.ttf new file mode 100644 index 0000000..d269187 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Bold Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Bold.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Bold.ttf new file mode 100644 index 0000000..c3ccd49 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Bold.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraBold Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraBold Italic.ttf new file mode 100644 index 0000000..aeff7c2 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraBold Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraBold.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraBold.ttf new file mode 100644 index 0000000..782442a Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraBold.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraLight Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraLight Italic.ttf new file mode 100644 index 0000000..0f6fe70 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraLight Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraLight.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraLight.ttf new file mode 100644 index 0000000..16a1560 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed ExtraLight.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Italic.ttf new file mode 100644 index 0000000..3b387eb Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Light Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Light Italic.ttf new file mode 100644 index 0000000..9f623e0 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Light Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Light.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Light.ttf new file mode 100644 index 0000000..e70c357 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Light.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Medium Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Medium Italic.ttf new file mode 100644 index 0000000..80ff64e Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Medium Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Medium.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Medium.ttf new file mode 100644 index 0000000..dd2842b Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Medium.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Regular.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Regular.ttf new file mode 100644 index 0000000..5af42d4 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Regular.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed SemiBold Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed SemiBold Italic.ttf new file mode 100644 index 0000000..6cb4656 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed SemiBold Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed SemiBold.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed SemiBold.ttf new file mode 100644 index 0000000..4297f17 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed SemiBold.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Thin Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Thin Italic.ttf new file mode 100644 index 0000000..e58e966 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Thin Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Thin.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Thin.ttf new file mode 100644 index 0000000..1ccebcc Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Condensed Thin.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraBold Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraBold Italic.ttf new file mode 100644 index 0000000..a5536f5 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraBold Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraBold.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraBold.ttf new file mode 100644 index 0000000..7092a88 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraBold.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraLight Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraLight Italic.ttf new file mode 100644 index 0000000..23dbbef Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraLight Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraLight.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraLight.ttf new file mode 100644 index 0000000..75608c6 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/ExtraLight.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Italic.ttf new file mode 100644 index 0000000..978e53a Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Light Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Light Italic.ttf new file mode 100644 index 0000000..a6e5047 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Light Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Light.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Light.ttf new file mode 100644 index 0000000..6fcd5f9 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Light.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Medium Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Medium Italic.ttf new file mode 100644 index 0000000..ef9ed1b Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Medium Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Medium.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Medium.ttf new file mode 100644 index 0000000..d629e98 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Medium.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Regular.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Regular.ttf new file mode 100644 index 0000000..bba55f6 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Regular.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiBold Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiBold Italic.ttf new file mode 100644 index 0000000..132cca1 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiBold Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiBold.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiBold.ttf new file mode 100644 index 0000000..3f34834 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiBold.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Black Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Black Italic.ttf new file mode 100644 index 0000000..19a5096 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Black Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Black.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Black.ttf new file mode 100644 index 0000000..8eedb64 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Black.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Bold Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Bold Italic.ttf new file mode 100644 index 0000000..8604aee Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Bold Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Bold.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Bold.ttf new file mode 100644 index 0000000..98d7b0d Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Bold.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraBold Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraBold Italic.ttf new file mode 100644 index 0000000..b40ce77 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraBold Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraBold.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraBold.ttf new file mode 100644 index 0000000..36423c3 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraBold.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraLight Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraLight Italic.ttf new file mode 100644 index 0000000..929a093 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraLight Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraLight.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraLight.ttf new file mode 100644 index 0000000..e1c25a0 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed ExtraLight.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Italic.ttf new file mode 100644 index 0000000..23454ff Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Light Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Light Italic.ttf new file mode 100644 index 0000000..c096473 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Light Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Light.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Light.ttf new file mode 100644 index 0000000..b9aedcd Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Light.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Medium Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Medium Italic.ttf new file mode 100644 index 0000000..ab34b70 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Medium Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Medium.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Medium.ttf new file mode 100644 index 0000000..e9c34d6 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Medium.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Regular.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Regular.ttf new file mode 100644 index 0000000..36109ba Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Regular.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed SemiBold Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed SemiBold Italic.ttf new file mode 100644 index 0000000..e88bc4a Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed SemiBold Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed SemiBold.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed SemiBold.ttf new file mode 100644 index 0000000..6d10b33 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed SemiBold.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Thin Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Thin Italic.ttf new file mode 100644 index 0000000..81afeea Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Thin Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Thin.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Thin.ttf new file mode 100644 index 0000000..8ed8d79 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/SemiCondensed Thin.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Thin Italic.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Thin Italic.ttf new file mode 100644 index 0000000..0381198 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Thin Italic.ttf differ diff --git a/mkdocs/.cache/plugin/social/fonts/Roboto/Thin.ttf b/mkdocs/.cache/plugin/social/fonts/Roboto/Thin.ttf new file mode 100644 index 0000000..6ee97b8 Binary files /dev/null and b/mkdocs/.cache/plugin/social/fonts/Roboto/Thin.ttf differ diff --git a/mkdocs/docs/.obsidian/app.json b/mkdocs/docs/.obsidian/app.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/mkdocs/docs/.obsidian/app.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/mkdocs/docs/.obsidian/appearance.json b/mkdocs/docs/.obsidian/appearance.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/mkdocs/docs/.obsidian/appearance.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/mkdocs/docs/.obsidian/core-plugins.json b/mkdocs/docs/.obsidian/core-plugins.json new file mode 100644 index 0000000..b977c25 --- /dev/null +++ b/mkdocs/docs/.obsidian/core-plugins.json @@ -0,0 +1,31 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "properties": false, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": true, + "webviewer": false +} \ No newline at end of file diff --git a/mkdocs/docs/.obsidian/workspace.json b/mkdocs/docs/.obsidian/workspace.json new file mode 100644 index 0000000..df09c8c --- /dev/null +++ b/mkdocs/docs/.obsidian/workspace.json @@ -0,0 +1,210 @@ +{ + "main": { + "id": "28d99ecfff66399f", + "type": "split", + "children": [ + { + "id": "23c806066dff2d8f", + "type": "tabs", + "children": [ + { + "id": "6a965ea6f31e2c40", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "resources.md", + "mode": "source", + "source": false + }, + "icon": "lucide-file", + "title": "resources" + } + } + ] + } + ], + "direction": "vertical" + }, + "left": { + "id": "fa91498d762f5bdc", + "type": "split", + "children": [ + { + "id": "a13317dd51ce53be", + "type": "tabs", + "children": [ + { + "id": "30d8652d788934d7", + "type": "leaf", + "state": { + "type": "file-explorer", + "state": { + "sortOrder": "alphabetical", + "autoReveal": false + }, + "icon": "lucide-folder-closed", + "title": "Files" + } + }, + { + "id": "1b7b7eca5484c232", + "type": "leaf", + "state": { + "type": "search", + "state": { + "query": "", + "matchingCase": false, + "explainSearch": false, + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical" + }, + "icon": "lucide-search", + "title": "Search" + } + }, + { + "id": "1e506d971cf8ab5e", + "type": "leaf", + "state": { + "type": "bookmarks", + "state": {}, + "icon": "lucide-bookmark", + "title": "Bookmarks" + } + } + ] + } + ], + "direction": "horizontal", + "width": 300 + }, + "right": { + "id": "c86b3de33a781003", + "type": "split", + "children": [ + { + "id": "c2fad495b67860fa", + "type": "tabs", + "children": [ + { + "id": "8bc6456f6238d0e8", + "type": "leaf", + "state": { + "type": "backlink", + "state": { + "file": "resources.md", + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical", + "showSearch": false, + "searchQuery": "", + "backlinkCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-coming-in", + "title": "Backlinks for resources" + } + }, + { + "id": "ce9900f18830d968", + "type": "leaf", + "state": { + "type": "outgoing-link", + "state": { + "file": "resources.md", + "linksCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-going-out", + "title": "Outgoing links from resources" + } + }, + { + "id": "9c572af5297adb90", + "type": "leaf", + "state": { + "type": "tag", + "state": { + "sortOrder": "frequency", + "useHierarchy": true, + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-tags", + "title": "Tags" + } + }, + { + "id": "b3c0e19b13ee4f3b", + "type": "leaf", + "state": { + "type": "outline", + "state": { + "file": "resources.md", + "followCursor": false, + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-list", + "title": "Outline of resources" + } + } + ] + } + ], + "direction": "horizontal", + "width": 300, + "collapsed": true + }, + "left-ribbon": { + "hiddenItems": { + "switcher:Open quick switcher": false, + "graph:Open graph view": false, + "canvas:Create new canvas": false, + "daily-notes:Open today's daily note": false, + "templates:Insert template": false, + "command-palette:Open command palette": false + } + }, + "active": "6a965ea6f31e2c40", + "lastOpenFiles": [ + "resources_new.md", + "overrides/resources.html", + "getting-started.md", + "cm-lite/index.md", + "assets/images/header.png", + "assets/images/Dropped Image.png", + "contributing/image.png", + "assets/images", + "assets", + "contributing/collaboration.md", + "contributing/submitting-changes.md", + "contributing/local-editing.md", + "contributing/git-basics.md", + "contributing/first-edit.md", + "contributing/navigating-gitea.md", + "contributing/getting-started.md", + "contributing/index.md", + "contributing", + "overrides/partials/footer.html", + "overrides/partials", + "bill-54-analysis.md", + "blog/posts/bill-54-corporate-control.md", + "archive/index.md", + "archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill.md", + "archive/Cold Lake First Nations opposes Albertas proposed Bill 54.md", + "archive/Improving consistency and fairness in Albertas democratic processes.md", + "archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate.md", + "archive/Smiths Electoral Reforms Are Straight from Trumps Playbook.md", + "archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca.md", + "archive/Alberta Government tables changes to the election act.md", + "faq.md", + "blog/posts/municipal-democracy-under-attack.md", + "resources.md", + "blog/posts/indigenous-opposition-bill-54.md", + "archive/Improving consistency and fairness in Alberta’s democratic processes.md", + "Clippings ✂" + ] +} \ No newline at end of file diff --git a/mkdocs/docs/archive/Alberta Government tables changes to the election act.md b/mkdocs/docs/archive/Alberta Government tables changes to the election act.md new file mode 100644 index 0000000..fc8817b --- /dev/null +++ b/mkdocs/docs/archive/Alberta Government tables changes to the election act.md @@ -0,0 +1,79 @@ +--- +title: "Alberta Government tables changes to the election act" +source: "https://www.reddeeradvocate.com/home2/alberta-government-tables-changes-to-the-election-act-7975596" +author: + - "[[Kevin Sabo]]" +published: 2025-04-29 +created: 2025-05-29 +description: "Multiple changes introduced to the Alberta Elections act and other legislation" +tags: + - "clippings" +--- +[Alberta Government tables changes to the election act](https://www.reddeeradvocate.com/home2/alberta-government-tables-changes-to-the-election-act-7975596) + +Multiple changes introduced to the Alberta Elections act and other legislation + +![smith-3](https://www.bpmcdn.com/f/files/stettler/stock-photos/danielle-smith/smith-3.jpg;w=960) + +Danielle Smith[Listen to this article + +00:05:12 + +](https://www.bpmcdn.com/files/texttospeech/7975596-7738590a-4f2e-4f7c-bcf2-07834aee7982.mp3) + +The Government of Alberta has introduced new legislation which it believes will strengthen democracy and result in fair and quick election results. + +Bill 54, the *Election Statutes Amendment Act, 2025,* was tabled in the Alberta legislature on April 29. + +Changes included in the legislation are the banning of electronic tabulators and other automated voting machines, the elimination of vouching at voting stations, the requirement of unofficial vote counts to be completed within 12 hours of polls closing, a requirement for voters to cast their ballot in their home constituency, increasing access to special ballots, making it easier to recall elected officials, and improving the process for citizens to get petitions going. + +"I believe that democracy thrives when people trust the process," said Premier Danielle Smith, via a media release. "These changes would make elections at every level in Alberta more accessible and transparent while protecting their integrity, ensuring confidence in the outcomes. We are also creating more opportunities for Albertans to be involved in direct democracy and to have their say on issues that matter to them.” + +Vouching is the process of having another confirmed voter vouch for someone's identification as a registered voter, even if they aren't carrying any documentation. Instead of allowing vouching, the amended legislation will allow for an expanded array of documentation which registered voters can use to prove residence. + +While not routinely used in Alberta, the updated legislation completely bans the use of electronic voting machines and online voting, opting instead for the traditional paper and pen, hand-counted ballots. The legislation does allow the use of voting assistance machines for those with disabilities, provided it is not connected to the internet and results in a paper, hand-counted ballot. + +Another change being made to the legislation is a requirement that 95 per cent of voters in an electoral division be within 50 kilometres of a voting place and that every population centre with more than 1,000 electors has, at minimum, a voting place on election day and at least one day for advanced voting. Population centres with 2,500 or more residents will be open on election day and on all advance voting days. + +Under the current legislation, special ballots may be delivered until the end of election day. With the amendments, special ballots must be received by the Friday before the election and begin being counted three hours before the polls close. + +The legislation also makes some changes for political parties and candidates under the *Election Act.* + +Under existing legislation, only candidates or their official representatives can inspect documents or request a judicial recount; under the amended legislation, political parties may inspect all documents, scrutineers may observe every aspect of the voting process, and political parties may begin and participate in judicial recounts. + +Other notable amendments being made include changes to the *Citizen Initiative Act,* which the general public can use to trigger petitions*.* + +Under the existing legislation, an initiative must gather signatures from 10 per cent of the registered voters province-wide for legislative and policy initiatives and 20 per cent of registered voters in two-thirds of the constituencies for constitutional initiatives in a 90-day period. + +With the amended legislation, the threshold for success will be changed to 10 per cent of the number of eligible voters who voted in the last general election in 120 days. + +"When we were talking about looking at the thresholds for both recall and citizen initiative, one of the reasons why we were discussing changing it is that you want a bar that's high, but you don't want a bar that's impossible to achieve," said Smith, during the press conference announcing the amendments. "We saw with some of the recall initiatives that took place at the municipal level, the bar was impossible to achieve. So we wanted to try to create something that was a little bit more reasonable." + +Once a petition is successfully submitted, the chief electoral officer will have 30 days to decide if the requirements have been met, and if so, 60 days to submit the matter to the courts for further disposition. + +One piece of legislation getting substantial work is the *Recall Act.* + +With the new amendments, an applicant submitting under the act will be limited to 100 words explaining the reasons that the elected official should be recalled, down from 200, and the elected official will be given seven days to respond. + +Should the recall petition be allowed to proceed, the applicant will have four months to gain the signatures on the petition. Recalls under the new rules will not be allowed within 12 months of someone being elected or within 12 months of a set general election. + +Finally, a change being made to the *Local Authorities Election Act* will require all municipal and school board candidates, and third-party advertisers, to report campaign expenses by Sept. 30 of an election year, where elections are typically held in October. + +--- + +- [See a typo/mistake?](https://www.reddeeradvocate.com/submissions/typo?id=7975596&t=Alberta+Government+tables+changes+to+the+election+act&u=https%3a%2f%2fwww.reddeeradvocate.com%2fhome2%2falberta-government-tables-changes-to-the-election-act-7975596) +- [Have a story/tip?](https://www.reddeeradvocate.com/submissions/newstip) + +--- + +About the Author: Kevin Sabo + +Kevin Sabo has been a resident of the Castor area for the last 12 years, first moving to the area in his previous career as an EMT. + +[Read more](https://www.reddeeradvocate.com/writers/kevin.sabo) + +--- + +--- + +--- \ No newline at end of file diff --git a/mkdocs/docs/archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold.md b/mkdocs/docs/archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold.md new file mode 100644 index 0000000..fe29932 --- /dev/null +++ b/mkdocs/docs/archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold.md @@ -0,0 +1,92 @@ +--- +title: "Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold" +source: "https://edmontonjournal.com/news/politics/alberta-bill-seeks-to-reintroduce-union-corporate-contributions-ban-tabulators-and-lower-recall-threshold" +author: + - "[[Matthew Black]]" +published: 2025-04-29 +created: 2025-05-29 +description: "Bill 54 seeks to overhaul how elections in Alberta are administered and also include a tabulator ban, and changes to initiative and recall." +tags: + - "clippings" +--- +[Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold](https://edmontonjournal.com/news/politics/alberta-bill-seeks-to-reintroduce-union-corporate-contributions-ban-tabulators-and-lower-recall-threshold) + +Alberta is seeking to overhaul how its elections are administered including reintroducing union and corporate spending, increasing election spending limits, and banning vote tabulators as well as change rules around citizen initiatives and recall. + +Bill 54: the Election Statutes Amendment Act, 2025 was tabled in the legislature by Justice Minister Mickey Amery on Tuesday. + +“I believe democracy thrives when people trust the process,” Premier Danielle Smith told reporters about the bill. + +She said the timing of the announcement, coming the day after the federal Liberals won Monday’s election, was coincidental. + +“We were going to introduce it regardless of what the outcome of the election was. It just so happens that this is the timing now.” + +The bill spells out more than 50 proposed changes to rules around elections and would amend seven government acts, some of which mirror the [changes made to municipal elections](https://edmontonjournal.com/news/politics/bill-20-alberta-ban-on-electronic-vote-counters) announced last year via Bill 20. + +Opposition justice critic Irfan Sabir said the new legislature was designed to appeal to the governing UCP’s supporter base. + +“This act is weakening our democracy. This is bringing back dark money into our politics.” + +Here are some of the major changes coming via Bill 54: + +![Headline News](https://dcs-static.gprod.postmedia.digital/18.7.2/websites/images/newsletters/icon-ej-headlineNews.svg) + +Headline News + +Get the latest headlines, breaking news and columns. + +## Unions and corporate donations + +If passed, the legislation would allow Alberta corporations and unions to make contributions to parties, constituency associations, leadership contests and third party advertisers, among others. + +Such contributions are prohibited under current rules in both provincial and federal elections. + +## Election spending limits + +The bill proposes changing the formula-based approach to provincial election spending limits to a limit of $5 million for each registered political party. + +Expense limits per candidate are set to rise to $75,000 from $60,800, and expense limits for parties in a byelection will grow to $75,000 from $28,000. + +## Recall and initiative + +The bill proposes lowering the signature thresholds for both citizen initiatives and recall. + +Currently, initiative petitions must have signatures from 10 per cent of registered voters provincewide for certain initiatives, rising to 20 per cent for others. + +The bill seeks to lower that bar to 10 per cent of the number of eligible voters who voted in the last election. + +Similarly, the bill seeks to make it easier to recall an MLA through a series of changes, including: + +- Reducing the time limit for a recall petition from 18 months after an MLA is elected to 12 months +- Extending the time for signatures to be gathered from 60 days to 90 days +- Reducing the standard for a recall vote to be authorized from signatures from 40 per cent of the total number of electors to 60 per cent of the total number of electors who voted in the most recent election + +## No more ‘vote anywhere’ or vouching, new special ballot rules + +The bill would end the ability of voters in a provincial election to vote outside of their constituency at designated stations. + +The “vote anywhere” option has been credited with making voting more accessible and for boosting turnout. + +Following the 2023 election, officials also cited changes to how those ballots were counted as cause for election night delays in reporting results. + +The legislation also proposes to end the practice of vouching, where an eligible voter in the same voting area vouches for a voter without identification. + +It also seeks to amend rules around special ballots which are currently only available when a voter is unable to vote on the regular election day. + +Under the new legislation, special ballot use would be expanded and voters could use one without having to first give a reason. + +## Tabulator ban + +Similar to municipal elections, the use of electronic vote tabulators will be banned for provincial elections. + +## No lengthy ballots + +The bill also proposed preventing a single official agent from acting on behalf of more than one independent candidate. + +During Monday’s federal elections, voters in the Ottawa riding of Carleton had to navigate a field of 91 candidates on a ballot, including 83 independents all of whom listed the [same individual as their official agent](https://www.elections.ca/Scripts/vis/candidates?L=e&ED=35020&EV=62&EV_TYPE=1&PC=&PROV=ON&PROVID=35&MAPID=&QID=8&PAGEID=17&TPAGEID=&PD=&STAT_CODE_ID=-1). + +[mblack@postmedia.com](https://edmontonjournal.com/news/politics/) + +--- + +![](https://static.adsafeprotected.com/skeleton.gif?adspot_id=ad_300x250_6922349) \ No newline at end of file diff --git a/mkdocs/docs/archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News.md b/mkdocs/docs/archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News.md new file mode 100644 index 0000000..1961d46 --- /dev/null +++ b/mkdocs/docs/archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News.md @@ -0,0 +1,84 @@ +--- +title: "Alberta overhauls election laws to allow corporate donations, change referendum thresholds | CBC News" +source: "https://www.cbc.ca/news/canada/edmonton/alberta-overhauls-election-laws-to-allow-corporate-donations-change-referendum-thresholds-1.7522144" +author: + - "[[Michelle Bellefontaine]]" +published: 2025-04-29 +created: 2025-05-29 +description: "The Alberta government wants to bring back corporate and union political donations, eliminate vouching for a voter’s identity at election polling stations, and lower the threshold for recalls and referendums." +tags: + - "clippings" +--- +[Alberta overhauls election laws to allow corporate donations, change referendum thresholds | CBC News](https://www.cbc.ca/news/canada/edmonton/alberta-overhauls-election-laws-to-allow-corporate-donations-change-referendum-thresholds-1.7522144) + +[Edmonton](https://www.cbc.ca/news/canada/edmonton) + +## Alberta overhauls election laws to allow corporate donations, change referendum thresholds + +The Alberta government wants to bring back corporate and union political donations, eliminate vouching for a voter’s identity at election polling stations, and lower the threshold for recalls and referendums. + +## Bill 54 also eliminates vouching and prohibits use of vote tabulators + +![Justice Minister Mickey Amery talks about his new Bill 54 as Premier Danielle Smith stand to the side, listening.](https://i.cbc.ca/1.7522153.1745962442!/fileImage/httpImage/image.jpg_gen/derivatives/16x9_1180/mickey-amery-and-danielle-smith.jpg?im=Resize%3D780) + +Justice Minister Mickey Amery talks about Bill 54 Tuesday as Premier Danielle Smith listens. (Maxime Lamache/Radio Canada ) + +The Alberta government wants to bring back corporate and union political donations, eliminate the process of vouching for a voter's identity at election polling stations, and lower the threshold for recalls and referendums. + +The measures are proposed in Bill 54, Election Statutes Amendment Act, 2025, tabled by Justice Minister Mickey Amery in the legislature Tuesday. + +The bill, which amends seven pieces of legislation including the Election Act, would also ban the use of electronic vote tabulators, a measure that was promised by Premier Danielle Smith's United Conservative government. + +Smith told a news conference that her government wants to make it easier for Albertans to express their political views. + +"These changes build on the integrity, trust and openness that have always been at the heart of democracy and keep Alberta strong and free," she said. + +- [Alberta government unveils new rules for municipal political parties, donations](https://www.cbc.ca/news/canada/edmonton/alberta-government-unveils-new-rules-for-municipal-political-parties-donations-1.7356117) +- [MLAs pass bill banning corporate and union political donations](https://www.cbc.ca/news/canada/edmonton/mlas-pass-bill-banning-corporate-and-union-political-donations-1.3124424) + +The ban on corporate and union donations to political parties was in the first piece of legislation passed by Rachel Notley's NDP government in 2015. + +If passed, Bill 54 will allow these types of contributions to an aggregate maximum of $5,000 to parties, constituency associations, candidates and third-party political advertisers. The bill also sets a separate contribution limit of $5,000 for leadership candidates. + +Amery said there are differences for how the donations will be reported this time. + +"All candidates have to account for where their money is coming from, who it's coming from and make sure that that is publicly disclosed to members of the public," he said in an interview with CBC News. + +"Moreover, at this time the corporate donations, for example, are not tax deductible. And so that is an important component that differs, I think, from previous time." + +Last fall, the government passed legislation allowing corporate and union donations in municipal elections. + +## Recall and referendum changes + +Currently, voters who lack proper identification can still vote if another eligible voter from their riding is able to vouch for them. Bill 54 will eliminate vouching but it expands the types of identification that can be used to prove someone lives in the electoral district and can vote. + +The Recall Act and the Citizens Initiative Act, passed by the UCP government in 2021, outlines the process by which citizens can initiate the recall of an elected MLA. People have since complained that the timeline and number of signatures required for a successful petition were too onerous. + +Bill 54 proposes lowering the signature threshold, and extending the signature collection period from 60 to 90 days for MLA recalls and from 90 to 120 days for a citizen's initiative or referendum. + +The number of signatures for an MLA recall would be 60 per cent of the number who voted in a riding in the most recent provincial election. The current threshold is 40 per cent of all eligible voters in that riding. + +The threshold for a referendum would be 10 per cent of people who voted in the last provincial election, compared to the current 10 per cent of all registered voters for legislative and policy referendums and 20 per cent of registered voters in two-thirds of Alberta ridings for constitutional questions. + +If the bill is passed, an MLA who is the subject of a recall petition could add a response to the reasons listed by the petitioner. + +A recall vote would be moved up to four months from the current six months if the petition is approved by the chief electoral officer. + +MLA Irfan Sabir, the NDP Opposition justice critic, said he is concerned the government is loosening the rules around referendums to whip up separatist discontent among their base. + +Sabir said he is worried that corporate donors will use a numbered company and make it more difficult to trace the source of a donation. + +"I think elections should not be about who has more money or has deep pockets," Sabir said. "Elections should be about ideas and broader participation from the public." + +The use of tabulator or electronic vote counting machines will be banned under Bill 54 so ballots will have to be counted by hand. The bill sets a deadline of 12 hours for the unofficial vote count to be completed. + +Other measures proposed in Bill 54 include: + +- Requiring municipal councillors and school trustees to take an unpaid leave of absence when they run in a provincial election. +- Increasing spending limits for third-party advertisers from $182,000 to $500,000 in both the pre-writ and election periods. +- Allowing mail-in ballots for constitutional referendums. They are currently allowed for non-constitutional referendums. +- Giving the chief electoral officer the ability to hold referendum votes on First Nations and Métis settlements at the same time as a municipal election. +- Requiring municipal and school board candidates to report their donations by Sept. 30, in advance of the October election. The requirement would also apply to third-party advertisers. +- Allow people to buy party memberships for family members without requiring a receipt if the purchase is under $50. Current rules allow people to buy only memberships for themselves. + +![](https://static.adsafeprotected.com/skeleton.gif?adspot_id=kdalk_728x90_) \ No newline at end of file diff --git a/mkdocs/docs/archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca.md b/mkdocs/docs/archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca.md new file mode 100644 index 0000000..14785c2 --- /dev/null +++ b/mkdocs/docs/archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca.md @@ -0,0 +1,70 @@ +--- +title: "Alberta to make changes to bill proposing sweeping powers over municipalities | Globalnews.ca" +source: "https://globalnews.ca/news/10465280/alberta-bill-20-amendments/" +author: + - "[[Caley Gibson]]" +published: 2024-05-02 +created: 2025-05-29 +description: "Municipal Affairs Minister Ric McIver says the government will introduce changes and implement rules surrounding how and when cabinet can overrule local governments." +tags: + - "clippings" +--- +[Alberta to make changes to bill proposing sweeping powers over municipalities | Globalnews.ca](https://globalnews.ca/news/10465280/alberta-bill-20-amendments/) + +[Politics](https://globalnews.ca/politics/) + +## Alberta to make changes to bill proposing sweeping powers over municipalities + +![Click to play video: 'Alberta Municipalities speaks out over province’s Bill 20 to have more control over local politics'](https://i1.wp.com/media.globalnews.ca/videostatic/news/q8qlpgssjx-qd9vfoj0om/6P-BILL-20-FOLO-PKG_OM00TAZL_thumbnail_1280x720.jpg?w=1040&quality=70&strip=all) + +Alberta Municipalities speaks out over province’s Bill 20 to have more control over local politics + +The Alberta government says it will make amendments to [a bill that would give cabinet unfettered power to fire mayors and councillors](https://globalnews.ca/news/10450717/alberta-municipal-politics-elections-bill/) and overturn bylaws. + +Municipal Affairs Minister Ric McIver said in a statement Thursday that the government will introduce changes and implement rules surrounding how and when cabinet can overrule local governments. + +McIver said the province will work with municipalities on the amendments. + +The bill is before the legislature and has been criticized by municipal leaders as a severe overreach into municipal government affairs. + +“What I would propose is, don’t move ahead with Bill 20 at all. There’s no need for it,” Edmonton Mayor Amarjeet Sohi said Thursday. + +Sohi said he is pleased to hear McIver is responding to the criticism and concerns raised about the bill, and that he’s open to discussing changes with those who have raised issues with it. + +“If there’s a problem they want to solve I think the best way to do that is co-create legislation, not just impose legislation on municipalities,” Sohi said. “This has been kind of a one-way street where we are being told what they are going to do instead of listening to us and engaging with us.” + +Calgary Mayor Jyoti Gondek said she too is appreciative that the minister has indicated he wants to consult with municipalities, but added the legislation as it stands is a “great overreach.” + +“I’ve had a call with him. He reiterated that he will be engaging with us, so that’s great. But I continue to see an issue with the idea of saying that someone could be removed in the public interest without defining what that means,” Gondek said. + +“If they’re truly interested in making sure that someone who’s broken a law or misrepresented themselves or done something unethical is to be removed, then that language needs to be clear.” + +Gondek also noted she is unclear how the consultation process is going to unfold. + +“Bill 20 comes with a whole lot of questions and right now there’s not a lot of answers.” + +![Click to play video: 'Alberta Municipalities ‘caught off guard’ by details of Bill 20'](https://i2.wp.com/media.globalnews.ca/videostatic/news/sd4w5l3tx4-93znkke4mh/nntyler.jpg?w=1040&quality=70&strip=all) + +Alberta Municipalities ‘caught off guard’ by details of Bill 20 + +Alberta Municipalities president Tyler Gandam has said members are concerned the proposed law would intimidate and silence legally elected officials who dare criticize the province. + +McIver said he wants to make it clear that the new powers in the bill would only be used as a last resort. + +He said the power to repeal municipal bylaws should be used only when those bylaws fall under areas of shared responsibility, such as health care, education, the provincial economy or public safety. + +Sohi went on to say that if the legislation does move forward, he believes it should be used only in the rarest of circumstances. He also believes any use of the bill should be discussed in the legislature, and not just within cabinet. + +“Cabinet decisions are not made in a transparent, open way and there’s no accountability on cabinet. There is accountability in the legislature where people can ask questions around why a council member is being removed or why a duly-passed bylaw by a council is being repealed by the province,” Sohi said. + +He also believes there is no need for political parties at a municipal level. + +“Let people decide who they elect, and then let the local elected people make decisions on behalf of the constituents that have elected us.” + +The Alberta NDP’s critic for municipalities said rather than make amendments, the UCP needs to withdraw Bill 20 entirely. + +“Bill 20 is a threat to our democracy,” Kyle Kasawski said in a statement. + +“This bill is another example of Smith’s made-in-Alberta authoritarian approach to governing. The UCP wants to control everything, whether it be our universities, schools, health care, police force, pensions and now municipal councils.” + +*— with files from The Canadian Press* \ No newline at end of file diff --git a/mkdocs/docs/archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca.md b/mkdocs/docs/archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca.md new file mode 100644 index 0000000..dd40bd0 --- /dev/null +++ b/mkdocs/docs/archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca.md @@ -0,0 +1,36 @@ +--- +title: "Alberta’s chief electoral officer warns UCP proposed bill will hurt investigations | Globalnews.ca" +source: "https://globalnews.ca/news/11173342/alberta-chief-electoral-officer-warns-ucp-proposed-bill-will-hurt-investigations/" +author: + - "[[The Canadian Press, globalnewsdigital]]" +published: 2025-05-09 +created: 2025-05-29 +description: "Alberta's chief electoral officer said a controversial new bill, tabled by the UCP last month, will impair his ability to investigate allegations of election rule breaking." +tags: + - "clippings" +--- +[Alberta’s chief electoral officer warns UCP proposed bill will hurt investigations | Globalnews.ca](https://globalnews.ca/news/11173342/alberta-chief-electoral-officer-warns-ucp-proposed-bill-will-hurt-investigations/) + +[Politics](https://globalnews.ca/politics/) + +## Alberta’s chief electoral officer warns UCP proposed bill will hurt investigations + +![Click to play video: 'Alberta proposes sweeping changes to provincial election laws'](https://i1.wp.com/media.globalnews.ca/videostatic/news/mfnj1dqi88-fts7hn8q9l/6P_ELECTION_LEGISLATION_OM01APJW_thumbnail_1280x720.jpg?w=1040&quality=70&strip=all) + +Alberta proposes sweeping changes to provincial election laws + +Alberta’s chief electoral officer is warning the government that proposed legislation will impair the election commissioner’s power to investigate election rule breaking. + +A controversial bill introduced last month, if passed, will make sweeping changes to voting and referendums in the province, and is making its way through debate in the legislature. + +In documents sent to Justice Minister Mickey Amery and all legislature members, chief electoral officer Gordon McClure warns that some changes in the bill will reduce the election commissioner’s ability to investigate and enforce compliance with election law, including financial contribution rules. + +![Alberta's Chief Electoral Officer, Gordon McClure, warns new UCP legislation will reduce the election commissioner's ability to investigate and enforce compliance with election laws.](https://globalnews.ca/wp-content/uploads/2025/05/alberta-election-2_1.jpg?quality=85&strip=all&w=1200) + +Alberta’s Chief Electoral Officer, Gordon McClure, warns new UCP legislation will reduce the election commissioner’s ability to investigate and enforce compliance with election laws. Global News + +A summary of concerns attached to the email says that under one of the bill’s proposed changes, none of the significant investigations undertaken by the election commissioner in the last five years would have happened and some current investigations would need to be abandoned. + +Amery says all of the bill’s proposals are meant to protect democracy, deliver fair and open elections, and restore confidence in every vote cast by Albertans, but he did not directly address McClure’s concerns. + +Opposition NDP justice critic Irfan Sabir says McClure’s letter makes it clear the United Conservatives are undermining investigations into election law, which would let those who break the rules off the hook. \ No newline at end of file diff --git a/mkdocs/docs/archive/Central Alberta First Nations slam Bill 54.md b/mkdocs/docs/archive/Central Alberta First Nations slam Bill 54.md new file mode 100644 index 0000000..990f5dd --- /dev/null +++ b/mkdocs/docs/archive/Central Alberta First Nations slam Bill 54.md @@ -0,0 +1,79 @@ +--- +title: "Central Alberta First Nations slam Bill 54" +source: "https://www.reddeeradvocate.com/home/central-alberta-first-nations-slam-bill-54-8011556" +author: + - "[[Red Deer Advocate]]" +published: 2025-05-15 +created: 2025-05-29 +description: "Treaty 6 Nations vow to fight against separation legislation" +tags: + - "clippings" +--- +[Central Alberta First Nations slam Bill 54](https://www.reddeeradvocate.com/home/central-alberta-first-nations-slam-bill-54-8011556) + +Treaty 6 Nations vow to fight against separation legislation + +![web1_240222-rda-alberta-sports-hall-of-fame2](https://www.bpmcdn.com/f/files/shared/feeds/gps/2024/02/web1_240222-rda-alberta-sports-hall-of-fame2.jpg;w=960) + +Alberta Government House Leader Joseph Schow (Advocate file photo)[Listen to this article + +00:05:03 + +](https://www.bpmcdn.com/files/texttospeech/8011556-476b864d-f154-457f-a908-e1ae638ae6ec.mp3) + +Central Alberta First Nations have vowed to fight provincial legislation that would make it easier to put forward citizen-led referendums, including separation from Canada questions. + +"Premier (Danielle) Smith's government is not interested in partnership," said the Confederacy of Treaty 6 First Nations in a statement Thursday. "(I)nstead they sow division among Albertans and attack our Treaties by passing Bill 54. + +"We will fight against separtion and any 'citizen-led' referendum that threatens Treaty." + +Treaty 6 covers 15 First Nations, including Sunchild and O'Chiese, northwest of Rocky Mountain House, and Maskwacis's Samson, Louis Bull, Ermineskin and Montana First Nations. Alexander, Alexis Nakota Sioux, Beaver Lake, Cold Lake, Enoch, Frog Lake, Whitefish Lake, Heart Lake and Kehewin Cree First Nations are also part of the treaty first signed in 1876. + +The provincial government's Bill 54, known as the Election Statutes Amendment Act, among other things, lowers the threshold for citizen-led referendums. After First Nations groups complained, last-minute changes to the legislation were made declaring that existing treaty rights could not be threatened by any referendum question. + +"I believe that democracy thrives when people trust the process," said Premier Danielle Smith, via a media release last month. "These changes would make elections at every level in Alberta more accessible and transparent while protecting their integrity, ensuring confidence in the outcomes. We are also creating more opportunities for Albertans to be involved in direct democracy and to have their say on issues that matter to them.” + +With the amended legislation, the threshold for success will be changed to 10 per cent of the number of eligible voters who voted in the last general election in 120 days. + +"When we were talking about looking at the thresholds for both recall and citizen initiative, one of the reasons why we were discussing changing it is that you want a bar that's high, but you don't want a bar that's impossible to achieve," said Smith, during the press conference announcing the amendments. "We saw with some of the recall initiatives that took place at the municipal level, the bar was impossible to achieve. So we wanted to try to create something that was a little bit more reasonable." + +Once a petition is successfully submitted, the chief electoral officer will have 30 days to decide if the requirements have been met, and if so, 60 days to submit the matter to the courts for further disposition. + +The new amendments fall short of the changes First Nations groups wanted that would have made it impossible for a separation referendum to go forward. + +"First Nations have always been kind and loving, but our kindness is taken advantage of. Let us be clear: we are not subordinate to Alberta or Canada. Our relationship is Nation-to-Nation with the Crown, and that relationship must be respected," says the statement from Confederacy of Treaty 6 Grand Chief Greg Desjarlais. + +Desjarlais said they are prepared to take their fight to the courts. + +"Our rights are affirmed and protected by Section 35 of the Constitution — we will not hesitate to assert them. Our sacred Treaty will not be undone by the thoughtless and careless actions of a loud minority. + +"You cannot undermine our rights or our future." + +Alberta House Leader Joseph Schow said in a news conference on Thursday that the bill is a large piece of legislation is about making elections transparent and fair and not just about referendums. + +He said he was not surprised at the response because it involves change. "But I think it is change in response to the requests that we've had. + +"The most important thing we can do as a government is ensure confidence in election results and that's what I think this piece of legislation does." + +NDP Opposition Leader Christina Gray criticized the UCP government for Bill 54, as well as its lack of action on addressing cost of living or the health-care system "crisis." + +"Not only did they pass anti-democratic legislation like Bill 54, but they used anti-democratic tactics in the Legislature to get it done." + +Gray took aim at the Smith government for using time allocation motions that "cut off debate and allowed them to ram through controversial legislation with minimal scrutiny or public awareness." + +The UCP government has refused to pass any NDP Private Member's Bills, while passing all of those introduced by UCP MLAs, she says. + +Gray also accused the UCP of covering up a health-care inquiry and passing a provincial budget that cuts critical services and "did nothing for Albertans." + +*Editor's Note: This article has been updating to include additional comments and information from the Government of Alberta regarding Bill 54.* + +--- + +- [See a typo/mistake?](https://www.reddeeradvocate.com/submissions/typo?id=8011556&t=Central+Alberta+First+Nations+slam+Bill+54&u=https%3a%2f%2fwww.reddeeradvocate.com%2fhome%2fcentral-alberta-first-nations-slam-bill-54-8011556) +- [Have a story/tip?](https://www.reddeeradvocate.com/submissions/newstip) + +--- + +--- + +--- \ No newline at end of file diff --git a/mkdocs/docs/archive/Cold Lake First Nations opposes Albertas proposed Bill 54.md b/mkdocs/docs/archive/Cold Lake First Nations opposes Albertas proposed Bill 54.md new file mode 100644 index 0000000..31f40df --- /dev/null +++ b/mkdocs/docs/archive/Cold Lake First Nations opposes Albertas proposed Bill 54.md @@ -0,0 +1,34 @@ +--- +title: "Cold Lake First Nations opposes Alberta's proposed Bill 54" +source: "https://www.pentictonherald.ca/spare_news/article_86bbdec9-fb00-5fd2-b261-4a978636bc67.html" +author: + - "[[Chantel Downes, Local Journalism Initiative Reporter Lakeland This Week]]" +published: 2025-05-20 +created: 2025-05-29 +description: "CLFN asserts that such measures threaten their treaty rights and sovereignty." +tags: + - "clippings" +--- +[Cold Lake First Nations opposes Alberta's proposed Bill 54](https://www.pentictonherald.ca/spare_news/article_86bbdec9-fb00-5fd2-b261-4a978636bc67.html) + +CLFN asserts that such measures threaten their treaty rights and sovereignty. + +In a statement released on May 7, CLFN shared their identity as the Denesuline of Łué Chok Tué, original signatories of Treaty 6 in 1876. They highlighted their millennia-long occupation of ancestral lands in northeastern Treaty 6 territory, stating that their culture, language, and way of life are inherently tied to these lands. + +Chief Kelsey Jacko declared, "We are part of the land that continues to sustain us." + +The letter expressed strong opposition to the proposed changes in the Alberta Elections Act, particularly the provision allowing a citizen-led referendum on provincial separation from Canada in 2026. + +Jacko described this move as "reckless, dangerous and deeply disrespectful to the original peoples as holders of inherent rights and title." The statement further asserted, "Our treaties are solemn and sacred agreements... We continue to honour our sacred treaties and will do so forever, including protecting the lands that have sustained our people for thousands of years." + +The proposed Bill 54 aims to amend the Alberta Elections Act by lowering the threshold for citizen-initiated referendums. The bill proposes reducing the required number of signatures from 20 per cent to 10 per cent of eligible voters and extending the collection period from 90 to 120 days. This change would make it easier for citizens to trigger referendums on various issues, including provincial separation, as detailed in the Government of Alberta's official fact sheet on the Election Statutes Amendment Act, 2025. + +Premier Danielle Smith addressed the province on May 5, stating that while she does not support Alberta's separation from Canada, she would respect the democratic process if a citizen-led petition met the required criteria. + +She noted, "If there is a successful citizen-led referendum petition... our government will respect the democratic process and include that question on the 2026 provincial referendum ballot,” according to the Government of Alberta website. + +The Premier affirms a firm commitment to protecting and honoring the inherent rights of First Nations, Métis, and Inuit peoples. Any citizen-initiated referendum must not violate their constitutional rights and must respect Treaties 6, 7, and 8. This commitment is non-negotiable. + +Jacko added that they “will not be forced by any settler government to relocate, renegotiate our treaties or longstanding legal and political orders and relationships at the whim of settler populations.” + +In the letter, Cold Lake First Nations made clear that their rights and title have never been surrendered, stating, “We never surrendered our sovereignty. Our rights and title to our ancestral lands continue in force today and forever.” Jacko added, “Our treaty is not negotiable; it never was and never will be.” \ No newline at end of file diff --git a/mkdocs/docs/archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging.md b/mkdocs/docs/archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging.md new file mode 100644 index 0000000..742b3cb --- /dev/null +++ b/mkdocs/docs/archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging.md @@ -0,0 +1,66 @@ +--- +title: "Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging" +source: "https://nationalpost.com/news/politics/smith-lowers-bar-for-alberta-referendum-with-separatism-sentiment-emerging" +author: + - "[[Rahim Mohamed]]" +published: 2025-04-30 +created: 2025-05-29 +description: "Alberta Premier Danielle Smith says she'll make it easier for citizens to initiate a referendum on the province's future in Canada." +tags: + - "clippings" +--- +[Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging](https://nationalpost.com/news/politics/smith-lowers-bar-for-alberta-referendum-with-separatism-sentiment-emerging) + +![Alberta flag.](https://smartcdn.gprod.postmedia.digital/nationalpost/wp-content/uploads/2025/04/Alberta-flag.jpg?quality=90&strip=all&w=564&h=423&type=webp&sig=s3zUpV6y9l1knq3QckNZ1w) + +If passed into provincial law, the new bill would pave the way to put a citizen-proposed constitutional referendum question on the ballot with the signatures of just over 175,000 Albertans, based on 2023 electoral numbers. Photo by Azin Ghaffari/Postmedia + +OTTAWA — Alberta Premier Danielle Smith says she’ll make it easier for citizens to initiate a referendum on the province’s future in Canada, after warning that a Liberal win in Monday’s election could spur [a groundswell of support](https://x.com/ABDanielleSmith/status/1902787610608800048) for Alberta separatism. + +Smith said on Tuesday that a [newly tabled elections bill](https://www.assembly.ab.ca/assembly-business/assembly-dashboard?legl=31&session=1&billinfoid=12082&anchor=g12082%C2%A7ionb=d12082#g12082) will give everyday Albertans a bigger say in the province’s affairs. + +“(We’re giving) Albertans more ways to be directly involved in democracy, and to have their say on issues that matter to them,” Smith told reporters in Edmonton. + +![First Reading](https://dcs-static.gprod.postmedia.digital/18.7.2/websites/images/newsletters/icon-np-firstReading.svg) + +If passed, the new law would dramatically lower the number of signatures needed to put a citizen-proposed constitutional referendum question on the ballot, setting a new threshold of 10 per cent of general election turnout — or just over 175,000, based on Alberta’s last provincial election in 2023. + +The law will also extend the signature collection time for citizens’ initiatives, from 90 to 120 days, and get rid of the existing riding-level threshold for signatures. + +Smith said on Tuesday that the current threshold of 20 per cent of registered voters, roughly 600,000 signatures, is far too high, making citizens’ initiatives virtually impossible to move forward. + +“You want a bar that’s high, but you don’t want a bar that’s impossible to achieve… so we wanted to try to create something that was a little bit more reasonable.” said Smith. + +Smith noted that there haven’t been any citizen-initiated referendums [under the existing threshold](https://www.canlii.org/en/ab/laws/stat/sa-2021-c-c-13.2/latest/sa-2021-c-c-13.2.html), set in 2022. + +“That also suggested to us that people thought it was just pointless to go out and try to get that many signatures.” + +Smith said that, while she personally supported Alberta staying in Canada, she wouldn’t stand in the way of a citizen-led referendum on independence. + +“(T)here is a citizen initiative referendum process that if citizens want to put a question on the ballot and get enough of their fellow citizens to sign that petition, then those questions will be put forward… I don’t want to pre-judge what a question might be,” said Smith. + +Smith previously announced she’d be [setting up a post-election panel](https://www.ctvnews.ca/edmonton/article/premier-plans-post-election-panel-to-gauge-albertans-appetite-for-referendum/) that will give citizens a chance to put forward potential referendum questions. + +Polls heading into Monday’s federal election showed that as many as [three in 10 Albertans](https://thehub.ca/2025/03/21/hub-exclusive-while-separatism-sentiment-grows-in-western-canada-84-percent-of-quebeckers-say-independence-for-their-province-is-unlikely/) would vote for Alberta to leave Canada if the Liberals won a fourth term in office. + +![Danielle Smith](https://smartcdn.gprod.postmedia.digital/nationalpost/wp-content/uploads/2025/04/dsc_0682_295273284.jpg?quality=90&strip=all&w=288&sig=2KBNek-9KzI4-igSS8ljng) + +Premier Danielle Smith announces proposed changes to several pieces of democratic process legislation at the Alberta Legislature on April 29, 2025. Photo by Shaughn Butts/Postmedia + +Take Back Alberta founder David Parker said on Wednesday that his online petition for a referendum on Alberta sovereignty had collected [more than 80,000 signatures](https://x.com/DavidJPba/status/1917579648122093634) in less than 36 hours. + +Parker said he expected to hit the 200,000 mark by the end of the week. + +Karamveer Lalh, an Edmonton-based lawyer who helped write the first version of [the citizens’ initiatives law](https://www.canlii.org/en/ab/laws/stat/sa-2021-c-c-13.2/latest/sa-2021-c-c-13.2.html), said that he expects to see other grassroots campaigners test the waters in the coming weeks. + +“You ideally want the movement and infrastructure to be in place before you actually go forward with trying to go through the petition process,” Lalh told the National Post. + +“Basically, you want to be confident that you’ll be able to get the signatures to cross the threshold before you’re officially on the clock.” + +National Post + +*rmohamed@postmedia.com* + +*Get more deep-dive National Post political coverage and analysis in your inbox with the Political Hack newsletter, where Ottawa bureau chief Stuart Thomson and political analyst Tasha Kheiriddin get at what’s really going on behind the scenes on Parliament Hill every Wednesday and Friday, exclusively for subscribers. [Sign up here](https://nationalpost.com/newsletters/).* + +*Our website is the place for the latest breaking news, exclusive scoops, longreads and provocative commentary. Please bookmark [nationalpost.com](https://nationalpost.com/) and sign up for our politics newsletter, First Reading, [here](https://nationalpost.com/newsletters/).* \ No newline at end of file diff --git a/mkdocs/docs/archive/Improving consistency and fairness in Albertas democratic processes.md b/mkdocs/docs/archive/Improving consistency and fairness in Albertas democratic processes.md new file mode 100644 index 0000000..da0bc8f --- /dev/null +++ b/mkdocs/docs/archive/Improving consistency and fairness in Albertas democratic processes.md @@ -0,0 +1,66 @@ +--- +title: "Improving consistency and fairness in Alberta’s democratic processes" +source: "https://www.alberta.ca/improving-consistency-fairness-albertas-democratic-processes" +author: + - "[[Alberta.ca]]" +published: 2025-05-27 +created: 2025-05-29 +description: "The Election Statutes Amendment Act, 2025, updates several pieces of legislation to strengthen trust in democratic processes." +tags: + - "clippings" +--- +[Improving consistency and fairness in Alberta’s democratic processes](https://www.alberta.ca/improving-consistency-fairness-albertas-democratic-processes) + +Status: Bill 54 received Royal Assent on May 15, 2025. + +Ministry responsible: Justice + +## Overview + +The [*Election Statutes Amendment Act, 2025*](https://www.assembly.ab.ca/assembly-business/bills/bill?billinfoid=12082&from=bills) (formerly Bill 54), will ensure democratic processes are aligned and conducted in a transparent manner. Democratic processes include elections, whether provincial, municipal or Senate, and direct democracy processes like referendums, MLA recall and citizen initiative petitions. These legislative amendments are occurring together to help ensure a consistent framework for democratic processes. + +The act will aim to increase fairness in provincial elections by improving investigation and enforcement of election rules. + +Additional amendments will: + +- improve access to voting and timeliness and accuracy of election results +- permit Alberta businesses and unions to make contributions related to provincial elections and direct democracy processes +- hold MLAs accountable + +## Key changes + +The *Election Statutes Amendment Act, 2025* amends the following legislation. Read the [Election Statutes Amendment Act, 2025 fact sheet](https://www.alberta.ca/system/files/jus-election-statutes-amendment-act-2025.pdf "jus-election-statutes-amendment-act-2025.pdf") for a complete list of amendments. + +- - Bans the use of electronic vote tabulators and the use of vouching. + - Expands the availability and integrity of special ballots. + - Requires the unofficial vote count to be completed within 12 hours of polls closing. + - Requires Albertans to vote in their electoral divisions. + - Expands the types of identification that can be used to prove residence. + - Expands rights for political parties and scrutineers. + - Allows the province to set regulations for election signs and advertising. + - Clarifies that government may advertise during elections if the advertising does not have an undue influence on voters. +- - Allows corporate and union contributions for provincial elections and applies existing reporting requirements. + - Reduces the maximum limit on contributions to third party advertisers. + - Adjusts party and candidate expense limits to recognize the increasing costs of campaigning. + - Increases third party election advertising spending limits. +- - Improves the process for responding to emergencies and improves access to voting by First Nations and Metis Settlements. +- - Improves the process for responding to emergencies and improves access to voting by First Nations and Metis Settlements. + - Requires third-party referendum advertisers to indicate if they are for or against a referendum question or questions – this change is included in the *Election Finances and Contributions Disclosure Act* but applies to referendums. + - Removes the requirement for a referendum before a resolution for a constitutional amendment. + - Creates a regulation making power under which the government may specify the extent to which provisions of the *Election Finances and Contributions Disclosure Act* apply to a referendum. + - Adds a section that states nothing in a referendum held under this act is to be construed as abrogating or derogating from the existing Aboriginal and treaty rights of the Aboriginal Peoples of Canada that are recognized and affirmed by [section 35](https://www.canlii.org/en/ca/laws/stat/schedule-b-to-the-canada-act-1982-uk-1982-c-11/latest/schedule-b-to-the-canada-act-1982-uk-1982-c-11.html#sec35_smooth) of the [*Constitution Act, 1982*](https://www.canlii.org/en/ca/laws/stat/schedule-b-to-the-canada-act-1982-uk-1982-c-11/latest/schedule-b-to-the-canada-act-1982-uk-1982-c-11.html). +- - Increases public trust in the recall process and improves the process for Albertans to hold their elected MLAs accountable between elections. +- - Increases Albertans’ ability to have their voices heard and play a more direct role in the democratic process by initiating action on issues that affect them. +- - Improves transparency by updating campaign finance rules for candidates and third-party advertisers to report by September 30 of the election year, rather than March 1 of the following year. + +## Next steps + +The amendments to the *Local Authorities Election Act* came into force May 15, 2025. Changes to all other acts will come into force on proclamation. + +## Resources + +- [Local political parties and campaign expense limits](https://www.alberta.ca/system/files/ma-local-parties-and-campaign-expense-limits-fact-sheet.pdf "ma-local-parties-and-campaign-expense-limits-fact-sheet.pdf") + +## News + +- [Strengthening democracy](https://www.alberta.ca/release.cfm?xID=932071DE8A863-A23D-5F75-F0C967208F7B4ABB) (April 29, 2025) \ No newline at end of file diff --git a/mkdocs/docs/archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill.md b/mkdocs/docs/archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill.md new file mode 100644 index 0000000..22a5618 --- /dev/null +++ b/mkdocs/docs/archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill.md @@ -0,0 +1,138 @@ +--- +title: "May 2024: Alberta Municipalities said it hasn't been given chance to consult on changes to bill" +source: "https://www.winnipegfreepress.com/uncategorized/2024/05/06/alberta-municipalities-said-it-hasnt-been-given-chance-to-consult-on-changes-to-bill" +author: + - "[[Lisa Johnson, The Canadian Press, feedloaderapi]]" +published: 2024-05-06 +created: 2025-05-29 +description: "Breaking News, Sports, Manitoba, Canada" +tags: + - "clippings" +--- +[May 2024: Alberta Municipalities said it hasn't been given chance to consult on changes to bill](https://www.winnipegfreepress.com/uncategorized/2024/05/06/alberta-municipalities-said-it-hasnt-been-given-chance-to-consult-on-changes-to-bill) + +## Notification Settings + +This browser doesn't support push notifications at the moment. Check browsers features, update your browser or try to use one from the list of recommended to manage your notifications settings: + +- Firefox (27+) +- Google Chrome (30+) +- Safari ( MacOS 13+ with browser 16.1+ and iOS 16.4+ ) / Note make sure Push API support enabled under Settings > Safari > Advanced > Experimental Features +- Microsoft Edge + +If you wish to manage your notification settings from this browser you will need to update your browser's settings for this site. Just click button below and allow notifications for this site + +Note Safari 16.4+ working on iOS devices also need this site app to be installed at device's Home Screen for Push Notifications to work + +[Manage Notification Settings](https://www.winnipegfreepress.com/uncategorized/2024/05/06/#) + +Close + +- [Share](https://bsky.app/intent/compose?text=Alberta%20Municipalities%20said%20it%20hasn%26%238217%3Bt%20been%20given%20chance%20to%20consult%20on%20changes%20to%20bill%0Ahttps%3A%2F%2Fwww.winnipegfreepress.com%2Funcategorized%2F2024%2F05%2F06%2Falberta-municipalities-said-it-hasnt-been-given-chance-to-consult-on-changes-to-bill) +- [Print](https://www.winnipegfreepress.com/uncategorized/2024/05/06/ "Print Alberta Municipalities said it hasn’t been given chance to consult on changes to bill") +- [Email](https://www.winnipegfreepress.com/uncategorized/2024/05/06/alberta-municipalities-said-it-hasnt-been-given-chance-to-consult-on-changes-to-bill "Share by Email") +- [Read Later](https://www.winnipegfreepress.com/uncategorized/2024/05/06/# "Bookmark") + +EDMONTON - Alberta's municipal affairs minister declined Monday to clarify whether towns and cities would still get their say before changes are made to a contentious bill that gives the province broad authority to fire local councillors. + +Read this article for free: + +To continue reading, please subscribe: + +#### Monthly Digital Subscription + +**$19 + tax for 4 weeks** +and receive a Canada Proud Manitoba Strong mug and sticker FREE! + +- Enjoy unlimited reading on winnipegfreepress.com +- Read the E-Edition, our digital replica newspaper +- Access News Break, our award-winning app +- Play interactive puzzles + +![Canada Proud, Manitoba Strong mug and sticker](https://www.winnipegfreepress.com/wp-content/uploads/sites/2/2025/04/canada-strong-merch01.png) + +\*Special offer only available to new subscribers or returning subscribers without a subscription for more than eight weeks. New subscription must remain active for at least 12 weeks. If cancelled prior to 12 weeks, you will be charged regular price for the merchandise. Merchandise is provided “as is” and cannot be exchanged. Expect merchandise delivery within two weeks for addresses within Manitoba and up to four weeks if outside of Manitoba. + +To continue reading, please subscribe: + +#### Add Winnipeg Free Press access to your Brandon Sun subscription for only + +**$1 for the first 4 weeks\*** + +- Enjoy unlimited reading on winnipegfreepress.com +- Read the E-Edition, our digital replica newspaper +- Access News Break, our award-winning app +- Play interactive puzzles +[Start now](https://account.winnipegfreepress.com/subscribe-wfp-bsn-promo/) + +No thanks + +\*$1 will be added to your next bill. After your 4 weeks access is complete your rate will increase by $0.00 a X percent off the regular rate. + +EDMONTON - Alberta's municipal affairs minister declined Monday to clarify whether towns and cities would still get their say before changes are made to a contentious bill that gives the province broad authority to fire local councillors. + +Read unlimited articles for free today: + +**Hey there, time traveller!** +This article was published **06/05/2024** (388 days ago), so information in it may no longer be current. + +EDMONTON – Alberta’s municipal affairs minister declined Monday to clarify whether towns and cities would still get their say before changes are made to a contentious bill that gives the province broad authority to fire local councillors. + +Ric McIver announced the changes last Thursday and promised at that time he would talk to municipal leaders about looming amendments to the bill. + +But on Monday, when asked by reporters on the state of consultations, McIver pointed to the fact he already spoke with multiple leaders “over the last few days” about the impending changes. + +![Minister of Municipal Affairs Ric McIver and Alberta Premier Danielle Smith take part in a press conference in Edmonton on Wednesday April 10, 2024. THE CANADIAN PRESS/Jason Franson](https://www.winnipegfreepress.com/wp-content/uploads/sites/2/2024/04/20240506180532-cd9e2898c14de45e531fa644a2cb344ece6feaedc934ce4b17f86528defa9a21.jpg?w=1000) + +Minister of Municipal Affairs Ric McIver and Alberta Premier Danielle Smith take part in a press conference in Edmonton on Wednesday April 10, 2024. THE CANADIAN PRESS/Jason Franson + +When asked if he considered those discussions to be the promised consultation, McIver declined to clarify. + +“It’s one form of consultation, it’s certainly not the only form,” he replied. + +The bill, introduced April 25, has been widely condemned by municipal leaders as a broad overreach into their authority with a possible chill effect on their decision making. + +The bill not only gives cabinet broad power to fire councillors but also overturn any council bylaw. + +This weekend, Craig Snodgrass, the mayor of High River – Premier Danielle Smith’s hometown — said the only reason the bill is on the table is because the UCP has failed to get “their people” into the mayor’s seat in Edmonton and Calgary. + +“This is about control. It won’t end with the big cities. Scrap it,” Snodgrass wrote on social media. + +McIver said last week the amendments will address those concerns but has not provided specifics. + +Tyler Gandam, president of Alberta Municipalities — the organization representing Alberta towns, cities and villages – confirmed that McIver called him last week to say changes were coming, but said that has been it. + +“Minister McIver committed to consulting with Alberta Municipalities in advance of the announcement of the forthcoming amendments, but nothing has been arranged yet,” Gandam said in a statement. + +“I trust we will have the opportunity to address our concerns on all parts of the bill,” he said. + +Paul McLauchlin, head of Rural Municipalities of Alberta, told CHED radio Monday he has had “discussions” with McIver. + +While McLauchlin said he’s hopeful McIver has heard the organization’s concerns and will make necessary changes, he said nobody was asking for a bill making it easier for cabinet to remove local councillors or mayors. + +“What is the point? Is the point to assert authority? Or is the point to provide clarity to governance?” said McLauchlin. + +It’s also not clear when the amendments will be brought to the floor of the legislature. + +Smith has said amendments would come this week and would clarify the new cabinet powers would be used only sparingly. + +Asked Monday about the timeline, McIver said, “When amendments are ready, we will introduce them in the house.” + +But McIver said time is a factor. He said the government aims to ensure the bill passes debate in the legislature in the current sitting, which is scheduled to rise at the end of the month. + +Opposition New Democrats have said the bill is so flawed it needs to be pulled altogether. + +McIver said municipal officials will need time to get ready for the next elections in October 2025. + +“Time is ticking, and it’s an important issue,” McIver said. + +The bill also makes changes to local elections, including mandating hand-counted ballots, and green lighting political parties to run in Edmonton and Calgary. + +This report by The Canadian Press was first published May 6, 2024. + +- [Share](https://bsky.app/intent/compose?text=Alberta%20Municipalities%20said%20it%20hasn%26%238217%3Bt%20been%20given%20chance%20to%20consult%20on%20changes%20to%20bill%0Ahttps%3A%2F%2Fwww.winnipegfreepress.com%2Funcategorized%2F2024%2F05%2F06%2Falberta-municipalities-said-it-hasnt-been-given-chance-to-consult-on-changes-to-bill) +- [Print](https://www.winnipegfreepress.com/uncategorized/2024/05/06/ "Print Alberta Municipalities said it hasn’t been given chance to consult on changes to bill") +- [Email](https://www.winnipegfreepress.com/uncategorized/2024/05/06/alberta-municipalities-said-it-hasnt-been-given-chance-to-consult-on-changes-to-bill "Share by Email") +- [Read Later](https://www.winnipegfreepress.com/uncategorized/2024/05/06/# "Bookmark") + +[Report Error](https://www.winnipegfreepress.com/fact-check?fact_check_title=Alberta%20Municipalities%20said%20it%20hasn%E2%80%99t%20been%20given%20chance%20to%20consult%20on%20changes%20to%20bill) [Submit a Tip](https://www.winnipegfreepress.com/newstips?news_tip_title=Alberta%20Municipalities%20said%20it%20hasn%E2%80%99t%20been%20given%20chance%20to%20consult%20on%20changes%20to%20bill) \ No newline at end of file diff --git a/mkdocs/docs/archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate.md b/mkdocs/docs/archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate.md new file mode 100644 index 0000000..cfa3962 --- /dev/null +++ b/mkdocs/docs/archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate.md @@ -0,0 +1,80 @@ +--- +title: "Smith pushes ‘Alberta Accord,’ defends citizen referendums amid separation debate" +source: "https://westcentralonline.com/articles/smith-pushes-alberta-accord-defends-citizen-referendums-amid-separation-debate" +author: + - "[[WestCentralOnline]]" +published: +created: 2025-05-29 +description: "Premier Danielle Smith says her government is pursuing a stronger role for Alberta within Confederation and launching negotiations with Ottawa on a new “Alberta Accord” — while defending recent changes that would make it easier for citizens to trigger a referendum, including on the province’s possible separation from Canada. In back-to-back media appearances Monday and Tuesday, Smith struck a firm but conciliatory tone, saying she is hopeful new Prime Minister Mark Carney will work with Alberta to address long-standing grievances over energy policy, resource access, and federal oversight. “These conversations are a positive first step,” Smith said Monday, following her first face-to-face meeting with Carney. “But it will take tremendous effort and cooperation to repair the damage to Alberta’s economy caused in the last 10 years by Ottawa’s destructive anti-resource agenda.” googletag.cmd.push(function() { if($(document).width()<900) { s = googletag.defineSlot('/50748803/wco-all-bigbox', [300, 250], 'div-gpt-1632277500385-bbm1'); s.setTargeting('URL', [window.location.pathname]); s.setTargeting('position', [1632277500385]) s.addService(googletag.pubads()); googletag.pubads().refresh([s], {changeCorrelator: false}); } }); The Alberta government is establishing a formal negotiating team and plans to consult Albertans over the next six months on constitutional reforms. Smith said demands include guaranteed tidewater access on all three coasts for Alberta’s energy products, the repeal of federal laws like Bill C-69 and clean electricity regulations, and per-capita federal transfers equal to those received by Ontario, Quebec and British Columbia. Smith also confirmed the creation of an “Alberta Next” panel to explore long-term economic and constitutional options — potentially leading to a referendum in 2026. But the premier repeatedly denied that her government is pushing Alberta toward separation. Instead, she defended Bill 54, which lowers the threshold for citizen-led referendums, saying it empowers grassroots democracy without promoting secession. googletag.cmd.push(function() { if($(document).width()<900) { s = googletag.defineSlot('/50748803/wco-all-bigbox', [300, 250], 'div-gpt-1632277500385-bbm2'); s.setTargeting('URL', [window.location.pathname]); s.setTargeting('position', [1632277500385]) s.addService(googletag.pubads()); googletag.pubads().refresh([s], {changeCorrelator: false}); } }); “I don’t have a mandate, and my party doesn’t support [separation],” she said. “A citizen-initiated referendum would be, by definition, initiated by citizens. All I’ve said is I will honour the process.” The comments come as frustration in Alberta continues to simmer in the wake of last month’s federal election, with Ottawa’s climate and energy policies cited by many Albertans as evidence of chronic regional alienation. Smith acknowledged that public anger is real. “There’s a lot of anger after the last election — a lot of anger at the way we’ve been treated for the last 10 years,” she said. “I believe in free speech. Citizens have a right to express their opinion… It’s my job to make sure that debate is respectful.” Smith was pressed repeatedly about whether she would honour the results of a hypothetical referendum on separation. She remained non-committal. googletag.cmd.push(function() { if($(document).width()<900) { s = googletag.defineSlot('/50748803/wco-all-bigbox', [300, 250], 'div-gpt-1632277500385-bbm3'); s.setTargeting('URL', [window.location.pathname]); s.setTargeting('position', [1632277500385]) s.addService(googletag.pubads()); googletag.pubads().refresh([s], {changeCorrelator: false}); } }); “Until I see an actual question with 177,000 signatures of Albertans that are supportive of it, it is difficult for me to know what that looks like,” she said Tuesday. Smith said she believes support for separation sits at around 30 per cent but hopes that number will drop as negotiations with Ottawa proceed. During her Monday remarks, Smith emphasized that Alberta is seeking more autonomy over areas such as immigration and agriculture, citing Section 95 of the Constitution as grounds for provincial authority. “These are a couple of things that we would put to the people,” she said, adding that Quebec’s model of fiscal independence may offer a path forward. Critics have raised alarms about Alberta’s embrace of California-style citizen initiatives, warning that the model could create policy instability. Smith dismissed those concerns. googletag.cmd.push(function() { if($(document).width()<900) { s = googletag.defineSlot('/50748803/wco-all-bigbox', [300, 250], 'div-gpt-1632277500385-bbm4'); s.setTargeting('URL', [window.location.pathname]); s.setTargeting('position', [1632277500385]) s.addService(googletag.pubads()); googletag.pubads().refresh([s], {changeCorrelator: false}); } }); “Albertans don’t want to vote on every little thing,” she said. “But they might want to vote on some big things.” She also brushed off a warning from Ontario Premier Doug Ford, who recently criticized separatist rhetoric. Smith said she and Ford have a “great friendship,” but that Alberta’s issues differ from Ontario’s. “He’s the premier of Ontario. I’m the premier of Alberta,” she said. “I don’t tell him how he should run his province, and I would hope he doesn’t tell me how to run mine.” The growing debate around referendums has drawn opposition from First Nations across Alberta and Canada. Chiefs from Treaties 6, 7, 8 and 10 were set to speak out against any independence vote just hours after Smith’s Monday remarks. Asked whether separation could override treaty obligations, Smith said treaty and Indigenous rights would remain fully respected regardless of Alberta’s constitutional status. googletag.cmd.push(function() { if($(document).width()<900) { s = googletag.defineSlot('/50748803/wco-all-bigbox', [300, 250], 'div-gpt-1632277500385-bbm5'); s.setTargeting('URL', [window.location.pathname]); s.setTargeting('position', [1632277500385]) s.addService(googletag.pubads()); googletag.pubads().refresh([s], {changeCorrelator: false}); } }); “You can’t vote away treaty rights. You can’t vote away Indigenous rights,” she said. “We accept and respect that [Indigenous nations] are sovereign jurisdictions in their own right.” Despite her reassurances, Smith offered little clarity on how a binding referendum — or independence — would function within Canada’s legal framework. “I won’t prejudge what citizens might want to put on the table,” she said. “But I’m going to do everything in my power to negotiate a fair deal for Alberta.” Smith’s appearance also touched on a growing conflict-of-interest controversy involving Justice Minister Mickey Amery, whose family ties to businessman Sam Rash have drawn scrutiny. Rash is currently involved in a lawsuit and multiple investigations related to Alberta Health Services. googletag.cmd.push(function() { if($(document).width()<900) { s = googletag.defineSlot('/50748803/wco-all-bigbox', [300, 250], 'div-gpt-1632277500385-bbm6'); s.setTargeting('URL', [window.location.pathname]); s.setTargeting('position', [1632277500385]) s.addService(googletag.pubads()); googletag.pubads().refresh([s], {changeCorrelator: false}); } }); Smith dismissed the concerns outright. “Should he divorce his wife so he doesn’t have the relationship with the cousin anymore?” she said. “Minister Mickey Amery is in no conflict of interest.” Amery, she said, has not made any decisions that would affect Rash and remains compliant with ethics rules. Asked if she would discipline UCP MLAs who express support for separation, Smith demurred, saying the party was founded on a commitment to Canadian unity — but added that differing views within caucus are inevitable. “All I can do is try to convince people my view is right — that it’s worth fighting for, it’s worth doing the negotiation,” she said. The premier wrapped up her comments Tuesday by reiterating her government’s priorities: negotiation, consultation, and economic empowerment within Canada. googletag.cmd.push(function() { if($(document).width()<900) { s = googletag.defineSlot('/50748803/wco-all-bigbox', [300, 250], 'div-gpt-1632277500385-bbm7'); s.setTargeting('URL', [window.location.pathname]); s.setTargeting('position', [1632277500385]) s.addService(googletag.pubads()); googletag.pubads().refresh([s], {changeCorrelator: false}); } }); “There is no referendum question. There is no petition campaign,” she said. “So I don’t have answers to those questions because, until we see an actual question and an active petition, it really is just hypothetical.”" +tags: + - "clippings" +--- +[Smith pushes ‘Alberta Accord,’ defends citizen referendums amid separation debate](https://westcentralonline.com/articles/smith-pushes-alberta-accord-defends-citizen-referendums-amid-separation-debate) + +![](https://dht7q8fif4gks.cloudfront.net/2025-05/Screenshot%202025-05-06%20144846.jpg) + +Premier Danielle Smith says her government is pursuing a stronger role for Alberta within Confederation and launching negotiations with Ottawa on a new “Alberta Accord” — while defending recent changes that would make it easier for citizens to trigger a referendum, including on the province’s possible separation from Canada. + +In back-to-back media appearances Monday and Tuesday, Smith struck a firm but conciliatory tone, saying she is hopeful new Prime Minister Mark Carney will work with Alberta to address long-standing grievances over energy policy, resource access, and federal oversight. + +“These conversations are a positive first step,” Smith said Monday, following her first face-to-face meeting with Carney. “But it will take tremendous effort and cooperation to repair the damage to Alberta’s economy caused in the last 10 years by Ottawa’s destructive anti-resource agenda.” + +The Alberta government is establishing a formal negotiating team and plans to consult Albertans over the next six months on constitutional reforms. Smith said demands include guaranteed tidewater access on all three coasts for Alberta’s energy products, the repeal of federal laws like Bill C-69 and clean electricity regulations, and per-capita federal transfers equal to those received by Ontario, Quebec and British Columbia. + +Smith also confirmed the creation of an “Alberta Next” panel to explore long-term economic and constitutional options — potentially leading to a referendum in 2026. + +But the premier repeatedly denied that her government is pushing Alberta toward separation. Instead, she defended Bill 54, which lowers the threshold for citizen-led referendums, saying it empowers grassroots democracy without promoting secession. + +“I don’t have a mandate, and my party doesn’t support \[separation\],” she said. “A citizen-initiated referendum would be, by definition, initiated by citizens. All I’ve said is I will honour the process.” + +The comments come as frustration in Alberta continues to simmer in the wake of last month’s federal election, with Ottawa’s climate and energy policies cited by many Albertans as evidence of chronic regional alienation. Smith acknowledged that public anger is real. + +“There’s a lot of anger after the last election — a lot of anger at the way we’ve been treated for the last 10 years,” she said. “I believe in free speech. Citizens have a right to express their opinion… It’s my job to make sure that debate is respectful.” + +Smith was pressed repeatedly about whether she would honour the results of a hypothetical referendum on separation. She remained non-committal. + +“Until I see an actual question with 177,000 signatures of Albertans that are supportive of it, it is difficult for me to know what that looks like,” she said Tuesday. + +Smith said she believes support for separation sits at around 30 per cent but hopes that number will drop as negotiations with Ottawa proceed. + +During her Monday remarks, Smith emphasized that Alberta is seeking more autonomy over areas such as immigration and agriculture, citing Section 95 of the Constitution as grounds for provincial authority. + +“These are a couple of things that we would put to the people,” she said, adding that Quebec’s model of fiscal independence may offer a path forward. + +Critics have raised alarms about Alberta’s embrace of California-style citizen initiatives, warning that the model could create policy instability. Smith dismissed those concerns. + +“Albertans don’t want to vote on every little thing,” she said. “But they might want to vote on some big things.” + +She also brushed off a warning from Ontario Premier Doug Ford, who recently criticized separatist rhetoric. Smith said she and Ford have a “great friendship,” but that Alberta’s issues differ from Ontario’s. + +“He’s the premier of Ontario. I’m the premier of Alberta,” she said. “I don’t tell him how he should run his province, and I would hope he doesn’t tell me how to run mine.” + +The growing debate around referendums has drawn opposition from First Nations across Alberta and Canada. Chiefs from Treaties 6, 7, 8 and 10 were set to speak out against any independence vote just hours after Smith’s Monday remarks. + +Asked whether separation could override treaty obligations, Smith said treaty and Indigenous rights would remain fully respected regardless of Alberta’s constitutional status. + +“You can’t vote away treaty rights. You can’t vote away Indigenous rights,” she said. “We accept and respect that \[Indigenous nations\] are sovereign jurisdictions in their own right.” + +Despite her reassurances, Smith offered little clarity on how a binding referendum — or independence — would function within Canada’s legal framework. + +“I won’t prejudge what citizens might want to put on the table,” she said. “But I’m going to do everything in my power to negotiate a fair deal for Alberta.” + +Smith’s appearance also touched on a growing conflict-of-interest controversy involving Justice Minister Mickey Amery, whose family ties to businessman Sam Rash have drawn scrutiny. Rash is currently involved in a lawsuit and multiple investigations related to Alberta Health Services. + +Smith dismissed the concerns outright. + +“Should he divorce his wife so he doesn’t have the relationship with the cousin anymore?” she said. “Minister Mickey Amery is in no conflict of interest.” + +Amery, she said, has not made any decisions that would affect Rash and remains compliant with ethics rules. + +Asked if she would discipline UCP MLAs who express support for separation, Smith demurred, saying the party was founded on a commitment to Canadian unity — but added that differing views within caucus are inevitable. + +“All I can do is try to convince people my view is right — that it’s worth fighting for, it’s worth doing the negotiation,” she said. + +The premier wrapped up her comments Tuesday by reiterating her government’s priorities: negotiation, consultation, and economic empowerment within Canada. + +“There is no referendum question. There is no petition campaign,” she said. “So I don’t have answers to those questions because, until we see an actual question and an active petition, it really is just hypothetical.” + +- Events +- Jobs +- Buy & Sell \ No newline at end of file diff --git a/mkdocs/docs/archive/Smiths Electoral Reforms Are Straight from Trumps Playbook.md b/mkdocs/docs/archive/Smiths Electoral Reforms Are Straight from Trumps Playbook.md new file mode 100644 index 0000000..55ccc1b --- /dev/null +++ b/mkdocs/docs/archive/Smiths Electoral Reforms Are Straight from Trumps Playbook.md @@ -0,0 +1,114 @@ +--- +title: "Smith’s Electoral ‘Reforms’ Are Straight from Trump’s Playbook" +source: "https://thetyee.ca/Analysis/2025/04/30/Danielle-Smith-Electoral-Reforms-Trump-Playbook/" +author: + - "[[Jared Wesley]]" +published: 2025-04-30 +created: 2025-05-29 +description: "It’s no accident the changes were announced as attention was focused on the federal election." +tags: + - "clippings" +--- +[Smith’s Electoral ‘Reforms’ Are Straight from Trump’s Playbook](https://thetyee.ca/Analysis/2025/04/30/Danielle-Smith-Electoral-Reforms-Trump-Playbook/) + +![Danielle Smith stands with hands clasped and listens to Donald Trump in an ornate setting.](https://thetyee.ca/Analysis/2025/04/30/TrumpSmith.jpg) + +Alberta Premier Danielle Smith’s moves to reduce voting rights and allow big corporate donations are lifted from the tactics of US Republicans. Photo via X. + +The United Conservative Party introduced [sweeping changes](https://edmontonjournal.com/news/politics/alberta-bill-seeks-to-reintroduce-union-corporate-contributions-ban-tabulators-and-lower-recall-threshold) to Alberta’s election laws Tuesday. + +While billed as technical updates to restore faith in and improve access to elections in Alberta, they do precisely the opposite. + +In no uncertain terms: the reforms mirror tactics employed by Donald Trump’s Republican Party in the U.S. + +Viewed individually, each measure may appear modest. Taken together — and considered alongside their political timing — they mark another step in the [Americanization](https://thetyee.ca/Analysis/2024/10/28/Dangerous-Americanization-Alberta-Democracy/) of Alberta’s democratic institutions. And the latest in a [long list](https://thetyee.ca/Opinion/2024/05/06/Why-UCP-Is-Threat-Democracy/) of [democratic transgressions](https://thetyee.ca/Analysis/2025/02/06/Problem-Populist-Politicians/) in this province. + +**Reintroducing union and corporate contributions** + +The UCP’s bill removes existing restrictions on union and corporate donations to parties, candidates, leadership contestants and political action committees during the election period. + +This move revives the influence of well-funded third parties, a tactic Republicans perfected after the U.S. Supreme Court’s Citizens United decision. By channelling large sums through parties and PACs, political actors can effectively circumvent party donation limits while maintaining plausible deniability. + +In Alberta, the reintroduction of big money into elections risks further skewing the political process toward the interests of the wealthy, while ordinary citizens struggle to be heard. For these reasons, Albertans are [overwhelmingly opposed](https://www.commongroundpolitics.ca/albertans-views-abut-money-in-politics) to such measures. + +**Banning vote tabulators** + +The bill prohibits the use of vote-counting machines, or tabulators, across the province. While automation can improve efficiency (cutting down on the long wait times on election night that the UCP disparaged in restricting special ballots), the political context surrounding this change cannot be ignored. + +Trump Republicans have spent years undermining public confidence in election technology, falsely alleging that machines were rigged or hacked to steal the 2020 election. These manufactured doubts fuelled attacks on electoral legitimacy in the United States. + +Absent a comprehensive strategy for transparency and public education, Alberta’s banning of tabulators risks creating similar opportunities for conspiracy theories to take root. + +In short, this measure decreases efficiency and reinforces unfounded doubts about the integrity of our elections — precisely the opposite of what the UCP purports to achieve through this bill. + +**Lowering recall petition thresholds** + +The bill reduces the number of signatures required to initiate recall petitions against MLAs and municipal leaders. + +While pitched as a mechanism for greater accountability, experience from the U.S. suggests otherwise. Lower thresholds facilitate the weaponization of recall petitions by organized political groups seeking to destabilize elected officials over ideological disputes, not misconduct. + +In Republican-led states, such tactics have created a chilling effect, discouraging politicians from making difficult but necessary decisions for fear of constant political retaliation. + +**Restricting the vote** + +The UCP’s bill eliminates “vote anywhere” provisions, restricts special ballots and introduces additional identification requirements for voters. + +All three measures make voting more difficult, reversing decades of progress across Canada to improve voter equality. + +As research — including [our own](https://theconversation.com/albertas-voter-id-law-is-a-solution-for-a-problem-that-doesnt-exist-231130) — has shown, voter ID laws disproportionately affect younger and older, Indigenous, disabled, rural and low-income voters. These groups are less likely to have government-issued photo ID, and new requirements can create barriers that depress turnout. + +Despite the [many myths](https://policyoptions.irpp.org/magazines/august-2024/voter-id-canada-elections/) spread by Trump Republicans, there is no evidence of widespread voter fraud in the U.S. + +The same is true in Alberta. Like their Republican counterparts, the UCP is solving a problem that does not exist, with the likely consequence (and perhaps intent) of reducing participation among demographics less likely to support them. + +This amounts to the government choosing its voters, not vice versa. + +All of these measures feed conspiracy narratives surrounding election integrity, once again sowing baseless doubt in the sanctity of proven election processes. + +**Amending the Referendum Act** + +The UCP is lowering the barriers to holding province-wide referendums, a key demand from separatist factions within the party’s base. + +In the U.S., Trump’s allies have increasingly used referenda to pursue partisan objectives, bypassing legislative scrutiny. In Alberta, easier referendums open the door to populist campaigns on complex issues including, potentially, a vote on Alberta’s secession or joining the U.S. + +At a moment when the premier has been accused of stoking separatist sentiment, loosening these requirements represents a concession to radical elements that seek to destabilize Canadian federalism. If she is the federalist she claims to be, Smith should at least consider reviewing the [trials and tribulations](https://www.cbc.ca/radio/thecurrent/the-current-for-sept-30-2019-1.5300478/david-cameron-regrets-losing-brexit-vote-but-says-referendum-was-always-inevitable-1.5300480) of David Cameron, the unwitting architect of Brexit. + +**Political timing and strategic context** + +The timing of this bill is significant and far from coincidental. + +Smith introduced these controversial reforms the day after the federal election hoping to catch the media off-guard and hoping few of us would notice given the attention on Ottawa. + +That is scarcely a good-faith context for debating the most consequential set of reforms to election laws in Alberta’s history. + +Had the reforms been tabled later, they would have drawn national attention and hurt Pierre Poilievre’s federal Conservatives by reinforcing narratives about Trumpism within the conservative movement. + +Introducing the changes now minimizes that risk while placating UCP separatists and stoking the national unity crisis Smith and former Reform leader Preston Manning promised would follow a Liberal victory. + +**Trumpism at its clearest** + +The UCP’s proposed changes do not merely tweak administrative processes. + +And they most certainly do not enhance accessibility or integrity in our electoral processes. They do precisely the opposite. + +The UCP’s reforms reflect a deeper shift toward the strategies pioneered by Trump Republicans: leveraging dark money, undermining trust in elections, weaponizing recalls, disenfranchising opponents, suppressing voter turnout and empowering radical populist movements. + +This convergence is not accidental. It is a conscious political strategy. + +Whether Alberta follows the full arc of the Trump example remains to be seen. But today’s legislation makes clear that the risk is no longer hypothetical. It is real, present and growing. And the further it progresses, the harder it will be for concerned Albertans to stop it. + +Read more: [Alberta](https://thetyee.ca/Topic/Alberta/) + +### The Barometer + +What Writing Do You Do in Your Spare Time? + +- Journal writing +- Letters to friends +- Memoirs +- Fiction +- Poetry + +- Tell us more… + +[Take this week’s poll](https://thetyee.ca/Polls/2025/04/25/Writing-Spare-Time/) \ No newline at end of file diff --git a/mkdocs/docs/archive/Strengthening democracy Renforcer la démocratie.md b/mkdocs/docs/archive/Strengthening democracy Renforcer la démocratie.md new file mode 100644 index 0000000..9ef92be --- /dev/null +++ b/mkdocs/docs/archive/Strengthening democracy Renforcer la démocratie.md @@ -0,0 +1,125 @@ +--- +title: "Strengthening democracy | Renforcer la démocratie" +source: "https://www.alberta.ca/release.cfm?xID=932071DE8A863-A23D-5F75-F0C967208F7B4ABB" +author: + - "[[Government of Alberta]]" +published: 2025-04-29 +created: 2025-05-29 +description: "Alberta’s government is introducing changes to protect democracy, deliver fair and open elections and increase confidence in every vote cast." +tags: + - "clippings" +--- +[Strengthening democracy | Renforcer la démocratie](https://www.alberta.ca/release.cfm?xID=932071DE8A863-A23D-5F75-F0C967208F7B4ABB) + +![](https://www.youtube.com/watch?v=4Lg4ulBtDZU) + +Voting gives Albertans a voice in shaping the future of our province. Direct democracy processes like referendums, recall and citizen initiative petitions provide further opportunities for Albertans to be heard and express their views. The proposed *Election Statutes Amendment Act, 2025,* would make Alberta’s elections and other democratic processes more open, secure and accessible. + +> “I believe that democracy thrives when people trust the process. These changes would make elections at every level in Alberta more accessible and transparent while protecting their integrity, ensuring confidence in the outcomes. We are also creating more opportunities for Albertans to be involved in direct democracy and to have their say on issues that matter to them.” + +Fair and free elections are the foundation of democracy, and Alberta’s government is taking action to protect them. The proposed changes include: + +- Banning the use of electronic tabulators and other automated voting machines, requiring all ballots to be counted by hand to protect election integrity. +- Eliminating vouching at voting stations to strengthen identification and verification processes. +- Requiring unofficial vote counts to be completed within 12 hours of polls closing to provide timely, reliable results. +- Voters being required to cast their ballot in their constituency of residence or by requesting a special ballot. +- Expanding access to special ballots, allowing any voter to request one without needing to provide a reason while protecting integrity by requiring voters to personally request their special ballot (with exceptions for those needing assistance due to a disability). +- Updating the *Recall Act* to make it easier for Albertans to hold elected officials accountable by lowering the signature threshold and extending the timeframe to collect signatures. +- Improving the *Citizen Initiative Act* process by setting the threshold for all successful petitions at 10 per cent of eligible voters who participated in the last general election. + +> “Albertans rightly expect their government to make sure democratic processes are fair and transparent with accurate and timely results. These proposed amendments would deliver on my mandate to review and make changes to strengthen public trust in the integrity of our elections.” + +Additional amendments under the *Election Statutes Amendment Act, 2025* would: + +- Allow corporate and union contributions for provincial elections while maintaining transparency and accountability through existing financial disclosure requirements. +- Improve access to voting for First Nations and Métis Settlements during referendums and Senate elections. +- Enhance emergency response provisions for voting disruptions during referendums and Senate elections. + +These changes would help ensure that Alberta’s democratic processes are open, secure, and reflective of the will of Albertans, while creating new opportunities for greater public participation. + +## Quick facts + +- The *Election Act* governs the process for provincial elections, by-elections and plebiscites in Alberta and creates the office of the chief electoral officer, the head of Elections Alberta. +- The *Election Finances and Contributions Disclosure Act* governs the financing of provincial elections, Senate elections and referendums, including rules for registered political parties, constituency associations, candidates, leadership contestants and third parties. +- The *Alberta Senate Election Act* governs the process for Senate elections in Alberta. +- The *Referendum Act* governs the process for referendums in Alberta. +- The *Recall Act* outlines the process for Albertans to initiate the recall of an elected MLA. +- The *Citizen Initiative Act* allows eligible voters in Alberta to propose legislative or policy initiatives, constitutional referendum questions and establishes rules for advertising and spending. + +## Related information + +- [Improving consistency and fairness in Alberta’s democratic processes](http://www.alberta.ca/improving-consistency-fairness-albertas-democratic-processes) +- [Bill 54: Election Statutes Amendment Act, 2025](https://www.assembly.ab.ca/assembly-business/bills/bill?billinfoid=12082&from=bills) +- [Election Statutes Amendment Act, 2025 fact sheet](https://www.alberta.ca/system/files/jus-bill-54-election-statutes-amendment-act-2025-fact-sheet.pdf) + +## Related news + +- [Strengthening Alberta’s local elections](https://www.alberta.ca/release.cfm?xID=90230E56EB3B1-B992-FC39-DDC3D13933898D5B) (April 25, 2024) +- [Accountable and transparent local elections](https://www.alberta.ca/release.cfm?xID=9118441E43C1D-DBAB-B706-8092BEA0836EBE16) (October 18, 2024) + +## Multimedia + +- [Watch the news conference](https://www.youtube.com/watch?v=4Lg4ulBtDZU) +- [Listen to the news conference](https://soundcloud.com/your-alberta/strengthening-albertas-elections-april-29-2025) + +--- + +### Afin de préserver la démocratie, le gouvernement de l’Alberta propose des modifications visant à garantir des élections justes et ouvertes, tout en accroissant la confiance envers le processus électoral. + +En votant, les Albertaines et les Albertains participent activement à façonner l’avenir de la province. Les processus de démocratie directe, tels que les référendums, les révocations et les pétitions d’initiative citoyenne, offrent à la population d’autres occasions de se faire entendre et d’exprimer leurs opinions. Le projet de loi *Election Statutes Amendment Act, 2025* rendrait les élections et les autres processus démocratiques de l’Alberta plus ouverts, plus sûrs et plus accessibles. + +> « Je crois que la démocratie prospère lorsque les citoyens font confiance au processus. Ces modifications permettraient d’améliorer l’accessibilité et la transparence des élections en Alberta, quel que soit le niveau de gouvernement, tout en protégeant leur intégrité et en garantissant la confiance envers les résultats. Nous créons également davantage d’occasions pour que la population albertaine participe à la démocratie directe et puisse s’exprimer sur les enjeux qui la concernent. » + +Des élections libres et équitables sont le fondement de la démocratie, et le gouvernement de l’Alberta prend des mesures pour les protéger. Voici les modifications proposées: + +- interdire l’utilisation de tabulateurs électroniques et d’autres machines de vote automatisées, exigeant un dépouillement manuel pour préserver l’intégrité du scrutin; +- abolir le recours à un répondant dans les bureaux de vote afin de renforcer les processus d’identification et de vérification; +- exiger de compléter le dépouillement non officiel dans les 12 heures suivant la fermeture des bureaux de vote pour garantir des résultats fiables et en temps opportun; +- exiger que les électeurs votent dans leur propre circonscription ou par bulletin de vote spécial; +- élargir l’accès aux bulletins de vote spéciaux, en permettant à tout électeur d’en demander un sans avoir à fournir de raison, tout en protégeant l’intégrité en exigeant que les électeurs demandent personnellement leur bulletin de vote spécial (des exceptions sont prévues pour les personnes en situation de handicap); +- mettre à jour la *Recall Act* afin de permettre aux Albertaines et aux Albertains de tenir les élus responsables en abaissant le seuil du nombre de signatures et en prolongeant le délai de collecte des signatures; +- améliorer le processus de la *Citizen Initiative Act* en fixant le seuil pour toutes les pétitions retenues à 10 % des électeurs admissibles ayant pris part aux dernières élections générales. + +> « La population albertaine s’attend légitimement à ce que le gouvernement garantisse que les processus démocratiques soient justes, transparents, et fournissent des résultats précis et rapides. Ces modifications proposées me permettraient de remplir mon mandat consistant à examiner et à apporter des changements pour renforcer la confiance du public dans l’intégrité de nos élections. » + +Des modifications supplémentaires en vertu de l’ *Election Statutes Amendment Act, 2025* permettraient: + +- d’autoriser les contributions des entreprises et des syndicats aux élections provinciales tout en maintenant la transparence et la responsabilité grâce aux exigences actuelles en matière de divulgation financière; +- d’améliorer l’accès au vote pour les Premières Nations et les établissements métis lors des référendums et des élections sénatoriales; +- de renforcer les dispositions relatives aux interventions d’urgence en cas de perturbations électorales lors des référendums et des élections sénatoriales. + +Ces modifications contribueraient à garantir que les processus démocratiques de l’Alberta sont ouverts, sûrs et reflètent la volonté de la population, tout en créant de nouvelles occasions de participation publique accrue. + +## Faits en bref + +- L’ *Election Act* régit le processus des élections provinciales, des élections partielles et des plébiscites en Alberta et crée le poste de directeur général des élections, à la tête d’Élections Alberta. +- L’ *Election Finances and Contributions Disclosure Act* régit le financement des élections provinciales, des élections sénatoriales et des référendums, y compris les règles applicables aux partis politiques enregistrés, aux associations de circonscription, aux candidats, aux candidats à la direction et aux tiers. +- L’ *Alberta Senate Election Act* régit le processus des élections sénatoriales en Alberta. +- La *Referendum Act* régit le processus des référendums en Alberta. +- La *Recall Act* décrit le processus permettant aux Albertaines et aux Albertains de mettre en œuvre la révocation d’un député élu. +- La *Citizen Initiative Act* permet aux électeurs admissibles de l’Alberta de proposer des initiatives législatives ou politiques, des questions de référendum constitutionnel, et établit des règles en matière de publicité et de dépenses. + +## Renseignements connexes + +- [Améliorer la cohérence et l’équité des processus démocratiques de l’Alberta](http://www.alberta.ca/improving-consistency-fairness-albertas-democratic-processes) (en anglais seulement) +- [Projet de loi 54: Loi de 2025 modifiant les lois électorales](https://can01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.assembly.ab.ca%2Fassembly-business%2Fbills%2Fbill%3Fbillinfoid%3D12082%26from%3Dbills&data=05%7C02%7CBin.Wu%40gov.ab.ca%7C9fc3ae31dc8a4b0f4bee08dd87618bd8%7C2bb51c06af9b42c58bf53c3b7b10850b%7C0%7C0%7C638815575226263381%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=OCyrJ8l%2FocD94S%2BM8UL1VTypLTzM1k4GRbHnfiok1n0%3D&reserved=0) (en anglais seulement) +- [Fiche d’information sur la Loi de 2025 modifiant les lois électorales](https://www.alberta.ca/system/files/jus-bill-54-election-statutes-amendment-act-2025-fact-sheet.pdf) (en anglais seulement) + +## Nouvelles connexes + +- [Renforcer les élections municipales en Alberta](https://www.alberta.ca/release.cfm?xID=90230E56EB3B1-B992-FC39-DDC3D13933898D5B) (25 avril 2024) (en anglais seulement) +- [Des élections municipales responsables et transparentes](https://www.alberta.ca/release.cfm?xID=9118441E43C1D-DBAB-B706-8092BEA0836EBE16) (18 octobre 2024) (en anglais seulement) + +## Multimédia + +- [Visionnez la conférence de presse](https://can01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D4Lg4ulBtDZU&data=05%7C02%7CBin.Wu%40gov.ab.ca%7C9fc3ae31dc8a4b0f4bee08dd87618bd8%7C2bb51c06af9b42c58bf53c3b7b10850b%7C0%7C0%7C638815575226293235%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=QEMpJrZNIsiKZJykAyzjSrqHSHf%2FGan2RVTbPeERlbk%3D&reserved=0) (en anglais seulement) +- [Écoutez la conférence de presse](https://can01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fsoundcloud.com%2Fyour-alberta%2Fstrengthening-albertas-elections-april-29-2025&data=05%7C02%7CBin.Wu%40gov.ab.ca%7C9fc3ae31dc8a4b0f4bee08dd87618bd8%7C2bb51c06af9b42c58bf53c3b7b10850b%7C0%7C0%7C638815575226307515%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=FQ%2Fl6%2F1nzrXiUQPTTHhXKgxA5SxFV8gCAjvYSe7vhCo%3D&reserved=0) (en anglais seulement) + +## Translations + +- [Arabic](https://www.alberta.ca/system/files/news-strengthening-democracy-20250429-langar.pdf "Read the Arabic version") +- [Simplified Chinese](https://www.alberta.ca/system/files/news-strengthening-democracy-20250429-langsc.pdf "Read the Simplified Chinese version") +- [Traditional Chinese](https://www.alberta.ca/system/files/news-strengthening-democracy-20250429-langtc.pdf "Read the Traditional Chinese version") +- [Punjabi](https://www.alberta.ca/system/files/news-strengthening-democracy-20250429-langpa.pdf "Read the Punjabi version") +- [Spanish](https://www.alberta.ca/system/files/news-strengthening-democracy-20250429-langes.pdf "Read the Spanish version") +- [Ukrainian](https://www.alberta.ca/system/files/news-strengthening-democracy-20250429-languk.pdf "Read the Ukrainian version") \ No newline at end of file diff --git a/mkdocs/docs/archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News.md b/mkdocs/docs/archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News.md new file mode 100644 index 0000000..e1656e3 --- /dev/null +++ b/mkdocs/docs/archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News.md @@ -0,0 +1,81 @@ +--- +title: "The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider | CBC News" +source: "https://www.cbc.ca/news/canada/edmonton/the-alberta-government-banned-electronic-vote-tabulators-municipalities-want-it-to-reconsider-1.7331404" +author: + - "[[Emily Rae Pasiuk]]" +published: 2024-09-24 +created: 2025-05-29 +description: "The Alberta government banned the use of electronic tabulators in municipal elections when it passed Bill 20 in May 2024. It's a method that municipalities have used for decades, saying it has saved them both time and money." +tags: + - "clippings" +--- +[The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider | CBC News](https://www.cbc.ca/news/canada/edmonton/the-alberta-government-banned-electronic-vote-tabulators-municipalities-want-it-to-reconsider-1.7331404) + +[Edmonton](https://www.cbc.ca/news/canada/edmonton) + +## The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider + +The Alberta government banned the use of electronic tabulators in municipal elections when it passed Bill 20 in May 2024. It's a method that municipalities have used for decades, saying it has saved them both time and money. + +## Province says the change is about trust; some municipalities worry about cost + +![A voter enters his paper ballot into a tabulator machine at an advanced polling station in Sherwood Park on Tuesday. ](https://i.cbc.ca/1.6854498.1685032944!/fileImage/httpImage/image.jpg_gen/derivatives/16x9_1180/vote-tabulator.jpg?im=Resize%3D780) + +A voter enters his paper ballot into a tabulator machine at an advanced polling station in Sherwood Park in the 2023 provincial election. (CBC) + +The Alberta government banned the use of electronic tabulators in municipal elections when it passed Bill 20 in May of this year. It's a method that municipalities have used for decades, saying it has saved them time and money. + +Alberta Municipalities wants the province to reconsider. + +A resolution to be put forward at the organization's annual convention this week in Red Deer calls for tabulators to be permitted as an option "to ensure accurate, cost-effective and timely results for Albertan voters." + +St. Albert Mayor Cathy Heron, past-president of Alberta Municipalities, told CBC Radio's *[Edmonton AM](https://www.cbc.ca/listen/live-radio/1-17-edmonton-am)* that she can't remember a time when St. Albert wasn't using tabulators. + +"They provided really timely, efficient, and quite honestly, accurate counting of our residents' votes," Heron said. + +"Now we're going to get the exact opposite. We're going to get less timely and less accurate and much more costly counting of the votes." + +***WATCH | Municipalities pushing back against ban on electronic vote tabulators:***![](https://i.cbc.ca/ais/a433d0cc-f588-491e-8e6b-3adcfc66c59c,1727144630629/full/max/0/default.jpg?im=Crop%2Crect%3D%280%2C0%2C1872%2C1053%29%3BResize%3D620) + +Municipalities pushing back against ban on electronic vote tabulators 8 months ago Duration 1:53 + +In an emailed statement, Heather Jenkins, press secretary for Minister of Municipal Affairs Ric McIver, said the changes were made to give municipalities enough time to prepare for the next municipal general elections, scheduled for Oct. 20, 2025. + +"It is important for Albertans to feel they can trust the methods and results of local elections and requiring all ballots to be counted by hand will bolster their trust in the election outcome, which is better for democracy," Jenkins wrote. + +The Alberta Municipalities resolution says in part that some municipalities haven't used manual vote counting in years. Votes counted via a tabulator are subject to a post-election review process that verifies the results. + +The risk in "adapting alternative vote-counting processes without precedent or corporate expertise" increases the likelihood of mistakes, delayed results, and cost escalation, it says. + +"I have spoken to Minister McIver... at length about this, and he says that it is mainly because there is a certain part of the population that have spoken to him directly that indicated that they don't trust the machines," Heron said. + +"He's only going on a few anecdotal suspicions. I would happily support this if there was good, solid data and good, solid surveys of Albertans, but that doesn't exist." + +- [Alberta government promises amendments in wake of Bill 20 backlash](https://www.cbc.ca/news/canada/edmonton/alberta-government-promises-amendments-in-wake-of-bill-20-backlash-1.7191994) +- [Tabulators counting votes in Alberta advance polling](https://www.cbc.ca/news/canada/edmonton/tabulators-counting-votes-in-alberta-advance-polling-1.6854439) + +The City of Red Deer looked at the financial impact the change might have. In a report, the city's administration found the changes might cost almost $1.5 million for the next election — around 3½ times more than in past general elections. + +One section of the Red Deer report, which came out earlier this month, assumed that with 30 per cent voter turnout and one provincial referendum question, there would be about 90,000 ballots to count. + +"It will take four workers 37 days (counting 24/7) to hand count 90,000 ballots," the report said. + +"To complete the count in four hours, it will take 1,200 workers." + +The report indicates that the city would ask the province for that money in the budget. + +***LISTEN | Alberta Municipalities will ask the province to let municipalities use tabulators:***![](https://i.cbc.ca/ais/1.7113831,1717409196906/full/max/0/default.jpg?im=Crop%2Crect%3D%280%2C0%2C1920%2C1080%29%3BResize%3D620) + +In May, the Alberta government passed a bill that bans the use of vote-counting machines in local elections. Now, a motion is being put forward to bring back vote-counting machines. The City of St. Albert is bringing the motion forward. Cathy Heron is St. Albert's mayor. + +In an email to CBC, McIver said: "Conducting municipal elections has always been a cost for the municipality to bear. That has not changed." + +Ken Johnston, Red Deer's mayor, told CBC in an interview that the machines are tried and true. + +"They have served us well. They have served us efficiently. They've come through testing, they're tested frequently. Each morning of the election, they're tested," Johnston said. + +He said public servants understand the need for transparency. + +- [Elections Alberta says no issue with tabulators despite criticism over slow start to election results](https://www.cbc.ca/news/canada/edmonton/elections-alberta-says-no-issue-with-tabulators-despite-criticism-over-slow-start-to-election-results-1.6858864) + +"The bottom line, however, is if you want to proceed in this direction, please resource us so that we're not out another million dollars in our own budget." \ No newline at end of file diff --git a/mkdocs/docs/archive/The Dangerous Americanization of Alberta Democracy.md b/mkdocs/docs/archive/The Dangerous Americanization of Alberta Democracy.md new file mode 100644 index 0000000..8f42ecb --- /dev/null +++ b/mkdocs/docs/archive/The Dangerous Americanization of Alberta Democracy.md @@ -0,0 +1,117 @@ +--- +title: "The Dangerous Americanization of Alberta Democracy" +source: "https://thetyee.ca/Analysis/2024/10/28/Dangerous-Americanization-Alberta-Democracy/" +author: + - "[[Alex Ballos, Bashir Bello, Jared Wesley]]" +published: 2024-10-28 +created: 2025-05-29 +description: "Danielle Smith is looking south for inspiration, ideas and laws." +tags: + - "clippings" +--- +[The Dangerous Americanization of Alberta Democracy](https://thetyee.ca/Analysis/2024/10/28/Dangerous-Americanization-Alberta-Democracy/) + +![On the left, a woman with light skin and shoulder-length brown hair speaking into a microphone. On the right, a man with light skin dressed in red and wearing a red ball cap, standing outdoors with one white gloved hand leaning on a golf club.](https://thetyee.ca/News/2023/06/01/DanielleSmithDonaldTrump.jpg) + +Alberta Premier Danielle Smith is borrowing from US politics at a time when presidential candidate Donald Trump is attacking democratic norms. Smith photo via Alberta government. Trump photo via Wikimedia. + +Since her return to provincial politics, [elected representatives](https://calgaryherald.com/news/local-news/bill-18), [opposition leaders](https://www.cbc.ca/news/canada/edmonton/alberta-ndp-says-government-limited-debate-on-controversial-bills-1.7052603), [academics](https://globalnews.ca/news/10417424/alberta-universities-provincial-approval-federal-funding/) and [activists](https://www.cbc.ca/news/canada/calgary/alberta-transgender-support-rallies-1.7104366) have shared their concerns regarding the bills put forward by Alberta Premier Danielle Smith and the United Conservative Party. + +Legislation such as the Alberta Sovereignty Act and the Provincial Priorities Act have garnered strong opposition, with critics highlighting [threats](https://policyoptions.irpp.org/magazines/october-2022/is-the-alberta-sovereignty-act-constitutional/) to the constitutional division of powers and rule of law, [academic freedom](https://edmontonjournal.com/opinion/columnists/opinion-albertas-bill-18-spells-the-end-of-academic-freedom) and [Indigenous sovereignty](https://www.albertanativenews.com/treaty-chiefs-slam-bill-1-for-ignoring-indigenous-sovereignty/). + +Proposed [changes](https://www.cbc.ca/news/canada/calgary/bill-rights-danielle-smith-alberta-inside-1.7291123) to the Alberta Human Rights Act and [anti-trans legislation](https://theconversation.com/albertas-new-policies-are-not-only-anti-trans-they-are-anti-evidence-222579) have sparked additional concerns. + +Many of these measures were left out of the UCP’s 2023 election platform, [raising questions](https://edmontonjournal.com/opinion/columnists/opinion-how-danielle-smith-turns-cheap-talk-into-public-policy) as to their origins. While much has been made about her borrowing pages from the [Quebec playbook](https://policyoptions.irpp.org/magazines/may-2024/alberta-quebec-playbook/), Smith’s idealization of Republican policy in the United States may provide additional clues as to the source of the UCP’s policies. + +In a 2023 speech, Smith [praised](https://calgary.ctvnews.ca/danielle-smith-comments-suggest-she-wants-freedoms-like-desantis-and-noem-1.6376278) Florida Gov. Ron DeSantis and South Dakota Gov. Kristi Noem and projected Alberta as a “ [little bastion of freedom](https://calgaryherald.com/opinion/columnists/braid-the-premier-touts-american-politicians-as-models-for-making-alberta-free) ” in the same vein. + +This begs the question: To what extent does the Smith government draw inspiration from Republicans in crafting its legislative agenda? And what are the implications of this sort of Americanization of Alberta politics? + +Our research suggests that Smith’s admiration of Republicans goes beyond rhetoric. The UCP’s approach to legislation aligns well with red-state leaders who advance a vision of “freedom” that limits pluralism and concentrates power in the executive. + +At its core, the cross-pollination of these ideas marks a shift with potentially profound consequences for democracy in Alberta. + +**‘Policy diffusion’ in action** + +Policy diffusion occurs when ideas, practices or innovations spread from one government or jurisdiction to another. In January, for instance, Republican Gov. Spencer Cox signed the [Utah Constitutional Sovereignty Act](https://le.utah.gov/~2024/bills/static/SB0057.html), a bill that is almost identical to the [Alberta Sovereignty Within a United Canada Act (2022)](https://www.assembly.ab.ca/assembly-business/bills/bill?billinfoid=11984&from=bills). In fact, Utah Sen. Scott Sandall, who drafted the bill, [was happy](https://www.theglobeandmail.com/canada/british-columbia/article-western-canada-utah-gives-alberta-credit-for-idea-of-states-own/) to cite his sources. + +Policy ideas seem to be travelling north to a far larger extent, however, with Smith’s government introducing legislation that centralizes power in a manner similar to several U.S. states. + +The [Municipal Affairs Statutes Amendment Act (Bill 20)](https://docs.assembly.ab.ca/LADDAR_files/docs/bills/bill/legislature_31/session_1/20230530_bill-020.pdf) is a prime example, as it gives the provincial cabinet extensive control over municipalities, school boards and post-secondary institutions. In a similar vein, [North Carolina’s Senate Bill 36](https://drive.google.com/file/d/0B6NNJ2VZUabObkNmYXl2SXRfNjA/view?resourcekey=0-9DzDFXdbXicRUs6lTGcFBw) sought to redraw city council districts and mandate partisan declarations in traditionally non-partisan elections, a concerted effort to manipulate local governance in favour of the governing party. + +States like Missouri, Arkansas and North Dakota [have passed](https://www.ncsl.org/elections-and-campaigns/voter-id) strict voter ID laws and imposed limits on local electoral autonomy under the pretext of protecting “election integrity.” The UCP’s Bill 20 [contained similar provisions](https://thetyee.ca/Opinion/2024/08/22/Undemocratic-Voter-ID-Law/), outlawing the decades-old practice of vouching alongside the [elimination](https://www.stalbertgazette.com/local-news/alberta-premier-danielle-smith-digs-in-heels-on-vote-tabulator-ban-9579154) of electronic vote tabulators and the [introduction of parties](https://edmontonjournal.com/news/politics/edmontonians-unhappy-alberta-ucp-bill-20) to local election ballots in Edmonton and Calgary. Critics on both sides of the border contend partisan motives and conspiratorial thinking were at play. + +Bill 20 is not the only instance where policy diffusion has occurred. The [Red Tape Reduction Statutes Amendment Act (Bill 16)](https://docs.assembly.ab.ca/LADDAR_files/docs/bills/bill/legislature_31/session_1/20230530_bill-016.pdf), an amendment which aims to dismantle existing regulations across multiple Alberta ministries, resembles former president Donald Trump’s [Executive Order 13771](https://www.federalregister.gov/documents/2017/02/03/2017-02451/reducing-regulation-and-controlling-regulatory-costs), issued in 2017. Similar to Alberta, Trump [imposed](https://19january2021snapshot.epa.gov/laws-regulations/executive-order-13771-reducing-regulation-and-controlling-regulatory-costs_.html) annual reporting requirements on the bureaucracy. + +This focus on reducing red tape has not precluded governments on both sides of the border from imposing new regulations on public sector bodies, including municipalities and universities. In Alberta, the Provincial Priorities Act (Bill 18) places federal research funding at the discretion of the Alberta government. Introducing the bill, Smith [argued](https://edmontonjournal.com/opinion/columnists/opinion-albertas-bill-18-spells-the-end-of-academic-freedom) that it would counter perceived efforts by the federal government to impose ideological priorities by setting provincial research agendas. She also viewed the bill as an opportunity to achieve [more ideological balance](https://www.msn.com/en-ca/news/canada/danielle-smith-wants-ideology-balance-at-universities-alberta-academics-wonder-what-she-s-tilting-at/ar-AA1nln6L) on Alberta campuses. + +Among several other [anti-university measures](https://www.vox.com/policy/23762357/republican-attack-higher-education), Bill 18 mirrors Republican Rep. Brandon Williams’ Respecting the First Amendment on Campus Act, which would mandate institutions of higher education to adopt and adhere to principles of free speech, potentially undermining academic freedom and constraining diverse viewpoints. + +The UCP’s ongoing bid to amend the Alberta Human Rights Act betrays similar intentions at Americanization. Enshrining [gun rights](https://www.discoverairdrie.com/articles/what-are-the-major-changes-coming-to-albertas-bill-of-rights), alongside a [commitment to](https://calgaryherald.com/opinion/columnists/braid-powerful-ucp-board-premier-danielle-smith-governs-party-public) “Life, Liberty, Property and the Pursuit of Happiness,” borrows directly from the U.S. Declaration of Independence (albeit with the addition of the word “property”). + +The UCP’s proposed measures [to further marginalize](https://globalnews.ca/news/10296987/transgender-youth-alberta-legal-experts/) transgender Albertans and transfer medical decisions out of the hands of patients, parents and doctors when it comes to trans health also have [American roots](https://www.advocate.com/politics/project-2025-anti-transgender-all). + +Given these similarities and the influence of [Project 2025](https://www.bbc.com/news/articles/c977njnvq2do) on Republican policy in the United States, Albertans may have a reliable guidebook for their own fall 2024 legislative session, which begins today. + +**Impacts of Americanization** + +The UCP’s Republican-inspired legislative agenda has impacts beyond policy. It represents a broader transformation toward a brand of right-wing populism that [undermines liberal democratic norms](https://thetyee.ca/Opinion/2024/05/06/Why-UCP-Is-Threat-Democracy/) by reducing local autonomy, curtailing academic freedom and concentrating authority in the political executive. + +If similar moves at the federal level may be labelled the [presidentialization](https://www.jstor.org/stable/27550070) of the prime ministership, Smith’s actions can be considered an attempt to turn her own office into that of a U.S. governor. + +She has admitted as much. At the tail end of the COVID-19 pandemic, Smith mused about [issuing “pardons”](https://edmonton.ctvnews.ca/alberta-premier-exploring-pardons-for-covid-19-related-fines-and-arrests-1.6120925) to scofflaws. She retracted the proposal once she realized the Canadian system did not confer her such gubernatorial powers. + +The path Smith is charting for Alberta raises critical questions about the province’s democratic future. By borrowing from the Republican playbook, her government is not only pushing policies that redefine rights and responsibilities in Alberta — it is blurring the lines between Canadian and American democracy at a time when the latter has reached the point of [crisis](https://www.brookings.edu/articles/understanding-democratic-decline-in-the-united-states/). + +Canada’s system of [pluralism](https://www.theglobeandmail.com/opinion/pluralism-is-a-path-to-lasting-peace-and-prosperity/article36422623/) respects the importance of different viewpoints, beliefs and lifestyles within a society. It’s the idea that a healthy democracy allows diverse groups — whether based on culture, religion, politics or other factors — to coexist and have a voice in shaping decisions that affect the entire community. Checks and balances on executive power are crucial to this effort. Instead of one group dominating, pluralism ensures that everyone gets a chance to be heard and contribute to the public debate, leading to a more inclusive and balanced society. + +As Republicans steer the United States further away from that ideal, attempting to concentrate more power in governors and presidents, Albertans should be weary of similar developments in our own province. + +Read more: [Rights + Justice](https://thetyee.ca/Topic/RightsJustice/), [Politics](https://thetyee.ca/Topic/Politics/), [Alberta](https://thetyee.ca/Topic/Alberta/) + +**LATEST STORIES** + +- [![](https://thetyee.ca/News/2025/05/28/NurseVaccinatingChild_latest_size_thumb.jpg)](https://thetyee.ca/News/2025/05/29/BC-Measles-Vaccination-Schools/) + [ + #### BC Won’t Require Measles Vaccination for Schools + ](https://thetyee.ca/News/2025/05/29/BC-Measles-Vaccination-Schools/) + As outbreaks grow, that’s the wrong strategy against the most infectious disease, one retired doctor says. +- [![](https://thetyee.ca/News/2025/05/28/MountiesHorses_latest_size_thumb.jpg)](https://thetyee.ca/News/2025/05/29/Madu-Investigation-Drags-On/) + [ + #### Slow Trot Policing? The Madu Investigation Drags On + ](https://thetyee.ca/News/2025/05/29/Madu-Investigation-Drags-On/) + A ‘fairly straightforward’ RCMP probe of Alberta’s former justice minister hits three years and counting. +- [![](https://thetyee.ca/News/2020/06/18/child-at-school_latest_size_thumb.jpg)](https://thetyee.ca/News/2025/05/29/BC-Education-Underfunded-Tipping-Point/) + [ + #### Is BC’s Education Underfunded and at a ‘Tipping Point’? + ](https://thetyee.ca/News/2025/05/29/BC-Education-Underfunded-Tipping-Point/) + Yes, according to the BC School Trustees Association. They’re sounding the alarm. +- [![](https://thetyee.ca/Opinion/2025/05/28/HelicopterPolice_latest_size_thumb.jpg)](https://thetyee.ca/Opinion/2025/05/29/Canada-Joins-Trump-War-Drugs/) + [ + #### Canada Joins Trump’s New Ill-Fated ‘War on Drugs’ + ](https://thetyee.ca/Opinion/2025/05/29/Canada-Joins-Trump-War-Drugs/) + Repression of the drug trade always fails and often makes things worse here and abroad. +- [![](https://thetyee.ca/Analysis/2025/05/28/CanadaVaccineLeadership_latest_size_thumb.jpg)](https://thetyee.ca/Analysis/2025/05/28/Canada-Vaccine-Technology-Leadership-Matters/) + [ + #### Why Canada’s Vaccine Leadership Matters More than Ever + ](https://thetyee.ca/Analysis/2025/05/28/Canada-Vaccine-Technology-Leadership-Matters/) + We’re uniquely positioned to lead a revolution in vaccine technology. Here’s how. +- [![](https://thetyee.ca/Opinion/2023/08/16/DanielleSmithPodium_latest_size_thumb.jpg)](https://thetyee.ca/Opinion/2025/05/28/Alberta-Gave-Measles-Advantage/) + [ + #### How Alberta Gave Measles the Advantage + ](https://thetyee.ca/Opinion/2025/05/28/Alberta-Gave-Measles-Advantage/) + Danielle Smith promotes and thrives on post-pandemic chaos. It’s putting children at too much risk. + +### The Barometer + +What Writing Do You Do in Your Spare Time? + +- Journal writing +- Letters to friends +- Memoirs +- Fiction +- Poetry + +- Tell us more… + +[Take this week’s poll](https://thetyee.ca/Polls/2025/04/25/Writing-Spare-Time/) \ No newline at end of file diff --git a/mkdocs/docs/archive/Why the UCP Is a Threat to Democracy.md b/mkdocs/docs/archive/Why the UCP Is a Threat to Democracy.md new file mode 100644 index 0000000..fd928c1 --- /dev/null +++ b/mkdocs/docs/archive/Why the UCP Is a Threat to Democracy.md @@ -0,0 +1,146 @@ +--- +title: "Why the UCP Is a Threat to Democracy" +source: "https://thetyee.ca/Opinion/2024/05/06/Why-UCP-Is-Threat-Democracy/" +author: + - "[[Jared Wesley]]" +published: 2024-05-06 +created: 2025-05-29 +description: "Political scientist Jared Wesley makes the case. And explains how Albertans should push back." +tags: + - "clippings" +--- +[Why the UCP Is a Threat to Democracy](https://thetyee.ca/Opinion/2024/05/06/Why-UCP-Is-Threat-Democracy/) + +![A black and white image shows two photos of the same smiling 50-ish light-skinned woman wearing a dark suit and holding a binder and phone.](https://thetyee.ca/Opinion/2024/05/06/1_alberta-democracy-main.jpg) + +Alberta has become less democratic and more authoritarian under Jason Kenney and Danielle Smith, writes Jared Wesley. Photo via Alberta government. + +I’m going to be blunt in this piece. As a resident of Alberta and someone trained to recognize threats to democracy, I have an obligation to be. + +The United Conservative Party is an authoritarian force in Alberta. Full stop. + +I don’t come by this argument lightly. It’s based on extensive evidence that I present below, followed by some concrete actions Albertans can take to push back against creeping authoritarianism. + +**Drawing the line** + +There’s no hard-and-fast line between democracy and authoritarianism. Just ask [people from autocracies](https://x.com/LukaszukAB/status/1783735720034922886): you don’t simply wake up one day under arbitrary rule. + +They’re more like opposite sides of a spectrum, ranging from full participation by all citizens in policy-making at one end (democracy) to full control by a leader and their cadre on the other (authoritarianism). + +Clearly, Alberta politics sit somewhere between these two poles. It is neither an ideal Greek city-state nor a totalitarian hellscape. + +The question is: How much of a shift toward authoritarianism are we willing to accept? Where do we draw the line between politics as usual and anti-democratic activities? + +At a bare minimum, we should expect our leaders to respect the rule of law, constitutional checks and balances, electoral integrity and the distribution of power. + +Unfortunately, the United Conservative Party has shown disregard for these principles. They’ve breached them so many times that citizens can be forgiven for being desensitized. But it is important to take stock so we can determine how far we’ve slid. + +Here’s a breakdown of those principles. + +### 1\. Rule of Law + +In healthy democracies: + +- no one is above the law’s reach or below the law’s protection; +- there is due process; and +- the rules are clear and evenly applied. + +By these standards, Alberta is not looking so healthy these days. + +1. **Above the law:** Members of the UCP government have positioned themselves as being beyond reproach. A premier [fired the election commissioner](https://globalnews.ca/news/6189426/alberta-elections-commissioner-fired-political-reaction/) before he could complete an investigation into his own leadership campaign. A justice minister [confronted](https://www.cbc.ca/news/canada/calgary/madu-alberta-justice-minister-ticket-police-edmonton-1.6315184) a police chief over a traffic ticket. +2. **Legal interference:** The same UCP premier crossed the line in the [Artur Pawlowski affair](https://calgaryherald.com/news/local-news/danielle-smith-says-call-with-artur-pawlowski-was-between-two-party-leaders), earning a rebuke from the ethics commissioner that “it is a threat to democracy to interfere with the administration of justice.” The episode raised questions about how allies of the premier might receive preferential treatment in the courts. +3. **Targeting city dwellers:** Vengeance has [no place](https://www.readtheline.ca/p/kristin-raworth-the-ucps-petulant) in a province where rule of law ensures everyone is treated fairly. Through Bill 20, the UCP is singling out Alberta’s two biggest cities as sites for an experiment with local political parties. The premier [herself](https://x.com/disorderedyyc/status/1784371481088286952) noted that partisanship is ill-suited to local politics. She’s spared rural and other urban communities from those dangers, but not Edmonton and Calgary (whose voters elected many city councillors who don’t share the UCP’s viewpoint on public policy or democracy). + +### 2\. Checks and Balances + +Leaders should also abide by the Constitution, including: + +- the separation of powers among the executive, legislative and judicial branches; and +- the division of powers between federal and provincial governments. + +The UCP government has demonstrated a passing familiarity and respect for these checks on its authority. + +1. **Going around the legislature:** At the outset of the COVID-19 pandemic, the UCP government [stripped the legislature](https://docs.assembly.ab.ca/LADDAR_files/docs/bills/bill/legislature_30/session_2/20200225_bill-010.pdf) of its ability to review public health measures taken by the minister of health. They backtracked only after their own allies [threatened](https://edmontonjournal.com/news/politics/lawsuit-challenges-constitutionality-of-alberta-ucps-bill-10) to sue them. +2. **Going around the courts:** The first draft of the UCP’s Sovereignty Act would have stolen powers from the [federal government](https://calgaryherald.com/news/politics/smith-introduces-flagship-alberta-sovereignty-within-a-united-canada-act-giving-cabinet-new-power/wcm/30408893-3286-4e04-8642-ac59515b3783), the [Alberta legislature](https://www.cbc.ca/news/canada/edmonton/alberta-premier-danielle-smith-sovereignty-act-1.6668175) and the courts and granted them to the premier. They walked some of it back after public backlash but remain insistent that the provincial cabinet — not the Supreme Court — should determine the bounds of federal and provincial authority. + +### 3\. Electoral Integrity + +In democracies, leaders respect the will of the people. + +That includes: + +- abiding by internal party rules and election laws; +- campaigning openly about their policy proposals to seek a mandate from voters during elections; and +- ensuring that everyone entitled to vote has an opportunity to do so. + +Again, the UCP’s record is abysmal. + +1. **Tainted race:** The party didn’t start off on the right foot. The inaugural UCP leadership race featured [over $100,000 in fines](https://www.cbc.ca/news/canada/calgary/jeff-callaway-kamikaze-commissioner-fines-1.5216446) levied against various party operatives and contestants. While the RCMP [failed to find evidence](https://www.rcmp-grc.gc.ca/en/news/2024/alberta-rcmp-concludes-investigations-surrounding-the-2017-ucp-leadership-vote) of voter or identity fraud of a criminal nature, the police and Elections Alberta found “ [clear evidence](https://pressprogress.ca/rcmp-confirms-hundreds-on-ucp-voter-list-told-police-they-had-no-knowledge-they-ever-voted/) ” of suspicious votes and that many alleged voters had “no knowledge” of casting ballots. As someone who participated in that vote as a party member, I can attest: the outcome is tarnished for me as a result. +2. **Hidden agenda:** The UCP has a habit of keeping more promises than they make on the campaign trail. Of the party’s most high-profile policy initiatives — an [Alberta pension plan](https://www.albertapensionplan.ca/), an [Alberta police service](https://www.cbc.ca/news/canada/edmonton/new-bill-lays-groundwork-for-alberta-provincial-police-1.7142996), introducing [parties into municipal elections](https://edmontonjournal.com/news/politics/alberta-to-remove-councillors-change-bylaws-add-political-parties-to-municipal-politics), the [Sovereignty Act](https://www.reuters.com/world/americas/what-is-albertas-sovereignty-act-2023-11-27/) and the [Provincial Priorities Act](https://calgaryherald.com/news/politics/bill-18-provincial-approval-federal-funding-agreements) — none [appeared](https://daveberta.ca/2024/03/what-danielle-smith-said-she-wouldnt-campaign-for-in-the-2023-election/) in the UCP’s lengthy list of [campaign planks](https://www.unitedconservative.ca/ucp-platform-2023/). This is because most are wildly unpopular. Indeed, the premier [denied wanting](https://calgaryherald.com/news/local-news/smith-says-sovereignty-act-rcmp-replacement-and-pension-plan-not-in-ucp-campaign) to pursue several of them altogether, only to introduce them as legislation once in power. This disrespect for voters sows distrust in the democratic system. +3. **Fake referendum:** The UCP’s [disingenuous use](https://theconversation.com/why-alberta-lacks-a-mandate-to-reopen-canadas-constitution-170437) of a constitutional referendum on the equalization principle shows their lack of respect for direct democracy. No attempt was made to inform the public about the actual nature of equalization before a provincewide vote was held, and the government [capitalized on misperceptions](https://globalnews.ca/news/8263587/alberta-equalization-referendum-misunderstood/) in an effort to grandstand against Ottawa. +4. **Voters’ intent:** Bill 20 is also an [affront to voters’ intent](https://calgaryherald.com/opinion/columnists/breakenridge-bill-20-stacks-deck-favour-ucp) by giving cabinet sweeping new powers to dismiss local elected officials. Routine elections give voters the right to determine who represents them. Bill 20 takes that power away and gives it to two dozen ministers behind closed doors. +5. **Voter suppression:** Bill 20 goes one step further to require voter ID in local elections. Borrowed from the [MAGA playbook](https://www.pfaw.org/blog-posts/trumptastrophe-maga-republicans-and-their-ongoing-attacks-on-the-right-to-vote/), the UCP’s move is designed to [restrict](https://drjaredwesley.substack.com/p/fair-elections-require-more-than) the types of people who can vote in elections. It’s about voter suppression, plain and simple. Combined with the conspiracy-driven banning of vote tabulators, the government claims this is making elections fairer. At best, these are solutions in search of a problem. Voter fraud is [exceptionally rare](https://x.com/cspotweet/status/1784367103795204223) in Alberta, and [voting machines](https://www.edmonton.ca/city_government/municipal_elections/voting-technology) are safe and secure. + +### 4\. Distribution of Power + +More broadly, our leaders should respect the importance of pluralism, a system where power is dispersed among multiple groups or institutions, ensuring no single entity holds too much control. This includes: + +- respecting the autonomy of local governments and officials; +- protecting the independence of arm’s-length agencies, boards and commissions; +- upholding the public service bargain, which affords civil servants protection and benefits in return for providing fearless advice and loyal implementation; and +- upholding the principle of academic freedom, whereby academics can pursue lines of inquiry without fear of censorship or persecution. + +The UCP has little respect for these principles, either. + +1. **Kissing the ring:** In the past two weeks, the UCP government introduced [Bill 18 and Bill 20](https://drjaredwesley.substack.com/p/theyve-jumped-the-shark), the combined effect of which would be to bend municipal councillors and public bodies to the will of the provincial cabinet and [encroach](https://theconversation.com/albertas-bill-18-who-gets-the-most-federal-research-funding-danielle-smith-might-be-surprised-by-what-the-data-shows-228084) on matters of academic freedom by vetting federally funded research grants. +2. **Breaking the bargain:** UCP premiers have broken the public service bargain by [threatening to investigate](https://calgarysun.com/opinion/columnists/bell-hinshaw-bonus-whodunit-it-aint-over-until-somebody-sings) and eventually [firing](https://calgary.citynews.ca/video/2023/06/26/alberta-doctors-call-for-investigation-into-dr-hinshaw-decision/) individual officials, pledging to [roll back](https://www.cbc.ca/news/canada/edmonton/alberta-government-seeking-11-per-cent-wage-cuts-for-some-health-care-workers-1.6384910) wages and benefits and hinting at [taking over](https://edmontonjournal.com/opinion/columnists/opinion-kenney-sows-confusion-about-albertas-public-pensions) their pensions. They’ve also cut public servants and [stakeholders](https://www.cbc.ca/news/canada/edmonton/alberta-ahs-transgender-policies-danielle-smith-1.7186280) out of the [policy development process](https://edmontonjournal.com/opinion/columnists/opinion-how-danielle-smith-turns-cheap-talk-into-public-policy), limiting the amount of evidence and number of perspectives being considered. +3. **Cronyism and meddling:** The party has loaded various arm’s-length agencies with [patronage appointments](https://www.nationalobserver.com/2020/07/10/opinion/cronyism-patronage-and-destruction-democratic-rights-mark-kenneys-rule-decree) and [dismissed](https://edmontonjournal.com/news/politics/ahs-board-dismantled-as-dr-john-cowell-named-new-administrator) or [threatened to fire](https://www.cbc.ca/news/canada/edmonton/united-conservative-party-leadership-debate-edmonton-alberta-1.6562897) entire boards of others. During a UCP [leadership debate](https://www.cbc.ca/news/canada/edmonton/united-conservative-party-leadership-debate-edmonton-alberta-1.6562897), various contenders promised to politicize several fields normally kept at arm’s length from interference — academia, the police, the judiciary, prosecutions, pensions, tax collection, immigration and sport. + +Combined, these measures have steadily concentrated power in the hands of the premier and their entourage. The province has become less democratic and more authoritarian in the process. + +**What we can do about it** + +The first step in pushing back against this creeping authoritarianism is recognizing that this is not politics as usual. Despite the government’s disinformation, these new measures are unprecedented. Alberta’s drift toward authoritarianism has not happened overnight, but we cannot allow ourselves to become desensitized to the shift. + +We should continue to call out instances of anti-democratic behaviour and tie them to the growing narrative I’ve presented above. Crowing about each individual misdeed doesn’t help if they don’t fit into the broader storyline. Arguing over whether the UCP is acting in authoritarian or fascist ways also isn’t helpful. This isn’t about semantics; it’s about action. + +This also isn’t a left/right or partisan issue. [Conservatives](https://drjaredwesley.substack.com/p/theyve-jumped-the-shark) ought to be as concerned about the UCP’s trajectory as progressives. Politicians of all stripes should be speaking out and Albertans should welcome all who do. Opposition to the UCP’s backsliding can’t be monolithic. We need many voices, including those within the government caucus and [UCP base](https://drjaredwesley.substack.com/p/alberta-needs-a-few-good-tories). + +In this sense, it’s important to avoid engaging in whataboutism over which side is more authoritarian. It’s important to acknowledge when [any government](https://www.cbc.ca/news/politics/trudeau-wilson-raybould-attorney-general-snc-lavalin-1.5014271) strays from democratic principles. Finding common ground with folks from across the spectrum about what we expect from our governments is key. + +Some Albertans are organizing protests related to specific anti-democratic moves by the UCP government, while others are marshalling [general resistance events](https://www.enoughisenoughucp.ca/) and movements. With numerous public sector unions in [negotiations](https://thetyee.ca/Opinion/2024/04/30/Alberta-Has-Set-Stage-Battle-Workers/) with the government this year, there is a potential for a groundswell of public education and mobilization in the months ahead. Supporting these organizations and movements is an important way to signal your opposition to the UCP government’s democratic backsliding. + +Show up, amplify their messages, and donate if you can. Protests [work](https://edmontonjournal.com/news/politics/from-the-archives-prentice-puts-bill-10-on-hold-premier-acknowledges-debate-on-gay-straight-alliances-is-divisive), but only if everyday Albertans support the causes. + +[Calling or writing your MLA](https://www.reddit.com/r/alberta/comments/16rvta9/contacting_your_mla/) also helps. Don’t use a form letter or script; those are easily ignored. But staffers I’ve interviewed confirm that for every original phone call they receive, they assume at least a dozen other constituents are just as upset; you can double that for every letter. Inundating UCP MLA offices, in particular, can have a real impact on government caucus discussions. We know that governments make policy U-turns when enough caucus members [threaten a revolt](https://www.cbc.ca/news/canada/calgary/road-ahead-alberta-conservative-parties-splinter-history-1.5984055). On the flip side, silence from constituents is taken as complicity with the government’s agenda. + +Talking to friends, family and neighbours about your concerns is equally important. It lets people know that others are also fed up, helping communities break out of the “ [spiral of silence](https://en.wikipedia.org/wiki/Spiral_of_silence) ” that tends to hold citizens back from advocating for their interests. Encouraging them to write or call their MLA, or to join you at a rally, would also help. + +Elections are the ultimate source of accountability for governments. While Albertans will likely have to wait until May 2027 for another provincial campaign, there are some interim events that allow folks to voice their concerns. + +- Existing UCP members and people wanting to influence the party from within can participate in this fall’s leadership review. +- Opponents should support opposition parties and politicians who take these threats seriously. +- The next federal election is also an opportunity to get politicians on the record about how they feel about the UCP’s democratic backsliding. Ask folks who come to your door about their position on these issues and what they’re prepared to say publicly. +- The next round of municipal and school board elections in October 2025 offers Albertans another opportunity to weigh in. By introducing political parties into these elections in Edmonton and Calgary, and with Take Back Alberta openly [organizing](https://thetyee.ca/Opinion/2023/08/29/Social-Conservatives-Plan-Alberta-Schools/) affiliated slates throughout the province, the UCP is inviting Albertans to consider these local elections a referendum on their approach to democracy. + +None of what I’ve suggested starts or ends with spouting off on social media. Our digital world is full of [slacktivists](https://www.citizenlab.co/blog/civic-engagement/slacktivism/) who talk a good game on Facebook or X but whose actual impact is more performance than action. + +It’s also not enough to say “the courts will handle it.” Many of the UCP’s moves sit in a constitutional grey area. Even if the courts were to intervene, they’d be a backstop, at best. [Investigations](https://www.cbc.ca/news/canada/edmonton/alberta-rcmp-ucp-leadership-fraud-investigation-1.7137976), let alone court cases, take months if not years to conclude. And the standard of proof is high. In the meantime, the damage to individuals, groups and our democratic norms would have been done already. + +In short, if Albertans want to push back against the UCP’s creeping authoritarianism, they’ll need to get off the couch. Make a commitment and a plan to stand up. Democracy demands that of us, from time to time. + +Read more: [Politics](https://thetyee.ca/Topic/Politics/), [Alberta](https://thetyee.ca/Topic/Alberta/) + +### The Barometer + +What Writing Do You Do in Your Spare Time? + +- Journal writing +- Letters to friends +- Memoirs +- Fiction +- Poetry + +- Tell us more… + +[Take this week’s poll](https://thetyee.ca/Polls/2025/04/25/Writing-Spare-Time/) \ No newline at end of file diff --git a/mkdocs/docs/archive/index.md b/mkdocs/docs/archive/index.md new file mode 100644 index 0000000..823415b --- /dev/null +++ b/mkdocs/docs/archive/index.md @@ -0,0 +1,72 @@ +# Archive: The Evidence Against Bill 54 + +## The UCP's Anti-Democratic Agenda Exposed + +This archive contains comprehensive documentation of the UCP government's systematic assault on democratic institutions in Alberta. Bill 54 (the Election Statutes Amendment Act, 2025) represents one of the most significant threats to democratic participation in Alberta's history. + +## What You'll Find Here + +Our archive includes: + +### 📰 **News Coverage** +Mainstream media reports documenting the scope and impact of Bill 54's anti-democratic provisions. + +### 🏛️ **Government Sources** +The UCP's own statements and press releases, revealing their true intentions behind the legislation. + +### 📊 **Expert Analysis** +Academic and professional commentary exposing the authoritarian nature of these changes. + +### 🏘️ **Community Opposition** +Responses from Indigenous Nations, municipalities, unions, and civil society organizations. + +### ⚖️ **Legal Concerns** +Analysis from legal experts and the Chief Electoral Officer about the bill's impact on election integrity. + +## Key Themes in the Evidence + +### Voter Suppression +- Elimination of vouching systems that help eligible voters +- Barriers to accessible voting for marginalized communities +- Restrictions designed to reduce turnout among likely opposition voters + +### Corporate Capture +- Reintroduction of corporate political donations with $5,000 aggregate maximum +- Restrictions on union political activity +- Weakened oversight of election finance violations + +### Centralization of Power +- Introduction of political parties to municipal elections +- Reduced independence of electoral officials +- Weakened investigative powers for election law enforcement + +### Attack on Local Democracy +- Provincial interference in municipal governance +- Undermining of community-based decision making +- Partisan politicization of previously non-partisan local elections + +## The Broader Pattern + +Bill 54 is not an isolated incident—it's part of a broader authoritarian agenda that includes: + +- Bill 20: Giving cabinet power to fire mayors and overturn municipal bylaws +- Attacks on public healthcare and education +- Suppression of environmental activism +- Weakening of workers' rights + +## How to Use This Archive + +Each document in our archive provides crucial evidence of the UCP's anti-democratic agenda. We encourage you to: + +1. **Read widely** across different source types +2. **Share specific articles** that resonate with your community +3. **Use this evidence** when contacting elected officials +4. **Cite these sources** in letters to editors and social media + +The evidence is overwhelming: the UCP is systematically undermining democratic institutions in Alberta. This archive provides the documentation needed to fight back. + +--- + +*The contents of this archive are subject to updates as new evidence emerges of the UCP's continuing assault on Alberta democracy.* + + diff --git a/mkdocs/docs/assets/images/adtf-logo.png b/mkdocs/docs/assets/images/adtf-logo.png new file mode 100644 index 0000000..4a8df60 Binary files /dev/null and b/mkdocs/docs/assets/images/adtf-logo.png differ diff --git a/mkdocs/docs/assets/images/header.png b/mkdocs/docs/assets/images/header.png new file mode 100644 index 0000000..2724de7 Binary files /dev/null and b/mkdocs/docs/assets/images/header.png differ diff --git a/mkdocs/docs/assets/images/image.png b/mkdocs/docs/assets/images/image.png new file mode 100644 index 0000000..93d634b Binary files /dev/null and b/mkdocs/docs/assets/images/image.png differ diff --git a/mkdocs/docs/bill-54-analysis.md b/mkdocs/docs/bill-54-analysis.md new file mode 100644 index 0000000..44920fc --- /dev/null +++ b/mkdocs/docs/bill-54-analysis.md @@ -0,0 +1,296 @@ +# The Damage Done: Bill 54's Attack on Alberta Democracy + +## A Comprehensive Analysis of How Bill 54 Undermines Democratic Rights + +Bill 54 (the Election Statutes Amendment Act, 2025) represents the most comprehensive assault on democratic institutions in Alberta's history. This page breaks down exactly what the legislation does and why each provision threatens democratic participation. + +## Corporate Money Floods Back Into Politics + +### What Changed +Bill 54 reintroduces **corporate and union donations** to political parties and candidates, with an aggregate maximum of $5,000 per year to parties, constituency associations, candidates and third-party political advertisers. A separate $5,000 limit applies to leadership candidates. + +### The Real Impact +**For Corporations:** + +- Oil and gas companies can now donate up to $5,000 to the UCP and affiliated entities +- Real estate developers can buy influence in municipal and provincial elections +- Alberta corporations can shape our politics through direct donations +- Corporate interests gain direct access to political parties that individual donors cannot match + +**For Workers:** + +- Union donations are also limited to the same $5,000 aggregate maximum +- Despite equal donation limits, corporate wealth gives businesses significant structural advantages +- Multiple corporations can donate from the same industry or ownership group +- Workers' collective voice faces the same monetary restrictions as individual corporate entities +- The playing field remains tilted toward capital due to the number and wealth of corporate donors + +### Who Benefits + +- **Corporate interests** who can now donate $5,000 annually to buy direct political access +- **Wealthy developers** seeking favorable zoning and development decisions through municipal donations +- **Resource extraction companies** wanting fewer environmental regulations +- **The UCP** who are likely to receive the majority of corporate donations +- **Multiple corporate entities** from the same industry who can each donate the maximum amount + +### Who Gets Hurt + +- **Working families** whose small individual donations are dwarfed by coordinated corporate giving +- **Environmental groups** facing well-funded corporate opposition from multiple donors +- **Community organizations** that cannot access the same level of organized financial support +- **Democratic equality** when corporate money tips the scales of political influence + +## Voter Suppression Through "Election Integrity" + +### Elimination of Vouching +**What it was:** A system allowing eligible voters to vouch for other eligible voters who lacked proper identification. + +**What it's been replaced with:** Strict ID requirements with no backup options for eligible voters. + +**Who this hurts:** + +- **Indigenous peoples** living on reserves where addresses may not match government records +- **Homeless Albertans** who lack fixed addresses or current ID +- **Students** who may not have updated identification reflecting current addresses +- **Recent immigrants** still navigating bureaucratic ID processes +- **Seniors** who may have difficulty obtaining or maintaining current identification +- **Low-income Albertans** who can't afford to replace lost or expired ID + +**The real purpose:** Reducing turnout among communities likely to vote against the UCP. + +### Electronic Tabulator Ban +**What changed:** Prohibition on electronic vote counting machines that have been used safely for decades. + +**What this means:** + +- **Slower results** due to hand-counting requirements +- **Higher costs** for municipalities forced to hire more counting staff +- **More errors** as human counting is less accurate than machine counting +- **Undermined confidence** in election results due to delays and mistakes + +**The real purpose:** Creating doubt about election integrity while making voting more difficult and expensive. + +## Partisan Politics Invades Local Democracy + +### Political Parties in Municipal Elections +**What changed:** For the first time, political parties are allowed in municipal elections in Edmonton and Calgary. + +**What this destroys: +** + +- **Community-focused governance** where candidates respond to local needs +- **Non-partisan problem-solving** on issues like roads, water, and local services +- **Independent decision-making** by councillors accountable to their neighborhoods +- **Collaborative governance** based on community consensus rather than party lines + +**What this creates:** + +- **Top-down control** by provincial party organizations +- **Imported conflicts** from provincial and federal politics +- **Corporate influence** through party donations in local races +- **Ideological division** where practical community issues become partisan battles + +### Impact on Different Communities + +**Small Towns and Rural Areas:** + +- Local candidates must now choose provincial political sides +- Community consensus-building becomes partisan competition +- Provincial party priorities override local community needs +- Traditional non-partisan local leadership is undermined + +**Cities:** + +- Corporate donors can buy influence over development decisions +- Municipal policy becomes subject to provincial party discipline +- Local environmental and social initiatives face partisan opposition +- Community-based politics is replaced by top-down party control + +## Lowering the Bar for Separation Referendums + +### Making Divisive Referendums Easier +**What changed:** Bill 54 dramatically lowers the threshold for citizen-initiated referendums and extends the signature collection period. + +**The specific changes:** + +- **Reduced signature requirement:** From 20% of registered voters (roughly 600,000 signatures) to 10% of people who voted in the last election (approximately 177,000 signatures) +- **Extended collection time:** From 90 days to 120 days to gather signatures +- **Elimination of riding thresholds:** No longer requires signatures from two-thirds of constituencies for constitutional questions + +**What this enables:** + +- **Separation referendums** become much more achievable for organized groups +- **Divisive constitutional questions** can more easily reach the ballot +- **Well-funded campaigns** can more easily manipulate democratic processes +- **Minority positions** can force province-wide votes on fundamental issues + +**Who this threatens:** + +- **Indigenous Nations** whose Treaty rights could be jeopardized by separation +- **Federal constitutional protections** that safeguard minority rights +- **Economic stability** threatened by constitutional uncertainty +- **Social cohesion** undermined by constant referendum campaigns + +**The real purpose:** Creating a pathway for Alberta separation while appearing to enhance democratic participation. + +## Weakening Electoral Oversight + +### Reducing the Chief Electoral Officer's Powers +**What changed:** The Chief Electoral Officer's investigative authority has been significantly weakened. + +**Practical impact:** + +- **Harder to investigate** campaign finance violations +- **Easier to break rules** without consequences +- **Less enforcement** of spending limits and donation rules +- **Reduced deterrent effect** for potential law-breakers + +**Who benefits:** Wealthy interests who want to break campaign finance rules without facing penalties. + +**Who gets hurt:** Ordinary Albertans who depend on fair rules and equal enforcement. + +## The Broader Authoritarian Pattern + +### Bill 54 in Context +This legislation is part of a broader UCP strategy to concentrate power and weaken democratic institutions: + +**Bill 20 (2024):** Gave cabinet power to fire mayors and overturn municipal bylaws +**Budget cuts:** Defunded organizations providing democratic oversight +**Labor restrictions:** Weakened unions' ability to participate in politics +**Environmental suppression:** Restricted activism and protest rights + +### The Ultimate Goal +The UCP's anti-democratic agenda aims to: + +- **Eliminate effective opposition** to corporate and government power +- **Concentrate decision-making** in the Premier's office and cabinet +- **Weaken community resistance** to unpopular policies +- **Create one-party dominance** through institutional manipulation + +## Real-World Consequences + +### What This Looks Like in Practice + +**Municipal Elections:** + +- Developers donate heavily to pro-development candidates +- Environmental candidates are outspent by corporate-backed opponents +- Local issues become proxy fights for provincial politics +- Community voices are drowned out by outside money + +**Provincial Elections:** + +- Corporate donations dwarf individual contributions +- Policy platforms reflect corporate interests rather than public needs +- Candidates spend more time fundraising from wealthy donors than talking to voters +- Working-class candidates can't compete without corporate backing + +**Democratic Participation:** + +- Ordinary Albertans become cynical about the political process +- Voter turnout drops as people feel their voices don't matter +- Community organizations stop engaging with politics +- Democratic institutions lose legitimacy and public trust + +## The Social Democratic Alternative + +### What Real Democratic Reform Looks Like + +**Campaign Finance:** + +- **Public financing** of campaigns to ensure equal access +- **Strict individual donation limits** (e.g., $200 per person per year) +- **Real-time disclosure** of all political donations +- **Strong enforcement** with meaningful penalties for violations + +**Voting Access:** + +- **Automatic voter registration** for all eligible citizens +- **Multiple ways to prove identity** including community vouching +- **Extended voting periods** with more advance voting opportunities +- **Accessible voting** for people with disabilities + +**Local Democracy:** + +- **Protected municipal autonomy** enshrined in law +- **Non-partisan local elections** maintained +- **Proportional representation** to ensure all voices are heard +- **Community control** over local development and services + +**Electoral Integrity:** + +- **Independent electoral administration** free from political interference +- **Modern counting technology** with paper audit trails +- **Strong investigative powers** for electoral officers +- **Transparent processes** that build rather than undermine public confidence + +## The Path to Reversal + +### Legal Challenges +Several aspects of Bill 54 are vulnerable to constitutional challenge: + +- **Charter violations** in voter suppression provisions +- **Indigenous rights** violations in separation referendum provisions +- **Federal jurisdiction** issues in electoral administration +- **Municipal autonomy** protections under existing law + +### Electoral Strategy + +- **Support candidates** committed to reversing Bill 54 +- **Run democratic candidates** at all levels of government +- **Build coalitions** across affected communities +- **Organize voter registration** drives in affected communities + +### Community Resistance + +- **Document the harm** as Bill 54 is implemented +- **Support affected voters** in navigating new barriers +- **Challenge implementation** through administrative and legal means +- **Build alternative democratic structures** at the community level + +## What You Can Do + +### Immediate Actions + +1. **Contact your MLA** and demand they oppose Bill 54's implementation +2. **Support organizations** challenging the legislation in court +3. **Help affected voters** navigate new voting barriers +4. **Document instances** where Bill 54 harms democratic participation + +### Long-term Organizing + +1. **Join or support** organizations working for democratic reform +2. **Volunteer** for candidates committed to reversing Bill 54 +3. **Educate others** about the legislation's harmful impacts +4. **Build community power** that can resist authoritarian measures + +### Electoral Engagement + +1. **Ensure you're registered** to vote under the new rules +2. **Help others register** and understand voting requirements +3. **Support democratic candidates** at all levels +4. **Consider running for office** yourself to defend democracy + +## The Stakes + +Bill 54 represents a fundamental choice about what kind of society we want to live in: + +**The UCP's Vision:** + +- Democracy for sale to the highest bidder +- Corporate interests above community needs +- Centralized control over local decisions +- Barriers to participation for ordinary Albertans + +**Our Vision:** + +- Democracy accessible to all regardless of wealth +- Community control over local decisions +- Equal voice for all Albertans in politics +- Government accountable to people, not corporations + +The damage done by Bill 54 is real and immediate, but it's not irreversible. **With sustained organizing and political action, we can restore and expand democratic rights in Alberta.** + +--- + +*This analysis is based on the text of Bill 54 and its documented impacts. For source materials, see our [archive](archive/index.md). For ways to take action, see our [resources](resources.md) page.* diff --git a/mkdocs/docs/blog/.authors.yml b/mkdocs/docs/blog/.authors.yml new file mode 100644 index 0000000..dbee427 --- /dev/null +++ b/mkdocs/docs/blog/.authors.yml @@ -0,0 +1,9 @@ +authors: + Alberta Democracy Taskforce: + name: Alberta Democracy Taskforce + description: Group + avatar: https://simpleicons.org/icons/materialformkdocs.svg + Admin: + name: The Bunker Admin + description: Administrator + avatar: https://github.com/squidfunk.png \ No newline at end of file diff --git a/mkdocs/docs/blog/index.md b/mkdocs/docs/blog/index.md new file mode 100644 index 0000000..38259d7 --- /dev/null +++ b/mkdocs/docs/blog/index.md @@ -0,0 +1 @@ +# Democracy Blog \ No newline at end of file diff --git a/mkdocs/docs/blog/posts/bill-54-corporate-control.md b/mkdocs/docs/blog/posts/bill-54-corporate-control.md new file mode 100644 index 0000000..e1e9187 --- /dev/null +++ b/mkdocs/docs/blog/posts/bill-54-corporate-control.md @@ -0,0 +1,220 @@ +--- +title: "Bill 54: A Blueprint for Corporate Control" +date: 2025-05-29 +authors: + - Alberta Democracy Taskforce +categories: + - Analysis + - Bill 54 + - Democracy +tags: + - corporate donations + - voter suppression + - authoritarianism + - UCP +--- + +# Bill 54: A Blueprint for Corporate Control + +## How the UCP is Handing Alberta Democracy to the Highest Bidder + +The passage of Bill 54 represents one of the darkest moments in Alberta's democratic history. Under the guise of "strengthening democracy," the UCP has systematically dismantled the safeguards that protect ordinary Albertans' political voice while opening the floodgates for corporate influence. + + + +## The Corporate Takeover + +### Corporate Donations Return with $5,000 Limit + +The most egregious provision of Bill 54 is the reintroduction of corporate political donations with an aggregate maximum of $5,000 per year. While limited, this represents a significant step backward for democratic equality in Alberta. + +**What this means in practice:** + +- **Oil and gas corporations** can now donate up to $5,000 to the UCP and affiliated entities +- **Wealthy developers** can buy influence over municipal elections within the $5,000 limit +- **Multiple corporate entities** from the same industry can each donate the maximum amount +- **Small donors** - working families, seniors, students - face organized corporate coordination + +This isn't about "fairness" as the UCP claims. It's about ensuring that those with the most money have the loudest political voice. + +### Attacking Workers' Political Rights + +While corporations can coordinate multiple $5,000 donations from related entities, Bill 54 maintains equal restrictions on unions. However, the practical effect favors capital due to the number and wealth of corporate donors. + +The legislation: + +- Maintains strict limits on union political activity +- Makes it harder for unions to educate members about political issues +- Reduces unions' ability to advocate for workers' interests +- Tilts the playing field decisively toward corporate interests + +## Voter Suppression by Design + +### Eliminating Vouching + +Bill 54 eliminates the vouching system that has helped eligible Albertans vote for decades. This system allowed voters to vouch for the identity of other eligible voters who lacked proper ID. + +**Who this hurts most:** + +- **Indigenous peoples** living on reserves where addresses may not match government records +- **Homeless Albertans** who lack fixed addresses +- **Students** who may not have updated ID reflecting their current address +- **Recent immigrants** still navigating bureaucratic processes +- **Seniors** who may have difficulty obtaining current ID + +This isn't about election integrity - it's about making it harder for likely opposition voters to cast ballots. + +### Banning Electronic Tabulators + +The prohibition on electronic vote tabulators is perhaps the most irrational provision of Bill 54. These machines: + +- **Increase accuracy** by eliminating human counting errors +- **Speed up results** allowing faster, more reliable reporting +- **Save money** by reducing the need for large counting staff +- **Provide paper backup** maintaining full audit capability + +The ban forces municipalities to return to slow, error-prone hand counting while increasing costs. There is no legitimate reason for this change except to sow doubt about election results and make voting more difficult. + +## Centralizing Control + +### Partisan Municipal Elections + +Bill 54 allows political parties in municipal elections in Edmonton and Calgary for the first time. This represents a fundamental attack on local democracy. + +Municipal politics has traditionally been non-partisan because: + +- **Local issues** don't follow party lines (roads, water, local services) +- **Community needs** are best addressed by candidates focused on their neighborhoods +- **Non-partisan elections** encourage coalition-building and compromise +- **Local democracy** works best when freed from provincial/federal partisan divides + +Introducing parties will: + +- Force artificial divisions on communities +- Import provincial political conflicts to local issues +- Give party organizations (funded by corporations) control over candidate selection +- Undermine the independence of local councillors + +### Weakening Electoral Oversight + +The legislation also weakens the Chief Electoral Officer's investigative powers, making it: + +- Harder to investigate election finance violations +- More difficult to enforce campaign spending rules +- Easier for wealthy interests to break rules with impunity +- Less likely that violations will be discovered or punished + +## The Broader Authoritarian Pattern + +Bill 54 must be understood as part of the UCP's broader authoritarian agenda: + +### Bill 20: Provincial Control Over Municipalities + +- Gives cabinet power to fire mayors and councillors +- Allows the province to overturn local bylaws +- Undermines municipal autonomy and local democracy + +### Attacks on Civil Society + +- Defunding organizations that provide oversight or criticism +- Restricting environmental activism +- Undermining independent media and research + +### Labor Suppression + +- Weakening collective bargaining rights +- Restricting union political activity +- Attacking public sector workers + +### Concentration of Power + +- Centralizing decision-making in the Premier's office +- Reducing legislative oversight and debate +- Bypassing normal democratic processes + +## The Social Democratic Alternative + +We envision a very different approach to democratic reform—one that expands participation rather than restricting it: + +### Getting Money Out of Politics + +- **Public financing** of campaigns to level the playing field +- **Strict donation limits** from individuals only +- **Real-time disclosure** of all political donations +- **Enhanced penalties** for finance violations + +### Expanding Voting Access + +- **Automatic voter registration** for all eligible citizens +- **Extended voting periods** including more advance voting days +- **Improved accessibility** for voters with disabilities +- **Mobile voting** for remote and Indigenous communities + +### Strengthening Oversight + +- **Independent electoral administration** free from political interference +- **Enhanced investigative powers** for electoral officers +- **Transparent counting** using modern, auditable technology +- **Regular democratic audits** to identify and fix problems + +### Protecting Local Democracy + +- **Municipal autonomy** protected by law +- **Non-partisan local elections** maintained +- **Community control** over local decisions +- **Proportional representation** to ensure all voices are heard + +## What's at Stake + +The battle over Bill 54 isn't just about election rules—it's about what kind of society we want to live in: + +**The UCP vision:** + +- Politics dominated by wealthy corporations +- Working people marginalized and silenced +- Local communities controlled by provincial parties +- Democracy as a privilege for the powerful + +**Our vision:** + +- Politics accessible to all Albertans regardless of wealth +- Workers' voices heard and respected +- Local communities controlling their own futures +- Democracy as a right for everyone + +## Fighting Back + +Bill 54 has passed, but the fight for democracy in Alberta is far from over. We can: + +### Immediate Actions + +- **Challenge** the legislation in court +- **Organize** community resistance to implementation +- **Document** the harmful effects as they unfold +- **Build** coalitions across affected communities + +### Long-term Strategy + +- **Electoral** - support candidates committed to reversing Bill 54 +- **Grassroots** - build democratic capacity in communities +- **Legal** - use courts to protect democratic rights +- **Political** - pressure government to reverse course + +### Building Power + +- **Union organizing** to strengthen workers' collective voice +- **Community organizing** to build local democratic capacity +- **Electoral organizing** to support democratic candidates +- **Coalition building** across movements and communities + +## Conclusion + +Bill 54 represents a fork in the road for Alberta. We can accept the UCP's vision of democracy for sale to the highest bidder, or we can fight for a democracy that serves all Albertans. + +The choice is ours, but only if we act. Democracy isn't a spectator sport—it requires all of us to participate, organize, and fight for the kind of society we want to live in. + +**The corporate takeover of Alberta democracy can be stopped, but only if we build the movement to stop it.** + +--- + +*This analysis is based on the Alberta Democracy Taskforce's review of Bill 54 and its implications for democratic participation in Alberta. For source materials and documentation, see our [archive](../../archive/index.md).* diff --git a/mkdocs/docs/blog/posts/indigenous-opposition-bill-54.md b/mkdocs/docs/blog/posts/indigenous-opposition-bill-54.md new file mode 100644 index 0000000..9aace18 --- /dev/null +++ b/mkdocs/docs/blog/posts/indigenous-opposition-bill-54.md @@ -0,0 +1,201 @@ +--- +title: "Indigenous Nations Stand Against UCP Authoritarianism" +date: 2025-05-29 +authors: + - Alberta Democracy Taskforce +categories: + - Analysis + - Indigenous Rights + - Bill 54 +tags: + - Treaty rights + - sovereignty + - First Nations + - separation +--- + +# Indigenous Nations Stand Against UCP Authoritarianism + +## Treaty Rights Under Attack Through Bill 54's Separation Referendum Provisions + +The voices of Indigenous Nations across Alberta have been clear and unified: Bill 54 represents a direct threat to Treaty rights and Indigenous sovereignty. From the Confederacy of Treaty 6 First Nations to Cold Lake First Nations, Indigenous leaders are sounding the alarm about the UCP's dangerous agenda. + + + +## Treaty Rights Are Not Negotiable + +### The Indigenous Response + +As Chief Kelsey Jacko of Cold Lake First Nations declared: **"Our treaty is not negotiable; it never was and never will be."** + +This statement cuts to the heart of why Bill 54's referendum provisions are so dangerous. The legislation makes it easier to put separation questions on the ballot—but Treaties were signed with the Crown, not with individual provinces. + +### What Treaties Protect + +Indigenous Treaties in Alberta protect: + +- **Inherent sovereignty** that predates and supersedes provincial authority +- **Land rights** that cannot be extinguished by provincial legislation +- **Self-governance** independent of provincial political whims +- **Federal obligations** that provinces cannot override +- **Cultural and spiritual practices** protected by constitutional law + +### The Threat of Separation + +Bill 54's lowered threshold for citizen-initiated referendums creates a pathway for separation questions that could: + +- **Undermine federal Treaty obligations** by weakening the Crown's capacity to fulfill commitments +- **Create legal uncertainty** about Treaty enforcement in a separated Alberta +- **Expose Indigenous Nations** to even more aggressive provincial interference +- **Violate the principle** that Treaties cannot be altered without Indigenous consent + +## The Broader Pattern of UCP Authoritarianism + +### Historical Context + +Indigenous peoples in Alberta have experience with authoritarian governments that: + +- Imposed residential schools to destroy Indigenous cultures +- Passed laws restricting Indigenous movement and governance +- Seized Indigenous lands without consent +- Used legislation to undermine Treaty rights + +The UCP's current approach echoes these historical patterns of colonial control. + +### Current Attacks + +Beyond Bill 54, the UCP has: + +- **Ignored Indigenous consultation** on resource projects +- **Undermined Indigenous education** funding and programming +- **Attacked Indigenous environmental activism** through anti-protest legislation +- **Failed to implement** calls to action from the Truth and Reconciliation Commission + +## Democratic Solidarity + +### Standing Together + +The Indigenous opposition to Bill 54 provides crucial leadership for all Albertans concerned about democracy. Indigenous Nations understand that: + +- **Treaty rights** protect not just Indigenous peoples but set important limits on government power +- **Indigenous sovereignty** offers a model for community self-determination +- **Collective resistance** to authoritarianism benefits everyone +- **Constitutional rights** must be defended through unified action + +### Learning from Indigenous Leadership + +Non-Indigenous Albertans can learn from Indigenous approaches to defending rights: + +**Long-term thinking:** Indigenous Nations plan for seven generations, not just election cycles +**Collective action:** Indigenous politics emphasizes community consensus and collective wellbeing +**Principled resistance:** Indigenous movements maintain clear values even under pressure +**Constitutional awareness:** Indigenous leaders understand the legal foundations of rights protection + +## The UCP's Dangerous Game + +### Playing with Separation + +The UCP's flirtation with separation rhetoric serves multiple authoritarian purposes: + +- **Distracts** from failures in healthcare, education, and economic management +- **Mobilizes** their base around grievance politics rather than policy solutions +- **Creates crisis** that can justify extraordinary measures +- **Undermines** federal institutions that provide checks on provincial power + +### Threatening Indigenous Nations + +For Indigenous Nations, separation talk represents: + +- **Existential threat** to Treaty relationships with the federal Crown +- **Legal uncertainty** about the status of Treaties in a separated Alberta +- **Potential exposure** to even more aggressive provincial control +- **Violation** of the principle that Treaties cannot be altered without consent + +## Building Alliances + +### Indigenous-Settler Solidarity + +The fight against Bill 54 requires authentic alliances between Indigenous and non-Indigenous Albertans based on: + +**Mutual respect** for Indigenous sovereignty and Treaty rights + +**Shared opposition** to authoritarianism and corporate control + +**Common interest** in democratic institutions that serve communities + +**Recognition** that Indigenous rights strengthen everyone's rights + +### Supporting Indigenous Leadership + +Non-Indigenous allies can support Indigenous-led resistance by: + +- **Amplifying Indigenous voices** rather than speaking for Indigenous communities +- **Learning** about Treaty history and Indigenous legal traditions +- **Supporting** Indigenous organizations financially and politically +- **Challenging** colonial attitudes in their own communities +- **Following** Indigenous leadership on issues affecting Indigenous rights + +## The Path Forward + +### Legal Strategies + +Indigenous Nations have unique legal tools to challenge Bill 54: + +- **Treaty rights** that supersede provincial legislation +- **Constitutional protection** under Section 35 +- **Fiduciary relationship** with the federal Crown +- **International law** protecting Indigenous rights + +### Political Mobilization + +Indigenous political organization provides a model for broader resistance: + +- **Grassroots organizing** rooted in community relationships +- **Clear principles** that don't compromise on fundamental rights +- **Coalition building** across different Nations and communities +- **Long-term strategy** focused on systemic change + +### Building Power + +The Indigenous response to Bill 54 shows how to build real political power: + +- **Cultural grounding** in values that can't be bought or sold +- **Institutional knowledge** of legal and political systems +- **Community accountability** that keeps leaders connected to their base +- **Intergenerational perspective** that prioritizes long-term sustainability + +## Lessons for the Broader Movement + +### What We Can Learn + +The Indigenous opposition to Bill 54 teaches the broader democratic movement: + +**Rights are not gifts** from government—they exist independently and must be defended +**Collective action** is more powerful than individual resistance +**Legal strategy** must be combined with political mobilization +**Long-term vision** is essential for sustained resistance +**Cultural values** provide the foundation for political action + +### Building Solidarity + +Effective solidarity with Indigenous Nations requires: +- **Respect** for Indigenous sovereignty and leadership +- **Education** about Treaty history and Indigenous law +- **Action** supporting Indigenous-led initiatives +- **Accountability** to Indigenous communities in our work + +## Conclusion + +The unified Indigenous opposition to Bill 54 represents some of the strongest leadership in the fight for democracy in Alberta. Indigenous Nations understand the stakes because they have the most experience with colonial authoritarianism. + +Their clear stance—that Treaties are not negotiable and that separation threatens Indigenous sovereignty—provides a principled foundation for broader resistance to the UCP's anti-democratic agenda. + +For non-Indigenous Albertans, supporting Indigenous leadership in this fight isn't just the right thing to do—it's strategically essential. Indigenous Nations have the legal tools, political experience, and moral authority to lead the challenge to Bill 54. + +**When Indigenous Nations lead the fight for rights and democracy, all Albertans benefit.** + +The question for non-Indigenous Albertans is simple: Will we follow Indigenous leadership in defending democracy, or will we allow the UCP to undermine the constitutional foundations that protect all our rights? + +--- + +*This analysis draws on public statements from Indigenous Nations across Alberta opposing Bill 54. For full documentation, see our [archive](../../archive/index.md).* diff --git a/mkdocs/docs/blog/posts/municipal-democracy-under-attack.md b/mkdocs/docs/blog/posts/municipal-democracy-under-attack.md new file mode 100644 index 0000000..2e492f6 --- /dev/null +++ b/mkdocs/docs/blog/posts/municipal-democracy-under-attack.md @@ -0,0 +1,331 @@ +--- +title: "Defending Local Democracy Against UCP Centralization" +date: 2025-05-29 +authors: + - Alberta Democracy Taskforce +categories: + - Analysis + - Municipal Democracy + - Bill 54 + - Bill 20 +tags: + - local democracy + - municipal autonomy + - centralization + - community control +--- + +# Defending Local Democracy Against UCP Centralization + +## How the UCP is Destroying Community Self-Governance + +The UCP's assault on democracy extends far beyond provincial elections. Through Bill 54 and the earlier Bill 20, the Smith government is systematically dismantling local democratic control and centralizing power in the Premier's office. This represents one of the most dangerous aspects of their authoritarian agenda. + + + +## The Attack on Municipal Autonomy + +### Bill 20: The Foundation of Municipal Control + +Before Bill 54, the UCP laid the groundwork for municipal control through Bill 20, which gave cabinet unprecedented power over local governments: + +- **Power to fire mayors and councillors** without cause +- **Authority to overturn municipal bylaws** that displease the province +- **Control over municipal boundaries** and administrative structures +- **Veto power over municipal decisions** on any issue + +### Bill 54: Completing the Takeover + +Bill 54 builds on this foundation by introducing **political parties to municipal elections** for the first time in Alberta history. This seemingly small change has enormous implications for local democracy. + +## Why Non-Partisan Local Elections Matter + +### The Traditional Alberta Approach + +Municipal elections in Alberta have historically been non-partisan because: + +**Local issues don't follow party lines:** + +- Road maintenance, water systems, and garbage collection aren't "conservative" or "progressive" +- Zoning decisions should be based on community needs, not partisan ideology +- Local budgets require practical solutions, not ideological positions + +**Community-based representation:** + +- Councillors could focus on their neighborhoods rather than party discipline +- Voters could evaluate candidates based on local knowledge and commitment +- Decision-making could be collaborative rather than adversarial + +**Reduced outside influence:** + +- Candidates relied on local support rather than party fundraising +- Policy platforms reflected community priorities rather than provincial agendas +- Local business interests couldn't hide behind party affiliations + +### What Partisan Elections Will Destroy + +**Community consensus-building:** +Instead of working together on local issues, councillors will be divided by party lines imported from provincial and federal politics. + +**Local accountability:** +Councillors will answer to party leadership rather than their neighborhoods, reducing responsiveness to community concerns. + +**Independent decision-making:** +Municipal decisions will be influenced by provincial party priorities rather than local needs and circumstances. + +**Grassroots participation:** +Local politics will become dominated by party organizations rather than community groups and neighborhood associations. + +## The Corporate Connection + +### How Big Money Invades Local Politics + +The combination of partisan municipal elections and corporate donations up to $5,000 per entity creates a perfect storm for corporate control: + +**Development Industry Capture:** + +- Real estate developers can donate heavily to pro-development candidates +- Municipal planning becomes subject to corporate influence rather than community input +- Environmental protections are weakened by corporate-backed councillors + +**Resource Industry Influence:** + +- Oil and gas companies can influence municipal decisions on pipelines and facilities +- Environmental assessments become subject to corporate pressure +- Community opposition to industrial projects faces well-funded opposition + +**Chain Store and Big Box Dominance:** + +- Large retailers can influence zoning decisions to favor big box developments +- Local business interests are overwhelmed by corporate campaign spending +- Downtown revitalization efforts face opposition from suburban developers + +### Case Study: What This Looks Like + +Imagine a municipal election in a mid-sized Alberta city: + +**Before Bill 54:** + +- Local candidates run on platforms addressing traffic, housing, and community services +- A local small business owner runs against a retired teacher and a community volunteer +- Campaigns focus on door-to-door canvassing and community forums +- Funding comes from small local donations and volunteer effort + +**After Bill 54:** + +- Candidates must align with UCP or NDP to access party resources +- A developer-backed UCP candidate faces an environmentalist NDP candidate +- Campaigns are funded by corporate donations and run by party organizers +- Local issues become proxy battles for provincial political conflicts + +The community loses local representation and gains partisan division. + +## The Rural-Urban Divide Strategy + +### Dividing Communities Against Each Other + +The UCP's municipal strategy deliberately exploits and amplifies rural-urban tensions: + +**In Rural Areas:** + +- UCP-affiliated candidates campaign against "urban elites" and "environmental extremists" +- Local agricultural concerns are subordinated to resource extraction industry interests +- Traditional rural independence is replaced by partisan conformity +- Federal and provincial grievances are imported into local elections + +**In Urban Areas:** + +- Corporate-backed candidates oppose transit, affordable housing, and environmental initiatives +- Suburban development interests are pitted against urban intensification +- Municipal climate action becomes a partisan issue rather than practical planning +- Progressive policies face coordinated opposition funded by corporate interests + +### The Real Winners and Losers + +**Winners:** + +- **Corporate donors** who can buy influence at the local level +- **Provincial party organizers** who gain control over municipal agendas +- **Development industry** facing less community resistance to projects +- **Resource extraction companies** with municipal allies against environmental regulation + +**Losers:** + +- **Local communities** losing control over their own governance +- **Small businesses** unable to compete with corporate-backed candidates +- **Environmental groups** facing well-funded opposition at every level +- **Working families** whose neighborhood concerns are ignored in favor of donor interests + +## Historical Context: The Importance of Local Democracy + +### Learning from History + +Strong local democracy has historically been crucial for: + +**Economic Development:** + +- Community-controlled development that benefits local residents +- Support for local businesses and cooperative enterprises +- Investment in infrastructure that serves community needs + +**Social Progress:** + +- Municipal leadership on issues like public health and education +- Local innovation in social programs and community services +- Protection of marginalized communities through local policy + +**Environmental Protection:** + +- Community-based environmental stewardship +- Local resistance to harmful industrial projects +- Municipal climate action and sustainability initiatives + +**Democratic Participation:** + +- Training ground for civic engagement and political participation +- Accessible entry point for working-class and marginalized candidates +- Laboratory for democratic innovation and community organizing + +### International Examples + +Around the world, strong local democracy has been essential for: + +- **Participatory budgeting** in Brazil and Spain +- **Community land trusts** in the UK and US +- **Municipal socialism** in cities like Preston, Barcelona, and Jackson +- **Indigenous self-governance** in communities worldwide + +## The Social Democratic Alternative + +### What Democratic Municipal Reform Looks Like + +**Protecting Municipal Autonomy:** + +- Constitutional protection for municipal self-governance +- Limits on provincial interference in local decisions +- Guaranteed municipal revenue sources independent of provincial control + +**Expanding Democratic Participation:** + +- **Proportional representation** in municipal elections +- **Participatory budgeting** for community priorities +- **Citizens' assemblies** on major local issues +- **Neighborhood councils** with real decision-making power + +**Getting Money Out of Local Politics:** + +- **Public financing** of municipal campaigns +- **Strict limits** on donations from any source +- **Real-time disclosure** of campaign contributions +- **Strong enforcement** of campaign finance rules + +**Community-Controlled Development:** + +- **Community land trusts** to prevent speculation +- **Inclusionary zoning** for affordable housing +- **Local procurement** policies supporting community businesses +- **Environmental assessment** with meaningful community input + +### Examples of Democratic Municipal Innovation + +**Porto Alegre, Brazil:** +Participatory budgeting allows residents to directly decide municipal spending priorities through neighborhood assemblies and city-wide votes. + +**Barcelona, Spain:** +"Barcelona en Comú" created a municipal platform that combines neighborhood activism with city-wide governance, prioritizing housing rights and environmental justice. + +**Preston, England:** +"Community wealth building" policies redirect municipal spending to local cooperatives and social enterprises, keeping money circulating in the community. + +**Jackson, Mississippi:** +The "Jackson Plan" combines electoral organizing with cooperative economic development and community land trusts. + +## Fighting Back: Strategies for Local Democracy + +### Legal Resistance + +- **Constitutional challenges** to Bills 20 and 54 +- **Court injunctions** against provincial interference in municipal decisions +- **Support for municipalities** defending their autonomy through legal action + +### Electoral Strategy + +- **Support non-partisan candidates** committed to community representation +- **Run candidates** who prioritize local concerns over party politics +- **Build local coalitions** that transcend provincial party lines +- **Organize voter education** about the importance of local democracy + +### Community Organizing + +- **Strengthen neighborhood associations** and community groups +- **Create participatory processes** for municipal decision-making +- **Build local coalitions** around specific community issues +- **Develop alternative economic institutions** like cooperatives and land trusts + +### Policy Advocacy + +- **Demand municipal autonomy protection** in provincial legislation +- **Support proportional representation** and other democratic reforms +- **Advocate for campaign finance reform** at the municipal level +- **Push for participatory budgeting** and other community engagement tools + +## Building the Movement + +### Coalition Building +The fight for local democracy requires unity among: + +- **Neighborhood associations** defending community character +- **Environmental groups** protecting local ecosystems +- **Small businesses** opposing corporate dominance +- **Housing advocates** fighting for affordable communities +- **Workers' organizations** supporting democratic participation + +### Community Education + +- **Workshops** on municipal government and how to get involved +- **Forums** connecting local issues to broader democratic concerns +- **Training** in community organizing and political engagement +- **Media** highlighting the importance of local democracy + +### Direct Action + +- **Attending council meetings** and participating in public comment +- **Organizing petitions** and community campaigns on local issues +- **Peaceful protests** against anti-democratic provincial interference +- **Community forums** creating space for democratic participation + +## The Stakes for Communities + +### What We Stand to Lose + +- **Community control** over development and growth +- **Environmental protection** based on local knowledge and values +- **Affordable housing** and supports for working families +- **Local business** and cooperative economic development +- **Democratic participation** accessible to ordinary residents + +### What We Can Win + +- **Real community power** over local decisions +- **Sustainable development** that serves residents rather than developers +- **Economic democracy** through cooperatives and community ownership +- **Environmental justice** protecting local ecosystems and public health +- **Inclusive governance** that centers marginalized voices + +## Conclusion + +The UCP's attack on local democracy through Bills 20 and 54 represents an existential threat to community self-governance in Alberta. By centralizing power and introducing corporate money into municipal politics, they are destroying the foundations of democratic participation at the most accessible level. + +But communities across Alberta are fighting back. From Indigenous Nations asserting sovereignty to municipalities defending autonomy to neighborhood groups organizing for community control, the movement for local democracy is growing. + +**The future of our communities depends on defending local democracy today.** + +Municipal elections may seem small compared to provincial and federal politics, but they're where democracy is most real and immediate for most people. They're where we decide how our neighborhoods grow, how our tax dollars are spent, and what kind of communities we want to live in. + +The UCP wants to take that power away from communities and give it to corporations and party organizations. We can't let that happen. + +**Local democracy is the foundation of all democracy. If we lose it at the community level, we lose it everywhere.** + +--- + +*This analysis draws on municipal democracy research and the documented impacts of Bills 20 and 54. For more information, see our [resources](../../resources.md) page and [archive](../../archive/index.md).* diff --git a/mkdocs/docs/cm-lite/index.md b/mkdocs/docs/cm-lite/index.md new file mode 100644 index 0000000..ca8cd62 --- /dev/null +++ b/mkdocs/docs/cm-lite/index.md @@ -0,0 +1,74 @@ +# Welcome to Changemaker Lite + + + +A streamlined, self-hosted platform for documentation and development. + +## Quick Start + +Get up and running in minutes: + +```bash +# Clone the repository +git clone https://gitea.bnkhome.org/admin/changemaker.lite.git +cd changemaker.lite + +# Configure environment +./config.sh + +# Start all services +docker compose up -d +``` + +## Contributing to This Platform + +This Changemaker Lite setup is actively used by the Alberta Democracy Taskforce and welcomes contributions from the community. Whether you want to improve the platform itself or use it for your own organization's needs, we'd love your input. + +**Get involved:** +- Report issues or suggest improvements +- Contribute code enhancements +- Share how you've adapted it for your needs +- Help make collaborative documentation easier for everyone + +See our [contributing guide](../contributing/index.md) to get started, or dive directly into the [repository](https://git.albertademocracytaskforce.org/admin/ab.dem.tf.changemaker.git). + +## Services + +Changemaker Lite includes these essential services: + +- **[Homepage](services/homepage.md)** (Port 3010) - Service dashboard and monitoring +- **[Code Server](services/code-server.md)** (Port 8888) - VS Code in your browser +- **[MkDocs](services/mkdocs.md)** (Port 4000) - Documentation with live preview +- **[Static Server](services/static-server.md)** (Port 4001) - Built site hosting +- **[Listmonk](services/listmonk.md)** (Port 9000) - Newsletter management +- **[PostgreSQL](services/postgresql.md)** (Port 5432) - Database backend +- **[n8n](services/n8n.md)** (Port 5678) - Workflow automation +- **[NocoDB](services/nocodb.md)** (Port 8090) - No-code database platform + +## Getting Started + +1. **Documentation**: Start writing in [Code Server](http://localhost:8888) +2. **Preview**: See live changes at [MkDocs](http://localhost:4000) +3. **Production**: View built site at [Static Server](http://localhost:4001) +4. **Email**: Set up campaigns with [Listmonk](http://localhost:9000) +5. **Automation**: Create workflows in [n8n](http://localhost:5678) + +## Project Structure + +``` +changemaker.lite/ +├── docker-compose.yml # Service definitions +├── config.sh # Setup script +├── mkdocs/ # Documentation source +│ ├── docs/ # Markdown files +│ └── mkdocs.yml # Configuration +├── configs/ # Service configurations +└── assets/ # Shared assets +``` + +## Learn More + +- [Services Overview](services/index.md) - Detailed service documentation +- [Blog](../blog/index.md) - Updates and tutorials +- [Git Repository](https://git.albertademocracytaskforce.org/admin/ab.dem.tf.changemaker.git) - Source code and issues +- [Contributing Guide](../contributing/index.md) - How to get involved diff --git a/mkdocs/docs/cm-lite/services/code-server.md b/mkdocs/docs/cm-lite/services/code-server.md new file mode 100644 index 0000000..82bd67c --- /dev/null +++ b/mkdocs/docs/cm-lite/services/code-server.md @@ -0,0 +1,59 @@ +# Code Server + +Visual Studio Code in your browser for remote development. + +## Overview + +Code Server provides a full Visual Studio Code experience in your web browser, allowing you to develop from any device. It runs on your server and provides access to your development environment through a web interface. + +## Features + +- Full VS Code experience in the browser +- Extensions support +- Terminal access +- Git integration +- File editing and management +- Multi-language support + +## Access + +- **Default Port**: 8888 +- **URL**: `http://localhost:8888` +- **Default Workspace**: `/home/coder/mkdocs/` + +## Configuration + +### Environment Variables + +- `DOCKER_USER`: The user to run code-server as (default: `coder`) +- `DEFAULT_WORKSPACE`: Default workspace directory +- `USER_ID`: User ID for file permissions +- `GROUP_ID`: Group ID for file permissions + +### Volumes + +- `./configs/code-server/.config`: VS Code configuration +- `./configs/code-server/.local`: Local data +- `./mkdocs`: Main workspace directory + +## Usage + +1. Access Code Server at `http://localhost:8888` +2. Open the `/home/coder/mkdocs/` workspace +3. Start editing your documentation files +4. Install extensions as needed +5. Use the integrated terminal for commands + +## Useful Extensions + +Consider installing these extensions for better documentation work: + +- Markdown All in One +- Material Design Icons +- GitLens +- Docker +- YAML + +## Official Documentation + +For more detailed information, visit the [official Code Server documentation](https://coder.com/docs/code-server). diff --git a/mkdocs/docs/cm-lite/services/homepage.md b/mkdocs/docs/cm-lite/services/homepage.md new file mode 100644 index 0000000..c597aa0 --- /dev/null +++ b/mkdocs/docs/cm-lite/services/homepage.md @@ -0,0 +1,199 @@ +# Homepage + +Modern dashboard for accessing all your self-hosted services. + +## Overview + +Homepage is a modern, fully static, fast, secure fully configurable application dashboard with integrations for over 100 services. It provides a beautiful and customizable interface to access all your Changemaker Lite services from a single location. + +## Features + +- **Service Dashboard**: Central hub for all your applications +- **Docker Integration**: Automatic service discovery and monitoring +- **Customizable Layout**: Flexible grid-based layout system +- **Service Widgets**: Live status and metrics for services +- **Quick Search**: Fast navigation with built-in search +- **Bookmarks**: Organize frequently used links +- **Dark/Light Themes**: Multiple color schemes available +- **Responsive Design**: Works on desktop and mobile devices + +## Access + +- **Default Port**: 3010 +- **URL**: `http://localhost:3010` +- **Configuration**: YAML-based configuration files + +## Configuration + +### Environment Variables + +- `HOMEPAGE_PORT`: External port mapping (default: 3010) +- `PUID`: User ID for file permissions (default: 1000) +- `PGID`: Group ID for file permissions (default: 1000) +- `TZ`: Timezone setting (default: Etc/UTC) +- `HOMEPAGE_ALLOWED_HOSTS`: Allowed hosts for the dashboard + +### Configuration Files + +Homepage uses YAML configuration files located in `./configs/homepage/`: + +- `settings.yaml`: Global settings and theme configuration +- `services.yaml`: Service definitions and widgets +- `bookmarks.yaml`: Bookmark categories and links +- `widgets.yaml`: Dashboard widgets configuration +- `docker.yaml`: Docker integration settings + +### Volumes + +- `./configs/homepage:/app/config`: Configuration files +- `./assets/icons:/app/public/icons`: Custom service icons +- `./assets/images:/app/public/images`: Background images and assets +- `/var/run/docker.sock:/var/run/docker.sock`: Docker socket for container monitoring + +## Changemaker Lite Services + +Homepage is pre-configured with all Changemaker Lite services: + +### Essential Tools +- **Code Server** (Port 8888): VS Code in the browser +- **Listmonk** (Port 9000): Newsletter & mailing list manager +- **NocoDB** (Port 8090): No-code database platform + +### Content & Documentation +- **MkDocs** (Port 4000): Live documentation server +- **Static Site** (Port 4001): Built documentation hosting + +### Automation & Data +- **n8n** (Port 5678): Workflow automation platform +- **PostgreSQL** (Port 5432): Database backends + +## Customization + +### Adding Custom Services + +Edit `configs/homepage/services.yaml` to add new services: + +```yaml +- Custom Category: + - My Service: + href: http://localhost:8080 + description: Custom service description + icon: mdi-application + widget: + type: ping + url: http://localhost:8080 +``` + +### Custom Icons + +Add custom icons to `./assets/icons/` directory and reference them in services.yaml: + +```yaml +icon: /icons/my-custom-icon.png +``` + +### Themes and Styling + +Modify `configs/homepage/settings.yaml` to customize appearance: + +```yaml +theme: dark # or light +color: purple # slate, gray, zinc, neutral, stone, red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose +``` + +### Widgets + +Enable live monitoring widgets in `configs/homepage/services.yaml`: + +```yaml +- Service Name: + widget: + type: docker + container: container-name + server: my-docker +``` + +## Service Monitoring + +Homepage can display real-time status information for your services: + +- **Docker Integration**: Container status and resource usage +- **HTTP Ping**: Service availability monitoring +- **Custom APIs**: Integration with service-specific APIs + +## Docker Integration + +Homepage monitors Docker containers automatically when configured: + +1. Ensure Docker socket is mounted (`/var/run/docker.sock`) +2. Configure container mappings in `docker.yaml` +3. Add widget configurations to `services.yaml` + +## Security Considerations + +- Homepage runs with limited privileges +- Configuration files should have appropriate permissions +- Consider network isolation for production deployments +- Use HTTPS for external access +- Regularly update the Homepage image + +## Troubleshooting + +### Common Issues + +**Configuration not loading**: Check YAML syntax in configuration files +```bash +docker logs homepage-changemaker +``` + +**Icons not displaying**: Verify icon paths and file permissions +```bash +ls -la ./assets/icons/ +``` + +**Services not reachable**: Verify network connectivity between containers +```bash +docker exec homepage-changemaker ping service-name +``` + +**Widget data not updating**: Check Docker socket permissions and container access +```bash +docker exec homepage-changemaker ls -la /var/run/docker.sock +``` + +## Configuration Examples + +### Basic Service Widget + +```yaml +- Code Server: + href: http://localhost:8888 + description: VS Code in the browser + icon: code-server + widget: + type: docker + container: code-server-changemaker +``` + +### Custom Dashboard Layout + +```yaml +# settings.yaml +layout: + style: columns + columns: 3 + +# Responsive breakpoints +responsive: + mobile: 1 + tablet: 2 + desktop: 3 +``` + +## Official Documentation + +For comprehensive configuration guides and advanced features: +- [Homepage Documentation](https://gethomepage.dev/) +- [GitHub Repository](https://github.com/gethomepage/homepage) +- [Configuration Examples](https://gethomepage.dev/configs/) +- [Widget Integrations](https://gethomepage.dev/widgets/) diff --git a/mkdocs/docs/cm-lite/services/index.md b/mkdocs/docs/cm-lite/services/index.md new file mode 100644 index 0000000..9bfc21b --- /dev/null +++ b/mkdocs/docs/cm-lite/services/index.md @@ -0,0 +1,168 @@ +# Services + +Changemaker Lite includes several powerful services that work together to provide a complete documentation and development platform. Each service is containerized and can be accessed through its dedicated port. + +## Available Services + +### [Code Server](code-server.md) +**Port: 8888** | Visual Studio Code in your browser for remote development +- Full IDE experience +- Extensions support +- Git integration +- Terminal access + +### [Listmonk](listmonk.md) +**Port: 9000** | Self-hosted newsletter and mailing list manager +- Email campaigns +- Subscriber management +- Analytics +- Template system + +### [PostgreSQL](postgresql.md) +**Port: 5432** | Reliable database backend +- Data persistence for Listmonk +- ACID compliance +- High performance +- Backup and restore capabilities + +### [MkDocs Material](mkdocs.md) +**Port: 4000** | Documentation site generator with live preview +- Material Design theme +- Live reload +- Search functionality +- Markdown support + +### [Static Site Server](static-server.md) +**Port: 4001** | Nginx-powered static site hosting +- High-performance serving +- Built documentation hosting +- Caching and compression +- Security headers + +### [n8n](n8n.md) +**Port: 5678** | Workflow automation tool +- Visual workflow editor +- 400+ integrations +- Custom code execution +- Webhook support + +### [NocoDB](nocodb.md) +**Port: 8090** | No-code database platform +- Smart spreadsheet interface +- Form builder and API generation +- Real-time collaboration +- Multi-database support + +### [Homepage](homepage.md) +**Port: 3010** | Modern dashboard for all services +- Service dashboard and monitoring +- Docker integration +- Customizable layout +- Quick search and bookmarks + +## Service Architecture + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Homepage │ │ Code Server │ │ MkDocs │ +│ :3010 │ │ :8888 │ │ :4000 │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Static Server │ │ Listmonk │ │ n8n │ +│ :4001 │ │ :9000 │ │ :5678 │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ NocoDB │ │ PostgreSQL │ │ PostgreSQL │ +│ :8090 │ │ (listmonk-db) │ │ (root_db) │ +└─────────────────┘ │ :5432 │ │ :5432 │ + │ └─────────────────┘ └─────────────────┘ + └──────────────────────────────────────────────────────┘ +``` + +## Getting Started + +1. **Start all services**: `docker compose up -d` +2. **Check service status**: `docker compose ps` +3. **View logs**: `docker compose logs [service-name]` +4. **Stop services**: `docker compose down` + +## Service Dependencies + +- **Listmonk** depends on **PostgreSQL** (listmonk-db) +- **NocoDB** depends on **PostgreSQL** (root_db) +- **Static Server** serves content built by **MkDocs** +- **n8n** can integrate with all other services +- All services share the `changemaker` network + +## Environment Configuration + +Services are configured through environment variables in your `.env` file: + +```env +# Port configurations +CODE_SERVER_PORT=8888 +LISTMONK_PORT=9000 +LISTMONK_DB_PORT=5432 +MKDOCS_PORT=4000 +MKDOCS_SITE_SERVER_PORT=4001 +N8N_PORT=5678 + +# User and group IDs +USER_ID=1000 +GROUP_ID=1000 + +# Database configuration +POSTGRES_USER=listmonk +POSTGRES_PASSWORD=your_password +POSTGRES_DB=listmonk + +# n8n configuration +N8N_ENCRYPTION_KEY=your_encryption_key +N8N_USER_EMAIL=admin@example.com +N8N_USER_PASSWORD=your_password +``` + +## Monitoring and Maintenance + +### Health Checks +```bash +# Check all services +docker compose ps + +# Check specific service logs +docker compose logs listmonk-app +docker compose logs code-server +``` + +### Updates +```bash +# Pull latest images +docker compose pull + +# Restart with new images +docker compose down && docker compose up -d +``` + +### Backups +- **PostgreSQL**: Regular database backups +- **n8n**: Export workflows and credentials +- **Code Server**: Backup configuration and workspace +- **MkDocs**: Version control your documentation + +## Troubleshooting + +### Common Issues + +1. **Port Conflicts**: Ensure ports are not used by other applications +2. **Permission Issues**: Check `USER_ID` and `GROUP_ID` settings +3. **Network Issues**: Verify services can communicate through the `changemaker` network +4. **Data Persistence**: Ensure volumes are properly mounted + +### Getting Help + +- Check individual service documentation +- Review container logs for error messages +- Verify environment variable configuration +- Test network connectivity between services diff --git a/mkdocs/docs/cm-lite/services/listmonk.md b/mkdocs/docs/cm-lite/services/listmonk.md new file mode 100644 index 0000000..e0d51c5 --- /dev/null +++ b/mkdocs/docs/cm-lite/services/listmonk.md @@ -0,0 +1,66 @@ +# Listmonk + +Self-hosted newsletter and mailing list manager. + +## Overview + +Listmonk is a modern, feature-rich newsletter and mailing list manager designed for high performance and easy management. It provides a complete solution for email campaigns, subscriber management, and analytics. + +## Features + +- Newsletter and email campaign management +- Subscriber list management +- Template system with HTML/markdown support +- Campaign analytics and tracking +- API for integration +- Multi-list support +- Bounce handling +- Privacy-focused design + +## Access + +- **Default Port**: 9000 +- **URL**: `http://localhost:9000` +- **Admin User**: Set via `LISTMONK_ADMIN_USER` environment variable +- **Admin Password**: Set via `LISTMONK_ADMIN_PASSWORD` environment variable + +## Configuration + +### Environment Variables + +- `LISTMONK_ADMIN_USER`: Admin username +- `LISTMONK_ADMIN_PASSWORD`: Admin password +- `POSTGRES_USER`: Database username +- `POSTGRES_PASSWORD`: Database password +- `POSTGRES_DB`: Database name + +### Database + +Listmonk uses PostgreSQL as its backend database. The database is automatically configured through the docker-compose setup. + +### Uploads + +- Upload directory: `./assets/uploads` +- Used for media files, templates, and attachments + +## Getting Started + +1. Access Listmonk at `http://localhost:9000` +2. Log in with your admin credentials +3. Set up your first mailing list +4. Configure SMTP settings for sending emails +5. Import subscribers or create subscription forms +6. Create your first campaign + +## Important Notes + +- Configure SMTP settings before sending emails +- Set up proper domain authentication (SPF, DKIM) for better deliverability +- Regularly backup your subscriber data and campaigns +- Monitor bounce rates and maintain list hygiene + +## Official Documentation + +For comprehensive guides and API documentation, visit: +- [Listmonk Documentation](https://listmonk.app/docs/) +- [GitHub Repository](https://github.com/knadh/listmonk) diff --git a/mkdocs/docs/cm-lite/services/mkdocs.md b/mkdocs/docs/cm-lite/services/mkdocs.md new file mode 100644 index 0000000..c7a397a --- /dev/null +++ b/mkdocs/docs/cm-lite/services/mkdocs.md @@ -0,0 +1,124 @@ +# MkDocs Material + +Modern documentation site generator with live preview. + +## Overview + +MkDocs Material is a powerful documentation framework built on top of MkDocs, providing a beautiful Material Design theme and advanced features for creating professional documentation sites. + +## Features + +- Material Design theme +- Live preview during development +- Search functionality +- Navigation and organization +- Code syntax highlighting +- Mathematical expressions support +- Responsive design +- Customizable themes and colors + +## Access + +- **Development Port**: 4000 +- **Development URL**: `http://localhost:4000` +- **Live Reload**: Automatically refreshes on file changes + +## Configuration + +### Main Configuration + +Configuration is managed through `mkdocs.yml` in the project root. + +### Volumes + +- `./mkdocs`: Documentation source files +- `./assets/images`: Shared images directory + +### Environment Variables + +- `SITE_URL`: Base domain for the site +- `USER_ID`: User ID for file permissions +- `GROUP_ID`: Group ID for file permissions + +## Directory Structure + +``` +mkdocs/ +├── mkdocs.yml # Configuration file +├── docs/ # Documentation source +│ ├── index.md # Homepage +│ ├── services/ # Service documentation +│ ├── blog/ # Blog posts +│ └── overrides/ # Template overrides +└── site/ # Built static site +``` + +## Writing Documentation + +### Markdown Basics + +- Use standard Markdown syntax +- Support for tables, code blocks, and links +- Mathematical expressions with MathJax +- Admonitions for notes and warnings + +### Example Page + +```markdown +# Page Title + +This is a sample documentation page. + +## Section + +Content goes here with **bold** and *italic* text. + +### Code Example + +```python +def hello_world(): + print("Hello, World!") +``` + +!!! note + This is an informational note. +``` + +## Building and Deployment + +### Development + +The development server runs automatically with live reload. + +### Building Static Site + +```bash +docker exec mkdocs-changemaker mkdocs build +``` + +The built site will be available in the `mkdocs/site/` directory. + +## Customization + +### Themes and Colors + +Customize appearance in `mkdocs.yml`: + +```yaml +theme: + name: material + palette: + primary: blue + accent: indigo +``` + +### Custom CSS + +Add custom styles in `docs/stylesheets/extra.css`. + +## Official Documentation + +For comprehensive MkDocs Material documentation: +- [MkDocs Material](https://squidfunk.github.io/mkdocs-material/) +- [MkDocs Documentation](https://www.mkdocs.org/) +- [Markdown Guide](https://www.markdownguide.org/) diff --git a/mkdocs/docs/cm-lite/services/n8n.md b/mkdocs/docs/cm-lite/services/n8n.md new file mode 100644 index 0000000..07da533 --- /dev/null +++ b/mkdocs/docs/cm-lite/services/n8n.md @@ -0,0 +1,145 @@ +# n8n + +Workflow automation tool for connecting services and automating tasks. + +## Overview + +n8n is a powerful workflow automation tool that allows you to connect various apps and services together. It provides a visual interface for creating automated workflows, making it easy to integrate different systems and automate repetitive tasks. + +## Features + +- Visual workflow editor +- 400+ integrations +- Custom code execution (JavaScript/Python) +- Webhook support +- Scheduled workflows +- Error handling and retries +- User management +- API access +- Self-hosted and privacy-focused + +## Access + +- **Default Port**: 5678 +- **URL**: `http://localhost:5678` +- **Default User Email**: Set via `N8N_DEFAULT_USER_EMAIL` +- **Default User Password**: Set via `N8N_DEFAULT_USER_PASSWORD` + +## Configuration + +### Environment Variables + +- `N8N_HOST`: Hostname for n8n (default: `n8n.${DOMAIN}`) +- `N8N_PORT`: Internal port (5678) +- `N8N_PROTOCOL`: Protocol for webhooks (https) +- `NODE_ENV`: Environment (production) +- `WEBHOOK_URL`: Base URL for webhooks +- `GENERIC_TIMEZONE`: Timezone setting +- `N8N_ENCRYPTION_KEY`: Encryption key for credentials +- `N8N_USER_MANAGEMENT_DISABLED`: Enable/disable user management +- `N8N_DEFAULT_USER_EMAIL`: Default admin email +- `N8N_DEFAULT_USER_PASSWORD`: Default admin password + +### Volumes + +- `n8n_data`: Persistent data storage +- `./local-files`: Local file access for workflows + +## Getting Started + +1. Access n8n at `http://localhost:5678` +2. Log in with your admin credentials +3. Create your first workflow +4. Add nodes for different services +5. Configure connections between nodes +6. Test and activate your workflow + +## Common Use Cases + +### Documentation Automation +- Auto-generate documentation from code comments +- Sync documentation between different platforms +- Notify team when documentation is updated + +### Email Campaign Integration +- Connect Listmonk with external data sources +- Automate subscriber management +- Trigger campaigns based on events + +### Database Management with NocoDB +- Sync data between NocoDB and external APIs +- Automate data entry and validation +- Create backup workflows for database content +- Generate reports from NocoDB data + +### Development Workflows +- Auto-deploy documentation on git push +- Sync code changes with documentation +- Backup automation + +### Data Processing +- Process CSV files and import to databases +- Transform data between different formats +- Schedule regular data updates + +## Example Workflows + +### Simple Webhook to Email +``` +Webhook → Email +``` + +### Scheduled Documentation Backup +``` +Schedule → Read Files → Compress → Upload to Storage +``` + +### Git Integration +``` +Git Webhook → Process Changes → Update Documentation → Notify Team +``` + +## Security Considerations + +- Use strong encryption keys +- Secure webhook URLs +- Regularly update credentials +- Monitor workflow executions +- Implement proper error handling + +## Integration with Other Services + +n8n can integrate with all services in your Changemaker Lite setup: +- **Listmonk**: Manage subscribers and campaigns +- **PostgreSQL**: Read/write database operations +- **Code Server**: File operations and git integration +- **MkDocs**: Documentation generation and updates + +## Troubleshooting + +### Common Issues + +- **Workflow Execution Errors**: Check node configurations and credentials +- **Webhook Issues**: Verify URLs and authentication +- **Connection Problems**: Check network connectivity between services + +### Debugging + +```bash +# Check container logs +docker logs n8n-changemaker + +# Access container shell +docker exec -it n8n-changemaker sh + +# Check workflow executions in the UI +# Visit http://localhost:5678 → Executions +``` + +## Official Documentation + +For comprehensive n8n documentation: +- [n8n Documentation](https://docs.n8n.io/) +- [Community Workflows](https://n8n.io/workflows/) +- [Node Reference](https://docs.n8n.io/integrations/builtin/) +- [GitHub Repository](https://github.com/n8n-io/n8n) diff --git a/mkdocs/docs/cm-lite/services/nocodb.md b/mkdocs/docs/cm-lite/services/nocodb.md new file mode 100644 index 0000000..a1ca8d4 --- /dev/null +++ b/mkdocs/docs/cm-lite/services/nocodb.md @@ -0,0 +1,153 @@ +# NocoDB + +No-code database platform that turns any database into a smart spreadsheet. + +## Overview + +NocoDB is an open-source no-code platform that transforms any database into a smart spreadsheet interface. It provides a user-friendly way to manage data, create forms, build APIs, and collaborate on database operations without requiring extensive technical knowledge. + +## Features + +- **Smart Spreadsheet Interface**: Transform databases into intuitive spreadsheets +- **Form Builder**: Create custom forms for data entry +- **API Generation**: Auto-generated REST APIs for all tables +- **Collaboration**: Real-time collaboration with team members +- **Access Control**: Role-based permissions and sharing +- **Data Visualization**: Charts and dashboard creation +- **Webhooks**: Integration with external services +- **Import/Export**: Support for CSV, Excel, and other formats +- **Multi-Database Support**: Works with PostgreSQL, MySQL, SQLite, and more + +## Access + +- **Default Port**: 8090 +- **URL**: `http://localhost:8090` +- **Database**: PostgreSQL (dedicated `root_db` instance) + +## Configuration + +### Environment Variables + +- `NOCODB_PORT`: External port mapping (default: 8090) +- `NC_DB`: Database connection string for PostgreSQL backend + +### Database Backend + +NocoDB uses a dedicated PostgreSQL instance (`root_db`) with the following configuration: +- **Database Name**: `root_db` +- **Username**: `postgres` +- **Password**: `password` +- **Host**: `root_db` (internal container name) + +### Volumes + +- `nc_data`: Application data and configuration storage +- `db_data`: PostgreSQL database files + +## Getting Started + +1. **Access NocoDB**: Navigate to `http://localhost:8090` +2. **Initial Setup**: Complete the onboarding process +3. **Create Project**: Start with a new project or connect existing databases +4. **Add Tables**: Import data or create new tables +5. **Configure Views**: Set up different views (Grid, Form, Gallery, etc.) +6. **Set Permissions**: Configure user access and sharing settings + +## Common Use Cases + +### Content Management +- Create content databases for blogs and websites +- Manage product catalogs and inventories +- Track customer information and interactions + +### Project Management +- Task and project tracking systems +- Team collaboration workspaces +- Resource and timeline management + +### Data Collection +- Custom forms for surveys and feedback +- Event registration and management +- Lead capture and CRM systems + +### Integration with Other Services + +NocoDB can integrate well with other Changemaker Lite services: + +- **n8n Integration**: Use NocoDB as a data source/destination in automation workflows +- **Listmonk Integration**: Manage subscriber lists and campaign data +- **Documentation**: Store and manage documentation metadata + +## API Usage + +NocoDB automatically generates REST APIs for all your tables: + +```bash +# Get all records from a table +GET http://localhost:8090/api/v1/db/data/v1/{project}/table/{table} + +# Create a new record +POST http://localhost:8090/api/v1/db/data/v1/{project}/table/{table} + +# Update a record +PATCH http://localhost:8090/api/v1/db/data/v1/{project}/table/{table}/{id} +``` + +## Backup and Data Management + +### Database Backup + +Since NocoDB uses PostgreSQL, you can backup the database: + +```bash +# Backup NocoDB database +docker exec root_db pg_dump -U postgres root_db > nocodb_backup.sql + +# Restore from backup +docker exec -i root_db psql -U postgres root_db < nocodb_backup.sql +``` + +### Application Data + +Application settings and metadata are stored in the `nc_data` volume. + +## Security Considerations + +- Change default database credentials in production +- Configure proper access controls within NocoDB +- Use HTTPS for production deployments +- Regularly backup both database and application data +- Monitor access logs and user activities + +## Performance Tips + +- Regular database maintenance and optimization +- Monitor memory usage for large datasets +- Use appropriate indexing for frequently queried fields +- Consider database connection pooling for high-traffic scenarios + +## Troubleshooting + +### Common Issues + +**Service won't start**: Check if the PostgreSQL database is healthy +```bash +docker logs root_db +``` + +**Database connection errors**: Verify database credentials and network connectivity +```bash +docker exec nocodb nc_data nc +``` + +**Performance issues**: Monitor resource usage and optimize queries +```bash +docker stats nocodb root_db +``` + +## Official Documentation + +For comprehensive guides and advanced features: +- [NocoDB Documentation](https://docs.nocodb.com/) +- [GitHub Repository](https://github.com/nocodb/nocodb) +- [Community Forum](https://community.nocodb.com/) \ No newline at end of file diff --git a/mkdocs/docs/cm-lite/services/postgresql.md b/mkdocs/docs/cm-lite/services/postgresql.md new file mode 100644 index 0000000..bc55fb2 --- /dev/null +++ b/mkdocs/docs/cm-lite/services/postgresql.md @@ -0,0 +1,90 @@ +# PostgreSQL Database + +Reliable database backend for applications. + +## Overview + +PostgreSQL is a powerful, open-source relational database system. In Changemaker Lite, it serves as the backend database for Listmonk and can be used by other applications requiring persistent data storage. + +## Features + +- ACID compliance +- Advanced SQL features +- JSON/JSONB support +- Full-text search +- Extensibility +- High performance +- Reliability and data integrity + +## Access + +- **Default Port**: 5432 +- **Host**: `listmonk-db` (internal container name) +- **Database**: Set via `POSTGRES_DB` environment variable +- **Username**: Set via `POSTGRES_USER` environment variable +- **Password**: Set via `POSTGRES_PASSWORD` environment variable + +## Configuration + +### Environment Variables + +- `POSTGRES_USER`: Database username +- `POSTGRES_PASSWORD`: Database password +- `POSTGRES_DB`: Database name + +### Health Checks + +The PostgreSQL container includes health checks to ensure the database is ready before dependent services start. + +### Data Persistence + +Database data is stored in a Docker volume (`listmonk-data`) to ensure persistence across container restarts. + +## Connecting to the Database + +### From Host Machine + +You can connect to PostgreSQL from your host machine using: + +```bash +psql -h localhost -p 5432 -U [username] -d [database] +``` + +### From Other Containers + +Other containers can connect using the internal hostname `listmonk-db` on port 5432. + +## Backup and Restore + +### Backup + +```bash +docker exec listmonk-db pg_dump -U [username] [database] > backup.sql +``` + +### Restore + +```bash +docker exec -i listmonk-db psql -U [username] [database] < backup.sql +``` + +## Monitoring + +Monitor database health and performance through: +- Container logs: `docker logs listmonk-db` +- Database metrics and queries +- Connection monitoring + +## Security Considerations + +- Use strong passwords +- Regularly update PostgreSQL version +- Monitor access logs +- Implement regular backups +- Consider network isolation + +## Official Documentation + +For comprehensive PostgreSQL documentation: +- [PostgreSQL Documentation](https://www.postgresql.org/docs/) +- [Docker PostgreSQL Image](https://hub.docker.com/_/postgres) diff --git a/mkdocs/docs/cm-lite/services/static-server.md b/mkdocs/docs/cm-lite/services/static-server.md new file mode 100644 index 0000000..ecc517d --- /dev/null +++ b/mkdocs/docs/cm-lite/services/static-server.md @@ -0,0 +1,100 @@ +# Static Site Server + +Nginx-powered static site server for hosting built documentation and websites. + +## Overview + +The Static Site Server uses Nginx to serve your built documentation and static websites. It's configured to serve the built MkDocs site and other static content with high performance and reliability. + +## Features + +- High-performance static file serving +- Automatic index file handling +- Gzip compression +- Caching headers +- Security headers +- Custom error pages +- URL rewriting support + +## Access + +- **Default Port**: 4001 +- **URL**: `http://localhost:4001` +- **Document Root**: `/config/www` (mounted from `./mkdocs/site`) + +## Configuration + +### Environment Variables + +- `PUID`: User ID for file permissions (default: 1000) +- `PGID`: Group ID for file permissions (default: 1000) +- `TZ`: Timezone setting (default: Etc/UTC) + +### Volumes + +- `./mkdocs/site:/config/www`: Static site files +- Built MkDocs site is automatically served + +## Usage + +1. Build your MkDocs site: `docker exec mkdocs-changemaker mkdocs build` +2. The built site is automatically available at `http://localhost:4001` +3. Any files in `./mkdocs/site/` will be served statically + +## File Structure + +``` +mkdocs/site/ # Served at / +├── index.html # Homepage +├── assets/ # CSS, JS, images +├── services/ # Service documentation +└── search/ # Search functionality +``` + +## Performance Features + +- **Gzip Compression**: Automatic compression for text files +- **Browser Caching**: Optimized cache headers +- **Fast Static Serving**: Nginx optimized for static content +- **Security Headers**: Basic security header configuration + +## Custom Configuration + +For advanced Nginx configuration, you can: +1. Create custom Nginx config files +2. Mount them as volumes +3. Restart the container + +## Monitoring + +Monitor the static site server through: +- Container logs: `docker logs mkdocs-site-server-changemaker` +- Access logs for traffic analysis +- Performance metrics + +## Troubleshooting + +### Common Issues + +- **404 Errors**: Ensure MkDocs site is built and files exist in `./mkdocs/site/` +- **Permission Issues**: Check `PUID` and `PGID` settings +- **File Not Found**: Verify file paths and case sensitivity + +### Debugging + +```bash +# Check container logs +docker logs mkdocs-site-server-changemaker + +# Verify files are present +docker exec mkdocs-site-server-changemaker ls -la /config/www + +# Test file serving +curl -I http://localhost:4001 +``` + +## Official Documentation + +For more information about the underlying Nginx server: +- [LinuxServer.io Nginx](https://docs.linuxserver.io/images/docker-nginx) +- [Nginx Documentation](https://nginx.org/en/docs/) diff --git a/mkdocs/docs/contributing/collaboration.md b/mkdocs/docs/contributing/collaboration.md new file mode 100644 index 0000000..3b6b929 --- /dev/null +++ b/mkdocs/docs/contributing/collaboration.md @@ -0,0 +1,172 @@ +# Collaboration Best Practices + +Working effectively with others is key to successful project contribution. This guide covers how to collaborate smoothly, handle conflicts, and be a positive community member. + +## Being a Good Collaborator + +### Communicate Clearly + +- **Be specific** in your questions and descriptions +- **Use examples** when explaining problems or suggestions +- **Be patient** - people have different schedules and time zones +- **Ask for help** when you're stuck - it's better than struggling alone + +### Respect Others' Work + +- **Read existing content** before making changes to understand the current approach +- **Build on others' contributions** rather than completely replacing them +- **Give credit** when you're building on someone else's ideas +- **Discuss major changes** before implementing them + +### Stay Focused on the Mission +Remember we're all working toward the same goal: defending democracy in Alberta. Keep discussions: + +- **Constructive** rather than critical +- **Focused on the work** rather than personal preferences +- **Aligned with our values** of democratic participation and transparency + +## Working with Issues + +### Finding Work to Do + +1. Check the **Issues** tab for tasks marked "good first issue" or "help wanted" +2. Read through the description to understand what's needed +3. Comment on the issue to let others know you're working on it +4. Ask questions if anything is unclear + +### Reporting Problems +When you find a bug or have a suggestion: + +1. **Check existing issues** first to avoid duplicates +2. **Use a clear title** like "Mobile menu doesn't work on iPhone" +3. **Provide details**: + - What you expected to happen + - What actually happened + - Steps to reproduce the problem + - What browser/device you're using + +4. **Add labels** if you have permission (bug, enhancement, etc.) + +## Handling Disagreements + +### When You Disagree with Feedback +Sometimes you might disagree with a reviewer's suggestions: + +**Step 1: Understand their perspective** +- Ask clarifying questions +- Consider that they might have context you don't +- Look at how similar issues were handled before + +**Step 2: Explain your reasoning** +- Share why you made the choice you did +- Provide evidence or examples if relevant +- Be open to finding a compromise solution + +**Step 3: Involve others if needed** +- If you can't reach agreement, ask other team members for input +- Tag project maintainers for guidance +- Remember the goal is the best outcome for the project + +### When Others Disagree with You +If someone challenges your review or suggestion: + +- **Stay calm and professional** +- **Re-examine your position** - you might have missed something +- **Focus on the project's needs** rather than being "right" +- **Be willing to change your mind** when presented with good reasoning + +## Managing Merge Conflicts + +Sometimes Git can't automatically combine changes - this creates a "merge conflict." + +### Why Conflicts Happen +- Two people edited the same lines in a file +- Someone deleted a file that another person modified +- Changes were made to the same section but in different ways + +### Resolving Simple Conflicts + +1. **Don't panic** - conflicts are normal and fixable +2. **Look at the conflicted sections** - Git marks them clearly +3. **Decide which version to keep** or how to combine them +4. **Remove the conflict markers** (`<<<<<<<`, `=======`, `>>>>>>>`) +5. **Test that everything still works** +6. **Commit the resolution** + +### When to Ask for Help + +- If you're not sure which version to keep +- If the conflict involves code you didn't write +- If there are many conflicts or they seem complex +- If you're new to Git and feeling overwhelmed + +## Communication Channels + +### Where to Discuss What + +**Pull Request Comments**: For discussing specific changes in your submission + +**Issue Comments**: For general discussion about problems or improvements + +**Project Chat/Forum**: For real-time questions and community discussion + +**Email**: For private matters or when you need direct help + +### Response Time Expectations + +- **Pull request reviews**: Usually within 2-3 business days +- **Issue responses**: Within a week for non-urgent matters +- **Chat messages**: Best effort during business hours +- **Emergency fixes**: Tag maintainers for faster response + +## Building Community + +### Help Other Contributors + +- **Answer questions** when you can help +- **Review others' pull requests** if you feel confident +- **Share resources** you've found helpful +- **Welcome new contributors** and help them get started + +### Stay Engaged + +- **Follow project updates** to stay informed about changes +- **Participate in discussions** about the project's direction +- **Attend community meetings** if they're held +- **Share the project** with others who might want to contribute + +## Red Flags to Avoid + +These behaviors can harm the collaborative environment: + +- **Personal attacks** or hostile language +- **Dismissing others' contributions** without constructive feedback +- **Making unilateral decisions** about major changes +- **Ignoring established processes** without discussion +- **Taking credit** for others' work + +## Video Tutorial + +*[Administrator: Add a video tutorial showing examples of good collaboration, how to handle feedback constructively, and conflict resolution strategies]* + +## Quick Do's and Don'ts + +### Do: + +- ✅ Ask questions when unsure +- ✅ Give specific, helpful feedback +- ✅ Test your changes before submitting +- ✅ Respond to feedback promptly +- ✅ Help others when you can + +### Don't: + +- ❌ Make personal attacks or hostile comments +- ❌ Ignore project conventions without discussion +- ❌ Submit untested changes +- ❌ Take feedback personally +- ❌ Work in isolation on major changes + +## Remember + +Good collaboration makes everyone more effective and creates a positive environment where people want to contribute. By following these practices, you're not just improving the website - you're helping build a stronger community committed to defending democracy in Alberta. diff --git a/mkdocs/docs/contributing/first-edit.md b/mkdocs/docs/contributing/first-edit.md new file mode 100644 index 0000000..74e3568 --- /dev/null +++ b/mkdocs/docs/contributing/first-edit.md @@ -0,0 +1,100 @@ +# Make Your First Edit + +Ready to make your first contribution? This guide will walk you through editing a file directly in your web browser - no special software needed! + +## What You'll Do + +We'll make a simple change to practice the process. Don't worry about breaking anything - there are safeguards in place. + +## Step 1: Choose a File to Edit + +For your first edit, let's improve a page that already exists: + +1. Go to the project homepage on Gitea +2. Navigate to `mkdocs` → `docs` +3. Find a page you'd like to improve (maybe `faq.md` or create a small edit to any `.md` file) + +## Step 2: Open the Editor + +1. Click on the file you want to edit +2. Look for the **pencil icon** (✏️) and click it +3. You're now in the web editor! + +## Step 3: Understand Markdown + +The files use "Markdown" - a simple way to format text. Here are the basics: + +```markdown +# This is a big heading +## This is a smaller heading +**This text is bold** +*This text is italic* +- This is a bullet point +[This is a link](https://example.com) +``` + +## Step 4: Make Your Edit + +Let's practice with a small change: + +1. Find a paragraph you want to improve +2. Make a simple edit like: + - Fix a typo + - Add a sentence + - Improve wording +3. Don't make huge changes for your first edit - keep it simple! + +## Step 5: Preview Your Changes + +1. Click the **"Preview"** tab to see how your changes will look +2. Switch back to **"Edit"** if you want to make more changes +3. Review your work carefully + +## Step 6: Save Your Changes + +At the bottom of the page, you'll see a "Commit Changes" section: + +1. **Commit message**: Write a brief description of what you changed + - Good: "Fixed typo in FAQ section" + - Good: "Added information about voting rights" + - Not helpful: "Updated file" + +2. **Choose commit type**: + - Select "Create a new branch for this commit and start a pull request" + - This lets others review your changes before they go live + +3. Click **"Propose Changes"** + +## Step 7: Create Your Pull Request + +After clicking "Propose Changes": + +1. You'll see a "Pull Request" form +2. Add a title that describes your change +3. In the description, explain why you made the change +4. Click **"Create Pull Request"** + +Congratulations! You've submitted your first contribution! + +## What Happens Next? + +- A team member will review your changes +- They might suggest improvements or ask questions +- Once approved, your changes will appear on the live website +- You'll get notified by email about any updates + +## What's Next? + +Now that you've made your first edit, learn more about [Git Basics](git-basics.md) to understand what just happened behind the scenes. + +## Video Tutorial + +*[Administrator: Add a video tutorial showing the complete process of making an edit through the web interface]* + +## Troubleshooting + +**Can't find the pencil icon?** Make sure you're viewing a file (not a folder) and that you're logged in. + +**Preview looks wrong?** Check your Markdown syntax - missing spaces or symbols can cause formatting issues. + +**Nervous about breaking something?** Don't worry! Your changes won't go live until they're reviewed and approved. diff --git a/mkdocs/docs/contributing/getting-started.md b/mkdocs/docs/contributing/getting-started.md new file mode 100644 index 0000000..8079ae9 --- /dev/null +++ b/mkdocs/docs/contributing/getting-started.md @@ -0,0 +1,49 @@ +# Getting Started with Contributing + +Welcome to your first step in contributing to our website! This page will help you get set up with an account and understand what we're working with. + +## What is Git and Gitea? + +**Git** is a tool that helps people work together on projects by tracking changes to files. Think of it like "track changes" in Microsoft Word, but much more powerful. + +**Gitea** is a website that hosts Git projects, making it easy to share and collaborate. It's like Google Drive, but specifically designed for code and documentation projects. + +## Step 1: Create Your Account + +1. Go to **[git.albertademocracytaskforce.org](https://git.albertademocracytaskforce.org)** +2. Click the "Sign Up" button (usually in the top right corner) +3. Fill out the registration form with: + - Username (choose something professional, you'll use this for contributions) + - Email address + - Password +4. Click "Create Account" +5. Check your email for a confirmation message and click the link + +## Step 2: Find Our Project + +1. Once logged in, use the search bar to find "Alberta Democracy Taskforce" or the specific repository name +2. Click on the project to open it +3. Bookmark this page - you'll be coming back often! + +## Step 3: Understand the Project Structure + +Our website's files are organized like this: +- `mkdocs/docs/` - This is where all the website content lives +- `*.md` files - These are "Markdown" files that contain the text you see on the website +- Images and other files are in their own folders + +## What's Next? + +Now that you have an account, let's learn how to navigate around Gitea in the next section: [Navigating Gitea](navigating-gitea.md). + +## Video Tutorial + +*[Administrator: Add a video tutorial showing the account creation and project navigation process]* + +## Troubleshooting + +**Can't find the sign-up button?** Look for "Register" or "Join" instead. + +**Didn't receive a confirmation email?** Check your spam folder, or contact us for help. + +**Can't find our project?** Make sure you're logged in, and try searching for "democracy" or "taskforce". diff --git a/mkdocs/docs/contributing/git-basics.md b/mkdocs/docs/contributing/git-basics.md new file mode 100644 index 0000000..69c0d56 --- /dev/null +++ b/mkdocs/docs/contributing/git-basics.md @@ -0,0 +1,92 @@ +# Git Basics + +Now that you've made your first edit, let's understand what Git actually does and why it's so helpful for collaborative work. + +## What is Git? + +Think of Git as a sophisticated "undo" system that: + +- **Tracks every change** to every file +- **Remembers who** made each change and **when** +- **Allows multiple people** to work on the same project without conflicts +- **Keeps a complete history** so nothing is ever truly lost + +## Key Concepts (Simplified) + +### Repository ("Repo") +A repository is like a project folder that Git watches. Our website is one repository. + +### Commit +A commit is like saving a snapshot of your work. Each commit includes: + +- What files were changed +- Who made the changes +- When the changes were made +- A message describing the changes + +### Branch +A branch is like a parallel version of the project where you can make changes safely. Think of it as making a copy, editing the copy, then merging the good changes back to the original. + +### Pull Request +A pull request is like saying "Hey, I made some improvements - would you like to include them?" It's a way to propose changes and discuss them before they become part of the main project. + +## The Git Workflow (What You Just Did) + +When you made your first edit, here's what happened: + +1. **You created a branch** - A safe copy to work on +2. **You made changes** - Edited the file +3. **You committed** - Saved a snapshot with a description +4. **You created a pull request** - Asked for your changes to be reviewed +5. **Someone will review** - A team member checks your work +6. **Changes get merged** - If approved, your changes join the main project + +## Why This System Works + +### Safety + +- Multiple people can work simultaneously without breaking each other's work +- Every change is tracked, so mistakes can be undone +- Changes are reviewed before going live + +### Transparency + +- Anyone can see what changed and why +- The history shows how the project evolved +- Credit is given to each contributor + +### Collaboration + +- Team members can suggest improvements to your changes +- Discussions happen around specific edits +- Knowledge is shared through the review process + +## Common Git Terms + +| Term | Simple Explanation | +|------|-------------------| +| **Clone** | Make a copy of the entire project on your computer | +| **Fork** | Make your own copy of someone else's project | +| **Push** | Send your changes from your computer to the server | +| **Pull** | Get the latest changes from the server to your computer | +| **Merge** | Combine changes from one branch into another | +| **Conflict** | When two people changed the same thing - needs manual fixing | + +## What's Next? + +Now that you understand the basics, you can either: +- Continue making edits through the web interface (easiest) +- Learn to [Clone and Edit Locally](local-editing.md) for more advanced work + +## Video Tutorial + +*[Administrator: Add a video tutorial explaining Git concepts with visual examples and analogies]* + +## Remember + +- **Git protects you** - Your changes are safe and reviewable +- **Mistakes are fixable** - Nothing is ever permanently lost +- **Learning takes time** - Don't worry about understanding everything at once +- **Practice helps** - The more you use it, the more natural it becomes + +The most important thing to remember: Git is designed to help people work together safely. All the complexity exists to prevent problems and make collaboration possible. diff --git a/mkdocs/docs/contributing/index.md b/mkdocs/docs/contributing/index.md new file mode 100644 index 0000000..1cc3af0 --- /dev/null +++ b/mkdocs/docs/contributing/index.md @@ -0,0 +1,46 @@ + +# Contributing to the Alberta Democracy Taskforce Website + +Welcome! We're excited that you want to help improve our website and contribute to defending democracy in Alberta. This guide will walk you through everything you need to know, step by step. + + + +## What You'll Learn + +This guide is designed for complete beginners. By the end, you'll know how to: + +1. **[Get Started](getting-started.md)** - Set up your account and understand the basics +2. **[Navigate Gitea](navigating-gitea.md)** - Learn our Git hosting platform +3. **[Make Your First Edit](first-edit.md)** - Edit content directly in your browser +4. **[Use Git Basics](git-basics.md)** - Understanding version control +5. **[Clone and Edit Locally](local-editing.md)** - Work on your own computer +6. **[Submit Changes](submitting-changes.md)** - Share your improvements with the team +7. **[Collaborate Effectively](collaboration.md)** - Work with others and handle feedback + +## Our Git Server + +We use Gitea, hosted at **[git.albertademocracytaskforce.org](https://git.albertademocracytaskforce.org)**, to manage our website's source code and collaborate on changes. + +## About This Website + +This website is built using **Changemaker Lite**, an open-source platform that makes it easy for organizations to create collaborative documentation sites. The entire site - including all content, configuration, and this contribution system - can be downloaded and rebuilt on any computer. + +**Want to use this for your own organization?** You can clone the complete setup from our repository at [git.albertademocracytaskforce.org/admin/ab.dem.tf.changemaker.git](https://git.albertademocracytaskforce.org/admin/ab.dem.tf.changemaker.git). This includes everything needed to create a similar site for your cause, complete with documentation tools, email campaigns, and workflow automation. + +## No Experience Required + +Don't worry if terms like "Git", "repository", or "pull request" are unfamiliar. We'll explain everything as we go, and each page focuses on just a few simple steps you can master before moving on. + +## Video Tutorials + +*[Administrator: Add video embeds or links to video tutorials for each section here]* + +## Getting Help + +If you get stuck at any point: + +- Check the specific page for that step in this guide +- Ask questions in our community chat +- Email us at [contact email] + +Ready to get started? Let's begin with [Getting Started](getting-started.md)! diff --git a/mkdocs/docs/contributing/local-editing.md b/mkdocs/docs/contributing/local-editing.md new file mode 100644 index 0000000..792cb13 --- /dev/null +++ b/mkdocs/docs/contributing/local-editing.md @@ -0,0 +1,180 @@ +# Clone and Edit Locally + +Ready to work on your own computer? This guide will show you how to download the entire project and make changes using proper development tools. + +## Why Work Locally? + +Working on your own computer gives you: + +- **Faster editing** with better text editors +- **Offline work** capability +- **Better tools** for handling images and complex changes +- **More control** over your development environment + +## What You'll Need + +Before starting, install these free tools: + +### Step 1: Install Git + +1. Go to [git-scm.com](https://git-scm.com) +2. Download Git for your operating system +3. Install with default settings +4. Open a terminal/command prompt and type `git --version` to verify + +### Step 2: Install a Text Editor +Choose one of these beginner-friendly options: + +- **VS Code** (recommended) - [code.visualstudio.com](https://code.visualstudio.com) +- **Atom** - [atom.io](https://atom.io) +- **Sublime Text** - [sublimetext.com](https://sublimetext.com) + +### Step 3: Set Up Git +Open a terminal/command prompt and run these commands (replace with your info): + +```bash +git config --global user.name "Your Name" +git config --global user.email "your.email@example.com" +``` + +## Clone the Repository + +### Step 1: Get the Clone URL +1. Go to our project on [git.albertademocracytaskforce.org](https://git.albertademocracytaskforce.org) +2. Click the **"Clone"** button +3. Copy the HTTPS URL (it looks like: `https://git.albertademocracytaskforce.org/username/projectname.git`) + +### Step 2: Choose a Location +Decide where on your computer you want the project folder: + +- Windows: `C:\Users\YourName\Documents\Projects\` +- Mac/Linux: `/Users/YourName/Documents/Projects/` or `/home/YourName/Projects/` + +### Step 3: Clone the Project +Open a terminal/command prompt, navigate to your chosen location, and run: + +```bash +git clone https://git.albertademocracytaskforce.org/[USERNAME]/[PROJECTNAME].git +``` + +This creates a folder with all the project files. + +## Make Changes Locally + +### Step 1: Open the Project + +1. Open your text editor (VS Code, etc.) +2. Open the project folder you just cloned +3. Navigate to `mkdocs/docs/` to see the website files + +### Step 2: Create a New Branch +Before making changes, create a new branch: + +```bash +git checkout -b my-improvement-branch +``` + +### Step 3: Make Your Edits + +1. Edit any `.md` files in your text editor +2. Save your changes +3. Preview if possible (your editor might have Markdown preview) + +### Step 4: Check Your Changes +See what files you've modified: + +```bash +git status +``` + +See exactly what changed: + +```bash +git diff +``` + +## Commit Your Changes + +### Step 1: Add Files +Tell Git which files to include in your commit: + +```bash +git add . +``` + +(The `.` means "add all changed files") + +### Step 2: Commit +Save your changes with a descriptive message: + +```bash +git commit -m "Improve FAQ section with clearer examples" +``` + +## Push and Create Pull Request + +### Step 1: Push Your Branch +Send your changes to the server: + +```bash +git push origin my-improvement-branch +``` + +### Step 2: Create Pull Request + +1. Go to our project on Gitea +2. You'll see a notice about your new branch with a button to create a pull request +3. Click it and fill out the form +4. Submit your pull request + +## Keep Your Local Copy Updated + +Before starting new work, always get the latest changes: + +```bash +git checkout main +git pull origin main +``` + +Then create a new branch for your next improvement. + +## What's Next? + +Now you know how to work locally! Learn about [Submitting Changes](submitting-changes.md) to master the review process. + +## Video Tutorial + +*[Administrator: Add a video tutorial showing the complete local development workflow from clone to pull request]* + +## Quick Command Reference + +```bash +# Clone a repository +git clone [URL] + +# Create and switch to new branch +git checkout -b [branch-name] + +# Check status +git status + +# Add all changes +git add . + +# Commit changes +git commit -m "Your message" + +# Push branch +git push origin [branch-name] + +# Get latest changes +git pull origin main +``` + +## Troubleshooting + +**"Git not recognized"?** Make sure Git is installed and restart your terminal. + +**Permission denied?** You might need to set up SSH keys or use HTTPS authentication. + +**Merge conflicts?** Don't panic! This happens when multiple people edit the same lines. Ask for help or check our collaboration guide. diff --git a/mkdocs/docs/contributing/navigating-gitea.md b/mkdocs/docs/contributing/navigating-gitea.md new file mode 100644 index 0000000..ff51149 --- /dev/null +++ b/mkdocs/docs/contributing/navigating-gitea.md @@ -0,0 +1,73 @@ +# Navigating Gitea + +Now that you have an account, let's learn how to find your way around our Git hosting platform. This page will show you the key areas you'll use most often. + +## The Project Homepage + +When you open our project on Gitea, you'll see several important areas: + +### Step 1: Understand the Main Sections + +1. **Files Tab** - Shows all the files in our project (this is where you'll spend most of your time) +2. **Issues Tab** - Where we track problems, suggestions, and planned improvements +3. **Pull Requests Tab** - Where people submit changes for review +4. **Wiki Tab** - Additional documentation (if we use it) + +### Step 2: Explore the Files + +1. Click on the "Files" tab if you're not already there +2. You'll see a list of folders and files +3. Click on `mkdocs` then `docs` to see the website content +4. Click on any `.md` file to see its contents + +### Step 3: Learn the File View + +When viewing a file, you'll see: + +- **Raw content** - The actual text with special formatting codes +- **Edit button** (pencil icon) - Click this to make changes +- **History button** - See who changed what and when +- **Download button** - Save a copy to your computer + +## Key Areas to Know + +### The Repository Root +This is the main folder containing everything. Key items: + +- `mkdocs/docs/` - Website content goes here +- `README.md` - Project description and instructions +- `docker-compose.yml` - Technical setup file (don't worry about this) + +### The Docs Folder +This is where you'll make most changes: + +- `index.md` - The homepage content +- Individual `.md` files - Other pages on the website +- `blog/` folder - Blog posts and news +- `assets/` folder - Images and files + +## Practice Navigation + +Try these steps to get comfortable: + +1. Start at the project homepage +2. Click into `mkdocs` → `docs` +3. Open `index.md` to see the homepage content +4. Click the "back" button to return to the docs folder +5. Try opening another `.md` file + +## What's Next? + +Now that you can find your way around, let's make your first edit: [Make Your First Edit](first-edit.md). + +## Video Tutorial + +*[Administrator: Add a video tutorial showing how to navigate through Gitea's interface and find files]* + +## Quick Reference + +- **Project home**: All tabs and main project info +- **Files**: Browse and edit website content +- **Issues**: Report problems or suggest improvements +- **Pull requests**: Submit changes for review +- **Edit button**: Pencil icon next to any file diff --git a/mkdocs/docs/contributing/submitting-changes.md b/mkdocs/docs/contributing/submitting-changes.md new file mode 100644 index 0000000..8e16d0b --- /dev/null +++ b/mkdocs/docs/contributing/submitting-changes.md @@ -0,0 +1,157 @@ +# Submitting Changes + +Whether you're editing through the web interface or working locally, this guide covers best practices for submitting your changes and navigating the review process. + +## Before You Submit + +### Step 1: Review Your Own Work + +- **Read through your changes** as if seeing them for the first time +- **Check for typos** and grammar mistakes +- **Verify links work** and images display properly +- **Make sure formatting looks correct** in preview mode + +### Step 2: Write a Good Commit Message +Your commit message should clearly explain what you changed and why: + +**Good examples:** + +- "Fix broken link to voting rights resource" +- "Add FAQ section about Bill 54 implications" +- "Update contact information for Calgary office" + +**Poor examples:** + +- "Updated file" +- "Changes" +- "Fix" + +### Step 3: Check the Size of Your Changes + +- **Small focused changes** are easier to review and more likely to be accepted quickly +- **Large changes** should be broken into smaller, logical pieces when possible +- **If you must make large changes**, explain why in your pull request description + +## Creating a Great Pull Request + +### Step 1: Choose a Clear Title +Your pull request title should summarize the main improvement: + +- "Improve accessibility of navigation menu" +- "Add resources for municipal election information" +- "Fix mobile layout issues on FAQ page" + +### Step 2: Write a Helpful Description +Explain what you changed and why: + +``` +## What this changes + +- Fixes the broken link to the Alberta Elections website +- Updates the FAQ to include information about the new voting procedures +- Adds alt text to images for screen readers + +## Why this change is needed +The old link was returning a 404 error, and users were getting confused about the new voting procedures introduced in Bill 54. + +## How to test + +1. Click on the "Alberta Elections" link in the resources section +2. Verify it opens the correct page +3. Check that the FAQ section answers common questions about voting procedures +``` + +### Step 3: Reference Related Issues +If your pull request fixes a reported issue: +- Include "Fixes #123" in the description (where 123 is the issue number) +- This automatically links your pull request to the issue + +## The Review Process + +### What Happens Next + +1. **Automated checks** run to make sure your changes don't break anything +2. **A team member reviews** your changes within a few days +3. **Discussion happens** if they have questions or suggestions +4. **Changes are approved** and merged, or you're asked to make improvements + +### Responding to Feedback +When reviewers leave comments: + +**Be open to suggestions:** + +- Reviewers want to help improve the project +- They might know things about the project you don't +- Constructive feedback makes everyone better + +**Ask questions if unclear:** + +- "Could you give me an example of how you'd like this worded?" +- "I'm not sure I understand - could you clarify what you mean?" + +**Make requested changes promptly:** + +- Address feedback quickly to keep momentum +- Make additional commits to the same branch +- Your pull request will update automatically + +### Types of Feedback You Might Receive + +**Content suggestions:** + +- "Could you add a link to the source document here?" +- "This might be clearer if we break it into bullet points" + +**Technical improvements:** + +- "Please add alt text to this image for accessibility" +- "This link should open in a new tab" + +**Style consistency:** + +- "We use 'Alberta' instead of 'AB' throughout the site" +- "Can you match the heading format used on other pages?" + +## After Your Changes Are Merged + +### Celebrate! +You've successfully contributed to defending democracy in Alberta! Your changes are now live and helping others. + +### What's Next? + +- **Look for more ways to help** - check the Issues tab for other needed improvements +- **Share your knowledge** - help other new contributors +- **Stay engaged** - watch for updates and continue contributing + +## Common Submission Mistakes + +**Avoid these pitfalls:** + +- Submitting changes without testing them first +- Making unrelated changes in the same pull request +- Not explaining why the change is needed +- Taking feedback personally instead of constructively + +## Quick Checklist + +Before submitting any change: + +- [ ] I've reviewed my own work for errors +- [ ] My commit message clearly describes the change +- [ ] My pull request has a clear title and description +- [ ] I've tested that my changes work as expected +- [ ] I've kept the change focused on one improvement + +## Video Tutorial + +*[Administrator: Add a video tutorial showing the pull request process, including how to respond to feedback and make revisions]* + +## Getting Help + +If you're unsure about any part of the submission process: + +- Ask questions in your pull request +- Contact the project maintainers +- Join our contributor chat for real-time help + +Remember: everyone was a beginner once, and the community is here to help you succeed! diff --git a/mkdocs/docs/faq.md b/mkdocs/docs/faq.md new file mode 100644 index 0000000..d538d57 --- /dev/null +++ b/mkdocs/docs/faq.md @@ -0,0 +1,430 @@ +# Frequently Asked Questions + +## Common Questions About Bill 54 and Democratic Rights in Alberta + +This page answers the most common questions we receive about Bill 54, the UCP's anti-democratic agenda, and how ordinary Albertans can fight back. + +## About Bill 54 + +
+What exactly is Bill 54? +
+Bill 54 (the Election Statutes Amendment Act, 2025) is legislation passed by the UCP government that fundamentally changes how elections work in Alberta. It: + +
    +
  • Allows corporate and union donations up to $5,000 annually to political campaigns
  • +
  • Eliminates voter vouching systems
  • +
  • Bans electronic vote tabulators
  • +
  • Allows political parties in municipal elections in Edmonton and Calgary
  • +
  • Weakens the Chief Electoral Officer's investigative powers
  • +
+
+
+ +
+When did Bill 54 become law? +
+Bill 54 received Royal Assent on May 15, 2025, making it law in Alberta. +
+
+ +
+Why is Bill 54 called anti-democratic? +
+The legislation makes it harder for ordinary Albertans to vote while making it easier for wealthy corporations to buy political influence. It centralizes power while weakening oversight—classic hallmarks of authoritarian governance. +
+
+ +
+Doesn't the bill also allow union donations? +
+While the bill technically allows both corporate and union donations with the same $5,000 aggregate limit, the practical effect is very different: + +
    +
  • Corporations can coordinate donations from multiple entities to maximize influence
  • +
  • Unions represent workers' collective interests, not individual profit
  • +
  • Union political activity remains subject to additional restrictions
  • +
  • Corporate influence will far outweigh workers' collective voice
  • +
+
+
+ +## About Corporate Donations + +
+Why are corporate donations bad for democracy? +
+Corporate donations create a system where: + +
    +
  • Policy is shaped by those who can afford to buy influence
  • +
  • Ordinary voters are drowned out by corporate money
  • +
  • Politicians become accountable to donors rather than constituents
  • +
  • Democratic equality becomes impossible when money determines political influence
  • +
+
+
+ +
+What kinds of corporations will donate? +
+Expect major donations from: + +
    +
  • Oil and gas companies seeking favorable regulations
  • +
  • Real estate developers wanting easier approvals
  • +
  • Large retailers opposing minimum wage increases
  • +
  • Financial institutions seeking deregulation
  • +
  • Any business wanting government contracts or favorable treatment
  • +
+
+
+ +
+How much money are we talking about? +
+Corporate political donations can easily reach: + +
    +
  • Hundreds of thousands from major corporations per election
  • +
  • Millions collectively from entire industries
  • +
  • Amounts that dwarf small individual donations from working families
  • +
  • Enough money to fundamentally alter political competition
  • +
+
+
+ +## About Voting Changes + +
+What is "vouching" and why does it matter? +
+Vouching allowed eligible voters to vouch for other eligible voters who lacked proper ID. This helped: + +
    +
  • Indigenous peoples whose addresses might not match government records
  • +
  • Students without current local ID
  • +
  • Homeless people lacking fixed addresses
  • +
  • Seniors with difficulty obtaining current ID
  • +
  • Recent immigrants navigating bureaucratic processes
  • +
+
+
+ +
+Why are electronic tabulators being banned? +
+The ban on electronic vote counting has no legitimate justification. Electronic tabulators: + +
    +
  • Increase accuracy by eliminating human counting errors
  • +
  • Speed up results providing faster, more reliable reporting
  • +
  • Save money by reducing staffing needs
  • +
  • Maintain paper trails for audit purposes
  • +
+ +The real purpose is to create doubt about election results and make voting more difficult. +
+
+ +
+Will these changes affect me personally? +
+The changes could affect you if: + +
    +
  • You're Indigenous and live on a reserve
  • +
  • You're a student without local ID
  • +
  • You've moved recently and your ID doesn't reflect your current address
  • +
  • You're homeless or have unstable housing
  • +
  • You're elderly and have difficulty maintaining current ID
  • +
  • You care about election integrity and want accurate, efficient vote counting
  • +
+
+
+ +## About Municipal Elections + +
+Why is allowing political parties in municipal elections bad? +
+Municipal politics has traditionally been non-partisan because: + +
    +
  • Local issues (roads, water, garbage) don't follow party lines
  • +
  • Community solutions work better than ideological positions
  • +
  • Councillors can focus on neighborhoods rather than party discipline
  • +
  • Decision-making can be collaborative rather than adversarial
  • +
+
+
+ +
+How will this change my local election? +
+Expect to see: + +
    +
  • Candidates aligned with UCP or NDP rather than running independently
  • +
  • Corporate money flowing into local campaigns
  • +
  • Provincial politics imported into local issues
  • +
  • Community consensus replaced by partisan division
  • +
+
+
+ +
+What about small towns and rural areas? +
+Small communities will be particularly harmed: + +
    +
  • Local candidates must now choose provincial political sides
  • +
  • Community issues become subject to party politics
  • +
  • Traditional local leadership is undermined by partisan requirements
  • +
  • Outside money influences local decisions
  • +
+
+
+ +## About the Opposition + +
+Who opposes Bill 54? +
+Opposition comes from across Alberta society: + +
    +
  • Indigenous Nations defending treaty rights and sovereignty
  • +
  • Municipal leaders protecting local autonomy
  • +
  • Labour organizations defending workers' political rights
  • +
  • Civil liberties groups protecting democratic rights
  • +
  • Environmental organizations opposing corporate capture
  • +
  • The Chief Electoral Officer warning about harm to election integrity
  • +
+
+
+ +
+What are Indigenous Nations saying? +
+Indigenous leaders have been clear that Bill 54 threatens: + +
    +
  • Treaty rights that cannot be subject to provincial referendums
  • +
  • Indigenous sovereignty that predates provincial authority
  • +
  • Federal obligations that provinces cannot override
  • +
  • Constitutional protections that must be respected
  • +
+
+
+ +
+What do municipalities say? +
+Municipal leaders oppose the legislation because it: + +
    +
  • Undermines local autonomy and community self-governance
  • +
  • Forces partisan politics on traditionally non-partisan elections
  • +
  • Increases election costs by banning efficient counting methods
  • +
  • Opens local politics to corporate influence
  • +
+
+
+ +## About Taking Action + +
+What can I do as an individual? +
+You can: + +
    +
  • Contact your MLA and demand they oppose Bill 54's implementation
  • +
  • Join organizations fighting for democratic rights
  • +
  • Educate others about the legislation's harmful impacts
  • +
  • Support candidates committed to reversing the legislation
  • +
  • Volunteer for democratic advocacy organizations
  • +
+
+
+ +
+Is it too late since the bill is already law? +
+No! There are many ways to continue fighting: + +
    +
  • Legal challenges in the courts
  • +
  • Electoral action supporting candidates who will reverse the law
  • +
  • Community organizing to minimize the harm
  • +
  • Public education to build opposition for future action
  • +
+
+
+ +
+How can I help with voter education? +
+You can: + +
    +
  • Share information about new voting requirements
  • +
  • Help people understand how to meet ID requirements
  • +
  • Volunteer with voter registration drives
  • +
  • Support organizations doing voter education work
  • +
+
+
+ +
+What organizations should I support? +
+Consider supporting: + +
    +
  • Alberta Federation of Labour (workers' rights)
  • +
  • Indigenous political organizations (treaty rights)
  • +
  • Alberta Civil Liberties Research Centre (civil rights)
  • +
  • Municipal associations (local democracy)
  • +
  • Environmental groups (fighting corporate capture)
  • +
+
+
+ +## About the Broader Context + +
+Is this happening elsewhere? +
+Yes, similar attacks on democracy are occurring: + +
    +
  • United States: Voter suppression and unlimited corporate spending
  • +
  • Other provinces: Various restrictions on democratic participation
  • +
  • Internationally: Authoritarian movements using similar tactics
  • +
+
+
+ +
+What's the connection to other UCP policies? +
+Bill 54 is part of a broader authoritarian pattern: + +
    +
  • Bill 20: Provincial control over municipalities
  • +
  • Labour restrictions: Weakening unions and workers' rights
  • +
  • Environmental suppression: Restricting activism and protest
  • +
  • Healthcare privatization: Reducing public democratic control
  • +
+
+
+ +
+What does this have to do with separation? +
+Bill 54 makes it easier to put separation questions on the ballot, which: + +
    +
  • Threatens Indigenous treaty rights with the federal Crown
  • +
  • Creates uncertainty about federal constitutional protections
  • +
  • Distracts from real issues like healthcare and cost of living
  • +
  • Serves the UCP's political interests rather than Albertans' needs
  • +
+
+
+ +## About Solutions + +
+What would good democratic reform look like? +
+Real democratic reform would include: + +
    +
  • Public financing of campaigns to level the playing field
  • +
  • Expanded voting access making it easier for all eligible voters
  • +
  • Proportional representation ensuring all voices are heard
  • +
  • Protected municipal autonomy from provincial interference
  • +
  • Strengthened oversight of electoral processes
  • +
+
+
+ +
+Can these changes be reversed? +
+Yes, but it requires: + +
    +
  • Electoral success by candidates committed to democratic reform
  • +
  • Sustained organizing by civil society organizations
  • +
  • Legal challenges to unconstitutional provisions
  • +
  • Public pressure demanding better from government
  • +
+
+
+ +
+What can we learn from other places? +
+Successful democratic reform elsewhere has included: + +
    +
  • Participatory budgeting giving communities control over spending
  • +
  • Citizens' assemblies involving ordinary people in policy-making
  • +
  • Proportional representation ensuring fair electoral outcomes
  • +
  • Campaign finance reform reducing the influence of big money
  • +
+
+
+ +## Getting Involved + +
+I'm new to politics. Where do I start? +
+Start by: + +
    +
  • Learning about the issues through our resources
  • +
  • Contacting your elected representatives
  • +
  • Joining a local organization aligned with your values
  • +
  • Attending community meetings and events
  • +
+
+
+ +
+I don't have much time. What's the most important thing I can do? +
+If you only have time for one thing: + +
    +
  • Vote in every election and help others vote
  • +
  • Share information about democratic issues with your networks
  • +
  • Contact your MLA about specific concerns
  • +
  • Support organizations doing democratic advocacy work
  • +
+
+
+ +
+I want to do more. How can I get deeply involved? +
+For deeper involvement: + +
    +
  • Join the board or volunteer committee of a democratic organization
  • +
  • Run for office yourself at any level
  • +
  • Organize in your workplace, community, or social networks
  • +
  • Donate regularly to organizations fighting for democracy
  • +
+
+
+ +--- + +*Don't see your question answered here? Contact us through our social media channels or community networks. We're always happy to provide more information about defending democracy in Alberta.* diff --git a/mkdocs/docs/getting-started.md b/mkdocs/docs/getting-started.md new file mode 100644 index 0000000..3fa5467 --- /dev/null +++ b/mkdocs/docs/getting-started.md @@ -0,0 +1,196 @@ +# Getting Started: Defending Democracy in Alberta + +## Understanding the Threat + +The UCP government under Danielle Smith has launched an unprecedented attack on democratic institutions in Alberta. Bill 54, along with other authoritarian legislation like Bill 20, represents a fundamental threat to: + +- **Your right to vote** and have that vote counted fairly +- **Equal representation** free from corporate influence +- **Local democratic control** over community decisions +- **Workers' collective political voice** through unions + +## Immediate Actions You Can Take + +### 1. 📚 Educate Yourself and Others + +**Read the Evidence:** + +- Review our [comprehensive archive](archive/index.md) of documentation +- Focus on sources that speak to your interests (municipal politics, Indigenous rights, workers' rights, etc.) +- Understand how these changes affect your community specifically + +**Share Information:** + +- Post articles from our archive on social media +- Email links to friends, family, and colleagues +- Discuss these issues at community gatherings +- Write letters to local newspapers + +### 2. ✉️ Contact Your Representatives + +**Your MLA:** +Find your MLA at [assembly.ab.ca](https://www.assembly.ab.ca) and: + +- Call their office during business hours +- Email with specific concerns about Bill 54 +- Request a meeting to discuss democratic rights +- Ask them to publicly oppose anti-democratic legislation + +**Municipal Representatives:** + +- Contact your mayor and city/county councillors +- Attend council meetings during public comment periods +- Ask them to pass resolutions opposing Bill 54 +- Support municipal leaders defending local autonomy + +**Federal Representatives:** + +- Contact your MP about the democratic crisis in Alberta +- Ask for federal intervention if Alberta undermines electoral integrity + +### 3. 🤝 Join the Movement + +**Connect with Organizations:** + +- **Labour unions** fighting for workers' political rights +- **Indigenous organizations** defending treaty rights and sovereignty +- **Municipal associations** opposing provincial interference +- **Civil liberties groups** protecting democratic rights +- **Environmental organizations** facing government suppression +- **Community groups** working on social justice issues + +**Attend Events:** + +- Public forums and town halls +- Protest rallies and demonstrations +- Union meetings and solidarity events +- Municipal council meetings +- Community organization gatherings + +### 4. 🗳️ Electoral Action + +**Prepare for Elections:** + +- Ensure you're registered to vote +- Help others get registered +- Volunteer for democratic candidates +- Support candidates who oppose Bill 54 +- Consider running for office yourself + +**Support Democracy-Friendly Candidates:** +Look for candidates who commit to: + +- Reversing Bill 54's anti-democratic provisions +- Expanding voting access +- Getting corporate money out of politics +- Strengthening electoral oversight +- Protecting municipal autonomy + +## Long-Term Strategies + +### Build Community Power + +**Organize in Your Neighborhood:** + +- Form or join community associations +- Organize informal political discussion groups +- Host house parties to discuss democratic issues +- Create mutual aid networks + +**Workplace Organizing:** + +- Support union drives and collective bargaining +- Advocate for political action in your union +- Organize workplace discussions about democratic rights +- Support workers facing political repression + +### Support Independent Media + +**Share and Fund:** + +- Support journalists covering the democracy crisis +- Share articles from independent Alberta media +- Subscribe to publications doing investigative reporting +- Fund citizen journalism and community media + +### Legal and Policy Action + +**Support Legal Challenges:** + +- Donate to organizations challenging anti-democratic laws +- Attend court hearings when possible +- Amplify legal challenges through social media + +**Policy Advocacy:** + +- Submit written comments on legislation +- Participate in government consultations +- Develop alternative policy proposals +- Support think tanks promoting democratic reform + +## Resources for Different Communities + +### For Workers and Union Members + +- Contact your union leadership about political action +- Attend union meetings to discuss Bill 54 +- Support union political education programs +- Advocate for stronger labour-community alliances + +### For Students + +- Organize on campus around democratic issues +- Connect with student unions and advocacy groups +- Use student media to raise awareness +- Participate in youth political organizations + +### For Parents and Families + +- Discuss democratic values with children +- Engage with school councils and parent groups +- Support civic education in schools +- Model democratic participation + +### For Indigenous Community Members + +- Connect with First Nations and Métis political organizations +- Support Indigenous sovereignty and treaty rights +- Participate in Indigenous-led resistance to Bill 54 +- Build alliances between Indigenous and non-Indigenous democrats + +### For Seniors + +- Share your experience of democratic struggles +- Engage with seniors' organizations +- Mentor younger activists +- Use your time and resources to support the movement + +## Building Solidarity + +The fight for democracy in Alberta requires unity across different communities: + +- **Workers and business owners** who believe in fair elections +- **Indigenous and non-Indigenous** people defending treaty rights +- **Urban and rural** communities opposing centralized control +- **Recent immigrants and multi-generational Albertans** supporting inclusive democracy +- **People of all political backgrounds** who value democratic institutions + +## Next Steps + +1. **Start with one action today** - whether it's reading an article, making a phone call, or sharing information +2. **Commit to regular engagement** - democracy requires sustained effort, not just one-time actions +3. **Find your community** - connect with others who share your values and concerns +4. **Keep learning** - stay informed about ongoing threats and opportunities +5. **Take care of yourself** - democratic work is marathon, not a sprint + +## Remember + +Democracy is not a spectator sport. It requires active participation from all of us. The UCP is counting on public apathy and resignation to advance their authoritarian agenda. + +But history shows us that when ordinary people organize together, they can defeat even the most powerful interests. The civil rights movement, the labour movement, the women's suffrage movement - all were built by people like you taking action in their communities. + +**The time to act is now. The future of Alberta democracy depends on what we do today.** + +--- + +*For more information, explore our [archive](archive/index.md) or contact local democratic organizations in your community.* \ No newline at end of file diff --git a/mkdocs/docs/index.md b/mkdocs/docs/index.md new file mode 100644 index 0000000..ae77238 --- /dev/null +++ b/mkdocs/docs/index.md @@ -0,0 +1,51 @@ +--- +title: Alberta Democracy Taskforce +template: home.html +hide: + - navigation + - toc +--- + +# Defending Democracy in Alberta + +The Alberta Democracy Taskforce is a coalition committed to protecting and expanding democratic rights in the face of the UCP government's authoritarian overreach. We believe that democracy should serve the people, not wealthy elites and corporations. + +## Our Mission + +We stand for: +- **Expanding voting access** for all Albertans +- **Getting big money out of politics** through public financing and strict donation limits +- **Protecting electoral integrity** with proper oversight and modern counting methods +- **Defending local democracy** against partisan interference +- **Supporting workers' political rights** and union participation in democracy + +## Take Action + +Democracy requires your participation. Explore our site to learn about the threats facing Alberta's democratic institutions and how you can help defend them. + +## About This Site + +This website is built using [Changemaker Lite](cm-lite/index.md), an open-source, self-hosted platform designed for documentation and collaborative development. Changemaker Lite provides everything needed to create, maintain, and deploy websites like this one. + +### Why Changemaker Lite? + +- **Self-hosted**: Complete control over your data and content +- **Open source**: Free to use and modify for any organization +- **Collaborative**: Built-in tools for team editing and contribution +- **Portable**: Can be downloaded and rebuilt on any computer +- **Integrated**: Includes documentation, automation, and publishing tools + +### Rebuild This Site + +You can download and rebuild this entire site on your own computer: + +1. **Download**: Clone the repository from [git.albertademocracytaskforce.org/admin/ab.dem.tf.changemaker.git](https://git.albertademocracytaskforce.org/admin/ab.dem.tf.changemaker.git) +2. **Setup**: Run the included configuration script +3. **Launch**: Start all services with Docker Compose +4. **Customize**: Modify content and styling to fit your needs + +For detailed instructions, see our [Changemaker Lite documentation](cm-lite/index.md). + +## Contributing to This Site + +Want to help improve this site or add content? We welcome contributions from anyone interested in defending democracy in Alberta. Our [contribution guide](contributing/index.md) will walk you through everything you need to know, even if you've never used Git before. \ No newline at end of file diff --git a/mkdocs/docs/overrides/home.html b/mkdocs/docs/overrides/home.html new file mode 100644 index 0000000..dafd512 --- /dev/null +++ b/mkdocs/docs/overrides/home.html @@ -0,0 +1,264 @@ +{% extends "main.html" %} + +{% block content %} + +
+
+
+
+

Alberta Democracy Taskforce

+

Defending democracy against authoritarian overreach

+ +
+
+
+ +
+
+ +
+

🚨 Democracy Under Attack in Alberta

+

Bill 54 and the UCP's anti-democratic agenda threatens the fundamental rights of all Albertans. The Smith government is systematically dismantling democratic institutions, making it harder to vote, allowing big money to corrupt our politics, and centralizing power at the expense of local communities.

+

Read Full Bill 54 Analysis →

+
+ +

Standing Up for Democratic Rights

+

The Alberta Democracy Taskforce is a coalition of citizens, workers, and organizations committed to defending and expanding democratic participation in Alberta. We believe that democracy belongs to the people, not to wealthy corporations and political elites. New to the fight? Start here →

+ +
+
+

❌ What They're Taking Away

+
    +
  • Vote counting integrity: Banning electronic tabulators that ensure accurate, efficient counts
  • +
  • Voting accessibility: Eliminating vouching systems that help eligible voters cast ballots
  • +
  • Democratic oversight: Weakening the Chief Electoral Officer's investigative powers
  • +
  • Local autonomy: Allowing political parties in municipal elections
  • +
  • Referendum thresholds: Lowering the bar for separation referendums
  • +
+

Read Edmonton Journal Coverage →

+
+
+

💰 Big Money Returns

+
    +
  • Corporate donations: Letting wealthy corporations buy political influence
  • +
  • Union restrictions: Undermining workers' collective political voice
  • +
  • Higher spending limits: Giving advantages to well-funded candidates
  • +
  • Weakened enforcement: Making it easier to break election finance rules
  • +
+

Read Expert Analysis →

+
+
+

✊ Our Democratic Vision

+
    +
  • Expand voting access: Make it easier for all Albertans to vote
  • +
  • Get money out of politics: Public financing and strict donation limits
  • +
  • Strengthen oversight: Independent electoral administration
  • +
  • Protect local democracy: Keep municipal elections non-partisan
  • +
+

Learn More →

+
+ +
+ +
+ +

The UCP's Anti-Democratic Playbook

+

Bill 54 is not an isolated incident—it's part of a broader pattern of authoritarian governance that mirrors tactics used by right-wing movements across North America. Read expert analysis comparing these tactics to Trump's playbook. The UCP is:

+ +
+
+

Voter Suppression

+

Making it harder for working-class Albertans, Indigenous peoples, and marginalized communities to vote by eliminating vouching and creating barriers to ballot access. Learn about the tabulator ban →

+
+
+

Corporate Capture

+

Allowing corporate and union donations up to $5,000 annually while tilting the playing field toward wealthy interests through multiple coordinated donations from related corporate entities. Read CBC's coverage →

+
+
+

Centralization of Power

+

Undermining municipal autonomy and introducing partisan politics to local elections, making communities more vulnerable to top-down control. See municipal impact analysis →

+
+
+

Weakening Oversight

+

Reducing the independence and investigative capacity of electoral officials, making it easier to break rules without consequences. Read the Chief Electoral Officer's warning →

+
+
+

📧 Fight Back - Subscribe

+

Stay informed about UCP tactics and organized resistance efforts. Knowledge is power in the fight for democracy.

+
+ +
+ + +
+ + +
+ +
+
+
+
+ +
+ +
+

How to Fight Back

+

Democracy is not a spectator sport. It requires active participation from all of us. Here's how you can help defend democratic rights in Alberta:

+ +
+
+

📚 Educate Yourself

+

Read our comprehensive archive of articles and analysis about Bill 54 and the UCP's anti-democratic agenda. Start with our detailed Bill 54 analysis and check out the frequently asked questions.

+
+
+

📢 Spread the Word

+

Share this information with friends, family, and community members. Many Albertans don't know what's happening to their democratic rights. Check our resources page for shareable materials and talking points.

+
+
+

✉️ Contact Representatives

+

Call or write to your MLA, municipal councillors, and other elected officials. Demand they stand up for democratic principles. Visit our getting started guide for templates and contact information.

+
+
+

🤝 Join Organizations

+

Connect with unions, community groups, Indigenous organizations, and civil society groups fighting for democratic rights.

+
+
+

📧 Take Action - Subscribe

+

Get action alerts, campaign updates, and mobilization calls. Turn your concern into concrete action for democracy.

+
+ +
+ + +
+ + +
+ +
+
+
+
+
+ +
+ +
+

Standing in Solidarity

+

We stand with:

+ + +
+

🤝 Join Our Coalition

+

Stand in solidarity with Indigenous Nations, workers, municipalities, and all Albertans defending democracy. Get updates on coalition actions and solidarity campaigns.

+
+ +
+ + +
+ + +
+ +
+
+
+
+ +
+ + + +
+ +
+

The Time to Act is Now

+

The UCP's assault on democracy didn't happen overnight, and it won't be stopped without sustained resistance. But history shows us that when ordinary people organize together, they can defeat even the most powerful interests.

+

Explore our site, learn the facts, and join the fight for democratic Alberta.

+ +
+ +
+
+ +{% endblock %} + diff --git a/mkdocs/docs/overrides/main.html b/mkdocs/docs/overrides/main.html new file mode 100644 index 0000000..e98bde1 --- /dev/null +++ b/mkdocs/docs/overrides/main.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} + +{% block extrahead %} +{% endblock %} + +{% block announce %} + +- Changemaker-lite Docs +{% endblock %} diff --git a/mkdocs/docs/overrides/partials/footer.html b/mkdocs/docs/overrides/partials/footer.html new file mode 100644 index 0000000..c690522 --- /dev/null +++ b/mkdocs/docs/overrides/partials/footer.html @@ -0,0 +1,55 @@ + + \ No newline at end of file diff --git a/mkdocs/docs/resources.md b/mkdocs/docs/resources.md new file mode 100644 index 0000000..5334e61 --- /dev/null +++ b/mkdocs/docs/resources.md @@ -0,0 +1,191 @@ +# Democracy Action Toolkit + +
+

Ready-to-Use Resources for Defending Democracy

+
+ +Everything you need to take action: social media content, contact info, legal resources, and tools to build your own democratic movement using our open-source platform. + +## Quick Action Guide + +
+
+

✍️ Contribute to the Fight

+

Join our collaborative effort. Edit this site, add resources, share your expertise. No technical experience required - full training provided.

+ Start Contributing → +
+
+

📱 Ready-to-Share Content

+

Copy and paste social media posts for Twitter/X, Facebook, and Instagram. Spread awareness about Bill 54 and democratic issues instantly.

+ Get Social Content → +
+
+

📞 Take Direct Action

+

Contact your representatives, find allied organizations, and access legal resources to defend democratic participation.

+ Take Action → +
+
+ +--- + +## Stay Connected and Informed + +The fight for democracy requires sustained effort and coordination. Join our network to stay informed about UCP tactics and organized resistance efforts. + + + + + +--- + +## Replicate This Platform + +**Changemaker Lite** is the open-source platform powering this website. You can clone the complete setup - documentation tools, email campaigns, automation workflows - and rebuild it for your own organization in minutes. + + + +--- + +## Social Media Content + +Copy these posts with one click and customize them for your social media channels: + +### Twitter/X Posts + +
+ +
+

🚨 Bill 54 gives the UCP power to fire elected municipal officials without cause. This isn't governance - it's authoritarianism. Albertans deserve democracy, not dictators. #BillNo54 #AbDemocracy #UCPAuthoritarianism

+ +
+ +
+

📞 TAKE ACTION: Call your MLA today about Bill 54. Tell them you won't stand for attacks on municipal democracy. Find your rep: assembly.ab.ca #AbDemocracy #BillNo54

+ +
+ +
+ +### Facebook Posts + +
+
+

URGENT: The UCP's Bill 54 would fundamentally change how democracy works in Alberta. This bill would give the provincial government unprecedented power to fire elected municipal officials, override local decisions, and impose their will on communities across Alberta. This isn't about left vs right - it's about democracy vs authoritarianism.

+ +
+
+ +### Instagram Captions + +
+
+

Democracy isn't a spectator sport 🗳️ Bill 54 would let the UCP government fire YOUR elected municipal representatives. The people YOU voted for could be removed by politicians YOU didn't elect. We can't let this stand. #BillNo54 #AbDemocracy #LocalDemocracy #Democracy

+ +
+
+ +--- + +## Direct Action + +### Contact Your Representatives + +
+
+

🏛️ Contact Your MLA

+
    +
  • Find Your MLA - Alberta Legislature Directory
  • +
  • Talking Points: Oppose Bill 54, defend municipal democracy, respect local elections
  • +
  • Best Practice: Call during business hours (9am-5pm), be polite but firm
  • +
+
+ +
+

🤝 Allied Organizations

+
    +
  • Alberta Federation of Labour: afl.org
  • +
  • Canadian Civil Liberties Association: ccla.org
  • +
  • Alberta Urban Municipalities Association: auma.ca
  • +
  • Rural Municipalities of Alberta: rmalberta.com
  • +
+
+ +
+

⚖️ Legal Resources

+
    +
  • Legal Aid Alberta: legalaid.ab.ca | 1-866-845-3425
  • +
  • Canadian Charter of Rights: Protects democratic participation
  • +
  • Municipal Government Act: Defines local democracy in Alberta
  • +
  • Emergency: If facing legal issues, contact Legal Aid immediately
  • +
+
+
+ +--- + +## Find All Your Representatives + +
+
+

🏛️ Provincial (MLA)

+
    +
  • Find Your MLA
  • +
  • Contact by phone, email, or in person
  • +
  • Attend town halls and public meetings
  • +
+
+ +
+

🏘️ Municipal

+ +
+ +
+

🇨🇦 Federal (MP)

+
    +
  • Find Your MP
  • +
  • Raise concerns about provincial overreach
  • +
  • Request federal intervention if needed
  • +
+
+
+ + diff --git a/mkdocs/docs/stylesheets/extra.css b/mkdocs/docs/stylesheets/extra.css new file mode 100644 index 0000000..c0d5a4d --- /dev/null +++ b/mkdocs/docs/stylesheets/extra.css @@ -0,0 +1,897 @@ +/* Footer layout adjustments - completely unified */ +.md-footer__unified { + width: 100%; + background-color: var(--md-footer-bg-color); + color: var(--md-footer-fg-color); + padding: 1rem 0; +} + +.md-footer__inner { + max-width: 1200px; + margin: 0 auto; + padding: 0 1rem; +} + +.footer-content { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + gap: 1rem; +} + +.footer-nav-links { + flex-shrink: 0; + min-width: 80px; + display: flex; + align-items: center; +} + +.footer-nav-prev { + margin-right: auto; +} + +.footer-nav-next { + margin-left: auto; + justify-content: flex-end; +} + +.footer-center { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.5rem; + text-align: center; +} + +/* Inline subscribe form */ +.footer-subscribe-inline { + margin-bottom: 0.5rem; +} + +.subscribe-row-inline { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; +} + +.subscribe-logo-small { + width: 60px; + height: auto; + opacity: 0.9; +} + +.inline-form-container { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.email-input-inline { + width: 200px; + padding: 0.4rem 0.6rem; + border: 1px solid var(--md-default-fg-color--lightest); + border-radius: 4px; + background: var(--md-default-bg-color); + color: var(--md-default-fg-color); + font-size: 0.85rem; +} + +.email-input-inline:focus { + outline: none; + border-color: var(--md-primary-fg-color); + box-shadow: 0 0 0 2px var(--md-primary-fg-color--light); +} + +.subscribe-btn-inline { + background: var(--md-primary-fg-color); + color: var(--md-primary-bg-color); + border: none; + padding: 0.4rem 0.8rem; + border-radius: 4px; + font-size: 0.85rem; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s ease; + white-space: nowrap; +} + +.subscribe-btn-inline:hover { + background: var(--md-accent-fg-color); +} + +.md-copyright { + font-size: 0.8rem; + opacity: 0.9; +} + +/* Original nav link styles */ +.md-footer__link { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--md-footer-fg-color); + text-decoration: none; + font-size: 0.9rem; + padding: 0.5rem; + border-radius: 4px; + transition: background-color 0.2s ease; + white-space: nowrap; +} + +.md-footer__link:hover { + background: rgba(255, 255, 255, 0.1); +} + +.nav-icon { + width: 1.2rem; + height: 1.2rem; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.nav-icon svg { + width: 100%; + height: 100%; + fill: currentColor; +} + +.nav-label { + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* Dark theme adjustments for inline subscribe */ +[data-md-color-scheme="slate"] .email-input-inline { + background: var(--md-code-bg-color); + border-color: var(--md-default-fg-color--lightest); +} + +[data-md-color-scheme="slate"] .email-input-inline:focus { + border-color: var(--md-accent-fg-color); + box-shadow: 0 0 0 2px rgba(255, 193, 7, 0.2); +} + +/* Responsive adjustments for footer */ +@media (max-width: 768px) { + .footer-content { + flex-direction: column; + gap: 0.7rem; + } + + .footer-nav-links { + width: 100%; + justify-content: center; + } + + .footer-center { + width: 100%; + order: 1; + } + + .footer-nav-prev { + order: 0; + } + + .footer-nav-next { + order: 2; + } + + .subscribe-row-inline { + flex-direction: column; + gap: 0.5rem; + } + + .inline-form-container { + flex-direction: column; + width: 100%; + } + + .email-input-inline { + width: 100%; + max-width: 250px; + } +} + +/* Subscribe Footer Styles */ +.md-footer-subscribe { + background: var(--md-footer-bg-color); + border-top: 1px solid var(--md-footer-fg-color--light); + padding: 1.5rem 0; +} + +.md-footer-subscribe__inner { + max-width: 1200px; + margin: 0 auto; + padding: 0 1rem; +} + +.subscribe-row { + display: flex; + align-items: center; + justify-content: center; + gap: 2rem; + max-width: 600px; + margin: 0 auto; +} + +.subscribe-container { + max-width: 350px; + text-align: center; + flex: 1; +} + +.subscribe-logo-container { + flex-shrink: 0; +} + +.subscribe-logo { + width: 200px; + height: auto; + opacity: 0.9; +} + +.subscribe-container h3 { + color: var(--md-footer-fg-color); + font-size: 1.25rem; + font-weight: 600; + margin-bottom: 0.4rem; + line-height: 1.3; +} + +.subscribe-description { + color: var(--md-footer-fg-color--light); + margin-bottom: 1.2rem; + font-size: 0.85rem; + line-height: 1.4; +} + +.form-group { + margin-bottom: 0.8rem; +} + +.email-input, +.name-input { + width: 100%; + max-width: 320px; + padding: 0.6rem 0.8rem; + border: 1px solid var(--md-default-fg-color--lightest); + border-radius: 4px; + background: var(--md-default-bg-color); + color: var(--md-default-fg-color); + font-size: 0.9rem; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.email-input:focus, +.name-input:focus { + outline: none; + border-color: var(--md-primary-fg-color); + box-shadow: 0 0 0 2px var(--md-primary-fg-color--light); +} + +.email-input::placeholder, +.name-input::placeholder { + color: var(--md-default-fg-color--light); +} + +.checkbox-group { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + margin-bottom: 1.2rem; +} + +.checkbox-group input[type="checkbox"] { + margin: 0; + transform: scale(1.0); +} + +.checkbox-group label { + color: var(--md-footer-fg-color--light); + font-size: 0.8rem; + cursor: pointer; + user-select: none; +} + +.subscribe-btn { + background: var(--md-primary-fg-color); + color: var(--md-primary-bg-color); + border: none; + padding: 0.6rem 1.5rem; + border-radius: 4px; + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s ease, transform 0.1s ease; + min-width: 100px; +} + +.subscribe-btn:hover { + background: var(--md-accent-fg-color); + transform: translateY(-1px); +} + +.subscribe-btn:active { + transform: translateY(0); +} + +/* Dark theme adjustments */ +[data-md-color-scheme="slate"] .email-input, +[data-md-color-scheme="slate"] .name-input { + background: var(--md-code-bg-color); + border-color: var(--md-default-fg-color--lightest); +} + +[data-md-color-scheme="slate"] .email-input:focus, +[data-md-color-scheme="slate"] .name-input:focus { + border-color: var(--md-accent-fg-color); + box-shadow: 0 0 0 2px rgba(255, 193, 7, 0.2); +} + +/* Dark theme adjustments for subscribe grid item */ +[data-md-color-scheme="slate"] .grid-item.subscribe .email-input, +[data-md-color-scheme="slate"] .grid-item.subscribe .name-input { + background: var(--md-code-bg-color); + border-color: var(--md-default-fg-color--lightest); +} + +[data-md-color-scheme="slate"] .grid-item.subscribe .email-input:focus, +[data-md_color-scheme="slate"] .grid-item.subscribe .name-input:focus { + border-color: var(--md-accent-fg-color); + box-shadow: 0 0 0 2px rgba(255, 193, 7, 0.2); +} + +/* Home Page Hero and Content Styles */ +.hero-with-image { + position: relative; + overflow: hidden; + min-height: 60vh; + display: flex; + align-items: center; + padding: 3rem 0; +} + +.hero-background { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-image: url('/assets/images/header.png'); + background-size: cover; + background-position: center; + background-repeat: no-repeat; + opacity: 0.8; + z-index: -1; +} + +.hero-background::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(124, 77, 255, 0.7), rgba(220, 53, 69, 0.6)); + z-index: 1; +} + +.hero-with-image .md-hero__inner { + position: relative; + z-index: 2; + max-width: 1200px; + margin: 0 auto; + padding: 0 2rem; + text-align: center; +} + +.hero-with-image h1 { + color: white; + text-shadow: 2px 2px 4px rgba(0,0,0,0.7); + font-size: 3rem; + font-weight: bold; + margin-bottom: 1rem; + max-width: 800px; + margin-left: auto; + margin-right: auto; +} + +.hero-with-image p { + color: white; + text-shadow: 1px 1px 3px rgba(0,0,0,0.7); + font-size: 1.25rem; + margin-bottom: 2rem; + max-width: 600px; + margin-left: auto; + margin-right: auto; + line-height: 1.5; +} + +.hero-actions { + margin-top: 1.5rem; + display: flex; + gap: 1rem; + flex-wrap: wrap; +} + +.hero-actions .md-button { + background: rgba(255, 255, 255, 0.9); + color: var(--md-primary-fg-color); + border: 2px solid transparent; + font-weight: 600; + text-shadow: none; + backdrop-filter: blur(10px); + transition: all 0.3s ease; +} + +.hero-actions .md-button:hover { + background: rgba(255, 255, 255, 1); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +.hero-actions .md-button--primary { + background: var(--md-primary-fg-color); + color: white; +} + +.hero-actions .md-button--primary:hover { + background: var(--md-accent-fg-color); + color: white; +} + +.alert { + padding: 1.5rem; + margin: 2rem 0; + border-radius: 8px; + border-left: 4px solid; +} + +.alert-danger { + background-color: rgba(75, 0, 130, 0.95); /* Much darker purple */ + border-left-color: #4b0082; + color: white; + font-weight: 500; +} + +.alert-danger h2 { + color: white !important; + font-weight: 700; + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8); + margin-bottom: 1rem; + margin-top: 0; + padding-bottom: 0; + border-bottom: none; +} + +.alert-danger strong { + color: white; + font-weight: 700; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 2rem; + margin: 2rem 0; +} + +.grid-item { + padding: 2rem; + border-radius: 8px; + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.grid-item:hover { + transform: translateY(-5px); + box-shadow: 0 10px 20px rgba(0,0,0,0.1); +} + +.grid-item.threat { + background: linear-gradient(135deg, rgba(220, 53, 69, 0.1), rgba(220, 53, 69, 0.05)); + border-left: 4px solid #dc3545; +} + +.grid-item.corruption { + background: linear-gradient(135deg, rgba(255, 193, 7, 0.1), rgba(255, 193, 7, 0.05)); + border-left: 4px solid #ffc107; +} + +.grid-item.solution { + background: linear-gradient(135deg, rgba(40, 167, 69, 0.1), rgba(40, 167, 69, 0.05)); + border-left: 4px solid #28a745; +} + +.grid-item.subscribe { + background: linear-gradient(135deg, rgba(124, 77, 255, 0.1), rgba(124, 77, 255, 0.05)); + border-left: 4px solid #7c4dff; + text-align: center; +} + +.grid-item.subscribe h3 { + color: var(--md-primary-fg-color); + margin-bottom: 1rem; +} + +.grid-item.subscribe p { + margin-bottom: 1.5rem; + color: var(--md-default-fg-color--light); +} + +.grid-item.subscribe .form-group { + margin-bottom: 1rem; +} + +.grid-item.subscribe .email-input, +.grid-item.subscribe .name-input { + width: 100%; + max-width: 100%; + padding: 0.75rem 1rem; + border: 1px solid var(--md-default-fg-color--lightest); + border-radius: 4px; + background: var(--md-default-bg-color); + color: var(--md-default-fg-color); + font-size: 0.95rem; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.grid-item.subscribe .email-input:focus, +.grid-item.subscribe .name-input:focus { + outline: none; + border-color: var(--md-primary-fg-color); + box-shadow: 0 0 0 2px rgba(124, 77, 255, 0.2); +} + +.grid-item.subscribe .checkbox-group { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + margin-bottom: 1.5rem; + font-size: 0.9rem; +} + +.grid-item.subscribe .checkbox-group label { + color: var(--md-default-fg-color--light); + cursor: pointer; +} + +.grid-item.subscribe .subscribe-btn { + background: var(--md-primary-fg-color); + color: white; + border: none; + padding: 0.75rem 1.5rem; + border-radius: 4px; + font-size: 0.95rem; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + width: 100%; + max-width: 200px; +} + +.grid-item.subscribe .subscribe-btn:hover { + background: var(--md-accent-fg-color); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(124, 77, 255, 0.3); +} + +.tactics-grid, .action-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; + margin: 2rem 0; +} + +.tactic-item, .action-item { + padding: 1.5rem; + background: rgba(124, 77, 255, 0.05); + border-radius: 8px; + border: 1px solid rgba(124, 77, 255, 0.2); + transition: all 0.3s ease; +} + +.tactic-item:hover, .action-item:hover { + background: rgba(124, 77, 255, 0.1); + border-color: rgba(124, 77, 255, 0.4); +} + +.section-divider { + height: 2px; + background: linear-gradient(90deg, transparent, var(--md-default-fg-color--lightest), transparent); + margin: 3rem 0; +} + +.quick-links-section { + margin: 3rem 0; +} + +.quick-links-section h2 { + text-align: center; + margin-bottom: 1rem; +} + +.quick-links-section p { + text-align: center; + margin-bottom: 2rem; + color: var(--md-default-fg-color--light); +} + +.quick-links-section .grid-item h4 { + color: var(--md-primary-fg-color); + margin-bottom: 1rem; + font-size: 1.1rem; +} + +.quick-links-section .grid-item p { + margin-bottom: 1.5rem; + text-align: center; + font-size: 0.9rem; + color: var(--md-default-fg-color--light); +} + +/* Force code blocks to wrap instead of scroll */ +.highlight pre, +.codehilite pre, +code { + white-space: pre-wrap !important; + word-wrap: break-word !important; + overflow-wrap: break-word !important; +} + +/* Ensure code block containers don't create horizontal scroll */ +.highlight, +.codehilite { + overflow-x: visible !important; + overflow-y: visible !important; +} + +/* Make sure inline code also wraps */ +p code, +li code { + white-space: pre-wrap !important; + word-break: break-word !important; +} + +/* FAQ Dropdown Styles */ +.faq-item { + margin-bottom: 1rem; + border: 1px solid var(--md-default-fg-color--lightest); + border-radius: 8px; + overflow: hidden; + transition: all 0.3s ease; + background: var(--md-default-bg-color); +} + +.faq-item:hover { + border-color: var(--md-primary-fg-color--light); + box-shadow: 0 2px 8px rgba(124, 77, 255, 0.1); +} + +.faq-item summary { + padding: 1.25rem 1.5rem; + background: var(--md-default-bg-color); + cursor: pointer; + font-weight: 600; + font-size: 1.1rem; + color: var(--md-default-fg-color); + border: none; + outline: none; + transition: all 0.3s ease; + position: relative; + list-style: none; + user-select: none; +} + +.faq-item summary::-webkit-details-marker { + display: none; +} + +.faq-item summary::after { + content: '+'; + position: absolute; + right: 1.5rem; + top: 50%; + transform: translateY(-50%); + font-size: 1.5rem; + font-weight: 300; + color: var(--md-primary-fg-color); + transition: transform 0.3s ease; +} + +.faq-item[open] summary::after { + transform: translateY(-50%) rotate(45deg); +} + +.faq-item summary:hover { + background: rgba(124, 77, 255, 0.05); + color: var(--md-primary-fg-color); +} + +.faq-content { + padding: 0 1.5rem 1.5rem 1.5rem; + color: var(--md-default-fg-color--light); + line-height: 1.6; + animation: fadeIn 0.3s ease; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.faq-content ul { + margin: 1rem 0; + padding-left: 1.5rem; +} + +.faq-content li { + margin-bottom: 0.5rem; +} + +.faq-content strong { + color: var(--md-default-fg-color); + font-weight: 600; +} + +/* Dark theme adjustments for FAQ */ +[data-md-color-scheme="slate"] .faq-item { + background: var(--md-code-bg-color); + border-color: var(--md-default-fg-color--lightest); +} + +[data-md-color-scheme="slate"] .faq-item:hover { + border-color: var(--md-accent-fg-color); + box-shadow: 0 2px 8px rgba(255, 193, 7, 0.1); +} + +[data-md-color-scheme="slate"] .faq-item summary { + background: var(--md-code-bg-color); +} + +[data-md_color-scheme="slate"] .faq-item summary:hover { + background: rgba(255, 193, 7, 0.1); + color: var(--md-accent-fg-color); +} + +[data-md-color-scheme="slate"] .faq-item summary::after { + color: var(--md-accent-fg-color); +} + +/* FAQ section headers */ +.md-content h2 { + margin-top: 3rem; + margin-bottom: 1.5rem; + padding-bottom: 0.5rem; + border-bottom: 2px solid var(--md-default-fg-color--lightest); + color: var(--md-primary-fg-color); +} + +/* Override the general h2 styling for alert-danger specifically */ +.alert-danger h2 { + color: white !important; + font-weight: 700; + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8); + margin-bottom: 1rem; + margin-top: 0; + padding-bottom: 0; + border-bottom: none; +} + +.md-content h2:first-of-type { + margin-top: 1.5rem; +} + +/* Responsive adjustments for subscribe row */ +@media (max-width: 768px) { + .subscribe-row { + flex-direction: column; + gap: 1rem; + } + + .subscribe-logo { + width: 60px; + } +} + +/* Footer layout adjustments */ +.md-footer-meta__inner { + display: flex; + align-items: center; + justify-content: space-between; + gap: 2rem; + flex-wrap: wrap; +} + +.md-footer-nav { + display: flex; + gap: 1rem; + flex: 1; + min-width: 0; +} + +.md-footer-content { + display: flex; + align-items: center; + gap: 1rem; + flex-shrink: 0; +} + +.md-footer__link { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem; + border-radius: 4px; + transition: background-color 0.2s ease; + text-decoration: none; + color: var(--md-footer-fg-color); + font-size: 0.9rem; +} + +.md-footer__link:hover { + background: rgba(255, 255, 255, 0.1); + color: var(--md-footer-fg-color); +} + +.md-footer__button { + width: 1.5rem; + height: 1.5rem; + flex-shrink: 0; +} + +.md-footer__title { + min-width: 0; +} + +.md-footer__direction { + font-size: 0.75rem; + opacity: 0.8; + display: block; +} + +.md-ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: 500; +} + +/* Responsive adjustments for footer */ +@media (max-width: 768px) { + .md-footer-meta__inner { + flex-direction: column; + align-items: stretch; + gap: 1rem; + } + + .md-footer-nav { + justify-content: space-between; + } + + .md-footer-content { + justify-content: center; + flex-direction: column; + gap: 0.5rem; + } + + .md-footer__link { + flex: 1; + justify-content: center; + text-align: center; + } +} \ No newline at end of file diff --git a/mkdocs/docs/vision.md b/mkdocs/docs/vision.md new file mode 100644 index 0000000..eebe162 --- /dev/null +++ b/mkdocs/docs/vision.md @@ -0,0 +1,224 @@ +
+
+
+

Another Alberta is Possible

+

A province where democracy isn't just for the wealthy few, but belongs to everyone who calls Alberta home

+ +
+
+ +
+

🏛️ Democracy Under Attack

+

The UCP's Bill 54 is just the beginning. While they restrict voting access and silence opposition voices, we envision an Alberta where democracy is expanded, not eroded. Where every worker, student, immigrant, and Indigenous person has not just a voice, but real power in shaping our collective future.

+
+ +## Our Vision: True Democratic Participation + +
+
+

🗳️ Universal Voting Rights

+

If you live here, work here, or pay taxes here - you vote here.

+

No more arbitrary citizenship requirements. Permanent residents, temporary workers, students, and all community members get a say in the decisions that affect their daily lives.

+
+ +
+

⚒️ Workplace Democracy

+

Democracy doesn't end at the factory gate.

+

Worker cooperatives, union representation on corporate boards, and employee ownership programs. When workers control their workplaces, they control their communities.

+
+ +
+

🏘️ Community Power

+

Real local control over local issues.

+

Participatory budgeting, community assemblies, and neighbourhood councils with actual decision-making power over housing, transit, and development.

+
+ + +
+ +
+ +## From Exclusion to Inclusion + +While the UCP works to **restrict** who can vote and **limit** democratic participation, we fight for the opposite: a democracy that includes everyone affected by political decisions. + +
+
+

📋 Automatic Voter Registration

+

Register every Albertan automatically when they turn 18, get a health card, file taxes, or establish residency. No bureaucratic barriers.

+
+ +
+

🏢 Workplace Voting

+

Polling stations in every major workplace. Paid time off to vote. Make it easier to participate than not to participate.

+
+ +
+

🏠 Resident Voting Rights

+

Municipal voting rights for all residents regardless of citizenship status. If you live in the community, you get a say in how it's run.

+
+ +
+

📱 Digital Democracy

+

Secure online voting options, digital town halls, and mobile polling for rural and remote communities.

+
+ +
+

🗣️ Multilingual Access

+

Ballots and voting information in all community languages. Democracy shouldn't require perfect English.

+
+ +
+

♿ Universal Access

+

Every polling station fully accessible. Home voting for seniors and disabled community members. No one left behind.

+
+
+ +
+ +## Economic Democracy + +**True democracy requires economic democracy.** When a small elite controls the wealth, they control the politics. + +
+
+

🏭 The Problem: Corporate Control

+

Giant corporations and wealthy donors buy elections while working families struggle to afford housing, healthcare, and education. This isn't democracy - it's oligarchy.

+
+ +
+

🤝 The Solution: Worker Ownership

+

When workers own businesses collectively, profits stay in communities. When workers have power, they vote for policies that benefit working families, not just shareholders.

+
+
+ +
+
+

🏭 Cooperative Development

+

Public funding for worker cooperatives and employee stock ownership plans. Transform capitalism from within.

+
+ +
+

🏦 Public Banking

+

A provincial bank owned by and accountable to Albertans, not Wall Street shareholders. Looking at you ATB.

+
+ +
+

⚡ Energy Democracy

+

Community-owned renewable energy projects. Let communities profit from their own resources.

+
+ +
+

🏠 Housing as a Right

+

Public housing development, tenant cooperatives, and community land trusts to end housing as a commodity.

+
+
+ +
+ +## Indigenous Sovereignty & Solidarity + +**No democracy in Alberta is legitimate without Indigenous sovereignty.** True reconciliation means sharing power, not just consulting. + +
+
+

🚫 Colonial Democracy

+

The UCP's "democracy" continues 150+ years of colonial domination. Bill 54 affects Indigenous communities who were never consulted about its impacts on their governance and rights.

+
+ +
+

🪶 Indigenous Leadership

+

Guaranteed Indigenous representation in provincial government. Recognition of Indigenous law and governance. Land back and resource sharing agreements that respect Indigenous sovereignty.

+
+
+ +
+ +## Youth Power & Climate Justice + +**The future belongs to young people.** They deserve the biggest say in creating it. + +
+
+

🗳️ Votes at 16

+

Lower the voting age to 16 for all elections. Young people work, pay taxes, and live with political consequences longer than anyone.

+
+ +
+

🏫 School Democracy

+

Student representation on school boards. Student unions with real power over curriculum and school policy.

+
+ +
+

🌍 Climate Assemblies

+

Citizens' assemblies with youth leadership to plan Alberta's just transition to renewable energy.

+
+ +
+

💼 Youth Job Guarantee

+

Public employment programs focused on climate action, care work, and community building.

+
+
+ +
+ +## From Vision to Reality + +
+

🔥 This isn't just a dream - it's a roadmap

+

Every victory for democracy started with people who refused to accept the status quo. The eight-hour work day, women's suffrage, Indigenous rights - all won through organized struggle by ordinary people who demanded something better.

+
+ + + +--- + +*"Another world is possible. She is walking toward us on a quiet day, and I can hear her breathing."* - Arundhati Roy + +**The choice is ours: accept the UCP's vision of restricted democracy for the few, or fight for expanded democracy for all. Which Alberta do you choose?** diff --git a/mkdocs/mkdocs.yml b/mkdocs/mkdocs.yml new file mode 100644 index 0000000..3b9d17b --- /dev/null +++ b/mkdocs/mkdocs.yml @@ -0,0 +1,115 @@ +site_name: Alberta Democracy Taskforce +site_description: Defending democratic rights against UCP authoritarianism - Opposing Bill 54 and fighting for expanded democratic participation in Alberta +site_url: https://albertademocracytaskforce.org +site_author: Alberta Democracy Taskforce +docs_dir: docs +site_dir: site + +# Theme +theme: + name: material + custom_dir: docs/overrides + logo: assets/images/adtf-logo.png + favicon: assets/images/adtf-logo.png + palette: + scheme: slate + primary: deep purple + accent: amber + features: + - navigation.tracking + - navigation.indexes + - navigation.collapse + - navigation.path + - content.code.copy + - navigation.top + - navigation.tabs + - navigation.footer + +extra_css: + - stylesheets/extra.css +markdown_extensions: + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - admonition + - pymdownx.details + - attr_list + - md_in_html + - pymdownx.emoji # Simplified emoji config + - footnotes + - toc: + permalink: true + # The specific slugify line was removed to avoid previous tool error, + # you may need to add back your preferred slugify option: + # slugify: !!python/name:pymdownx.slugs.uslugify + +extra: + generator: false + +# Plugins +plugins: + - social + - search + - blog: + blog_toc: true + archive_date_format: MMMM yyyy + # - tags # Consider adding if you use tags for your blog or docs + +# Navigation +nav: + - Home: index.md + - Vision: vision.md + - Getting Started: getting-started.md + - Bill 54 Analysis: bill-54-analysis.md + - Resources: resources.md + - FAQ: faq.md + - Archive: + - Overview: archive/index.md + - Bill 54 News Coverage: + - Edmonton Journal: archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold.md + - CBC News: archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News.md + - Global News: archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca.md + - Alberta Government: archive/Alberta Government tables changes to the election act.md + - May 2024 Municipal Consultation: archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill.md + - Expert Analysis: + - The Tyee - Trump Playbook: archive/Smiths Electoral Reforms Are Straight from Trumps Playbook.md + - The Tyee - UCP Threat: archive/Why the UCP Is a Threat to Democracy.md + - The Tyee - Americanization: archive/The Dangerous Americanization of Alberta Democracy.md + - Indigenous Opposition: + - Treaty 6 Nations: archive/Central Alberta First Nations slam Bill 54.md + - Cold Lake First Nations: archive/Cold Lake First Nations opposes Albertas proposed Bill 54.md + - Municipal Impact: + - Tabulator Ban: archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News.md + - Municipal Powers: archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca.md + - Government Sources: + - Official Release: archive/Strengthening democracy Renforcer la démocratie.md + - Implementation: archive/Improving consistency and fairness in Albertas democratic processes.md + - Political Context: + - Referendum Changes: archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging.md + - Alberta Accord: archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate.md + - Blog: blog/index.md + - Contributing: + - Getting Started: contributing/index.md + - Setup Account: contributing/getting-started.md + - Navigate Gitea: contributing/navigating-gitea.md + - First Edit: contributing/first-edit.md + - Git Basics: contributing/git-basics.md + - Local Development: contributing/local-editing.md + - Submit Changes: contributing/submitting-changes.md + - Collaboration: contributing/collaboration.md + - Changemaker Lite: + - Overview: cm-lite/index.md + - Services: + - Overview: cm-lite/services/index.md + - Homepage: cm-lite/services/homepage.md + - Code Server: cm-lite/services/code-server.md + - MkDocs: cm-lite/services/mkdocs.md + - Static Server: cm-lite/services/static-server.md + - Listmonk: cm-lite/services/listmonk.md + - PostgreSQL: cm-lite/services/postgresql.md + - n8n: cm-lite/services/n8n.md + - NocoDB: cm-lite/services/nocodb.md diff --git a/mkdocs/site/404.html b/mkdocs/site/404.html new file mode 100644 index 0000000..2bb813a --- /dev/null +++ b/mkdocs/site/404.html @@ -0,0 +1,2019 @@ + + + + + + + + + + + + + + + + + + + + + + + Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + +
+ + + +
+ + +
+ +
+ +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Alberta Government tables changes to the election act/index.html b/mkdocs/site/archive/Alberta Government tables changes to the election act/index.html new file mode 100644 index 0000000..2ac2b29 --- /dev/null +++ b/mkdocs/site/archive/Alberta Government tables changes to the election act/index.html @@ -0,0 +1,2135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Alberta Government tables changes to the election act - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Alberta Government

+ +

Alberta Government tables changes to the election act

+

Multiple changes introduced to the Alberta Elections act and other legislation

+

smith-3

+

Danielle Smith[Listen to this article

+

00:05:12

+

](https://www.bpmcdn.com/files/texttospeech/7975596-7738590a-4f2e-4f7c-bcf2-07834aee7982.mp3)

+

The Government of Alberta has introduced new legislation which it believes will strengthen democracy and result in fair and quick election results.

+

Bill 54, the Election Statutes Amendment Act, 2025, was tabled in the Alberta legislature on April 29.

+

Changes included in the legislation are the banning of electronic tabulators and other automated voting machines, the elimination of vouching at voting stations, the requirement of unofficial vote counts to be completed within 12 hours of polls closing, a requirement for voters to cast their ballot in their home constituency, increasing access to special ballots, making it easier to recall elected officials, and improving the process for citizens to get petitions going.

+

"I believe that democracy thrives when people trust the process," said Premier Danielle Smith, via a media release. "These changes would make elections at every level in Alberta more accessible and transparent while protecting their integrity, ensuring confidence in the outcomes. We are also creating more opportunities for Albertans to be involved in direct democracy and to have their say on issues that matter to them.”

+

Vouching is the process of having another confirmed voter vouch for someone's identification as a registered voter, even if they aren't carrying any documentation. Instead of allowing vouching, the amended legislation will allow for an expanded array of documentation which registered voters can use to prove residence.

+

While not routinely used in Alberta, the updated legislation completely bans the use of electronic voting machines and online voting, opting instead for the traditional paper and pen, hand-counted ballots. The legislation does allow the use of voting assistance machines for those with disabilities, provided it is not connected to the internet and results in a paper, hand-counted ballot.

+

Another change being made to the legislation is a requirement that 95 per cent of voters in an electoral division be within 50 kilometres of a voting place and that every population centre with more than 1,000 electors has, at minimum, a voting place on election day and at least one day for advanced voting. Population centres with 2,500 or more residents will be open on election day and on all advance voting days.

+

Under the current legislation, special ballots may be delivered until the end of election day. With the amendments, special ballots must be received by the Friday before the election and begin being counted three hours before the polls close.

+

The legislation also makes some changes for political parties and candidates under the Election Act.

+

Under existing legislation, only candidates or their official representatives can inspect documents or request a judicial recount; under the amended legislation, political parties may inspect all documents, scrutineers may observe every aspect of the voting process, and political parties may begin and participate in judicial recounts.

+

Other notable amendments being made include changes to the Citizen Initiative Act, which the general public can use to trigger petitions.

+

Under the existing legislation, an initiative must gather signatures from 10 per cent of the registered voters province-wide for legislative and policy initiatives and 20 per cent of registered voters in two-thirds of the constituencies for constitutional initiatives in a 90-day period.

+

With the amended legislation, the threshold for success will be changed to 10 per cent of the number of eligible voters who voted in the last general election in 120 days.

+

"When we were talking about looking at the thresholds for both recall and citizen initiative, one of the reasons why we were discussing changing it is that you want a bar that's high, but you don't want a bar that's impossible to achieve," said Smith, during the press conference announcing the amendments. "We saw with some of the recall initiatives that took place at the municipal level, the bar was impossible to achieve. So we wanted to try to create something that was a little bit more reasonable."

+

Once a petition is successfully submitted, the chief electoral officer will have 30 days to decide if the requirements have been met, and if so, 60 days to submit the matter to the courts for further disposition.

+

One piece of legislation getting substantial work is the Recall Act.

+

With the new amendments, an applicant submitting under the act will be limited to 100 words explaining the reasons that the elected official should be recalled, down from 200, and the elected official will be given seven days to respond.

+

Should the recall petition be allowed to proceed, the applicant will have four months to gain the signatures on the petition. Recalls under the new rules will not be allowed within 12 months of someone being elected or within 12 months of a set general election.

+

Finally, a change being made to the Local Authorities Election Act will require all municipal and school board candidates, and third-party advertisers, to report campaign expenses by Sept. 30 of an election year, where elections are typically held in October.

+
+ +
+

About the Author: Kevin Sabo

+

Kevin Sabo has been a resident of the Castor area for the last 12 years, first moving to the area in his previous career as an EMT.

+

Read more

+
+
+
+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold/index.html b/mkdocs/site/archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold/index.html new file mode 100644 index 0000000..1b32f38 --- /dev/null +++ b/mkdocs/site/archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold/index.html @@ -0,0 +1,2293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + +

Edmonton Journal

+ +

Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold

+

Alberta is seeking to overhaul how its elections are administered including reintroducing union and corporate spending, increasing election spending limits, and banning vote tabulators as well as change rules around citizen initiatives and recall.

+

Bill 54: the Election Statutes Amendment Act, 2025 was tabled in the legislature by Justice Minister Mickey Amery on Tuesday.

+

“I believe democracy thrives when people trust the process,” Premier Danielle Smith told reporters about the bill.

+

She said the timing of the announcement, coming the day after the federal Liberals won Monday’s election, was coincidental.

+

“We were going to introduce it regardless of what the outcome of the election was. It just so happens that this is the timing now.”

+

The bill spells out more than 50 proposed changes to rules around elections and would amend seven government acts, some of which mirror the changes made to municipal elections announced last year via Bill 20.

+

Opposition justice critic Irfan Sabir said the new legislature was designed to appeal to the governing UCP’s supporter base.

+

“This act is weakening our democracy. This is bringing back dark money into our politics.”

+

Here are some of the major changes coming via Bill 54:

+

Headline News

+

Headline News

+

Get the latest headlines, breaking news and columns.

+

Unions and corporate donations

+

If passed, the legislation would allow Alberta corporations and unions to make contributions to parties, constituency associations, leadership contests and third party advertisers, among others.

+

Such contributions are prohibited under current rules in both provincial and federal elections.

+

Election spending limits

+

The bill proposes changing the formula-based approach to provincial election spending limits to a limit of $5 million for each registered political party.

+

Expense limits per candidate are set to rise to $75,000 from $60,800, and expense limits for parties in a byelection will grow to $75,000 from $28,000.

+

Recall and initiative

+

The bill proposes lowering the signature thresholds for both citizen initiatives and recall.

+

Currently, initiative petitions must have signatures from 10 per cent of registered voters provincewide for certain initiatives, rising to 20 per cent for others.

+

The bill seeks to lower that bar to 10 per cent of the number of eligible voters who voted in the last election.

+

Similarly, the bill seeks to make it easier to recall an MLA through a series of changes, including:

+
    +
  • Reducing the time limit for a recall petition from 18 months after an MLA is elected to 12 months
  • +
  • Extending the time for signatures to be gathered from 60 days to 90 days
  • +
  • Reducing the standard for a recall vote to be authorized from signatures from 40 per cent of the total number of electors to 60 per cent of the total number of electors who voted in the most recent election
  • +
+

No more ‘vote anywhere’ or vouching, new special ballot rules

+

The bill would end the ability of voters in a provincial election to vote outside of their constituency at designated stations.

+

The “vote anywhere” option has been credited with making voting more accessible and for boosting turnout.

+

Following the 2023 election, officials also cited changes to how those ballots were counted as cause for election night delays in reporting results.

+

The legislation also proposes to end the practice of vouching, where an eligible voter in the same voting area vouches for a voter without identification.

+

It also seeks to amend rules around special ballots which are currently only available when a voter is unable to vote on the regular election day.

+

Under the new legislation, special ballot use would be expanded and voters could use one without having to first give a reason.

+

Tabulator ban

+

Similar to municipal elections, the use of electronic vote tabulators will be banned for provincial elections.

+

No lengthy ballots

+

The bill also proposed preventing a single official agent from acting on behalf of more than one independent candidate.

+

During Monday’s federal elections, voters in the Ottawa riding of Carleton had to navigate a field of 91 candidates on a ballot, including 83 independents all of whom listed the same individual as their official agent.

+

mblack@postmedia.com

+
+

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News/index.html b/mkdocs/site/archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News/index.html new file mode 100644 index 0000000..1c05145 --- /dev/null +++ b/mkdocs/site/archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News/index.html @@ -0,0 +1,2239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Alberta overhauls election laws to allow corporate donations, change referendum thresholds | CBC News - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + +

CBC News

+ +

Alberta overhauls election laws to allow corporate donations, change referendum thresholds | CBC News

+

Edmonton

+

Alberta overhauls election laws to allow corporate donations, change referendum thresholds

+

The Alberta government wants to bring back corporate and union political donations, eliminate vouching for a voter’s identity at election polling stations, and lower the threshold for recalls and referendums.

+

Bill 54 also eliminates vouching and prohibits use of vote tabulators

+

Justice Minister Mickey Amery talks about his new Bill 54 as Premier Danielle Smith stand to the side, listening.

+

Justice Minister Mickey Amery talks about Bill 54 Tuesday as Premier Danielle Smith listens. (Maxime Lamache/Radio Canada )

+

The Alberta government wants to bring back corporate and union political donations, eliminate the process of vouching for a voter's identity at election polling stations, and lower the threshold for recalls and referendums.

+

The measures are proposed in Bill 54, Election Statutes Amendment Act, 2025, tabled by Justice Minister Mickey Amery in the legislature Tuesday.

+

The bill, which amends seven pieces of legislation including the Election Act, would also ban the use of electronic vote tabulators, a measure that was promised by Premier Danielle Smith's United Conservative government.

+

Smith told a news conference that her government wants to make it easier for Albertans to express their political views.

+

"These changes build on the integrity, trust and openness that have always been at the heart of democracy and keep Alberta strong and free," she said.

+ +

The ban on corporate and union donations to political parties was in the first piece of legislation passed by Rachel Notley's NDP government in 2015.

+

If passed, Bill 54 will allow these types of contributions to an aggregate maximum of $5,000 to parties, constituency associations, candidates and third-party political advertisers. The bill also sets a separate contribution limit of $5,000 for leadership candidates.

+

Amery said there are differences for how the donations will be reported this time.

+

"All candidates have to account for where their money is coming from, who it's coming from and make sure that that is publicly disclosed to members of the public," he said in an interview with CBC News.

+

"Moreover, at this time the corporate donations, for example, are not tax deductible. And so that is an important component that differs, I think, from previous time."

+

Last fall, the government passed legislation allowing corporate and union donations in municipal elections.

+

Recall and referendum changes

+

Currently, voters who lack proper identification can still vote if another eligible voter from their riding is able to vouch for them. Bill 54 will eliminate vouching but it expands the types of identification that can be used to prove someone lives in the electoral district and can vote.

+

The Recall Act and the Citizens Initiative Act, passed by the UCP government in 2021, outlines the process by which citizens can initiate the recall of an elected MLA. People have since complained that the timeline and number of signatures required for a successful petition were too onerous.

+

Bill 54 proposes lowering the signature threshold, and extending the signature collection period from 60 to 90 days for MLA recalls and from 90 to 120 days for a citizen's initiative or referendum.

+

The number of signatures for an MLA recall would be 60 per cent of the number who voted in a riding in the most recent provincial election. The current threshold is 40 per cent of all eligible voters in that riding.

+

The threshold for a referendum would be 10 per cent of people who voted in the last provincial election, compared to the current 10 per cent of all registered voters for legislative and policy referendums and 20 per cent of registered voters in two-thirds of Alberta ridings for constitutional questions.

+

If the bill is passed, an MLA who is the subject of a recall petition could add a response to the reasons listed by the petitioner.

+

A recall vote would be moved up to four months from the current six months if the petition is approved by the chief electoral officer.

+

MLA Irfan Sabir, the NDP Opposition justice critic, said he is concerned the government is loosening the rules around referendums to whip up separatist discontent among their base.

+

Sabir said he is worried that corporate donors will use a numbered company and make it more difficult to trace the source of a donation.

+

"I think elections should not be about who has more money or has deep pockets," Sabir said. "Elections should be about ideas and broader participation from the public."

+

The use of tabulator or electronic vote counting machines will be banned under Bill 54 so ballots will have to be counted by hand. The bill sets a deadline of 12 hours for the unofficial vote count to be completed.

+

Other measures proposed in Bill 54 include:

+
    +
  • Requiring municipal councillors and school trustees to take an unpaid leave of absence when they run in a provincial election.
  • +
  • Increasing spending limits for third-party advertisers from $182,000 to $500,000 in both the pre-writ and election periods.
  • +
  • Allowing mail-in ballots for constitutional referendums. They are currently allowed for non-constitutional referendums.
  • +
  • Giving the chief electoral officer the ability to hold referendum votes on First Nations and Métis settlements at the same time as a municipal election.
  • +
  • Requiring municipal and school board candidates to report their donations by Sept. 30, in advance of the October election. The requirement would also apply to third-party advertisers.
  • +
  • Allow people to buy party memberships for family members without requiring a receipt if the purchase is under $50. Current rules allow people to buy only memberships for themselves.
  • +
+

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca/index.html b/mkdocs/site/archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca/index.html new file mode 100644 index 0000000..27eb656 --- /dev/null +++ b/mkdocs/site/archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca/index.html @@ -0,0 +1,2189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Alberta to make changes to bill proposing sweeping powers over municipalities | Globalnews.ca - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Municipal Powers

+ +

Alberta to make changes to bill proposing sweeping powers over municipalities | Globalnews.ca

+

Politics

+

Alberta to make changes to bill proposing sweeping powers over municipalities

+

Click to play video: 'Alberta Municipalities speaks out over province’s Bill 20 to have more control over local politics'

+

Alberta Municipalities speaks out over province’s Bill 20 to have more control over local politics

+

The Alberta government says it will make amendments to a bill that would give cabinet unfettered power to fire mayors and councillors and overturn bylaws.

+

Municipal Affairs Minister Ric McIver said in a statement Thursday that the government will introduce changes and implement rules surrounding how and when cabinet can overrule local governments.

+

McIver said the province will work with municipalities on the amendments.

+

The bill is before the legislature and has been criticized by municipal leaders as a severe overreach into municipal government affairs.

+

“What I would propose is, don’t move ahead with Bill 20 at all. There’s no need for it,” Edmonton Mayor Amarjeet Sohi said Thursday.

+

Sohi said he is pleased to hear McIver is responding to the criticism and concerns raised about the bill, and that he’s open to discussing changes with those who have raised issues with it.

+

“If there’s a problem they want to solve I think the best way to do that is co-create legislation, not just impose legislation on municipalities,” Sohi said. “This has been kind of a one-way street where we are being told what they are going to do instead of listening to us and engaging with us.”

+

Calgary Mayor Jyoti Gondek said she too is appreciative that the minister has indicated he wants to consult with municipalities, but added the legislation as it stands is a “great overreach.”

+

“I’ve had a call with him. He reiterated that he will be engaging with us, so that’s great. But I continue to see an issue with the idea of saying that someone could be removed in the public interest without defining what that means,” Gondek said.

+

“If they’re truly interested in making sure that someone who’s broken a law or misrepresented themselves or done something unethical is to be removed, then that language needs to be clear.”

+

Gondek also noted she is unclear how the consultation process is going to unfold.

+

“Bill 20 comes with a whole lot of questions and right now there’s not a lot of answers.”

+

Click to play video: 'Alberta Municipalities ‘caught off guard’ by details of Bill 20'

+

Alberta Municipalities ‘caught off guard’ by details of Bill 20

+

Alberta Municipalities president Tyler Gandam has said members are concerned the proposed law would intimidate and silence legally elected officials who dare criticize the province.

+

McIver said he wants to make it clear that the new powers in the bill would only be used as a last resort.

+

He said the power to repeal municipal bylaws should be used only when those bylaws fall under areas of shared responsibility, such as health care, education, the provincial economy or public safety.

+

Sohi went on to say that if the legislation does move forward, he believes it should be used only in the rarest of circumstances. He also believes any use of the bill should be discussed in the legislature, and not just within cabinet.

+

“Cabinet decisions are not made in a transparent, open way and there’s no accountability on cabinet. There is accountability in the legislature where people can ask questions around why a council member is being removed or why a duly-passed bylaw by a council is being repealed by the province,” Sohi said.

+

He also believes there is no need for political parties at a municipal level.

+

“Let people decide who they elect, and then let the local elected people make decisions on behalf of the constituents that have elected us.”

+

The Alberta NDP’s critic for municipalities said rather than make amendments, the UCP needs to withdraw Bill 20 entirely.

+

“Bill 20 is a threat to our democracy,” Kyle Kasawski said in a statement.

+

“This bill is another example of Smith’s made-in-Alberta authoritarian approach to governing. The UCP wants to control everything, whether it be our universities, schools, health care, police force, pensions and now municipal councils.”

+

— with files from The Canadian Press

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca/index.html b/mkdocs/site/archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca/index.html new file mode 100644 index 0000000..18bbde3 --- /dev/null +++ b/mkdocs/site/archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca/index.html @@ -0,0 +1,2172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Alberta’s chief electoral officer warns UCP proposed bill will hurt investigations | Globalnews.ca - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + +

Global News

+ +

Alberta’s chief electoral officer warns UCP proposed bill will hurt investigations | Globalnews.ca

+

Politics

+

Alberta’s chief electoral officer warns UCP proposed bill will hurt investigations

+

Click to play video: 'Alberta proposes sweeping changes to provincial election laws'

+

Alberta proposes sweeping changes to provincial election laws

+

Alberta’s chief electoral officer is warning the government that proposed legislation will impair the election commissioner’s power to investigate election rule breaking.

+

A controversial bill introduced last month, if passed, will make sweeping changes to voting and referendums in the province, and is making its way through debate in the legislature.

+

In documents sent to Justice Minister Mickey Amery and all legislature members, chief electoral officer Gordon McClure warns that some changes in the bill will reduce the election commissioner’s ability to investigate and enforce compliance with election law, including financial contribution rules.

+

Alberta's Chief Electoral Officer, Gordon McClure, warns new UCP legislation will reduce the election commissioner's ability to investigate and enforce compliance with election laws.

+

Alberta’s Chief Electoral Officer, Gordon McClure, warns new UCP legislation will reduce the election commissioner’s ability to investigate and enforce compliance with election laws. Global News

+

A summary of concerns attached to the email says that under one of the bill’s proposed changes, none of the significant investigations undertaken by the election commissioner in the last five years would have happened and some current investigations would need to be abandoned.

+

Amery says all of the bill’s proposals are meant to protect democracy, deliver fair and open elections, and restore confidence in every vote cast by Albertans, but he did not directly address McClure’s concerns.

+

Opposition NDP justice critic Irfan Sabir says McClure’s letter makes it clear the United Conservatives are undermining investigations into election law, which would let those who break the rules off the hook.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Central Alberta First Nations slam Bill 54/index.html b/mkdocs/site/archive/Central Alberta First Nations slam Bill 54/index.html new file mode 100644 index 0000000..c383350 --- /dev/null +++ b/mkdocs/site/archive/Central Alberta First Nations slam Bill 54/index.html @@ -0,0 +1,2135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Central Alberta First Nations slam Bill 54 - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Treaty 6 Nations

+ +

Central Alberta First Nations slam Bill 54

+

Treaty 6 Nations vow to fight against separation legislation

+

web1_240222-rda-alberta-sports-hall-of-fame2

+

Alberta Government House Leader Joseph Schow (Advocate file photo)[Listen to this article

+

00:05:03

+

](https://www.bpmcdn.com/files/texttospeech/8011556-476b864d-f154-457f-a908-e1ae638ae6ec.mp3)

+

Central Alberta First Nations have vowed to fight provincial legislation that would make it easier to put forward citizen-led referendums, including separation from Canada questions.

+

"Premier (Danielle) Smith's government is not interested in partnership," said the Confederacy of Treaty 6 First Nations in a statement Thursday. "(I)nstead they sow division among Albertans and attack our Treaties by passing Bill 54.

+

"We will fight against separtion and any 'citizen-led' referendum that threatens Treaty."

+

Treaty 6 covers 15 First Nations, including Sunchild and O'Chiese, northwest of Rocky Mountain House, and Maskwacis's Samson, Louis Bull, Ermineskin and Montana First Nations. Alexander, Alexis Nakota Sioux, Beaver Lake, Cold Lake, Enoch, Frog Lake, Whitefish Lake, Heart Lake and Kehewin Cree First Nations are also part of the treaty first signed in 1876.

+

The provincial government's Bill 54, known as the Election Statutes Amendment Act, among other things, lowers the threshold for citizen-led referendums. After First Nations groups complained, last-minute changes to the legislation were made declaring that existing treaty rights could not be threatened by any referendum question.

+

"I believe that democracy thrives when people trust the process," said Premier Danielle Smith, via a media release last month. "These changes would make elections at every level in Alberta more accessible and transparent while protecting their integrity, ensuring confidence in the outcomes. We are also creating more opportunities for Albertans to be involved in direct democracy and to have their say on issues that matter to them.”

+

With the amended legislation, the threshold for success will be changed to 10 per cent of the number of eligible voters who voted in the last general election in 120 days.

+

"When we were talking about looking at the thresholds for both recall and citizen initiative, one of the reasons why we were discussing changing it is that you want a bar that's high, but you don't want a bar that's impossible to achieve," said Smith, during the press conference announcing the amendments. "We saw with some of the recall initiatives that took place at the municipal level, the bar was impossible to achieve. So we wanted to try to create something that was a little bit more reasonable."

+

Once a petition is successfully submitted, the chief electoral officer will have 30 days to decide if the requirements have been met, and if so, 60 days to submit the matter to the courts for further disposition.

+

The new amendments fall short of the changes First Nations groups wanted that would have made it impossible for a separation referendum to go forward.

+

"First Nations have always been kind and loving, but our kindness is taken advantage of. Let us be clear: we are not subordinate to Alberta or Canada. Our relationship is Nation-to-Nation with the Crown, and that relationship must be respected," says the statement from Confederacy of Treaty 6 Grand Chief Greg Desjarlais.

+

Desjarlais said they are prepared to take their fight to the courts.

+

"Our rights are affirmed and protected by Section 35 of the Constitution — we will not hesitate to assert them. Our sacred Treaty will not be undone by the thoughtless and careless actions of a loud minority.

+

"You cannot undermine our rights or our future."

+

Alberta House Leader Joseph Schow said in a news conference on Thursday that the bill is a large piece of legislation is about making elections transparent and fair and not just about referendums.

+

He said he was not surprised at the response because it involves change. "But I think it is change in response to the requests that we've had.

+

"The most important thing we can do as a government is ensure confidence in election results and that's what I think this piece of legislation does."

+

NDP Opposition Leader Christina Gray criticized the UCP government for Bill 54, as well as its lack of action on addressing cost of living or the health-care system "crisis."

+

"Not only did they pass anti-democratic legislation like Bill 54, but they used anti-democratic tactics in the Legislature to get it done."

+

Gray took aim at the Smith government for using time allocation motions that "cut off debate and allowed them to ram through controversial legislation with minimal scrutiny or public awareness."

+

The UCP government has refused to pass any NDP Private Member's Bills, while passing all of those introduced by UCP MLAs, she says.

+

Gray also accused the UCP of covering up a health-care inquiry and passing a provincial budget that cuts critical services and "did nothing for Albertans."

+

Editor's Note: This article has been updating to include additional comments and information from the Government of Alberta regarding Bill 54.

+
+ +
+
+
+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Cold Lake First Nations opposes Albertas proposed Bill 54/index.html b/mkdocs/site/archive/Cold Lake First Nations opposes Albertas proposed Bill 54/index.html new file mode 100644 index 0000000..705a5dc --- /dev/null +++ b/mkdocs/site/archive/Cold Lake First Nations opposes Albertas proposed Bill 54/index.html @@ -0,0 +1,2110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cold Lake First Nations opposes Alberta's proposed Bill 54 - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Cold Lake First Nations

+ +

Cold Lake First Nations opposes Alberta's proposed Bill 54

+

CLFN asserts that such measures threaten their treaty rights and sovereignty.

+

In a statement released on May 7, CLFN shared their identity as the Denesuline of Łué Chok Tué, original signatories of Treaty 6 in 1876. They highlighted their millennia-long occupation of ancestral lands in northeastern Treaty 6 territory, stating that their culture, language, and way of life are inherently tied to these lands.

+

Chief Kelsey Jacko declared, "We are part of the land that continues to sustain us."

+

The letter expressed strong opposition to the proposed changes in the Alberta Elections Act, particularly the provision allowing a citizen-led referendum on provincial separation from Canada in 2026.

+

Jacko described this move as "reckless, dangerous and deeply disrespectful to the original peoples as holders of inherent rights and title." The statement further asserted, "Our treaties are solemn and sacred agreements... We continue to honour our sacred treaties and will do so forever, including protecting the lands that have sustained our people for thousands of years."

+

The proposed Bill 54 aims to amend the Alberta Elections Act by lowering the threshold for citizen-initiated referendums. The bill proposes reducing the required number of signatures from 20 per cent to 10 per cent of eligible voters and extending the collection period from 90 to 120 days. This change would make it easier for citizens to trigger referendums on various issues, including provincial separation, as detailed in the Government of Alberta's official fact sheet on the Election Statutes Amendment Act, 2025.

+

Premier Danielle Smith addressed the province on May 5, stating that while she does not support Alberta's separation from Canada, she would respect the democratic process if a citizen-led petition met the required criteria.

+

She noted, "If there is a successful citizen-led referendum petition... our government will respect the democratic process and include that question on the 2026 provincial referendum ballot,” according to the Government of Alberta website.

+

The Premier affirms a firm commitment to protecting and honoring the inherent rights of First Nations, Métis, and Inuit peoples. Any citizen-initiated referendum must not violate their constitutional rights and must respect Treaties 6, 7, and 8. This commitment is non-negotiable.

+

Jacko added that they “will not be forced by any settler government to relocate, renegotiate our treaties or longstanding legal and political orders and relationships at the whim of settler populations.”

+

In the letter, Cold Lake First Nations made clear that their rights and title have never been surrendered, stating, “We never surrendered our sovereignty. Our rights and title to our ancestral lands continue in force today and forever.” Jacko added, “Our treaty is not negotiable; it never was and never will be.”

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging/index.html b/mkdocs/site/archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging/index.html new file mode 100644 index 0000000..acada73 --- /dev/null +++ b/mkdocs/site/archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging/index.html @@ -0,0 +1,2126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Referendum Changes

+ +

Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging

+

Alberta flag.

+

If passed into provincial law, the new bill would pave the way to put a citizen-proposed constitutional referendum question on the ballot with the signatures of just over 175,000 Albertans, based on 2023 electoral numbers. Photo by Azin Ghaffari/Postmedia

+

OTTAWA — Alberta Premier Danielle Smith says she’ll make it easier for citizens to initiate a referendum on the province’s future in Canada, after warning that a Liberal win in Monday’s election could spur a groundswell of support for Alberta separatism.

+

Smith said on Tuesday that a newly tabled elections bill will give everyday Albertans a bigger say in the province’s affairs.

+

“(We’re giving) Albertans more ways to be directly involved in democracy, and to have their say on issues that matter to them,” Smith told reporters in Edmonton.

+

First Reading

+

If passed, the new law would dramatically lower the number of signatures needed to put a citizen-proposed constitutional referendum question on the ballot, setting a new threshold of 10 per cent of general election turnout — or just over 175,000, based on Alberta’s last provincial election in 2023.

+

The law will also extend the signature collection time for citizens’ initiatives, from 90 to 120 days, and get rid of the existing riding-level threshold for signatures.

+

Smith said on Tuesday that the current threshold of 20 per cent of registered voters, roughly 600,000 signatures, is far too high, making citizens’ initiatives virtually impossible to move forward.

+

“You want a bar that’s high, but you don’t want a bar that’s impossible to achieve… so we wanted to try to create something that was a little bit more reasonable.” said Smith.

+

Smith noted that there haven’t been any citizen-initiated referendums under the existing threshold, set in 2022.

+

“That also suggested to us that people thought it was just pointless to go out and try to get that many signatures.”

+

Smith said that, while she personally supported Alberta staying in Canada, she wouldn’t stand in the way of a citizen-led referendum on independence.

+

“(T)here is a citizen initiative referendum process that if citizens want to put a question on the ballot and get enough of their fellow citizens to sign that petition, then those questions will be put forward… I don’t want to pre-judge what a question might be,” said Smith.

+

Smith previously announced she’d be setting up a post-election panel that will give citizens a chance to put forward potential referendum questions.

+

Polls heading into Monday’s federal election showed that as many as three in 10 Albertans would vote for Alberta to leave Canada if the Liberals won a fourth term in office.

+

Danielle Smith

+

Premier Danielle Smith announces proposed changes to several pieces of democratic process legislation at the Alberta Legislature on April 29, 2025. Photo by Shaughn Butts/Postmedia

+

Take Back Alberta founder David Parker said on Wednesday that his online petition for a referendum on Alberta sovereignty had collected more than 80,000 signatures in less than 36 hours.

+

Parker said he expected to hit the 200,000 mark by the end of the week.

+

Karamveer Lalh, an Edmonton-based lawyer who helped write the first version of the citizens’ initiatives law, said that he expects to see other grassroots campaigners test the waters in the coming weeks.

+

“You ideally want the movement and infrastructure to be in place before you actually go forward with trying to go through the petition process,” Lalh told the National Post.

+

“Basically, you want to be confident that you’ll be able to get the signatures to cross the threshold before you’re officially on the clock.”

+

National Post

+

rmohamed@postmedia.com

+

Get more deep-dive National Post political coverage and analysis in your inbox with the Political Hack newsletter, where Ottawa bureau chief Stuart Thomson and political analyst Tasha Kheiriddin get at what’s really going on behind the scenes on Parliament Hill every Wednesday and Friday, exclusively for subscribers. Sign up here.

+

Our website is the place for the latest breaking news, exclusive scoops, longreads and provocative commentary. Please bookmark nationalpost.com and sign up for our politics newsletter, First Reading, here.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Improving consistency and fairness in Albertas democratic processes/index.html b/mkdocs/site/archive/Improving consistency and fairness in Albertas democratic processes/index.html new file mode 100644 index 0000000..677ef71 --- /dev/null +++ b/mkdocs/site/archive/Improving consistency and fairness in Albertas democratic processes/index.html @@ -0,0 +1,2306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Improving consistency and fairness in Alberta’s democratic processes - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Implementation

+ +

Improving consistency and fairness in Alberta’s democratic processes

+

Status: Bill 54 received Royal Assent on May 15, 2025.

+

Ministry responsible: Justice

+

Overview

+

The Election Statutes Amendment Act, 2025 (formerly Bill 54), will ensure democratic processes are aligned and conducted in a transparent manner. Democratic processes include elections, whether provincial, municipal or Senate, and direct democracy processes like referendums, MLA recall and citizen initiative petitions. These legislative amendments are occurring together to help ensure a consistent framework for democratic processes.

+

The act will aim to increase fairness in provincial elections by improving investigation and enforcement of election rules.

+

Additional amendments will:

+
    +
  • improve access to voting and timeliness and accuracy of election results
  • +
  • permit Alberta businesses and unions to make contributions related to provincial elections and direct democracy processes
  • +
  • hold MLAs accountable
  • +
+

Key changes

+

The Election Statutes Amendment Act, 2025 amends the following legislation. Read the Election Statutes Amendment Act, 2025 fact sheet for a complete list of amendments.

+
    +
  • +
      +
    • Bans the use of electronic vote tabulators and the use of vouching.
    • +
    • Expands the availability and integrity of special ballots.
    • +
    • Requires the unofficial vote count to be completed within 12 hours of polls closing.
    • +
    • Requires Albertans to vote in their electoral divisions.
    • +
    • Expands the types of identification that can be used to prove residence.
    • +
    • Expands rights for political parties and scrutineers.
    • +
    • Allows the province to set regulations for election signs and advertising.
    • +
    • Clarifies that government may advertise during elections if the advertising does not have an undue influence on voters.
    • +
    +
  • +
  • +
      +
    • Allows corporate and union contributions for provincial elections and applies existing reporting requirements.
    • +
    • Reduces the maximum limit on contributions to third party advertisers.
    • +
    • Adjusts party and candidate expense limits to recognize the increasing costs of campaigning.
    • +
    • Increases third party election advertising spending limits.
    • +
    +
  • +
  • +
      +
    • Improves the process for responding to emergencies and improves access to voting by First Nations and Metis Settlements.
    • +
    +
  • +
  • +
      +
    • Improves the process for responding to emergencies and improves access to voting by First Nations and Metis Settlements.
    • +
    • Requires third-party referendum advertisers to indicate if they are for or against a referendum question or questions – this change is included in the Election Finances and Contributions Disclosure Act but applies to referendums.
    • +
    • Removes the requirement for a referendum before a resolution for a constitutional amendment.
    • +
    • Creates a regulation making power under which the government may specify the extent to which provisions of the Election Finances and Contributions Disclosure Act apply to a referendum.
    • +
    • Adds a section that states nothing in a referendum held under this act is to be construed as abrogating or derogating from the existing Aboriginal and treaty rights of the Aboriginal Peoples of Canada that are recognized and affirmed by section 35 of the Constitution Act, 1982.
    • +
    +
  • +
  • +
      +
    • Increases public trust in the recall process and improves the process for Albertans to hold their elected MLAs accountable between elections.
    • +
    +
  • +
  • +
      +
    • Increases Albertans’ ability to have their voices heard and play a more direct role in the democratic process by initiating action on issues that affect them.
    • +
    +
  • +
  • +
      +
    • Improves transparency by updating campaign finance rules for candidates and third-party advertisers to report by September 30 of the election year, rather than March 1 of the following year.
    • +
    +
  • +
+

Next steps

+

The amendments to the Local Authorities Election Act came into force May 15, 2025. Changes to all other acts will come into force on proclamation.

+

Resources

+ +

News

+ + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill/index.html b/mkdocs/site/archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill/index.html new file mode 100644 index 0000000..d49c62a --- /dev/null +++ b/mkdocs/site/archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill/index.html @@ -0,0 +1,2290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + May 2024: Alberta Municipalities said it hasn't been given chance to consult on changes to bill - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + +

May 2024 Municipal Consultation

+ +

May 2024: Alberta Municipalities said it hasn't been given chance to consult on changes to bill

+

Notification Settings

+

This browser doesn't support push notifications at the moment. Check browsers features, update your browser or try to use one from the list of recommended to manage your notifications settings:

+
    +
  • Firefox (27+)
  • +
  • Google Chrome (30+)
  • +
  • Safari ( MacOS 13+ with browser 16.1+ and iOS 16.4+ ) / Note make sure Push API support enabled under Settings > Safari > Advanced > Experimental Features
  • +
  • Microsoft Edge
  • +
+

If you wish to manage your notification settings from this browser you will need to update your browser's settings for this site. Just click button below and allow notifications for this site

+

Note Safari 16.4+ working on iOS devices also need this site app to be installed at device's Home Screen for Push Notifications to work

+

Manage Notification Settings

+

Close

+ +

EDMONTON - Alberta's municipal affairs minister declined Monday to clarify whether towns and cities would still get their say before changes are made to a contentious bill that gives the province broad authority to fire local councillors.

+

Read this article for free:

+

To continue reading, please subscribe:

+

Monthly Digital Subscription

+

$19 + tax for 4 weeks
+and receive a Canada Proud Manitoba Strong mug and sticker FREE!

+
    +
  • Enjoy unlimited reading on winnipegfreepress.com
  • +
  • Read the E-Edition, our digital replica newspaper
  • +
  • Access News Break, our award-winning app
  • +
  • Play interactive puzzles
  • +
+

Canada Proud, Manitoba Strong mug and sticker

+

*Special offer only available to new subscribers or returning subscribers without a subscription for more than eight weeks. New subscription must remain active for at least 12 weeks. If cancelled prior to 12 weeks, you will be charged regular price for the merchandise. Merchandise is provided “as is” and cannot be exchanged. Expect merchandise delivery within two weeks for addresses within Manitoba and up to four weeks if outside of Manitoba.

+

To continue reading, please subscribe:

+

Add Winnipeg Free Press access to your Brandon Sun subscription for only

+

$1 for the first 4 weeks*

+
    +
  • Enjoy unlimited reading on winnipegfreepress.com
  • +
  • Read the E-Edition, our digital replica newspaper
  • +
  • Access News Break, our award-winning app
  • +
  • Play interactive puzzles +Start now
  • +
+

No thanks

+

*$1 will be added to your next bill. After your 4 weeks access is complete your rate will increase by $0.00 a X percent off the regular rate.

+

EDMONTON - Alberta's municipal affairs minister declined Monday to clarify whether towns and cities would still get their say before changes are made to a contentious bill that gives the province broad authority to fire local councillors.

+

Read unlimited articles for free today:

+

Hey there, time traveller!
+This article was published 06/05/2024 (388 days ago), so information in it may no longer be current.

+

EDMONTON – Alberta’s municipal affairs minister declined Monday to clarify whether towns and cities would still get their say before changes are made to a contentious bill that gives the province broad authority to fire local councillors.

+

Ric McIver announced the changes last Thursday and promised at that time he would talk to municipal leaders about looming amendments to the bill.

+

But on Monday, when asked by reporters on the state of consultations, McIver pointed to the fact he already spoke with multiple leaders “over the last few days” about the impending changes.

+

Minister of Municipal Affairs Ric McIver and Alberta Premier Danielle Smith take part in a press conference in Edmonton on Wednesday April 10, 2024. THE CANADIAN PRESS/Jason Franson

+

Minister of Municipal Affairs Ric McIver and Alberta Premier Danielle Smith take part in a press conference in Edmonton on Wednesday April 10, 2024. THE CANADIAN PRESS/Jason Franson

+

When asked if he considered those discussions to be the promised consultation, McIver declined to clarify.

+

“It’s one form of consultation, it’s certainly not the only form,” he replied.

+

The bill, introduced April 25, has been widely condemned by municipal leaders as a broad overreach into their authority with a possible chill effect on their decision making.

+

The bill not only gives cabinet broad power to fire councillors but also overturn any council bylaw.

+

This weekend, Craig Snodgrass, the mayor of High River – Premier Danielle Smith’s hometown — said the only reason the bill is on the table is because the UCP has failed to get “their people” into the mayor’s seat in Edmonton and Calgary.

+

“This is about control. It won’t end with the big cities. Scrap it,” Snodgrass wrote on social media.

+

McIver said last week the amendments will address those concerns but has not provided specifics.

+

Tyler Gandam, president of Alberta Municipalities — the organization representing Alberta towns, cities and villages – confirmed that McIver called him last week to say changes were coming, but said that has been it.

+

“Minister McIver committed to consulting with Alberta Municipalities in advance of the announcement of the forthcoming amendments, but nothing has been arranged yet,” Gandam said in a statement.

+

“I trust we will have the opportunity to address our concerns on all parts of the bill,” he said.

+

Paul McLauchlin, head of Rural Municipalities of Alberta, told CHED radio Monday he has had “discussions” with McIver.

+

While McLauchlin said he’s hopeful McIver has heard the organization’s concerns and will make necessary changes, he said nobody was asking for a bill making it easier for cabinet to remove local councillors or mayors.

+

“What is the point? Is the point to assert authority? Or is the point to provide clarity to governance?” said McLauchlin.

+

It’s also not clear when the amendments will be brought to the floor of the legislature.

+

Smith has said amendments would come this week and would clarify the new cabinet powers would be used only sparingly.

+

Asked Monday about the timeline, McIver said, “When amendments are ready, we will introduce them in the house.”

+

But McIver said time is a factor. He said the government aims to ensure the bill passes debate in the legislature in the current sitting, which is scheduled to rise at the end of the month.

+

Opposition New Democrats have said the bill is so flawed it needs to be pulled altogether.

+

McIver said municipal officials will need time to get ready for the next elections in October 2025.

+

“Time is ticking, and it’s an important issue,” McIver said.

+

The bill also makes changes to local elections, including mandating hand-counted ballots, and green lighting political parties to run in Edmonton and Calgary.

+

This report by The Canadian Press was first published May 6, 2024.

+ +

Report Error Submit a Tip

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate/index.html b/mkdocs/site/archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate/index.html new file mode 100644 index 0000000..b2e81ef --- /dev/null +++ b/mkdocs/site/archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate/index.html @@ -0,0 +1,2136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Smith pushes ‘Alberta Accord,’ defends citizen referendums amid separation debate - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Alberta Accord

+ +

Smith pushes ‘Alberta Accord,’ defends citizen referendums amid separation debate

+

+

Premier Danielle Smith says her government is pursuing a stronger role for Alberta within Confederation and launching negotiations with Ottawa on a new “Alberta Accord” — while defending recent changes that would make it easier for citizens to trigger a referendum, including on the province’s possible separation from Canada.

+

In back-to-back media appearances Monday and Tuesday, Smith struck a firm but conciliatory tone, saying she is hopeful new Prime Minister Mark Carney will work with Alberta to address long-standing grievances over energy policy, resource access, and federal oversight.

+

“These conversations are a positive first step,” Smith said Monday, following her first face-to-face meeting with Carney. “But it will take tremendous effort and cooperation to repair the damage to Alberta’s economy caused in the last 10 years by Ottawa’s destructive anti-resource agenda.”

+

The Alberta government is establishing a formal negotiating team and plans to consult Albertans over the next six months on constitutional reforms. Smith said demands include guaranteed tidewater access on all three coasts for Alberta’s energy products, the repeal of federal laws like Bill C-69 and clean electricity regulations, and per-capita federal transfers equal to those received by Ontario, Quebec and British Columbia.

+

Smith also confirmed the creation of an “Alberta Next” panel to explore long-term economic and constitutional options — potentially leading to a referendum in 2026.

+

But the premier repeatedly denied that her government is pushing Alberta toward separation. Instead, she defended Bill 54, which lowers the threshold for citizen-led referendums, saying it empowers grassroots democracy without promoting secession.

+

“I don’t have a mandate, and my party doesn’t support [separation],” she said. “A citizen-initiated referendum would be, by definition, initiated by citizens. All I’ve said is I will honour the process.”

+

The comments come as frustration in Alberta continues to simmer in the wake of last month’s federal election, with Ottawa’s climate and energy policies cited by many Albertans as evidence of chronic regional alienation. Smith acknowledged that public anger is real.

+

“There’s a lot of anger after the last election — a lot of anger at the way we’ve been treated for the last 10 years,” she said. “I believe in free speech. Citizens have a right to express their opinion… It’s my job to make sure that debate is respectful.”

+

Smith was pressed repeatedly about whether she would honour the results of a hypothetical referendum on separation. She remained non-committal.

+

“Until I see an actual question with 177,000 signatures of Albertans that are supportive of it, it is difficult for me to know what that looks like,” she said Tuesday.

+

Smith said she believes support for separation sits at around 30 per cent but hopes that number will drop as negotiations with Ottawa proceed.

+

During her Monday remarks, Smith emphasized that Alberta is seeking more autonomy over areas such as immigration and agriculture, citing Section 95 of the Constitution as grounds for provincial authority.

+

“These are a couple of things that we would put to the people,” she said, adding that Quebec’s model of fiscal independence may offer a path forward.

+

Critics have raised alarms about Alberta’s embrace of California-style citizen initiatives, warning that the model could create policy instability. Smith dismissed those concerns.

+

“Albertans don’t want to vote on every little thing,” she said. “But they might want to vote on some big things.”

+

She also brushed off a warning from Ontario Premier Doug Ford, who recently criticized separatist rhetoric. Smith said she and Ford have a “great friendship,” but that Alberta’s issues differ from Ontario’s.

+

“He’s the premier of Ontario. I’m the premier of Alberta,” she said. “I don’t tell him how he should run his province, and I would hope he doesn’t tell me how to run mine.”

+

The growing debate around referendums has drawn opposition from First Nations across Alberta and Canada. Chiefs from Treaties 6, 7, 8 and 10 were set to speak out against any independence vote just hours after Smith’s Monday remarks.

+

Asked whether separation could override treaty obligations, Smith said treaty and Indigenous rights would remain fully respected regardless of Alberta’s constitutional status.

+

“You can’t vote away treaty rights. You can’t vote away Indigenous rights,” she said. “We accept and respect that [Indigenous nations] are sovereign jurisdictions in their own right.”

+

Despite her reassurances, Smith offered little clarity on how a binding referendum — or independence — would function within Canada’s legal framework.

+

“I won’t prejudge what citizens might want to put on the table,” she said. “But I’m going to do everything in my power to negotiate a fair deal for Alberta.”

+

Smith’s appearance also touched on a growing conflict-of-interest controversy involving Justice Minister Mickey Amery, whose family ties to businessman Sam Rash have drawn scrutiny. Rash is currently involved in a lawsuit and multiple investigations related to Alberta Health Services.

+

Smith dismissed the concerns outright.

+

“Should he divorce his wife so he doesn’t have the relationship with the cousin anymore?” she said. “Minister Mickey Amery is in no conflict of interest.”

+

Amery, she said, has not made any decisions that would affect Rash and remains compliant with ethics rules.

+

Asked if she would discipline UCP MLAs who express support for separation, Smith demurred, saying the party was founded on a commitment to Canadian unity — but added that differing views within caucus are inevitable.

+

“All I can do is try to convince people my view is right — that it’s worth fighting for, it’s worth doing the negotiation,” she said.

+

The premier wrapped up her comments Tuesday by reiterating her government’s priorities: negotiation, consultation, and economic empowerment within Canada.

+

“There is no referendum question. There is no petition campaign,” she said. “So I don’t have answers to those questions because, until we see an actual question and an active petition, it really is just hypothetical.”

+
    +
  • Events
  • +
  • Jobs
  • +
  • Buy & Sell
  • +
+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Smiths Electoral Reforms Are Straight from Trumps Playbook/index.html b/mkdocs/site/archive/Smiths Electoral Reforms Are Straight from Trumps Playbook/index.html new file mode 100644 index 0000000..936b2be --- /dev/null +++ b/mkdocs/site/archive/Smiths Electoral Reforms Are Straight from Trumps Playbook/index.html @@ -0,0 +1,2219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Smith’s Electoral ‘Reforms’ Are Straight from Trump’s Playbook - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

The Tyee - Trump Playbook

+ +

Smith’s Electoral ‘Reforms’ Are Straight from Trump’s Playbook

+

Danielle Smith stands with hands clasped and listens to Donald Trump in an ornate setting.

+

Alberta Premier Danielle Smith’s moves to reduce voting rights and allow big corporate donations are lifted from the tactics of US Republicans. Photo via X.

+

The United Conservative Party introduced sweeping changes to Alberta’s election laws Tuesday.

+

While billed as technical updates to restore faith in and improve access to elections in Alberta, they do precisely the opposite.

+

In no uncertain terms: the reforms mirror tactics employed by Donald Trump’s Republican Party in the U.S.

+

Viewed individually, each measure may appear modest. Taken together — and considered alongside their political timing — they mark another step in the Americanization of Alberta’s democratic institutions. And the latest in a long list of democratic transgressions in this province.

+

Reintroducing union and corporate contributions

+

The UCP’s bill removes existing restrictions on union and corporate donations to parties, candidates, leadership contestants and political action committees during the election period.

+

This move revives the influence of well-funded third parties, a tactic Republicans perfected after the U.S. Supreme Court’s Citizens United decision. By channelling large sums through parties and PACs, political actors can effectively circumvent party donation limits while maintaining plausible deniability.

+

In Alberta, the reintroduction of big money into elections risks further skewing the political process toward the interests of the wealthy, while ordinary citizens struggle to be heard. For these reasons, Albertans are overwhelmingly opposed to such measures.

+

Banning vote tabulators

+

The bill prohibits the use of vote-counting machines, or tabulators, across the province. While automation can improve efficiency (cutting down on the long wait times on election night that the UCP disparaged in restricting special ballots), the political context surrounding this change cannot be ignored.

+

Trump Republicans have spent years undermining public confidence in election technology, falsely alleging that machines were rigged or hacked to steal the 2020 election. These manufactured doubts fuelled attacks on electoral legitimacy in the United States.

+

Absent a comprehensive strategy for transparency and public education, Alberta’s banning of tabulators risks creating similar opportunities for conspiracy theories to take root.

+

In short, this measure decreases efficiency and reinforces unfounded doubts about the integrity of our elections — precisely the opposite of what the UCP purports to achieve through this bill.

+

Lowering recall petition thresholds

+

The bill reduces the number of signatures required to initiate recall petitions against MLAs and municipal leaders.

+

While pitched as a mechanism for greater accountability, experience from the U.S. suggests otherwise. Lower thresholds facilitate the weaponization of recall petitions by organized political groups seeking to destabilize elected officials over ideological disputes, not misconduct.

+

In Republican-led states, such tactics have created a chilling effect, discouraging politicians from making difficult but necessary decisions for fear of constant political retaliation.

+

Restricting the vote

+

The UCP’s bill eliminates “vote anywhere” provisions, restricts special ballots and introduces additional identification requirements for voters.

+

All three measures make voting more difficult, reversing decades of progress across Canada to improve voter equality.

+

As research — including our own — has shown, voter ID laws disproportionately affect younger and older, Indigenous, disabled, rural and low-income voters. These groups are less likely to have government-issued photo ID, and new requirements can create barriers that depress turnout.

+

Despite the many myths spread by Trump Republicans, there is no evidence of widespread voter fraud in the U.S.

+

The same is true in Alberta. Like their Republican counterparts, the UCP is solving a problem that does not exist, with the likely consequence (and perhaps intent) of reducing participation among demographics less likely to support them.

+

This amounts to the government choosing its voters, not vice versa.

+

All of these measures feed conspiracy narratives surrounding election integrity, once again sowing baseless doubt in the sanctity of proven election processes.

+

Amending the Referendum Act

+

The UCP is lowering the barriers to holding province-wide referendums, a key demand from separatist factions within the party’s base.

+

In the U.S., Trump’s allies have increasingly used referenda to pursue partisan objectives, bypassing legislative scrutiny. In Alberta, easier referendums open the door to populist campaigns on complex issues including, potentially, a vote on Alberta’s secession or joining the U.S.

+

At a moment when the premier has been accused of stoking separatist sentiment, loosening these requirements represents a concession to radical elements that seek to destabilize Canadian federalism. If she is the federalist she claims to be, Smith should at least consider reviewing the trials and tribulations of David Cameron, the unwitting architect of Brexit.

+

Political timing and strategic context

+

The timing of this bill is significant and far from coincidental.

+

Smith introduced these controversial reforms the day after the federal election hoping to catch the media off-guard and hoping few of us would notice given the attention on Ottawa.

+

That is scarcely a good-faith context for debating the most consequential set of reforms to election laws in Alberta’s history.

+

Had the reforms been tabled later, they would have drawn national attention and hurt Pierre Poilievre’s federal Conservatives by reinforcing narratives about Trumpism within the conservative movement.

+

Introducing the changes now minimizes that risk while placating UCP separatists and stoking the national unity crisis Smith and former Reform leader Preston Manning promised would follow a Liberal victory.

+

Trumpism at its clearest

+

The UCP’s proposed changes do not merely tweak administrative processes.

+

And they most certainly do not enhance accessibility or integrity in our electoral processes. They do precisely the opposite.

+

The UCP’s reforms reflect a deeper shift toward the strategies pioneered by Trump Republicans: leveraging dark money, undermining trust in elections, weaponizing recalls, disenfranchising opponents, suppressing voter turnout and empowering radical populist movements.

+

This convergence is not accidental. It is a conscious political strategy.

+

Whether Alberta follows the full arc of the Trump example remains to be seen. But today’s legislation makes clear that the risk is no longer hypothetical. It is real, present and growing. And the further it progresses, the harder it will be for concerned Albertans to stop it.

+

Read more: Alberta

+

The Barometer

+

What Writing Do You Do in Your Spare Time?

+
    +
  • Journal writing
  • +
  • Letters to friends
  • +
  • Memoirs
  • +
  • Fiction
  • +
  • +

    Poetry

    +
  • +
  • +

    Tell us more…

    +
  • +
+

Take this week’s poll

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Strengthening democracy Renforcer la démocratie/index.html b/mkdocs/site/archive/Strengthening democracy Renforcer la démocratie/index.html new file mode 100644 index 0000000..6f86931 --- /dev/null +++ b/mkdocs/site/archive/Strengthening democracy Renforcer la démocratie/index.html @@ -0,0 +1,2444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Strengthening democracy | Renforcer la démocratie - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + +

Official Release

+ +

Strengthening democracy | Renforcer la démocratie

+

+

Voting gives Albertans a voice in shaping the future of our province. Direct democracy processes like referendums, recall and citizen initiative petitions provide further opportunities for Albertans to be heard and express their views. The proposed Election Statutes Amendment Act, 2025, would make Alberta’s elections and other democratic processes more open, secure and accessible.

+
+

“I believe that democracy thrives when people trust the process. These changes would make elections at every level in Alberta more accessible and transparent while protecting their integrity, ensuring confidence in the outcomes. We are also creating more opportunities for Albertans to be involved in direct democracy and to have their say on issues that matter to them.”

+
+

Fair and free elections are the foundation of democracy, and Alberta’s government is taking action to protect them. The proposed changes include:

+
    +
  • Banning the use of electronic tabulators and other automated voting machines, requiring all ballots to be counted by hand to protect election integrity.
  • +
  • Eliminating vouching at voting stations to strengthen identification and verification processes.
  • +
  • Requiring unofficial vote counts to be completed within 12 hours of polls closing to provide timely, reliable results.
  • +
  • Voters being required to cast their ballot in their constituency of residence or by requesting a special ballot.
  • +
  • Expanding access to special ballots, allowing any voter to request one without needing to provide a reason while protecting integrity by requiring voters to personally request their special ballot (with exceptions for those needing assistance due to a disability).
  • +
  • Updating the Recall Act to make it easier for Albertans to hold elected officials accountable by lowering the signature threshold and extending the timeframe to collect signatures.
  • +
  • Improving the Citizen Initiative Act process by setting the threshold for all successful petitions at 10 per cent of eligible voters who participated in the last general election.
  • +
+
+

“Albertans rightly expect their government to make sure democratic processes are fair and transparent with accurate and timely results. These proposed amendments would deliver on my mandate to review and make changes to strengthen public trust in the integrity of our elections.”

+
+

Additional amendments under the Election Statutes Amendment Act, 2025 would:

+
    +
  • Allow corporate and union contributions for provincial elections while maintaining transparency and accountability through existing financial disclosure requirements.
  • +
  • Improve access to voting for First Nations and Métis Settlements during referendums and Senate elections.
  • +
  • Enhance emergency response provisions for voting disruptions during referendums and Senate elections.
  • +
+

These changes would help ensure that Alberta’s democratic processes are open, secure, and reflective of the will of Albertans, while creating new opportunities for greater public participation.

+

Quick facts

+
    +
  • The Election Act governs the process for provincial elections, by-elections and plebiscites in Alberta and creates the office of the chief electoral officer, the head of Elections Alberta.
  • +
  • The Election Finances and Contributions Disclosure Act governs the financing of provincial elections, Senate elections and referendums, including rules for registered political parties, constituency associations, candidates, leadership contestants and third parties.
  • +
  • The Alberta Senate Election Act governs the process for Senate elections in Alberta.
  • +
  • The Referendum Act governs the process for referendums in Alberta.
  • +
  • The Recall Act outlines the process for Albertans to initiate the recall of an elected MLA.
  • +
  • The Citizen Initiative Act allows eligible voters in Alberta to propose legislative or policy initiatives, constitutional referendum questions and establishes rules for advertising and spending.
  • +
+ + + + +

Multimedia

+ +
+

Afin de préserver la démocratie, le gouvernement de l’Alberta propose des modifications visant à garantir des élections justes et ouvertes, tout en accroissant la confiance envers le processus électoral.

+

En votant, les Albertaines et les Albertains participent activement à façonner l’avenir de la province. Les processus de démocratie directe, tels que les référendums, les révocations et les pétitions d’initiative citoyenne, offrent à la population d’autres occasions de se faire entendre et d’exprimer leurs opinions. Le projet de loi Election Statutes Amendment Act, 2025 rendrait les élections et les autres processus démocratiques de l’Alberta plus ouverts, plus sûrs et plus accessibles.

+
+

« Je crois que la démocratie prospère lorsque les citoyens font confiance au processus. Ces modifications permettraient d’améliorer l’accessibilité et la transparence des élections en Alberta, quel que soit le niveau de gouvernement, tout en protégeant leur intégrité et en garantissant la confiance envers les résultats. Nous créons également davantage d’occasions pour que la population albertaine participe à la démocratie directe et puisse s’exprimer sur les enjeux qui la concernent. »

+
+

Des élections libres et équitables sont le fondement de la démocratie, et le gouvernement de l’Alberta prend des mesures pour les protéger. Voici les modifications proposées:

+
    +
  • interdire l’utilisation de tabulateurs électroniques et d’autres machines de vote automatisées, exigeant un dépouillement manuel pour préserver l’intégrité du scrutin;
  • +
  • abolir le recours à un répondant dans les bureaux de vote afin de renforcer les processus d’identification et de vérification;
  • +
  • exiger de compléter le dépouillement non officiel dans les 12 heures suivant la fermeture des bureaux de vote pour garantir des résultats fiables et en temps opportun;
  • +
  • exiger que les électeurs votent dans leur propre circonscription ou par bulletin de vote spécial;
  • +
  • élargir l’accès aux bulletins de vote spéciaux, en permettant à tout électeur d’en demander un sans avoir à fournir de raison, tout en protégeant l’intégrité en exigeant que les électeurs demandent personnellement leur bulletin de vote spécial (des exceptions sont prévues pour les personnes en situation de handicap);
  • +
  • mettre à jour la Recall Act afin de permettre aux Albertaines et aux Albertains de tenir les élus responsables en abaissant le seuil du nombre de signatures et en prolongeant le délai de collecte des signatures;
  • +
  • améliorer le processus de la Citizen Initiative Act en fixant le seuil pour toutes les pétitions retenues à 10 % des électeurs admissibles ayant pris part aux dernières élections générales.
  • +
+
+

« La population albertaine s’attend légitimement à ce que le gouvernement garantisse que les processus démocratiques soient justes, transparents, et fournissent des résultats précis et rapides. Ces modifications proposées me permettraient de remplir mon mandat consistant à examiner et à apporter des changements pour renforcer la confiance du public dans l’intégrité de nos élections. »

+
+

Des modifications supplémentaires en vertu de l’ Election Statutes Amendment Act, 2025 permettraient:

+
    +
  • d’autoriser les contributions des entreprises et des syndicats aux élections provinciales tout en maintenant la transparence et la responsabilité grâce aux exigences actuelles en matière de divulgation financière;
  • +
  • d’améliorer l’accès au vote pour les Premières Nations et les établissements métis lors des référendums et des élections sénatoriales;
  • +
  • de renforcer les dispositions relatives aux interventions d’urgence en cas de perturbations électorales lors des référendums et des élections sénatoriales.
  • +
+

Ces modifications contribueraient à garantir que les processus démocratiques de l’Alberta sont ouverts, sûrs et reflètent la volonté de la population, tout en créant de nouvelles occasions de participation publique accrue.

+

Faits en bref

+
    +
  • L’ Election Act régit le processus des élections provinciales, des élections partielles et des plébiscites en Alberta et crée le poste de directeur général des élections, à la tête d’Élections Alberta.
  • +
  • L’ Election Finances and Contributions Disclosure Act régit le financement des élections provinciales, des élections sénatoriales et des référendums, y compris les règles applicables aux partis politiques enregistrés, aux associations de circonscription, aux candidats, aux candidats à la direction et aux tiers.
  • +
  • L’ Alberta Senate Election Act régit le processus des élections sénatoriales en Alberta.
  • +
  • La Referendum Act régit le processus des référendums en Alberta.
  • +
  • La Recall Act décrit le processus permettant aux Albertaines et aux Albertains de mettre en œuvre la révocation d’un député élu.
  • +
  • La Citizen Initiative Act permet aux électeurs admissibles de l’Alberta de proposer des initiatives législatives ou politiques, des questions de référendum constitutionnel, et établit des règles en matière de publicité et de dépenses.
  • +
+

Renseignements connexes

+ +

Nouvelles connexes

+ +

Multimédia

+ +

Translations

+ + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News/index.html b/mkdocs/site/archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News/index.html new file mode 100644 index 0000000..2d46578 --- /dev/null +++ b/mkdocs/site/archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News/index.html @@ -0,0 +1,2217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider | CBC News - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + +

Tabulator Ban

+ +

The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider | CBC News

+

Edmonton

+

The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider

+

The Alberta government banned the use of electronic tabulators in municipal elections when it passed Bill 20 in May 2024. It's a method that municipalities have used for decades, saying it has saved them both time and money.

+

Province says the change is about trust; some municipalities worry about cost

+

A voter enters his paper ballot into a tabulator machine at an advanced polling station in Sherwood Park on Tuesday.

+

A voter enters his paper ballot into a tabulator machine at an advanced polling station in Sherwood Park in the 2023 provincial election. (CBC)

+

The Alberta government banned the use of electronic tabulators in municipal elections when it passed Bill 20 in May of this year. It's a method that municipalities have used for decades, saying it has saved them time and money.

+

Alberta Municipalities wants the province to reconsider.

+

A resolution to be put forward at the organization's annual convention this week in Red Deer calls for tabulators to be permitted as an option "to ensure accurate, cost-effective and timely results for Albertan voters."

+

St. Albert Mayor Cathy Heron, past-president of Alberta Municipalities, told CBC Radio's Edmonton AM that she can't remember a time when St. Albert wasn't using tabulators.

+

"They provided really timely, efficient, and quite honestly, accurate counting of our residents' votes," Heron said.

+

"Now we're going to get the exact opposite. We're going to get less timely and less accurate and much more costly counting of the votes."

+

WATCH | Municipalities pushing back against ban on electronic vote tabulators:

+

Municipalities pushing back against ban on electronic vote tabulators 8 months ago Duration 1:53

+

In an emailed statement, Heather Jenkins, press secretary for Minister of Municipal Affairs Ric McIver, said the changes were made to give municipalities enough time to prepare for the next municipal general elections, scheduled for Oct. 20, 2025.

+

"It is important for Albertans to feel they can trust the methods and results of local elections and requiring all ballots to be counted by hand will bolster their trust in the election outcome, which is better for democracy," Jenkins wrote.

+

The Alberta Municipalities resolution says in part that some municipalities haven't used manual vote counting in years. Votes counted via a tabulator are subject to a post-election review process that verifies the results.

+

The risk in "adapting alternative vote-counting processes without precedent or corporate expertise" increases the likelihood of mistakes, delayed results, and cost escalation, it says.

+

"I have spoken to Minister McIver... at length about this, and he says that it is mainly because there is a certain part of the population that have spoken to him directly that indicated that they don't trust the machines," Heron said.

+

"He's only going on a few anecdotal suspicions. I would happily support this if there was good, solid data and good, solid surveys of Albertans, but that doesn't exist."

+ +

The City of Red Deer looked at the financial impact the change might have. In a report, the city's administration found the changes might cost almost $1.5 million for the next election — around 3½ times more than in past general elections.

+

One section of the Red Deer report, which came out earlier this month, assumed that with 30 per cent voter turnout and one provincial referendum question, there would be about 90,000 ballots to count.

+

"It will take four workers 37 days (counting 24/7) to hand count 90,000 ballots," the report said.

+

"To complete the count in four hours, it will take 1,200 workers."

+

The report indicates that the city would ask the province for that money in the budget.

+

LISTEN | Alberta Municipalities will ask the province to let municipalities use tabulators:

+

In May, the Alberta government passed a bill that bans the use of vote-counting machines in local elections. Now, a motion is being put forward to bring back vote-counting machines. The City of St. Albert is bringing the motion forward. Cathy Heron is St. Albert's mayor.

+

In an email to CBC, McIver said: "Conducting municipal elections has always been a cost for the municipality to bear. That has not changed."

+

Ken Johnston, Red Deer's mayor, told CBC in an interview that the machines are tried and true.

+

"They have served us well. They have served us efficiently. They've come through testing, they're tested frequently. Each morning of the election, they're tested," Johnston said.

+

He said public servants understand the need for transparency.

+ +

"The bottom line, however, is if you want to proceed in this direction, please resource us so that we're not out another million dollars in our own budget."

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/The Dangerous Americanization of Alberta Democracy/index.html b/mkdocs/site/archive/The Dangerous Americanization of Alberta Democracy/index.html new file mode 100644 index 0000000..4edf3b7 --- /dev/null +++ b/mkdocs/site/archive/The Dangerous Americanization of Alberta Democracy/index.html @@ -0,0 +1,2237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The Dangerous Americanization of Alberta Democracy - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

The Tyee - Americanization

+ +

The Dangerous Americanization of Alberta Democracy

+

On the left, a woman with light skin and shoulder-length brown hair speaking into a microphone. On the right, a man with light skin dressed in red and wearing a red ball cap, standing outdoors with one white gloved hand leaning on a golf club.

+

Alberta Premier Danielle Smith is borrowing from US politics at a time when presidential candidate Donald Trump is attacking democratic norms. Smith photo via Alberta government. Trump photo via Wikimedia.

+

Since her return to provincial politics, elected representatives, opposition leaders, academics and activists have shared their concerns regarding the bills put forward by Alberta Premier Danielle Smith and the United Conservative Party.

+

Legislation such as the Alberta Sovereignty Act and the Provincial Priorities Act have garnered strong opposition, with critics highlighting threats to the constitutional division of powers and rule of law, academic freedom and Indigenous sovereignty.

+

Proposed changes to the Alberta Human Rights Act and anti-trans legislation have sparked additional concerns.

+

Many of these measures were left out of the UCP’s 2023 election platform, raising questions as to their origins. While much has been made about her borrowing pages from the Quebec playbook, Smith’s idealization of Republican policy in the United States may provide additional clues as to the source of the UCP’s policies.

+

In a 2023 speech, Smith praised Florida Gov. Ron DeSantis and South Dakota Gov. Kristi Noem and projected Alberta as a “ little bastion of freedom ” in the same vein.

+

This begs the question: To what extent does the Smith government draw inspiration from Republicans in crafting its legislative agenda? And what are the implications of this sort of Americanization of Alberta politics?

+

Our research suggests that Smith’s admiration of Republicans goes beyond rhetoric. The UCP’s approach to legislation aligns well with red-state leaders who advance a vision of “freedom” that limits pluralism and concentrates power in the executive.

+

At its core, the cross-pollination of these ideas marks a shift with potentially profound consequences for democracy in Alberta.

+

‘Policy diffusion’ in action

+

Policy diffusion occurs when ideas, practices or innovations spread from one government or jurisdiction to another. In January, for instance, Republican Gov. Spencer Cox signed the Utah Constitutional Sovereignty Act, a bill that is almost identical to the Alberta Sovereignty Within a United Canada Act (2022). In fact, Utah Sen. Scott Sandall, who drafted the bill, was happy to cite his sources.

+

Policy ideas seem to be travelling north to a far larger extent, however, with Smith’s government introducing legislation that centralizes power in a manner similar to several U.S. states.

+

The Municipal Affairs Statutes Amendment Act (Bill 20) is a prime example, as it gives the provincial cabinet extensive control over municipalities, school boards and post-secondary institutions. In a similar vein, North Carolina’s Senate Bill 36 sought to redraw city council districts and mandate partisan declarations in traditionally non-partisan elections, a concerted effort to manipulate local governance in favour of the governing party.

+

States like Missouri, Arkansas and North Dakota have passed strict voter ID laws and imposed limits on local electoral autonomy under the pretext of protecting “election integrity.” The UCP’s Bill 20 contained similar provisions, outlawing the decades-old practice of vouching alongside the elimination of electronic vote tabulators and the introduction of parties to local election ballots in Edmonton and Calgary. Critics on both sides of the border contend partisan motives and conspiratorial thinking were at play.

+

Bill 20 is not the only instance where policy diffusion has occurred. The Red Tape Reduction Statutes Amendment Act (Bill 16), an amendment which aims to dismantle existing regulations across multiple Alberta ministries, resembles former president Donald Trump’s Executive Order 13771, issued in 2017. Similar to Alberta, Trump imposed annual reporting requirements on the bureaucracy.

+

This focus on reducing red tape has not precluded governments on both sides of the border from imposing new regulations on public sector bodies, including municipalities and universities. In Alberta, the Provincial Priorities Act (Bill 18) places federal research funding at the discretion of the Alberta government. Introducing the bill, Smith argued that it would counter perceived efforts by the federal government to impose ideological priorities by setting provincial research agendas. She also viewed the bill as an opportunity to achieve more ideological balance on Alberta campuses.

+

Among several other anti-university measures, Bill 18 mirrors Republican Rep. Brandon Williams’ Respecting the First Amendment on Campus Act, which would mandate institutions of higher education to adopt and adhere to principles of free speech, potentially undermining academic freedom and constraining diverse viewpoints.

+

The UCP’s ongoing bid to amend the Alberta Human Rights Act betrays similar intentions at Americanization. Enshrining gun rights, alongside a commitment to “Life, Liberty, Property and the Pursuit of Happiness,” borrows directly from the U.S. Declaration of Independence (albeit with the addition of the word “property”).

+

The UCP’s proposed measures to further marginalize transgender Albertans and transfer medical decisions out of the hands of patients, parents and doctors when it comes to trans health also have American roots.

+

Given these similarities and the influence of Project 2025 on Republican policy in the United States, Albertans may have a reliable guidebook for their own fall 2024 legislative session, which begins today.

+

Impacts of Americanization

+

The UCP’s Republican-inspired legislative agenda has impacts beyond policy. It represents a broader transformation toward a brand of right-wing populism that undermines liberal democratic norms by reducing local autonomy, curtailing academic freedom and concentrating authority in the political executive.

+

If similar moves at the federal level may be labelled the presidentialization of the prime ministership, Smith’s actions can be considered an attempt to turn her own office into that of a U.S. governor.

+

She has admitted as much. At the tail end of the COVID-19 pandemic, Smith mused about issuing “pardons” to scofflaws. She retracted the proposal once she realized the Canadian system did not confer her such gubernatorial powers.

+

The path Smith is charting for Alberta raises critical questions about the province’s democratic future. By borrowing from the Republican playbook, her government is not only pushing policies that redefine rights and responsibilities in Alberta — it is blurring the lines between Canadian and American democracy at a time when the latter has reached the point of crisis.

+

Canada’s system of pluralism respects the importance of different viewpoints, beliefs and lifestyles within a society. It’s the idea that a healthy democracy allows diverse groups — whether based on culture, religion, politics or other factors — to coexist and have a voice in shaping decisions that affect the entire community. Checks and balances on executive power are crucial to this effort. Instead of one group dominating, pluralism ensures that everyone gets a chance to be heard and contribute to the public debate, leading to a more inclusive and balanced society.

+

As Republicans steer the United States further away from that ideal, attempting to concentrate more power in governors and presidents, Albertans should be weary of similar developments in our own province.

+

Read more: Rights + Justice, Politics, Alberta

+

LATEST STORIES

+ +

The Barometer

+

What Writing Do You Do in Your Spare Time?

+
    +
  • Journal writing
  • +
  • Letters to friends
  • +
  • Memoirs
  • +
  • Fiction
  • +
  • +

    Poetry

    +
  • +
  • +

    Tell us more…

    +
  • +
+

Take this week’s poll

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/Why the UCP Is a Threat to Democracy/index.html b/mkdocs/site/archive/Why the UCP Is a Threat to Democracy/index.html new file mode 100644 index 0000000..84f784c --- /dev/null +++ b/mkdocs/site/archive/Why the UCP Is a Threat to Democracy/index.html @@ -0,0 +1,2335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Why the UCP Is a Threat to Democracy - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

The Tyee - UCP Threat

+ +

Why the UCP Is a Threat to Democracy

+

A black and white image shows two photos of the same smiling 50-ish light-skinned woman wearing a dark suit and holding a binder and phone.

+

Alberta has become less democratic and more authoritarian under Jason Kenney and Danielle Smith, writes Jared Wesley. Photo via Alberta government.

+

I’m going to be blunt in this piece. As a resident of Alberta and someone trained to recognize threats to democracy, I have an obligation to be.

+

The United Conservative Party is an authoritarian force in Alberta. Full stop.

+

I don’t come by this argument lightly. It’s based on extensive evidence that I present below, followed by some concrete actions Albertans can take to push back against creeping authoritarianism.

+

Drawing the line

+

There’s no hard-and-fast line between democracy and authoritarianism. Just ask people from autocracies: you don’t simply wake up one day under arbitrary rule.

+

They’re more like opposite sides of a spectrum, ranging from full participation by all citizens in policy-making at one end (democracy) to full control by a leader and their cadre on the other (authoritarianism).

+

Clearly, Alberta politics sit somewhere between these two poles. It is neither an ideal Greek city-state nor a totalitarian hellscape.

+

The question is: How much of a shift toward authoritarianism are we willing to accept? Where do we draw the line between politics as usual and anti-democratic activities?

+

At a bare minimum, we should expect our leaders to respect the rule of law, constitutional checks and balances, electoral integrity and the distribution of power.

+

Unfortunately, the United Conservative Party has shown disregard for these principles. They’ve breached them so many times that citizens can be forgiven for being desensitized. But it is important to take stock so we can determine how far we’ve slid.

+

Here’s a breakdown of those principles.

+

1. Rule of Law

+

In healthy democracies:

+
    +
  • no one is above the law’s reach or below the law’s protection;
  • +
  • there is due process; and
  • +
  • the rules are clear and evenly applied.
  • +
+

By these standards, Alberta is not looking so healthy these days.

+
    +
  1. Above the law: Members of the UCP government have positioned themselves as being beyond reproach. A premier fired the election commissioner before he could complete an investigation into his own leadership campaign. A justice minister confronted a police chief over a traffic ticket.
  2. +
  3. Legal interference: The same UCP premier crossed the line in the Artur Pawlowski affair, earning a rebuke from the ethics commissioner that “it is a threat to democracy to interfere with the administration of justice.” The episode raised questions about how allies of the premier might receive preferential treatment in the courts.
  4. +
  5. Targeting city dwellers: Vengeance has no place in a province where rule of law ensures everyone is treated fairly. Through Bill 20, the UCP is singling out Alberta’s two biggest cities as sites for an experiment with local political parties. The premier herself noted that partisanship is ill-suited to local politics. She’s spared rural and other urban communities from those dangers, but not Edmonton and Calgary (whose voters elected many city councillors who don’t share the UCP’s viewpoint on public policy or democracy).
  6. +
+

2. Checks and Balances

+

Leaders should also abide by the Constitution, including:

+
    +
  • the separation of powers among the executive, legislative and judicial branches; and
  • +
  • the division of powers between federal and provincial governments.
  • +
+

The UCP government has demonstrated a passing familiarity and respect for these checks on its authority.

+
    +
  1. Going around the legislature: At the outset of the COVID-19 pandemic, the UCP government stripped the legislature of its ability to review public health measures taken by the minister of health. They backtracked only after their own allies threatened to sue them.
  2. +
  3. Going around the courts: The first draft of the UCP’s Sovereignty Act would have stolen powers from the federal government, the Alberta legislature and the courts and granted them to the premier. They walked some of it back after public backlash but remain insistent that the provincial cabinet — not the Supreme Court — should determine the bounds of federal and provincial authority.
  4. +
+

3. Electoral Integrity

+

In democracies, leaders respect the will of the people.

+

That includes:

+
    +
  • abiding by internal party rules and election laws;
  • +
  • campaigning openly about their policy proposals to seek a mandate from voters during elections; and
  • +
  • ensuring that everyone entitled to vote has an opportunity to do so.
  • +
+

Again, the UCP’s record is abysmal.

+
    +
  1. Tainted race: The party didn’t start off on the right foot. The inaugural UCP leadership race featured over $100,000 in fines levied against various party operatives and contestants. While the RCMP failed to find evidence of voter or identity fraud of a criminal nature, the police and Elections Alberta found “ clear evidence ” of suspicious votes and that many alleged voters had “no knowledge” of casting ballots. As someone who participated in that vote as a party member, I can attest: the outcome is tarnished for me as a result.
  2. +
  3. Hidden agenda: The UCP has a habit of keeping more promises than they make on the campaign trail. Of the party’s most high-profile policy initiatives — an Alberta pension plan, an Alberta police service, introducing parties into municipal elections, the Sovereignty Act and the Provincial Priorities Act — none appeared in the UCP’s lengthy list of campaign planks. This is because most are wildly unpopular. Indeed, the premier denied wanting to pursue several of them altogether, only to introduce them as legislation once in power. This disrespect for voters sows distrust in the democratic system.
  4. +
  5. Fake referendum: The UCP’s disingenuous use of a constitutional referendum on the equalization principle shows their lack of respect for direct democracy. No attempt was made to inform the public about the actual nature of equalization before a provincewide vote was held, and the government capitalized on misperceptions in an effort to grandstand against Ottawa.
  6. +
  7. Voters’ intent: Bill 20 is also an affront to voters’ intent by giving cabinet sweeping new powers to dismiss local elected officials. Routine elections give voters the right to determine who represents them. Bill 20 takes that power away and gives it to two dozen ministers behind closed doors.
  8. +
  9. Voter suppression: Bill 20 goes one step further to require voter ID in local elections. Borrowed from the MAGA playbook, the UCP’s move is designed to restrict the types of people who can vote in elections. It’s about voter suppression, plain and simple. Combined with the conspiracy-driven banning of vote tabulators, the government claims this is making elections fairer. At best, these are solutions in search of a problem. Voter fraud is exceptionally rare in Alberta, and voting machines are safe and secure.
  10. +
+

4. Distribution of Power

+

More broadly, our leaders should respect the importance of pluralism, a system where power is dispersed among multiple groups or institutions, ensuring no single entity holds too much control. This includes:

+
    +
  • respecting the autonomy of local governments and officials;
  • +
  • protecting the independence of arm’s-length agencies, boards and commissions;
  • +
  • upholding the public service bargain, which affords civil servants protection and benefits in return for providing fearless advice and loyal implementation; and
  • +
  • upholding the principle of academic freedom, whereby academics can pursue lines of inquiry without fear of censorship or persecution.
  • +
+

The UCP has little respect for these principles, either.

+
    +
  1. Kissing the ring: In the past two weeks, the UCP government introduced Bill 18 and Bill 20, the combined effect of which would be to bend municipal councillors and public bodies to the will of the provincial cabinet and encroach on matters of academic freedom by vetting federally funded research grants.
  2. +
  3. Breaking the bargain: UCP premiers have broken the public service bargain by threatening to investigate and eventually firing individual officials, pledging to roll back wages and benefits and hinting at taking over their pensions. They’ve also cut public servants and stakeholders out of the policy development process, limiting the amount of evidence and number of perspectives being considered.
  4. +
  5. Cronyism and meddling: The party has loaded various arm’s-length agencies with patronage appointments and dismissed or threatened to fire entire boards of others. During a UCP leadership debate, various contenders promised to politicize several fields normally kept at arm’s length from interference — academia, the police, the judiciary, prosecutions, pensions, tax collection, immigration and sport.
  6. +
+

Combined, these measures have steadily concentrated power in the hands of the premier and their entourage. The province has become less democratic and more authoritarian in the process.

+

What we can do about it

+

The first step in pushing back against this creeping authoritarianism is recognizing that this is not politics as usual. Despite the government’s disinformation, these new measures are unprecedented. Alberta’s drift toward authoritarianism has not happened overnight, but we cannot allow ourselves to become desensitized to the shift.

+

We should continue to call out instances of anti-democratic behaviour and tie them to the growing narrative I’ve presented above. Crowing about each individual misdeed doesn’t help if they don’t fit into the broader storyline. Arguing over whether the UCP is acting in authoritarian or fascist ways also isn’t helpful. This isn’t about semantics; it’s about action.

+

This also isn’t a left/right or partisan issue. Conservatives ought to be as concerned about the UCP’s trajectory as progressives. Politicians of all stripes should be speaking out and Albertans should welcome all who do. Opposition to the UCP’s backsliding can’t be monolithic. We need many voices, including those within the government caucus and UCP base.

+

In this sense, it’s important to avoid engaging in whataboutism over which side is more authoritarian. It’s important to acknowledge when any government strays from democratic principles. Finding common ground with folks from across the spectrum about what we expect from our governments is key.

+

Some Albertans are organizing protests related to specific anti-democratic moves by the UCP government, while others are marshalling general resistance events and movements. With numerous public sector unions in negotiations with the government this year, there is a potential for a groundswell of public education and mobilization in the months ahead. Supporting these organizations and movements is an important way to signal your opposition to the UCP government’s democratic backsliding.

+

Show up, amplify their messages, and donate if you can. Protests work, but only if everyday Albertans support the causes.

+

Calling or writing your MLA also helps. Don’t use a form letter or script; those are easily ignored. But staffers I’ve interviewed confirm that for every original phone call they receive, they assume at least a dozen other constituents are just as upset; you can double that for every letter. Inundating UCP MLA offices, in particular, can have a real impact on government caucus discussions. We know that governments make policy U-turns when enough caucus members threaten a revolt. On the flip side, silence from constituents is taken as complicity with the government’s agenda.

+

Talking to friends, family and neighbours about your concerns is equally important. It lets people know that others are also fed up, helping communities break out of the “ spiral of silence ” that tends to hold citizens back from advocating for their interests. Encouraging them to write or call their MLA, or to join you at a rally, would also help.

+

Elections are the ultimate source of accountability for governments. While Albertans will likely have to wait until May 2027 for another provincial campaign, there are some interim events that allow folks to voice their concerns.

+
    +
  • Existing UCP members and people wanting to influence the party from within can participate in this fall’s leadership review.
  • +
  • Opponents should support opposition parties and politicians who take these threats seriously.
  • +
  • The next federal election is also an opportunity to get politicians on the record about how they feel about the UCP’s democratic backsliding. Ask folks who come to your door about their position on these issues and what they’re prepared to say publicly.
  • +
  • The next round of municipal and school board elections in October 2025 offers Albertans another opportunity to weigh in. By introducing political parties into these elections in Edmonton and Calgary, and with Take Back Alberta openly organizing affiliated slates throughout the province, the UCP is inviting Albertans to consider these local elections a referendum on their approach to democracy.
  • +
+

None of what I’ve suggested starts or ends with spouting off on social media. Our digital world is full of slacktivists who talk a good game on Facebook or X but whose actual impact is more performance than action.

+

It’s also not enough to say “the courts will handle it.” Many of the UCP’s moves sit in a constitutional grey area. Even if the courts were to intervene, they’d be a backstop, at best. Investigations, let alone court cases, take months if not years to conclude. And the standard of proof is high. In the meantime, the damage to individuals, groups and our democratic norms would have been done already.

+

In short, if Albertans want to push back against the UCP’s creeping authoritarianism, they’ll need to get off the couch. Make a commitment and a plan to stand up. Democracy demands that of us, from time to time.

+

Read more: Politics, Alberta

+

The Barometer

+

What Writing Do You Do in Your Spare Time?

+
    +
  • Journal writing
  • +
  • Letters to friends
  • +
  • Memoirs
  • +
  • Fiction
  • +
  • +

    Poetry

    +
  • +
  • +

    Tell us more…

    +
  • +
+

Take this week’s poll

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/archive/index.html b/mkdocs/site/archive/index.html new file mode 100644 index 0000000..261e072 --- /dev/null +++ b/mkdocs/site/archive/index.html @@ -0,0 +1,2298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Overview - Alberta Democracy Taskforce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + +

Archive: The Evidence Against Bill 54

+

The UCP's Anti-Democratic Agenda Exposed

+

This archive contains comprehensive documentation of the UCP government's systematic assault on democratic institutions in Alberta. Bill 54 (the Election Statutes Amendment Act, 2025) represents one of the most significant threats to democratic participation in Alberta's history.

+

What You'll Find Here

+

Our archive includes:

+

📰 News Coverage

+

Mainstream media reports documenting the scope and impact of Bill 54's anti-democratic provisions.

+

🏛️ Government Sources

+

The UCP's own statements and press releases, revealing their true intentions behind the legislation.

+

📊 Expert Analysis

+

Academic and professional commentary exposing the authoritarian nature of these changes.

+

🏘️ Community Opposition

+

Responses from Indigenous Nations, municipalities, unions, and civil society organizations.

+ +

Analysis from legal experts and the Chief Electoral Officer about the bill's impact on election integrity.

+

Key Themes in the Evidence

+

Voter Suppression

+
    +
  • Elimination of vouching systems that help eligible voters
  • +
  • Barriers to accessible voting for marginalized communities
  • +
  • Restrictions designed to reduce turnout among likely opposition voters
  • +
+

Corporate Capture

+
    +
  • Reintroduction of corporate political donations with $5,000 aggregate maximum
  • +
  • Restrictions on union political activity
  • +
  • Weakened oversight of election finance violations
  • +
+

Centralization of Power

+
    +
  • Introduction of political parties to municipal elections
  • +
  • Reduced independence of electoral officials
  • +
  • Weakened investigative powers for election law enforcement
  • +
+

Attack on Local Democracy

+
    +
  • Provincial interference in municipal governance
  • +
  • Undermining of community-based decision making
  • +
  • Partisan politicization of previously non-partisan local elections
  • +
+

The Broader Pattern

+

Bill 54 is not an isolated incident—it's part of a broader authoritarian agenda that includes:

+
    +
  • Bill 20: Giving cabinet power to fire mayors and overturn municipal bylaws
  • +
  • Attacks on public healthcare and education
  • +
  • Suppression of environmental activism
  • +
  • Weakening of workers' rights
  • +
+

How to Use This Archive

+

Each document in our archive provides crucial evidence of the UCP's anti-democratic agenda. We encourage you to:

+
    +
  1. Read widely across different source types
  2. +
  3. Share specific articles that resonate with your community
  4. +
  5. Use this evidence when contacting elected officials
  6. +
  7. Cite these sources in letters to editors and social media
  8. +
+

The evidence is overwhelming: the UCP is systematically undermining democratic institutions in Alberta. This archive provides the documentation needed to fight back.

+
+

The contents of this archive are subject to updates as new evidence emerges of the UCP's continuing assault on Alberta democracy.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mkdocs/site/assets/images/adtf-logo.png b/mkdocs/site/assets/images/adtf-logo.png new file mode 100644 index 0000000..4a8df60 Binary files /dev/null and b/mkdocs/site/assets/images/adtf-logo.png differ diff --git a/mkdocs/site/assets/images/favicon.png b/mkdocs/site/assets/images/favicon.png new file mode 100644 index 0000000..1cf13b9 Binary files /dev/null and b/mkdocs/site/assets/images/favicon.png differ diff --git a/mkdocs/site/assets/images/header.png b/mkdocs/site/assets/images/header.png new file mode 100644 index 0000000..2724de7 Binary files /dev/null and b/mkdocs/site/assets/images/header.png differ diff --git a/mkdocs/site/assets/images/image.png b/mkdocs/site/assets/images/image.png new file mode 100644 index 0000000..93d634b Binary files /dev/null and b/mkdocs/site/assets/images/image.png differ diff --git a/mkdocs/site/assets/images/social/archive/Alberta Government tables changes to the election act.png b/mkdocs/site/assets/images/social/archive/Alberta Government tables changes to the election act.png new file mode 100644 index 0000000..6fcf47d Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Alberta Government tables changes to the election act.png differ diff --git a/mkdocs/site/assets/images/social/archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold.png b/mkdocs/site/assets/images/social/archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold.png new file mode 100644 index 0000000..2a94099 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Alberta bill seeks to reintroduce union, corporate contributions, ban tabulators and lower recall threshold.png differ diff --git a/mkdocs/site/assets/images/social/archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News.png b/mkdocs/site/assets/images/social/archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News.png new file mode 100644 index 0000000..9f0f21a Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Alberta overhauls election laws to allow corporate donations, change referendum thresholds CBC News.png differ diff --git a/mkdocs/site/assets/images/social/archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca.png b/mkdocs/site/assets/images/social/archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca.png new file mode 100644 index 0000000..50789cd Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Alberta to make changes to bill proposing sweeping powers over municipalities Globalnews.ca.png differ diff --git a/mkdocs/site/assets/images/social/archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca.png b/mkdocs/site/assets/images/social/archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca.png new file mode 100644 index 0000000..9b854e6 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Albertas chief electoral officer warns UCP proposed bill will hurt investigations - Globalnews.ca.png differ diff --git a/mkdocs/site/assets/images/social/archive/Central Alberta First Nations slam Bill 54.png b/mkdocs/site/assets/images/social/archive/Central Alberta First Nations slam Bill 54.png new file mode 100644 index 0000000..1f24b49 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Central Alberta First Nations slam Bill 54.png differ diff --git a/mkdocs/site/assets/images/social/archive/Cold Lake First Nations opposes Albertas proposed Bill 54.png b/mkdocs/site/assets/images/social/archive/Cold Lake First Nations opposes Albertas proposed Bill 54.png new file mode 100644 index 0000000..29114e1 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Cold Lake First Nations opposes Albertas proposed Bill 54.png differ diff --git a/mkdocs/site/assets/images/social/archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging.png b/mkdocs/site/assets/images/social/archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging.png new file mode 100644 index 0000000..9f848c4 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Danielle Smith lowers bar for Alberta referendum with separatism sentiment emerging.png differ diff --git a/mkdocs/site/assets/images/social/archive/Improving consistency and fairness in Albertas democratic processes.png b/mkdocs/site/assets/images/social/archive/Improving consistency and fairness in Albertas democratic processes.png new file mode 100644 index 0000000..ee10bc2 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Improving consistency and fairness in Albertas democratic processes.png differ diff --git a/mkdocs/site/assets/images/social/archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill.png b/mkdocs/site/assets/images/social/archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill.png new file mode 100644 index 0000000..10d6ac8 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/May 2024 Alberta Municipalities said it hasnt been given chance to consult on changes to bill.png differ diff --git a/mkdocs/site/assets/images/social/archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate.png b/mkdocs/site/assets/images/social/archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate.png new file mode 100644 index 0000000..5beb6eb Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Smith pushes Alberta Accord defends citizen referendums amid separation debate.png differ diff --git a/mkdocs/site/assets/images/social/archive/Smiths Electoral Reforms Are Straight from Trumps Playbook.png b/mkdocs/site/assets/images/social/archive/Smiths Electoral Reforms Are Straight from Trumps Playbook.png new file mode 100644 index 0000000..9a31c00 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Smiths Electoral Reforms Are Straight from Trumps Playbook.png differ diff --git a/mkdocs/site/assets/images/social/archive/Strengthening democracy Renforcer la démocratie.png b/mkdocs/site/assets/images/social/archive/Strengthening democracy Renforcer la démocratie.png new file mode 100644 index 0000000..1358ef4 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Strengthening democracy Renforcer la démocratie.png differ diff --git a/mkdocs/site/assets/images/social/archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News.png b/mkdocs/site/assets/images/social/archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News.png new file mode 100644 index 0000000..13f702b Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/The Alberta government banned electronic vote tabulators. Municipalities want it to reconsider CBC News.png differ diff --git a/mkdocs/site/assets/images/social/archive/The Dangerous Americanization of Alberta Democracy.png b/mkdocs/site/assets/images/social/archive/The Dangerous Americanization of Alberta Democracy.png new file mode 100644 index 0000000..5a75775 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/The Dangerous Americanization of Alberta Democracy.png differ diff --git a/mkdocs/site/assets/images/social/archive/Why the UCP Is a Threat to Democracy.png b/mkdocs/site/assets/images/social/archive/Why the UCP Is a Threat to Democracy.png new file mode 100644 index 0000000..c142aeb Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/Why the UCP Is a Threat to Democracy.png differ diff --git a/mkdocs/site/assets/images/social/archive/index.png b/mkdocs/site/assets/images/social/archive/index.png new file mode 100644 index 0000000..ffa9332 Binary files /dev/null and b/mkdocs/site/assets/images/social/archive/index.png differ diff --git a/mkdocs/site/assets/images/social/bill-54-analysis.png b/mkdocs/site/assets/images/social/bill-54-analysis.png new file mode 100644 index 0000000..712882f Binary files /dev/null and b/mkdocs/site/assets/images/social/bill-54-analysis.png differ diff --git a/mkdocs/site/assets/images/social/blog/archive/2025.png b/mkdocs/site/assets/images/social/blog/archive/2025.png new file mode 100644 index 0000000..acd5a48 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/archive/2025.png differ diff --git a/mkdocs/site/assets/images/social/blog/category/analysis.png b/mkdocs/site/assets/images/social/blog/category/analysis.png new file mode 100644 index 0000000..0bf2734 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/category/analysis.png differ diff --git a/mkdocs/site/assets/images/social/blog/category/bill-20.png b/mkdocs/site/assets/images/social/blog/category/bill-20.png new file mode 100644 index 0000000..aada6b0 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/category/bill-20.png differ diff --git a/mkdocs/site/assets/images/social/blog/category/bill-54.png b/mkdocs/site/assets/images/social/blog/category/bill-54.png new file mode 100644 index 0000000..a0b3417 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/category/bill-54.png differ diff --git a/mkdocs/site/assets/images/social/blog/category/democracy.png b/mkdocs/site/assets/images/social/blog/category/democracy.png new file mode 100644 index 0000000..ddb6c82 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/category/democracy.png differ diff --git a/mkdocs/site/assets/images/social/blog/category/indigenous-rights.png b/mkdocs/site/assets/images/social/blog/category/indigenous-rights.png new file mode 100644 index 0000000..c07e616 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/category/indigenous-rights.png differ diff --git a/mkdocs/site/assets/images/social/blog/category/municipal-democracy.png b/mkdocs/site/assets/images/social/blog/category/municipal-democracy.png new file mode 100644 index 0000000..5b2e76e Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/category/municipal-democracy.png differ diff --git a/mkdocs/site/assets/images/social/blog/index.png b/mkdocs/site/assets/images/social/blog/index.png new file mode 100644 index 0000000..a18f362 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/index.png differ diff --git a/mkdocs/site/assets/images/social/blog/posts/bill-54-corporate-control.png b/mkdocs/site/assets/images/social/blog/posts/bill-54-corporate-control.png new file mode 100644 index 0000000..651b012 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/posts/bill-54-corporate-control.png differ diff --git a/mkdocs/site/assets/images/social/blog/posts/indigenous-opposition-bill-54.png b/mkdocs/site/assets/images/social/blog/posts/indigenous-opposition-bill-54.png new file mode 100644 index 0000000..eab9da1 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/posts/indigenous-opposition-bill-54.png differ diff --git a/mkdocs/site/assets/images/social/blog/posts/municipal-democracy-under-attack.png b/mkdocs/site/assets/images/social/blog/posts/municipal-democracy-under-attack.png new file mode 100644 index 0000000..61673c9 Binary files /dev/null and b/mkdocs/site/assets/images/social/blog/posts/municipal-democracy-under-attack.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/index.png b/mkdocs/site/assets/images/social/cm-lite/index.png new file mode 100644 index 0000000..ffa9332 Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/index.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/services/code-server.png b/mkdocs/site/assets/images/social/cm-lite/services/code-server.png new file mode 100644 index 0000000..10ace26 Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/services/code-server.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/services/homepage.png b/mkdocs/site/assets/images/social/cm-lite/services/homepage.png new file mode 100644 index 0000000..c56523d Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/services/homepage.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/services/index.png b/mkdocs/site/assets/images/social/cm-lite/services/index.png new file mode 100644 index 0000000..ffa9332 Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/services/index.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/services/listmonk.png b/mkdocs/site/assets/images/social/cm-lite/services/listmonk.png new file mode 100644 index 0000000..bc68b41 Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/services/listmonk.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/services/mkdocs.png b/mkdocs/site/assets/images/social/cm-lite/services/mkdocs.png new file mode 100644 index 0000000..cbf6eca Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/services/mkdocs.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/services/n8n.png b/mkdocs/site/assets/images/social/cm-lite/services/n8n.png new file mode 100644 index 0000000..962df15 Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/services/n8n.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/services/nocodb.png b/mkdocs/site/assets/images/social/cm-lite/services/nocodb.png new file mode 100644 index 0000000..816767c Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/services/nocodb.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/services/postgresql.png b/mkdocs/site/assets/images/social/cm-lite/services/postgresql.png new file mode 100644 index 0000000..0b158aa Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/services/postgresql.png differ diff --git a/mkdocs/site/assets/images/social/cm-lite/services/static-server.png b/mkdocs/site/assets/images/social/cm-lite/services/static-server.png new file mode 100644 index 0000000..6bb2ba0 Binary files /dev/null and b/mkdocs/site/assets/images/social/cm-lite/services/static-server.png differ diff --git a/mkdocs/site/assets/images/social/contributing/collaboration.png b/mkdocs/site/assets/images/social/contributing/collaboration.png new file mode 100644 index 0000000..cd7376a Binary files /dev/null and b/mkdocs/site/assets/images/social/contributing/collaboration.png differ diff --git a/mkdocs/site/assets/images/social/contributing/first-edit.png b/mkdocs/site/assets/images/social/contributing/first-edit.png new file mode 100644 index 0000000..e644b7a Binary files /dev/null and b/mkdocs/site/assets/images/social/contributing/first-edit.png differ diff --git a/mkdocs/site/assets/images/social/contributing/getting-started.png b/mkdocs/site/assets/images/social/contributing/getting-started.png new file mode 100644 index 0000000..2769dd8 Binary files /dev/null and b/mkdocs/site/assets/images/social/contributing/getting-started.png differ diff --git a/mkdocs/site/assets/images/social/contributing/git-basics.png b/mkdocs/site/assets/images/social/contributing/git-basics.png new file mode 100644 index 0000000..878cca7 Binary files /dev/null and b/mkdocs/site/assets/images/social/contributing/git-basics.png differ diff --git a/mkdocs/site/assets/images/social/contributing/index.png b/mkdocs/site/assets/images/social/contributing/index.png new file mode 100644 index 0000000..9723f12 Binary files /dev/null and b/mkdocs/site/assets/images/social/contributing/index.png differ diff --git a/mkdocs/site/assets/images/social/contributing/local-editing.png b/mkdocs/site/assets/images/social/contributing/local-editing.png new file mode 100644 index 0000000..6c5f4e4 Binary files /dev/null and b/mkdocs/site/assets/images/social/contributing/local-editing.png differ diff --git a/mkdocs/site/assets/images/social/contributing/navigating-gitea.png b/mkdocs/site/assets/images/social/contributing/navigating-gitea.png new file mode 100644 index 0000000..5446103 Binary files /dev/null and b/mkdocs/site/assets/images/social/contributing/navigating-gitea.png differ diff --git a/mkdocs/site/assets/images/social/contributing/submitting-changes.png b/mkdocs/site/assets/images/social/contributing/submitting-changes.png new file mode 100644 index 0000000..b28e06f Binary files /dev/null and b/mkdocs/site/assets/images/social/contributing/submitting-changes.png differ diff --git a/mkdocs/site/assets/images/social/faq.png b/mkdocs/site/assets/images/social/faq.png new file mode 100644 index 0000000..26f71c6 Binary files /dev/null and b/mkdocs/site/assets/images/social/faq.png differ diff --git a/mkdocs/site/assets/images/social/getting-started.png b/mkdocs/site/assets/images/social/getting-started.png new file mode 100644 index 0000000..9723f12 Binary files /dev/null and b/mkdocs/site/assets/images/social/getting-started.png differ diff --git a/mkdocs/site/assets/images/social/index.png b/mkdocs/site/assets/images/social/index.png new file mode 100644 index 0000000..25ef54f Binary files /dev/null and b/mkdocs/site/assets/images/social/index.png differ diff --git a/mkdocs/site/assets/images/social/resources.png b/mkdocs/site/assets/images/social/resources.png new file mode 100644 index 0000000..ac94bdf Binary files /dev/null and b/mkdocs/site/assets/images/social/resources.png differ diff --git a/mkdocs/site/assets/images/social/vision.png b/mkdocs/site/assets/images/social/vision.png new file mode 100644 index 0000000..23df58c Binary files /dev/null and b/mkdocs/site/assets/images/social/vision.png differ diff --git a/mkdocs/site/assets/javascripts/bundle.13a4f30d.min.js b/mkdocs/site/assets/javascripts/bundle.13a4f30d.min.js new file mode 100644 index 0000000..c31fa1a --- /dev/null +++ b/mkdocs/site/assets/javascripts/bundle.13a4f30d.min.js @@ -0,0 +1,16 @@ +"use strict";(()=>{var Wi=Object.create;var gr=Object.defineProperty;var Vi=Object.getOwnPropertyDescriptor;var Di=Object.getOwnPropertyNames,Vt=Object.getOwnPropertySymbols,zi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,ao=Object.prototype.propertyIsEnumerable;var io=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,$=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&io(e,r,t[r]);if(Vt)for(var r of Vt(t))ao.call(t,r)&&io(e,r,t[r]);return e};var so=(e,t)=>{var r={};for(var o in e)yr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Vt)for(var o of Vt(e))t.indexOf(o)<0&&ao.call(e,o)&&(r[o]=e[o]);return r};var xr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Ni=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Di(t))!yr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=Vi(t,n))||o.enumerable});return e};var Lt=(e,t,r)=>(r=e!=null?Wi(zi(e)):{},Ni(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var co=(e,t,r)=>new Promise((o,n)=>{var i=p=>{try{s(r.next(p))}catch(c){n(c)}},a=p=>{try{s(r.throw(p))}catch(c){n(c)}},s=p=>p.done?o(p.value):Promise.resolve(p.value).then(i,a);s((r=r.apply(e,t)).next())});var lo=xr((Er,po)=>{(function(e,t){typeof Er=="object"&&typeof po!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(k){return!!(k&&k!==document&&k.nodeName!=="HTML"&&k.nodeName!=="BODY"&&"classList"in k&&"contains"in k.classList)}function p(k){var ft=k.type,qe=k.tagName;return!!(qe==="INPUT"&&a[ft]&&!k.readOnly||qe==="TEXTAREA"&&!k.readOnly||k.isContentEditable)}function c(k){k.classList.contains("focus-visible")||(k.classList.add("focus-visible"),k.setAttribute("data-focus-visible-added",""))}function l(k){k.hasAttribute("data-focus-visible-added")&&(k.classList.remove("focus-visible"),k.removeAttribute("data-focus-visible-added"))}function f(k){k.metaKey||k.altKey||k.ctrlKey||(s(r.activeElement)&&c(r.activeElement),o=!0)}function u(k){o=!1}function d(k){s(k.target)&&(o||p(k.target))&&c(k.target)}function y(k){s(k.target)&&(k.target.classList.contains("focus-visible")||k.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(k.target))}function L(k){document.visibilityState==="hidden"&&(n&&(o=!0),X())}function X(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function ee(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(k){k.target.nodeName&&k.target.nodeName.toLowerCase()==="html"||(o=!1,ee())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),X(),r.addEventListener("focus",d,!0),r.addEventListener("blur",y,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var qr=xr((dy,On)=>{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var $a=/["'&<>]/;On.exports=Pa;function Pa(e){var t=""+e,r=$a.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Rt=="object"&&typeof Yr=="object"?Yr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Rt=="object"?Rt.ClipboardJS=r():t.ClipboardJS=r()})(Rt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Ui}});var a=i(279),s=i.n(a),p=i(370),c=i.n(p),l=i(817),f=i.n(l);function u(D){try{return document.execCommand(D)}catch(A){return!1}}var d=function(A){var M=f()(A);return u("cut"),M},y=d;function L(D){var A=document.documentElement.getAttribute("dir")==="rtl",M=document.createElement("textarea");M.style.fontSize="12pt",M.style.border="0",M.style.padding="0",M.style.margin="0",M.style.position="absolute",M.style[A?"right":"left"]="-9999px";var F=window.pageYOffset||document.documentElement.scrollTop;return M.style.top="".concat(F,"px"),M.setAttribute("readonly",""),M.value=D,M}var X=function(A,M){var F=L(A);M.container.appendChild(F);var V=f()(F);return u("copy"),F.remove(),V},ee=function(A){var M=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},F="";return typeof A=="string"?F=X(A,M):A instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(A==null?void 0:A.type)?F=X(A.value,M):(F=f()(A),u("copy")),F},J=ee;function k(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?k=function(M){return typeof M}:k=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},k(D)}var ft=function(){var A=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=A.action,F=M===void 0?"copy":M,V=A.container,Y=A.target,$e=A.text;if(F!=="copy"&&F!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&k(Y)==="object"&&Y.nodeType===1){if(F==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(F==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if($e)return J($e,{container:V});if(Y)return F==="cut"?y(Y):J(Y,{container:V})},qe=ft;function Fe(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(M){return typeof M}:Fe=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},Fe(D)}function ki(D,A){if(!(D instanceof A))throw new TypeError("Cannot call a class as a function")}function no(D,A){for(var M=0;M0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof V.action=="function"?V.action:this.defaultAction,this.target=typeof V.target=="function"?V.target:this.defaultTarget,this.text=typeof V.text=="function"?V.text:this.defaultText,this.container=Fe(V.container)==="object"?V.container:document.body}},{key:"listenClick",value:function(V){var Y=this;this.listener=c()(V,"click",function($e){return Y.onClick($e)})}},{key:"onClick",value:function(V){var Y=V.delegateTarget||V.currentTarget,$e=this.action(Y)||"copy",Wt=qe({action:$e,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(Wt?"success":"error",{action:$e,text:Wt,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(V){return vr("action",V)}},{key:"defaultTarget",value:function(V){var Y=vr("target",V);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(V){return vr("text",V)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(V){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(V,Y)}},{key:"cut",value:function(V){return y(V)}},{key:"isSupported",value:function(){var V=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof V=="string"?[V]:V,$e=!!document.queryCommandSupported;return Y.forEach(function(Wt){$e=$e&&!!document.queryCommandSupported(Wt)}),$e}}]),M}(s()),Ui=Fi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,p){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(p))return s;s=s.parentNode}}o.exports=a},438:function(o,n,i){var a=i(828);function s(l,f,u,d,y){var L=c.apply(this,arguments);return l.addEventListener(u,L,y),{destroy:function(){l.removeEventListener(u,L,y)}}}function p(l,f,u,d,y){return typeof l.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return s(L,f,u,d,y)}))}function c(l,f,u,d){return function(y){y.delegateTarget=a(y.target,f),y.delegateTarget&&d.call(l,y)}}o.exports=p},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(o,n,i){var a=i(879),s=i(438);function p(u,d,y){if(!u&&!d&&!y)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(y))throw new TypeError("Third argument must be a Function");if(a.node(u))return c(u,d,y);if(a.nodeList(u))return l(u,d,y);if(a.string(u))return f(u,d,y);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(u,d,y){return u.addEventListener(d,y),{destroy:function(){u.removeEventListener(d,y)}}}function l(u,d,y){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,y)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,y)})}}}function f(u,d,y){return s(document.body,u,d,y)}o.exports=p},817:function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var p=window.getSelection(),c=document.createRange();c.selectNodeContents(i),p.removeAllRanges(),p.addRange(c),a=p.toString()}return a}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,a,s){var p=this.e||(this.e={});return(p[i]||(p[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var p=this;function c(){p.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),p=0,c=s.length;for(p;p0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function z(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],a;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(s){a={error:s}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(a)throw a.error}}return i}function q(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||p(d,L)})},y&&(n[d]=y(n[d])))}function p(d,y){try{c(o[d](y))}catch(L){u(i[0][3],L)}}function c(d){d.value instanceof nt?Promise.resolve(d.value.v).then(l,f):u(i[0][2],d)}function l(d){p("next",d)}function f(d){p("throw",d)}function u(d,y){d(y),i.shift(),i.length&&p(i[0][0],i[0][1])}}function uo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof he=="function"?he(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(a){return new Promise(function(s,p){a=e[i](a),n(s,p,a.done,a.value)})}}function n(i,a,s,p){Promise.resolve(p).then(function(c){i({value:c,done:s})},a)}}function H(e){return typeof e=="function"}function ut(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var zt=ut(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Qe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ue=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=he(a),p=s.next();!p.done;p=s.next()){var c=p.value;c.remove(this)}}catch(L){t={error:L}}finally{try{p&&!p.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var l=this.initialTeardown;if(H(l))try{l()}catch(L){i=L instanceof zt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=he(f),d=u.next();!d.done;d=u.next()){var y=d.value;try{ho(y)}catch(L){i=i!=null?i:[],L instanceof zt?i=q(q([],z(i)),z(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new zt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ho(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Qe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Qe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=Ue.EMPTY;function Nt(e){return e instanceof Ue||e&&"closed"in e&&H(e.remove)&&H(e.add)&&H(e.unsubscribe)}function ho(e){H(e)?e():e.unsubscribe()}var Pe={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var dt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,a=n.isStopped,s=n.observers;return i||a?Tr:(this.currentObservers=null,s.push(r),new Ue(function(){o.currentObservers=null,Qe(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new j;return r.source=this,r},t.create=function(r,o){return new To(r,o)},t}(j);var To=function(e){oe(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t}(g);var _r=function(e){oe(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(g);var _t={now:function(){return(_t.delegate||Date).now()},delegate:void 0};var At=function(e){oe(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=_t);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,a=o._infiniteTimeWindow,s=o._timestampProvider,p=o._windowTime;n||(i.push(r),!a&&i.push(s.now()+p)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,a=n._buffer,s=a.slice(),p=0;p0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(gt);var Lo=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(yt);var kr=new Lo(Oo);var Mo=function(e){oe(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=vt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var a=r.actions;o!=null&&o===r._scheduled&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==o&&(vt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(gt);var _o=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o;r?o=r.id:(o=this._scheduled,this._scheduled=void 0);var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(yt);var me=new _o(Mo);var S=new j(function(e){return e.complete()});function Kt(e){return e&&H(e.schedule)}function Hr(e){return e[e.length-1]}function Xe(e){return H(Hr(e))?e.pop():void 0}function ke(e){return Kt(Hr(e))?e.pop():void 0}function Yt(e,t){return typeof Hr(e)=="number"?e.pop():t}var xt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Bt(e){return H(e==null?void 0:e.then)}function Gt(e){return H(e[bt])}function Jt(e){return Symbol.asyncIterator&&H(e==null?void 0:e[Symbol.asyncIterator])}function Xt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Zt=Zi();function er(e){return H(e==null?void 0:e[Zt])}function tr(e){return fo(this,arguments,function(){var r,o,n,i;return Dt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,nt(r.read())];case 3:return o=a.sent(),n=o.value,i=o.done,i?[4,nt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,nt(n)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function rr(e){return H(e==null?void 0:e.getReader)}function U(e){if(e instanceof j)return e;if(e!=null){if(Gt(e))return ea(e);if(xt(e))return ta(e);if(Bt(e))return ra(e);if(Jt(e))return Ao(e);if(er(e))return oa(e);if(rr(e))return na(e)}throw Xt(e)}function ea(e){return new j(function(t){var r=e[bt]();if(H(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ta(e){return new j(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?b(function(n,i){return e(n,i,o)}):le,Te(1),r?Ve(t):Qo(function(){return new nr}))}}function jr(e){return e<=0?function(){return S}:E(function(t,r){var o=[];t.subscribe(T(r,function(n){o.push(n),e=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new g}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,p=s===void 0?!0:s;return function(c){var l,f,u,d=0,y=!1,L=!1,X=function(){f==null||f.unsubscribe(),f=void 0},ee=function(){X(),l=u=void 0,y=L=!1},J=function(){var k=l;ee(),k==null||k.unsubscribe()};return E(function(k,ft){d++,!L&&!y&&X();var qe=u=u!=null?u:r();ft.add(function(){d--,d===0&&!L&&!y&&(f=Ur(J,p))}),qe.subscribe(ft),!l&&d>0&&(l=new at({next:function(Fe){return qe.next(Fe)},error:function(Fe){L=!0,X(),f=Ur(ee,n,Fe),qe.error(Fe)},complete:function(){y=!0,X(),f=Ur(ee,a),qe.complete()}}),U(k).subscribe(l))})(c)}}function Ur(e,t){for(var r=[],o=2;oe.next(document)),e}function P(e,t=document){return Array.from(t.querySelectorAll(e))}function R(e,t=document){let r=fe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function fe(e,t=document){return t.querySelector(e)||void 0}function Ie(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var wa=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(_e(1),Q(void 0),m(()=>Ie()||document.body),G(1));function et(e){return wa.pipe(m(t=>e.contains(t)),K())}function Ht(e,t){return C(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?kt(r=>Le(+!r*t)):le,Q(e.matches(":hover"))))}function Jo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Jo(e,r)}function x(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Jo(o,n);return o}function sr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function wt(e){let t=x("script",{src:e});return C(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(v(()=>$r(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),_(()=>document.head.removeChild(t)),Te(1))))}var Xo=new g,Ta=C(()=>typeof ResizeObserver=="undefined"?wt("https://unpkg.com/resize-observer-polyfill"):I(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>Xo.next(t)))),v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function ce(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return Ta.pipe(w(r=>r.observe(t)),v(r=>Xo.pipe(b(o=>o.target===t),_(()=>r.unobserve(t)))),m(()=>ce(e)),Q(ce(e)))}function Tt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function cr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function Zo(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function De(e){return{x:e.offsetLeft,y:e.offsetTop}}function en(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function tn(e){return O(h(window,"load"),h(window,"resize")).pipe(Me(0,me),m(()=>De(e)),Q(De(e)))}function pr(e){return{x:e.scrollLeft,y:e.scrollTop}}function ze(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe(Me(0,me),m(()=>pr(e)),Q(pr(e)))}var rn=new g,Sa=C(()=>I(new IntersectionObserver(e=>{for(let t of e)rn.next(t)},{threshold:0}))).pipe(v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function tt(e){return Sa.pipe(w(t=>t.observe(e)),v(t=>rn.pipe(b(({target:r})=>r===e),_(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function on(e,t=16){return ze(e).pipe(m(({y:r})=>{let o=ce(e),n=Tt(e);return r>=n.height-o.height-t}),K())}var lr={drawer:R("[data-md-toggle=drawer]"),search:R("[data-md-toggle=search]")};function nn(e){return lr[e].checked}function Je(e,t){lr[e].checked!==t&&lr[e].click()}function Ne(e){let t=lr[e];return h(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function Oa(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function La(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function an(){let e=h(window,"keydown").pipe(b(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:nn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),b(({mode:t,type:r})=>{if(t==="global"){let o=Ie();if(typeof o!="undefined")return!Oa(o,r)}return!0}),pe());return La().pipe(v(t=>t?S:e))}function ye(){return new URL(location.href)}function lt(e,t=!1){if(B("navigation.instant")&&!t){let r=x("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function sn(){return new g}function cn(){return location.hash.slice(1)}function pn(e){let t=x("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Ma(e){return O(h(window,"hashchange"),e).pipe(m(cn),Q(cn()),b(t=>t.length>0),G(1))}function ln(e){return Ma(e).pipe(m(t=>fe(`[id="${t}"]`)),b(t=>typeof t!="undefined"))}function $t(e){let t=matchMedia(e);return ir(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function mn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function zr(e,t){return e.pipe(v(r=>r?t():S))}function Nr(e,t){return new j(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let a=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+a*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function je(e,t){return Nr(e,t).pipe(v(r=>r.text()),m(r=>JSON.parse(r)),G(1))}function fn(e,t){let r=new DOMParser;return Nr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),G(1))}function un(e,t){let r=new DOMParser;return Nr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),G(1))}function dn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function hn(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(dn),Q(dn()))}function bn(){return{width:innerWidth,height:innerHeight}}function vn(){return h(window,"resize",{passive:!0}).pipe(m(bn),Q(bn()))}function gn(){return N([hn(),vn()]).pipe(m(([e,t])=>({offset:e,size:t})),G(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(te("size")),n=N([o,r]).pipe(m(()=>De(e)));return N([r,t,n]).pipe(m(([{height:i},{offset:a,size:s},{x:p,y:c}])=>({offset:{x:a.x-p,y:a.y-c+i},size:s})))}function _a(e){return h(e,"message",t=>t.data)}function Aa(e){let t=new g;return t.subscribe(r=>e.postMessage(r)),t}function yn(e,t=new Worker(e)){let r=_a(t),o=Aa(t),n=new g;n.subscribe(o);let i=o.pipe(Z(),ie(!0));return n.pipe(Z(),Re(r.pipe(W(i))),pe())}var Ca=R("#__config"),St=JSON.parse(Ca.textContent);St.base=`${new URL(St.base,ye())}`;function xe(){return St}function B(e){return St.features.includes(e)}function Ee(e,t){return typeof t!="undefined"?St.translations[e].replace("#",t.toString()):St.translations[e]}function Se(e,t=document){return R(`[data-md-component=${e}]`,t)}function ae(e,t=document){return P(`[data-md-component=${e}]`,t)}function ka(e){let t=R(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>R(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function xn(e){if(!B("announce.dismiss")||!e.childElementCount)return S;if(!e.hidden){let t=R(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return C(()=>{let t=new g;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),ka(e).pipe(w(r=>t.next(r)),_(()=>t.complete()),m(r=>$({ref:e},r)))})}function Ha(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function En(e,t){let r=new g;return r.subscribe(({hidden:o})=>{e.hidden=o}),Ha(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))}function Pt(e,t){return t==="inline"?x("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"})):x("div",{class:"md-tooltip",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"}))}function wn(...e){return x("div",{class:"md-tooltip2",role:"tooltip"},x("div",{class:"md-tooltip2__inner md-typeset"},e))}function Tn(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("a",{href:r,class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}else return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("span",{class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}function Sn(e){return x("button",{class:"md-clipboard md-icon",title:Ee("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}var Ln=Lt(qr());function Qr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(p=>!e.terms[p]).reduce((p,c)=>[...p,x("del",null,(0,Ln.default)(c))," "],[]).slice(0,-1),i=xe(),a=new URL(e.location,i.base);B("search.highlight")&&a.searchParams.set("h",Object.entries(e.terms).filter(([,p])=>p).reduce((p,[c])=>`${p} ${c}`.trim(),""));let{tags:s}=xe();return x("a",{href:`${a}`,class:"md-search-result__link",tabIndex:-1},x("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&x("div",{class:"md-search-result__icon md-icon"}),r>0&&x("h1",null,e.title),r<=0&&x("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&x("nav",{class:"md-tags"},e.tags.map(p=>{let c=s?p in s?`md-tag-icon md-tag--${s[p]}`:"md-tag-icon":"";return x("span",{class:`md-tag ${c}`},p)})),o>0&&n.length>0&&x("p",{class:"md-search-result__terms"},Ee("search.result.term.missing"),": ",...n)))}function Mn(e){let t=e[0].score,r=[...e],o=xe(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),a=r.findIndex(l=>l.scoreQr(l,1)),...p.length?[x("details",{class:"md-search-result__more"},x("summary",{tabIndex:-1},x("div",null,p.length>0&&p.length===1?Ee("search.result.more.one"):Ee("search.result.more.other",p.length))),...p.map(l=>Qr(l,1)))]:[]];return x("li",{class:"md-search-result__item"},c)}function _n(e){return x("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>x("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?sr(r):r)))}function Kr(e){let t=`tabbed-control tabbed-control--${e}`;return x("div",{class:t,hidden:!0},x("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function An(e){return x("div",{class:"md-typeset__scrollwrap"},x("div",{class:"md-typeset__table"},e))}function Ra(e){var o;let t=xe(),r=new URL(`../${e.version}/`,t.base);return x("li",{class:"md-version__item"},x("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&x("span",{class:"md-version__alias"},e.aliases[0])))}function Cn(e,t){var o;let r=xe();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),x("div",{class:"md-version"},x("button",{class:"md-version__current","aria-label":Ee("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&x("span",{class:"md-version__alias"},t.aliases[0])),x("ul",{class:"md-version__list"},e.map(Ra)))}var Ia=0;function ja(e){let t=N([et(e),Ht(e)]).pipe(m(([o,n])=>o||n),K()),r=C(()=>Zo(e)).pipe(ne(ze),pt(1),He(t),m(()=>en(e)));return t.pipe(Ae(o=>o),v(()=>N([t,r])),m(([o,n])=>({active:o,offset:n})),pe())}function Fa(e,t){let{content$:r,viewport$:o}=t,n=`__tooltip2_${Ia++}`;return C(()=>{let i=new g,a=new _r(!1);i.pipe(Z(),ie(!1)).subscribe(a);let s=a.pipe(kt(c=>Le(+!c*250,kr)),K(),v(c=>c?r:S),w(c=>c.id=n),pe());N([i.pipe(m(({active:c})=>c)),s.pipe(v(c=>Ht(c,250)),Q(!1))]).pipe(m(c=>c.some(l=>l))).subscribe(a);let p=a.pipe(b(c=>c),re(s,o),m(([c,l,{size:f}])=>{let u=e.getBoundingClientRect(),d=u.width/2;if(l.role==="tooltip")return{x:d,y:8+u.height};if(u.y>=f.height/2){let{height:y}=ce(l);return{x:d,y:-16-y}}else return{x:d,y:16+u.height}}));return N([s,i,p]).subscribe(([c,{offset:l},f])=>{c.style.setProperty("--md-tooltip-host-x",`${l.x}px`),c.style.setProperty("--md-tooltip-host-y",`${l.y}px`),c.style.setProperty("--md-tooltip-x",`${f.x}px`),c.style.setProperty("--md-tooltip-y",`${f.y}px`),c.classList.toggle("md-tooltip2--top",f.y<0),c.classList.toggle("md-tooltip2--bottom",f.y>=0)}),a.pipe(b(c=>c),re(s,(c,l)=>l),b(c=>c.role==="tooltip")).subscribe(c=>{let l=ce(R(":scope > *",c));c.style.setProperty("--md-tooltip-width",`${l.width}px`),c.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(K(),ve(me),re(s)).subscribe(([c,l])=>{l.classList.toggle("md-tooltip2--active",c)}),N([a.pipe(b(c=>c)),s]).subscribe(([c,l])=>{l.role==="dialog"?(e.setAttribute("aria-controls",n),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",n)}),a.pipe(b(c=>!c)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),ja(e).pipe(w(c=>i.next(c)),_(()=>i.complete()),m(c=>$({ref:e},c)))})}function mt(e,{viewport$:t},r=document.body){return Fa(e,{content$:new j(o=>{let n=e.title,i=wn(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t})}function Ua(e,t){let r=C(()=>N([tn(e),ze(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:a,height:s}=ce(e);return{x:o-i.x+a/2,y:n-i.y+s/2}}));return et(e).pipe(v(o=>r.pipe(m(n=>({active:o,offset:n})),Te(+!o||1/0))))}function kn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return C(()=>{let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),tt(e).pipe(W(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),O(i.pipe(b(({active:s})=>s)),i.pipe(_e(250),b(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Me(16,me)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(a),b(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),h(n,"mousedown").pipe(W(a),re(i)).subscribe(([s,{active:p}])=>{var c;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(p){s.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(c=Ie())==null||c.blur()}}),r.pipe(W(a),b(s=>s===o),Ge(125)).subscribe(()=>e.focus()),Ua(e,t).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function Wa(e){return e.tagName==="CODE"?P(".c, .c1, .cm",e):[e]}function Va(e){let t=[];for(let r of Wa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,p]=a;if(typeof p=="undefined"){let c=i.splitText(a.index);i=c.splitText(s.length),t.push(c)}else{i.textContent=s,t.push(i);break}}}}return t}function Hn(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,a=new Map;for(let s of Va(t)){let[,p]=s.textContent.match(/\((\d+)\)/);fe(`:scope > li:nth-child(${p})`,e)&&(a.set(p,Tn(p,i)),s.replaceWith(a.get(p)))}return a.size===0?S:C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=[];for(let[l,f]of a)c.push([R(".md-typeset",f),R(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(p)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of c)l?Hn(f,u):Hn(u,f)}),O(...[...a].map(([,l])=>kn(l,t,{target$:r}))).pipe(_(()=>s.complete()),pe())})}function $n(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return $n(t)}}function Pn(e,t){return C(()=>{let r=$n(e);return typeof r!="undefined"?fr(r,e,t):S})}var Rn=Lt(Br());var Da=0;function In(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return In(t)}}function za(e){return ge(e).pipe(m(({width:t})=>({scrollable:Tt(e).width>t})),te("scrollable"))}function jn(e,t){let{matches:r}=matchMedia("(hover)"),o=C(()=>{let n=new g,i=n.pipe(jr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[];if(Rn.default.isSupported()&&(e.closest(".copy")||B("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Da++}`;let l=Sn(c.id);c.insertBefore(l,e),B("content.tooltips")&&a.push(mt(l,{viewport$}))}let s=e.closest(".highlight");if(s instanceof HTMLElement){let c=In(s);if(typeof c!="undefined"&&(s.classList.contains("annotate")||B("content.code.annotate"))){let l=fr(c,e,t);a.push(ge(s).pipe(W(i),m(({width:f,height:u})=>f&&u),K(),v(f=>f?l:S)))}}return P(":scope > span[id]",e).length&&e.classList.add("md-code__content"),za(e).pipe(w(c=>n.next(c)),_(()=>n.complete()),m(c=>$({ref:e},c)),Re(...a))});return B("content.lazy")?tt(e).pipe(b(n=>n),Te(1),v(()=>o)):o}function Na(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),b(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(b(n=>n||!o),w(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Fn(e,t){return C(()=>{let r=new g;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Na(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}var Un=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.flowchartTitleText{fill:var(--md-mermaid-label-fg-color)}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}.classDiagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs marker.marker.composition.class path,defs marker.marker.dependency.class path,defs marker.marker.extension.class path{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs marker.marker.aggregation.class path{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}.statediagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}[id^=entity] path,[id^=entity] rect{fill:var(--md-default-bg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs .marker.oneOrMore.er *,defs .marker.onlyOne.er *,defs .marker.zeroOrMore.er *,defs .marker.zeroOrOne.er *{stroke:var(--md-mermaid-edge-color)!important}text:not([class]):last-child{fill:var(--md-mermaid-label-fg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Gr,Qa=0;function Ka(){return typeof mermaid=="undefined"||mermaid instanceof Element?wt("https://unpkg.com/mermaid@11/dist/mermaid.min.js"):I(void 0)}function Wn(e){return e.classList.remove("mermaid"),Gr||(Gr=Ka().pipe(w(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Un,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),G(1))),Gr.subscribe(()=>co(null,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Qa++}`,r=x("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),a=r.attachShadow({mode:"closed"});a.innerHTML=n,e.replaceWith(r),i==null||i(a)})),Gr.pipe(m(()=>({ref:e})))}var Vn=x("table");function Dn(e){return e.replaceWith(Vn),Vn.replaceWith(An(e)),I({ref:e})}function Ya(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>R(`label[for="${r.id}"]`))))).pipe(Q(R(`label[for="${t.id}"]`)),m(r=>({active:r})))}function zn(e,{viewport$:t,target$:r}){let o=R(".tabbed-labels",e),n=P(":scope > input",e),i=Kr("prev");e.append(i);let a=Kr("next");return e.append(a),C(()=>{let s=new g,p=s.pipe(Z(),ie(!0));N([s,ge(e),tt(e)]).pipe(W(p),Me(1,me)).subscribe({next([{active:c},l]){let f=De(c),{width:u}=ce(c);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=pr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),N([ze(o),ge(o)]).pipe(W(p)).subscribe(([c,l])=>{let f=Tt(o);i.hidden=c.x<16,a.hidden=c.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(a,"click").pipe(m(()=>1))).pipe(W(p)).subscribe(c=>{let{width:l}=ce(o);o.scrollBy({left:l*c,behavior:"smooth"})}),r.pipe(W(p),b(c=>n.includes(c))).subscribe(c=>c.click()),o.classList.add("tabbed-labels--linked");for(let c of n){let l=R(`label[for="${c.id}"]`);l.replaceChildren(x("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(p),b(f=>!(f.metaKey||f.ctrlKey)),w(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return B("content.tabs.link")&&s.pipe(Ce(1),re(t)).subscribe(([{active:c},{offset:l}])=>{let f=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let y of P("[data-tabs]"))for(let L of P(":scope > input",y)){let X=R(`label[for="${L.id}"]`);if(X!==c&&X.innerText.trim()===f){X.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),s.pipe(W(p)).subscribe(()=>{for(let c of P("audio, video",e))c.pause()}),Ya(n).pipe(w(c=>s.next(c)),_(()=>s.complete()),m(c=>$({ref:e},c)))}).pipe(Ke(se))}function Nn(e,{viewport$:t,target$:r,print$:o}){return O(...P(".annotate:not(.highlight)",e).map(n=>Pn(n,{target$:r,print$:o})),...P("pre:not(.mermaid) > code",e).map(n=>jn(n,{target$:r,print$:o})),...P("pre.mermaid",e).map(n=>Wn(n)),...P("table:not([class])",e).map(n=>Dn(n)),...P("details",e).map(n=>Fn(n,{target$:r,print$:o})),...P("[data-tabs]",e).map(n=>zn(n,{viewport$:t,target$:r})),...P("[title]",e).filter(()=>B("content.tooltips")).map(n=>mt(n,{viewport$:t})))}function Ba(e,{alert$:t}){return t.pipe(v(r=>O(I(!0),I(!1).pipe(Ge(2e3))).pipe(m(o=>({message:r,active:o})))))}function qn(e,t){let r=R(".md-typeset",e);return C(()=>{let o=new g;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ba(e,t).pipe(w(n=>o.next(n)),_(()=>o.complete()),m(n=>$({ref:e},n)))})}var Ga=0;function Ja(e,t){document.body.append(e);let{width:r}=ce(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=cr(t),n=typeof o!="undefined"?ze(o):I({x:0,y:0}),i=O(et(t),Ht(t)).pipe(K());return N([i,n]).pipe(m(([a,s])=>{let{x:p,y:c}=De(t),l=ce(t),f=t.closest("table");return f&&t.parentElement&&(p+=f.offsetLeft+t.parentElement.offsetLeft,c+=f.offsetTop+t.parentElement.offsetTop),{active:a,offset:{x:p-s.x+l.width/2-r/2,y:c-s.y+l.height+8}}}))}function Qn(e){let t=e.title;if(!t.length)return S;let r=`__tooltip_${Ga++}`,o=Pt(r,"inline"),n=R(".md-typeset",o);return n.innerHTML=t,C(()=>{let i=new g;return i.subscribe({next({offset:a}){o.style.setProperty("--md-tooltip-x",`${a.x}px`),o.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(b(({active:a})=>a)),i.pipe(_e(250),b(({active:a})=>!a))).subscribe({next({active:a}){a?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Me(16,me)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?o.style.setProperty("--md-tooltip-0",`${-a}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ja(o,e).pipe(w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))}).pipe(Ke(se))}function Xa({viewport$:e}){if(!B("header.autohide"))return I(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Be(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),K()),o=Ne("search");return N([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),K(),v(n=>n?r:I(!1)),Q(!1))}function Kn(e,t){return C(()=>N([ge(e),Xa(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),K((r,o)=>r.height===o.height&&r.hidden===o.hidden),G(1))}function Yn(e,{header$:t,main$:r}){return C(()=>{let o=new g,n=o.pipe(Z(),ie(!0));o.pipe(te("active"),He(t)).subscribe(([{active:a},{hidden:s}])=>{e.classList.toggle("md-header--shadow",a&&!s),e.hidden=s});let i=ue(P("[title]",e)).pipe(b(()=>B("content.tooltips")),ne(a=>Qn(a)));return r.subscribe(o),t.pipe(W(n),m(a=>$({ref:e},a)),Re(i.pipe(W(n))))})}function Za(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=ce(e);return{active:o>=n}}),te("active"))}function Bn(e,t){return C(()=>{let r=new g;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=fe(".md-content h1");return typeof o=="undefined"?S:Za(o,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))})}function Gn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),K()),n=o.pipe(v(()=>ge(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),te("bottom"))));return N([o,n,t]).pipe(m(([i,{top:a,bottom:s},{offset:{y:p},size:{height:c}}])=>(c=Math.max(0,c-Math.max(0,a-p,i)-Math.max(0,c+p-s)),{offset:a-i,height:c,active:a-i<=p})),K((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function es(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return I(...e).pipe(ne(o=>h(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),G(1))}function Jn(e){let t=P("input",e),r=x("meta",{name:"theme-color"});document.head.appendChild(r);let o=x("meta",{name:"color-scheme"});document.head.appendChild(o);let n=$t("(prefers-color-scheme: light)");return C(()=>{let i=new g;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),p=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=p.getAttribute("data-md-color-scheme"),a.color.primary=p.getAttribute("data-md-color-primary"),a.color.accent=p.getAttribute("data-md-color-accent")}for(let[s,p]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,p);for(let s=0;sa.key==="Enter"),re(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(m(()=>{let a=Se("header"),s=window.getComputedStyle(a);return o.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(p=>(+p).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(ve(se)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),es(t).pipe(W(n.pipe(Ce(1))),ct(),w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))})}function Xn(e,{progress$:t}){return C(()=>{let r=new g;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(w(o=>r.next({value:o})),_(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Jr=Lt(Br());function ts(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Zn({alert$:e}){Jr.default.isSupported()&&new j(t=>{new Jr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ts(R(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(w(t=>{t.trigger.focus()}),m(()=>Ee("clipboard.copied"))).subscribe(e)}function ei(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function rs(e,t){let r=new Map;for(let o of P("url",e)){let n=R("loc",o),i=[ei(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let a of P("[rel=alternate]",o)){let s=a.getAttribute("href");s!=null&&i.push(ei(new URL(s),t))}}return r}function ur(e){return un(new URL("sitemap.xml",e)).pipe(m(t=>rs(t,new URL(e))),de(()=>I(new Map)))}function os(e,t){if(!(e.target instanceof Element))return S;let r=e.target.closest("a");if(r===null)return S;if(r.target||e.metaKey||e.ctrlKey)return S;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),I(new URL(r.href))):S}function ti(e){let t=new Map;for(let r of P(":scope > *",e.head))t.set(r.outerHTML,r);return t}function ri(e){for(let t of P("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return I(e)}function ns(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...B("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=fe(o),i=fe(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=ti(document);for(let[o,n]of ti(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Se("container");return We(P("script",r)).pipe(v(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new j(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),S}),Z(),ie(document))}function oi({location$:e,viewport$:t,progress$:r}){let o=xe();if(location.protocol==="file:")return S;let n=ur(o.base);I(document).subscribe(ri);let i=h(document.body,"click").pipe(He(n),v(([p,c])=>os(p,c)),pe()),a=h(window,"popstate").pipe(m(ye),pe());i.pipe(re(t)).subscribe(([p,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",p)}),O(i,a).subscribe(e);let s=e.pipe(te("pathname"),v(p=>fn(p,{progress$:r}).pipe(de(()=>(lt(p,!0),S)))),v(ri),v(ns),pe());return O(s.pipe(re(e,(p,c)=>c)),s.pipe(v(()=>e),te("hash")),e.pipe(K((p,c)=>p.pathname===c.pathname&&p.hash===c.hash),v(()=>i),w(()=>history.back()))).subscribe(p=>{var c,l;history.state!==null||!p.hash?window.scrollTo(0,(l=(c=history.state)==null?void 0:c.y)!=null?l:0):(history.scrollRestoration="auto",pn(p.hash),history.scrollRestoration="manual")}),e.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),t.pipe(te("offset"),_e(100)).subscribe(({offset:p})=>{history.replaceState(p,"")}),s}var ni=Lt(qr());function ii(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(0,ni.default)(a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function It(e){return e.type===1}function dr(e){return e.type===3}function ai(e,t){let r=yn(e);return O(I(location.protocol!=="file:"),Ne("search")).pipe(Ae(o=>o),v(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:B("search.suggest")}}})),r}function si(e){var l;let{selectedVersionSitemap:t,selectedVersionBaseURL:r,currentLocation:o,currentBaseURL:n}=e,i=(l=Xr(n))==null?void 0:l.pathname;if(i===void 0)return;let a=ss(o.pathname,i);if(a===void 0)return;let s=ps(t.keys());if(!t.has(s))return;let p=Xr(a,s);if(!p||!t.has(p.href))return;let c=Xr(a,r);if(c)return c.hash=o.hash,c.search=o.search,c}function Xr(e,t){try{return new URL(e,t)}catch(r){return}}function ss(e,t){if(e.startsWith(t))return e.slice(t.length)}function cs(e,t){let r=Math.min(e.length,t.length),o;for(o=0;oS)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:a,aliases:s})=>a===i||s.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),v(n=>h(document.body,"click").pipe(b(i=>!i.metaKey&&!i.ctrlKey),re(o),v(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&n.has(s.href)){let p=s.href;return!i.target.closest(".md-version")&&n.get(p)===a?S:(i.preventDefault(),I(new URL(p)))}}return S}),v(i=>ur(i).pipe(m(a=>{var s;return(s=si({selectedVersionSitemap:a,selectedVersionBaseURL:i,currentLocation:ye(),currentBaseURL:t.base}))!=null?s:i})))))).subscribe(n=>lt(n,!0)),N([r,o]).subscribe(([n,i])=>{R(".md-header__topic").appendChild(Cn(n,i))}),e.pipe(v(()=>o)).subscribe(n=>{var s;let i=new URL(t.base),a=__md_get("__outdated",sessionStorage,i);if(a===null){a=!0;let p=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(p)||(p=[p]);e:for(let c of p)for(let l of n.aliases.concat(n.version))if(new RegExp(c,"i").test(l)){a=!1;break e}__md_set("__outdated",a,sessionStorage,i)}if(a)for(let p of ae("outdated"))p.hidden=!1})}function ls(e,{worker$:t}){let{searchParams:r}=ye();r.has("q")&&(Je("search",!0),e.value=r.get("q"),e.focus(),Ne("search").pipe(Ae(i=>!i)).subscribe(()=>{let i=ye();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=et(e),n=O(t.pipe(Ae(It)),h(e,"keyup"),o).pipe(m(()=>e.value),K());return N([n,o]).pipe(m(([i,a])=>({value:i,focus:a})),G(1))}function pi(e,{worker$:t}){let r=new g,o=r.pipe(Z(),ie(!0));N([t.pipe(Ae(It)),r],(i,a)=>a).pipe(te("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(te("focus")).subscribe(({focus:i})=>{i&&Je("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=R("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),ls(e,{worker$:t}).pipe(w(i=>r.next(i)),_(()=>r.complete()),m(i=>$({ref:e},i)),G(1))}function li(e,{worker$:t,query$:r}){let o=new g,n=on(e.parentElement).pipe(b(Boolean)),i=e.parentElement,a=R(":scope > :first-child",e),s=R(":scope > :last-child",e);Ne("search").subscribe(l=>s.setAttribute("role",l?"list":"presentation")),o.pipe(re(r),Wr(t.pipe(Ae(It)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:a.textContent=f.length?Ee("search.result.none"):Ee("search.result.placeholder");break;case 1:a.textContent=Ee("search.result.one");break;default:let u=sr(l.length);a.textContent=Ee("search.result.other",u)}});let p=o.pipe(w(()=>s.innerHTML=""),v(({items:l})=>O(I(...l.slice(0,10)),I(...l.slice(10)).pipe(Be(4),Dr(n),v(([f])=>f)))),m(Mn),pe());return p.subscribe(l=>s.appendChild(l)),p.pipe(ne(l=>{let f=fe("details",l);return typeof f=="undefined"?S:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(b(dr),m(({data:l})=>l)).pipe(w(l=>o.next(l)),_(()=>o.complete()),m(l=>$({ref:e},l)))}function ms(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=ye();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function mi(e,t){let r=new g,o=r.pipe(Z(),ie(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),ms(e,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))}function fi(e,{worker$:t,keyboard$:r}){let o=new g,n=Se("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(ve(se),m(()=>n.value),K());return o.pipe(He(i),m(([{suggest:s},p])=>{let c=p.split(/([\s-]+)/);if(s!=null&&s.length&&c[c.length-1]){let l=s[s.length-1];l.startsWith(c[c.length-1])&&(c[c.length-1]=l)}else c.length=0;return c})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(b(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(b(dr),m(({data:s})=>s)).pipe(w(s=>o.next(s)),_(()=>o.complete()),m(()=>({ref:e})))}function ui(e,{index$:t,keyboard$:r}){let o=xe();try{let n=ai(o.search,t),i=Se("search-query",e),a=Se("search-result",e);h(e,"click").pipe(b(({target:p})=>p instanceof Element&&!!p.closest("a"))).subscribe(()=>Je("search",!1)),r.pipe(b(({mode:p})=>p==="search")).subscribe(p=>{let c=Ie();switch(p.type){case"Enter":if(c===i){let l=new Map;for(let f of P(":first-child [href]",a)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}p.claim()}break;case"Escape":case"Tab":Je("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof c=="undefined")i.focus();else{let l=[i,...P(":not(details) > [href], summary, details[open] [href]",a)],f=Math.max(0,(Math.max(0,l.indexOf(c))+l.length+(p.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}p.claim();break;default:i!==Ie()&&i.focus()}}),r.pipe(b(({mode:p})=>p==="global")).subscribe(p=>{switch(p.type){case"f":case"s":case"/":i.focus(),i.select(),p.claim();break}});let s=pi(i,{worker$:n});return O(s,li(a,{worker$:n,query$:s})).pipe(Re(...ae("search-share",e).map(p=>mi(p,{query$:s})),...ae("search-suggest",e).map(p=>fi(p,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ye}}function di(e,{index$:t,location$:r}){return N([t,r.pipe(Q(ye()),b(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>ii(o.config)(n.searchParams.get("h"))),m(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let p=s.textContent,c=o(p);c.length>p.length&&n.set(s,c)}for(let[s,p]of n){let{childNodes:c}=x("span",null,p);s.replaceWith(...Array.from(c))}return{ref:e,nodes:n}}))}function fs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return N([r,t]).pipe(m(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(n,Math.max(0,s-i))-n,{height:a,locked:s>=i+n})),K((i,a)=>i.height===a.height&&i.locked===a.locked))}function Zr(e,o){var n=o,{header$:t}=n,r=so(n,["header$"]);let i=R(".md-sidebar__scrollwrap",e),{y:a}=De(i);return C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=s.pipe(Me(0,me));return c.pipe(re(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*a}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(Ae()).subscribe(()=>{for(let l of P(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2})}}}),ue(P("label[tabindex]",e)).pipe(ne(l=>h(l,"click").pipe(ve(se),m(()=>l),W(p)))).subscribe(l=>{let f=R(`[id="${l.htmlFor}"]`);R(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),fs(e,r).pipe(w(l=>s.next(l)),_(()=>s.complete()),m(l=>$({ref:e},l)))})}function hi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return st(je(`${r}/releases/latest`).pipe(de(()=>S),m(o=>({version:o.tag_name})),Ve({})),je(r).pipe(de(()=>S),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),Ve({}))).pipe(m(([o,n])=>$($({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return je(r).pipe(m(o=>({repositories:o.public_repos})),Ve({}))}}function bi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return st(je(`${r}/releases/permalink/latest`).pipe(de(()=>S),m(({tag_name:o})=>({version:o})),Ve({})),je(r).pipe(de(()=>S),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Ve({}))).pipe(m(([o,n])=>$($({},o),n)))}function vi(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return hi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return bi(r,o)}return S}var us;function ds(e){return us||(us=C(()=>{let t=__md_get("__source",sessionStorage);if(t)return I(t);if(ae("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return S}return vi(e.href).pipe(w(o=>__md_set("__source",o,sessionStorage)))}).pipe(de(()=>S),b(t=>Object.keys(t).length>0),m(t=>({facts:t})),G(1)))}function gi(e){let t=R(":scope > :last-child",e);return C(()=>{let r=new g;return r.subscribe(({facts:o})=>{t.appendChild(_n(o)),t.classList.add("md-source__repository--active")}),ds(e).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function hs(e,{viewport$:t,header$:r}){return ge(document.body).pipe(v(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),te("hidden"))}function yi(e,t){return C(()=>{let r=new g;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(B("navigation.tabs.sticky")?I({hidden:!1}):hs(e,t)).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function bs(e,{viewport$:t,header$:r}){let o=new Map,n=P(".md-nav__link",e);for(let s of n){let p=decodeURIComponent(s.hash.substring(1)),c=fe(`[id="${p}"]`);typeof c!="undefined"&&o.set(s,c)}let i=r.pipe(te("height"),m(({height:s})=>{let p=Se("main"),c=R(":scope > :first-child",p);return s+.8*(c.offsetTop-p.offsetTop)}),pe());return ge(document.body).pipe(te("height"),v(s=>C(()=>{let p=[];return I([...o].reduce((c,[l,f])=>{for(;p.length&&o.get(p[p.length-1]).tagName>=f.tagName;)p.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return c.set([...p=[...p,l]].reverse(),u)},new Map))}).pipe(m(p=>new Map([...p].sort(([,c],[,l])=>c-l))),He(i),v(([p,c])=>t.pipe(Fr(([l,f],{offset:{y:u},size:d})=>{let y=u+d.height>=Math.floor(s.height);for(;f.length;){let[,L]=f[0];if(L-c=u&&!y)f=[l.pop(),...f];else break}return[l,f]},[[],[...p]]),K((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([s,p])=>({prev:s.map(([c])=>c),next:p.map(([c])=>c)})),Q({prev:[],next:[]}),Be(2,1),m(([s,p])=>s.prev.length{let i=new g,a=i.pipe(Z(),ie(!0));if(i.subscribe(({prev:s,next:p})=>{for(let[c]of p)c.classList.remove("md-nav__link--passed"),c.classList.remove("md-nav__link--active");for(let[c,[l]]of s.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",c===s.length-1)}),B("toc.follow")){let s=O(t.pipe(_e(1),m(()=>{})),t.pipe(_e(250),m(()=>"smooth")));i.pipe(b(({prev:p})=>p.length>0),He(o.pipe(ve(se))),re(s)).subscribe(([[{prev:p}],c])=>{let[l]=p[p.length-1];if(l.offsetHeight){let f=cr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2,behavior:c})}}})}return B("navigation.tracking")&&t.pipe(W(a),te("offset"),_e(250),Ce(1),W(n.pipe(Ce(1))),ct({delay:250}),re(i)).subscribe(([,{prev:s}])=>{let p=ye(),c=s[s.length-1];if(c&&c.length){let[l]=c,{hash:f}=new URL(l.href);p.hash!==f&&(p.hash=f,history.replaceState({},"",`${p}`))}else p.hash="",history.replaceState({},"",`${p}`)}),bs(e,{viewport$:t,header$:r}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function vs(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:a}})=>a),Be(2,1),m(([a,s])=>a>s&&s>0),K()),i=r.pipe(m(({active:a})=>a));return N([i,n]).pipe(m(([a,s])=>!(a&&s)),K(),W(o.pipe(Ce(1))),ie(!0),ct({delay:250}),m(a=>({hidden:a})))}function Ei(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(a),te("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),h(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),vs(e,{viewport$:t,main$:o,target$:n}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))}function wi({document$:e,viewport$:t}){e.pipe(v(()=>P(".md-ellipsis")),ne(r=>tt(r).pipe(W(e.pipe(Ce(1))),b(o=>o),m(()=>r),Te(1))),b(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,B("content.tooltips")?mt(n,{viewport$:t}).pipe(W(e.pipe(Ce(1))),_(()=>n.removeAttribute("title"))):S})).subscribe(),B("content.tooltips")&&e.pipe(v(()=>P(".md-status")),ne(r=>mt(r,{viewport$:t}))).subscribe()}function Ti({document$:e,tablet$:t}){e.pipe(v(()=>P(".md-toggle--indeterminate")),w(r=>{r.indeterminate=!0,r.checked=!1}),ne(r=>h(r,"change").pipe(Vr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),re(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function gs(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Si({document$:e}){e.pipe(v(()=>P("[data-md-scrollfix]")),w(t=>t.removeAttribute("data-md-scrollfix")),b(gs),ne(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Oi({viewport$:e,tablet$:t}){N([Ne("search"),t]).pipe(m(([r,o])=>r&&!o),v(r=>I(r).pipe(Ge(r?400:100))),re(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function ys(){return location.protocol==="file:"?wt(`${new URL("search/search_index.js",eo.base)}`).pipe(m(()=>__index),G(1)):je(new URL("search/search_index.json",eo.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var ot=Go(),Ft=sn(),Ot=ln(Ft),to=an(),Oe=gn(),hr=$t("(min-width: 960px)"),Mi=$t("(min-width: 1220px)"),_i=mn(),eo=xe(),Ai=document.forms.namedItem("search")?ys():Ye,ro=new g;Zn({alert$:ro});var oo=new g;B("navigation.instant")&&oi({location$:Ft,viewport$:Oe,progress$:oo}).subscribe(ot);var Li;((Li=eo.version)==null?void 0:Li.provider)==="mike"&&ci({document$:ot});O(Ft,Ot).pipe(Ge(125)).subscribe(()=>{Je("drawer",!1),Je("search",!1)});to.pipe(b(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=fe("link[rel=prev]");typeof t!="undefined"&<(t);break;case"n":case".":let r=fe("link[rel=next]");typeof r!="undefined"&<(r);break;case"Enter":let o=Ie();o instanceof HTMLLabelElement&&o.click()}});wi({viewport$:Oe,document$:ot});Ti({document$:ot,tablet$:hr});Si({document$:ot});Oi({viewport$:Oe,tablet$:hr});var rt=Kn(Se("header"),{viewport$:Oe}),jt=ot.pipe(m(()=>Se("main")),v(e=>Gn(e,{viewport$:Oe,header$:rt})),G(1)),xs=O(...ae("consent").map(e=>En(e,{target$:Ot})),...ae("dialog").map(e=>qn(e,{alert$:ro})),...ae("palette").map(e=>Jn(e)),...ae("progress").map(e=>Xn(e,{progress$:oo})),...ae("search").map(e=>ui(e,{index$:Ai,keyboard$:to})),...ae("source").map(e=>gi(e))),Es=C(()=>O(...ae("announce").map(e=>xn(e)),...ae("content").map(e=>Nn(e,{viewport$:Oe,target$:Ot,print$:_i})),...ae("content").map(e=>B("search.highlight")?di(e,{index$:Ai,location$:Ft}):S),...ae("header").map(e=>Yn(e,{viewport$:Oe,header$:rt,main$:jt})),...ae("header-title").map(e=>Bn(e,{viewport$:Oe,header$:rt})),...ae("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?zr(Mi,()=>Zr(e,{viewport$:Oe,header$:rt,main$:jt})):zr(hr,()=>Zr(e,{viewport$:Oe,header$:rt,main$:jt}))),...ae("tabs").map(e=>yi(e,{viewport$:Oe,header$:rt})),...ae("toc").map(e=>xi(e,{viewport$:Oe,header$:rt,main$:jt,target$:Ot})),...ae("top").map(e=>Ei(e,{viewport$:Oe,header$:rt,main$:jt,target$:Ot})))),Ci=ot.pipe(v(()=>Es),Re(xs),G(1));Ci.subscribe();window.document$=ot;window.location$=Ft;window.target$=Ot;window.keyboard$=to;window.viewport$=Oe;window.tablet$=hr;window.screen$=Mi;window.print$=_i;window.alert$=ro;window.progress$=oo;window.component$=Ci;})(); +//# sourceMappingURL=bundle.13a4f30d.min.js.map + diff --git a/mkdocs/site/assets/javascripts/bundle.13a4f30d.min.js.map b/mkdocs/site/assets/javascripts/bundle.13a4f30d.min.js.map new file mode 100644 index 0000000..8941cb8 --- /dev/null +++ b/mkdocs/site/assets/javascripts/bundle.13a4f30d.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/escape-html/index.js", "node_modules/clipboard/dist/clipboard.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/tslib/tslib.es6.mjs", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/BehaviorSubject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/QueueAction.ts", "node_modules/rxjs/src/internal/scheduler/QueueScheduler.ts", "node_modules/rxjs/src/internal/scheduler/queue.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounce.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip2/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/findurl/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*\n * Copyright (c) 2016-2025 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ viewport$, document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\n\nvar extendStatics = function(d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\n return extendStatics(d, b);\n};\n\nexport function __extends(d, b) {\n if (typeof b !== \"function\" && b !== null)\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\n\nexport var __assign = function() {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n }\n return __assign.apply(this, arguments);\n}\n\nexport function __rest(s, e) {\n var t = {};\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n t[p] = s[p];\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n t[p[i]] = s[p[i]];\n }\n return t;\n}\n\nexport function __decorate(decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\n\nexport function __param(paramIndex, decorator) {\n return function (target, key) { decorator(target, key, paramIndex); }\n}\n\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n var _, done = false;\n for (var i = decorators.length - 1; i >= 0; i--) {\n var context = {};\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n if (kind === \"accessor\") {\n if (result === void 0) continue;\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n if (_ = accept(result.get)) descriptor.get = _;\n if (_ = accept(result.set)) descriptor.set = _;\n if (_ = accept(result.init)) initializers.unshift(_);\n }\n else if (_ = accept(result)) {\n if (kind === \"field\") initializers.unshift(_);\n else descriptor[key] = _;\n }\n }\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\n done = true;\n};\n\nexport function __runInitializers(thisArg, initializers, value) {\n var useValue = arguments.length > 2;\n for (var i = 0; i < initializers.length; i++) {\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n }\n return useValue ? value : void 0;\n};\n\nexport function __propKey(x) {\n return typeof x === \"symbol\" ? x : \"\".concat(x);\n};\n\nexport function __setFunctionName(f, name, prefix) {\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n};\n\nexport function __metadata(metadataKey, metadataValue) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\n\nexport function __awaiter(thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n}\n\nexport function __generator(thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n}\n\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n});\n\nexport function __exportStar(m, o) {\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\n}\n\nexport function __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return { value: o && o[i++], done: !o };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\n\nexport function __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o), r, ar = [], e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n }\n catch (error) { e = { error: error }; }\n finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n }\n finally { if (e) throw e.error; }\n }\n return ar;\n}\n\n/** @deprecated */\nexport function __spread() {\n for (var ar = [], i = 0; i < arguments.length; i++)\n ar = ar.concat(__read(arguments[i]));\n return ar;\n}\n\n/** @deprecated */\nexport function __spreadArrays() {\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n r[k] = a[j];\n return r;\n}\n\nexport function __spreadArray(to, from, pack) {\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n if (ar || !(i in from)) {\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n ar[i] = from[i];\n }\n }\n return to.concat(ar || Array.prototype.slice.call(from));\n}\n\nexport function __await(v) {\n return this instanceof __await ? (this.v = v, this) : new __await(v);\n}\n\nexport function __asyncGenerator(thisArg, _arguments, generator) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\n function fulfill(value) { resume(\"next\", value); }\n function reject(value) { resume(\"throw\", value); }\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\n}\n\nexport function __asyncDelegator(o) {\n var i, p;\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\n}\n\nexport function __asyncValues(o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n}\n\nexport function __makeTemplateObject(cooked, raw) {\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\n return cooked;\n};\n\nvar __setModuleDefault = Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n};\n\nexport function __importStar(mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n}\n\nexport function __importDefault(mod) {\n return (mod && mod.__esModule) ? mod : { default: mod };\n}\n\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\n\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n}\n\nexport function __classPrivateFieldIn(state, receiver) {\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\n\nexport function __addDisposableResource(env, value, async) {\n if (value !== null && value !== void 0) {\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n var dispose, inner;\n if (async) {\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n dispose = value[Symbol.asyncDispose];\n }\n if (dispose === void 0) {\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n dispose = value[Symbol.dispose];\n if (async) inner = dispose;\n }\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\n env.stack.push({ value: value, dispose: dispose, async: async });\n }\n else if (async) {\n env.stack.push({ async: true });\n }\n return value;\n}\n\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nexport function __disposeResources(env) {\n function fail(e) {\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n env.hasError = true;\n }\n var r, s = 0;\n function next() {\n while (r = env.stack.pop()) {\n try {\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\n if (r.dispose) {\n var result = r.dispose.call(r.value);\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\n }\n else s |= 1;\n }\n catch (e) {\n fail(e);\n }\n }\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\n if (env.hasError) throw env.error;\n }\n return next();\n}\n\nexport default {\n __extends,\n __assign,\n __rest,\n __decorate,\n __param,\n __metadata,\n __awaiter,\n __generator,\n __createBinding,\n __exportStar,\n __values,\n __read,\n __spread,\n __spreadArrays,\n __spreadArray,\n __await,\n __asyncGenerator,\n __asyncDelegator,\n __asyncValues,\n __makeTemplateObject,\n __importStar,\n __importDefault,\n __classPrivateFieldGet,\n __classPrivateFieldSet,\n __classPrivateFieldIn,\n __addDisposableResource,\n __disposeResources,\n};\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n */\nexport class Subscription implements SubscriptionLike {\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param value The `next` value.\n */\n next(value: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param err The `error` exception.\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as ((value: T) => void) | undefined,\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent.\n * @param subscriber The stopped subscriber.\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @param subscribe The function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @param subscribe the subscriber function to be passed to the Observable constructor\n * @return A new observable.\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @param operator the operator defining the operation to take on the observable\n * @return A new observable with the Operator applied.\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param observerOrNext Either an {@link Observer} with some or all callback methods,\n * or the `next` handler that is called for each value emitted from the subscribed Observable.\n * @param error A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param complete A handler for a terminal event resulting from successful completion.\n * @return A subscription reference to the registered handlers.\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next A handler for each value emitted by the observable.\n * @return A promise that either resolves on observable completion or\n * rejects with the handled error.\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @return This instance of the observable.\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n *\n * @return The Observable result of all the operators having been called\n * in the order they were passed in.\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return Observable that this Subject casts to.\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { Subject } from './Subject';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\n\n/**\n * A variant of Subject that requires an initial value and emits its current\n * value whenever it is subscribed to.\n */\nexport class BehaviorSubject extends Subject {\n constructor(private _value: T) {\n super();\n }\n\n get value(): T {\n return this.getValue();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n const subscription = super._subscribe(subscriber);\n !subscription.closed && subscriber.next(this._value);\n return subscription;\n }\n\n getValue(): T {\n const { hasError, thrownError, _value } = this;\n if (hasError) {\n throw thrownError;\n }\n this._throwIfClosed();\n return _value;\n }\n\n next(value: T): void {\n super.next((this._value = value));\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param _bufferSize The size of the buffer to replay on subscription\n * @param _windowTime The amount of time the buffered items will stay buffered\n * @param _timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param state Some contextual data that the `work` function uses when called by the\n * Scheduler.\n * @param delay Time to wait before executing the work, where the time unit is implicit\n * and defined by the Scheduler.\n * @return A subscription in order to be able to unsubscribe the scheduled work.\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param work A function representing a task, or some unit of work to be\n * executed by the Scheduler.\n * @param delay Time to wait before executing the work, where the time unit is\n * implicit and defined by the Scheduler itself.\n * @param state Some contextual data that the `work` function uses when called\n * by the Scheduler.\n * @return A subscription in order to be able to unsubscribe the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { Subscription } from '../Subscription';\nimport { QueueScheduler } from './QueueScheduler';\nimport { SchedulerAction } from '../types';\nimport { TimerHandle } from './timerHandle';\n\nexport class QueueAction extends AsyncAction {\n constructor(protected scheduler: QueueScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (delay > 0) {\n return super.schedule(state, delay);\n }\n this.delay = delay;\n this.state = state;\n this.scheduler.flush(this);\n return this;\n }\n\n public execute(state: T, delay: number): any {\n return delay > 0 || this.closed ? super.execute(state, delay) : this._execute(state, delay);\n }\n\n protected requestAsyncId(scheduler: QueueScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n\n if ((delay != null && delay > 0) || (delay == null && this.delay > 0)) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n\n // Otherwise flush the scheduler starting with this action.\n scheduler.flush(this);\n\n // HACK: In the past, this was returning `void`. However, `void` isn't a valid\n // `TimerHandle`, and generally the return value here isn't really used. So the\n // compromise is to return `0` which is both \"falsy\" and a valid `TimerHandle`,\n // as opposed to refactoring every other instanceo of `requestAsyncId`.\n return 0;\n }\n}\n", "import { AsyncScheduler } from './AsyncScheduler';\n\nexport class QueueScheduler extends AsyncScheduler {\n}\n", "import { QueueAction } from './QueueAction';\nimport { QueueScheduler } from './QueueScheduler';\n\n/**\n *\n * Queue Scheduler\n *\n * Put every next task on a queue, instead of executing it immediately\n *\n * `queue` scheduler, when used with delay, behaves the same as {@link asyncScheduler} scheduler.\n *\n * When used without delay, it schedules given task synchronously - executes it right when\n * it is scheduled. However when called recursively, that is when inside the scheduled task,\n * another task is scheduled with queue scheduler, instead of executing immediately as well,\n * that task will be put on a queue and wait for current one to finish.\n *\n * This means that when you execute task with `queue` scheduler, you are sure it will end\n * before any other task scheduled with that scheduler will start.\n *\n * ## Examples\n * Schedule recursively first, then do something\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(() => {\n * queueScheduler.schedule(() => console.log('second')); // will not happen now, but will be put on a queue\n *\n * console.log('first');\n * });\n *\n * // Logs:\n * // \"first\"\n * // \"second\"\n * ```\n *\n * Reschedule itself recursively\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(function(state) {\n * if (state !== 0) {\n * console.log('before', state);\n * this.schedule(state - 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * console.log('after', state);\n * }\n * }, 0, 3);\n *\n * // In scheduler that runs recursively, you would expect:\n * // \"before\", 3\n * // \"before\", 2\n * // \"before\", 1\n * // \"after\", 1\n * // \"after\", 2\n * // \"after\", 3\n *\n * // But with queue it logs:\n * // \"before\", 3\n * // \"after\", 3\n * // \"before\", 2\n * // \"after\", 2\n * // \"before\", 1\n * // \"after\", 1\n * ```\n */\n\nexport const queueScheduler = new QueueScheduler(QueueAction);\n\n/**\n * @deprecated Renamed to {@link queueScheduler}. Will be removed in v8.\n */\nexport const queue = queueScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && id === scheduler._scheduled && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n let flushId;\n if (action) {\n flushId = action.id;\n } else {\n flushId = this._scheduled;\n this._scheduled = undefined;\n }\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an