diff --git a/old code/1cc01b8Comenzi Productie (19).xlsx b/old code/1cc01b8Comenzi Productie (19).xlsx deleted file mode 100644 index 1e77714..0000000 Binary files a/old code/1cc01b8Comenzi Productie (19).xlsx and /dev/null differ diff --git a/old code/CSS_MODULAR_GUIDE.md b/old code/CSS_MODULAR_GUIDE.md deleted file mode 100644 index f9d069c..0000000 --- a/old code/CSS_MODULAR_GUIDE.md +++ /dev/null @@ -1,152 +0,0 @@ -# CSS Modular Structure Guide - -## Overview -This guide explains how to migrate from a monolithic CSS file to a modular CSS structure for better maintainability and organization. - -## New CSS Structure - -``` -app/static/css/ -├── base.css # Global styles, header, buttons, theme -├── login.css # Login page specific styles -├── dashboard.css # Dashboard and module cards -├── warehouse.css # Warehouse module styles -├── etichete.css # Labels/etiquette module styles (to be created) -├── quality.css # Quality module styles (to be created) -└── scan.css # Scan module styles (to be created) -``` - -## Implementation Strategy - -### Phase 1: Setup Modular Structure ✅ -- [x] Created `css/` directory -- [x] Created `base.css` with global styles -- [x] Created `login.css` for login page -- [x] Created `warehouse.css` for warehouse module -- [x] Updated `base.html` to include modular CSS -- [x] Updated `login.html` to use new structure - -### Phase 2: Migration Plan (Next Steps) - -1. **Extract module-specific styles from style.css:** - - Etiquette/Labels module → `etichete.css` - - Quality module → `quality.css` - - Scan module → `scan.css` - -2. **Update templates to use modular CSS:** - ```html - {% block head %} - - {% endblock %} - ``` - -3. **Clean up original style.css:** - - Remove extracted styles - - Keep only legacy/common styles temporarily - - Eventually eliminate when all modules migrated - -## Template Usage Pattern - -### Standard Template Structure: -```html -{% extends "base.html" %} -{% block title %}Page Title{% endblock %} - -{% block head %} - - - - -{% endblock %} - -{% block content %} - -{% endblock %} -``` - -## CSS Loading Order - -1. `base.css` - Global styles, header, buttons, theme -2. `style.css` - Legacy styles (temporary, for backward compatibility) -3. Module-specific CSS (e.g., `warehouse.css`) -4. Inline ` -{% endblock %} -``` - -### After: -1. Move styles to `css/module-name.css` -2. Update template: -```html -{% block head %} - -{% endblock %} -``` - -## Best Practices - -1. **Use semantic naming:** `warehouse.css`, `login.css`, not `page1.css` -2. **Keep base.css minimal:** Only truly global styles -3. **Avoid deep nesting:** Keep CSS selectors simple -4. **Use consistent naming:** Follow existing patterns -5. **Document changes:** Update this guide when adding new modules - -## Next Steps - -1. Extract etiquette module styles to `etichete.css` -2. Update all etiquette templates to use new CSS -3. Extract quality module styles to `quality.css` -4. Extract scan module styles to `scan.css` -5. Gradually remove migrated styles from `style.css` -6. Eventually remove `style.css` dependency from `base.html` \ No newline at end of file diff --git a/old code/DATABASE_SETUP_README.md b/old code/DATABASE_SETUP_README.md deleted file mode 100644 index 73c617b..0000000 --- a/old code/DATABASE_SETUP_README.md +++ /dev/null @@ -1,133 +0,0 @@ -# Quick Database Setup for Trasabilitate Application - -This script provides a complete one-step database setup for quick deployment of the Trasabilitate application. - -## Prerequisites - -Before running the setup script, ensure: - -1. **MariaDB is installed and running** -2. **Database and user are created**: - ```sql - CREATE DATABASE trasabilitate; - CREATE USER 'trasabilitate'@'localhost' IDENTIFIED BY 'Initial01!'; - GRANT ALL PRIVILEGES ON trasabilitate.* TO 'trasabilitate'@'localhost'; - FLUSH PRIVILEGES; - ``` -3. **Python virtual environment is activated**: - ```bash - source ../recticel/bin/activate - ``` -4. **Python dependencies are installed**: - ```bash - pip install -r requirements.txt - ``` - -## Usage - -### Quick Setup (Recommended) -```bash -cd /srv/quality_recticel/py_app -source ../recticel/bin/activate -python3 app/db_create_scripts/setup_complete_database.py -``` - -### What the script creates: - -#### MariaDB Tables: -- `scan1_orders` - Quality scanning data for process 1 -- `scanfg_orders` - Quality scanning data for finished goods -- `order_for_labels` - Label printing orders -- `warehouse_locations` - Warehouse location management -- `permissions` - System permissions -- `role_permissions` - Role-permission mappings -- `role_hierarchy` - User role hierarchy -- `permission_audit_log` - Permission change audit trail - -#### Database Triggers: -- Auto-increment approved/rejected quantities based on quality codes -- Triggers for both scan1_orders and scanfg_orders tables - -#### SQLite Tables: -- `users` - User authentication (in instance/users.db) -- `roles` - User roles (in instance/users.db) - -#### Configuration: -- Updates `instance/external_server.conf` with correct database settings -- Creates default superadmin user (username: `superadmin`, password: `superadmin123`) - -#### Permission System: -- 7 user roles (superadmin, admin, manager, quality_manager, warehouse_manager, quality_worker, warehouse_worker) -- 25+ granular permissions for different application areas -- Complete role hierarchy with inheritance - -## After Setup - -1. **Start the application**: - ```bash - python3 run.py - ``` - -2. **Access the application**: - - Local: http://127.0.0.1:8781 - - Network: http://192.168.0.205:8781 - -3. **Login with superadmin**: - - Username: `superadmin` - - Password: `superadmin123` - -## Troubleshooting - -### Common Issues: - -1. **Database connection failed**: - - Check if MariaDB is running: `sudo systemctl status mariadb` - - Verify database exists: `sudo mysql -e "SHOW DATABASES;"` - - Check user privileges: `sudo mysql -e "SHOW GRANTS FOR 'trasabilitate'@'localhost';"` - -2. **Import errors**: - - Ensure virtual environment is activated - - Install missing dependencies: `pip install -r requirements.txt` - -3. **Permission denied**: - - Make script executable: `chmod +x app/db_create_scripts/setup_complete_database.py` - - Check file ownership: `ls -la app/db_create_scripts/` - -### Manual Database Recreation: - -If you need to completely reset the database: - -```bash -# Drop and recreate database -sudo mysql -e "DROP DATABASE IF EXISTS trasabilitate; CREATE DATABASE trasabilitate; GRANT ALL PRIVILEGES ON trasabilitate.* TO 'trasabilitate'@'localhost'; FLUSH PRIVILEGES;" - -# Remove SQLite database -rm -f instance/users.db - -# Run setup script -python3 app/db_create_scripts/setup_complete_database.py -``` - -## Script Features - -- ✅ **Comprehensive**: Creates all necessary database structure -- ✅ **Safe**: Uses `IF NOT EXISTS` clauses to prevent conflicts -- ✅ **Verified**: Includes verification step to confirm setup -- ✅ **Informative**: Detailed output showing each step -- ✅ **Error handling**: Clear error messages and troubleshooting hints -- ✅ **Idempotent**: Can be run multiple times safely - -## Development Notes - -The script combines functionality from these individual scripts: -- `create_scan_1db.py` -- `create_scanfg_orders.py` -- `create_order_for_labels_table.py` -- `create_warehouse_locations_table.py` -- `create_permissions_tables.py` -- `create_roles_table.py` -- `create_triggers.py` -- `create_triggers_fg.py` -- `populate_permissions.py` - -For development or debugging, you can still run individual scripts if needed. \ No newline at end of file diff --git a/old code/DOCKER_DEPLOYMENT.md b/old code/DOCKER_DEPLOYMENT.md deleted file mode 100644 index 1866eab..0000000 --- a/old code/DOCKER_DEPLOYMENT.md +++ /dev/null @@ -1,319 +0,0 @@ -# Recticel Quality Application - Docker Deployment Guide - -## 📋 Overview - -This is a complete Docker-based deployment solution for the Recticel Quality Application. It includes: -- **Flask Web Application** (Python 3.10) -- **MariaDB 11.3 Database** with automatic initialization -- **Gunicorn WSGI Server** for production-ready performance -- **Automatic database schema setup** using existing setup scripts -- **Superadmin user seeding** for immediate access - -## 🚀 Quick Start - -### Prerequisites -- Docker Engine 20.10+ -- Docker Compose 2.0+ -- At least 2GB free disk space -- Ports 8781 and 3306 available (or customize in .env) - -### 1. Clone and Prepare - -```bash -cd /srv/quality_recticel -``` - -### 2. Configure Environment (Optional) - -Create a `.env` file from the example: - -```bash -cp .env.example .env -``` - -Edit `.env` to customize settings: -```env -MYSQL_ROOT_PASSWORD=your_secure_root_password -DB_PORT=3306 -APP_PORT=8781 -INIT_DB=true -SEED_DB=true -``` - -### 3. Build and Deploy - -Start all services: - -```bash -docker-compose up -d --build -``` - -This will: -1. ✅ Build the Flask application Docker image -2. ✅ Pull MariaDB 11.3 image -3. ✅ Create and initialize the database -4. ✅ Run all database schema creation scripts -5. ✅ Seed the superadmin user -6. ✅ Start the web application on port 8781 - -### 4. Verify Deployment - -Check service status: -```bash -docker-compose ps -``` - -View logs: -```bash -# All services -docker-compose logs -f - -# Just the web app -docker-compose logs -f web - -# Just the database -docker-compose logs -f db -``` - -### 5. Access the Application - -Open your browser and navigate to: -``` -http://localhost:8781 -``` - -**Default Login:** -- Username: `superadmin` -- Password: `superadmin123` - -## 🔧 Management Commands - -### Start Services -```bash -docker-compose up -d -``` - -### Stop Services -```bash -docker-compose down -``` - -### Stop and Remove All Data (including database) -```bash -docker-compose down -v -``` - -### Restart Services -```bash -docker-compose restart -``` - -### View Real-time Logs -```bash -docker-compose logs -f -``` - -### Rebuild After Code Changes -```bash -docker-compose up -d --build -``` - -### Access Database Console -```bash -docker-compose exec db mariadb -u trasabilitate -p trasabilitate -# Password: Initial01! -``` - -### Execute Commands in App Container -```bash -docker-compose exec web bash -``` - -## 📁 Data Persistence - -The following data is persisted across container restarts: - -- **Database Data:** Stored in Docker volume `mariadb_data` -- **Application Logs:** Mapped to `./logs` directory -- **Instance Config:** Mapped to `./instance` directory - -## 🔐 Security Considerations - -### Production Deployment Checklist: - -1. **Change Default Passwords:** - - Update `MYSQL_ROOT_PASSWORD` in `.env` - - Update database password in `docker-compose.yml` - - Change superadmin password after first login - -2. **Use Environment Variables:** - - Never commit `.env` file to version control - - Use secrets management for production - -3. **Network Security:** - - If database access from host is not needed, remove the port mapping: - ```yaml - # Comment out in docker-compose.yml: - # ports: - # - "3306:3306" - ``` - -4. **SSL/TLS:** - - Configure reverse proxy (nginx/traefik) for HTTPS - - Update gunicorn SSL configuration if needed - -5. **Firewall:** - - Only expose necessary ports - - Use firewall rules to restrict access - -## 🐛 Troubleshooting - -### Database Connection Issues - -If the app can't connect to the database: - -```bash -# Check database health -docker-compose exec db healthcheck.sh --connect - -# Check database logs -docker-compose logs db - -# Verify database is accessible -docker-compose exec db mariadb -u trasabilitate -p -e "SHOW DATABASES;" -``` - -### Application Not Starting - -```bash -# Check application logs -docker-compose logs web - -# Verify database initialization -docker-compose exec web python3 -c "import mariadb; print('MariaDB module OK')" - -# Restart with fresh initialization -docker-compose down -docker-compose up -d -``` - -### Port Already in Use - -If port 8781 or 3306 is already in use, edit `.env`: - -```env -APP_PORT=8782 -DB_PORT=3307 -``` - -Then restart: -```bash -docker-compose down -docker-compose up -d -``` - -### Reset Everything - -To start completely fresh: - -```bash -# Stop and remove all containers, networks, and volumes -docker-compose down -v - -# Remove any local data -rm -rf logs/* instance/external_server.conf - -# Start fresh -docker-compose up -d --build -``` - -## 🔄 Updating the Application - -### Update Application Code - -1. Make your code changes -2. Rebuild and restart: - ```bash - docker-compose up -d --build web - ``` - -### Update Database Schema - -If you need to run migrations or schema updates: - -```bash -docker-compose exec web python3 /app/app/db_create_scripts/setup_complete_database.py -``` - -## 📊 Monitoring - -### Health Checks - -Both services have health checks configured: - -```bash -# Check overall status -docker-compose ps - -# Detailed health status -docker inspect recticel-app | grep -A 10 Health -docker inspect recticel-db | grep -A 10 Health -``` - -### Resource Usage - -```bash -# View resource consumption -docker stats recticel-app recticel-db -``` - -## 🏗️ Architecture - -``` -┌─────────────────────────────────────┐ -│ Docker Compose Network │ -│ │ -│ ┌──────────────┐ ┌─────────────┐ │ -│ │ MariaDB │ │ Flask App │ │ -│ │ Container │◄─┤ Container │ │ -│ │ │ │ │ │ -│ │ Port: 3306 │ │ Port: 8781 │ │ -│ └──────┬───────┘ └──────┬──────┘ │ -│ │ │ │ -└─────────┼─────────────────┼─────────┘ - │ │ - ▼ ▼ - [Volume: [Logs & - mariadb_data] Instance] -``` - -## 📝 Environment Variables - -### Database Configuration -- `MYSQL_ROOT_PASSWORD`: MariaDB root password -- `DB_HOST`: Database hostname (default: `db`) -- `DB_PORT`: Database port (default: `3306`) -- `DB_NAME`: Database name (default: `trasabilitate`) -- `DB_USER`: Database user (default: `trasabilitate`) -- `DB_PASSWORD`: Database password (default: `Initial01!`) - -### Application Configuration -- `FLASK_ENV`: Flask environment (default: `production`) -- `FLASK_APP`: Flask app entry point (default: `run.py`) -- `APP_PORT`: Application port (default: `8781`) - -### Initialization Flags -- `INIT_DB`: Run database initialization (default: `true`) -- `SEED_DB`: Seed superadmin user (default: `true`) - -## 🆘 Support - -For issues or questions: -1. Check the logs: `docker-compose logs -f` -2. Verify environment configuration -3. Ensure all prerequisites are met -4. Review this documentation - -## 📄 License - -[Your License Here] diff --git a/old code/DOCKER_DEPLOYMENT_GUIDE.md b/old code/DOCKER_DEPLOYMENT_GUIDE.md deleted file mode 100644 index cdeb7e1..0000000 --- a/old code/DOCKER_DEPLOYMENT_GUIDE.md +++ /dev/null @@ -1,303 +0,0 @@ -# Quality Application - Docker Deployment Guide - -## 📋 Overview - -This application is containerized with Docker and docker-compose, providing: -- **MariaDB 11.3** database with persistent storage -- **Flask** web application with Gunicorn -- **Mapped volumes** for easy access to code, data, and backups - -## 🗂️ Volume Structure - -``` -quality_app/ -├── data/ -│ └── mariadb/ # Database files (MariaDB data directory) -├── config/ -│ └── instance/ # Application configuration (external_server.conf) -├── logs/ # Application and Gunicorn logs -├── backups/ # Database backup files (shared with DB container) -└── py_app/ # Application source code (optional mapping) -``` - -## 🚀 Quick Start - -### 1. Setup Volumes - -```bash -# Create necessary directories -bash setup-volumes.sh -``` - -### 2. Configure Environment - -```bash -# Create .env file from example -cp .env.example .env - -# Edit configuration (IMPORTANT: Change passwords!) -nano .env -``` - -**Critical settings to change:** -- `MYSQL_ROOT_PASSWORD` - Database root password -- `DB_PASSWORD` - Application database password -- `SECRET_KEY` - Flask secret key (generate random string) - -**First deployment settings:** -- `INIT_DB=true` - Initialize database schema -- `SEED_DB=true` - Seed with default data - -**After first deployment:** -- `INIT_DB=false` -- `SEED_DB=false` - -### 3. Deploy Application - -**Option A: Automated deployment** -```bash -bash quick-deploy.sh -``` - -**Option B: Manual deployment** -```bash -# Build images -docker-compose build - -# Start services -docker-compose up -d - -# View logs -docker-compose logs -f -``` - -## 📦 Application Dependencies - -### Python Packages (from requirements.txt): -- Flask - Web framework -- Flask-SSLify - SSL support -- Werkzeug - WSGI utilities -- gunicorn - Production WSGI server -- pyodbc - ODBC database connectivity -- mariadb - MariaDB connector -- reportlab - PDF generation -- requests - HTTP library -- pandas - Data manipulation -- openpyxl - Excel file support -- APScheduler - Job scheduling for automated backups - -### System Dependencies (handled in Dockerfile): -- Python 3.10 -- MariaDB client libraries -- curl (for health checks) - -## 🐳 Docker Images - -### Web Application -- **Base**: python:3.10-slim -- **Multi-stage build** for minimal image size -- **Non-root user** for security -- **Health checks** enabled - -### Database -- **Image**: mariadb:11.3 -- **Persistent storage** with volume mapping -- **Performance tuning** via environment variables - -## 📊 Resource Limits - -### Database Container -- CPU: 2.0 cores (limit), 0.5 cores (reserved) -- Memory: 2GB (limit), 512MB (reserved) -- Buffer pool: 512MB - -### Web Container -- CPU: 2.0 cores (limit), 0.5 cores (reserved) -- Memory: 2GB (limit), 512MB (reserved) -- Workers: 5 Gunicorn workers - -## 🔧 Common Operations - -### View Logs -```bash -# Application logs -docker-compose logs -f web - -# Database logs -docker-compose logs -f db - -# All logs -docker-compose logs -f -``` - -### Restart Services -```bash -# Restart all -docker-compose restart - -# Restart specific service -docker-compose restart web -docker-compose restart db -``` - -### Stop Services -```bash -# Stop (keeps data) -docker-compose down - -# Stop and remove volumes (WARNING: deletes database!) -docker-compose down -v -``` - -### Update Application Code - -**Without rebuilding (development mode):** -1. Uncomment volume mapping in docker-compose.yml: - ```yaml - - ${APP_CODE_PATH}:/app:ro - ``` -2. Edit code in `./py_app/` -3. Restart: `docker-compose restart web` - -**With rebuilding (production mode):** -```bash -docker-compose build --no-cache web -docker-compose up -d -``` - -### Database Access - -**MySQL shell inside container:** -```bash -docker-compose exec db mysql -u trasabilitate -p -# Enter password: Initial01! (or your custom password) -``` - -**From host machine:** -```bash -mysql -h 127.0.0.1 -P 3306 -u trasabilitate -p -``` - -**Root access:** -```bash -docker-compose exec db mysql -u root -p -``` - -## 💾 Backup Operations - -### Manual Backup -```bash -# Full backup -docker-compose exec db mysqldump -u trasabilitate -pInitial01! trasabilitate > backups/manual_$(date +%Y%m%d_%H%M%S).sql - -# Data-only backup -docker-compose exec db mysqldump -u trasabilitate -pInitial01! --no-create-info trasabilitate > backups/data_only_$(date +%Y%m%d_%H%M%S).sql - -# Structure-only backup -docker-compose exec db mysqldump -u trasabilitate -pInitial01! --no-data trasabilitate > backups/structure_only_$(date +%Y%m%d_%H%M%S).sql -``` - -### Automated Backups -The application includes a built-in scheduler for automated backups. Configure via the web interface. - -### Restore from Backup -```bash -# Stop application (keeps database running) -docker-compose stop web - -# Restore database -docker-compose exec -T db mysql -u trasabilitate -pInitial01! trasabilitate < backups/backup_file.sql - -# Start application -docker-compose start web -``` - -## 🔍 Troubleshooting - -### Container won't start -```bash -# Check logs -docker-compose logs db -docker-compose logs web - -# Check if ports are available -ss -tulpn | grep 8781 -ss -tulpn | grep 3306 -``` - -### Database connection failed -```bash -# Check database is healthy -docker-compose ps - -# Test database connection -docker-compose exec db mysqladmin ping -u root -p - -# Check database users -docker-compose exec db mysql -u root -p -e "SELECT User, Host FROM mysql.user;" -``` - -### Permission issues -```bash -# Check directory permissions -ls -la data/mariadb -ls -la logs -ls -la backups - -# Fix permissions if needed -chmod -R 755 data logs backups config -``` - -### Reset everything (WARNING: deletes all data!) -```bash -# Stop and remove containers, volumes -docker-compose down -v - -# Remove volume directories -rm -rf data/mariadb/* logs/* config/instance/* - -# Start fresh -bash quick-deploy.sh -``` - -## 🔒 Security Notes - -1. **Change default passwords** in .env file -2. **Generate new SECRET_KEY** for Flask -3. Never commit .env file to version control -4. Use firewall rules to restrict database port (3306) access -5. Consider using Docker secrets for sensitive data in production -6. Regular security updates: `docker-compose pull && docker-compose up -d` - -## 🌐 Port Mapping - -- **8781** - Web application (configurable via APP_PORT in .env) -- **3306** - MariaDB database (configurable via DB_PORT in .env) - -## 📁 Configuration Files - -- **docker-compose.yml** - Service orchestration -- **.env** - Environment variables and configuration -- **Dockerfile** - Web application image definition -- **docker-entrypoint.sh** - Container initialization script -- **init-db.sql** - Database initialization script - -## 🎯 Production Checklist - -- [ ] Change all default passwords -- [ ] Generate secure SECRET_KEY -- [ ] Set FLASK_ENV=production -- [ ] Configure resource limits appropriately -- [ ] Set up backup schedule -- [ ] Configure firewall rules -- [ ] Set up monitoring and logging -- [ ] Test backup/restore procedures -- [ ] Document deployment procedure for your team -- [ ] Set INIT_DB=false and SEED_DB=false after first deployment - -## 📞 Support - -For issues or questions, refer to: -- Documentation in `documentation/` folder -- Docker logs: `docker-compose logs -f` -- Application logs: `./logs/` directory diff --git a/old code/DOCKER_SOLUTION_SUMMARY.md b/old code/DOCKER_SOLUTION_SUMMARY.md deleted file mode 100644 index 0ad64ad..0000000 --- a/old code/DOCKER_SOLUTION_SUMMARY.md +++ /dev/null @@ -1,346 +0,0 @@ -# Recticel Quality Application - Docker Solution Summary - -## 📦 What Has Been Created - -A complete, production-ready Docker deployment solution for your Recticel Quality Application with the following components: - -### Core Files Created - -1. **`Dockerfile`** - Multi-stage Flask application container - - Based on Python 3.10-slim - - Installs all dependencies from requirements.txt - - Configures Gunicorn WSGI server - - Exposes port 8781 - -2. **`docker-compose.yml`** - Complete orchestration configuration - - MariaDB 11.3 database service - - Flask web application service - - Automatic networking between services - - Health checks for both services - - Volume persistence for database and logs - -3. **`docker-entrypoint.sh`** - Smart initialization script - - Waits for database to be ready - - Creates database configuration file - - Runs database schema initialization - - Seeds superadmin user - - Starts the application - -4. **`init-db.sql`** - MariaDB initialization - - Creates database and user - - Sets up permissions automatically - -5. **`.env.example`** - Configuration template - - Database passwords - - Port configurations - - Initialization flags - -6. **`.dockerignore`** - Build optimization - - Excludes unnecessary files from Docker image - - Reduces image size - -7. **`deploy.sh`** - One-command deployment script - - Checks prerequisites - - Creates configuration - - Builds and starts services - - Shows deployment status - -8. **`Makefile`** - Convenient management commands - - `make install` - First-time installation - - `make up` - Start services - - `make down` - Stop services - - `make logs` - View logs - - `make shell` - Access container - - `make backup-db` - Backup database - - And many more... - -9. **`DOCKER_DEPLOYMENT.md`** - Complete documentation - - Quick start guide - - Management commands - - Troubleshooting - - Security considerations - - Architecture diagrams - -### Enhanced Files - -10. **`setup_complete_database.py`** - Updated to support Docker - - Now reads from environment variables - - Fallback to config file for non-Docker deployments - - Maintains backward compatibility - -## 🎯 Key Features - -### 1. Single-Command Deployment -```bash -./deploy.sh -``` -This single command will: -- ✅ Build Docker images -- ✅ Create MariaDB database -- ✅ Initialize all database tables and triggers -- ✅ Seed superadmin user -- ✅ Start the application - -### 2. Complete Isolation -- Application runs in its own container -- Database runs in its own container -- No system dependencies needed except Docker -- No Python/MariaDB installation on host required - -### 3. Data Persistence -- Database data persists across restarts (Docker volume) -- Application logs accessible on host -- Configuration preserved - -### 4. Production Ready -- Gunicorn WSGI server (not Flask dev server) -- Health checks for monitoring -- Automatic restart on failure -- Proper logging configuration -- Resource isolation - -### 5. Easy Management -```bash -# Start -docker compose up -d - -# Stop -docker compose down - -# View logs -docker compose logs -f - -# Backup database -make backup-db - -# Restore database -make restore-db BACKUP=backup_20231215.sql - -# Access shell -make shell - -# Complete reset -make reset -``` - -## 🚀 Deployment Options - -### Option 1: Quick Deploy (Recommended for Testing) -```bash -cd /srv/quality_recticel -./deploy.sh -``` - -### Option 2: Using Makefile (Recommended for Management) -```bash -cd /srv/quality_recticel -make install # First time only -make up # Start services -make logs # Monitor -``` - -### Option 3: Using Docker Compose Directly -```bash -cd /srv/quality_recticel -cp .env.example .env -docker compose up -d --build -``` - -## 📋 Prerequisites - -The deployment **requires** Docker to be installed on the target system: - -### Installing Docker on Ubuntu/Debian: -```bash -# Update package index -sudo apt-get update - -# Install dependencies -sudo apt-get install -y ca-certificates curl gnupg - -# Add Docker's official GPG key -sudo install -m 0755 -d /etc/apt/keyrings -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg -sudo chmod a+r /etc/apt/keyrings/docker.gpg - -# Set up the repository -echo \ - "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ - $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ - sudo tee /etc/apt/sources.list.d/docker.list > /dev/null - -# Install Docker Engine -sudo apt-get update -sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin - -# Add current user to docker group (optional, to run without sudo) -sudo usermod -aG docker $USER -``` - -After installation, log out and back in for group changes to take effect. - -### Installing Docker on CentOS/RHEL: -```bash -sudo yum install -y yum-utils -sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo -sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -sudo systemctl start docker -sudo systemctl enable docker -sudo usermod -aG docker $USER -``` - -## 🏗️ Architecture - -``` -┌──────────────────────────────────────────────────────┐ -│ Docker Compose Stack │ -│ │ -│ ┌────────────────────┐ ┌───────────────────┐ │ -│ │ MariaDB 11.3 │ │ Flask App │ │ -│ │ Container │◄─────┤ Container │ │ -│ │ │ │ │ │ -│ │ - Port: 3306 │ │ - Port: 8781 │ │ -│ │ - Volume: DB Data │ │ - Gunicorn WSGI │ │ -│ │ - Auto Init │ │ - Python 3.10 │ │ -│ │ - Health Checks │ │ - Health Checks │ │ -│ └──────────┬─────────┘ └─────────┬─────────┘ │ -│ │ │ │ -└─────────────┼──────────────────────────┼─────────────┘ - │ │ - ▼ ▼ - [mariadb_data] [logs directory] - Docker Volume Host filesystem -``` - -## 🔐 Security Features - -1. **Database Isolation**: Database not exposed to host by default (can be configured) -2. **Password Management**: All passwords in `.env` file (not committed to git) -3. **User Permissions**: Proper MariaDB user with limited privileges -4. **Network Isolation**: Services communicate on private Docker network -5. **Production Mode**: Flask runs in production mode with Gunicorn - -## 📊 What Gets Deployed - -### Database Schema -All tables from `setup_complete_database.py`: -- `scan1_orders` - First scan orders -- `scanfg_orders` - Final goods scan orders -- `order_for_labels` - Label orders -- `warehouse_locations` - Warehouse locations -- `permissions` - Permission system -- `role_permissions` - Role-based access -- `role_hierarchy` - Role hierarchy -- `permission_audit_log` - Audit logging -- Plus SQLAlchemy tables: `users`, `roles` - -### Initial Data -- Superadmin user: `superadmin` / `superadmin123` - -### Application Features -- Complete Flask web application -- Gunicorn WSGI server (4-8 workers depending on CPU) -- Static file serving -- Session management -- Database connection pooling - -## 🔄 Migration from Existing Deployment - -If you have an existing non-Docker deployment: - -### 1. Backup Current Data -```bash -# Backup database -mysqldump -u trasabilitate -p trasabilitate > backup.sql - -# Backup any uploaded files or custom data -cp -r py_app/instance backup_instance/ -``` - -### 2. Deploy Docker Solution -```bash -cd /srv/quality_recticel -./deploy.sh -``` - -### 3. Restore Data (if needed) -```bash -# Restore database -docker compose exec -T db mariadb -u trasabilitate -pInitial01! trasabilitate < backup.sql -``` - -### 4. Stop Old Service -```bash -# Stop systemd service -sudo systemctl stop trasabilitate -sudo systemctl disable trasabilitate -``` - -## 🎓 Learning Resources - -- Docker Compose docs: https://docs.docker.com/compose/ -- Gunicorn configuration: https://docs.gunicorn.org/ -- MariaDB Docker: https://hub.docker.com/_/mariadb - -## ✅ Testing Checklist - -After deployment, verify: - -- [ ] Services are running: `docker compose ps` -- [ ] App is accessible: http://localhost:8781 -- [ ] Can log in with superadmin -- [ ] Database contains tables: `make shell-db` then `SHOW TABLES;` -- [ ] Logs are being written: `ls -la logs/` -- [ ] Can restart services: `docker compose restart` -- [ ] Data persists after restart - -## 🆘 Support Commands - -```bash -# View all services -docker compose ps - -# View logs -docker compose logs -f - -# Restart a specific service -docker compose restart web - -# Access web container shell -docker compose exec web bash - -# Access database -docker compose exec db mariadb -u trasabilitate -p - -# Check resource usage -docker stats - -# Remove everything and start fresh -docker compose down -v -./deploy.sh -``` - -## 📝 Next Steps - -1. **Install Docker** on the target server (if not already installed) -2. **Review and customize** `.env` file after copying from `.env.example` -3. **Run deployment**: `./deploy.sh` -4. **Change default passwords** after first login -5. **Set up reverse proxy** (nginx/traefik) for HTTPS if needed -6. **Configure backups** using `make backup-db` -7. **Monitor logs** regularly with `make logs` - -## 🎉 Benefits of This Solution - -1. **Portable**: Works on any system with Docker -2. **Reproducible**: Same deployment every time -3. **Isolated**: No conflicts with system packages -4. **Easy Updates**: Just rebuild and restart -5. **Scalable**: Can easily add more services -6. **Professional**: Production-ready configuration -7. **Documented**: Complete documentation included -8. **Maintainable**: Simple management commands - ---- - -**Your Flask application is now ready for modern, containerized deployment! 🚀** diff --git a/old code/EXCEL_UPLOAD_MAPPING.md b/old code/EXCEL_UPLOAD_MAPPING.md deleted file mode 100644 index 2b7251f..0000000 --- a/old code/EXCEL_UPLOAD_MAPPING.md +++ /dev/null @@ -1,146 +0,0 @@ -# Excel File Upload Mapping - -## File Information -- **File**: `1cc01b8Comenzi Productie (19).xlsx` -- **Sheets**: DataSheet (corrupted), Sheet1 (249 rows × 29 columns) -- **Purpose**: Production orders for label generation - -## Excel Columns (29 total) - -### Core Order Fields (✅ Stored in Database) -1. **Comanda Productie** → `comanda_productie` ✅ -2. **Cod Articol** → `cod_articol` ✅ -3. **Descriere** → `descr_com_prod` ✅ -4. **Cantitate ceruta** → `cantitate` ✅ -5. **Delivery date** → `data_livrare` ✅ -6. **Customer** → `customer_name` ✅ -7. **Comanda client** → `com_achiz_client` ✅ - -### Additional Fields (📊 Read but not stored in order_for_labels table) -8. **Status** → `status` 📊 -9. **End of Quilting** → `end_of_quilting` 📊 -10. **End of sewing** → `end_of_sewing` 📊 -11. **T1** → `t1` 📊 (Quality control stage 1) -12. **Data inregistrare T1** → `data_inregistrare_t1` 📊 -13. **Numele Complet T1** → `numele_complet_t1` 📊 -14. **T2** → `t2` 📊 (Quality control stage 2) -15. **Data inregistrare T2** → `data_inregistrare_t2` 📊 -16. **Numele Complet T2** → `numele_complet_t2` 📊 -17. **T3** → `t3` 📊 (Quality control stage 3) -18. **Data inregistrare T3** → `data_inregistrare_t3` 📊 -19. **Numele Complet T3** → `numele_complet_t3` 📊 -20. **Clasificare** → `clasificare` 📊 -21. **Masina Cusut** → `masina_cusut` 📊 -22. **Tip Masina** → `tip_masina` 📊 -23. **Timp normat total** → `timp_normat_total` 📊 -24. **Data Deschiderii** → `data_deschiderii` 📊 -25. **Model Lb2** → `model_lb2` 📊 -26. **Data Planific.** → `data_planific` 📊 -27. **Numar masina** → `numar_masina` 📊 -28. **Design nr** → `design_nr` 📊 -29. **Needle position** → `needle_position` 📊 - -## Database Schema (order_for_labels) - -```sql -CREATE TABLE order_for_labels ( - id INT AUTO_INCREMENT PRIMARY KEY, - comanda_productie VARCHAR(25) NOT NULL, - cod_articol VARCHAR(25) NOT NULL, - descr_com_prod VARCHAR(100), - cantitate INT, - data_livrare DATE, - dimensiune VARCHAR(25), - com_achiz_client VARCHAR(25), - nr_linie_com_client INT, - customer_name VARCHAR(50), - customer_article_number VARCHAR(25), - open_for_order VARCHAR(25), - line_number INT, - printed_labels INT DEFAULT 0 -); -``` - -## Validation Rules - -### Required Fields -- ✅ `comanda_productie` (Production Order #) -- ✅ `cod_articol` (Article Code) -- ✅ `descr_com_prod` (Description) -- ✅ `cantitate` (Quantity) - -### Optional Fields -- `data_livrare` (Delivery Date) -- `dimensiune` (Dimension) -- `com_achiz_client` (Customer Order #) -- `nr_linie_com_client` (Customer Order Line) -- `customer_name` (Customer Name) -- `customer_article_number` (Customer Article #) -- `open_for_order` (Open for Order) -- `line_number` (Line Number) - -## Processing Logic - -1. **Sheet Selection**: Tries Sheet1 → sheet 0 → DataSheet -2. **Column Normalization**: Converts to lowercase, strips whitespace -3. **Column Mapping**: Maps Excel columns to database fields -4. **Row Processing**: - - Skips empty rows - - Handles NaN values (converts to empty string) - - Validates required fields - - Returns validation errors and warnings -5. **Data Storage**: Only valid rows with required fields are stored - -## Sample Data (Row 1) - -``` -comanda_productie : CP00267043 -cod_articol : PF010147 -descr_com_prod : HUSA STARLINE NEXT X7 90X210 -cantitate : 1 -data_livrare : 2024-03-12 -customer_name : 411_01RECT BED -com_achiz_client : 379579-1 -status : Inchis -classificare : HP3D -masina_cusut : SPECIALA -``` - -## Upload Functionality - -**URL**: `/upload_data` (Labels module) - -**Supported Formats**: -- CSV (.csv) -- Excel (.xlsx, .xls) - -**Process**: -1. User uploads file -2. System validates file type -3. Processes file (CSV or Excel) -4. Shows preview with validation -5. User confirms upload -6. Data inserted into database - -## Testing - -```bash -# Test Excel reading -cd /srv/quality_app -python3 << 'EOF' -import pandas as pd -df = pd.read_excel("1cc01b8Comenzi Productie (19).xlsx", sheet_name='Sheet1') -print(f"✅ Read {len(df)} rows × {len(df.columns)} columns") -print(f"Required fields present: {all(col in df.columns for col in ['Comanda Productie', 'Cod Articol', 'Descriere', 'Cantitate ceruta'])}") -EOF -``` - -## Implementation Files - -- `/srv/quality_app/py_app/app/order_labels.py` - Processing functions -- `/srv/quality_app/py_app/app/routes.py` - Upload route handler -- `/srv/quality_app/py_app/app/templates/upload_orders.html` - Upload UI - ---- -**Status**: ✅ All 29 columns readable and mapped correctly -**Date**: 2024-11-26 diff --git a/old code/FILES_CREATED.md b/old code/FILES_CREATED.md deleted file mode 100644 index 76fd899..0000000 --- a/old code/FILES_CREATED.md +++ /dev/null @@ -1,280 +0,0 @@ -# ✅ Docker Solution - Files Created - -## 📦 Complete Docker Deployment Package - -Your Flask application has been packaged into a complete Docker solution. Here's everything that was created: - -### Core Docker Files - -``` -/srv/quality_recticel/ -├── Dockerfile # Flask app container definition -├── docker-compose.yml # Multi-container orchestration -├── docker-entrypoint.sh # Container initialization script -├── init-db.sql # MariaDB initialization -├── .dockerignore # Build optimization -└── .env.example # Configuration template -``` - -### Deployment & Management - -``` -├── deploy.sh # One-command deployment script -├── Makefile # Management commands (make up, make down, etc.) -├── README-DOCKER.md # Quick start guide -├── DOCKER_DEPLOYMENT.md # Complete deployment documentation -└── DOCKER_SOLUTION_SUMMARY.md # This comprehensive summary -``` - -### Modified Files - -``` -py_app/app/db_create_scripts/ -└── setup_complete_database.py # Updated to support Docker env vars -``` - -## 🎯 What This Deployment Includes - -### Services -1. **Flask Web Application** - - Python 3.10 - - Gunicorn WSGI server (production-ready) - - Auto-generated database configuration - - Health checks - - Automatic restart on failure - -2. **MariaDB 11.3 Database** - - Automatic initialization - - User and database creation - - Data persistence (Docker volume) - - Health checks - -### Features -- ✅ Single-command deployment -- ✅ Automatic database schema setup -- ✅ Superadmin user seeding -- ✅ Data persistence across restarts -- ✅ Container health monitoring -- ✅ Log collection and management -- ✅ Production-ready configuration -- ✅ Easy backup and restore -- ✅ Complete isolation from host system - -## 🚀 How to Deploy - -### Prerequisites -**Install Docker first:** -```bash -# Ubuntu/Debian -curl -fsSL https://get.docker.com -o get-docker.sh -sudo sh get-docker.sh -sudo usermod -aG docker $USER -# Log out and back in -``` - -### Deploy -```bash -cd /srv/quality_recticel -./deploy.sh -``` - -That's it! Your application will be available at http://localhost:8781 - -## 📋 Usage Examples - -### Basic Operations -```bash -# Start services -docker compose up -d - -# View logs -docker compose logs -f - -# Stop services -docker compose down - -# Restart -docker compose restart - -# Check status -docker compose ps -``` - -### Using Makefile (Recommended) -```bash -make install # First-time setup -make up # Start services -make down # Stop services -make logs # View logs -make logs-web # View only web logs -make logs-db # View only database logs -make shell # Access app container -make shell-db # Access database console -make backup-db # Backup database -make status # Show service status -make help # Show all commands -``` - -### Advanced Operations -```bash -# Rebuild after code changes -docker compose up -d --build web - -# Access application shell -docker compose exec web bash - -# Run database commands -docker compose exec db mariadb -u trasabilitate -p trasabilitate - -# View resource usage -docker stats recticel-app recticel-db - -# Complete reset (removes all data!) -docker compose down -v -``` - -## 🗂️ Data Storage - -### Persistent Data -- **Database**: Stored in Docker volume `mariadb_data` -- **Logs**: Mounted to `./logs` directory -- **Config**: Mounted to `./instance` directory - -### Backup Database -```bash -docker compose exec -T db mariadb-dump -u trasabilitate -pInitial01! trasabilitate > backup.sql -``` - -### Restore Database -```bash -docker compose exec -T db mariadb -u trasabilitate -pInitial01! trasabilitate < backup.sql -``` - -## 🔐 Default Credentials - -### Application -- URL: http://localhost:8781 -- Username: `superadmin` -- Password: `superadmin123` -- **⚠️ Change after first login!** - -### Database -- Host: `localhost:3306` (from host) or `db:3306` (from containers) -- Database: `trasabilitate` -- User: `trasabilitate` -- Password: `Initial01!` -- Root Password: Set in `.env` file - -## 📊 Service Architecture - -``` -┌─────────────────────────────────────────────────────┐ -│ recticel-network (Docker) │ -│ │ -│ ┌─────────────────┐ ┌─────────────────┐ │ -│ │ recticel-db │ │ recticel-app │ │ -│ │ (MariaDB 11.3) │◄───────┤ (Flask/Python) │ │ -│ │ │ │ │ │ -│ │ - Internal DB │ │ - Gunicorn │ │ -│ │ - Health Check │ │ - Health Check │ │ -│ │ - Auto Init │ │ - Auto Config │ │ -│ └────────┬────────┘ └────────┬────────┘ │ -│ │ │ │ -│ │ 3306 (optional) 8781 │ │ -└────────────┼──────────────────────────┼────────────┘ - │ │ - ▼ ▼ - [mariadb_data] [Host: 8781] - Docker Volume Application Access -``` - -## 🎓 Quick Reference - -### Environment Variables (.env) -```env -MYSQL_ROOT_PASSWORD=rootpassword # MariaDB root password -DB_PORT=3306 # Database port (external) -APP_PORT=8781 # Application port -INIT_DB=true # Run DB initialization -SEED_DB=true # Seed superadmin user -``` - -### Important Ports -- `8781`: Flask application (web interface) -- `3306`: MariaDB database (optional external access) - -### Log Locations -- Application logs: `./logs/access.log` and `./logs/error.log` -- Container logs: `docker compose logs` - -## 🔧 Troubleshooting - -### Can't connect to application -```bash -# Check if services are running -docker compose ps - -# Check web logs -docker compose logs web - -# Verify port not in use -netstat -tuln | grep 8781 -``` - -### Database connection issues -```bash -# Check database health -docker compose exec db healthcheck.sh --connect - -# View database logs -docker compose logs db - -# Test database connection -docker compose exec web python3 -c "import mariadb; print('OK')" -``` - -### Port already in use -Edit `.env` file: -```env -APP_PORT=8782 # Change to available port -DB_PORT=3307 # Change if needed -``` - -### Start completely fresh -```bash -docker compose down -v -rm -rf logs/* instance/external_server.conf -./deploy.sh -``` - -## 📖 Documentation Files - -1. **README-DOCKER.md** - Quick start guide (start here!) -2. **DOCKER_DEPLOYMENT.md** - Complete deployment guide -3. **DOCKER_SOLUTION_SUMMARY.md** - Comprehensive overview -4. **FILES_CREATED.md** - This file - -## ✨ Benefits - -- **No System Dependencies**: Only Docker required -- **Portable**: Deploy on any system with Docker -- **Reproducible**: Consistent deployments every time -- **Isolated**: No conflicts with other applications -- **Production-Ready**: Gunicorn, health checks, proper logging -- **Easy Management**: Simple commands, one-line deployment -- **Persistent**: Data survives container restarts -- **Scalable**: Easy to add more services - -## 🎉 Success! - -Your Recticel Quality Application is now containerized and ready for deployment! - -**Next Steps:** -1. Install Docker (if not already installed) -2. Run `./deploy.sh` -3. Access http://localhost:8781 -4. Log in with superadmin credentials -5. Change default passwords -6. Enjoy your containerized application! - -For detailed instructions, see **README-DOCKER.md** or **DOCKER_DEPLOYMENT.md**. diff --git a/old code/IMPROVEMENTS_APPLIED.md b/old code/IMPROVEMENTS_APPLIED.md deleted file mode 100644 index c55b8a7..0000000 --- a/old code/IMPROVEMENTS_APPLIED.md +++ /dev/null @@ -1,123 +0,0 @@ -# Improvements Applied to Quality App - -## Date: November 13, 2025 - -### Overview -All improvements from the production environment have been successfully transposed to the quality_app project. - -## Files Updated/Copied - -### 1. Docker Configuration -- **Dockerfile** - Added `mariadb-client` package for backup functionality -- **docker-compose.yml** - Updated with proper volume mappings and /data folder support -- **.env** - Updated all paths to use absolute paths under `/srv/quality_app/` - -### 2. Backup & Restore System -- **database_backup.py** - Fixed backup/restore functions: - - Changed `result_success` to `result.returncode == 0` - - Added `--skip-ssl` flag for MariaDB connections - - Fixed restore function error handling -- **restore_database.sh** - Fixed SQL file parsing to handle MariaDB dump format - -### 3. UI Improvements - Sticky Table Headers -- **base.css** - Added sticky header CSS for all report tables -- **scan.html** - Wrapped table in `report-table-container` div -- **fg_scan.html** - Wrapped table in `report-table-container` div - -### 4. Quality Code Display Enhancement -- **fg_quality.js** - Quality code `0` displays as "OK" in green; CSV exports as "0" -- **script.js** - Same improvements for quality module reports - -## Directory Structure - -``` -/srv/quality_app/ -├── py_app/ # Application code (mapped to /app in container) -├── data/ -│ └── mariadb/ # Database files -├── config/ -│ └── instance/ # Application configuration -├── logs/ # Application logs -├── backups/ # Database backups -├── docker-compose.yml -├── Dockerfile -├── .env -└── restore_database.sh -``` - -## Environment Configuration - -### Volume Mappings in .env: -``` -DB_DATA_PATH=/srv/quality_app/data/mariadb -APP_CODE_PATH=/srv/quality_app/py_app -LOGS_PATH=/srv/quality_app/logs -INSTANCE_PATH=/srv/quality_app/config/instance -BACKUP_PATH=/srv/quality_app/backups -``` - -## Features Implemented - -### ✅ Backup System -- Automatic scheduled backups -- Manual backup creation -- Data-only backups -- Backup retention policies -- MariaDB client tools installed - -### ✅ Restore System -- Python-based restore function -- Shell script restore with proper SQL parsing -- Handles MariaDB dump format correctly - -### ✅ UI Enhancements -- **Sticky Headers**: Table headers remain fixed when scrolling -- **Quality Code Display**: - - Shows "OK" in green for quality code 0 - - Exports "0" in CSV files - - Better user experience - -### ✅ Volume Mapping -- All volumes use absolute paths -- Support for /data folder mapping -- Easy to configure backup location on different drives - -## Starting the Application - -```bash -cd /srv/quality_app -docker compose up -d --build -``` - -## Testing Backup & Restore - -### Create Backup: -```bash -cd /srv/quality_app -docker compose exec web bash -c "cd /app && python3 -c 'from app import create_app; from app.database_backup import DatabaseBackupManager; app = create_app(); -with app.app_context(): bm = DatabaseBackupManager(); result = bm.create_backup(); print(result)'" -``` - -### Restore Backup: -```bash -cd /srv/quality_app -./restore_database.sh /srv/quality_app/backups/backup_file.sql -``` - -## Notes - -- Database initialization is set to `false` (already initialized) -- All improvements are production-ready -- Backup path can be changed to external drive if needed -- Application port: 8781 (default) - -## Next Steps - -1. Review .env file and update passwords if needed -2. Test all functionality after deployment -3. Configure backup schedule if needed -4. Set up external backup drive if desired - ---- -**Compatibility**: All changes are backward compatible with existing data. -**Status**: Ready for deployment diff --git a/old code/MERGE_COMPATIBILITY.md b/old code/MERGE_COMPATIBILITY.md deleted file mode 100644 index 1b7790d..0000000 --- a/old code/MERGE_COMPATIBILITY.md +++ /dev/null @@ -1,292 +0,0 @@ -# Merge Compatibility Analysis: docker-deploy → master - -## 📊 Merge Status: **SAFE TO MERGE** ✅ - -### Conflict Analysis -- **No merge conflicts detected** between `master` and `docker-deploy` branches -- All changes are additive or modify existing code in compatible ways -- The docker-deploy branch adds 13 files with 1034 insertions and 117 deletions - -### Files Changed -#### New Files (No conflicts): -1. `DOCKER_DEPLOYMENT_GUIDE.md` - Documentation -2. `IMPROVEMENTS_APPLIED.md` - Documentation -3. `quick-deploy.sh` - Deployment script -4. `restore_database.sh` - Restore script -5. `setup-volumes.sh` - Setup script - -#### Modified Files: -1. `Dockerfile` - Added mariadb-client package -2. `docker-compose.yml` - Added /data volume mapping, resource limits -3. `py_app/app/database_backup.py` - **CRITICAL: Compatibility layer added** -4. `py_app/app/static/css/base.css` - Added sticky header styles -5. `py_app/app/static/fg_quality.js` - Quality code display enhancement -6. `py_app/app/static/script.js` - Quality code display enhancement -7. `py_app/app/templates/fg_scan.html` - Added report-table-container wrapper -8. `py_app/app/templates/scan.html` - Added report-table-container wrapper - ---- - -## 🔧 Compatibility Layer: database_backup.py - -### Problem Identified -The docker-deploy branch changed backup commands from `mysqldump` to `mariadb-dump` and added `--skip-ssl` flag, which would break the application when running with standard Gunicorn (non-Docker) deployment. - -### Solution Implemented -Added intelligent environment detection and command selection: - -#### 1. Dynamic Command Detection -```python -def _detect_dump_command(self): - """Detect which mysqldump command is available (mariadb-dump or mysqldump)""" - try: - # Try mariadb-dump first (newer MariaDB versions) - result = subprocess.run(['which', 'mariadb-dump'], - capture_output=True, text=True) - if result.returncode == 0: - return 'mariadb-dump' - - # Fall back to mysqldump - result = subprocess.run(['which', 'mysqldump'], - capture_output=True, text=True) - if result.returncode == 0: - return 'mysqldump' - - # Default to mariadb-dump (will error if not available) - return 'mariadb-dump' - except Exception as e: - print(f"Warning: Could not detect dump command: {e}") - return 'mysqldump' # Default fallback -``` - -#### 2. Conditional SSL Arguments -```python -def _get_ssl_args(self): - """Get SSL arguments based on environment (Docker needs --skip-ssl)""" - # Check if running in Docker container - if os.path.exists('/.dockerenv') or os.environ.get('DOCKER_CONTAINER'): - return ['--skip-ssl'] - return [] -``` - -#### 3. Updated Backup Command Building -```python -cmd = [ - self.dump_command, # Uses detected command (mariadb-dump or mysqldump) - f"--host={self.config['host']}", - f"--port={self.config['port']}", - f"--user={self.config['user']}", - f"--password={self.config['password']}", -] - -# Add SSL args if needed (Docker environment) -cmd.extend(self._get_ssl_args()) - -# Add backup options -cmd.extend([ - '--single-transaction', - '--skip-lock-tables', - '--force', - # ... other options -]) -``` - ---- - -## 🎯 Deployment Scenarios - -### Scenario 1: Docker Deployment (docker-compose) -**Environment Detection:** -- ✅ `/.dockerenv` file exists -- ✅ `DOCKER_CONTAINER` environment variable set in docker-compose.yml - -**Backup Behavior:** -- Uses `mariadb-dump` (installed in Dockerfile) -- Adds `--skip-ssl` flag automatically -- Works correctly ✅ - -### Scenario 2: Standard Gunicorn Deployment (systemd service) -**Environment Detection:** -- ❌ `/.dockerenv` file does NOT exist -- ❌ `DOCKER_CONTAINER` environment variable NOT set - -**Backup Behavior:** -- Detects available command: `mysqldump` or `mariadb-dump` -- Does NOT add `--skip-ssl` flag -- Uses system-installed MySQL/MariaDB client tools -- Works correctly ✅ - -### Scenario 3: Mixed Environment (External Database) -**Both deployment types can connect to:** -- External MariaDB server -- Remote database instance -- Local database with proper SSL configuration - -**Backup Behavior:** -- Automatically adapts to available tools -- SSL handling based on container detection -- Works correctly ✅ - ---- - -## 🧪 Testing Plan - -### Pre-Merge Testing -1. **Docker Environment:** - ```bash - cd /srv/quality_app - git checkout docker-deploy - docker-compose up -d - # Test backup via web UI - # Test scheduled backup - # Test restore functionality - ``` - -2. **Gunicorn Environment:** - ```bash - # Stop Docker if running - docker-compose down - - # Start with systemd service (if available) - sudo systemctl start trasabilitate - - # Test backup via web UI - # Test scheduled backup - # Test restore functionality - ``` - -3. **Command Detection Test:** - ```bash - # Inside Docker container - docker-compose exec web python3 -c " - from app.database_backup import DatabaseBackupManager - manager = DatabaseBackupManager() - print(f'Dump command: {manager.dump_command}') - print(f'SSL args: {manager._get_ssl_args()}') - " - - # On host system (if MySQL client installed) - python3 -c " - from app.database_backup import DatabaseBackupManager - manager = DatabaseBackupManager() - print(f'Dump command: {manager.dump_command}') - print(f'SSL args: {manager._get_ssl_args()}') - " - ``` - -### Post-Merge Testing -1. Verify both deployment methods still work -2. Test backup/restore in both environments -3. Verify scheduled backups function correctly -4. Check error handling when tools are missing - ---- - -## 📋 Merge Checklist - -- [x] No merge conflicts detected -- [x] Compatibility layer implemented in `database_backup.py` -- [x] Environment detection for Docker vs Gunicorn -- [x] Dynamic command selection (mariadb-dump vs mysqldump) -- [x] Conditional SSL flag handling -- [x] UI improvements (sticky headers) are purely CSS/JS - no conflicts -- [x] Quality code display changes are frontend-only - no conflicts -- [x] New documentation files added - no conflicts -- [x] Docker-specific files don't affect Gunicorn deployment - -### Safe to Merge Because: -1. **Additive Changes**: Most changes are new files or new features -2. **Backward Compatible**: Code detects environment and adapts -3. **No Breaking Changes**: Gunicorn deployment still works without Docker -4. **Independent Features**: UI improvements work in any environment -5. **Fail-Safe Defaults**: Falls back to mysqldump if mariadb-dump unavailable - ---- - -## 🚀 Merge Process - -### Recommended Steps: -```bash -cd /srv/quality_app - -# 1. Ensure working directory is clean -git status - -# 2. Switch to master branch -git checkout master - -# 3. Pull latest changes -git pull origin master - -# 4. Merge docker-deploy (should be clean merge) -git merge docker-deploy - -# 5. Review merge -git log --oneline -10 - -# 6. Test in current environment -# (If using systemd, test the app) -# (If using Docker, test with docker-compose) - -# 7. Push to remote -git push origin master - -# 8. Tag the release (optional) -git tag -a v2.0-docker -m "Docker deployment support with compatibility layer" -git push origin v2.0-docker -``` - -### Rollback Plan (if needed): -```bash -# If issues arise after merge -git log --oneline -10 # Find commit hash before merge -git reset --hard -git push origin master --force # Use with caution! - -# Or revert the merge commit -git revert -m 1 -git push origin master -``` - ---- - -## 🎓 Key Improvements in docker-deploy Branch - -### 1. **Bug Fixes** -- Fixed `result_success` variable error → `result.returncode == 0` -- Fixed restore SQL parsing with sed preprocessing -- Fixed missing mariadb-client in Docker container - -### 2. **Docker Support** -- Complete Docker Compose setup -- Volume mapping for persistent data -- Health checks and resource limits -- Environment-based configuration - -### 3. **UI Enhancements** -- Sticky table headers for scrollable reports -- Quality code 0 displays as "OK" (green) -- CSV export preserves original "0" value - -### 4. **Compatibility** -- Works in Docker AND traditional Gunicorn deployment -- Auto-detects available backup tools -- Environment-aware SSL handling -- No breaking changes to existing functionality - ---- - -## 📞 Support - -If issues arise after merge: -1. Check environment detection: `ls -la /.dockerenv` -2. Verify backup tools: `which mysqldump mariadb-dump` -3. Review logs: `docker-compose logs web` or application logs -4. Test backup manually from command line -5. Fall back to master branch if critical issues occur - ---- - -**Last Updated:** 2025-11-13 -**Branch:** docker-deploy → master -**Status:** Ready for merge ✅ diff --git a/old code/Open .Orders WIZ New.xlsb b/old code/Open .Orders WIZ New.xlsb deleted file mode 100644 index 766c994..0000000 Binary files a/old code/Open .Orders WIZ New.xlsb and /dev/null differ diff --git a/old code/README-DOCKER.md b/old code/README-DOCKER.md deleted file mode 100644 index 1029e2e..0000000 --- a/old code/README-DOCKER.md +++ /dev/null @@ -1,73 +0,0 @@ -# 🚀 Quick Start - Docker Deployment - -## What You Need -- A server with Docker installed -- 2GB free disk space -- Ports 8781 and 3306 available - -## Deploy in 3 Steps - -### 1️⃣ Install Docker (if not already installed) - -**Ubuntu/Debian:** -```bash -curl -fsSL https://get.docker.com -o get-docker.sh -sudo sh get-docker.sh -sudo usermod -aG docker $USER -``` -Then log out and back in. - -### 2️⃣ Deploy the Application -```bash -cd /srv/quality_recticel -./deploy.sh -``` - -### 3️⃣ Access Your Application -Open browser: **http://localhost:8781** - -**Login:** -- Username: `superadmin` -- Password: `superadmin123` - -## 🎯 Done! - -Your complete application with database is now running in Docker containers. - -## Common Commands - -```bash -# View logs -docker compose logs -f - -# Stop services -docker compose down - -# Restart services -docker compose restart - -# Backup database -docker compose exec -T db mariadb-dump -u trasabilitate -pInitial01! trasabilitate > backup.sql -``` - -## 📚 Full Documentation - -See `DOCKER_DEPLOYMENT.md` for complete documentation. - -## 🆘 Problems? - -```bash -# Check status -docker compose ps - -# View detailed logs -docker compose logs -f web - -# Start fresh -docker compose down -v -./deploy.sh -``` - ---- - -**Note:** This is a production-ready deployment using Gunicorn WSGI server, MariaDB 11.3, and proper health checks. diff --git a/old code/README.md b/old code/README.md deleted file mode 100644 index 04809c9..0000000 --- a/old code/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# Quality Recticel Application - -Production traceability and quality management system. - -## 📚 Documentation - -All development and deployment documentation has been moved to the **[documentation](./documentation/)** folder. - -### Quick Links - -- **[Documentation Index](./documentation/README.md)** - Complete documentation overview -- **[Database Setup](./documentation/DATABASE_DOCKER_SETUP.md)** - Database configuration guide -- **[Docker Guide](./documentation/DOCKER_QUICK_REFERENCE.md)** - Docker commands reference -- **[Backup System](./documentation/BACKUP_SYSTEM.md)** - Database backup documentation - -## 🚀 Quick Start - -```bash -# Start application -cd /srv/quality_app/py_app -bash start_production.sh - -# Stop application -bash stop_production.sh - -# View logs -tail -f /srv/quality_app/logs/error.log -``` - -## 📦 Docker Deployment - -```bash -# Start with Docker Compose -docker-compose up -d - -# View logs -docker-compose logs -f web - -# Stop services -docker-compose down -``` - -## 🔐 Default Access - -- **URL**: http://localhost:8781 -- **Username**: superadmin -- **Password**: superadmin123 - -## 📁 Project Structure - -``` -quality_app/ -├── documentation/ # All documentation files -├── py_app/ # Flask application -├── backups/ # Database backups -├── logs/ # Application logs -├── docker-compose.yml # Docker configuration -└── Dockerfile # Container image definition -``` - -## 📖 For More Information - -See the **[documentation](./documentation/)** folder for comprehensive guides on: - -- Setup and deployment -- Docker configuration -- Database management -- Backup and restore procedures -- Application features - ---- - -**Version**: 1.0.0 -**Last Updated**: November 3, 2025 diff --git a/old code/backup/db_test.html b/old code/backup/db_test.html deleted file mode 100755 index 0342323..0000000 --- a/old code/backup/db_test.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - Database Test - - -

Database Connection Test

- -
- - - - \ No newline at end of file diff --git a/old code/backup/print_module copy.html b/old code/backup/print_module copy.html deleted file mode 100755 index 6032eff..0000000 --- a/old code/backup/print_module copy.html +++ /dev/null @@ -1,1085 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - -{% endblock %} - -{% block content %} -
- -
-
Label View
-

Label Preview

-
- -
- -
- INNOFA RROMANIA SRL -
- - -
- -
- - -
-
-
-
-
- -
- -
- -
- - - -
- - - - -
- Quantity ordered -
-
- -
- - -
- Customer order -
-
- -
- - -
- Delivery date -
-
- -
- - -
- Description -
-
- -
- - -
- Size -
-
- -
- - -
- Article Code -
-
- -
- - -
- Prod Order -
-
- -
- -
- - -
- -
-
- -
- -
-
- - -
- -
-
- -
- -
-
-
- - -
- -
- - - - Checking for available printers... - -
- - -
-
-
- � Upgrade to Silent Printing -
- - 📥 Install Print Service & Extension - -
- 5-minute setup • Auto-starts with Windows • Silent printing -
-
-
-
- - -
- - -
-
- Creates sequential labels based on quantity (e.g., CP00000711-001 to CP00000711-063) -
-
- - � PDF labels can be printed directly from your browser or saved for later use - -
-
- - -
-

Data Preview (Unprinted Orders)

- -
- - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -{% endblock %} \ No newline at end of file diff --git a/old code/backup/print_module.html. old 1backup b/old code/backup/print_module.html. old 1backup deleted file mode 100755 index 7f4a9ee..0000000 --- a/old code/backup/print_module.html. old 1backup +++ /dev/null @@ -1,1383 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - - - -{% endblock %} - -{% block content %} -
- -
-
Label View
- - -
- 🔑 Manage Pairing Keys -
- - -
- - -
- - -
- - -
- -
- -
- INNOFA ROMANIA SRL -
- - -
- -
- - -
-
-
-
-
-
-
-
- - -
- - -
- Quantity ordered -
-
- -
- - -
- Customer order -
-
- -
- - -
- Delivery date -
-
- -
- - -
- Product description -
-
- -
- - -
- Size -
-
- -
- - -
- Article code -
-
- -
- - -
- Prod. order -
-
- -
-
- - -
- - - - -
- -
-
- - -
- - - - -
- -
-
-
- - -
- -
- - -
- - -
- -
- - -
-
- - - - - -
- -
- - -
-
Creates sequential labels based on quantity
- (e.g., CP00000711-001 to CP00000711-063) -
- - - -
-
- - -
-

Data Preview (Unprinted Orders)

- -
- - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - - - - - - -{% endblock %} \ No newline at end of file diff --git a/old code/backup/print_module.html.old 2backup2 b/old code/backup/print_module.html.old 2backup2 deleted file mode 100755 index 4913228..0000000 --- a/old code/backup/print_module.html.old 2backup2 +++ /dev/null @@ -1,1374 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - - - -{% endblock %} - -{% block content %} -
- -
-
Label View
- - -
- 🔑 Manage Pairing Keys -
- - -
- - -
- - -
- - -
- -
- -
- INNOFA ROMANIA SRL -
- - -
- -
- - -
-
-
-
-
-
-
-
- - -
- - -
- Quantity ordered -
-
- -
- - -
- Customer order -
-
- -
- - -
- Delivery date -
-
- -
- - -
- Product description -
-
- -
- - -
- Size -
-
- -
- - -
- Article code -
-
- -
- - -
- Prod. order -
-
- -
-
- - -
- - - - -
- -
-
- - -
- - - - -
- -
-
-
- - -
- -
- - -
- - -
- -
- - -
-
- - - - - -
- -
- - -
-
Creates sequential labels based on quantity
- (e.g., CP00000711-001 to CP00000711-063) -
- - - -
-
- - -
-

Data Preview (Unprinted Orders)

- -
- - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - - - - - - -{% endblock %} \ No newline at end of file diff --git a/old code/backup/print_module.htmlold 3.bak b/old code/backup/print_module.htmlold 3.bak deleted file mode 100755 index 67feba8..0000000 --- a/old code/backup/print_module.htmlold 3.bak +++ /dev/null @@ -1,1844 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - - - -{% endblock %} - -{% block content %} -
- -
-
Label View
- - -
- - - - 🔑 Manage Keys -
- - -
- -
- -
- INNOFA ROMANIA SRL -
- - -
- -
- - -
-
-
-
-
-
-
-
- - -
- - -
- Quantity ordered -
-
- -
- - -
- Customer order -
-
- -
- - -
- Delivery date -
-
- -
- - -
- Product description -
-
- -
- - -
- Size -
-
- -
- - -
- Article code -
-
- -
- - -
- Prod. order -
-
- -
-
- - -
- - - - -
- -
-
- - -
- - - - -
- -
-
-
- - -
- -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - -
-
Creates sequential labels based on quantity
- (e.g., CP00000711-001, CP00000711-002, ...) -
- - -
-
-
- QZ Tray is required for direct printing -
- - 📥 Download QZ Tray - -
-
-
-
- - -
-

Data Preview (Unprinted Orders)

- -
- - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - - - - - - - - - - - -{% endblock %} \ No newline at end of file diff --git a/old code/backup/print_module_backup.html b/old code/backup/print_module_backup.html deleted file mode 100755 index a2cdd2e..0000000 --- a/old code/backup/print_module_backup.html +++ /dev/null @@ -1,1346 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - -{% endblock %} - -{% block content %} -
- -
-
Label View
- - -
- -
- -
- INNOFA RROMANIA SRL -
- - -
- -
- - -
-
-
-
-
- -
- -
- -
- - -
- - -
- Quantity ordered -
-
- -
- - -
- Customer order -
-
- -
- - -
- Delivery date -
-
- -
- - -
- Description -
-
- -
- - -
- Size -
-
- -
- - -
- Article Code -
-
- -
- - -
- Prod Order -
-
- -
-
- - -
- -
-
- -
- -
-
- - -
- -
-
- -
- -
-
-
- - -
- -
- - -
- - -
-
- - -
- -
- - -
-
Creates sequential labels based on quantity
- (e.g., CP00000711-001 to CP00000711-063) -
- - -
- -
-
- 🖥️ Quality Print Desktop v1.0.0 (RECOMMENDED) -
-
- Professional desktop app • Direct hardware access • Rich formatting -
- - - ✅ READY! -
- - -
-
- 📦 Windows Print Service (DEPRECATED) -
-
- Legacy background service • Limited features • Use desktop app instead -
- - 📥 Download Legacy Service - -
- -
- 🏆 Desktop App Benefits: Direct thermal printing • Rich barcodes/QR codes • Better reliability
- ✨ Two versions: Full Linux AppImage or Lightweight Windows Portable • Cross-platform support -
-
-
-
-
-

Data Preview (Unprinted Orders)

- -
- - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -{% endblock %} \ No newline at end of file diff --git a/old code/backup/print_module_clean.html b/old code/backup/print_module_clean.html deleted file mode 100755 index cce1899..0000000 --- a/old code/backup/print_module_clean.html +++ /dev/null @@ -1,487 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - -{% endblock %} - -{% block content %} -
- -
-
Label View
- - -
- -
- -
- INNOFA ROMANIA SRL -
- - -
- -
- - -
-
-
-
-
-
-
-
- - -
- - -
- Quantity ordered -
-
- -
- - -
- Customer order -
-
- -
- - -
- Delivery date -
-
- -
- - -
- Product description -
-
- -
- - -
- Size -
-
- -
- - -
- Article code -
-
- -
- - -
- Prod. order -
-
- -
-
- - -
-
- -
-
- - -
-
- -
-
-
- - -
- -
- - -
- - -
-
- - -
- -
- - -
-
Creates sequential labels based on quantity
- (e.g., CP00000711-001 to CP00000711-063) -
-
-
- - -
-

Data Preview (Unprinted Orders)

- -
- - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -{% endblock %} \ No newline at end of file diff --git a/old code/backup/print_moduleold but good.html b/old code/backup/print_moduleold but good.html deleted file mode 100755 index 766dab4..0000000 --- a/old code/backup/print_moduleold but good.html +++ /dev/null @@ -1,1110 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - - - -{% endblock %} - -{% block content %} -
- -
-
Label View
- - -
- -
- -
- INNOFA ROMANIA SRL -
- - -
- -
- - -
-
-
-
-
-
-
-
- - -
- - -
- Quantity ordered -
-
- -
- - -
- Customer order -
-
- -
- - -
- Delivery date -
-
- -
- - -
- Product description -
-
- -
- - -
- Size -
-
- -
- - -
- Article code -
-
- -
- - -
- Prod. order -
-
- -
-
- - -
- - - - -
- -
-
- - -
- - - - -
- -
-
-
- - -
- -
- - -
- - -
- -
- - -
-
- - - - - -
- -
- - -
-
Creates sequential labels based on quantity
- (e.g., CP00000711-001 to CP00000711-063) -
- - - -
-
- - -
-

Data Preview (Unprinted Orders)

- -
- - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - - - - - - -{% endblock %} \ No newline at end of file diff --git a/old code/backup_db_scripts/add_email_column.py b/old code/backup_db_scripts/add_email_column.py deleted file mode 100755 index 08cbb37..0000000 --- a/old code/backup_db_scripts/add_email_column.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python3 - -import mariadb -import os -import sys - -def get_external_db_connection(): - """Reads the external_server.conf file and returns a MariaDB database connection.""" - # Get the instance folder path - current_dir = os.path.dirname(os.path.abspath(__file__)) - instance_folder = os.path.join(current_dir, '../../instance') - settings_file = os.path.join(instance_folder, 'external_server.conf') - - if not os.path.exists(settings_file): - raise FileNotFoundError(f"The external_server.conf file is missing: {settings_file}") - - # Read settings from the configuration file - settings = {} - with open(settings_file, 'r') as f: - for line in f: - line = line.strip() - if line and '=' in line: - key, value = line.split('=', 1) - settings[key] = value - - print(f"Connecting to MariaDB:") - print(f" Host: {settings.get('server_domain', 'N/A')}") - print(f" Port: {settings.get('port', 'N/A')}") - print(f" Database: {settings.get('database_name', 'N/A')}") - - return mariadb.connect( - user=settings['username'], - password=settings['password'], - host=settings['server_domain'], - port=int(settings['port']), - database=settings['database_name'] - ) - -def main(): - try: - print("=== Adding Email Column to Users Table ===") - conn = get_external_db_connection() - cursor = conn.cursor() - - # First, check the current table structure - print("\n1. Checking current table structure...") - cursor.execute("DESCRIBE users") - columns = cursor.fetchall() - - has_email = False - for column in columns: - print(f" Column: {column[0]} ({column[1]})") - if column[0] == 'email': - has_email = True - - if not has_email: - print("\n2. Adding email column...") - cursor.execute("ALTER TABLE users ADD COLUMN email VARCHAR(255)") - conn.commit() - print(" ✓ Email column added successfully") - else: - print("\n2. Email column already exists") - - # Now check and display all users - print("\n3. Current users in database:") - cursor.execute("SELECT id, username, role, email FROM users") - users = cursor.fetchall() - - if users: - print(f" Found {len(users)} users:") - for user in users: - email = user[3] if user[3] else "No email" - print(f" - ID: {user[0]}, Username: {user[1]}, Role: {user[2]}, Email: {email}") - else: - print(" No users found - creating test users...") - - # Create some test users - test_users = [ - ('admin_user', 'admin123', 'admin', 'admin@company.com'), - ('manager_user', 'manager123', 'manager', 'manager@company.com'), - ('warehouse_user', 'warehouse123', 'warehouse_manager', 'warehouse@company.com'), - ('quality_user', 'quality123', 'quality_manager', 'quality@company.com') - ] - - for username, password, role, email in test_users: - try: - cursor.execute(""" - INSERT INTO users (username, password, role, email) - VALUES (%s, %s, %s, %s) - """, (username, password, role, email)) - print(f" ✓ Created user: {username} ({role})") - except mariadb.IntegrityError as e: - print(f" ⚠ User {username} already exists: {e}") - - conn.commit() - print(" ✓ Test users created successfully") - - conn.close() - print("\n=== Database Update Complete ===") - - except Exception as e: - print(f"❌ Error: {e}") - import traceback - traceback.print_exc() - return 1 - - return 0 - -if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file diff --git a/old code/backup_db_scripts/check_external_db_users.py b/old code/backup_db_scripts/check_external_db_users.py deleted file mode 100755 index 8f28e24..0000000 --- a/old code/backup_db_scripts/check_external_db_users.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python3 - -import mariadb -import os -import sys - -def get_external_db_connection(): - """Reads the external_server.conf file and returns a MariaDB database connection.""" - # Get the instance folder path - current_dir = os.path.dirname(os.path.abspath(__file__)) - instance_folder = os.path.join(current_dir, '../../instance') - settings_file = os.path.join(instance_folder, 'external_server.conf') - - if not os.path.exists(settings_file): - raise FileNotFoundError(f"The external_server.conf file is missing: {settings_file}") - - # Read settings from the configuration file - settings = {} - with open(settings_file, 'r') as f: - for line in f: - line = line.strip() - if line and '=' in line: - key, value = line.split('=', 1) - settings[key] = value - - print(f"Connecting to MariaDB with settings:") - print(f" Host: {settings.get('server_domain', 'N/A')}") - print(f" Port: {settings.get('port', 'N/A')}") - print(f" Database: {settings.get('database_name', 'N/A')}") - print(f" Username: {settings.get('username', 'N/A')}") - - # Create a database connection - return mariadb.connect( - user=settings['username'], - password=settings['password'], - host=settings['server_domain'], - port=int(settings['port']), - database=settings['database_name'] - ) - -def main(): - try: - print("=== Checking External MariaDB Database ===") - conn = get_external_db_connection() - cursor = conn.cursor() - - # Create users table if it doesn't exist - print("\n1. Creating/verifying users table...") - cursor.execute(''' - CREATE TABLE IF NOT EXISTS users ( - id INT AUTO_INCREMENT PRIMARY KEY, - username VARCHAR(50) UNIQUE NOT NULL, - password VARCHAR(255) NOT NULL, - role VARCHAR(50) NOT NULL, - email VARCHAR(255) - ) - ''') - print(" ✓ Users table created/verified") - - # Check existing users - print("\n2. Checking existing users...") - cursor.execute("SELECT id, username, role, email FROM users") - users = cursor.fetchall() - - if users: - print(f" Found {len(users)} existing users:") - for user in users: - email = user[3] if user[3] else "No email" - print(f" - ID: {user[0]}, Username: {user[1]}, Role: {user[2]}, Email: {email}") - else: - print(" No users found in external database") - - # Create some test users - print("\n3. Creating test users...") - test_users = [ - ('admin_user', 'admin123', 'admin', 'admin@company.com'), - ('manager_user', 'manager123', 'manager', 'manager@company.com'), - ('warehouse_user', 'warehouse123', 'warehouse_manager', 'warehouse@company.com'), - ('quality_user', 'quality123', 'quality_manager', 'quality@company.com') - ] - - for username, password, role, email in test_users: - try: - cursor.execute(""" - INSERT INTO users (username, password, role, email) - VALUES (%s, %s, %s, %s) - """, (username, password, role, email)) - print(f" ✓ Created user: {username} ({role})") - except mariadb.IntegrityError as e: - print(f" ⚠ User {username} already exists: {e}") - - conn.commit() - print(" ✓ Test users created successfully") - - conn.close() - print("\n=== Database Check Complete ===") - - except Exception as e: - print(f"❌ Error: {e}") - return 1 - - return 0 - -if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file diff --git a/old code/backup_db_scripts/create_external_superadmin.py b/old code/backup_db_scripts/create_external_superadmin.py deleted file mode 100755 index 5e61924..0000000 --- a/old code/backup_db_scripts/create_external_superadmin.py +++ /dev/null @@ -1,60 +0,0 @@ -import mariadb -import os - -def get_external_db_connection(): - """Get MariaDB connection using external_server.conf""" - settings_file = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../instance/external_server.conf')) - settings = {} - with open(settings_file, 'r') as f: - for line in f: - key, value = line.strip().split('=', 1) - settings[key] = value - return mariadb.connect( - user=settings['username'], - password=settings['password'], - host=settings['server_domain'], - port=int(settings['port']), - database=settings['database_name'] - ) - -def create_external_users_table(): - """Create users table and superadmin user in external MariaDB database""" - try: - conn = get_external_db_connection() - cursor = conn.cursor() - - # Create users table if not exists (MariaDB syntax) - cursor.execute(''' - CREATE TABLE IF NOT EXISTS users ( - id INT AUTO_INCREMENT PRIMARY KEY, - username VARCHAR(50) UNIQUE NOT NULL, - password VARCHAR(255) NOT NULL, - role VARCHAR(50) NOT NULL - ) - ''') - - # Insert superadmin user if not exists - cursor.execute(''' - INSERT IGNORE INTO users (username, password, role) - VALUES (%s, %s, %s) - ''', ('superadmin', 'superadmin123', 'superadmin')) - - # Check if user was created/exists - cursor.execute("SELECT username, password, role FROM users WHERE username = %s", ('superadmin',)) - result = cursor.fetchone() - - if result: - print(f"SUCCESS: Superadmin user exists in external database") - print(f"Username: {result[0]}, Password: {result[1]}, Role: {result[2]}") - else: - print("ERROR: Failed to create/find superadmin user") - - conn.commit() - conn.close() - print("External MariaDB users table setup completed.") - - except Exception as e: - print(f"ERROR: {e}") - -if __name__ == "__main__": - create_external_users_table() \ No newline at end of file diff --git a/old code/backup_db_scripts/create_order_for_labels_table.py b/old code/backup_db_scripts/create_order_for_labels_table.py deleted file mode 100755 index fc21e80..0000000 --- a/old code/backup_db_scripts/create_order_for_labels_table.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python3 -""" -Database script to create the order_for_labels table -This table will store order information for label generation -""" - -import sys -import os -import mariadb -from flask import Flask - -# Add the app directory to the path -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - -def get_db_connection(): - """Get database connection using settings from external_server.conf""" - # Go up two levels from this script to reach py_app directory, then to instance - app_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - settings_file = os.path.join(app_root, 'instance', 'external_server.conf') - - settings = {} - with open(settings_file, 'r') as f: - for line in f: - key, value = line.strip().split('=', 1) - settings[key] = value - - return mariadb.connect( - user=settings['username'], - password=settings['password'], - host=settings['server_domain'], - port=int(settings['port']), - database=settings['database_name'] - ) - -def create_order_for_labels_table(): - """ - Creates the order_for_labels table with the specified structure - """ - try: - conn = get_db_connection() - cursor = conn.cursor() - - # First check if table already exists - cursor.execute("SHOW TABLES LIKE 'order_for_labels'") - result = cursor.fetchone() - - if result: - print("Table 'order_for_labels' already exists.") - # Show current structure - cursor.execute("DESCRIBE order_for_labels") - columns = cursor.fetchall() - print("\nCurrent table structure:") - for col in columns: - print(f" {col[0]} - {col[1]} {'NULL' if col[2] == 'YES' else 'NOT NULL'}") - else: - # Create the table - create_table_sql = """ - CREATE TABLE order_for_labels ( - id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 'Unique identifier', - comanda_productie VARCHAR(15) NOT NULL COMMENT 'Production Order', - cod_articol VARCHAR(15) COMMENT 'Article Code', - descr_com_prod VARCHAR(50) NOT NULL COMMENT 'Production Order Description', - cantitate INT(3) NOT NULL COMMENT 'Quantity', - com_achiz_client VARCHAR(25) COMMENT 'Client Purchase Order', - nr_linie_com_client INT(3) COMMENT 'Client Order Line Number', - customer_name VARCHAR(50) COMMENT 'Customer Name', - customer_article_number VARCHAR(25) COMMENT 'Customer Article Number', - open_for_order VARCHAR(25) COMMENT 'Open for Order Status', - line_number INT(3) COMMENT 'Line Number', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'Record creation timestamp', - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Record update timestamp' - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Table for storing order information for label generation' - """ - - cursor.execute(create_table_sql) - conn.commit() - print("✅ Table 'order_for_labels' created successfully!") - - # Show the created structure - cursor.execute("DESCRIBE order_for_labels") - columns = cursor.fetchall() - print("\n📋 Table structure:") - for col in columns: - null_info = 'NULL' if col[2] == 'YES' else 'NOT NULL' - default_info = f" DEFAULT {col[4]}" if col[4] else "" - print(f" 📌 {col[0]:<25} {col[1]:<20} {null_info}{default_info}") - - conn.close() - - except mariadb.Error as e: - print(f"❌ Database error: {e}") - return False - except Exception as e: - print(f"❌ Error: {e}") - return False - - return True - -if __name__ == "__main__": - print("🏗️ Creating order_for_labels table...") - print("="*50) - - success = create_order_for_labels_table() - - if success: - print("\n✅ Database setup completed successfully!") - else: - print("\n❌ Database setup failed!") - - print("="*50) \ No newline at end of file diff --git a/old code/backup_db_scripts/create_permissions_tables.py b/old code/backup_db_scripts/create_permissions_tables.py deleted file mode 100755 index a807a0b..0000000 --- a/old code/backup_db_scripts/create_permissions_tables.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python3 - -import mariadb -import os -import sys - -def get_external_db_connection(): - """Reads the external_server.conf file and returns a MariaDB database connection.""" - # Get the instance folder path - current_dir = os.path.dirname(os.path.abspath(__file__)) - instance_folder = os.path.join(current_dir, '../../instance') - settings_file = os.path.join(instance_folder, 'external_server.conf') - - if not os.path.exists(settings_file): - raise FileNotFoundError(f"The external_server.conf file is missing: {settings_file}") - - # Read settings from the configuration file - settings = {} - with open(settings_file, 'r') as f: - for line in f: - line = line.strip() - if line and '=' in line: - key, value = line.split('=', 1) - settings[key] = value - - return mariadb.connect( - user=settings['username'], - password=settings['password'], - host=settings['server_domain'], - port=int(settings['port']), - database=settings['database_name'] - ) - -def main(): - try: - print("=== Creating Permission Management Tables ===") - conn = get_external_db_connection() - cursor = conn.cursor() - - # 1. Create permissions table - print("\n1. Creating permissions table...") - cursor.execute(''' - CREATE TABLE IF NOT EXISTS permissions ( - id INT AUTO_INCREMENT PRIMARY KEY, - permission_key VARCHAR(255) UNIQUE NOT NULL, - page VARCHAR(100) NOT NULL, - page_name VARCHAR(255) NOT NULL, - section VARCHAR(100) NOT NULL, - section_name VARCHAR(255) NOT NULL, - action VARCHAR(50) NOT NULL, - action_name VARCHAR(255) NOT NULL, - description TEXT, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP - ) - ''') - print(" ✓ Permissions table created/verified") - - # 2. Create role_permissions table - print("\n2. Creating role_permissions table...") - cursor.execute(''' - CREATE TABLE IF NOT EXISTS role_permissions ( - id INT AUTO_INCREMENT PRIMARY KEY, - role VARCHAR(50) NOT NULL, - permission_key VARCHAR(255) NOT NULL, - granted BOOLEAN DEFAULT TRUE, - granted_by VARCHAR(50), - granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - UNIQUE KEY unique_role_permission (role, permission_key), - FOREIGN KEY (permission_key) REFERENCES permissions(permission_key) ON DELETE CASCADE - ) - ''') - print(" ✓ Role permissions table created/verified") - - # 3. Create role_hierarchy table for role management - print("\n3. Creating role_hierarchy table...") - cursor.execute(''' - CREATE TABLE IF NOT EXISTS role_hierarchy ( - id INT AUTO_INCREMENT PRIMARY KEY, - role_name VARCHAR(50) UNIQUE NOT NULL, - display_name VARCHAR(255) NOT NULL, - description TEXT, - level INT DEFAULT 0, - is_active BOOLEAN DEFAULT TRUE, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP - ) - ''') - print(" ✓ Role hierarchy table created/verified") - - # 4. Create permission_audit_log table for tracking changes - print("\n4. Creating permission_audit_log table...") - cursor.execute(''' - CREATE TABLE IF NOT EXISTS permission_audit_log ( - id INT AUTO_INCREMENT PRIMARY KEY, - role VARCHAR(50) NOT NULL, - permission_key VARCHAR(255) NOT NULL, - action ENUM('granted', 'revoked') NOT NULL, - changed_by VARCHAR(50) NOT NULL, - changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - reason TEXT, - ip_address VARCHAR(45) - ) - ''') - print(" ✓ Permission audit log table created/verified") - - conn.commit() - - # 5. Check if we need to populate initial data - print("\n5. Checking for existing data...") - cursor.execute("SELECT COUNT(*) FROM permissions") - permission_count = cursor.fetchone()[0] - - if permission_count == 0: - print(" No permissions found - will need to populate with default data") - print(" Run 'populate_permissions.py' to initialize the permission system") - else: - print(f" Found {permission_count} existing permissions") - - cursor.execute("SELECT COUNT(*) FROM role_hierarchy") - role_count = cursor.fetchone()[0] - - if role_count == 0: - print(" No roles found - will need to populate with default roles") - else: - print(f" Found {role_count} existing roles") - - conn.close() - print("\n=== Permission Database Schema Created Successfully ===") - - except Exception as e: - print(f"❌ Error: {e}") - import traceback - traceback.print_exc() - return 1 - - return 0 - -if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file diff --git a/old code/backup_db_scripts/create_roles_table.py b/old code/backup_db_scripts/create_roles_table.py deleted file mode 100755 index 693e846..0000000 --- a/old code/backup_db_scripts/create_roles_table.py +++ /dev/null @@ -1,45 +0,0 @@ -import sqlite3 -import os - -def create_roles_and_users_tables(db_path): - conn = sqlite3.connect(db_path) - cursor = conn.cursor() - # Create users table if not exists - cursor.execute(''' - CREATE TABLE IF NOT EXISTS users ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - username TEXT UNIQUE NOT NULL, - password TEXT NOT NULL, - role TEXT NOT NULL - ) - ''') - # Insert superadmin user if not exists (default password: 'admin', change after first login) - cursor.execute(''' - INSERT OR IGNORE INTO users (username, password, role) - VALUES (?, ?, ?) - ''', ('superadmin', 'superadmin123', 'superadmin')) - # Create roles table if not exists - cursor.execute(''' - CREATE TABLE IF NOT EXISTS roles ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT UNIQUE NOT NULL, - access_level TEXT NOT NULL, - description TEXT - ) - ''') - # Insert superadmin role if not exists - cursor.execute(''' - INSERT OR IGNORE INTO roles (name, access_level, description) - VALUES (?, ?, ?) - ''', ('superadmin', 'full', 'Full access to all app areas and functions')) - conn.commit() - conn.close() - -if __name__ == "__main__": - # Default path to users.db in instance folder - instance_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../instance')) - if not os.path.exists(instance_folder): - os.makedirs(instance_folder) - db_path = os.path.join(instance_folder, 'users.db') - create_roles_and_users_tables(db_path) - print("Roles and users tables created. Superadmin user and role initialized.") diff --git a/old code/backup_db_scripts/create_scan_1db.py b/old code/backup_db_scripts/create_scan_1db.py deleted file mode 100755 index 5f76e3f..0000000 --- a/old code/backup_db_scripts/create_scan_1db.py +++ /dev/null @@ -1,42 +0,0 @@ -import mariadb - -# Database connection credentials -db_config = { - "user": "trasabilitate", - "password": "Initial01!", - "host": "localhost", - "database": "trasabilitate" -} - -# Connect to the database -try: - conn = mariadb.connect(**db_config) - cursor = conn.cursor() - print("Connected to the database successfully!") - - # Create the scan1_orders table - create_table_query = """ - CREATE TABLE IF NOT EXISTS scan1_orders ( - Id INT AUTO_INCREMENT PRIMARY KEY, -- Auto-incremented ID with 6 digits - operator_code VARCHAR(4) NOT NULL, -- Operator code with 4 characters - CP_full_code VARCHAR(15) NOT NULL UNIQUE, -- Full CP code with up to 15 characters - OC1_code VARCHAR(4) NOT NULL, -- OC1 code with 4 characters - OC2_code VARCHAR(4) NOT NULL, -- OC2 code with 4 characters - CP_base_code VARCHAR(10) GENERATED ALWAYS AS (LEFT(CP_full_code, 10)) STORED, -- Auto-generated base code (first 10 characters of CP_full_code) - quality_code INT(3) NOT NULL, -- Quality code with 3 digits - date DATE NOT NULL, -- Date in format dd-mm-yyyy - time TIME NOT NULL, -- Time in format hh:mm:ss - approved_quantity INT DEFAULT 0, -- Auto-incremented quantity for quality_code = 000 - rejected_quantity INT DEFAULT 0 -- Auto-incremented quantity for quality_code != 000 - ); - """ - cursor.execute(create_table_query) - print("Table 'scan1_orders' created successfully!") - - # Commit changes and close the connection - conn.commit() - cursor.close() - conn.close() - -except mariadb.Error as e: - print(f"Error connecting to the database: {e}") \ No newline at end of file diff --git a/old code/backup_db_scripts/create_scanfg_orders.py b/old code/backup_db_scripts/create_scanfg_orders.py deleted file mode 100644 index f461039..0000000 --- a/old code/backup_db_scripts/create_scanfg_orders.py +++ /dev/null @@ -1,41 +0,0 @@ -import mariadb - -# Database connection credentials -# (reuse from create_scan_1db.py or update as needed) -db_config = { - "user": "trasabilitate", - "password": "Initial01!", - "host": "localhost", - "database": "trasabilitate" -} - -try: - conn = mariadb.connect(**db_config) - cursor = conn.cursor() - print("Connected to the database successfully!") - - # Create the scanfg_orders table (same structure as scan1_orders) - create_table_query = """ - CREATE TABLE IF NOT EXISTS scanfg_orders ( - Id INT AUTO_INCREMENT PRIMARY KEY, - operator_code VARCHAR(4) NOT NULL, - CP_full_code VARCHAR(15) NOT NULL UNIQUE, - OC1_code VARCHAR(4) NOT NULL, - OC2_code VARCHAR(4) NOT NULL, - CP_base_code VARCHAR(10) GENERATED ALWAYS AS (LEFT(CP_full_code, 10)) STORED, - quality_code INT(3) NOT NULL, - date DATE NOT NULL, - time TIME NOT NULL, - approved_quantity INT DEFAULT 0, - rejected_quantity INT DEFAULT 0 - ); - """ - cursor.execute(create_table_query) - print("Table 'scanfg_orders' created successfully!") - - conn.commit() - cursor.close() - conn.close() - -except mariadb.Error as e: - print(f"Error connecting to the database: {e}") diff --git a/old code/backup_db_scripts/create_triggers.py b/old code/backup_db_scripts/create_triggers.py deleted file mode 100755 index c7a04ed..0000000 --- a/old code/backup_db_scripts/create_triggers.py +++ /dev/null @@ -1,70 +0,0 @@ -import mariadb - -# Database connection credentials -db_config = { - "user": "trasabilitate", - "password": "Initial01!", - "host": "localhost", - "database": "trasabilitate" -} - -# Connect to the database -try: - conn = mariadb.connect(**db_config) - cursor = conn.cursor() - print("Connected to the database successfully!") - - # Delete old triggers if they exist - try: - cursor.execute("DROP TRIGGER IF EXISTS increment_approved_quantity;") - print("Old trigger 'increment_approved_quantity' deleted successfully.") - except mariadb.Error as e: - print(f"Error deleting old trigger 'increment_approved_quantity': {e}") - - try: - cursor.execute("DROP TRIGGER IF EXISTS increment_rejected_quantity;") - print("Old trigger 'increment_rejected_quantity' deleted successfully.") - except mariadb.Error as e: - print(f"Error deleting old trigger 'increment_rejected_quantity': {e}") - - # Create corrected trigger for approved_quantity - create_approved_trigger = """ - CREATE TRIGGER increment_approved_quantity - BEFORE INSERT ON scan1_orders - FOR EACH ROW - BEGIN - IF NEW.quality_code = 000 THEN - SET NEW.approved_quantity = ( - SELECT COUNT(*) - FROM scan1_orders - WHERE CP_base_code = NEW.CP_base_code AND quality_code = 000 - ) + 1; - SET NEW.rejected_quantity = ( - SELECT COUNT(*) - FROM scan1_orders - WHERE CP_base_code = NEW.CP_base_code AND quality_code != 000 - ); - ELSE - SET NEW.approved_quantity = ( - SELECT COUNT(*) - FROM scan1_orders - WHERE CP_base_code = NEW.CP_base_code AND quality_code = 000 - ); - SET NEW.rejected_quantity = ( - SELECT COUNT(*) - FROM scan1_orders - WHERE CP_base_code = NEW.CP_base_code AND quality_code != 000 - ) + 1; - END IF; - END; - """ - cursor.execute(create_approved_trigger) - print("Trigger 'increment_approved_quantity' created successfully!") - - # Commit changes and close the connection - conn.commit() - cursor.close() - conn.close() - -except mariadb.Error as e: - print(f"Error connecting to the database or creating triggers: {e}") \ No newline at end of file diff --git a/old code/backup_db_scripts/create_triggers_fg.py b/old code/backup_db_scripts/create_triggers_fg.py deleted file mode 100644 index 3246f06..0000000 --- a/old code/backup_db_scripts/create_triggers_fg.py +++ /dev/null @@ -1,73 +0,0 @@ -import mariadb - -# Database connection credentials -db_config = { - "user": "trasabilitate", - "password": "Initial01!", - "host": "localhost", - "database": "trasabilitate" -} - -# Connect to the database -try: - conn = mariadb.connect(**db_config) - cursor = conn.cursor() - print("Connected to the database successfully!") - - # Delete old triggers if they exist - try: - cursor.execute("DROP TRIGGER IF EXISTS increment_approved_quantity_fg;") - print("Old trigger 'increment_approved_quantity_fg' deleted successfully.") - except mariadb.Error as e: - print(f"Error deleting old trigger 'increment_approved_quantity_fg': {e}") - - try: - cursor.execute("DROP TRIGGER IF EXISTS increment_rejected_quantity_fg;") - print("Old trigger 'increment_rejected_quantity_fg' deleted successfully.") - except mariadb.Error as e: - print(f"Error deleting old trigger 'increment_rejected_quantity_fg': {e}") - - # Create corrected trigger for approved_quantity in scanfg_orders - create_approved_trigger_fg = """ - CREATE TRIGGER increment_approved_quantity_fg - BEFORE INSERT ON scanfg_orders - FOR EACH ROW - BEGIN - IF NEW.quality_code = 000 THEN - SET NEW.approved_quantity = ( - SELECT COUNT(*) - FROM scanfg_orders - WHERE CP_base_code = NEW.CP_base_code AND quality_code = 000 - ) + 1; - SET NEW.rejected_quantity = ( - SELECT COUNT(*) - FROM scanfg_orders - WHERE CP_base_code = NEW.CP_base_code AND quality_code != 000 - ); - ELSE - SET NEW.approved_quantity = ( - SELECT COUNT(*) - FROM scanfg_orders - WHERE CP_base_code = NEW.CP_base_code AND quality_code = 000 - ); - SET NEW.rejected_quantity = ( - SELECT COUNT(*) - FROM scanfg_orders - WHERE CP_base_code = NEW.CP_base_code AND quality_code != 000 - ) + 1; - END IF; - END; - """ - cursor.execute(create_approved_trigger_fg) - print("Trigger 'increment_approved_quantity_fg' created successfully for scanfg_orders table!") - - # Commit changes and close the connection - conn.commit() - cursor.close() - conn.close() - - print("\n✅ All triggers for scanfg_orders table created successfully!") - print("The approved_quantity and rejected_quantity will now be calculated automatically.") - -except mariadb.Error as e: - print(f"Error connecting to the database or creating triggers: {e}") diff --git a/old code/backup_db_scripts/create_warehouse_locations_table.py b/old code/backup_db_scripts/create_warehouse_locations_table.py deleted file mode 100755 index 37e6be5..0000000 --- a/old code/backup_db_scripts/create_warehouse_locations_table.py +++ /dev/null @@ -1,25 +0,0 @@ -import mariadb -from app.warehouse import get_db_connection -from flask import Flask -import os - -def create_warehouse_locations_table(): - conn = get_db_connection() - cursor = conn.cursor() - cursor.execute(''' - CREATE TABLE IF NOT EXISTS warehouse_locations ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - location_code VARCHAR(12) NOT NULL UNIQUE, - size INT, - description VARCHAR(250) - ) - ''') - conn.commit() - conn.close() - -if __name__ == "__main__": - instance_path = os.path.abspath("instance") - app = Flask(__name__, instance_path=instance_path) - with app.app_context(): - create_warehouse_locations_table() - print("warehouse_locations table created or already exists.") \ No newline at end of file diff --git a/old code/backup_db_scripts/delet scan1_orders values.py b/old code/backup_db_scripts/delet scan1_orders values.py deleted file mode 100755 index a4f2050..0000000 --- a/old code/backup_db_scripts/delet scan1_orders values.py +++ /dev/null @@ -1,30 +0,0 @@ -import mariadb - -# Database connection credentials -def get_db_connection(): - return mariadb.connect( - user="trasabilitate", # Replace with your username - password="Initial01!", # Replace with your password - host="localhost", # Replace with your host - port=3306, # Default MariaDB port - database="trasabilitate_database" # Replace with your database name - ) - -try: - # Connect to the database - conn = get_db_connection() - cursor = conn.cursor() - - # Delete query - delete_query = "DELETE FROM scan1_orders" - cursor.execute(delete_query) - conn.commit() - - print("All data from the 'scan1_orders' table has been deleted successfully.") - - # Close the connection - cursor.close() - conn.close() - -except mariadb.Error as e: - print(f"Error deleting data: {e}") \ No newline at end of file diff --git a/old code/backup_db_scripts/drop_external_users_roles_tables.py b/old code/backup_db_scripts/drop_external_users_roles_tables.py deleted file mode 100755 index 2eb814e..0000000 --- a/old code/backup_db_scripts/drop_external_users_roles_tables.py +++ /dev/null @@ -1,26 +0,0 @@ -import mariadb -import os - -def get_external_db_connection(): - settings_file = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../instance/external_server.conf')) - settings = {} - with open(settings_file, 'r') as f: - for line in f: - key, value = line.strip().split('=', 1) - settings[key] = value - return mariadb.connect( - user=settings['username'], - password=settings['password'], - host=settings['server_domain'], - port=int(settings['port']), - database=settings['database_name'] - ) - -if __name__ == "__main__": - conn = get_external_db_connection() - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS users") - cursor.execute("DROP TABLE IF EXISTS roles") - conn.commit() - conn.close() - print("Dropped users and roles tables from external database.") diff --git a/old code/backup_db_scripts/find_users_databases.py b/old code/backup_db_scripts/find_users_databases.py deleted file mode 100755 index 9f72a0c..0000000 --- a/old code/backup_db_scripts/find_users_databases.py +++ /dev/null @@ -1,53 +0,0 @@ -import sqlite3 -import os - -def check_database(db_path, description): - """Check if a database exists and show its users.""" - if os.path.exists(db_path): - print(f"\n{description}: FOUND at {db_path}") - try: - conn = sqlite3.connect(db_path) - cursor = conn.cursor() - - # Check if users table exists - cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users'") - if cursor.fetchone(): - cursor.execute("SELECT id, username, password, role FROM users") - users = cursor.fetchall() - if users: - print("Users in this database:") - for user in users: - print(f" ID: {user[0]}, Username: {user[1]}, Password: {user[2]}, Role: {user[3]}") - else: - print(" Users table exists but is empty") - else: - print(" No users table found") - conn.close() - except Exception as e: - print(f" Error reading database: {e}") - else: - print(f"\n{description}: NOT FOUND at {db_path}") - -if __name__ == "__main__": - # Check different possible locations for users.db - - # 1. Root quality_recticel/instance/users.db - root_instance = "/home/ske087/quality_recticel/instance/users.db" - check_database(root_instance, "Root instance users.db") - - # 2. App instance folder - app_instance = "/home/ske087/quality_recticel/py_app/instance/users.db" - check_database(app_instance, "App instance users.db") - - # 3. Current working directory - cwd_db = "/home/ske087/quality_recticel/py_app/users.db" - check_database(cwd_db, "Working directory users.db") - - # 4. Flask app database (relative to py_app) - flask_db = "/home/ske087/quality_recticel/py_app/app/users.db" - check_database(flask_db, "Flask app users.db") - - print("\n" + "="*50) - print("RECOMMENDATION:") - print("The login should use the external MariaDB database.") - print("Make sure you have created the superadmin user in MariaDB using create_roles_table.py") \ No newline at end of file diff --git a/old code/backup_db_scripts/populate_permissions.py b/old code/backup_db_scripts/populate_permissions.py deleted file mode 100755 index 2d2d4eb..0000000 --- a/old code/backup_db_scripts/populate_permissions.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env python3 - -import mariadb -import os -import sys - -# Add the app directory to the path so we can import our permissions module -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) - -from permissions import APP_PERMISSIONS, ROLE_HIERARCHY, ACTIONS, get_all_permissions, get_default_permissions_for_role - -def get_external_db_connection(): - """Reads the external_server.conf file and returns a MariaDB database connection.""" - current_dir = os.path.dirname(os.path.abspath(__file__)) - instance_folder = os.path.join(current_dir, '../../instance') - settings_file = os.path.join(instance_folder, 'external_server.conf') - - if not os.path.exists(settings_file): - raise FileNotFoundError(f"The external_server.conf file is missing: {settings_file}") - - settings = {} - with open(settings_file, 'r') as f: - for line in f: - line = line.strip() - if line and '=' in line: - key, value = line.split('=', 1) - settings[key] = value - - return mariadb.connect( - user=settings['username'], - password=settings['password'], - host=settings['server_domain'], - port=int(settings['port']), - database=settings['database_name'] - ) - -def main(): - try: - print("=== Populating Permission System ===") - conn = get_external_db_connection() - cursor = conn.cursor() - - # 1. Populate all permissions - print("\n1. Populating permissions...") - permissions = get_all_permissions() - - for perm in permissions: - try: - cursor.execute(''' - INSERT INTO permissions (permission_key, page, page_name, section, section_name, action, action_name) - VALUES (%s, %s, %s, %s, %s, %s, %s) - ON DUPLICATE KEY UPDATE - page_name = VALUES(page_name), - section_name = VALUES(section_name), - action_name = VALUES(action_name), - updated_at = CURRENT_TIMESTAMP - ''', ( - perm['key'], - perm['page'], - perm['page_name'], - perm['section'], - perm['section_name'], - perm['action'], - perm['action_name'] - )) - except Exception as e: - print(f" ⚠ Error inserting permission {perm['key']}: {e}") - - conn.commit() - print(f" ✓ Populated {len(permissions)} permissions") - - # 2. Populate role hierarchy - print("\n2. Populating role hierarchy...") - for role_name, role_data in ROLE_HIERARCHY.items(): - try: - cursor.execute(''' - INSERT INTO role_hierarchy (role_name, display_name, description, level) - VALUES (%s, %s, %s, %s) - ON DUPLICATE KEY UPDATE - display_name = VALUES(display_name), - description = VALUES(description), - level = VALUES(level), - updated_at = CURRENT_TIMESTAMP - ''', ( - role_name, - role_data['name'], - role_data['description'], - role_data['level'] - )) - except Exception as e: - print(f" ⚠ Error inserting role {role_name}: {e}") - - conn.commit() - print(f" ✓ Populated {len(ROLE_HIERARCHY)} roles") - - # 3. Set default permissions for each role - print("\n3. Setting default role permissions...") - for role_name in ROLE_HIERARCHY.keys(): - default_permissions = get_default_permissions_for_role(role_name) - - print(f" Setting permissions for {role_name}: {len(default_permissions)} permissions") - - for permission_key in default_permissions: - try: - cursor.execute(''' - INSERT INTO role_permissions (role, permission_key, granted, granted_by) - VALUES (%s, %s, TRUE, 'system') - ON DUPLICATE KEY UPDATE - granted = TRUE, - updated_at = CURRENT_TIMESTAMP - ''', (role_name, permission_key)) - except Exception as e: - print(f" ⚠ Error setting permission {permission_key} for {role_name}: {e}") - - conn.commit() - - # 4. Show summary - print("\n4. Permission Summary:") - cursor.execute(''' - SELECT r.role_name, r.display_name, COUNT(rp.permission_key) as permission_count - FROM role_hierarchy r - LEFT JOIN role_permissions rp ON r.role_name = rp.role AND rp.granted = TRUE - GROUP BY r.role_name, r.display_name - ORDER BY r.level DESC - ''') - - results = cursor.fetchall() - for role_name, display_name, count in results: - print(f" {display_name} ({role_name}): {count} permissions") - - conn.close() - print("\n=== Permission System Initialization Complete ===") - - except Exception as e: - print(f"❌ Error: {e}") - import traceback - traceback.print_exc() - return 1 - - return 0 - -if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file diff --git a/old code/backup_db_scripts/print_internal_users.py b/old code/backup_db_scripts/print_internal_users.py deleted file mode 100755 index 5a953e0..0000000 --- a/old code/backup_db_scripts/print_internal_users.py +++ /dev/null @@ -1,30 +0,0 @@ -import sqlite3 -import os - -instance_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../instance')) -db_path = os.path.join(instance_folder, 'users.db') - -if not os.path.exists(db_path): - print("users.db not found at", db_path) - exit(1) - -conn = sqlite3.connect(db_path) -cursor = conn.cursor() - -# Check if users table exists -cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users'") -if not cursor.fetchone(): - print("No users table found in users.db.") - conn.close() - exit(1) - -# Print all users -cursor.execute("SELECT id, username, password, role FROM users") -rows = cursor.fetchall() -if not rows: - print("No users found in users.db.") -else: - print("Users in users.db:") - for row in rows: - print(f"id={row[0]}, username={row[1]}, password={row[2]}, role={row[3]}") -conn.close() diff --git a/old code/backup_db_scripts/query.py b/old code/backup_db_scripts/query.py deleted file mode 100755 index 57e72bb..0000000 --- a/old code/backup_db_scripts/query.py +++ /dev/null @@ -1,34 +0,0 @@ -import mariadb - -# Database connection credentials -db_config = { - "user": "trasabilitate", - "password": "Initial01!", - "host": "localhost", - "database": "trasabilitate_database" -} - -try: - # Connect to the database - conn = mariadb.connect(**db_config) - cursor = conn.cursor() - - # Query to fetch all records from the scan1 table - query = "SELECT * FROM scan1_orders ORDER BY Id DESC LIMIT 15" - cursor.execute(query) - - # Fetch and print the results - rows = cursor.fetchall() - if rows: - print("Records in the 'scan1_orders' table:") - for row in rows: - print(row) - else: - print("No records found in the 'scan1_orders' table.") - - # Close the connection - cursor.close() - conn.close() - -except mariadb.Error as e: - print(f"Error connecting to the database: {e}") \ No newline at end of file diff --git a/old code/backup_db_scripts/recreate_order_for_labels_table.py b/old code/backup_db_scripts/recreate_order_for_labels_table.py deleted file mode 100755 index 163d58d..0000000 --- a/old code/backup_db_scripts/recreate_order_for_labels_table.py +++ /dev/null @@ -1,50 +0,0 @@ -import mariadb - -# Database connection credentials -DB_CONFIG = { - "user": "sa", - "password": "12345678", - "host": "localhost", - "database": "recticel" -} - -def recreate_order_for_labels_table(): - conn = mariadb.connect(**DB_CONFIG) - cursor = conn.cursor() - print("Connected to the database successfully!") - - # Drop the table if it exists - cursor.execute("DROP TABLE IF EXISTS order_for_labels") - print("Dropped existing 'order_for_labels' table.") - - # Create the table with the new unique constraint - create_table_sql = """ - CREATE TABLE order_for_labels ( - id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 'Unique identifier', - comanda_productie VARCHAR(15) NOT NULL UNIQUE COMMENT 'Production Order (unique)', - cod_articol VARCHAR(15) COMMENT 'Article Code', - descr_com_prod VARCHAR(50) NOT NULL COMMENT 'Production Order Description', - cantitate INT(3) NOT NULL COMMENT 'Quantity', - data_livrare DATE COMMENT 'Delivery date', - dimensiune VARCHAR(20) COMMENT 'Dimensions', - com_achiz_client VARCHAR(25) COMMENT 'Client Purchase Order', - nr_linie_com_client INT(3) COMMENT 'Client Order Line Number', - customer_name VARCHAR(50) COMMENT 'Customer Name', - customer_article_number VARCHAR(25) COMMENT 'Customer Article Number', - open_for_order VARCHAR(25) COMMENT 'Open for Order Status', - line_number INT(3) COMMENT 'Line Number', - printed_labels TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Boolean flag: 0=labels not printed, 1=labels printed', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'Record creation timestamp', - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Record update timestamp' - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Table for storing order information for label generation'; - """ - cursor.execute(create_table_sql) - print("Created new 'order_for_labels' table with unique comanda_productie.") - - conn.commit() - cursor.close() - conn.close() - print("Done.") - -if __name__ == "__main__": - recreate_order_for_labels_table() diff --git a/old code/backup_db_scripts/seed_internal_superadmin.py b/old code/backup_db_scripts/seed_internal_superadmin.py deleted file mode 100755 index fd950c3..0000000 --- a/old code/backup_db_scripts/seed_internal_superadmin.py +++ /dev/null @@ -1,34 +0,0 @@ -import sqlite3 -import os -from flask import Flask - -app = Flask(__name__) -app.config['SECRET_KEY'] = 'your_secret_key' # Use the same key as in __init__.py - -instance_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../instance')) -if not os.path.exists(instance_folder): - os.makedirs(instance_folder) -db_path = os.path.join(instance_folder, 'users.db') - -conn = sqlite3.connect(db_path) -cursor = conn.cursor() - -# Create users table if not exists -cursor.execute(''' - CREATE TABLE IF NOT EXISTS users ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - username TEXT UNIQUE NOT NULL, - password TEXT NOT NULL, - role TEXT NOT NULL - ) -''') - -# Insert superadmin user if not exists -cursor.execute(''' - INSERT OR IGNORE INTO users (username, password, role) - VALUES (?, ?, ?) -''', ('superadmin', 'superadmin123', 'superadmin')) - -conn.commit() -conn.close() -print("Internal users.db seeded with superadmin user.") diff --git a/old code/backup_db_scripts/test.py b/old code/backup_db_scripts/test.py deleted file mode 100755 index 76544e8..0000000 --- a/old code/backup_db_scripts/test.py +++ /dev/null @@ -1,37 +0,0 @@ -import mariadb - -# Database connection credentials -def get_db_connection(): - return mariadb.connect( - user="trasabilitate", # Replace with your username - password="Initial01!", # Replace with your password - host="localhost", # Replace with your host - port=3306, # Default MariaDB port - database="trasabilitate_database" # Replace with your database name - ) - -try: - # Connect to the database - conn = get_db_connection() - cursor = conn.cursor() - - # Insert query - insert_query = """ - INSERT INTO scan1_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time) - VALUES (?, ?, ?, ?, ?, ?, ?) - """ - # Values to insert - values = ('OP01', 'CP12345678-0002', 'OC11', 'OC22', 000, '2025-04-22', '14:30:00') - - # Execute the query - cursor.execute(insert_query, values) - conn.commit() - - print("Test data inserted successfully into scan1_orders.") - - # Close the connection - cursor.close() - conn.close() - -except mariadb.Error as e: - print(f"Error inserting data: {e}") \ No newline at end of file diff --git a/old code/documentation/INSTALLATION_GUIDE.md b/old code/documentation/INSTALLATION_GUIDE.md deleted file mode 100755 index 0b68622..0000000 --- a/old code/documentation/INSTALLATION_GUIDE.md +++ /dev/null @@ -1,361 +0,0 @@ -# Quality Recticel Windows Print Service - Installation Guide - -## 📋 Overview - -The Quality Recticel Windows Print Service enables **silent PDF printing** directly from the web application through a Chrome extension. This system eliminates the need for manual PDF downloads and provides seamless label printing functionality. - -## 🏗️ System Architecture - -``` -Web Application (print_module.html) - ↓ -Windows Print Service (localhost:8765) - ↓ -Chrome Extension (Native Messaging) - ↓ -Windows Print System -``` - -## 📦 Package Contents - -``` -windows_print_service/ -├── print_service.py # Main Windows service (Flask API) -├── service_manager.py # Service installation & management -├── install_service.bat # Automated installation script -├── chrome_extension/ # Chrome extension files -│ ├── manifest.json # Extension configuration -│ ├── background.js # Service worker -│ ├── content.js # Page integration -│ ├── popup.html # Extension UI -│ ├── popup.js # Extension logic -│ └── icons/ # Extension icons -└── INSTALLATION_GUIDE.md # This documentation -``` - -## 🔧 Prerequisites - -### System Requirements -- **Operating System**: Windows 10/11 (64-bit) -- **Python**: Python 3.8 or higher -- **Browser**: Google Chrome (latest version) -- **Privileges**: Administrator access required for installation - -### Python Dependencies -The following packages will be installed automatically: -- `flask` - Web service framework -- `flask-cors` - Cross-origin resource sharing -- `requests` - HTTP client library -- `pywin32` - Windows service integration - -## 🚀 Installation Process - -### Step 1: Download and Extract Files - -1. Download the `windows_print_service` folder to your system -2. Extract to a permanent location (e.g., `C:\QualityRecticel\PrintService\`) -3. **Do not move or delete this folder after installation** - -### Step 2: Install Windows Service - -#### Method A: Automated Installation (Recommended) - -1. **Right-click** on `install_service.bat` -2. Select **"Run as administrator"** -3. Click **"Yes"** when Windows UAC prompt appears -4. Wait for installation to complete - -#### Method B: Manual Installation - -If the automated script fails, follow these steps: - -```bash -# Open Command Prompt as Administrator -cd C:\path\to\windows_print_service - -# Install Python dependencies -pip install flask flask-cors requests pywin32 - -# Install Windows service -python service_manager.py install - -# Add firewall exception -netsh advfirewall firewall add rule name="Quality Recticel Print Service" dir=in action=allow protocol=TCP localport=8765 - -# Create Chrome extension registry entry -reg add "HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.qualityrecticel.printservice" /ve /d "%cd%\chrome_extension\manifest.json" /f -``` - -### Step 3: Install Chrome Extension - -1. Open **Google Chrome** -2. Navigate to `chrome://extensions/` -3. Enable **"Developer mode"** (toggle in top-right corner) -4. Click **"Load unpacked"** -5. Select the `chrome_extension` folder -6. Verify the extension appears with a printer icon - -### Step 4: Verify Installation - -#### Check Windows Service Status - -1. Press `Win + R`, type `services.msc`, press Enter -2. Look for **"Quality Recticel Print Service"** -3. Status should show **"Running"** -4. Startup type should be **"Automatic"** - -#### Test API Endpoints - -Open a web browser and visit: -- **Health Check**: `http://localhost:8765/health` -- **Printer List**: `http://localhost:8765/printers` - -Expected response for health check: -```json -{ - "status": "healthy", - "service": "Quality Recticel Print Service", - "version": "1.0", - "timestamp": "2025-09-21T10:30:00" -} -``` - -#### Test Chrome Extension - -1. Click the extension icon in Chrome toolbar -2. Verify it shows "Service Status: Connected ✅" -3. Check that printers are listed -4. Try the "Test Print" button - -## 🔄 Web Application Integration - -The web application automatically detects the Windows service and adapts the user interface: - -### Service Available (Green Button) -- Button text: **"🖨️ Print Labels (Silent)"** -- Functionality: Direct printing to default printer -- User experience: Click → Labels print immediately - -### Service Unavailable (Blue Button) -- Button text: **"📄 Generate PDF"** -- Functionality: PDF download for manual printing -- User experience: Click → PDF downloads to browser - -### Detection Logic -```javascript -// Automatic service detection on page load -const response = await fetch('http://localhost:8765/health'); -if (response.ok) { - // Service available - enable silent printing -} else { - // Service unavailable - fallback to PDF download -} -``` - -## 🛠️ Configuration - -### Service Configuration - -The service runs with the following default settings: - -| Setting | Value | Description | -|---------|-------|-------------| -| **Port** | 8765 | Local API port | -| **Host** | localhost | Service binding | -| **Startup** | Automatic | Starts with Windows | -| **Printer** | Default | Uses system default printer | -| **Copies** | 1 | Default print copies | - -### Chrome Extension Permissions - -The extension requires these permissions: -- `printing` - Access to printer functionality -- `nativeMessaging` - Communication with Windows service -- `activeTab` - Access to current webpage -- `storage` - Save extension settings - -## 🔍 Troubleshooting - -### Common Issues - -#### 1. Service Not Starting -**Symptoms**: API not accessible at localhost:8765 -**Solutions**: -```bash -# Check service status -python -c "from service_manager import service_status; service_status()" - -# Restart service manually -python service_manager.py restart - -# Check Windows Event Viewer for service errors -``` - -#### 2. Chrome Extension Not Working -**Symptoms**: Extension shows "Service Status: Disconnected ❌" -**Solutions**: -- Verify Windows service is running -- Check firewall settings (port 8765 must be open) -- Reload the Chrome extension -- Restart Chrome browser - -#### 3. Firewall Blocking Connection -**Symptoms**: Service runs but web page can't connect -**Solutions**: -```bash -# Add firewall rule manually -netsh advfirewall firewall add rule name="Quality Recticel Print Service" dir=in action=allow protocol=TCP localport=8765 - -# Or disable Windows Firewall temporarily to test -``` - -#### 4. Permission Denied Errors -**Symptoms**: Installation fails with permission errors -**Solutions**: -- Ensure running as Administrator -- Check Windows UAC settings -- Verify Python installation permissions - -#### 5. Print Jobs Not Processing -**Symptoms**: API accepts requests but nothing prints -**Solutions**: -- Check default printer configuration -- Verify printer drivers are installed -- Test manual printing from other applications -- Check Windows Print Spooler service - -### Log Files - -Check these locations for troubleshooting: - -| Component | Log Location | -|-----------|--------------| -| **Windows Service** | `print_service.log` (same folder as service) | -| **Chrome Extension** | Chrome DevTools → Extensions → Background page | -| **Windows Event Log** | Event Viewer → Windows Logs → System | - -### Diagnostic Commands - -```bash -# Check service status -python service_manager.py status - -# Test API manually -curl http://localhost:8765/health - -# List available printers -curl http://localhost:8765/printers - -# Check Windows service -sc query QualityRecticelPrintService - -# Check listening ports -netstat -an | findstr :8765 -``` - -## 🔄 Maintenance - -### Updating the Service - -1. Stop the current service: -```bash -python service_manager.py stop -``` - -2. Replace service files with new versions - -3. Restart the service: -```bash -python service_manager.py start -``` - -### Uninstalling - -#### Remove Chrome Extension -1. Go to `chrome://extensions/` -2. Find "Quality Recticel Print Service" -3. Click "Remove" - -#### Remove Windows Service -```bash -# Run as Administrator -python service_manager.py uninstall -``` - -#### Remove Firewall Rule -```bash -netsh advfirewall firewall delete rule name="Quality Recticel Print Service" -``` - -## 📞 Support Information - -### API Endpoints Reference - -| Endpoint | Method | Purpose | -|----------|--------|---------| -| `/health` | GET | Service health check | -| `/printers` | GET | List available printers | -| `/print/pdf` | POST | Print PDF from URL | -| `/print/silent` | POST | Silent print with metadata | - -### Request Examples - -**Silent Print Request**: -```json -POST /print/silent -{ - "pdf_url": "http://localhost:5000/generate_labels_pdf/123", - "printer_name": "default", - "copies": 1, - "silent": true, - "order_id": "123", - "quantity": "10" -} -``` - -**Expected Response**: -```json -{ - "success": true, - "message": "Print job sent successfully", - "job_id": "print_20250921_103000", - "printer": "HP LaserJet Pro", - "timestamp": "2025-09-21T10:30:00" -} -``` - -## 📚 Technical Details - -### Service Architecture -- **Framework**: Flask (Python) -- **Service Type**: Windows Service (pywin32) -- **Communication**: HTTP REST API + Native Messaging -- **Security**: Localhost binding only (127.0.0.1:8765) - -### Chrome Extension Architecture -- **Manifest Version**: 3 -- **Service Worker**: Handles background print requests -- **Content Script**: Integrates with Quality Recticel web pages -- **Native Messaging**: Communicates with Windows service - -### Security Considerations -- Service only accepts local connections (localhost) -- No external network access required -- Chrome extension runs in sandboxed environment -- Windows service runs with system privileges (required for printing) - ---- - -## 📋 Quick Start Checklist - -- [ ] Download `windows_print_service` folder -- [ ] Right-click `install_service.bat` → "Run as administrator" -- [ ] Install Chrome extension from `chrome_extension` folder -- [ ] Verify service at `http://localhost:8765/health` -- [ ] Test printing from Quality Recticel web application - -**Installation Time**: ~5 minutes -**User Training Required**: Minimal (automatic detection and fallback) -**Maintenance**: Zero (auto-starts with Windows) - -For additional support, check the log files and diagnostic commands listed above. \ No newline at end of file diff --git a/old code/documentation/QUICK_SETUP.md b/old code/documentation/QUICK_SETUP.md deleted file mode 100755 index e48da2b..0000000 --- a/old code/documentation/QUICK_SETUP.md +++ /dev/null @@ -1,69 +0,0 @@ -# 🚀 Quality Recticel Print Service - Quick Setup - -## 📦 What You Get -- **Silent PDF Printing** - No more manual downloads! -- **Automatic Detection** - Smart fallback when service unavailable -- **Zero Configuration** - Works out of the box - -## ⚡ 2-Minute Installation - -### Step 1: Install Windows Service -1. **Right-click** `install_service.bat` -2. Select **"Run as administrator"** -3. Click **"Yes"** and wait for completion - -### Step 2: Install Chrome Extension -1. Open Chrome → `chrome://extensions/` -2. Enable **"Developer mode"** -3. Click **"Load unpacked"** → Select `chrome_extension` folder - -### Step 3: Verify Installation -- Visit: `http://localhost:8765/health` -- Should see: `{"status": "healthy"}` - -## 🎯 How It Works - -| Service Status | Button Appearance | What Happens | -|---------------|-------------------|--------------| -| **Running** ✅ | 🖨️ **Print Labels (Silent)** (Green) | Direct printing | -| **Not Running** ❌ | 📄 **Generate PDF** (Blue) | PDF download | - -## ⚠️ Troubleshooting - -| Problem | Solution | -|---------|----------| -| **Service won't start** | Run `install_service.bat` as Administrator | -| **Chrome extension not working** | Reload extension in `chrome://extensions/` | -| **Can't connect to localhost:8765** | Check Windows Firewall (port 8765) | -| **Nothing prints** | Verify default printer is set up | - -## 🔧 Management Commands - -```bash -# Check service status -python service_manager.py status - -# Restart service -python service_manager.py restart - -# Uninstall service -python service_manager.py uninstall -``` - -## 📍 Important Notes - -- ⚡ **Auto-starts** with Windows - no manual intervention needed -- 🔒 **Local only** - service only accessible from same computer -- 🖨️ **Uses default printer** - configure your default printer in Windows -- 💾 **Don't move files** after installation - keep folder in same location - -## 🆘 Quick Support - -**Service API**: `http://localhost:8765` -**Health Check**: `http://localhost:8765/health` -**Printer List**: `http://localhost:8765/printers` - -**Log File**: `print_service.log` (same folder as installation) - ---- -*Installation takes ~5 minutes • Zero maintenance required • Works with existing Quality Recticel web application* \ No newline at end of file diff --git a/old code/documentation/README.md b/old code/documentation/README.md deleted file mode 100755 index 01a49f3..0000000 --- a/old code/documentation/README.md +++ /dev/null @@ -1,348 +0,0 @@ -# Quality Recticel Windows Print Service - -## 🏗️ Technical Architecture - -Local Windows service providing REST API for silent PDF printing via Chrome extension integration. - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Quality Recticel Web App │ -│ (print_module.html) │ -└─────────────────────┬───────────────────────────────────────┘ - │ HTTP Request - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Windows Print Service │ -│ (localhost:8765) │ -│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │ -│ │ Flask │ │ CORS │ │ PDF Handler │ │ -│ │ Server │ │ Support │ │ │ │ -│ └─────────────┘ └──────────────┘ └─────────────────┘ │ -└─────────────────────┬───────────────────────────────────────┘ - │ Native Messaging - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Chrome Extension │ -│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │ -│ │ Background │ │ Content │ │ Popup │ │ -│ │ Service │ │ Script │ │ UI │ │ -│ │ Worker │ │ │ │ │ │ -│ └─────────────┘ └──────────────┘ └─────────────────┘ │ -└─────────────────────┬───────────────────────────────────────┘ - │ Windows API - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Windows Print System │ -└─────────────────────────────────────────────────────────────┘ -``` - -## 📁 Project Structure - -``` -windows_print_service/ -├── 📄 print_service.py # Main Flask service -├── 📄 service_manager.py # Windows service wrapper -├── 📄 install_service.bat # Installation script -├── 📄 INSTALLATION_GUIDE.md # Complete documentation -├── 📄 QUICK_SETUP.md # User quick reference -├── 📄 README.md # This file -└── 📁 chrome_extension/ # Chrome extension - ├── 📄 manifest.json # Extension manifest v3 - ├── 📄 background.js # Service worker - ├── 📄 content.js # Page content integration - ├── 📄 popup.html # Extension popup UI - ├── 📄 popup.js # Popup functionality - └── 📁 icons/ # Extension icons -``` - -## 🚀 API Endpoints - -### Base URL: `http://localhost:8765` - -| Endpoint | Method | Description | Request Body | Response | -|----------|--------|-------------|--------------|----------| -| `/health` | GET | Service health check | None | `{"status": "healthy", ...}` | -| `/printers` | GET | List available printers | None | `{"printers": [...]}` | -| `/print/pdf` | POST | Print PDF from URL | `{"url": "...", "printer": "..."}` | `{"success": true, ...}` | -| `/print/silent` | POST | Silent print with metadata | `{"pdf_url": "...", "order_id": "..."}` | `{"success": true, ...}` | - -### Example API Usage - -```javascript -// Health Check -const health = await fetch('http://localhost:8765/health'); -const status = await health.json(); - -// Silent Print -const printRequest = { - pdf_url: 'http://localhost:5000/generate_labels_pdf/123', - printer_name: 'default', - copies: 1, - silent: true, - order_id: '123', - quantity: '10' -}; - -const response = await fetch('http://localhost:8765/print/silent', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify(printRequest) -}); -``` - -## 🔧 Development Setup - -### Prerequisites -- Python 3.8+ -- Windows 10/11 -- Chrome Browser -- Administrator privileges - -### Local Development - -```bash -# Clone/download the project -cd windows_print_service - -# Install dependencies -pip install flask flask-cors requests pywin32 - -# Run development server (not as service) -python print_service.py - -# Install as Windows service -python service_manager.py install - -# Service management -python service_manager.py start -python service_manager.py stop -python service_manager.py restart -python service_manager.py uninstall -``` - -### Chrome Extension Development - -```bash -# Load extension in Chrome -chrome://extensions/ → Developer mode ON → Load unpacked - -# Debug extension -chrome://extensions/ → Details → Background page (for service worker) -chrome://extensions/ → Details → Inspect views (for popup) -``` - -## 📋 Configuration - -### Service Configuration (`print_service.py`) - -```python -class WindowsPrintService: - def __init__(self, host='127.0.0.1', port=8765): - self.host = host # Localhost binding only - self.port = port # Service port - self.app = Flask(__name__) -``` - -### Chrome Extension Permissions (`manifest.json`) - -```json -{ - "permissions": [ - "printing", // Access to printer API - "nativeMessaging", // Communication with Windows service - "activeTab", // Current tab access - "storage" // Extension settings storage - ] -} -``` - -## 🔄 Integration Flow - -### 1. Service Detection -```javascript -// Web page detects service availability -const isServiceAvailable = await checkServiceHealth(); -updatePrintButton(isServiceAvailable); -``` - -### 2. Print Request Flow -``` -User clicks print → Web app → Windows service → Chrome extension → Printer -``` - -### 3. Fallback Mechanism -``` -Service unavailable → Fallback to PDF download → Manual printing -``` - -## 🛠️ Customization - -### Adding New Print Options - -```python -# In print_service.py -@app.route('/print/custom', methods=['POST']) -def print_custom(): - data = request.json - # Custom print logic here - return jsonify({'success': True}) -``` - -### Modifying Chrome Extension - -```javascript -// In background.js - Add new message handler -chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { - if (message.type === 'CUSTOM_PRINT') { - // Custom print logic - } -}); -``` - -### Web Application Integration - -```javascript -// In print_module.html - Modify print function -async function customPrintFunction(orderId) { - const response = await fetch('http://localhost:8765/print/custom', { - method: 'POST', - body: JSON.stringify({orderId, customOptions: {...}}) - }); -} -``` - -## 🧪 Testing - -### Unit Tests (Future Enhancement) - -```python -# test_print_service.py -import unittest -from print_service import WindowsPrintService - -class TestPrintService(unittest.TestCase): - def test_health_endpoint(self): - # Test implementation - pass -``` - -### Manual Testing Checklist - -- [ ] Service starts automatically on Windows boot -- [ ] API endpoints respond correctly -- [ ] Chrome extension loads without errors -- [ ] Print jobs execute successfully -- [ ] Fallback works when service unavailable -- [ ] Firewall allows port 8765 traffic - -## 📊 Monitoring & Logging - -### Log Files -- **Service Log**: `print_service.log` (Flask application logs) -- **Windows Event Log**: Windows Services logs -- **Chrome DevTools**: Extension console logs - -### Health Monitoring - -```python -# Monitor service health -import requests -try: - response = requests.get('http://localhost:8765/health', timeout=5) - if response.status_code == 200: - print("✅ Service healthy") -except: - print("❌ Service unavailable") -``` - -## 🔒 Security Considerations - -### Network Security -- **Localhost Only**: Service binds to 127.0.0.1 (no external access) -- **No Authentication**: Relies on local machine security -- **Firewall Rule**: Port 8765 opened for local connections only - -### Chrome Extension Security -- **Manifest V3**: Latest security standards -- **Minimal Permissions**: Only necessary permissions requested -- **Sandboxed**: Runs in Chrome's security sandbox - -### Windows Service Security -- **System Service**: Runs with appropriate Windows service privileges -- **Print Permissions**: Requires printer access (normal for print services) - -## 🚀 Deployment - -### Production Deployment - -1. **Package Distribution**: -```bash -# Create deployment package -zip -r quality_recticel_print_service.zip windows_print_service/ -``` - -2. **Installation Script**: Use `install_service.bat` for end users - -3. **Group Policy Deployment**: Deploy Chrome extension via enterprise policies - -### Enterprise Considerations - -- **Silent Installation**: Modify `install_service.bat` for unattended install -- **Registry Deployment**: Pre-configure Chrome extension registry entries -- **Network Policies**: Ensure firewall policies allow localhost:8765 - -## 📚 Dependencies - -### Python Packages -``` -flask>=2.3.0 # Web framework -flask-cors>=4.0.0 # CORS support -requests>=2.31.0 # HTTP client -pywin32>=306 # Windows service integration -``` - -### Chrome APIs -- `chrome.printing.*` - Printing functionality -- `chrome.runtime.*` - Extension messaging -- `chrome.nativeMessaging.*` - Native app communication - -## 🐛 Debugging - -### Common Debug Commands - -```bash -# Check service status -sc query QualityRecticelPrintService - -# Test API manually -curl http://localhost:8765/health - -# Check listening ports -netstat -an | findstr :8765 - -# View service logs -type print_service.log -``` - -### Chrome Extension Debugging - -```javascript -// In background.js - Add debug logging -console.log('Print request received:', message); - -// In popup.js - Test API connection -fetch('http://localhost:8765/health') - .then(r => r.json()) - .then(data => console.log('Service status:', data)); -``` - ---- - -## 📄 License & Support - -**Project**: Quality Recticel Print Service -**Version**: 1.0 -**Compatibility**: Windows 10/11, Chrome 88+ -**Maintenance**: Zero-maintenance after installation - -For technical support, refer to `INSTALLATION_GUIDE.md` troubleshooting section. \ No newline at end of file diff --git a/old code/external_database_settings b/old code/external_database_settings deleted file mode 100755 index ce3855e..0000000 --- a/old code/external_database_settings +++ /dev/null @@ -1,5 +0,0 @@ -Server Domain/IP Address: testserver.com -Port: 3602 -Database Name: recticel -Username: sa -Password: 12345678 diff --git a/old code/migrate_external_db.py b/old code/migrate_external_db.py deleted file mode 100644 index 28afeff..0000000 --- a/old code/migrate_external_db.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to add modules column to external database and migrate existing users -""" - -import os -import sys -import mariadb - -def migrate_external_database(): - """Add modules column to external database and update existing users""" - try: - # Read external database configuration from instance folder - config_file = os.path.join(os.path.dirname(__file__), 'instance/external_server.conf') - if not os.path.exists(config_file): - print("External database configuration file not found at instance/external_server.conf") - return False - - with open(config_file, 'r') as f: - lines = f.read().strip().split('\n') - - # Parse the config file format "key=value" - config = {} - for line in lines: - if '=' in line and not line.strip().startswith('#'): - key, value = line.split('=', 1) - config[key.strip()] = value.strip() - - host = config.get('server_domain', 'localhost') - port = int(config.get('port', '3306')) - database = config.get('database_name', '') - user = config.get('username', '') - password = config.get('password', '') - - if not all([host, database, user, password]): - print("Missing required database configuration values.") - return False - - print(f"Connecting to external database: {host}:{port}/{database}") - - # Connect to external database - conn = mariadb.connect( - user=user, - password=password, - host=host, - port=port, - database=database - ) - cursor = conn.cursor() - - # Check if users table exists - cursor.execute("SHOW TABLES LIKE 'users'") - if not cursor.fetchone(): - print("Users table not found in external database.") - conn.close() - return False - - # Check if modules column already exists - cursor.execute("DESCRIBE users") - columns = [row[0] for row in cursor.fetchall()] - - if 'modules' not in columns: - print("Adding modules column to users table...") - cursor.execute("ALTER TABLE users ADD COLUMN modules TEXT") - print("Modules column added successfully.") - else: - print("Modules column already exists.") - - # Get current users and convert their roles - cursor.execute("SELECT id, username, role FROM users") - users = cursor.fetchall() - - role_mapping = { - 'superadmin': ('superadmin', None), - 'administrator': ('admin', None), - 'admin': ('admin', None), - 'quality': ('manager', '["quality"]'), - 'warehouse': ('manager', '["warehouse"]'), - 'warehouse_manager': ('manager', '["warehouse"]'), - 'scan': ('worker', '["quality"]'), - 'etichete': ('manager', '["labels"]'), - 'quality_manager': ('manager', '["quality"]'), - 'quality_worker': ('worker', '["quality"]'), - } - - print(f"Migrating {len(users)} users...") - - for user_id, username, old_role in users: - if old_role in role_mapping: - new_role, modules_json = role_mapping[old_role] - - cursor.execute("UPDATE users SET role = ?, modules = ? WHERE id = ?", - (new_role, modules_json, user_id)) - - print(f" {username}: {old_role} -> {new_role} with modules {modules_json}") - else: - print(f" {username}: Unknown role '{old_role}', keeping as-is") - - conn.commit() - conn.close() - - print("External database migration completed successfully!") - return True - - except Exception as e: - print(f"Error migrating external database: {e}") - return False - -if __name__ == "__main__": - print("External Database Migration for Simplified 4-Tier Permission System") - print("=" * 70) - - success = migrate_external_database() - - if success: - print("\n✅ Migration completed successfully!") - print("\nUsers can now log in with the new simplified permission system.") - print("Role structure: superadmin → admin → manager → worker") - print("Modules: quality, warehouse, labels") - else: - print("\n❌ Migration failed. Please check the error messages above.") \ No newline at end of file diff --git a/old code/migrate_permissions.py b/old code/migrate_permissions.py deleted file mode 100755 index ad39d86..0000000 --- a/old code/migrate_permissions.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python3 -""" -Migration script to convert from complex permission system to simplified 4-tier system -This script will: -1. Add 'modules' column to users table -2. Convert existing roles to new 4-tier system -3. Assign appropriate modules based on old roles -""" - -import sqlite3 -import json -import os -import sys - -# Add the app directory to Python path -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) - -def get_db_connections(): - """Get both internal SQLite and external database connections""" - connections = {} - - # Internal SQLite database - internal_db_path = os.path.join(os.path.dirname(__file__), 'instance/users.db') - if os.path.exists(internal_db_path): - connections['internal'] = sqlite3.connect(internal_db_path) - print(f"Connected to internal SQLite database: {internal_db_path}") - - # External database (try to connect using existing method) - try: - import mariadb - - # Read external database configuration - config_file = os.path.join(os.path.dirname(__file__), '../external_database_settings') - if os.path.exists(config_file): - with open(config_file, 'r') as f: - lines = f.read().strip().split('\n') - if len(lines) >= 5: - host = lines[0].strip() - port = int(lines[1].strip()) - database = lines[2].strip() - user = lines[3].strip() - password = lines[4].strip() - - conn = mariadb.connect( - user=user, - password=password, - host=host, - port=port, - database=database - ) - connections['external'] = conn - print(f"Connected to external MariaDB database: {host}:{port}/{database}") - except Exception as e: - print(f"Could not connect to external database: {e}") - - return connections - -def role_mapping(): - """Map old roles to new 4-tier system""" - return { - # Old role -> (new_role, modules) - 'superadmin': ('superadmin', []), # All modules by default - 'administrator': ('admin', []), # All modules by default - 'admin': ('admin', []), # All modules by default - 'quality': ('manager', ['quality']), - 'warehouse': ('manager', ['warehouse']), - 'warehouse_manager': ('manager', ['warehouse']), - 'scan': ('worker', ['quality']), # Assume scan users are quality workers - 'etichete': ('manager', ['labels']), - 'quality_manager': ('manager', ['quality']), - 'quality_worker': ('worker', ['quality']), - } - -def migrate_database(conn, db_type): - """Migrate a specific database""" - cursor = conn.cursor() - - print(f"Migrating {db_type} database...") - - # Check if users table exists - if db_type == 'internal': - cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users'") - else: # external/MariaDB - cursor.execute("SHOW TABLES LIKE 'users'") - - if not cursor.fetchone(): - print(f"No users table found in {db_type} database") - return - - # Check if modules column already exists - try: - if db_type == 'internal': - cursor.execute("PRAGMA table_info(users)") - columns = [row[1] for row in cursor.fetchall()] - else: # external/MariaDB - cursor.execute("DESCRIBE users") - columns = [row[0] for row in cursor.fetchall()] - - if 'modules' not in columns: - print(f"Adding modules column to {db_type} database...") - if db_type == 'internal': - cursor.execute("ALTER TABLE users ADD COLUMN modules TEXT") - else: # external/MariaDB - cursor.execute("ALTER TABLE users ADD COLUMN modules TEXT") - else: - print(f"Modules column already exists in {db_type} database") - - except Exception as e: - print(f"Error checking/adding modules column in {db_type}: {e}") - return - - # Get current users - cursor.execute("SELECT id, username, role FROM users") - users = cursor.fetchall() - - print(f"Found {len(users)} users in {db_type} database") - - # Convert roles and assign modules - mapping = role_mapping() - updates = [] - - for user_id, username, old_role in users: - if old_role in mapping: - new_role, modules = mapping[old_role] - modules_json = json.dumps(modules) if modules else None - updates.append((new_role, modules_json, user_id, username)) - print(f" {username}: {old_role} -> {new_role} with modules {modules}") - else: - print(f" {username}: Unknown role '{old_role}', keeping as-is") - - # Apply updates - for new_role, modules_json, user_id, username in updates: - try: - cursor.execute("UPDATE users SET role = ?, modules = ? WHERE id = ?", - (new_role, modules_json, user_id)) - print(f" Updated {username} successfully") - except Exception as e: - print(f" Error updating {username}: {e}") - - conn.commit() - print(f"Migration completed for {db_type} database") - -def main(): - """Main migration function""" - print("Starting migration to simplified 4-tier permission system...") - print("="*60) - - connections = get_db_connections() - - if not connections: - print("No database connections available. Please check your configuration.") - return - - for db_type, conn in connections.items(): - try: - migrate_database(conn, db_type) - print() - except Exception as e: - print(f"Error migrating {db_type} database: {e}") - finally: - conn.close() - - print("Migration completed!") - print("\nNew role structure:") - print("- superadmin: Full system access") - print("- admin: Full app access (except role_permissions and download_extension)") - print("- manager: Module-based access (can have multiple modules)") - print("- worker: Limited module access (one module only)") - print("\nAvailable modules: quality, warehouse, labels") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/old code/qz-tray-PATCH-NOTES.txt b/old code/qz-tray-PATCH-NOTES.txt deleted file mode 100755 index 2d7fd27..0000000 --- a/old code/qz-tray-PATCH-NOTES.txt +++ /dev/null @@ -1,35 +0,0 @@ -QZ TRAY LIBRARY PATCH NOTES -=========================== -Version: 2.2.4 (patched for custom QZ Tray with pairing key authentication) -Date: October 2, 2025 - -CHANGES MADE: -------------- - -1. Line ~387: Commented out certificate sending - - Original: _qz.websocket.connection.sendData({ certificate: cert, promise: openPromise }); - - Patched: openPromise.resolve(); (resolves immediately without sending certificate) - -2. Line ~391-403: Bypassed certificate retrieval - - Original: Called _qz.security.callCert() to get certificate from user - - Patched: Directly calls sendCert(null) without trying to get certificate - -3. Comments added to indicate patches - -REASON FOR PATCHES: ------------------- -The custom QZ Tray server has certificate validation COMPLETELY DISABLED. -It uses ONLY pairing key (HMAC) authentication instead of certificates. -The original qz-tray.js library expects certificate-based authentication and -fails when the server doesn't respond to certificate requests. - -COMPATIBILITY: -------------- -- Works with custom QZ Tray server (forked version with certificate validation disabled) -- NOT compatible with standard QZ Tray servers -- Connects to both ws://localhost:8181 and wss://localhost:8182 -- Authentication handled by server-side pairing keys - -BACKUP: -------- -Original unpatched version saved as: qz-tray.js.backup diff --git a/old code/recticel-app.service b/old code/recticel-app.service deleted file mode 100644 index 46b9361..0000000 --- a/old code/recticel-app.service +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=Recticel Quality App -After=network.target mariadb.service - -[Service] -Type=simple -User=ske087 -WorkingDirectory=/home/ske087/quality_recticel -Environment=PATH=/home/ske087/quality_recticel/recticel/bin -ExecStart=/home/ske087/quality_recticel/recticel/bin/python py_app/run.py -Restart=always -RestartSec=10 - -[Install] -WantedBy=multi-user.target \ No newline at end of file diff --git a/old code/role_permissions.html b/old code/role_permissions.html deleted file mode 100755 index 5d03e90..0000000 --- a/old code/role_permissions.html +++ /dev/null @@ -1,454 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Role Permissions Management{% endblock %} - -{% block head %} - -{% endblock %} - -{% block content %} -
-
-

- 🔐 Role Permissions Management -

-

- Configure granular access permissions for each role in the system -

-
- - -
- - - - - - - - - - - {% set current_role = '' %} - {% set current_module = '' %} - {% for role_name, role_data in roles.items() %} - {% for page_key, page_data in pages.items() %} - {% for section_key, section_data in page_data.sections.items() %} - - - {% if current_role != role_name %} - {% set current_role = role_name %} - - - - {% endif %} - - - {% if current_module != page_key %} - {% set current_module = page_key %} - - - - - {% endif %} - - - - - - - - {% endfor %} - {% set current_module = '' %} - {% endfor %} - {% endfor %} - -
👤 Role Name🏢 Module Name📄 Page Name⚙️ Functions & Permissions
-
- {{ role_data.display_name }} (Level {{ role_data.level }}) -
-
-
- {{ page_data.name }} -
-
-
- 👤 - {{ role_data.display_name }} -
-
- {{ page_data.name }} - -
- 📋 - {{ section_data.name }} -
-
-
- {% for action in section_data.actions %} - {% set permission_key = page_key + '.' + section_key + '.' + action %} -
- - {{ action_names[action] }} -
- {% endfor %} -
-
-
- - -
-
- - -
-
-
- - -{% endblock %} \ No newline at end of file diff --git a/old code/test_permissions.py b/old code/test_permissions.py deleted file mode 100644 index 4753243..0000000 --- a/old code/test_permissions.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python3 -""" -Test script for the new simplified 4-tier permission system -""" - -import sys -import os -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'app')) - -from permissions_simple import check_access, validate_user_modules, get_user_accessible_pages - -def test_permission_system(): - """Test the new permission system with various scenarios""" - print("Testing Simplified 4-Tier Permission System") - print("=" * 50) - - # Test cases: (role, modules, page, expected_result) - test_cases = [ - # Superadmin tests - ('superadmin', [], 'dashboard', True), - ('superadmin', [], 'role_permissions', True), - ('superadmin', [], 'quality', True), - ('superadmin', [], 'warehouse', True), - - # Admin tests - ('admin', [], 'dashboard', True), - ('admin', [], 'role_permissions', False), # Restricted for admin - ('admin', [], 'download_extension', False), # Restricted for admin - ('admin', [], 'quality', True), - ('admin', [], 'warehouse', True), - - # Manager tests - ('manager', ['quality'], 'quality', True), - ('manager', ['quality'], 'quality_reports', True), - ('manager', ['quality'], 'warehouse', False), # No warehouse module - ('manager', ['warehouse'], 'warehouse', True), - ('manager', ['warehouse'], 'quality', False), # No quality module - ('manager', ['quality', 'warehouse'], 'quality', True), # Multiple modules - ('manager', ['quality', 'warehouse'], 'warehouse', True), - - # Worker tests - ('worker', ['quality'], 'quality', True), - ('worker', ['quality'], 'quality_reports', False), # Workers can't access reports - ('worker', ['quality'], 'warehouse', False), # No warehouse module - ('worker', ['warehouse'], 'move_orders', True), - ('worker', ['warehouse'], 'create_locations', False), # Workers can't create locations - - # Invalid role test - ('invalid_role', ['quality'], 'quality', False), - ] - - print("Testing access control:") - print("-" * 30) - - passed = 0 - failed = 0 - - for role, modules, page, expected in test_cases: - result = check_access(role, modules, page) - status = "PASS" if result == expected else "FAIL" - print(f"{status}: {role:12} {str(modules):20} {page:18} -> {result} (expected {expected})") - - if result == expected: - passed += 1 - else: - failed += 1 - - print(f"\nResults: {passed} passed, {failed} failed") - - # Test module validation - print("\nTesting module validation:") - print("-" * 30) - - validation_tests = [ - ('superadmin', ['quality'], True), # Superadmin can have any modules - ('admin', ['warehouse'], True), # Admin can have any modules - ('manager', ['quality'], True), # Manager can have one module - ('manager', ['quality', 'warehouse'], True), # Manager can have multiple modules - ('manager', [], False), # Manager must have at least one module - ('worker', ['quality'], True), # Worker can have one module - ('worker', ['quality', 'warehouse'], False), # Worker cannot have multiple modules - ('worker', [], False), # Worker must have exactly one module - ('invalid_role', ['quality'], False), # Invalid role - ] - - for role, modules, expected in validation_tests: - is_valid, error_msg = validate_user_modules(role, modules) - status = "PASS" if is_valid == expected else "FAIL" - print(f"{status}: {role:12} {str(modules):20} -> {is_valid} (expected {expected})") - if error_msg: - print(f" Error: {error_msg}") - - # Test accessible pages for different users - print("\nTesting accessible pages:") - print("-" * 30) - - user_tests = [ - ('superadmin', []), - ('admin', []), - ('manager', ['quality']), - ('manager', ['warehouse']), - ('worker', ['quality']), - ('worker', ['warehouse']), - ] - - for role, modules in user_tests: - accessible_pages = get_user_accessible_pages(role, modules) - print(f"{role:12} {str(modules):20} -> {len(accessible_pages)} pages: {', '.join(accessible_pages[:5])}{'...' if len(accessible_pages) > 5 else ''}") - -if __name__ == "__main__": - test_permission_system() \ No newline at end of file diff --git a/old code/to_do.txt b/old code/to_do.txt deleted file mode 100755 index a71112b..0000000 --- a/old code/to_do.txt +++ /dev/null @@ -1,23 +0,0 @@ -python3 -m venv recticel -source recticel/bin/activate - python /home/ske087/quality_recticel/py_app/run.py - -sudo apt install mariadb-server mariadb-client -sudo apt-get install libmariadb-dev libmariadb-dev-compat - - sudo mysql -u root -p - - root password : Initaial01! acasa Matei@123 - - CREATE DATABASE trasabilitate_database; - CREATE USER 'trasabilitate'@'localhost' IDENTIFIED BY 'Initial01!'; - GRANT ALL PRIVILEGES ON trasabilitate_database.* TO 'trasabilitate'@'localhost'; - FLUSH PRIVILEGES; - EXIT - - - Server Domain/IP Address: testserver.com -Port: 3602 -Database Name: recticel -Username: sa -Password: 12345678 diff --git a/old code/to_do_install.txt b/old code/to_do_install.txt deleted file mode 100644 index e996dc8..0000000 --- a/old code/to_do_install.txt +++ /dev/null @@ -1,32 +0,0 @@ - -# Steps to Prepare Environment for Installing Python Requirements - -1. Change ownership of the project directory (if needed): - sudo chown -R $USER:$USER /home/ske087/quality_recticel - -2. Install Python venv module: - sudo apt install -y python3-venv - -3. Create and activate the virtual environment: - python3 -m venv recticel - source recticel/bin/activate - -4. Install MariaDB server and development libraries: - sudo apt install -y mariadb-server libmariadb-dev - -5. Create MariaDB database and user: - sudo mysql -e "CREATE DATABASE trasabilitate; CREATE USER 'sa'@'localhost' IDENTIFIED BY 'qasdewrftgbcgfdsrytkmbf\"b'; GRANT ALL PRIVILEGES ON quality.* TO 'sa'@'localhost'; FLUSH PRIVILEGES;" - sa - qasdewrftgbcgfdsrytkmbf\"b - - trasabilitate - Initial01! - -6. Install build tools (for compiling Python packages): - sudo apt install -y build-essential - -7. Install Python development headers: - sudo apt install -y python3-dev - -8. Install Python requirements: - pip install -r py_app/requirements.txt diff --git a/old code/tray/.github/workflows/build.yaml b/old code/tray/.github/workflows/build.yaml deleted file mode 100755 index 787177a..0000000 --- a/old code/tray/.github/workflows/build.yaml +++ /dev/null @@ -1,60 +0,0 @@ -name: build - -on: [push, pull_request] - -jobs: - ubuntu: - runs-on: [ubuntu-latest] - strategy: - matrix: - java: [11, 21] - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - java-version: ${{ matrix.java }} - distribution: 'liberica' - - run: sudo apt-get install nsis makeself - - run: ant makeself - - run: sudo out/qz-tray-*.run - - run: /opt/qz-tray/qz-tray --version - - run: ant nsis - - macos: - runs-on: [macos-latest] - strategy: - matrix: - java: [11, 21] - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - java-version: ${{ matrix.java }} - distribution: 'liberica' - - run: brew install nsis makeself - - run: ant pkgbuild - - run: echo "Setting CA trust settings to 'allow' (https://github.com/actions/runner-images/issues/4519)" - - run: security authorizationdb read com.apple.trust-settings.admin > /tmp/trust-settings-backup.xml - - run: sudo security authorizationdb write com.apple.trust-settings.admin allow - - run: sudo installer -pkg out/qz-tray-*.pkg -target / - - run: echo "Restoring CA trust settings back to default" - - run: sudo security authorizationdb write com.apple.trust-settings.admin < /tmp/trust-settings-backup.xml - - run: "'/Applications/QZ Tray.app/Contents/MacOS/QZ Tray' --version" - - run: ant makeself - - run: ant nsis - - windows: - runs-on: [windows-latest] - strategy: - matrix: - java: [11, 21] - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - java-version: ${{ matrix.java }} - distribution: 'liberica' - - run: choco install nsis - - run: ant nsis - - run: Start-Process -Wait ./out/qz-tray-*.exe -ArgumentList "/S" - - run: "&'C:/Program Files/QZ Tray/qz-tray.exe' --wait --version|Out-Null" diff --git a/old code/tray/.gitignore b/old code/tray/.gitignore deleted file mode 100755 index 39cea5e..0000000 --- a/old code/tray/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# Build outputs -/out/ -*.class - -# Node modules -/js/node_modules - -# JavaFX runtime (too large, should be downloaded) -/lib/javafx* - -# IDE files -/.idea/workspace.xml -/.idea/misc.xml -/.idea/uiDesigner.xml -/.idea/compiler.xml -.idea/ -*.iml -.vscode/ - -# OS files -.DS_Store -Thumbs.db -windows-debug-launcher.nsi.in - -# Build artifacts -/fx.zip -/provision.json - -# Private keys -/ant/private/qz.ks - -# Logs -*.log diff --git a/old code/tray/Dockerfile b/old code/tray/Dockerfile deleted file mode 100755 index 15c1973..0000000 --- a/old code/tray/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM openjdk:11 as build -RUN apt-get update -RUN apt-get install -y ant nsis makeself -COPY . /usr/src/tray -WORKDIR /usr/src/tray -RUN ant makeself - -FROM openjdk:11-jre as install -RUN apt-get update -RUN apt-get install -y libglib2.0-bin -COPY --from=build /usr/src/tray/out/*.run /tmp -RUN find /tmp -iname "*.run" -exec {} \; -WORKDIR /opt/qz-tray -ENTRYPOINT ["/opt/qz-tray/qz-tray"] \ No newline at end of file diff --git a/old code/tray/LICENSE.txt b/old code/tray/LICENSE.txt deleted file mode 100755 index 1cc0a30..0000000 --- a/old code/tray/LICENSE.txt +++ /dev/null @@ -1,601 +0,0 @@ - ATTRIBUTION, LICENSING AND SUMMARY OF COMPONENTS - Version 1.2, February 2016 - -Project Source Code (unless otherwise specified): - Copyright (c) 2013-2016 QZ Industries, LLC - LGPL-2.1 License (attached) - https://qz.io - -All API Examples (unless otherwise specified): - Covers: JavaScript examples, Wiki API Examples, Signing API Examples - Public Domain (no restrictions) -______________________________________________________________________ - -Other licenses: - -jOOR Reflection Library (As-Is, No Modifications) - Copyright (c) 2011-2012, Lukas Eder, lukas.eder@gmail.com - Apache License, Version 2.0 (attached), with Copyright Notice - https://github.com/jOOQ/jOOR - - -jetty Web Server Library (As-Is, No Modifications) - Copyright (c) 1995-2014 Eclipse Foundation - Apache License, Version 2.0 (attached), with Copyright Notice - http://eclipse.org/jetty/ - - -Apache log4j (As-Is, No Modifications) - Copyright (C) 1999-2005 The Apache Software Foundation - Apache License, Version 2.0 (attached), with Copyright Notice - https://logging.apache.org/ - - -Apache PDFBox (As-Is, No Modifications) - Copyright (C) 2009–2015 The Apache Software Foundation - Apache License, Version 2.0 (attached), with Copyright Notice - https://pdfbox.apache.org/ - - -jSSC Library (As-Is, No Modifications) - Copyright (c) 2010-2013 Alexey Sokolov (scream3r) - LGPL-2.1 License (attached), with Copyright notice - https://code.google.com/p/java-simple-serial-connector/ - - -hid4java (As-Is, No Modifications) - Copyright (c) 2014 Gary Rowe - MIT License (attached), with Copyright notice - https://github.com/gary-rowe/hid4java - - -jsemver (As-Is, No Modifications) - Copyright 2012-2014 Zafar Khaja - MIT License (attached), with Copyright notice - https://github.com/zafarkhaja/jsemver -______________________________________________________________________ - - -LGPL 2.1 -Applies ONLY to: qz-tray, jssc - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - USA - -END OF LGPL 2.1 - -______________________________________________________________________ - - -Apache 2.0 -Applies ONLY to: joor, jetty, Apache PDFBox, Apache log4j - - - APACHE LICENSE - Version 2.0, January 2004 - - Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -END OF Apache 2.0 - -______________________________________________________________________ - - -MIT License -Applies ONLY to: hid4java, jsemver - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -END OF MIT License - -______________________________________________________________________ - -END OF ATTRIBUTION, LICENSING AND SUMMARY OF QZ-TRAY COMPONENTS \ No newline at end of file diff --git a/old code/tray/README.md b/old code/tray/README.md deleted file mode 100755 index 1509396..0000000 --- a/old code/tray/README.md +++ /dev/null @@ -1,23 +0,0 @@ -QZ Tray -======== - - [![Build Status](https://github.com/qzind/tray/actions/workflows/build.yaml/badge.svg)](../../actions) [![Downloads](https://img.shields.io/github/downloads/qzind/tray/latest/total.svg)](../../releases) [![Issues](https://img.shields.io/github/issues/qzind/tray.svg)](../../issues) [![Commits](https://img.shields.io/github/commit-activity/m/qzind/tray.svg)](../../commits) - -Browser plugin for sending documents and raw commands to a printer or attached device - -## Getting Started - * Download here https://qz.io/download/ - * See our [Getting Started](../../wiki/getting-started) guide. - * Visit our home page https://qz.io. - -## Support - * File a bug via our [issue tracker](../../issues) - * Ask the community via our [community support page](https://qz.io/support/) - * Ask the developers via [premium support](https://qz.io/contact/) (fees may apply) - -## Changelog - * See our [most recent releases](../../releases) - -## Java Developer Resources - * [Install dependencies](../../wiki/install-dependencies) - * [Compile, Package](../../wiki/compiling) diff --git a/old code/tray/SUPPORT.md b/old code/tray/SUPPORT.md deleted file mode 100755 index a3b79e6..0000000 --- a/old code/tray/SUPPORT.md +++ /dev/null @@ -1,11 +0,0 @@ -Please feel free to open bug reports on GitHub. Before opening an issue, we ask that you consider whether your issue is a support question, or a potential bug with the software. - -If you have a support question, first [check the FAQ](https://qz.io/wiki/faq) and the [wiki](https://qz.io/wiki/Home). If you cannot find a solution please reach out to one of the appropriate channels: - -### Community Support - -If you need assistance using the software and do not have a paid subscription, please reference our community support channel: https://qz.io/support/ - -### Premium Support - -If you have an active support license with QZ Industries, LLC, please send support requests to support@qz.io diff --git a/old code/tray/ant/apple/appdmg.json.in b/old code/tray/ant/apple/appdmg.json.in deleted file mode 100755 index 5fd595a..0000000 --- a/old code/tray/ant/apple/appdmg.json.in +++ /dev/null @@ -1,12 +0,0 @@ -{ - "title": "${project.name}", - "background": "${basedir}/ant/apple/dmg-background.png", - "icon-size": 128, - "contents": [ - { "x": 501, "y": 154, "type": "link", "path": "/Applications" }, - { "x": 179, "y": 154, "type": "file", "path": "${build.dir}/${project.name}.app" } - ], - "code-sign": { - "signing-identity" : "${codesign.activeid}" - } -} diff --git a/old code/tray/ant/apple/apple-bundle.plist.in b/old code/tray/ant/apple/apple-bundle.plist.in deleted file mode 100755 index 5044c4c..0000000 --- a/old code/tray/ant/apple/apple-bundle.plist.in +++ /dev/null @@ -1,28 +0,0 @@ - - - - CFBundleDevelopmentRegionEnglish - CFBundleIconFile${project.filename} - CFBundleIdentifier${apple.bundleid} - CFBundlePackageTypeAPPL - CFBundleGetInfoString${project.name} ${build.version} - CFBundleSignature${project.name} - CFBundleExecutable${project.name} - CFBundleVersion${build.version} - CFBundleShortVersionString${build.version} - CFBundleName${project.name} - CFBundleInfoDictionaryVersion6.0 - CFBundleURLTypes - - - CFBundleURLName - ${project.name} - CFBundleURLSchemes - ${vendor.name} - - - LSArchitecturePriority - - ${apple.target.arch} - - \ No newline at end of file diff --git a/old code/tray/ant/apple/apple-entitlements.plist.in b/old code/tray/ant/apple/apple-entitlements.plist.in deleted file mode 100755 index 8ae1b0e..0000000 --- a/old code/tray/ant/apple/apple-entitlements.plist.in +++ /dev/null @@ -1,30 +0,0 @@ - - - - - com.apple.security.app-sandbox - <${build.sandboxed}/> - com.apple.security.network.client - - com.apple.security.network.server - - com.apple.security.files.all - - com.apple.security.print - - com.apple.security.device.usb - - com.apple.security.device.bluetooth - - com.apple.security.cs.allow-jit - - com.apple.security.cs.allow-unsigned-executable-memory - - com.apple.security.cs.disable-library-validation - - com.apple.security.cs.allow-dyld-environment-variables - - com.apple.security.cs.debugger - - - \ No newline at end of file diff --git a/old code/tray/ant/apple/apple-postinstall.sh.in b/old code/tray/ant/apple/apple-postinstall.sh.in deleted file mode 100755 index 10bf706..0000000 --- a/old code/tray/ant/apple/apple-postinstall.sh.in +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# Halt on first error -set -e - -# Get working directory -DIR=$(cd "$(dirname "$0")" && pwd) -pushd "$DIR/payload/${project.name}.app/Contents/MacOS/" - -./"${project.name}" install >> "${install.log}" 2>&1 -popd - -# Use install target from pkgbuild, an undocumented feature; fallback on sane location -if [ -n "$2" ]; then - pushd "$2/Contents/MacOS/" -else - pushd "/Applications/${project.name}.app/Contents/MacOS/" -fi - -./"${project.name}" certgen >> "${install.log}" 2>&1 - -# Start qz by calling open on the .app as an ordinary user -su "$USER" -c "open ../../" || true \ No newline at end of file diff --git a/old code/tray/ant/apple/apple-preinstall.sh.in b/old code/tray/ant/apple/apple-preinstall.sh.in deleted file mode 100755 index 61091ae..0000000 --- a/old code/tray/ant/apple/apple-preinstall.sh.in +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# Halt on first error -set -e - -# Clear the log for writing -> "${install.log}" - -# Log helper -dbg () { - echo -e "[BASH] $(date -Iseconds)\n\t$1" >> "${install.log}" 2>&1 -} - -# Get working directory -dbg "Calculating working directory..." -DIR=$(cd "$(dirname "$0")" && pwd) -dbg "Using working directory $DIR" -dbg "Switching to payload directory $DIR/payload/${project.name}.app/Contents/MacOS/" -pushd "$DIR/payload/${project.name}.app/Contents/MacOS/" >> "${install.log}" 2>&1 - -# Offer to download Java if missing -dbg "Checking for Java in payload directory..." -if ! ./"${project.name}" --version >> "${install.log}" 2>&1; then - dbg "Java was not found" - osascript -e "tell app \"Installer\" to display dialog \"Java is required. Please install Java and try again.\"" - sudo -u "$USER" open "${java.download}" - exit 1 -fi - -dbg "Java was found in payload directory, running preinstall" -./"${project.name}" preinstall >> "${install.log}" 2>&1 \ No newline at end of file diff --git a/old code/tray/ant/apple/apple.properties b/old code/tray/ant/apple/apple.properties deleted file mode 100755 index 63ee4a2..0000000 --- a/old code/tray/ant/apple/apple.properties +++ /dev/null @@ -1,6 +0,0 @@ -# Apple build properties -apple.packager.signid=P5DMU6659X -# jdk9+ flags -# - Tray icon requires workaround https://github.com/dyorgio/macos-tray-icon-fixer/issues/9 -# - Dark theme requires workaround https://github.com/bobbylight/Darcula/issues/8 -apple.launch.jigsaw=--add-opens java.desktop/sun.lwawt.macosx=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-exports java.desktop/com.apple.laf=ALL-UNNAMED \ No newline at end of file diff --git a/old code/tray/ant/apple/certs/apple-codesign.cer b/old code/tray/ant/apple/certs/apple-codesign.cer deleted file mode 100755 index 25c9d02..0000000 Binary files a/old code/tray/ant/apple/certs/apple-codesign.cer and /dev/null differ diff --git a/old code/tray/ant/apple/certs/apple-intermediate.cer b/old code/tray/ant/apple/certs/apple-intermediate.cer deleted file mode 100755 index 8cbcf6f..0000000 Binary files a/old code/tray/ant/apple/certs/apple-intermediate.cer and /dev/null differ diff --git a/old code/tray/ant/apple/certs/apple-packager.cer b/old code/tray/ant/apple/certs/apple-packager.cer deleted file mode 100755 index e9136d2..0000000 Binary files a/old code/tray/ant/apple/certs/apple-packager.cer and /dev/null differ diff --git a/old code/tray/ant/apple/dmg-background.png b/old code/tray/ant/apple/dmg-background.png deleted file mode 100755 index 12bffe7..0000000 Binary files a/old code/tray/ant/apple/dmg-background.png and /dev/null differ diff --git a/old code/tray/ant/apple/dmg-background@2x.png b/old code/tray/ant/apple/dmg-background@2x.png deleted file mode 100755 index 75a7684..0000000 Binary files a/old code/tray/ant/apple/dmg-background@2x.png and /dev/null differ diff --git a/old code/tray/ant/apple/installer.xml b/old code/tray/ant/apple/installer.xml deleted file mode 100755 index 1d74f97..0000000 --- a/old code/tray/ant/apple/installer.xml +++ /dev/null @@ -1,376 +0,0 @@ - - - - - - - - - Creating installer using pkgbuild - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @project.name@ @build.version@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Creating app bundle - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copying native library files to libs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Verifying ${signed.bundle.name} Signature - Location: ${signed.bundle.dir} - - - - - - - - - - - - - ${message.description} - - - - - diff --git a/old code/tray/ant/apple/pkg-background-blank.tiff b/old code/tray/ant/apple/pkg-background-blank.tiff deleted file mode 100755 index 4121268..0000000 Binary files a/old code/tray/ant/apple/pkg-background-blank.tiff and /dev/null differ diff --git a/old code/tray/ant/apple/pkg-background.tiff b/old code/tray/ant/apple/pkg-background.tiff deleted file mode 100755 index e282f57..0000000 Binary files a/old code/tray/ant/apple/pkg-background.tiff and /dev/null differ diff --git a/old code/tray/ant/apple/product-def.plist.in b/old code/tray/ant/apple/product-def.plist.in deleted file mode 100755 index 0868f44..0000000 --- a/old code/tray/ant/apple/product-def.plist.in +++ /dev/null @@ -1,10 +0,0 @@ - - - - - arch - - ${apple.target.arch} - - - \ No newline at end of file diff --git a/old code/tray/ant/javafx.xml b/old code/tray/ant/javafx.xml deleted file mode 100755 index bab48cc..0000000 --- a/old code/tray/ant/javafx.xml +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${host.fx.message} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${target.fx.message} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - JavaFX host platform: - Version: ${host.fx.ver} (${host.os}, ${host.arch}) - Major Version: ${host.fx.majver} - URLs: "${host.fx.urlver}" - - JavaFX target platform: - Version: ${target.fx.ver} (${target.os}, ${target.arch}) - Major Version: ${target.fx.majver} - URLs: ""${target.fx.urlver}" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Downloading JavaFX from ${fx.url} - Temporarily saving JavaFX to ${fx.zip} - - - - - - - diff --git a/old code/tray/ant/lib/jsign-7.1.jar b/old code/tray/ant/lib/jsign-7.1.jar deleted file mode 100755 index 38924c6..0000000 Binary files a/old code/tray/ant/lib/jsign-7.1.jar and /dev/null differ diff --git a/old code/tray/ant/lib/slim-icu.py b/old code/tray/ant/lib/slim-icu.py deleted file mode 100755 index 1bd9e35..0000000 --- a/old code/tray/ant/lib/slim-icu.py +++ /dev/null @@ -1,109 +0,0 @@ -# 2018 Yohanes Nugroho (@yohanes) -# -# 1. Download icu4j source code, build using ant. -# It will generate icu4j.jar and icu4j-charset.jar -# -# 2. Run slim-icu.py to generate slim version. -# -# To invoke from ant, add python to $PATH -# and add the following to build.xml: -# -# -# -# -# -# -# -# ... then call: ant distill-icu -# -# 3. Overwrite files in lib/charsets/ - -# slim ICU -import sys -import os -from pathlib import Path -import zipfile -from zipfile import ZipFile - -directory = str(Path(__file__).resolve().parent) -if len(sys.argv) > 1: - directory = sys.argv[1] - -mode = zipfile.ZIP_DEFLATED - - -def keep_file(filename): - # skip all break iterators - if filename.endswith(".brk") \ - or filename.endswith(".dict") \ - or filename.endswith("unames.icu") \ - or filename.endswith("ucadata.icu") \ - or filename.endswith(".spp"): - return False - - # keep english and arabic - if filename.startswith("en") \ - or filename.startswith("ar") \ - or not filename.endswith(".res"): - return True - - return False - - -zin = ZipFile(os.path.join(directory, 'icu4j.jar'), 'r') -zout = ZipFile(os.path.join(directory, 'icu4j-slim.jar'), 'w', mode) - -for item in zin.infolist(): - buff = zin.read(item.filename) - print(item.filename) - - if keep_file(item.filename): - print("Keep") - zout.writestr(item, buff) - else: - print("Remove") - -zout.close() -zin.close() - - -def keep_charset_file(filename): - to_remove = [ - "cns-11643-1992.cnv", - "ebcdic-xml-us.cnv", - "euc-jp-2007.cnv", - "euc-tw-2014.cnv", - "gb18030.cnv", - "ibm-1363_P11B-1998.cnv", - "ibm-1364_P110-2007.cnv", - "ibm-1371_P100-1999.cnv", - "ibm-1373_P100-2002.cnv", - "ibm-1375_P100-2008.cnv", - "ibm-1383_P110-1999.cnv", - "ibm-1386_P100-2001.cnv", - "ibm-1388_P103-2001.cnv", - "ibm-1390_P110-2003.cnv" - ] - - for i in to_remove: - if i in filename: - return False - - return True - - -zin = ZipFile(os.path.join(directory, 'icu4j-charset.jar'), 'r') -zout = ZipFile(os.path.join(directory, 'icu4j-charset-slim.jar'), 'w', mode) - -for item in zin.infolist(): - buff = zin.read(item.filename) - print(item.filename, end=' ') - - if keep_charset_file(item.filename): - print("Keep") - zout.writestr(item, buff) - else: - print("Remove") - -zout.close() -zin.close() diff --git a/old code/tray/ant/linux/installer.xml b/old code/tray/ant/linux/installer.xml deleted file mode 100755 index 08477c1..0000000 --- a/old code/tray/ant/linux/installer.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - Creating installer using makeself - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copying native library files to libs - - - - - - - - - - - - - - - - - - - - - diff --git a/old code/tray/ant/linux/linux-installer.sh.in b/old code/tray/ant/linux/linux-installer.sh.in deleted file mode 100755 index d5cdfcc..0000000 --- a/old code/tray/ant/linux/linux-installer.sh.in +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash - -# Halt on first error -set -e - -if [ "$(id -u)" != "0" ]; then - echo "This script must be run with root (sudo) privileges" 1>&2 - exit 1 -fi - -# Console colors -RED="\\x1B[1;31m";GREEN="\\x1B[1;32m";YELLOW="\\x1B[1;33m";PLAIN="\\x1B[0m" - -# Statuses -SUCCESS=" [${GREEN}success${PLAIN}]" -FAILURE=" [${RED}failure${PLAIN}]" -WARNING=" [${YELLOW}warning${PLAIN}]" - -mask=755 - -echo -e "Starting install...\n" - -# Clear the log for writing -> "${install.log}" - -run_task () { - echo -e "Running $1 task..." - if [ -n "$DEBUG" ]; then - "./${project.filename}" $@ && ret_val=$? || ret_val=$? - else - "./${project.filename}" $@ &>> "${install.log}" && ret_val=$? || ret_val=$? - fi - - if [ $ret_val -eq 0 ]; then - echo -e " $SUCCESS Task $1 was successful" - else - if [ "$1" == "spawn" ]; then - echo -e " $WARNING Task $1 skipped. You'll have to start ${project.name} manually." - return - fi - echo -e " $FAILURE Task $1 failed.\n\nRe-run with DEBUG=true for more information." - false # throw error - fi -} - -# Ensure java is installed and working before starting -"./${project.filename}" --version - -# Make a temporary jar for preliminary installation steps -run_task preinstall - -run_task install --dest "/opt/${project.filename}" - -# We should be installed now, generate the certificate -pushd "/opt/${project.filename}" &> /dev/null -run_task certgen - -# Tell the desktop to look for new mimetypes in the background -umask_bak="$(umask)" -umask 0002 # more permissive umask for mimetype registration -update-desktop-database &> /dev/null & -umask "$umask_bak" - -echo "Installation complete... Starting ${project.name}..." -# spawn itself as a regular user, inheriting environment -run_task spawn "/opt/${project.filename}/${project.filename}" - -popd &> /dev/null \ No newline at end of file diff --git a/old code/tray/ant/linux/linux.properties b/old code/tray/ant/linux/linux.properties deleted file mode 100755 index 5f06032..0000000 --- a/old code/tray/ant/linux/linux.properties +++ /dev/null @@ -1,2 +0,0 @@ -# Expose UNIXToolkit.getGtkVersion -linux.launch.jigsaw=--add-opens java.desktop/sun.awt=ALL-UNNAMED \ No newline at end of file diff --git a/old code/tray/ant/platform-detect.xml b/old code/tray/ant/platform-detect.xml deleted file mode 100755 index 16feb06..0000000 --- a/old code/tray/ant/platform-detect.xml +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${title} platform: - ${prefix}.os: "${prefix.os}" - ${prefix}.arch: "${prefix.arch}" - ${prefix}.libext: "${prefix.libext}" - ${os.echo}: true - ${arch.echo}: true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/old code/tray/ant/private/private.properties b/old code/tray/ant/private/private.properties deleted file mode 100755 index c36079e..0000000 --- a/old code/tray/ant/private/private.properties +++ /dev/null @@ -1,5 +0,0 @@ -signing.alias=self-signed -signing.keystore=ant/private/qz.ks -signing.keypass=jzebraonfire -signing.storepass=jzebraonfire -signing.algorithm=SHA-256 diff --git a/old code/tray/ant/project.properties b/old code/tray/ant/project.properties deleted file mode 100755 index e4e3839..0000000 --- a/old code/tray/ant/project.properties +++ /dev/null @@ -1,62 +0,0 @@ -vendor.name=qz -vendor.company=QZ Industries, LLC -vendor.website=https://qz.io -vendor.email=support@qz.io - -project.name=QZ Tray -project.filename=qz-tray -project.datadir=qz - -install.opts=-Djna.nosys=true -launch.opts=-Xms512m ${install.opts} -install.log=/tmp/${project.datadir}-install.log -# jdk9+ flags -# - Dark theme requires workaround https://github.com/bobbylight/Darcula/issues/8 -launch.jigsaw=--add-exports java.desktop/sun.swing=ALL-UNNAMED -launch.overrides=QZ_OPTS - -src.dir=${basedir}/src -out.dir=${basedir}/out -build.dir=${out.dir}/build -dist.dir=${out.dir}/dist - -sign.lib.dir=${out.dir}/jar-signed - -jar.compress=true -jar.index=true - -# Separate native lib resources from jars -separate.static.libs=true - -# See also qz.common.Constants.java -javac.source=11 -javac.target=11 -java.download=https://bell-sw.com/pages/downloads/#/java-11-lts - -# Java vendor to bundle into software (e.g. "*BellSoft|Adoptium|Microsoft|Amazon|IBM") -jlink.java.vendor="BellSoft" -# Java vendor to bundle into software (e.g. "11.0.17+7") -jlink.java.version="11.0.27+9" -# Java garbage collector flavor to use (e.g. "hotspot|openj9") -jlink.java.gc="hotspot" -# Java garbage collector version to use (e.g. openj9: "0.35.0", zulu: "11.62.17") -jlink.java.gc.version="gc-ver-is-empty" -# Bundle a locally built copy of Java instead -jlink.java.target=/home/ske087/quality_recticel/jdk-11.0.20-full - -# Skip bundling the java runtime -jre.skip=false - -# JavaFX version -javafx.version=19_monocle -javafx.mirror=https://download2.gluonhq.com/openjfx - -# Provisioning -# provision.file=${basedir}/provision.json -provision.dir=${dist.dir}/provision - -# Mask tray toggle (Apple only) -java.mask.tray=true - -# Workaround to delay expansion of $${foo} (e.g. shell scripts) -dollar=$ diff --git a/old code/tray/ant/signing.xml b/old code/tray/ant/signing.xml deleted file mode 100755 index 1b0b9b1..0000000 --- a/old code/tray/ant/signing.xml +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Signing with hsm: ${hsm.keystore} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Signing without timestamp: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No tsaurl was provided so the file was not timestamped. Users will not be able to validate - this file after the signer certificate's expiration date or after any future revocation date. - - - - \ No newline at end of file diff --git a/old code/tray/ant/unix/unix-launcher.sh.in b/old code/tray/ant/unix/unix-launcher.sh.in deleted file mode 100755 index b56ea5c..0000000 --- a/old code/tray/ant/unix/unix-launcher.sh.in +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env bash -# Shared launcher for MacOS and Linux -# Parameters -- if any -- are passed on to the app - -# Halt on first error -set -e - -# Configured by ant at build time -JAVA_MIN="${javac.target}" -LAUNCH_OPTS="${launch.opts}" -ABOUT_TITLE="${project.name}" -PROPS_FILE="${project.filename}" - -# Get working directory -DIR=$(cd "$(dirname "$0")" && pwd) -pushd "$DIR" &> /dev/null - -# Console colors -RED="\\x1B[1;31m";GREEN="\\x1B[1;32m";YELLOW="\\x1B[1;33m";PLAIN="\\x1B[0m" - -# Statuses -SUCCESS=" [${GREEN}success${PLAIN}]" -FAILURE=" [${RED}failure${PLAIN}]" -WARNING=" [${YELLOW}warning${PLAIN}]" -MESSAGE=" [${YELLOW}message${PLAIN}]" - -echo "Looking for Java..." - -# Honor JAVA_HOME -if [ -n "$JAVA_HOME" ]; then - echo -e "$WARNING JAVA_HOME was detected, using $JAVA_HOME..." - PATH="$JAVA_HOME/bin:$PATH" -fi - -# Always prefer relative runtime/jre -if [[ "$DIR" == *"/Contents/MacOS"* ]]; then - PATH="$DIR/../PlugIns/Java.runtime/Contents/Home/bin:$PATH" -else - PATH="$DIR/runtime/bin:$DIR/jre/bin:$PATH" -fi - -# Check for user overridable launch options -if [ -n "${dollar}${launch.overrides}" ]; then - echo -e "$MESSAGE Picked up additional launch options: ${dollar}${launch.overrides}" - LAUNCH_OPTS="$LAUNCH_OPTS ${dollar}${launch.overrides}" -fi - -# Fallback on some known locations -if ! command -v java > /dev/null ; then - if [[ "$OSTYPE" == "darwin"* ]]; then - # Apple: Fallback on system-wide install - DEFAULTS_READ=$(defaults read ${apple.bundleid} ${launch.overrides} 2>/dev/null) || true - if [ -n "$DEFAULTS_READ" ]; then - echo -e "$MESSAGE Picked up additional launch options: $DEFAULTS_READ" - LAUNCH_OPTS="$LAUNCH_OPTS $DEFAULTS_READ" - fi - MAC_PRIMARY="/usr/libexec/java_home" - MAC_FALLBACK="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin" - echo "Trying $MAC_PRIMARY..." - if "$MAC_PRIMARY" -v $JAVA_MIN+ &>/dev/null; then - echo -e "$SUCCESS Using \"$MAC_PRIMARY -v $JAVA_MIN+ --exec\" to launch $ABOUT_TITLE" - java() { - "$MAC_PRIMARY" -v $JAVA_MIN+ --exec java "$@" - } - elif [ -d "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin" ]; then - echo -e "$WARNING No luck using $MAC_PRIMARY" - echo "Trying $MAC_FALLBACK..." - java() { - "$MAC_FALLBACK/java" "$@" - } - fi - else - # Linux/Unix: Fallback on known install location(s) - PATH="$PATH:/usr/java/latest/bin/" - fi -fi - -if command -v java > /dev/null ; then - echo -e "$SUCCESS Java was found: $(command -v java)" -else - echo -e "$FAILURE Please install Java $JAVA_MIN or higher to continue" - exit 1 -fi - -# Verify the bundled Java version actually works -if test -f "$DIR/runtime/bin/java" ; then - echo "Verifying the bundled Java version can run on this platform..." - if "$DIR/runtime/bin/java" -version &> /dev/null ; then - echo -e "$SUCCESS Bundled Java version is OK" - else - echo -e "$FAILURE Sorry, this version of $ABOUT_TITLE cannot be installed on this system:\n" - file "$DIR/runtime/bin/java" - exit 1 - fi -fi - -# Make sure Java version is sufficient -echo "Verifying the Java version is $JAVA_MIN+..." -curver=$(java -version 2>&1 | grep -i version | awk -F"\"" '{ print $2 }' | awk -F"." '{ print $1 "." $2 }') -minver="$JAVA_MIN" -if [ -z "$curver" ]; then - curver="0.0" -fi -desired=$(echo -e "$minver\n$curver") -actual=$(echo "$desired" |sort -t '.' -k 1,1 -k 2,2 -n) -if [ "$desired" != "$actual" ]; then - echo -e "$FAILURE Please install Java $JAVA_MIN or higher to continue" - exit 1 -else - echo -e "$SUCCESS Java $curver was detected" -fi - -jigsaw=$(echo -e "9.0\n$curver") -actual=$(echo "$jigsaw" |sort -t '.' -k 1,1 -k 2,2 -n) -if [ "$jigsaw" != "$actual" ]; then - echo -e "$SUCCESS Java < 9.0, skipping jigsaw options" -else - echo -e "$SUCCESS Java >= 9.0, adding jigsaw options" - LAUNCH_OPTS="$LAUNCH_OPTS ${launch.jigsaw}" - if [[ "$OSTYPE" == "darwin"* ]]; then - LAUNCH_OPTS="$LAUNCH_OPTS ${apple.launch.jigsaw}" - else - LAUNCH_OPTS="$LAUNCH_OPTS ${linux.launch.jigsaw}" - fi -fi - -if command -v java &>/dev/null; then - echo -e "$ABOUT_TITLE is starting..." - if [[ "$OSTYPE" == "darwin"* ]]; then - java $LAUNCH_OPTS -Xdock:name="$ABOUT_TITLE" -Xdock:icon="$DIR/../Resources/$PROPS_FILE.icns" -jar -Dapple.awt.UIElement="true" -Dapple.awt.enableTemplateImages="${java.mask.tray}" -Dapple.awt.application.appearance="system" "$DIR/../Resources/${prefix}$PROPS_FILE.jar" -NSRequiresAquaSystemAppearance False "$@" - else - java $LAUNCH_OPTS -jar "$PROPS_FILE.jar" "$@" - fi -else - echo -e "$FAILURE Java $JAVA_MIN+ was not found" -fi - -popd &>/dev/null \ No newline at end of file diff --git a/old code/tray/ant/unix/unix-uninstall.sh.in b/old code/tray/ant/unix/unix-uninstall.sh.in deleted file mode 100755 index deab4df..0000000 --- a/old code/tray/ant/unix/unix-uninstall.sh.in +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -# Halt on first error -set -e - -if [ "$(id -u)" != "0" ]; then - echo "This script must be run with root (sudo) privileges" 1>&2 - exit 1 -fi - -# Get working directory -DIR=$(cd "$(dirname "$0")" && pwd) -pushd "$DIR" - -echo "Running uninstall tasks..." -if [[ "$OSTYPE" == "darwin"* ]]; then - # Uninstall script is in "QZ Tray.app/Contents/Resources/uninstall" - # Calculate the path to "QZ Tray.app" - APP_DIR=$(cd "$(dirname "$0")/../.." && pwd) - - if [[ "$APP_DIR" != *".app" ]]; then - echo -e "\nMalformed app directory. Uninstallation of ${project.name} failed.\n" - exit 1 - fi - # Launcher script is in "QZ Tray.app/Contents/MacOS" - "$APP_DIR/Contents/MacOS/${project.name}" uninstall -else - # Uninstall script is in root of app (e.g. "/opt/qz-tray") - APP_DIR="$DIR" - # Launcher script is adjacent to uninstall script - "$APP_DIR/${project.filename}" uninstall -fi - -echo "Deleting files..." -rm -rf "$APP_DIR" -echo -e "\nUninstall of ${project.name} complete.\n" - -popd &>/dev/null \ No newline at end of file diff --git a/old code/tray/ant/version.xml b/old code/tray/ant/version.xml deleted file mode 100755 index a79d192..0000000 --- a/old code/tray/ant/version.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - Version : ${build.version}${build.type} - Bundle Id : ${apple.bundleid} - - - \ No newline at end of file diff --git a/old code/tray/ant/windows/installer.xml b/old code/tray/ant/windows/installer.xml deleted file mode 100755 index 17504d1..0000000 --- a/old code/tray/ant/windows/installer.xml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Creating ${nsis.outfile} using ${nsisbin} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copying native library files to libs - - - - - - - - - - - - - - diff --git a/old code/tray/ant/windows/nsis/Include/FindJava.nsh b/old code/tray/ant/windows/nsis/Include/FindJava.nsh deleted file mode 100755 index 33bf986..0000000 --- a/old code/tray/ant/windows/nsis/Include/FindJava.nsh +++ /dev/null @@ -1,143 +0,0 @@ -!include FileFunc.nsh -!include LogicLib.nsh -!include x64.nsh - -!include StrRep.nsh -!include IndexOf.nsh -!include StrTok.nsh - -; Resulting variable -Var /GLOBAL java -Var /GLOBAL javaw -Var /GLOBAL java_major - -; Constants -!define EXE "java.exe" - -!define ADOPT "SOFTWARE\Classes\AdoptOpenJDK.jarfile\shell\open\command" -!define ECLIPSE "SOFTWARE\Classes\Eclipse Adoptium.jarfile\shell\open\command" -!define ECLIPSE_OLD "SOFTWARE\Classes\Eclipse Foundation.jarfile\shell\open\command" - -!define JRE "Software\JavaSoft\Java Runtime Environment" -!define JRE32 "Software\Wow6432Node\JavaSoft\Java Runtime Environment" -!define JDK "Software\JavaSoft\JDK" -!define JDK32 "Software\Wow6432Node\JavaSoft\JDK" - -; Macros -!macro _ReadEclipseKey - ClearErrors - ReadRegStr $0 HKLM "${ECLIPSE}" "" - StrCpy $0 "$0" "" 1 ; Remove first double-quote - ${IndexOf} $1 $0 "$\"" ; Find the index of second double-quote - StrCpy $0 "$0" $1 ; Get the string section up to the index - IfFileExists "$0" Found -!macroend - -!macro _ReadEclipseOldKey - ClearErrors - ReadRegStr $0 HKLM "${ECLIPSE_OLD}" "" - StrCpy $0 "$0" "" 1 ; Remove first double-quote - ${IndexOf} $1 $0 "$\"" ; Find the index of second double-quote - StrCpy $0 "$0" $1 ; Get the string section up to the index - IfFileExists "$0" Found -!macroend - -!macro _ReadAdoptKey - ClearErrors - ReadRegStr $0 HKLM "${ADOPT}" "" - StrCpy $0 "$0" "" 1 ; Remove first double-quote - ${IndexOf} $1 $0 "$\"" ; Find the index of second double-quote - StrCpy $0 "$0" $1 ; Get the string section up to the index - IfFileExists "$0" Found -!macroend - -!macro _ReadReg key - ClearErrors - ReadRegStr $0 HKLM "${key}" "CurrentVersion" - ReadRegStr $0 HKLM "${key}\$0" "JavaHome" - IfErrors +2 0 - StrCpy $0 "$0\bin\${EXE}" - IfFileExists "$0" Found -!macroend - -!macro _ReadPayload root path - ClearErrors - StrCpy $0 "${root}\${path}\bin\${EXE}" - IfFileExists $0 Found -!macroend - -!macro _ReadWorking path - ClearErrors - StrCpy $0 "$EXEDIR\${path}\bin\${EXE}" - IfFileExists $0 Found -!macroend - -!macro _ReadEnv var - ClearErrors - ReadEnvStr $0 "${var}" - StrCpy $0 "$0\bin\${EXE}" - IfFileExists "$0" Found -!macroend - -; Create the shared function. -!macro _FindJava un - Function ${un}FindJava - ; Snag payload directory off the stack - exch $R0 - - ${If} ${RunningX64} - SetRegView 64 - ${EndIf} - - ; Check payload directories - !insertmacro _ReadPayload "$R0" "runtime" - - ; Check relative directories - !insertmacro _ReadWorking "runtime" - !insertmacro _ReadWorking "jre" - - ; Check common env vars - !insertmacro _ReadEnv "JAVA_HOME" - - ; Check registry - !insertmacro _ReadEclipseKey - !insertmacro _ReadEclipseOldKey - !insertmacro _ReadAdoptKey - !insertmacro _ReadReg "${JRE}" - !insertmacro _ReadReg "${JRE32}" - !insertmacro _ReadReg "${JDK}" - !insertmacro _ReadReg "${JDK32}" - - ; Give up. Use java.exe and hope it works - StrCpy $0 "${EXE}" - - ; Set global var - Found: - StrCpy $java $0 - ${StrRep} '$java' '$java' 'javaw.exe' '${EXE}' ; AdoptOpenJDK returns "javaw.exe" - ${StrRep} '$javaw' '$java' '${EXE}' 'javaw.exe' - - ; Discard payload directory - pop $R0 - - ; Detect java version - nsExec::ExecToStack '"$java" -version' - Pop $0 - Pop $1 - ; Isolate version number, e.g. "1.8.0" - ${StrTok} $0 "$1" "$\"" "1" "1" - ; Isolate major version - ${StrTok} $R0 "$0" "." "0" "1" - ; Handle old 1.x.x version format - ${If} "$R0" == "1" - ${StrTok} $R0 "$0" "." "1" "1" - ${EndIf} - - ; Convert to integer - IntOp $java_major $R0 + 0 - FunctionEnd -!macroend - -; Allows registering identical functions for install and uninstall -!insertmacro _FindJava "" -;!insertmacro _FindJava "un." \ No newline at end of file diff --git a/old code/tray/ant/windows/nsis/Include/IndexOf.nsh b/old code/tray/ant/windows/nsis/Include/IndexOf.nsh deleted file mode 100755 index 88f4d63..0000000 --- a/old code/tray/ant/windows/nsis/Include/IndexOf.nsh +++ /dev/null @@ -1,28 +0,0 @@ -!define IndexOf "!insertmacro IndexOf" - -!macro IndexOf Var Str Char - Push "${Char}" - Push "${Str}" - - Exch $R0 - Exch - Exch $R1 - Push $R2 - Push $R3 - - StrCpy $R3 $R0 - StrCpy $R0 -1 - IntOp $R0 $R0 + 1 - StrCpy $R2 $R3 1 $R0 - StrCmp $R2 "" +2 - StrCmp $R2 $R1 +2 -3 - - StrCpy $R0 -1 - - Pop $R3 - Pop $R2 - Pop $R1 - Exch $R0 - - Pop "${Var}" -!macroend \ No newline at end of file diff --git a/old code/tray/ant/windows/nsis/Include/SetTitleBar.nsh b/old code/tray/ant/windows/nsis/Include/SetTitleBar.nsh deleted file mode 100755 index c42dc34..0000000 --- a/old code/tray/ant/windows/nsis/Include/SetTitleBar.nsh +++ /dev/null @@ -1,5 +0,0 @@ -; Allow title masquerading -!define SetTitleBar "!insertmacro SetTitleBar" -!macro SetTitlebar title - SendMessage $HWNDPARENT ${WM_SETTEXT} 0 "STR:${title}" -!macroend \ No newline at end of file diff --git a/old code/tray/ant/windows/nsis/Include/StdUtils.nsh b/old code/tray/ant/windows/nsis/Include/StdUtils.nsh deleted file mode 100755 index 537655d..0000000 --- a/old code/tray/ant/windows/nsis/Include/StdUtils.nsh +++ /dev/null @@ -1,501 +0,0 @@ -################################################################################# -# StdUtils plug-in for NSIS -# Copyright (C) 2004-2018 LoRd_MuldeR -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -# http://www.gnu.org/licenses/lgpl-2.1.txt -################################################################################# - -# DEVELOPER NOTES: -# - Please see "https://github.com/lordmulder/stdutils/" for news and updates! -# - Please see "Docs\StdUtils\StdUtils.html" for detailed function descriptions! -# - Please see "Examples\StdUtils\StdUtilsTest.nsi" for usage examples! - -################################################################################# -# FUNCTION DECLARTIONS -################################################################################# - -!ifndef ___STDUTILS__NSH___ -!define ___STDUTILS__NSH___ - -!define StdUtils.Time '!insertmacro _StdU_Time' #time(), as in C standard library -!define StdUtils.GetMinutes '!insertmacro _StdU_GetMinutes' #GetSystemTimeAsFileTime(), returns the number of minutes -!define StdUtils.GetHours '!insertmacro _StdU_GetHours' #GetSystemTimeAsFileTime(), returns the number of hours -!define StdUtils.GetDays '!insertmacro _StdU_GetDays' #GetSystemTimeAsFileTime(), returns the number of days -!define StdUtils.Rand '!insertmacro _StdU_Rand' #rand(), as in C standard library -!define StdUtils.RandMax '!insertmacro _StdU_RandMax' #rand(), as in C standard library, with maximum value -!define StdUtils.RandMinMax '!insertmacro _StdU_RandMinMax' #rand(), as in C standard library, with minimum/maximum value -!define StdUtils.RandList '!insertmacro _StdU_RandList' #rand(), as in C standard library, with list support -!define StdUtils.RandBytes '!insertmacro _StdU_RandBytes' #Generates random bytes, returned as Base64-encoded string -!define StdUtils.FormatStr '!insertmacro _StdU_FormatStr' #sprintf(), as in C standard library, one '%d' placeholder -!define StdUtils.FormatStr2 '!insertmacro _StdU_FormatStr2' #sprintf(), as in C standard library, two '%d' placeholders -!define StdUtils.FormatStr3 '!insertmacro _StdU_FormatStr3' #sprintf(), as in C standard library, three '%d' placeholders -!define StdUtils.ScanStr '!insertmacro _StdU_ScanStr' #sscanf(), as in C standard library, one '%d' placeholder -!define StdUtils.ScanStr2 '!insertmacro _StdU_ScanStr2' #sscanf(), as in C standard library, two '%d' placeholders -!define StdUtils.ScanStr3 '!insertmacro _StdU_ScanStr3' #sscanf(), as in C standard library, three '%d' placeholders -!define StdUtils.TrimStr '!insertmacro _StdU_TrimStr' #Remove whitspaces from string, left and right -!define StdUtils.TrimStrLeft '!insertmacro _StdU_TrimStrLeft' #Remove whitspaces from string, left side only -!define StdUtils.TrimStrRight '!insertmacro _StdU_TrimStrRight' #Remove whitspaces from string, right side only -!define StdUtils.RevStr '!insertmacro _StdU_RevStr' #Reverse a string, e.g. "reverse me" <-> "em esrever" -!define StdUtils.ValidFileName '!insertmacro _StdU_ValidFileName' #Test whether string is a valid file name - no paths allowed -!define StdUtils.ValidPathSpec '!insertmacro _StdU_ValidPathSpec' #Test whether string is a valid full(!) path specification -!define StdUtils.ValidDomainName '!insertmacro _StdU_ValidDomain' #Test whether string is a valid host name or domain name -!define StdUtils.StrToUtf8 '!insertmacro _StdU_StrToUtf8' #Convert string from Unicode (UTF-16) or ANSI to UTF-8 bytes -!define StdUtils.StrFromUtf8 '!insertmacro _StdU_StrFromUtf8' #Convert string from UTF-8 bytes to Unicode (UTF-16) or ANSI -!define StdUtils.SHFileMove '!insertmacro _StdU_SHFileMove' #SHFileOperation(), using the FO_MOVE operation -!define StdUtils.SHFileCopy '!insertmacro _StdU_SHFileCopy' #SHFileOperation(), using the FO_COPY operation -!define StdUtils.AppendToFile '!insertmacro _StdU_AppendToFile' #Append contents of an existing file to another file -!define StdUtils.ExecShellAsUser '!insertmacro _StdU_ExecShlUser' #ShellExecute() as NON-elevated user from elevated installer -!define StdUtils.InvokeShellVerb '!insertmacro _StdU_InvkeShlVrb' #Invokes a "shell verb", e.g. for pinning items to the taskbar -!define StdUtils.ExecShellWaitEx '!insertmacro _StdU_ExecShlWaitEx' #ShellExecuteEx(), returns the handle of the new process -!define StdUtils.WaitForProcEx '!insertmacro _StdU_WaitForProcEx' #WaitForSingleObject(), e.g. to wait for a running process -!define StdUtils.GetParameter '!insertmacro _StdU_GetParameter' #Get the value of a specific command-line option -!define StdUtils.TestParameter '!insertmacro _StdU_TestParameter' #Test whether a specific command-line option has been set -!define StdUtils.ParameterCnt '!insertmacro _StdU_ParameterCnt' #Get number of command-line tokens, similar to argc in main() -!define StdUtils.ParameterStr '!insertmacro _StdU_ParameterStr' #Get the n-th command-line token, similar to argv[i] in main() -!define StdUtils.GetAllParameters '!insertmacro _StdU_GetAllParams' #Get complete command-line, but without executable name -!define StdUtils.GetRealOSVersion '!insertmacro _StdU_GetRealOSVer' #Get the *real* Windows version number, even on Windows 8.1+ -!define StdUtils.GetRealOSBuildNo '!insertmacro _StdU_GetRealOSBld' #Get the *real* Windows build number, even on Windows 8.1+ -!define StdUtils.GetRealOSName '!insertmacro _StdU_GetRealOSStr' #Get the *real* Windows version, as a "friendly" name -!define StdUtils.GetOSEdition '!insertmacro _StdU_GetOSEdition' #Get the Windows edition, i.e. "workstation" or "server" -!define StdUtils.GetOSReleaseId '!insertmacro _StdU_GetOSRelIdNo' #Get the Windows release identifier (on Windows 10) -!define StdUtils.GetOSReleaseName '!insertmacro _StdU_GetOSRelIdStr' #Get the Windows release (on Windows 10), as a "friendly" name -!define StdUtils.VerifyOSVersion '!insertmacro _StdU_VrfyRealOSVer' #Compare *real* operating system to an expected version number -!define StdUtils.VerifyOSBuildNo '!insertmacro _StdU_VrfyRealOSBld' #Compare *real* operating system to an expected build number -!define StdUtils.HashText '!insertmacro _StdU_HashText' #Compute hash from text string (CRC32, MD5, SHA1/2/3, BLAKE2) -!define StdUtils.HashFile '!insertmacro _StdU_HashFile' #Compute hash from file (CRC32, MD5, SHA1/2/3, BLAKE2) -!define StdUtils.NormalizePath '!insertmacro _StdU_NormalizePath' #Simplifies the path to produce a direct, well-formed path -!define StdUtils.GetParentPath '!insertmacro _StdU_GetParentPath' #Get parent path by removing the last component from the path -!define StdUtils.SplitPath '!insertmacro _StdU_SplitPath' #Split the components of the given path -!define StdUtils.GetDrivePart '!insertmacro _StdU_GetDrivePart' #Get drive component of path -!define StdUtils.GetDirectoryPart '!insertmacro _StdU_GetDirPart' #Get directory component of path -!define StdUtils.GetFileNamePart '!insertmacro _StdU_GetFNamePart' #Get file name component of path -!define StdUtils.GetExtensionPart '!insertmacro _StdU_GetExtnPart' #Get file extension component of path -!define StdUtils.TimerCreate '!insertmacro _StdU_TimerCreate' #Create a new event-timer that will be triggered periodically -!define StdUtils.TimerDestroy '!insertmacro _StdU_TimerDestroy' #Destroy a running timer created with TimerCreate() -!define StdUtils.ProtectStr '!insertmacro _StdU_PrtctStr' #Protect a given String using Windows' DPAPI -!define StdUtils.UnprotectStr '!insertmacro _StdU_UnprtctStr' #Unprotect a string that was protected via ProtectStr() -!define StdUtils.GetLibVersion '!insertmacro _StdU_GetLibVersion' #Get the current StdUtils library version (for debugging) -!define StdUtils.SetVerbose '!insertmacro _StdU_SetVerbose' #Enable or disable "verbose" mode (for debugging) - - -################################################################################# -# MACRO DEFINITIONS -################################################################################# - -!macro _StdU_Time out - StdUtils::Time /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetMinutes out - StdUtils::GetMinutes /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetHours out - StdUtils::GetHours /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetDays out - StdUtils::GetDays /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_Rand out - StdUtils::Rand /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_RandMax out max - push ${max} - StdUtils::RandMax /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_RandMinMax out min max - push ${min} - push ${max} - StdUtils::RandMinMax /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_RandList count max - push ${max} - push ${count} - StdUtils::RandList /NOUNLOAD -!macroend - -!macro _StdU_RandBytes out count - push ${count} - StdUtils::RandBytes /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_FormatStr out format val - push `${format}` - push ${val} - StdUtils::FormatStr /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_FormatStr2 out format val1 val2 - push `${format}` - push ${val1} - push ${val2} - StdUtils::FormatStr2 /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_FormatStr3 out format val1 val2 val3 - push `${format}` - push ${val1} - push ${val2} - push ${val3} - StdUtils::FormatStr3 /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_ScanStr out format input default - push `${format}` - push `${input}` - push ${default} - StdUtils::ScanStr /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_ScanStr2 out1 out2 format input default1 default2 - push `${format}` - push `${input}` - push ${default1} - push ${default2} - StdUtils::ScanStr2 /NOUNLOAD - pop ${out1} - pop ${out2} -!macroend - -!macro _StdU_ScanStr3 out1 out2 out3 format input default1 default2 default3 - push `${format}` - push `${input}` - push ${default1} - push ${default2} - push ${default3} - StdUtils::ScanStr3 /NOUNLOAD - pop ${out1} - pop ${out2} - pop ${out3} -!macroend - -!macro _StdU_TrimStr var - push ${var} - StdUtils::TrimStr /NOUNLOAD - pop ${var} -!macroend - -!macro _StdU_TrimStrLeft var - push ${var} - StdUtils::TrimStrLeft /NOUNLOAD - pop ${var} -!macroend - -!macro _StdU_TrimStrRight var - push ${var} - StdUtils::TrimStrRight /NOUNLOAD - pop ${var} -!macroend - -!macro _StdU_RevStr var - push ${var} - StdUtils::RevStr /NOUNLOAD - pop ${var} -!macroend - -!macro _StdU_ValidFileName out test - push `${test}` - StdUtils::ValidFileName /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_ValidPathSpec out test - push `${test}` - StdUtils::ValidPathSpec /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_ValidDomain out test - push `${test}` - StdUtils::ValidDomainName /NOUNLOAD - pop ${out} -!macroend - - -!macro _StdU_StrToUtf8 out str - push `${str}` - StdUtils::StrToUtf8 /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_StrFromUtf8 out trnc str - push ${trnc} - push `${str}` - StdUtils::StrFromUtf8 /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_SHFileMove out from to hwnd - push `${from}` - push `${to}` - push ${hwnd} - StdUtils::SHFileMove /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_SHFileCopy out from to hwnd - push `${from}` - push `${to}` - push ${hwnd} - StdUtils::SHFileCopy /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_AppendToFile out from dest offset maxlen - push `${from}` - push `${dest}` - push ${offset} - push ${maxlen} - StdUtils::AppendToFile /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_ExecShlUser out file verb args - push `${file}` - push `${verb}` - push `${args}` - StdUtils::ExecShellAsUser /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_InvkeShlVrb out path file verb_id - push "${path}" - push "${file}" - push ${verb_id} - StdUtils::InvokeShellVerb /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_ExecShlWaitEx out_res out_val file verb args - push `${file}` - push `${verb}` - push `${args}` - StdUtils::ExecShellWaitEx /NOUNLOAD - pop ${out_res} - pop ${out_val} -!macroend - -!macro _StdU_WaitForProcEx out handle - push `${handle}` - StdUtils::WaitForProcEx /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetParameter out name default - push `${name}` - push `${default}` - StdUtils::GetParameter /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_TestParameter out name - push `${name}` - StdUtils::TestParameter /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_ParameterCnt out - StdUtils::ParameterCnt /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_ParameterStr out index - push ${index} - StdUtils::ParameterStr /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetAllParams out truncate - push `${truncate}` - StdUtils::GetAllParameters /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetRealOSVer out_major out_minor out_spack - StdUtils::GetRealOsVersion /NOUNLOAD - pop ${out_major} - pop ${out_minor} - pop ${out_spack} -!macroend - -!macro _StdU_GetRealOSBld out - StdUtils::GetRealOsBuildNo /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetRealOSStr out - StdUtils::GetRealOsName /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_VrfyRealOSVer out major minor spack - push `${major}` - push `${minor}` - push `${spack}` - StdUtils::VerifyRealOsVersion /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_VrfyRealOSBld out build - push `${build}` - StdUtils::VerifyRealOsBuildNo /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetOSEdition out - StdUtils::GetOsEdition /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetOSRelIdNo out - StdUtils::GetOsReleaseId /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetOSRelIdStr out - StdUtils::GetOsReleaseName /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_HashText out type text - push `${type}` - push `${text}` - StdUtils::HashText /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_HashFile out type file - push `${type}` - push `${file}` - StdUtils::HashFile /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_NormalizePath out path - push `${path}` - StdUtils::NormalizePath /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetParentPath out path - push `${path}` - StdUtils::GetParentPath /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_SplitPath out_drive out_dir out_fname out_ext path - push `${path}` - StdUtils::SplitPath /NOUNLOAD - pop ${out_drive} - pop ${out_dir} - pop ${out_fname} - pop ${out_ext} -!macroend - -!macro _StdU_GetDrivePart out path - push `${path}` - StdUtils::GetDrivePart /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetDirPart out path - push `${path}` - StdUtils::GetDirectoryPart /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetFNamePart out path - push `${path}` - StdUtils::GetFileNamePart /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetExtnPart out path - push `${path}` - StdUtils::GetExtensionPart /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_TimerCreate out callback interval - GetFunctionAddress ${out} ${callback} - push ${out} - push ${interval} - StdUtils::TimerCreate /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_TimerDestroy out timer_id - push ${timer_id} - StdUtils::TimerDestroy /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_PrtctStr out dpsc salt text - push `${dpsc}` - push `${salt}` - push `${text}` - StdUtils::ProtectStr /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_UnprtctStr out trnc salt data - push `${trnc}` - push `${salt}` - push `${data}` - StdUtils::UnprotectStr /NOUNLOAD - pop ${out} -!macroend - -!macro _StdU_GetLibVersion out_ver out_tst - StdUtils::GetLibVersion /NOUNLOAD - pop ${out_ver} - pop ${out_tst} -!macroend - -!macro _StdU_SetVerbose enable - Push ${enable} - StdUtils::SetVerboseMode /NOUNLOAD -!macroend - - -################################################################################# -# MAGIC NUMBERS -################################################################################# - -!define StdUtils.Const.ShellVerb.PinToTaskbar 0 -!define StdUtils.Const.ShellVerb.UnpinFromTaskbar 1 -!define StdUtils.Const.ShellVerb.PinToStart 2 -!define StdUtils.Const.ShellVerb.UnpinFromStart 3 - -!endif # !___STDUTILS__NSH___ diff --git a/old code/tray/ant/windows/nsis/Include/StrLoc.nsh b/old code/tray/ant/windows/nsis/Include/StrLoc.nsh deleted file mode 100755 index 8adb1ca..0000000 --- a/old code/tray/ant/windows/nsis/Include/StrLoc.nsh +++ /dev/null @@ -1,72 +0,0 @@ -!define StrLoc "!insertmacro StrLoc" - -!macro StrLoc ResultVar String SubString StartPoint - Push "${String}" - Push "${SubString}" - Push "${StartPoint}" - Call StrLoc - Pop "${ResultVar}" -!macroend - -Function StrLoc -/*After this point: - ------------------------------------------ - $R0 = StartPoint (input) - $R1 = SubString (input) - $R2 = String (input) - $R3 = SubStringLen (temp) - $R4 = StrLen (temp) - $R5 = StartCharPos (temp) - $R6 = TempStr (temp)*/ - - ;Get input from user - Exch $R0 - Exch - Exch $R1 - Exch 2 - Exch $R2 - Push $R3 - Push $R4 - Push $R5 - Push $R6 - - ;Get "String" and "SubString" length - StrLen $R3 $R1 - StrLen $R4 $R2 - ;Start "StartCharPos" counter - StrCpy $R5 0 - - ;Loop until "SubString" is found or "String" reaches its end - ${Do} - ;Remove everything before and after the searched part ("TempStr") - StrCpy $R6 $R2 $R3 $R5 - - ;Compare "TempStr" with "SubString" - ${If} $R6 == $R1 - ${If} $R0 == `<` - IntOp $R6 $R3 + $R5 - IntOp $R0 $R4 - $R6 - ${Else} - StrCpy $R0 $R5 - ${EndIf} - ${ExitDo} - ${EndIf} - ;If not "SubString", this could be "String"'s end - ${If} $R5 >= $R4 - StrCpy $R0 `` - ${ExitDo} - ${EndIf} - ;If not, continue the loop - IntOp $R5 $R5 + 1 - ${Loop} - - ;Return output to user - Pop $R6 - Pop $R5 - Pop $R4 - Pop $R3 - Pop $R2 - Exch - Pop $R1 - Exch $R0 -FunctionEnd \ No newline at end of file diff --git a/old code/tray/ant/windows/nsis/Include/StrRep.nsh b/old code/tray/ant/windows/nsis/Include/StrRep.nsh deleted file mode 100755 index 57d1f3a..0000000 --- a/old code/tray/ant/windows/nsis/Include/StrRep.nsh +++ /dev/null @@ -1,66 +0,0 @@ -!define StrRep "!insertmacro StrRep" -!macro StrRep output string old new - Push `${string}` - Push `${old}` - Push `${new}` - ;!ifdef __UNINSTALL__ - ; Call un.StrRep - ;!else - Call StrRep - ;!endif - Pop ${output} -!macroend - -!macro Func_StrRep un - Function ${un}StrRep - Exch $R2 ;new - Exch 1 - Exch $R1 ;old - Exch 2 - Exch $R0 ;string - Push $R3 - Push $R4 - Push $R5 - Push $R6 - Push $R7 - Push $R8 - Push $R9 - - StrCpy $R3 0 - StrLen $R4 $R1 - StrLen $R6 $R0 - StrLen $R9 $R2 - loop: - StrCpy $R5 $R0 $R4 $R3 - StrCmp $R5 $R1 found - StrCmp $R3 $R6 done - IntOp $R3 $R3 + 1 ;move offset by 1 to check the next character - Goto loop - found: - StrCpy $R5 $R0 $R3 - IntOp $R8 $R3 + $R4 - StrCpy $R7 $R0 "" $R8 - StrCpy $R0 $R5$R2$R7 - StrLen $R6 $R0 - IntOp $R3 $R3 + $R9 ;move offset by length of the replacement string - Goto loop - done: - - Pop $R9 - Pop $R8 - Pop $R7 - Pop $R6 - Pop $R5 - Pop $R4 - Pop $R3 - Push $R0 - Push $R1 - Pop $R0 - Pop $R1 - Pop $R0 - Pop $R2 - Exch $R1 - FunctionEnd -!macroend -!insertmacro Func_StrRep "" -;!insertmacro Func_StrRep "un." \ No newline at end of file diff --git a/old code/tray/ant/windows/nsis/Include/StrTok.nsh b/old code/tray/ant/windows/nsis/Include/StrTok.nsh deleted file mode 100755 index 0c09ac7..0000000 --- a/old code/tray/ant/windows/nsis/Include/StrTok.nsh +++ /dev/null @@ -1,150 +0,0 @@ -!define StrTok "!insertmacro StrTok" - -!macro StrTok ResultVar String Separators ResultPart SkipEmptyParts - Push "${String}" - Push "${Separators}" - Push "${ResultPart}" - Push "${SkipEmptyParts}" - Call StrTok - Pop "${ResultVar}" -!macroend - -Function StrTok -/*After this point: - ------------------------------------------ - $0 = SkipEmptyParts (input) - $1 = ResultPart (input) - $2 = Separators (input) - $3 = String (input) - $4 = SeparatorsLen (temp) - $5 = StrLen (temp) - $6 = StartCharPos (temp) - $7 = TempStr (temp) - $8 = CurrentLoop - $9 = CurrentSepChar - $R0 = CurrentSepCharNum - */ - - ;Get input from user - Exch $0 - Exch - Exch $1 - Exch - Exch 2 - Exch $2 - Exch 2 - Exch 3 - Exch $3 - Exch 3 - Push $4 - Push $5 - Push $6 - Push $7 - Push $8 - Push $9 - Push $R0 - - ;Parameter defaults - ${IfThen} $2 == `` ${|} StrCpy $2 `|` ${|} - ${IfThen} $1 == `` ${|} StrCpy $1 `L` ${|} - ${IfThen} $0 == `` ${|} StrCpy $0 `0` ${|} - - ;Get "String" and "Separators" length - StrLen $4 $2 - StrLen $5 $3 - ;Start "StartCharPos" and "ResultPart" counters - StrCpy $6 0 - StrCpy $8 -1 - - ;Loop until "ResultPart" is met, "Separators" is found or - ;"String" reaches its end - ResultPartLoop: ;"CurrentLoop" Loop - - ;Increase "CurrentLoop" counter - IntOp $8 $8 + 1 - - StrSearchLoop: - ${Do} ;"String" Loop - ;Remove everything before and after the searched part ("TempStr") - StrCpy $7 $3 1 $6 - - ;Verify if it's the "String" end - ${If} $6 >= $5 - ;If "CurrentLoop" is what the user wants, remove the part - ;after "TempStr" and itself and get out of here - ${If} $8 == $1 - ${OrIf} $1 == `L` - StrCpy $3 $3 $6 - ${Else} ;If not, empty "String" and get out of here - StrCpy $3 `` - ${EndIf} - StrCpy $R0 `End` - ${ExitDo} - ${EndIf} - - ;Start "CurrentSepCharNum" counter (for "Separators" Loop) - StrCpy $R0 0 - - ${Do} ;"Separators" Loop - ;Use one "Separators" character at a time - ${If} $R0 <> 0 - StrCpy $9 $2 1 $R0 - ${Else} - StrCpy $9 $2 1 - ${EndIf} - - ;Go to the next "String" char if it's "Separators" end - ${IfThen} $R0 >= $4 ${|} ${ExitDo} ${|} - - ;Or, if "TempStr" equals "CurrentSepChar", then... - ${If} $7 == $9 - StrCpy $7 $3 $6 - - ;If "String" is empty because this result part doesn't - ;contain data, verify if "SkipEmptyParts" is activated, - ;so we don't return the output to user yet - - ${If} $7 == `` - ${AndIf} $0 = 1 ;${TRUE} - IntOp $6 $6 + 1 - StrCpy $3 $3 `` $6 - StrCpy $6 0 - Goto StrSearchLoop - ${ElseIf} $8 == $1 - StrCpy $3 $3 $6 - StrCpy $R0 "End" - ${ExitDo} - ${EndIf} ;If not, go to the next result part - IntOp $6 $6 + 1 - StrCpy $3 $3 `` $6 - StrCpy $6 0 - Goto ResultPartLoop - ${EndIf} - - ;Increase "CurrentSepCharNum" counter - IntOp $R0 $R0 + 1 - ${Loop} - ${IfThen} $R0 == "End" ${|} ${ExitDo} ${|} - - ;Increase "StartCharPos" counter - IntOp $6 $6 + 1 - ${Loop} - -/*After this point: - ------------------------------------------ - $3 = ResultVar (output)*/ - - ;Return output to user - - Pop $R0 - Pop $9 - Pop $8 - Pop $7 - Pop $6 - Pop $5 - Pop $4 - Pop $0 - Pop $1 - Pop $2 - Exch $3 -FunctionEnd \ No newline at end of file diff --git a/old code/tray/ant/windows/nsis/Plugins/Release_ANSI/AccessControl.dll b/old code/tray/ant/windows/nsis/Plugins/Release_ANSI/AccessControl.dll deleted file mode 100755 index 0de0324..0000000 Binary files a/old code/tray/ant/windows/nsis/Plugins/Release_ANSI/AccessControl.dll and /dev/null differ diff --git a/old code/tray/ant/windows/nsis/Plugins/Release_ANSI/StdUtils.dll b/old code/tray/ant/windows/nsis/Plugins/Release_ANSI/StdUtils.dll deleted file mode 100755 index 5317b6d..0000000 Binary files a/old code/tray/ant/windows/nsis/Plugins/Release_ANSI/StdUtils.dll and /dev/null differ diff --git a/old code/tray/ant/windows/nsis/Plugins/Release_Unicode/AccessControl.dll b/old code/tray/ant/windows/nsis/Plugins/Release_Unicode/AccessControl.dll deleted file mode 100755 index cc27f63..0000000 Binary files a/old code/tray/ant/windows/nsis/Plugins/Release_Unicode/AccessControl.dll and /dev/null differ diff --git a/old code/tray/ant/windows/nsis/Plugins/Release_Unicode/StdUtils.dll b/old code/tray/ant/windows/nsis/Plugins/Release_Unicode/StdUtils.dll deleted file mode 100755 index 6c852f4..0000000 Binary files a/old code/tray/ant/windows/nsis/Plugins/Release_Unicode/StdUtils.dll and /dev/null differ diff --git a/old code/tray/ant/windows/nsis/console.ico b/old code/tray/ant/windows/nsis/console.ico deleted file mode 100755 index 1630b6e..0000000 Binary files a/old code/tray/ant/windows/nsis/console.ico and /dev/null differ diff --git a/old code/tray/ant/windows/nsis/uninstall.ico b/old code/tray/ant/windows/nsis/uninstall.ico deleted file mode 100755 index dd5405c..0000000 Binary files a/old code/tray/ant/windows/nsis/uninstall.ico and /dev/null differ diff --git a/old code/tray/ant/windows/nsis/welcome.bmp b/old code/tray/ant/windows/nsis/welcome.bmp deleted file mode 100755 index 71c2da5..0000000 Binary files a/old code/tray/ant/windows/nsis/welcome.bmp and /dev/null differ diff --git a/old code/tray/ant/windows/windows-installer.nsi.in b/old code/tray/ant/windows/windows-installer.nsi.in deleted file mode 100755 index 9b8f80d..0000000 --- a/old code/tray/ant/windows/windows-installer.nsi.in +++ /dev/null @@ -1,132 +0,0 @@ -!define MUI_BGCOLOR "SYSCLR:Window" -!define MUI_TEXTCOLOR "SYSCLR:WindowText" -!include MUI2.nsh -!include x64.nsh -!include LogicLib.nsh - -!ifdef NSIS_UNICODE - !addplugindir "${basedir}/ant/windows/nsis/Plugins/Release_Unicode" -!else - !addplugindir "${basedir}/ant/windows/nsis/Plugins/Release_ANSI" -!endif -!addincludedir "${basedir}/ant/windows/nsis/Include" -!include FindJava.nsh -!include StdUtils.nsh -!include StrLoc.nsh - -Name "${project.name}" -OutFile "${nsis.outfile}" -RequestExecutionLevel admin - -!define MUI_ICON "${basedir}/assets/branding/windows-icon.ico" - -; Branding for qz only -!if "${project.filename}" == "qz-tray" - !define MUI_WELCOMEFINISHPAGE_BITMAP "${basedir}\ant\windows\nsis\welcome.bmp" -!endif - -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES -!insertmacro MUI_LANGUAGE "English" - -!macro QzInstaller step option value - SetDetailsPrint textonly - DetailPrint "Running ${step}..." - SetDetailsPrint listonly - DetailPrint 'Running ${step}: "$java" ${install.opts} -jar "$OUTDIR\${project.filename}.jar" "${step}" "${option}" "${value}"' - SetDetailsPrint both - ClearErrors - nsExec::ExecToLog '"$java" ${install.opts} -jar "$OUTDIR\${project.filename}.jar" "${step}" "${option}" "${value}"' - Pop $0 - ${If} "$0" != "0" - Abort "Installation failed during ${step} step. Please check log for details." - ${EndIf} -!macroend - -!macro VerifyJava jumpto - ; Test java executable - nsExec::ExecToLog '"$java" -version"' - Pop $0 - ${If} "$0" == "0" - Goto Resume - ${EndIf} - - ; Handle scenario where Java is bundled but broken - ${StrLoc} $R1 "$java" "runtime\bin" ">" ; e.g. "nss1234.tmp\payload\runtime\bin\java.exe" - ${If} $R1 != "" - SetDetailsPrint both - Abort "Sorry, this version of ${project.name} cannot be installed on this system." - ${EndIf} - - ; Offer to download Java if missing and non-silent install - ${IfNot} ${Silent} - MessageBox MB_YESNO "Java is required. Download now?" IDYES Website IDNO Resume - - ; Visit Java website - Website: - ExecShell "open" "${java.download}" - MessageBox MB_OK "Click OK after Java is installed" - - ; Check again for Java - Goto ${jumpto} - ${EndIf} - Resume: -!macroend - -Section - ; Set environmental variable for silent install to be picked up by Java - ${If} ${Silent} - System::Call 'Kernel32::SetEnvironmentVariable(t, t)i ("${vendor.name}_silent", "1").r0' - ${EndIf} - - ; Echo final destination to logs - SetOutPath $INSTDIR - - ; Copy files to a temporary location - SetOutPath "$PLUGINSDIR\payload" - DetailPrint "Extracting..." - SetDetailsPrint none ; Temporarily suppress details - File /r "${dist.dir}\*" - - ; Set the $java variable - TryAgain: - Push "$OUTDIR" - Call FindJava - !insertmacro VerifyJava "TryAgain" - - ; Run preinstall tasks - SetDetailsPrint both - !insertmacro QzInstaller "preinstall" "" "" - - ; Run install tasks - !insertmacro QzInstaller "install" "--dest" $INSTDIR - - ; Run certgen tasks - SetOutPath $INSTDIR - !insertmacro QzInstaller "certgen" "" "" - - ; Launch a non-elevated instance of ${project.name} - ${StdUtils.ExecShellAsUser} $0 "$INSTDIR\${project.filename}.exe" "open" "" -SectionEnd - -!macro Init - ${If} ${RunningX64} - SetRegView 64 - ${DisableX64FSRedirection} - ${EndIf} - ${If} $INSTDIR == "" - ${If} ${RunningX64} - StrCpy $INSTDIR "$PROGRAMFILES64\${project.name}" - ${Else} - StrCpy $INSTDIR "$PROGRAMFILES\${project.name}" - ${EndIf} - ${EndIf} -!macroend - -; Runs for installs -Function .onInit - !insertmacro Init -FunctionEnd diff --git a/old code/tray/ant/windows/windows-launcher.nsi.in b/old code/tray/ant/windows/windows-launcher.nsi.in deleted file mode 100755 index 9051491..0000000 --- a/old code/tray/ant/windows/windows-launcher.nsi.in +++ /dev/null @@ -1,91 +0,0 @@ -!include x64.nsh -!include LogicLib.nsh - -!ifdef NSIS_UNICODE - !addplugindir "${basedir}/ant/windows/nsis/Plugins/Release_Unicode" -!else - !addplugindir "${basedir}/ant/windows/nsis/Plugins/Release_ANSI" -!endif -!addincludedir "${basedir}/ant/windows/nsis/Include" -!include StdUtils.nsh -!include StrLoc.nsh -!include FindJava.nsh - -!insertmacro GetParameters - -; Run this exe as non-admin -RequestExecutionLevel user - -; Application information -Name "${project.name}" -Caption "${project.name}" -Icon "${basedir}/assets/branding/windows-icon.ico" -OutFile "${nsis.outfile}" - -SilentInstall silent -AutoCloseWindow true -ShowInstDetails nevershow - -; Full path to jar -!define JAR "$EXEDIR/${project.filename}.jar" - -Section - ${If} ${RunningX64} - ${DisableX64FSRedirection} - ${EndIf} - SetOutPath $EXEDIR - - ; Get params to pass to jar - Var /GLOBAL params - ${GetParameters} $params - - ; Sets the $java variable - Push "$EXEDIR" - Call FindJava - - Var /GLOBAL opts - StrCpy $opts "${launch.opts}" - ; Handle jdk9+ flags - ${If} $java_major >= 9 - StrCpy $opts "${launch.opts} ${launch.jigsaw}" - ${EndIf} - - ; Check for user overridable launch options - ClearErrors - ReadEnvStr $R0 ${launch.overrides} - IfErrors +2 0 - StrCpy $opts "$opts $R0" - - Var /GLOBAL command - StrCpy $command '"$javaw" $opts -jar "${JAR}" $params' - - ; If ends in "-console.exe", use "cmd /s /k" to launch - ${StrLoc} $R1 "${nsis.outfile}" "-console.exe" "<" - ${If} $R1 == "0" - ExpandEnvStrings $R2 %COMSPEC% - StrCpy $command '"$R2" /s /k "$command"' - ${EndIf} - - ; Allow return of exit code - ${StrLoc} $R2 $params "--wait" "<" - ${If} $R2 != "" - ; Switch from /k to /c to capture exit code from -console.exe - ${StrRep} $command "$command" " /k " " /c " - ExecWait $command $R3 - ; Set error-level - SetErrorLevel $R3 - ${Else} - Exec $command - ${EndIf} - - ${If} ${RunningX64} - ${EnableX64FSRedirection} - ${EndIf} -SectionEnd - -Function .onInit - ${If} ${RunningX64} - SetRegView 64 - ${DisableX64FSRedirection} - ${EndIf} -FunctionEnd \ No newline at end of file diff --git a/old code/tray/ant/windows/windows-uninstaller.nsi.in b/old code/tray/ant/windows/windows-uninstaller.nsi.in deleted file mode 100755 index e572ec1..0000000 --- a/old code/tray/ant/windows/windows-uninstaller.nsi.in +++ /dev/null @@ -1,117 +0,0 @@ -!define MUI_BGCOLOR "SYSCLR:Window" -!define MUI_TEXTCOLOR "SYSCLR:WindowText" -!include MUI2.nsh -!include x64.nsh -!include LogicLib.nsh -!include FileFunc.nsh -!include WinMessages.nsh - -!ifdef NSIS_UNICODE - !addplugindir "${basedir}/ant/windows/nsis/Plugins/Release_Unicode" -!else - !addplugindir "${basedir}/ant/windows/nsis/Plugins/Release_ANSI" -!endif -!addincludedir "${basedir}/ant/windows/nsis/Include" -!include StdUtils.nsh -!include SetTitleBar.nsh -!include FindJava.nsh - -!define MUI_PRODUCT "${project.name}" -!define MUI_VERSION "${build.version}" -; Branding for qz only -!if "${project.filename}" == "qz-tray" - !define MUI_ICON "${basedir}/ant/windows/nsis/uninstall.ico" -!else - !define MUI_ICON "${basedir}/assets/branding/windows-icon.ico" -!endif - -!define MUI_PAGE_HEADER_TEXT "Uninstall ${project.name}" -!define MUI_PAGE_HEADER_SUBTEXT "Remove ${project.name} from your computer" -!define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "Uninstallation Complete" -!define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "Uninstall was completed successfully." - -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_LANGUAGE "English" -!insertmacro GetParameters - -RequestExecutionLevel admin -CRCCheck On - -Name "Uninstall ${project.name}" -Caption "Uninstall ${project.name}" -Icon "${basedir}/ant/windows/nsis/uninstall.ico" -OutFile "${nsis.outfile}" - -Var /GLOBAL RESPAWN -Var /GLOBAL DELETE_DIR -Var /GLOBAL DELETE_EXE - -Section - ${SetTitlebar} "Uninstall" - SetDetailsPrint textonly - DetailPrint "Uninstalling" - SetDetailsPrint listonly - - ${GetParameters} $0 - ${GetOptions} "$0" "/RESPAWN=" $RESPAWN - ${GetOptions} "$0" "/DELETE_DIR=" $DELETE_DIR - ${GetOptions} "$0" "/DELETE_EXE=" $DELETE_EXE - - ${If} $RESPAWN != "" - ; We're running from $TEMP; Perform the uninstall - - ; Set environmental variable for silent uninstall to be picked up by Java - ${If} ${Silent} - System::Call 'Kernel32::SetEnvironmentVariable(t, t)i ("${vendor.name}_silent", "1").r0' - ${EndIf} - - ; Set $javaw variable - Push "$DELETE_DIR" - Call FindJava - - ; Run uninstall step using jar - SetDetailsPrint textonly - DetailPrint "Running uninstall..." - SetDetailsPrint none ; Temporarily suppress details - SetOutPath $DELETE_DIR - SetDetailsPrint listonly - DetailPrint 'Running uninstall: "$java" ${install.opts} -jar "$DELETE_DIR\${project.filename}.jar" uninstall' - ClearErrors - nsExec::ExecToLog '"$java" ${install.opts} -jar "$DELETE_DIR\${project.filename}.jar" uninstall' - Pop $0 - ${If} "$0" != "0" - Abort "Uninstall failed." - ${EndIf} - - ; Remove all files - DetailPrint "Removing remaining files..." - SetDetailsPrint none ; Temporarily suppress details - SetOutPath $TEMP - RMDir /r "$DELETE_DIR" - - ; Remove self from $TEMP after reboot - Delete /REBOOTOK $EXEPATH - - ${If} ${RunningX64} - ${EnableX64FSRedirection} - ${EndIf} - SetDetailsPrint both - ${Else} - ; We're NOT running from $TEMP, copy to temp and respawn ourself - GetTempFileName $0 - CopyFiles "$EXEPATH" "$0" - ${If} ${Silent} - Exec '"$0" /S /RESPAWN=1 /DELETE_DIR="$EXEDIR" /DELETE_EXE="$EXEPATH"' - ${Else} - Exec '"$0" /RESPAWN=1 /DELETE_DIR="$EXEDIR" /DELETE_EXE="$EXEPATH"' - ${EndIf} - Quit - ${EndIf} -SectionEnd - -Function .onInit - ${If} ${RunningX64} - SetRegView 64 - ${DisableX64FSRedirection} - ${EndIf} -FunctionEnd \ No newline at end of file diff --git a/old code/tray/assets/branding/apple-icon.icns b/old code/tray/assets/branding/apple-icon.icns deleted file mode 100755 index a375406..0000000 Binary files a/old code/tray/assets/branding/apple-icon.icns and /dev/null differ diff --git a/old code/tray/assets/branding/linux-icon.svg b/old code/tray/assets/branding/linux-icon.svg deleted file mode 100755 index f672314..0000000 --- a/old code/tray/assets/branding/linux-icon.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - diff --git a/old code/tray/assets/branding/windows-icon.ico b/old code/tray/assets/branding/windows-icon.ico deleted file mode 100755 index 4b474ba..0000000 Binary files a/old code/tray/assets/branding/windows-icon.ico and /dev/null differ diff --git a/old code/tray/assets/epl_multiples.txt b/old code/tray/assets/epl_multiples.txt deleted file mode 100755 index bd474b0..0000000 --- a/old code/tray/assets/epl_multiples.txt +++ /dev/null @@ -1,33 +0,0 @@ - -N -q812;four inch width for 203dpi printer -Q1218,26;six inch height for 203dpi printer -B5,26,0,1A,3,7,152,B,"0001" -A310,26,0,3,1,1,N,"SKU 00001 MFG 0001" -A310,56,0,3,1,1,N,"QZ-Tray Java Application" -A310,86,0,3,1,1,N,"TEST PRINT SUCCESSFUL" -A310,116,0,3,1,1,N,"FROM SAMPLE.HTML" -A310,146,0,3,1,1,N,"EDIT EPL_MULTIPLES.TXT" -P1,1 - -N -q812 -Q1218,26 -B5,26,0,1A,3,7,152,B,"0002" -A310,26,0,3,1,1,N,"SKU 00002 MFG 0002" -A310,56,0,3,1,1,N,"QZ-Tray Java Application" -A310,86,0,3,1,1,N,"TEST PRINT SUCCESSFUL" -A310,116,0,3,1,1,N,"FROM SAMPLE.HTML" -A310,146,0,3,1,1,N,"EDIT EPL_MULTIPLES.TXT" -P1,1 - -N -q812 -Q1218,26 -B5,26,0,1A,3,7,152,B,"0003" -A310,26,0,3,1,1,N,"SKU 00003 MFG 0003" -A310,56,0,3,1,1,N,"QZ-Tray Java Application" -A310,86,0,3,1,1,N,"TEST PRINT SUCCESSFUL" -A310,116,0,3,1,1,N,"FROM SAMPLE.HTML" -A310,146,0,3,1,1,N,"EDIT EPL_MULTIPLES.TXT" -P1,1 diff --git a/old code/tray/assets/epl_sample.txt b/old code/tray/assets/epl_sample.txt deleted file mode 100755 index c604175..0000000 --- a/old code/tray/assets/epl_sample.txt +++ /dev/null @@ -1,11 +0,0 @@ - -N -q812 -Q1218,26; q and Q values edited to reflect 4x6 inch size at 203 dpi -B5,26,0,1A,3,7,152,B,"1234" -A310,26,0,3,1,1,N,"SKU 00000 MFG 0000" -A310,56,0,3,1,1,N,"QZ-Tray Java Application" -A310,86,0,3,1,1,N,"TEST PRINT SUCCESSFUL" -A310,116,0,3,1,1,N,"FROM SAMPLE.HTML" -A310,146,0,3,1,1,N,"EDIT EPL_SAMPLE.TXT" -P1,1 diff --git a/old code/tray/assets/escpos_sample.bin b/old code/tray/assets/escpos_sample.bin deleted file mode 100755 index 54f17f2..0000000 Binary files a/old code/tray/assets/escpos_sample.bin and /dev/null differ diff --git a/old code/tray/assets/fgl_sample.txt b/old code/tray/assets/fgl_sample.txt deleted file mode 100755 index e85379e..0000000 --- a/old code/tray/assets/fgl_sample.txt +++ /dev/null @@ -1,25 +0,0 @@ -BOCA -PROM= -GHOSTWRITER -FRIENDLY GHOST LANGUAGE -PLACE LETTERS ANYWHERE -VOID -TEST TICKET ONLY -*GHOST 123* - CODE 39 -TICKET & LABEL PRINTER -EXCELLENT PRINT QUALITY - Print any bar code -^CODE 128^ -CODE 128 -*MONKEY* -*MONKEY* - -SW1= SW2= SW3=LEFT = 1 RIGHT = 0 -Script printing is now standard. -High density printing is clear and readable -High density printing is clear and readable -Legal size printing - -

- \ No newline at end of file diff --git a/old code/tray/assets/img/fade-test.png b/old code/tray/assets/img/fade-test.png deleted file mode 100755 index d0b9561..0000000 Binary files a/old code/tray/assets/img/fade-test.png and /dev/null differ diff --git a/old code/tray/assets/img/image_sample.png b/old code/tray/assets/img/image_sample.png deleted file mode 100755 index 13d145e..0000000 Binary files a/old code/tray/assets/img/image_sample.png and /dev/null differ diff --git a/old code/tray/assets/img/image_sample_bw.png b/old code/tray/assets/img/image_sample_bw.png deleted file mode 100755 index 2d0483b..0000000 Binary files a/old code/tray/assets/img/image_sample_bw.png and /dev/null differ diff --git a/old code/tray/assets/pdf_sample.pdf b/old code/tray/assets/pdf_sample.pdf deleted file mode 100755 index ec66729..0000000 Binary files a/old code/tray/assets/pdf_sample.pdf and /dev/null differ diff --git a/old code/tray/assets/pgl_sample.txt b/old code/tray/assets/pgl_sample.txt deleted file mode 100755 index 94f1652..0000000 --- a/old code/tray/assets/pgl_sample.txt +++ /dev/null @@ -1,12 +0,0 @@ -~CREATE;DATAMATRIX;144 -SCALE;DOT;300;300 -ALPHA -POINT;50;100;16;9;*Printed using QZ Tray* -STOP -BARCODE -DATAMATRIX;XD16;C20;R20;ECC200;ID5;150;150 -*0100000123000017* -STOP -END -~EXECUTE;DATAMATRIX;1 -~NORMAL diff --git a/old code/tray/assets/sbpl_sample.txt b/old code/tray/assets/sbpl_sample.txt deleted file mode 100755 index 1b83e34..0000000 --- a/old code/tray/assets/sbpl_sample.txt +++ /dev/null @@ -1,23 +0,0 @@ -AA1V01678H0812 -PS%0H0040V01510FW02H0735 -%2H200V1590P02RDB@1,057,056,SATO -%0H0040V01076FW02H0735 -%2H0353V01215P02RDB@0,026,025,BEST BEFORE -%2H0761V01215P02RDB@0,026,025,BATCH/LOT -%2H0761V01370P02RDB@0,026,025,CONTENT -%2H0761V01489P02RDB@0,026,025,SSCC -%2H0758V01590P02RDB@1,057,056,Product -%2H0777V01669P02RDB@0,057,056, -%2H0761V01183P02RDB@0,061,062,223344 -%2H0589V00109P02RDB@1,038,037,(00)038312345600000018 -%2H0741V01052BG04256>I>F0203831234560087370001 -%2H0719V00374BG04256>I>F00038312345600000018 -%2H0617V00786P02RDB@1,038,037,(02)03831234560087(37)0001 -%2H0139V01370P02RDB@0,026,025,COUNT -%2H0139V01344P02RDB@0,061,062,0001 -%2H0761V01344P02RDB@0,061,062,03831234560087 -%2H0761V01463P02RDB@1,061,062,038312345600000018 -%2H0675V00697BG04240>I>F1525052010223344 -%2H0559V00443P02RDB@1,038,037,(15)250520(10)223344 -%2H0355V01182P02RDB@0,061,062,20.05.25 -Q1Z \ No newline at end of file diff --git a/old code/tray/assets/signing/sign-message.R b/old code/tray/assets/signing/sign-message.R deleted file mode 100755 index 73b5d0c..0000000 --- a/old code/tray/assets/signing/sign-message.R +++ /dev/null @@ -1,38 +0,0 @@ -# -# Echoes the signed message and exits -# usage: R sign-message.R "test" -# - -######################################################### -# WARNING WARNING WARNING # -######################################################### -# # -# This file is intended for demonstration purposes # -# only. # -# # -# It is the SOLE responsibility of YOU, the programmer # -# to prevent against unauthorized access to any signing # -# functions. # -# # -# Organizations that do not protect against un- # -# authorized signing will be black-listed to prevent # -# software piracy. # -# # -# -QZ Industries, LLC # -# # -######################################################### - -library(openssl) - -mykey <- "private-key.pem" - -# Treat command line argument as message to be signed -message <- enc2utf8(commandArgs(trailingOnly = TRUE)) - -# Load the private key -key <- read_key(file = mykey, password = mypass) - -# Create the signature -sig <- signature_create(serialize(message, NULL), hash = sha512, key = key) # Use hash = sha1 for QZ Tray 2.0 and older - -print(sig) diff --git a/old code/tray/assets/signing/sign-message.asp b/old code/tray/assets/signing/sign-message.asp deleted file mode 100755 index 0ac1309..0000000 --- a/old code/tray/assets/signing/sign-message.asp +++ /dev/null @@ -1,50 +0,0 @@ -<% -'######################################################### -'# WARNING WARNING WARNING # -'######################################################### -'# # -'# This file is intended for demonstration purposes # -'# only. # -'# # -'# It is the SOLE responsibility of YOU, the programmer # -'# to prevent against unauthorized access to any signing # -'# functions. # -'# # -'# Organizations that do not protect against un- # -'# authorized signing will be black-listed to prevent # -'# software piracy. # -'# # -'# -QZ Industries, LLC # -'# # -'######################################################### -Option Explicit -Dim rsa, pem, sig, data, glob, success, password -' New unlock method for Chilkat - Unregistered version, only good for 30 days -Set glob = Server.CreateObject("Chilkat_9_5_0.Global") -success = glob.UnlockBundle("Anything for 30-day trial") -If (success <> 1) Then - Response.Write "

" & Server.HTMLEncode(glob.LastErrorText) & "
" - Response.End -End If - -' ActiveX library http://www.chilkatsoft.com/ -Set pem = CreateObject("Chilkat_9_5_0.Pem") -Set rsa = CreateObject("Chilkat_9_5_0.Rsa") - -data = request("request") - -password = "" -success = pem.LoadPemFile("private-key.pem", password) -If (success <> 1) Then - Response.Write "
" & Server.HTMLEncode(pem.LastErrorText) & "
" - Response.End -End If - -rsa.ImportPrivateKey(pem.GetPrivateKey(0).getXml()) -rsa.EncodingMode = "base64" -sig = rsa.SignStringENC(data, "SHA-512") ' Use "SHA-1" for QZ Tray 2.0 and older - -Response.ContentType = "text/plain" -Response.Write Server.HTMLEncode(sig) - -%> diff --git a/old code/tray/assets/signing/sign-message.bouncycastle.cs b/old code/tray/assets/signing/sign-message.bouncycastle.cs deleted file mode 100755 index 6d98fa1..0000000 --- a/old code/tray/assets/signing/sign-message.bouncycastle.cs +++ /dev/null @@ -1,67 +0,0 @@ -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -using System; -using System.Text; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.OpenSsl; -using Org.BouncyCastle.Security; - - -// Public method for signing the input string with the private key -// =============================================================== - -string privateKey = "private-key.pem"; // PKCS#8 PEM file - -string SignMessage(string msg) -{ - // Convert the input string to a byte array - byte[] input = Encoding.ASCII.GetBytes(msg); - - // Initialize the signer with the algorithm and the private key - ISigner sig = SignerUtilities.GetSigner("SHA512withRSA"); - sig.Init(true, getPrivateKey()); - - // Generate signature and return it as a base64 string - sig.BlockUpdate(input, 0, input.Length); - return Convert.ToBase64String(sig.GenerateSignature()); -} - -AsymmetricKeyParameter getPrivateKey() -{ - using (var reader = System.IO.File.OpenText(privateKey)) - { - var pem = new PemReader(reader).ReadObject(); - return pem as AsymmetricKeyParameter ?? (pem as AsymmetricCipherKeyPair).Private; - } -} - - -// Public method for returning the certificate -// =========================================== - -string certificate = "digital-certificate.txt"; - -string GetCertificate() -{ - using (var reader = System.IO.File.OpenText(certificate)) - { - return reader.ReadToEnd(); - } -} diff --git a/old code/tray/assets/signing/sign-message.cfm b/old code/tray/assets/signing/sign-message.cfm deleted file mode 100755 index cc36133..0000000 --- a/old code/tray/assets/signing/sign-message.cfm +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ColdFusion signing example - * Echoes the signed message and exits - */ - -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - - - -#signature# - - -/** -* Sign the given string -* @keyPath Path to PEM formatted private key -* @message message to be signed -* @encoding I am the encoding used when returning the signature (base64 by default). -* @output false -*/ -public any function sign(required string keyPath, required string message, string algorithm = "SHA512withRSA", string encoding = "base64") { - // Note: change algorithm to "SHA1withRSA" for QZ Tray 2.0 and older - createObject("java", "java.security.Security") - .addProvider(createObject("java", "org.bouncycastle.jce.provider.BouncyCastleProvider").init()); - privateKey = createPrivateKey(fileRead(expandPath(keyPath))); - var signer = createObject("java", "java.security.Signature").getInstance(javaCast( "string", algorithm )); - signer.initSign(privateKey); - signer.update(charsetDecode(message, "utf-8")); - var signedBytes = signer.sign(); - return encoding == "binary" ? signedBytes : binaryEncode(signedBytes, encoding); -} - -/** -* Set the private key using the provided pem formatted content. -* -* @contents PEM key contents -* @output false -*/ -private any function createPrivateKey(required string contents) { - var pkcs8 = createObject("java", "java.security.spec.PKCS8EncodedKeySpec").init( - binaryDecode(stripKeyDelimiters(contents), "base64") - ); - - return createObject("java", "java.security.KeyFactory") - .getInstance(javaCast( "string", "RSA" )).generatePrivate(pkcs8); -} - -/** -* Strip X509 cert delimiters -* -* @keyText PEM formatted key data -* @output false -*/ -private string function stripKeyDelimiters(required string keyText) { - return trim(reReplace(keyText, "-----(BEGIN|END)[^\r\n]+", "", "all" )); -} - diff --git a/old code/tray/assets/signing/sign-message.cls b/old code/tray/assets/signing/sign-message.cls deleted file mode 100755 index 91e0062..0000000 --- a/old code/tray/assets/signing/sign-message.cls +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Salesforce APEX Signing Example - * Returns the signed message to a wired controller - */ - -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -public with sharing class SignMessage { - @AuraEnabled(cacheable = true) - public static String signMessage(String toSign){ - String privateKeyBase64 = ''; - - Blob sig = Crypto.sign('RSA-SHA512', - Blob.valueOf(toSign), - EncodingUtil.base64Decode(privateKeyBase64)); - - return EncodingUtil.base64Encode(sig); - } -} - -/** JavaScript - Adjust as needed - -import signMessage from '@salesforce/apex/SignMessage.signMessage'; -@wire(signMessage) - -qz.security.setSignatureAlgorithm("SHA512"); -qz.security.setSignaturePromise(function(toSign) { - return function (resolve, reject) { - try { - resolve(signMessage({toSign : toSign})); - } catch(err) { - reject(err); - } - } -}); - -**/ diff --git a/old code/tray/assets/signing/sign-message.core.cs b/old code/tray/assets/signing/sign-message.core.cs deleted file mode 100755 index f453e07..0000000 --- a/old code/tray/assets/signing/sign-message.core.cs +++ /dev/null @@ -1,53 +0,0 @@ -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Web.Services; - -// To convert a .PEM PrivateKey: -// openssl pkcs12 -export -inkey private-key.pem -in digital-certificate.txt -out private-key.pfx -private static X509KeyStorageFlags STORAGE_FLAGS = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable; - -public IActionResult Index(string request) -{ - var KEY = "/path/to/private-key.pfx"; - var PASS = ""; - - try - { - byte[] data = new ASCIIEncoding().GetBytes(request); - var cert = new X509Certificate2(KEY, PASS, STORAGE_FLAGS); - RSA rsa = (RSA)cert.GetRSAPrivateKey(); - var signed = rsa.SignData(data, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1); - string base64 = Convert.ToBase64String(signed); - return Content(base64); - } - catch(Exception ex) - { - if((STORAGE_FLAGS & X509KeyStorageFlags.MachineKeySet) == X509KeyStorageFlags.MachineKeySet) - { - // IISExpress may fail with "Invalid provider type specified"; remove MachineKeySet flag, try again - STORAGE_FLAGS = STORAGE_FLAGS & ~X509KeyStorageFlags.MachineKeySet; - return Index(request); - } - throw ex; - } -} diff --git a/old code/tray/assets/signing/sign-message.cs b/old code/tray/assets/signing/sign-message.cs deleted file mode 100755 index 90abc79..0000000 --- a/old code/tray/assets/signing/sign-message.cs +++ /dev/null @@ -1,80 +0,0 @@ -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Web.Services; - -// To convert a .PEM PrivateKey: -// openssl pkcs12 -export -inkey private-key.pem -in digital-certificate.txt -out private-key.pfx -private static X509KeyStorageFlags STORAGE_FLAGS = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable; - -/** - * Note, this example is for .NET Forms/PageMethods - * For MVC, change the following: - * - * public ActionResult SignMessage() { - * string request = Request.QueryString["request"]; - * ... - * return Content(base64, "text/plain"); - * ... - * return SignMessage(); - * - * ... and replace PageMethods calls with fetch("@Url.Content("./SignMessage/?request=")" + toSign - */ -[WebMethod] -public static string SignMessage(string request) -{ - //var WEBROOT_PATH = HttpContext.Current.Server.MapPath("/"); - //var CURRENT_PATH = HttpContext.Current.Server.MapPath("~"); - //var PARENT_PATH = System.IO.Directory.GetParent(WEBROOT).Parent.FullName; - var KEY = "/path/to/private-key.pfx"; - var PASS = ""; - - try - { - var cert = new X509Certificate2(KEY, PASS, STORAGE_FLAGS); - RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PrivateKey; // PFX defaults to the weaker "SHA1" - byte[] data = new ASCIIEncoding().GetBytes(request); - RSACryptoServiceProvider cspStrong = new RSACryptoServiceProvider(); // 2.1 and higher: Make RSACryptoServiceProvider that can handle SHA256, SHA512 - cspStrong.ImportParameters(csp.ExportParameters(true)); // Copy to stronger RSACryptoServiceProvider - byte[] hash = new SHA512CryptoServiceProvider().ComputeHash(data); // Use SHA1CryptoServiceProvider for QZ Tray 2.0 and older - string base64 = Convert.ToBase64String(cspStrong.SignHash(hash, CryptoConfig.MapNameToOID("SHA512"))); // Use "SHA1" for QZ Tray 2.0 and older - return base64; - - /* - * // Or per https://stackoverflow.com/a/50104158/3196753 - * var cert = new X509Certificate2(KEY, PASS, STORAGE_FLAGS); - * var csp = cert.GetRSAPrivateKey(); - * byte[] data = new ASCIIEncoding().GetBytes(request); - * return Convert.ToBase64String(csp.SignData(data, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1)); // Use "SHA1" for QZ Tray 2.0 and older - */ - } - catch(Exception ex) - { - if((STORAGE_FLAGS & X509KeyStorageFlags.MachineKeySet) == X509KeyStorageFlags.MachineKeySet) - { - // IISExpress may fail with "Invalid provider type specified"; remove MachineKeySet flag, try again - STORAGE_FLAGS = STORAGE_FLAGS & ~X509KeyStorageFlags.MachineKeySet; - return SignMessage(request); - } - throw ex; - } -} diff --git a/old code/tray/assets/signing/sign-message.go b/old code/tray/assets/signing/sign-message.go deleted file mode 100755 index 25bd9ee..0000000 --- a/old code/tray/assets/signing/sign-message.go +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Echos the signed message - */ -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### -/* Steps: - * 1. Convert private key to golang compatible format: - * openssl rsa -in private-key.pem -out private-key-updated.pem - */ -package main - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/sha1" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "fmt" - "io/ioutil" - "net/http" -) - -var privateKey = "C:\\path\\to\\private-key-updated.pem" -var password = "S3cur3P@ssw0rd" -var listenPort = ":8080" - -func main() { - http.HandleFunc("/", handler) - http.ListenAndServe(listenPort, nil) -} - -func handler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Add("Content-Type", "text/plain") - - rsaPrivateKey, err := decodeKey(privateKey) - - if err != nil { - displayError(w, "Error reading key", err) - return - } - - data := r.URL.Query().Get("request") - - if len(data) < 1 { - displayError(w, "Request cannot be blank", err) - return - } - - hash := sha1.Sum([]byte(data)) - rng := rand.Reader - signature, err := rsa.SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA512, hash[:]) // Use crypto.SHA1 for QZ Tray 2.0 and older - if err != nil { - displayError(w, "Error from signing: %s\n", err) - return - } - fmt.Fprintf(w, base64.StdEncoding.EncodeToString(signature)) -} - -func displayError(w http.ResponseWriter, msg string, err error) { - w.WriteHeader(http.StatusInternalServerError) - fmt.Fprintf(w, "500 - Internal Server Error\n\n"+msg+"\n\nDetails:\n", err) -} - -func decodeKey(path string) (*rsa.PrivateKey, error) { - b, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - - block, _ := pem.Decode(b) - if x509.IsEncryptedPEMBlock(block) { - der, err := x509.DecryptPEMBlock(block, []byte(password)) - if err != nil { - return nil, err - } - return x509.ParsePKCS1PrivateKey(der) - } - - return x509.ParsePKCS1PrivateKey(block.Bytes) -} diff --git a/old code/tray/assets/signing/sign-message.java b/old code/tray/assets/signing/sign-message.java deleted file mode 100755 index 3efef06..0000000 --- a/old code/tray/assets/signing/sign-message.java +++ /dev/null @@ -1,143 +0,0 @@ -// package foo.bar; - -/* - * Java signing example - * Echoes the signed message and exits - */ - -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -import java.io.*; -import java.security.*; -import java.security.spec.*; -import java.util.Base64; -import java.util.logging.*; - -/** - * Utility for creating an RSA SHA1 signature based on a supplied PEM formatted private key - */ -public class MessageSigner { - private static Logger logger = Logger.getLogger(MessageSigner.class.getName()); - private Signature sig; - - /** - * Standard Java usage example, safe to remove - */ - public static void main(String args[]) throws Exception { - if (args.length < 2) { - logger.severe("Usage:\nMessageSigner.class [path to private key] [data to sign]\n"); - System.exit(1); - } - byte[] key = MessageSigner.readFile(args[0]); - String toSign = args[1]; - MessageSigner ms = new MessageSigner(key); - String signature = ms.sign(toSign); - - logger.log(Level.INFO, "Request: {0}", toSign); - logger.log(Level.INFO, "Response: {0}", signature); - } - - /** - * Servlet usage example, safe to remove - * - protected void doProcessRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // Get request from URL - String data = request.getParameter("request"); - - String signature = new MessageSigner("private-key.pem").sign(data); - - // Send signed message back - response.setContentType("text/plain"); - PrintWriter out = response.getWriter(); - out.write(signature); - out.flush(); - out.close(); - } - - /** - * Constructs an RSA SHA1 signature object for signing - * @param keyData - * @throws Exception - */ - public MessageSigner(byte[] keyData) throws Exception { - // Warning: PKCS#8 required. If PKCS#1 (RSA) key is provided convert using: - // $ openssl pkcs8 -topk8 -inform PEM -outform PEM -in private-key.pem -out private-key-pkcs8.pem -nocrypt - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(parseKeyData(keyData)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - PrivateKey key = kf.generatePrivate(keySpec); - sig = Signature.getInstance("SHA512withRSA"); // Use "SHA1withRSA" for QZ Tray 2.0 and older - sig.initSign(key); - } - - /** - * Signs the specified data with the provided private key, returning the - * RSA SHA1 signature - * @param data Message to sign - * @return Base64 encoded signature - * @throws Exception - */ - public String sign(String data) throws Exception { - sig.update(data.getBytes()); - return Base64.getEncoder().encodeToString(sig.sign()); - } - - /** - * Reads the raw byte[] data from a file resource - * @param path File path to read - * @return the raw byte data from file - * @throws IOException - */ - public static byte[] readFile(String path) throws IOException { - InputStream is = MessageSigner.class.getResourceAsStream(path); - if (is == null) { - throw new IOException(String.format("Can't open resource \"%s\"", path)); - } - DataInputStream dis = new DataInputStream(is); - byte[] data = new byte[dis.available()]; - dis.readFully(data); - dis.close(); - return data; - } - - /** - * Parses a base64 encoded private key by stripping the header and footer lines - * @param keyData PEM file contents - * @return Raw key byes - * @throws IOException - */ - private static byte[] parseKeyData(byte[] keyData) throws IOException { - StringBuilder sb = new StringBuilder(); - String[] lines = new String(keyData).split("[\r?\n]+"); - String[] skips = new String[]{"-----BEGIN", "-----END", ": "}; - for (String line : lines) { - boolean skipLine = false; - for (String skip : skips) { - if (line.contains(skip)) { - skipLine = true; - } - } - if (!skipLine) { - sb.append(line.trim()); - } - } - return Base64.getDecoder().decode(sb.toString()); - } - -} diff --git a/old code/tray/assets/signing/sign-message.js b/old code/tray/assets/signing/sign-message.js deleted file mode 100755 index 886adcd..0000000 --- a/old code/tray/assets/signing/sign-message.js +++ /dev/null @@ -1,89 +0,0 @@ -/* - * JavaScript client-side example using jsrsasign - */ - -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -/** - * Depends: - * - jsrsasign-latest-all-min.js - * - qz-tray.js - * - * Steps: - * - * 1. Include jsrsasign 10.9.0 into your web page - * - * - * 2. Update the privateKey below with contents from private-key.pem - * - * 3. Include this script into your web page - * - * - * 4. Remove or comment out any other references to "setSignaturePromise" - * - * 5. IMPORTANT: Before deploying to production, copy "jsrsasign-all-min.js" - * to the web server. Don't trust the CDN above to be available. - */ -var privateKey = "-----BEGIN PRIVATE KEY-----\n" + - "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0z9FeMynsC8+u\n" + - "dvX+LciZxnh5uRj4C9S6tNeeAlIGCfQYk0zUcNFCoCkTknNQd/YEiawDLNbxBqut\n" + - "bMDZ1aarys1a0lYmUeVLCIqvzBkPJTSQsCopQQ9V8WuT252zzNzs68dVGNdCJd5J\n" + - "NRQykpwexmnjPPv0mvj7i8XgG379TyW6P+WWV5okeUkXJ9eJS2ouDYdR2SM9BoVW\n" + - "+FgxDu6BmXhozW5EfsnajFp7HL8kQClI0QOc79yuKl3492rH6bzFsFn2lfwWy9ic\n" + - "7cP8EpCTeFp1tFaD+vxBhPZkeTQ1HKx6hQ5zeHIB5ySJJZ7af2W8r4eTGYzbdRW2\n" + - "4DDHCPhZAgMBAAECggEATvofR3gtrY8TLe+ET3wMDS8l3HU/NMlmKA9pxvjYfw7F\n" + - "8h4VBw4oOWPfzU7A07syWJUR72kckbcKMfw42G18GbnBrRQG0UIgV3/ppBQQNg9Y\n" + - "QILSR6bFXhLPnIvm/GxVa58pOEBbdec4it2Gbvie/MpJ4hn3K8atTqKk0djwxQ+b\n" + - "QNBWtVgTkyIqMpUTFDi5ECiVXaGWZ5AOVK2TzlLRNQ5Y7US8lmGxVWzt0GONjXSE\n" + - "iO/eBk8A7wI3zknMx5o1uZa/hFCPQH33uKeuqU5rmphi3zS0BY7iGY9EoKu/o+BO\n" + - "HPwLQJ3wCDA3O9APZ3gmmbHFPMFPr/mVGeAeGP/BAQKBgQDaPELRriUaanWrZpgT\n" + - "VnKKrRSqPED3anAVgmDfzTQwuR/3oD506F3AMBzloAo3y9BXmDfe8qLn6kgdZQKy\n" + - "SFNLz888at96oi+2mEKPpvssqiwE6F3OtEM6yv4DP9KJHaHmXaWv+/sjwjzpFNjs\n" + - "wGThBxFvrTWRJqBYsM1XNJJ2EQKBgQDUGbTSwHKqRCYWhQ1GPCZKE98l5UtMKvUb\n" + - "hyWWOXoyoeYbJEMfG1ynX4JeXIkl6YtBjYCqszv9PjHa1rowTZaAPJ0V70zyhTcF\n" + - "t581ii9LpiejIGrELHvJnW87QmjjStkjwGIqgKLp7Qe6CDjHI9HP1NM0uav/IQLW\n" + - "pB6wyEz1yQKBgQCuxPut+Ax2rzM05KB9PAnWzO1zt3U/rtm8IAF8uVVGf7r+EDJ0\n" + - "ZXJO6zj5G8WTEYHz5E86GI4ltBW0lKQoKouqdu27sMrv5trXG/CSImOcTVubQot9\n" + - "chc1CkOKTp5IeJajafO6j817wZ4N+0gNsbYYEBUCnm/7ojdfT5ficpOoQQKBgQDB\n" + - "PgKPmaNfGeQR1Ht5qEfCakR/RF/ML79Nq15FdmytQPBjfjBhYQ6Tt+MRkgGqtxOX\n" + - "UBMQc2iOnGHT3puYcrhScec1GufidhjhbqDxqMrag7HNYDWmMlk+IeA7/4+Mtp8L\n" + - "gbZuvvCvbLQDfIYueaYpUuBzQ08/jZYGdVU4/+WOcQKBgAGUN0kIB6EM1K/iZ0TN\n" + - "jlt8P5UEV3ZCyATWFiGZRhhE2WAh8gv1jx4J26pcUs1n8sd2a1h6ZuBSqsyIlNSp\n" + - "xtKsm3bqQFDHRrPcsBX4nanrw9DzkpH1k/I3WMSdGqkDAR3DtL7yXTJXJo2Sbrp5\n" + - "EjzSn7DcDE1tL2En/tSVXeUY\n" + - "-----END PRIVATE KEY-----"; - -qz.security.setSignatureAlgorithm("SHA512"); // Since 2.1 -qz.security.setSignaturePromise(function(toSign) { - return function(resolve, reject) { - try { - var pk = KEYUTIL.getKey(privateKey); - var sig = new KJUR.crypto.Signature({"alg": "SHA512withRSA"}); // Use "SHA1withRSA" for QZ Tray 2.0 and older - sig.init(pk); - sig.updateString(toSign); - var hex = sig.sign(); - console.log("DEBUG: \n\n" + stob64(hextorstr(hex))); - resolve(stob64(hextorstr(hex))); - } catch (err) { - console.error(err); - reject(err); - } - }; -}); diff --git a/old code/tray/assets/signing/sign-message.jsl b/old code/tray/assets/signing/sign-message.jsl deleted file mode 100755 index 754cb3c..0000000 --- a/old code/tray/assets/signing/sign-message.jsl +++ /dev/null @@ -1,48 +0,0 @@ -// -// J# Signing Example -// Echoes the signed message and exits -// - -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -module sample - -open System -open System.Security.Cryptography -open System.Security.Cryptography.X509Certificates -open System.IO -open System.Text - -let request = "test data" - -// How to associate a private key with the X509Certificate2 class in .net -// openssl pkcs12 -export -in private-key.pem -inkey digital-certificate.txt -out private-key.pfx -let cert = new X509Certificate2("private-key.pfx") - -let sha1 = new SHA512CryptoServiceProvider() // Use "SHA1CryptoServiceProvider" for QZ Tray 2.0 and older - -let csp = cert.PrivateKey :?> RSACryptoServiceProvider -let encoder = new ASCIIEncoding() - -let data = encoder.GetBytes(request) -let binaryData = csp.SignData(data, sha1) -let output = Convert.ToBase64String(binaryData) - -Console.WriteLine output \ No newline at end of file diff --git a/old code/tray/assets/signing/sign-message.jsp b/old code/tray/assets/signing/sign-message.jsp deleted file mode 100755 index 70cc978..0000000 --- a/old code/tray/assets/signing/sign-message.jsp +++ /dev/null @@ -1,120 +0,0 @@ -<% -/* - * JSP signing example - * Echoes the signed message and exits - */ - -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### -%> - -<%@ page import="java.io.*" %> -<%@ page import="java.util.*" %> -<%@ page import="java.lang.*" %> -<%@ page import="java.security.*" %> -<%@ page import="java.security.spec.*" %> -<%@ page import="java.util.logging.*" %> -<%@ page import="javax.xml.bind.DatatypeConverter" %> -<%@ page trimDirectiveWhitespaces="true" %> -<%@ page language="java" contentType="text/plain charset=UTF-8" pageEncoding="UTF-8"%> - -<%= getSignature(request.getParameter("request")) %> - - -<%! -/** - * Creates a signature using the provided private key and the provided (String) data inside Object o. - */ -private String getSignature(Object o) { - // Private key path if placed in CATALINA_HOME/private/ **AND** if JSP is - // placed in CATALINA_HOME/webapps/examples/. Adjust as needed. - String keyPath = "../../private/private-key.pem"; - - // Prepend servlet context path - keyPath = getServletContext().getRealPath("/") + keyPath; - String req = o == null ? "" : (String)o; - - try { - byte[] keyData = cleanseKeyData(readData(keyPath)); - // Warning: PKCS#8 required. If PKCS#1 (RSA) key is provided convert using: - // $ openssl pkcs8 -topk8 -inform PEM -outform PEM -in private-key.pem -out private-key-pkcs8.pem -nocrypt - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyData); - KeyFactory kf = KeyFactory.getInstance("RSA"); - PrivateKey key = kf.generatePrivate(keySpec); - Signature sig = Signature.getInstance("SHA512withRSA"); // Use "SHA1withRSA" for QZ Tray 2.0 and older - sig.initSign(key); - sig.update(req.getBytes()); - String output = DatatypeConverter.printBase64Binary(sig.sign()); - return output; - } catch (Throwable t) { - t.printStackTrace(); - return "Something went wrong while signing the message.\n" + - "Please check server console for sign-message.jsp"; - } -} -%> - -<%! -/** - * Reads the raw byte[] data from a file resource - * @param resourcePath - * @return the raw byte data from a resource file - * @throws IOException - */ -public byte[] readData(String resourcePath) throws IOException { - FileInputStream is = new FileInputStream(resourcePath); - - //InputStream is = getServletContext().getResourceAsStream(resourcePath); - if (is == null) { - throw new IOException(String.format("Can't open resource \"%s\"", resourcePath)); - } - DataInputStream dis = new DataInputStream(is); - byte[] data = new byte[dis.available()]; - dis.readFully(data); - dis.close(); - return data; -} -%> - -<%! -/** - * Parses an X509 PEM formatted base64 encoded private key, returns the decoded - * private key byte data - * @param keyData PEM file contents, a X509 base64 encoded private key - * @return Private key data - * @throws IOException - */ -private byte[] cleanseKeyData(byte[] keyData) throws IOException { - StringBuilder sb = new StringBuilder(); - String[] lines = new String(keyData).split("\n"); - String[] skips = new String[]{"-----BEGIN", "-----END", ": "}; - for (String line : lines) { - boolean skipLine = false; - for (String skip : skips) { - if (line.contains(skip)) { - skipLine = true; - } - } - if (!skipLine) { - sb.append(line.trim()); - } - } - return DatatypeConverter.parseBase64Binary(sb.toString()); -} -%> diff --git a/old code/tray/assets/signing/sign-message.node.js b/old code/tray/assets/signing/sign-message.node.js deleted file mode 100755 index 5ee68d8..0000000 --- a/old code/tray/assets/signing/sign-message.node.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Node.js signing example - * Echoes the signed message and exits - */ - -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -var key = "private-key.pem"; -//var pass = "S3cur3P@ssw0rd"; - -app.get('/sign', function(req, res) { - var crypto = require('crypto'); - var fs = require('fs'); - var path = require('path'); - var toSign = req.query.requestToSign; - - fs.readFile(path.join(__dirname, '\\' + key), 'utf-8', function(err, privateKey) { - var sign = crypto.createSign('SHA512'); // Use "SHA1" for QZ Tray 2.0 and older - - sign.update(toSign); - var signature = sign.sign({ key: privateKey/*, passphrase: pass */ }, 'base64'); - - res.set('Content-Type', 'text/plain'); - res.send(signature); - }); -}); diff --git a/old code/tray/assets/signing/sign-message.odoo.py b/old code/tray/assets/signing/sign-message.odoo.py deleted file mode 100755 index 2321252..0000000 --- a/old code/tray/assets/signing/sign-message.odoo.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# Python Odoo example for controller.py -# Echoes the signed message and exits -# - -######################################################### -# WARNING WARNING WARNING # -######################################################### -# # -# This file is intended for demonstration purposes # -# only. # -# # -# It is the SOLE responsibility of YOU, the programmer # -# to prevent against unauthorized access to any signing # -# functions. # -# # -# Organizations that do not protect against un- # -# authorized signing will be black-listed to prevent # -# software piracy. # -# # -# -QZ Industries, LLC # -# # -######################################################### - -from odoo import http -from odoo.http import request -from OpenSSL import crypto -import base64 - - -class SignMessage(http.Controller): - - @http.route('/sign-message/', auth='public') - def index(self, **kwargs): - mypass = None - key_file = open('path/to/private-key.pem', 'r') - key = key_file.read() - key_file.close() - password = None - pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key, password) - sign = crypto.sign(pkey, kwargs.get('request', ''), 'sha512') # Use 'sha1' for QZ Tray 2.0 and older - data_base64 = base64.b64encode(sign) - return request.make_response(data_base64, [('Content-Type', 'text/plain')]) diff --git a/old code/tray/assets/signing/sign-message.php b/old code/tray/assets/signing/sign-message.php deleted file mode 100755 index f57620d..0000000 --- a/old code/tray/assets/signing/sign-message.php +++ /dev/null @@ -1,55 +0,0 @@ -loadKey(file_get_contents($KEY)); -$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); -$signature = $rsa->sign($req); -*/ - -if ($signature) { - header("Content-type: text/plain"); - echo base64_encode($signature); - exit(0); -} - -echo '

Error signing message

'; -http_response_code(500); -exit(1); - -?> diff --git a/old code/tray/assets/signing/sign-message.pl b/old code/tray/assets/signing/sign-message.pl deleted file mode 100755 index 977dbf0..0000000 --- a/old code/tray/assets/signing/sign-message.pl +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/perl -# -# Echoes the signed message and exits -# usage: ./sign-message.pl "test" -# -######################################################### -# WARNING WARNING WARNING # -######################################################### -# # -# This file is intended for demonstration purposes # -# only. # -# # -# It is the SOLE responsibility of YOU, the programmer # -# to prevent against unauthorized access to any signing # -# functions. # -# # -# Organizations that do not protect against un- # -# authorized signing will be black-listed to prevent # -# software piracy. # -# # -# -QZ Industries, LLC # -# # -######################################################### - -# RSA Crypto libs provided by: -# Debian: libcrypt-openssl-rsa-perl -# RedHat: perl-Crypt-OpenSSL-RSA -use Crypt::OpenSSL::RSA; -use MIME::Base64 qw(encode_base64); - -# Get first argument passed to script -my $request = $ARGV[0]; - -# Path to the private key -my $pem_file = "private-key.pem"; - -# Read private key -my $private_key = do { - local $/ = undef; - open my $fh, "<", $pem_file - or die "could not open $file: $!"; - <$fh>; -}; - -# Load private key -my $rsa = Crypt::OpenSSL::RSA->new_private_key($private_key); - -# Create signature -$rsa->use_sha512_hash(); # use_sha1_hash for QZ Tray 2.0 and older -my $sig = encode_base64($rsa->sign($request)); - -print $sig; diff --git a/old code/tray/assets/signing/sign-message.py b/old code/tray/assets/signing/sign-message.py deleted file mode 100755 index 8ad584a..0000000 --- a/old code/tray/assets/signing/sign-message.py +++ /dev/null @@ -1,39 +0,0 @@ -# -# Python Django example for views.py -# Echoes the signed message and exits -# - -######################################################### -# WARNING WARNING WARNING # -######################################################### -# # -# This file is intended for demonstration purposes # -# only. # -# # -# It is the SOLE responsibility of YOU, the programmer # -# to prevent against unauthorized access to any signing # -# functions. # -# # -# Organizations that do not protect against un- # -# authorized signing will be black-listed to prevent # -# software piracy. # -# # -# -QZ Industries, LLC # -# # -######################################################### - -import base64 -import os -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import padding -from django.http import HttpResponse, HttpResponseBadRequest - -def get(self, request, message): - # Load signature - key = serialization.load_pem_private_key(open("private-key.pem","rb").read(), None, backend=default_backend()) - # Create the signature - signature = key.sign(message.encode('utf-8'), padding.PKCS1v15(), hashes.SHA512()) # Use hashes.SHA1() for QZ Tray 2.0 and older - # Echo the signature - return HttpResponse(base64.b64encode(signature), content_type="text/plain") - diff --git a/old code/tray/assets/signing/sign-message.rb b/old code/tray/assets/signing/sign-message.rb deleted file mode 100755 index c95e6b6..0000000 --- a/old code/tray/assets/signing/sign-message.rb +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env ruby -# -# Echoes the signed message and exits -# usage: ./sign-message.rb "request=test" -# -######################################################### -# WARNING WARNING WARNING # -######################################################### -# # -# This file is intended for demonstration purposes # -# only. # -# # -# It is the SOLE responsibility of YOU, the programmer # -# to prevent against unauthorized access to any signing # -# functions. # -# # -# Organizations that do not protect against un- # -# authorized signing will be black-listed to prevent # -# software piracy. # -# # -# -QZ Industries, LLC # -# # -######################################################### - -# Typical rails controller -class PrintingController < ActionController::Base - def sign - digest = OpenSSL::Digest.new('sha512') # Use 'sha1' for QZ Tray 2.0 and older - pkey = OpenSSL::PKey::read(File.read(Rails.root.join('lib', 'certs', 'private-key.pem'))) - - signed = pkey.sign(digest, params[:request]) - encoded = Base64.encode64(signed) - - render text: encoded - end -end diff --git a/old code/tray/assets/signing/sign-message.ts b/old code/tray/assets/signing/sign-message.ts deleted file mode 100755 index 54df7ba..0000000 --- a/old code/tray/assets/signing/sign-message.ts +++ /dev/null @@ -1,86 +0,0 @@ - -/* - * AngularJS example using jsrsasign (client) or fetch (server) - */ - -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -import { Component } from '@angular/core'; -import * as qz from 'qz-tray'; -import { KJUR, KEYUTIL, stob64, hextorstr } from 'jsrsasign'; - -qz.security.setCertificatePromise((resolve, reject) => { - fetch("assets/digital-certificate.txt", {cache: 'no-store', headers: {'Content-Type': 'text/plain'}}) - .then(data => resolve(data.text())); -}); - -/* - * Client-side using jsrsasign - */ -qz.security.setSignatureAlgorithm("SHA512"); // Since 2.1 -qz.security.setSignaturePromise(hash => { - return (resolve, reject) => { - fetch("assets/private-key.pem", {cache: 'no-store', headers: {'Content-Type': 'text/plain'}}) - .then(wrapped => wrapped.text()) - .then(data => { - var pk = KEYUTIL.getKey(data); - var sig = new KJUR.crypto.Signature({"alg": "SHA512withRSA"}); // Use "SHA1withRSA" for QZ Tray 2.0 and older - sig.init(pk); - sig.updateString(hash); - var hex = sig.sign(); - console.log("DEBUG: \n\n" + stob64(hextorstr(hex))); - resolve(stob64(hextorstr(hex))); - }) - .catch(err => console.error(err)); - }; -}); - - -/* - * Preferred, from a secure controller - * - qz.security.setSignaturePromise(hash => { - return (resolve, reject) => { - fetch("/path/to/controller?request=" + hash, {cache: 'no-store', headers: {'Content-Type': 'text/plain'}}) - .then(wrapped => wrapped.text()) - .then(data => resolve(data)) - .catch(err => console.error(err)); - }); - }; - }); - */ - -qz.api.setSha256Type(data => sha256(data)); -qz.api.setPromiseType(resolver => new Promise(resolver)); - -qz.websocket.connect() - .then(qz.printers.getDefault) - .then(printer => console.log("The default printer is: " + printer)) - .then(qz.websocket.disconnect) - .catch(err => console.error(err)); - -@Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] -}) -export class AppComponent { - title = 'QZ Tray AngularJS Signing'; -} diff --git a/old code/tray/assets/signing/sign-message.vb b/old code/tray/assets/signing/sign-message.vb deleted file mode 100755 index 77f7b6a..0000000 --- a/old code/tray/assets/signing/sign-message.vb +++ /dev/null @@ -1,43 +0,0 @@ -' -' Echoes the signed message and exits -' -Public Sub SignMessage(message As String) - - '********************************************************** - '* WARNING WARNING WARNING * - '********************************************************** - '* * - '* This file is intended for demonstration purposes only. * - '* only. * - '* * - '* It is the SOLE responsibility of YOU, the programmer * - '* to prevent against unauthorized access to any signing * - '* functions. * - '* * - '* Organizations that do not protect against un- * - '* authorized signing will be black-listed to prevent * - '* software piracy. * - '* * - '* -QZ Industries, LLC * - '* * - '********************************************************** - - ' Sample key. Replace with one used for CSR generation - ' How to associate a private key with the X509Certificate2 class in .net - ' openssl pkcs12 -export -inkey private-key.pem -in digital-certificate.txt -out private-key.pfx - - Dim KEY = "private-key.pfx" - - Dim cert = New X509Certificate2(KEY, X509KeyStorageFlags.MachineKeySet Or X509KeyStorageFlags.PersistKeySet Or X509KeyStorageFlags.Exportable) - Dim csp As RSACryptoServiceProvider = CType(cert.PrivateKey,RSACryptoServiceProvider) - - Dim cspStrong as RSACryptoServiceProvider() = New RSACryptoServiceProvider() ' 2.1 and higher: Make RSACryptoServiceProvider that can handle SHA256, SHA512 - cspStrong.ImportParameters(csp.ExportParameters(true)) ' Copy to stronger RSACryptoServiceProvider - - Dim data As Byte() = New ASCIIEncoding().GetBytes(message) - Dim hash As Byte() = New SHA512Managed().ComputeHash(data) ' Use SHA1Managed() for QZ Tray 2.0 and older - - Response.ContentType = "text/plain" - Response.Write(Convert.ToBase64String(cspStrong.SignHash(hash, CryptoConfig.MapNameToOID("SHA512")))) ' Use "SHA1" for QZ Tray 2.0 and older - Environment.[Exit](0) -End Sub diff --git a/old code/tray/assets/signing/sign-message.vue.js b/old code/tray/assets/signing/sign-message.vue.js deleted file mode 100755 index 74d8445..0000000 --- a/old code/tray/assets/signing/sign-message.vue.js +++ /dev/null @@ -1,88 +0,0 @@ -/* - * JavaScript client-side example using jwa - */ - -// ######################################################### -// # WARNING WARNING WARNING # -// ######################################################### -// # # -// # This file is intended for demonstration purposes # -// # only. # -// # # -// # It is the SOLE responsibility of YOU, the programmer # -// # to prevent against unauthorized access to any signing # -// # functions. # -// # # -// # Organizations that do not protect against un- # -// # authorized signing will be black-listed to prevent # -// # software piracy. # -// # # -// # -QZ Industries, LLC # -// # # -// ######################################################### - -import Vue from "vue"; - -import qz from "qz-tray"; -import jwa from "jwa"; - -const vue = new Vue({ - el: "#app", - data: { - message: "QZ Tray Vue.js Demo" - }, - template: "
{{ message }}
" -}).$mount(); - -const rsa512 = jwa("RS512"); - -const privateKey = getPrivateKey(); -qz.security.setSignatureAlgorithm("SHA512"); // Since 2.1 -qz.security.setSignaturePromise(function (toSign) { - return function (resolve, reject) { - try { - const hexUrl = rsa512.sign(toSign, privateKey); - // Crude base64URL to base64 conversion - const hex = hexUrl.replace(/_/g, "/").replace(/-/g, "+"); - resolve(hex); - } catch (err) { - reject(err); - } - }; -}); - -const certificate = getCertificate(); -qz.security.setCertificatePromise((resolve, reject) => { - resolve(certificate); -}); - -function getPrivateKey() { - // TODO: Switch to fetch()/AJAX/etc - return ( - "-----BEGIN PRIVATE KEY-----\n" + - "..." + - "-----END PRIVATE KEY-----" - ); -} - -function getCertificate() { - // TODO: Switch to fetch()/AJAX/etc - return ( - "-----BEGIN CERTIFICATE-----\n" + - "..." + - "-----END CERTIFICATE-----" - ); -} - -qz.websocket - .connect() - .then(() => { - vue.message = "Looking for printers..."; - return qz.printers.find(); - }) - .then((printers) => { - vue.message = "Found printers: " + printers; - }) - .catch((err) => { - vue.message = err; - }); diff --git a/old code/tray/assets/signing/sign_message.erl b/old code/tray/assets/signing/sign_message.erl deleted file mode 100755 index 8a950b1..0000000 --- a/old code/tray/assets/signing/sign_message.erl +++ /dev/null @@ -1,50 +0,0 @@ -%%%------------------------------------------------------------------- -%%% ######################################################### -%%% # WARNING WARNING WARNING # -%%% ######################################################### -%%% # # -%%% # This file is intended for demonstration purposes # -%%% # only. # -%%% # # -%%% # It is the SOLE responsibility of YOU, the programmer # -%%% # to prevent against unauthorized access to any signing # -%%% # functions. # -%%% # # -%%% # Organizations that do not protect against un- # -%%% # authorized signing will be black-listed to prevent # -%%% # software piracy. # -%%% # # -%%% # -QZ Industries, LLC # -%%% # # -%%% ######################################################### -%%%------------------------------------------------------------------- --module(sign_message). --export([sign/2]). - -%%% -%%% Usage: -%%% -import(sign_message, [sign/2]). -%%% [...] -%%% sign_message:sign(GetRequest, "path/to/private-key.rsa"). -%%% * Where GetRequest is the the "foo" portion of "?request=foo" -%%% * Web framework must echo the base64 encoded signature in plain text -%%% * Browser must use ajax technique to fetch base64 signature -%%% * See also qz.api.setSignaturePromise(...) -%%% -%%% Important: -%%% * Private key MUST be converted to newer RSA format using the following command: -%%% openssl rsa -in "private-key.pem" -out "private-key.rsa" -%%% -%%% Watch for: -%%% badmatch,{error,enoent} key cannot be read; check for valid path -%%% function_clause,[{public_key,sign,...}] key must be converted to newer RSA format -%%% -%%% - -sign(Message, KeyPath) -> - {ok, Data} = file:read_file(KeyPath), - [KeyEntry] = public_key:pem_decode(Data), - PrivateKey = public_key:pem_entry_decode(KeyEntry), - Signature = public_key:sign(list_to_binary(Message), sha512, PrivateKey), % Use sha1 for QZ Tray 2.0 and older - Base64 = base64:encode(Signature), - io:fwrite(Base64). diff --git a/old code/tray/assets/zpl_sample.txt b/old code/tray/assets/zpl_sample.txt deleted file mode 100755 index 8813e3e..0000000 --- a/old code/tray/assets/zpl_sample.txt +++ /dev/null @@ -1,51 +0,0 @@ -^XA^CF,0,0,0 -^FX Please avoid using PR (print rate) or MD (media darkness) commands; -They may change or be outside the range of current printer settings for subsequent print jobs and result in bad prints -lite1979^FS -^PW812^PON^CI13 -^FO0,147^GB800,4,4^FS -^FO0,401^GB800,4,4^FS -^FO0,736^GB800,4,4^FS -^FO35,12^AdN,0,0^FWN^FH^FDFrom:^FS -^FO35,31^AdN,0,0^FWN^FH^FDAlex^FS -^FO35,51^AdN,0,0^FWN^FH^FDFlagship^FS -^FO35,71^AdN,0,0^FWN^FH^FD79 Spike St.^FS -^FO35,92^AdN,0,0^FWN^FH^FD^FS -^FO35,112^AdN,0,0^FWN^FH^FDNorcross, GA 30071^FS -^FO35,132^AdN,0,0^FWN^FH^FD(123) 456-7890^FS -^FO490,31^AdN,0,0^FWN^FH^FDShip Date: 31DEC07^FS -^FO490,51^AdN,0,0^FWN^FH^FDActWgt: 10.5 LB^FS -^FO490,72^AdN,0,0^FWN^FH^FDSystem#: 1195167/WSXI0100^FS -^FO490,91^AdN,0,0^FWN^FH^FDAccount: S *********^FS -^FO43,158^A0N,25,27^FWN^FH^FDSteve Jobs^FS -^FO615,156^AdN,0,0^FWN^FH^FD(123) 456-7890^FS -^FO43,193^A0N,25,27^FWN^FH^FDApple Inc.^FS -^FO43,228^A0N,25,27^FWN^FH^FD1 Infinite Loop.^FS -^FO43,263^A0N,25,27^FWN^FH^FD^FS -^FO43,296^A0N,30,30^FWN^FH^FDCupertino, CA 95014^FS -^FO530,296^A0N,35,45^FWN^FH^FD(US)^FS -^FO725,216^AdN,0,0^FWN^FH^FDGround^FS -^FO670,238^GB105,10,10^FS -^FO670,248^GB10,112,10^FS -^FO765,248^GB10,112,10^FS -^FO670,360^GB105,10,10^FS -^FO650,173^A0N,50,55^FWN^FH^FDFedEx^FS -^FO690,256^A0N,130,130^FWN^FH^FDG^FS -^FO476,3^GB4,145,4^FS -^FO10,358^A0N,15,15^FWN^FH^FDRef:^FS -^FO406,388^A0N,15,15^FWN^FH^FDDept: Work^FS -^FO10,373^A0N,15,15^FWN^FH^FDInv:^FS -^FO10,388^A0N,15,15^FWN^FH^FDPO:^FS -^FO625,495^A0N,20,35^FWN^FH^FD1^FS -^FO640,535^A0N,20,35^FWN^FH^FDof^FS -^FO625,575^A0N,20,35^FWN^FH^FD1^FS -^FO80,771^BY4,2^BCN,290,N,N,N,N^FWN^FD>;>89612019333075610004019^FS -^FO135,1083^A0N,25,27^FWN^FH^FD(9612019) 3330756 10004019^FS -^FO783,288^A0N,15,15^FWB^FH^FDCLS090607/23/23^FS -^FO10,162^A0N,20,18^FWN^FH^FDTO^FS -^FO25,1108^A0N,50,55^FWN^FH^FDGND^FS -^FO25,1150^A0N,35,45^FWN^FH^FDPrepaid^FS -^FO300,1115^A0N,35,45^FWN^FH^FD^FS -^FO300,1149^A0N,35,45^FWN^FH^FD^FS -^FO30,428^BY2,2^B7N,10,5,12^FH^FWN^FH^FD[)>_1E01_1D02950142083_1D840_1D019_1D333075610004019_1DFDEB_1D3330756_1D365_1D _1D1/1_1D10.5LB_1DN_1D1 Infinite Loop._1DCupertino_1DCA_1DSteve Jobs_1E06_1D10ZGD004_1D11ZApple Inc._1D12Z1234567890_1D23ZN_1D22Z _1CN_1D20Z _1C0_1D29Z_1D28Z_1D26Z3632_1C_1D_1E_04^FS -^PQ1 -^XZ \ No newline at end of file diff --git a/old code/tray/assets/zpl_sample.xml b/old code/tray/assets/zpl_sample.xml deleted file mode 100755 index ef0f51c..0000000 --- a/old code/tray/assets/zpl_sample.xml +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - NOTE - - NOTE - ship - 6028 - LabelPrintingOrientationType not specified - using default value of N - LabelPrintingOrientationType not specified - using default value of N - - - Ship Service V7 - - - ship - 7 - 0 - 0 - - - true - FDXG - GROUND - YOUR_PACKAGING - - TWO_DAYS - - 019 - - PAYOR_ACCOUNT - - PAYOR_ACCOUNT - 4 - ACTUAL - 0 - 5.25 - - LB - 36.0 - - - USD - 13.74 - - - USD - 7.0 - - - USD - 6.74 - - - USD - 0.35 - - - USD - 7.09 - - - USD - 0.0 - - - USD - 7.09 - - - USD - 0.0 - - - VOLUME - Base - - USD - 4.38 - - 0.0 - - - VOLUME - Matrix - - USD - 2.62 - - 0.0 - - - INSURED_VALUE - PACKAGE - Insured value - - USD - 0.0 - - - - FUEL - PACKAGE - FedEx Ground Fuel - - USD - 0.35 - - - - - false - - 1 - - GROUND - 422268010001723 - - 0 - - PAYOR_ACCOUNT - - PAYOR_ACCOUNT - ACTUAL - - LB - 36.0 - - - USD - 13.74 - - - USD - 7.0 - - - USD - 6.74 - - - USD - 0.35 - - - USD - 7.09 - - - USD - 0.0 - - - USD - 7.09 - - - USD - 0.0 - - - VOLUME - Base - - USD - 4.38 - - 0.0 - - - VOLUME - Matrix - - USD - 2.62 - - 0.0 - - - INSURED_VALUE - PACKAGE - Insured value - - USD - 0.0 - - - - FUEL - PACKAGE - FedEx Ground Fuel - - USD - 0.35 - - - - - - - COMMON_2D - Wyk+HjAxHTAyMzgwMTcdODQwHTAxOR0wMDAwMDAwMDAwMDAwMDAdRkRFQh0wMDAwMDAwHTMzNR0dMS8xHTM2LjBMQh1OHVJlY2lwaWVudCBBZGRyZXNzIExpbmUgMR1Db2xsaWVydmlsbGUdVE4dUmVjaXBpZW50IENvbnRhY3QeMDYdMTBaR0QwMDQdMTJaMTIzNDU2Nzg5MB0xNFoqKlRFU1QgTEFCRUwgLSBETyBOT1QgU0hJUCoqHTIzWk4dMjJaHE4dMjBaIBw4MB0yNlo1MzEwHB0eBA== - - - GROUND - 9612019000000000000000 - - - - OUTBOUND_LABEL - 1 - - 1 - XlhBXkNGLDAsMCwwXlBSMTJeTUQzMF5QVzgwMF5QT0leQ0kxM15MSDAsMjAKXkZPMCwxNDdeR0I4MDAsNCw0XkZTCl5GTzAsNDAxXkdCODAwLDQsNF5GUwpeRk8wLDczNl5HQjgwMCw0LDReRlMKXkZPMzUsMTJeQWROLDAsMF5GV05eRkheRkRGcm9tOl5GUwpeRk8zNSwzMV5BZE4sMCwwXkZXTl5GSF5GRF5GUwpeRk8zNSw1MV5BZE4sMCwwXkZXTl5GSF5GRFRHS15GUwpeRk8zNSw3MV5BZE4sMCwwXkZXTl5GSF5GRFNOMjAwMCBUZXN0IE1ldGVyIDheRlMKXkZPMzUsOTJeQWROLDAsMF5GV05eRkheRkQxMCBGZWRleCBQYXJrd2F5XkZTCl5GTzM1LDEzMl5BZE4sMCwwXkZXTl5GSF5GRCgxMjMpIDQ1Ni03ODkwXkZTCl5GTzQ5MCw3Ml5BZE4sMCwwXkZXTl5GSF5GRENBRDogMTE4NTAwOTA3L1dTWEkyMzUwXkZTCl5GTzQzLDE5M15BME4sMjUsMjdeRldOXkZIXkZEXkZTCl5GTzQzLDIyOF5BME4sMjUsMjdeRldOXkZIXkZEUmVjaXBpZW50IEFkZHJlc3MgTGluZSAxXkZTCl5GTzQzLDI2M15BME4sMjUsMjdeRldOXkZIXkZEKipURVNUIExBQkVMIC0gRE8gTk9UIFNISVAqKl5GUwpeRk8zNSwxMTJeQWROLDAsMF5GV05eRkheRkRBdXN0aW4sIFRYIDczMzAxXkZTCl5GTzQ5MCwzMV5BZE4sMCwwXkZXTl5GSF5GRFNoaXAgRGF0ZTogMDFERUMwOV5GUwpeRk80OTAsNTFeQWROLDAsMF5GV05eRkheRkRBY3RXZ3Q6IDM2LjAgTEJeRlMKXkZPNDkwLDkxXkFkTiwwLDBeRldOXkZIXkZEQWNjb3VudDogUyAyOTY1NTY5NjNeRlMKXkZPNDMsMTU4XkEwTiwyNSwyN15GV05eRkheRkRSZWNpcGllbnQgQ29udGFjdF5GUwpeRk82MTUsMTU2XkFkTiwwLDBeRldOXkZIXkZEKDEyMykgNDU2LTc4OTBeRlMKXkZPNDMsMjk2XkEwTiwzMCwzMF5GV05eRkheRkRDb2xsaWVydmlsbGUsIFROIDM4MDE3XkZTCl5GTzUzMCwyOTZeQTBOLDM1LDQ1XkZXTl5GSF5GRChVUyleRlMKXkZPNzI1LDIxNl5BZE4sMCwwXkZXTl5GSF5GREdyb3VuZF5GUwpeRk82NzAsMjM4XkdCMTA1LDEwLDEwXkZTCl5GTzY3MCwyNDheR0IxMCwxMTIsMTBeRlMKXkZPNzY1LDI0OF5HQjEwLDExMiwxMF5GUwpeRk82NzAsMzYwXkdCMTA1LDEwLDEwXkZTCl5GTzQ3NiwzXkdCNCwxNDUsNF5GUwpeRk82NTAsMTczXkEwTiw1MCw1NV5GV05eRkheRkRGZWRFeF5GUwpeRk82OTAsMjU2XkEwTiwxMzAsMTMwXkZXTl5GSF5GREdeRlMKXkZPODAsNzcxXkJZNCwyXkJDTiwyOTAsTixOLE4sTl5GV05eRkQ+Oz44OTYxMjAxOTAwMDAwMDAwMDAwMDAwMF5GUwpeRk8xMzUsMTA4M15BME4sMjUsMjdeRldOXkZIXkZEKDk2MTIwMTkpIDAwMDAwMDAgIDAwMDAwMDAwXkZTCl5GTzc4MywyNTheQTBOLDE1LDE1XkZXQl5GSF5GREowOTMwMDkwNzMxMjEyM15GUwpeRk8xMCwxNjJeQTBOLDIwLDE4XkZXTl5GSF5GRFRPXkZTCl5GTzI1LDExMDheQTBOLDUwLDU1XkZXTl5GSF5GREdORF5GUwpeRk8yNSwxMTUwXkEwTiwzNSw0NV5GV05eRkheRkRQcmVwYWlkXkZTCl5GTzMwMCwxMTE1XkEwTiwzNSw0NV5GV05eRkheRkReRlMKXkZPMzAwLDExNDleQTBOLDM1LDQ1XkZXTl5GSF5GRF5GUwpeRk8zMCw0MjheQlkyLDJeQjdOLDEwLDUsMTJeRkheRldOXkZIXkZEWyk+XzFFMDFfMUQwMjM4MDE3XzFEODQwXzFEMDE5XzFEMDAwMDAwMDAwMDAwMDAwXzFERkRFQl8xRDAwMDAwMDBfMUQzMzVfMURfMUQxLzFfMUQzNi4wTEJfMUROXzFEUmVjaXBpZW50IEFkZHJlc3MgTGluZSAxXzFEQ29sbGllcnZpbGxlXzFEVE5fMURSZWNpcGllbnQgQ29udGFjdF8xRTA2XzFEMTBaR0QwMDRfMUQxMloxMjM0NTY3ODkwXzFEMTRaKipURVNUIExBQkVMIC0gRE8gTk9UIFNISVAqKl8xRDIzWk5fMUQyMlpfMUNOXzFEMjBaIF8xQzgwXzFEMjZaNTMxMF8xQ18xRF8xRV8wNF5GUwpeRk8xNiwzNTheQTBOLDE1LDE1XkZXTl5GSF5GRFJlZjogXkZTCl5GTzE2LDM3M15BME4sMTUsMTVeRldOXkZIXkZESU5WOiBeRlMKXkZPMTYsMzg4XkEwTiwxNSwxNV5GV05eRkheRkRQTzogXkZTCl5GTzQwNiwzODheQTBOLDE1LDE1XkZXTl5GSF5GRERlcHQ6IF5GUwpeRk82MjUsNDk1XkEwTiwyMCwzNV5GV05eRkheRkQxXkZTCl5GTzY0MCw1MzVeQTBOLDIwLDM1XkZXTl5GSF5GRG9mXkZTCl5GTzYyNSw1NzVeQTBOLDIwLDM1XkZXTl5GSF5GRDFeRlMKXlBRMQpeWFoK - - - SERVICE_DEFAULT - - - - - - diff --git a/old code/tray/build.xml b/old code/tray/build.xml deleted file mode 100755 index a4b4912..0000000 --- a/old code/tray/build.xml +++ /dev/null @@ -1,316 +0,0 @@ - - - - - - - - - - - - - - - - Process complete - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Building jar - - - Stripping jlink-incompatible files - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copying ${target.fx.dir} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Bundling with manual cert for signing auth: ${authcert.use} - - - - - - - - Copying certificate(s) to dist/whitelist: ${whitelist.use} - - - - - - - - - - Copying demo resource files to ${demo.dir} - - - - - - - - - - - - - - - - - - - - The "include-assets" task is deprecated, please use "build-demo" instead. - - - - - - - Found provision file '${provision.file}' calling 'provision --json [...]' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Downloading and bundling the jre for ${target.os} - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/old code/tray/css/bootstrap.min.css b/old code/tray/css/bootstrap.min.css deleted file mode 100755 index bf9bbf7..0000000 --- a/old code/tray/css/bootstrap.min.css +++ /dev/null @@ -1,7199 +0,0 @@ -/*! - * Bootstrap v3.3.5 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ -html { - font-family: sans-serif; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100% -} - -body { - margin: 0 -} - -article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { - display: block -} - -audio, canvas, progress, video { - display: inline-block; - vertical-align: baseline -} - -audio:not([controls]) { - display: none; - height: 0 -} - -[hidden], template { - display: none -} - -a { - background-color: transparent -} - -a:active, a:hover { - outline: 0 -} - -abbr[title] { - border-bottom: 1px dotted -} - -b, strong { - font-weight: 700 -} - -dfn { - font-style: italic -} - -h1 { - margin: .67em 0; - font-size: 2em -} - -mark { - color: #000; - background: #FF0 -} - -small { - font-size: 80% -} - -sub, sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline -} - -sup { - top: -.5em -} - -sub { - bottom: -.25em -} - -img { - border: 0 -} - -svg:not(:root) { - overflow: hidden -} - -figure { - margin: 1em 40px -} - -hr { - height: 0; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box -} - -pre { - overflow: auto -} - -code, kbd, pre, samp { - font-family: monospace, monospace; - font-size: 1em -} - -button, input, optgroup, select, textarea { - margin: 0; - font: inherit; - color: inherit -} - -button { - overflow: visible -} - -button, select { - text-transform: none -} - -button, html input[type=button], input[type=reset], input[type=submit] { - -webkit-appearance: button; - cursor: pointer -} - -button[disabled], html input[disabled] { - cursor: default -} - -button::-moz-focus-inner, input::-moz-focus-inner { - padding: 0; - border: 0 -} - -input { - line-height: normal -} - -input[type=checkbox], input[type=radio] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0 -} - -input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button { - height: auto -} - -input[type=search] { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - -webkit-appearance: textfield -} - -input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration { - -webkit-appearance: none -} - -fieldset { - padding: .35em .625em .75em; - margin: 0 2px; - border: 1px solid silver -} - -legend { - padding: 0; - border: 0 -} - -textarea { - overflow: auto -} - -optgroup { - font-weight: 700 -} - -table { - border-spacing: 0; - border-collapse: collapse -} - -td, th { - padding: 0 -} - -/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ -@media print { - *, :after, :before { - color: #000 !important; - text-shadow: none !important; - background: 0 0 !important; - -webkit-box-shadow: none !important; - box-shadow: none !important - } - - a, a:visited { - text-decoration: underline - } - - a[href]:after { - content: " (" attr(href) ")" - } - - abbr[title]:after { - content: " (" attr(title) ")" - } - - a[href^="javascript:"]:after, a[href^="#"]:after { - content: "" - } - - blockquote, pre { - border: 1px solid #999; - page-break-inside: avoid - } - - thead { - display: table-header-group - } - - img, tr { - page-break-inside: avoid - } - - img { - max-width: 100% !important - } - - h2, h3, p { - orphans: 3; - widows: 3 - } - - h2, h3 { - page-break-after: avoid - } - - .navbar { - display: none - } - - .btn > .caret, .dropup > .btn > .caret { - border-top-color: #000 !important - } - - .label { - border: 1px solid #000 - } - - .table { - border-collapse: collapse !important - } - - .table td, .table th { - background-color: #FFF !important - } - - .table-bordered td, .table-bordered th { - border: 1px solid #DDD !important - } -} - -@font-face { - font-family: 'Glyphicons Halflings'; - src: url(../fonts/glyphicons-halflings-regular.eot); - src: url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'), url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'), url(../fonts/glyphicons-halflings-regular.woff) format('woff'), url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'), url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg') -} - -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: 400; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale -} - -.glyphicon-asterisk:before { - content: "\2a" -} - -.glyphicon-plus:before { - content: "\2b" -} - -.glyphicon-eur:before, .glyphicon-euro:before { - content: "\20ac" -} - -.glyphicon-minus:before { - content: "\2212" -} - -.glyphicon-cloud:before { - content: "\2601" -} - -.glyphicon-envelope:before { - content: "\2709" -} - -.glyphicon-pencil:before { - content: "\270f" -} - -.glyphicon-glass:before { - content: "\e001" -} - -.glyphicon-music:before { - content: "\e002" -} - -.glyphicon-search:before { - content: "\e003" -} - -.glyphicon-heart:before { - content: "\e005" -} - -.glyphicon-star:before { - content: "\e006" -} - -.glyphicon-star-empty:before { - content: "\e007" -} - -.glyphicon-user:before { - content: "\e008" -} - -.glyphicon-film:before { - content: "\e009" -} - -.glyphicon-th-large:before { - content: "\e010" -} - -.glyphicon-th:before { - content: "\e011" -} - -.glyphicon-th-list:before { - content: "\e012" -} - -.glyphicon-ok:before { - content: "\e013" -} - -.glyphicon-remove:before { - content: "\e014" -} - -.glyphicon-zoom-in:before { - content: "\e015" -} - -.glyphicon-zoom-out:before { - content: "\e016" -} - -.glyphicon-off:before { - content: "\e017" -} - -.glyphicon-signal:before { - content: "\e018" -} - -.glyphicon-cog:before { - content: "\e019" -} - -.glyphicon-trash:before { - content: "\e020" -} - -.glyphicon-home:before { - content: "\e021" -} - -.glyphicon-file:before { - content: "\e022" -} - -.glyphicon-time:before { - content: "\e023" -} - -.glyphicon-road:before { - content: "\e024" -} - -.glyphicon-download-alt:before { - content: "\e025" -} - -.glyphicon-download:before { - content: "\e026" -} - -.glyphicon-upload:before { - content: "\e027" -} - -.glyphicon-inbox:before { - content: "\e028" -} - -.glyphicon-play-circle:before { - content: "\e029" -} - -.glyphicon-repeat:before { - content: "\e030" -} - -.glyphicon-refresh:before { - content: "\e031" -} - -.glyphicon-list-alt:before { - content: "\e032" -} - -.glyphicon-lock:before { - content: "\e033" -} - -.glyphicon-flag:before { - content: "\e034" -} - -.glyphicon-headphones:before { - content: "\e035" -} - -.glyphicon-volume-off:before { - content: "\e036" -} - -.glyphicon-volume-down:before { - content: "\e037" -} - -.glyphicon-volume-up:before { - content: "\e038" -} - -.glyphicon-qrcode:before { - content: "\e039" -} - -.glyphicon-barcode:before { - content: "\e040" -} - -.glyphicon-tag:before { - content: "\e041" -} - -.glyphicon-tags:before { - content: "\e042" -} - -.glyphicon-book:before { - content: "\e043" -} - -.glyphicon-bookmark:before { - content: "\e044" -} - -.glyphicon-print:before { - content: "\e045" -} - -.glyphicon-camera:before { - content: "\e046" -} - -.glyphicon-font:before { - content: "\e047" -} - -.glyphicon-bold:before { - content: "\e048" -} - -.glyphicon-italic:before { - content: "\e049" -} - -.glyphicon-text-height:before { - content: "\e050" -} - -.glyphicon-text-width:before { - content: "\e051" -} - -.glyphicon-align-left:before { - content: "\e052" -} - -.glyphicon-align-center:before { - content: "\e053" -} - -.glyphicon-align-right:before { - content: "\e054" -} - -.glyphicon-align-justify:before { - content: "\e055" -} - -.glyphicon-list:before { - content: "\e056" -} - -.glyphicon-indent-left:before { - content: "\e057" -} - -.glyphicon-indent-right:before { - content: "\e058" -} - -.glyphicon-facetime-video:before { - content: "\e059" -} - -.glyphicon-picture:before { - content: "\e060" -} - -.glyphicon-map-marker:before { - content: "\e062" -} - -.glyphicon-adjust:before { - content: "\e063" -} - -.glyphicon-tint:before { - content: "\e064" -} - -.glyphicon-edit:before { - content: "\e065" -} - -.glyphicon-share:before { - content: "\e066" -} - -.glyphicon-check:before { - content: "\e067" -} - -.glyphicon-move:before { - content: "\e068" -} - -.glyphicon-step-backward:before { - content: "\e069" -} - -.glyphicon-fast-backward:before { - content: "\e070" -} - -.glyphicon-backward:before { - content: "\e071" -} - -.glyphicon-play:before { - content: "\e072" -} - -.glyphicon-pause:before { - content: "\e073" -} - -.glyphicon-stop:before { - content: "\e074" -} - -.glyphicon-forward:before { - content: "\e075" -} - -.glyphicon-fast-forward:before { - content: "\e076" -} - -.glyphicon-step-forward:before { - content: "\e077" -} - -.glyphicon-eject:before { - content: "\e078" -} - -.glyphicon-chevron-left:before { - content: "\e079" -} - -.glyphicon-chevron-right:before { - content: "\e080" -} - -.glyphicon-plus-sign:before { - content: "\e081" -} - -.glyphicon-minus-sign:before { - content: "\e082" -} - -.glyphicon-remove-sign:before { - content: "\e083" -} - -.glyphicon-ok-sign:before { - content: "\e084" -} - -.glyphicon-question-sign:before { - content: "\e085" -} - -.glyphicon-info-sign:before { - content: "\e086" -} - -.glyphicon-screenshot:before { - content: "\e087" -} - -.glyphicon-remove-circle:before { - content: "\e088" -} - -.glyphicon-ok-circle:before { - content: "\e089" -} - -.glyphicon-ban-circle:before { - content: "\e090" -} - -.glyphicon-arrow-left:before { - content: "\e091" -} - -.glyphicon-arrow-right:before { - content: "\e092" -} - -.glyphicon-arrow-up:before { - content: "\e093" -} - -.glyphicon-arrow-down:before { - content: "\e094" -} - -.glyphicon-share-alt:before { - content: "\e095" -} - -.glyphicon-resize-full:before { - content: "\e096" -} - -.glyphicon-resize-small:before { - content: "\e097" -} - -.glyphicon-exclamation-sign:before { - content: "\e101" -} - -.glyphicon-gift:before { - content: "\e102" -} - -.glyphicon-leaf:before { - content: "\e103" -} - -.glyphicon-fire:before { - content: "\e104" -} - -.glyphicon-eye-open:before { - content: "\e105" -} - -.glyphicon-eye-close:before { - content: "\e106" -} - -.glyphicon-warning-sign:before { - content: "\e107" -} - -.glyphicon-plane:before { - content: "\e108" -} - -.glyphicon-calendar:before { - content: "\e109" -} - -.glyphicon-random:before { - content: "\e110" -} - -.glyphicon-comment:before { - content: "\e111" -} - -.glyphicon-magnet:before { - content: "\e112" -} - -.glyphicon-chevron-up:before { - content: "\e113" -} - -.glyphicon-chevron-down:before { - content: "\e114" -} - -.glyphicon-retweet:before { - content: "\e115" -} - -.glyphicon-shopping-cart:before { - content: "\e116" -} - -.glyphicon-folder-close:before { - content: "\e117" -} - -.glyphicon-folder-open:before { - content: "\e118" -} - -.glyphicon-resize-vertical:before { - content: "\e119" -} - -.glyphicon-resize-horizontal:before { - content: "\e120" -} - -.glyphicon-hdd:before { - content: "\e121" -} - -.glyphicon-bullhorn:before { - content: "\e122" -} - -.glyphicon-bell:before { - content: "\e123" -} - -.glyphicon-certificate:before { - content: "\e124" -} - -.glyphicon-thumbs-up:before { - content: "\e125" -} - -.glyphicon-thumbs-down:before { - content: "\e126" -} - -.glyphicon-hand-right:before { - content: "\e127" -} - -.glyphicon-hand-left:before { - content: "\e128" -} - -.glyphicon-hand-up:before { - content: "\e129" -} - -.glyphicon-hand-down:before { - content: "\e130" -} - -.glyphicon-circle-arrow-right:before { - content: "\e131" -} - -.glyphicon-circle-arrow-left:before { - content: "\e132" -} - -.glyphicon-circle-arrow-up:before { - content: "\e133" -} - -.glyphicon-circle-arrow-down:before { - content: "\e134" -} - -.glyphicon-globe:before { - content: "\e135" -} - -.glyphicon-wrench:before { - content: "\e136" -} - -.glyphicon-tasks:before { - content: "\e137" -} - -.glyphicon-filter:before { - content: "\e138" -} - -.glyphicon-briefcase:before { - content: "\e139" -} - -.glyphicon-fullscreen:before { - content: "\e140" -} - -.glyphicon-dashboard:before { - content: "\e141" -} - -.glyphicon-paperclip:before { - content: "\e142" -} - -.glyphicon-heart-empty:before { - content: "\e143" -} - -.glyphicon-link:before { - content: "\e144" -} - -.glyphicon-phone:before { - content: "\e145" -} - -.glyphicon-pushpin:before { - content: "\e146" -} - -.glyphicon-usd:before { - content: "\e148" -} - -.glyphicon-gbp:before { - content: "\e149" -} - -.glyphicon-sort:before { - content: "\e150" -} - -.glyphicon-sort-by-alphabet:before { - content: "\e151" -} - -.glyphicon-sort-by-alphabet-alt:before { - content: "\e152" -} - -.glyphicon-sort-by-order:before { - content: "\e153" -} - -.glyphicon-sort-by-order-alt:before { - content: "\e154" -} - -.glyphicon-sort-by-attributes:before { - content: "\e155" -} - -.glyphicon-sort-by-attributes-alt:before { - content: "\e156" -} - -.glyphicon-unchecked:before { - content: "\e157" -} - -.glyphicon-expand:before { - content: "\e158" -} - -.glyphicon-collapse-down:before { - content: "\e159" -} - -.glyphicon-collapse-up:before { - content: "\e160" -} - -.glyphicon-log-in:before { - content: "\e161" -} - -.glyphicon-flash:before { - content: "\e162" -} - -.glyphicon-log-out:before { - content: "\e163" -} - -.glyphicon-new-window:before { - content: "\e164" -} - -.glyphicon-record:before { - content: "\e165" -} - -.glyphicon-save:before { - content: "\e166" -} - -.glyphicon-open:before { - content: "\e167" -} - -.glyphicon-saved:before { - content: "\e168" -} - -.glyphicon-import:before { - content: "\e169" -} - -.glyphicon-export:before { - content: "\e170" -} - -.glyphicon-send:before { - content: "\e171" -} - -.glyphicon-floppy-disk:before { - content: "\e172" -} - -.glyphicon-floppy-saved:before { - content: "\e173" -} - -.glyphicon-floppy-remove:before { - content: "\e174" -} - -.glyphicon-floppy-save:before { - content: "\e175" -} - -.glyphicon-floppy-open:before { - content: "\e176" -} - -.glyphicon-credit-card:before { - content: "\e177" -} - -.glyphicon-transfer:before { - content: "\e178" -} - -.glyphicon-cutlery:before { - content: "\e179" -} - -.glyphicon-header:before { - content: "\e180" -} - -.glyphicon-compressed:before { - content: "\e181" -} - -.glyphicon-earphone:before { - content: "\e182" -} - -.glyphicon-phone-alt:before { - content: "\e183" -} - -.glyphicon-tower:before { - content: "\e184" -} - -.glyphicon-stats:before { - content: "\e185" -} - -.glyphicon-sd-video:before { - content: "\e186" -} - -.glyphicon-hd-video:before { - content: "\e187" -} - -.glyphicon-subtitles:before { - content: "\e188" -} - -.glyphicon-sound-stereo:before { - content: "\e189" -} - -.glyphicon-sound-dolby:before { - content: "\e190" -} - -.glyphicon-sound-5-1:before { - content: "\e191" -} - -.glyphicon-sound-6-1:before { - content: "\e192" -} - -.glyphicon-sound-7-1:before { - content: "\e193" -} - -.glyphicon-copyright-mark:before { - content: "\e194" -} - -.glyphicon-registration-mark:before { - content: "\e195" -} - -.glyphicon-cloud-download:before { - content: "\e197" -} - -.glyphicon-cloud-upload:before { - content: "\e198" -} - -.glyphicon-tree-conifer:before { - content: "\e199" -} - -.glyphicon-tree-deciduous:before { - content: "\e200" -} - -.glyphicon-cd:before { - content: "\e201" -} - -.glyphicon-save-file:before { - content: "\e202" -} - -.glyphicon-open-file:before { - content: "\e203" -} - -.glyphicon-level-up:before { - content: "\e204" -} - -.glyphicon-copy:before { - content: "\e205" -} - -.glyphicon-paste:before { - content: "\e206" -} - -.glyphicon-alert:before { - content: "\e209" -} - -.glyphicon-equalizer:before { - content: "\e210" -} - -.glyphicon-king:before { - content: "\e211" -} - -.glyphicon-queen:before { - content: "\e212" -} - -.glyphicon-pawn:before { - content: "\e213" -} - -.glyphicon-bishop:before { - content: "\e214" -} - -.glyphicon-knight:before { - content: "\e215" -} - -.glyphicon-baby-formula:before { - content: "\e216" -} - -.glyphicon-tent:before { - content: "\26fa" -} - -.glyphicon-blackboard:before { - content: "\e218" -} - -.glyphicon-bed:before { - content: "\e219" -} - -.glyphicon-apple:before { - content: "\f8ff" -} - -.glyphicon-erase:before { - content: "\e221" -} - -.glyphicon-hourglass:before { - content: "\231b" -} - -.glyphicon-lamp:before { - content: "\e223" -} - -.glyphicon-duplicate:before { - content: "\e224" -} - -.glyphicon-piggy-bank:before { - content: "\e225" -} - -.glyphicon-scissors:before { - content: "\e226" -} - -.glyphicon-bitcoin:before { - content: "\e227" -} - -.glyphicon-btc:before { - content: "\e227" -} - -.glyphicon-xbt:before { - content: "\e227" -} - -.glyphicon-yen:before { - content: "\00a5" -} - -.glyphicon-jpy:before { - content: "\00a5" -} - -.glyphicon-ruble:before { - content: "\20bd" -} - -.glyphicon-rub:before { - content: "\20bd" -} - -.glyphicon-scale:before { - content: "\e230" -} - -.glyphicon-ice-lolly:before { - content: "\e231" -} - -.glyphicon-ice-lolly-tasted:before { - content: "\e232" -} - -.glyphicon-education:before { - content: "\e233" -} - -.glyphicon-option-horizontal:before { - content: "\e234" -} - -.glyphicon-option-vertical:before { - content: "\e235" -} - -.glyphicon-menu-hamburger:before { - content: "\e236" -} - -.glyphicon-modal-window:before { - content: "\e237" -} - -.glyphicon-oil:before { - content: "\e238" -} - -.glyphicon-grain:before { - content: "\e239" -} - -.glyphicon-sunglasses:before { - content: "\e240" -} - -.glyphicon-text-size:before { - content: "\e241" -} - -.glyphicon-text-color:before { - content: "\e242" -} - -.glyphicon-text-background:before { - content: "\e243" -} - -.glyphicon-object-align-top:before { - content: "\e244" -} - -.glyphicon-object-align-bottom:before { - content: "\e245" -} - -.glyphicon-object-align-horizontal:before { - content: "\e246" -} - -.glyphicon-object-align-left:before { - content: "\e247" -} - -.glyphicon-object-align-vertical:before { - content: "\e248" -} - -.glyphicon-object-align-right:before { - content: "\e249" -} - -.glyphicon-triangle-right:before { - content: "\e250" -} - -.glyphicon-triangle-left:before { - content: "\e251" -} - -.glyphicon-triangle-bottom:before { - content: "\e252" -} - -.glyphicon-triangle-top:before { - content: "\e253" -} - -.glyphicon-console:before { - content: "\e254" -} - -.glyphicon-superscript:before { - content: "\e255" -} - -.glyphicon-subscript:before { - content: "\e256" -} - -.glyphicon-menu-left:before { - content: "\e257" -} - -.glyphicon-menu-right:before { - content: "\e258" -} - -.glyphicon-menu-down:before { - content: "\e259" -} - -.glyphicon-menu-up:before { - content: "\e260" -} - -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box -} - -:after, :before { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box -} - -html { - font-size: 10px; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0) -} - -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - line-height: 1.42857143; - color: #333; - background-color: #FFF -} - -button, input, select, textarea { - font-family: inherit; - font-size: inherit; - line-height: inherit -} - -a { - color: #337AB7; - text-decoration: none -} - -a:focus, a:hover { - color: #23527C; - text-decoration: underline -} - -a:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px -} - -figure { - margin: 0 -} - -img { - vertical-align: middle -} - -.carousel-inner > .item > a > img, .carousel-inner > .item > img, .img-responsive, .thumbnail a > img, .thumbnail > img { - display: block; - max-width: 100%; - height: auto -} - -.img-rounded { - border-radius: 6px -} - -.img-thumbnail { - display: inline-block; - max-width: 100%; - height: auto; - padding: 4px; - line-height: 1.42857143; - background-color: #FFF; - border: 1px solid #DDD; - border-radius: 4px; - -webkit-transition: all .2s ease-in-out; - -o-transition: all .2s ease-in-out; - transition: all .2s ease-in-out -} - -.img-circle { - border-radius: 50% -} - -hr { - margin-top: 20px; - margin-bottom: 20px; - border: 0; - border-top: 1px solid #EEE -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0 -} - -.sr-only-focusable:active, .sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto -} - -[role=button] { - cursor: pointer -} - -.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { - font-family: inherit; - font-weight: 500; - line-height: 1.1; - color: inherit -} - -.h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, .h4 .small, .h4 small, .h5 .small, .h5 small, .h6 .small, .h6 small, h1 .small, h1 small, h2 .small, h2 small, h3 .small, h3 small, h4 .small, h4 small, h5 .small, h5 small, h6 .small, h6 small { - font-weight: 400; - line-height: 1; - color: #777 -} - -.h1, .h2, .h3, h1, h2, h3 { - margin-top: 20px; - margin-bottom: 10px -} - -.h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, h1 .small, h1 small, h2 .small, h2 small, h3 .small, h3 small { - font-size: 65% -} - -.h4, .h5, .h6, h4, h5, h6 { - margin-top: 10px; - margin-bottom: 10px -} - -.h4 .small, .h4 small, .h5 .small, .h5 small, .h6 .small, .h6 small, h4 .small, h4 small, h5 .small, h5 small, h6 .small, h6 small { - font-size: 75% -} - -.h1, h1 { - font-size: 36px -} - -.h2, h2 { - font-size: 30px -} - -.h3, h3 { - font-size: 24px -} - -.h4, h4 { - font-size: 18px -} - -.h5, h5 { - font-size: 14px -} - -.h6, h6 { - font-size: 12px -} - -p { - margin: 0 0 10px -} - -.lead { - margin-bottom: 20px; - font-size: 16px; - font-weight: 300; - line-height: 1.4 -} - -@media (min-width: 768px) { - .lead { - font-size: 21px - } -} - -.small, small { - font-size: 85% -} - -.mark, mark { - padding: .2em; - background-color: #FCF8E3 -} - -.text-left { - text-align: left -} - -.text-right { - text-align: right -} - -.text-center { - text-align: center -} - -.text-justify { - text-align: justify -} - -.text-nowrap { - white-space: nowrap -} - -.text-lowercase { - text-transform: lowercase -} - -.text-uppercase { - text-transform: uppercase -} - -.text-capitalize { - text-transform: capitalize -} - -.text-muted { - color: #777 -} - -.text-primary { - color: #337AB7 -} - -a.text-primary:focus, a.text-primary:hover { - color: #286090 -} - -.text-success { - color: #3C763D -} - -a.text-success:focus, a.text-success:hover { - color: #2B542C -} - -.text-info { - color: #31708F -} - -a.text-info:focus, a.text-info:hover { - color: #245269 -} - -.text-warning { - color: #8A6D3B -} - -a.text-warning:focus, a.text-warning:hover { - color: #66512C -} - -.text-danger { - color: #A94442 -} - -a.text-danger:focus, a.text-danger:hover { - color: #843534 -} - -.bg-primary { - color: #FFF; - background-color: #337AB7 -} - -a.bg-primary:focus, a.bg-primary:hover { - background-color: #286090 -} - -.bg-success { - background-color: #DFF0D8 -} - -a.bg-success:focus, a.bg-success:hover { - background-color: #C1E2B3 -} - -.bg-info { - background-color: #D9EDF7 -} - -a.bg-info:focus, a.bg-info:hover { - background-color: #AFD9EE -} - -.bg-warning { - background-color: #FCF8E3 -} - -a.bg-warning:focus, a.bg-warning:hover { - background-color: #F7ECB5 -} - -.bg-danger { - background-color: #F2DEDE -} - -a.bg-danger:focus, a.bg-danger:hover { - background-color: #E4B9B9 -} - -.page-header { - padding-bottom: 9px; - margin: 40px 0 20px; - border-bottom: 1px solid #EEE -} - -ol, ul { - margin-top: 0; - margin-bottom: 10px -} - -ol ol, ol ul, ul ol, ul ul { - margin-bottom: 0 -} - -.list-unstyled { - padding-left: 0; - list-style: none -} - -.list-inline { - padding-left: 0; - margin-left: -5px; - list-style: none -} - -.list-inline > li { - display: inline-block; - padding-right: 5px; - padding-left: 5px -} - -dl { - margin-top: 0; - margin-bottom: 20px -} - -dd, dt { - line-height: 1.42857143 -} - -dt { - font-weight: 700 -} - -dd { - margin-left: 0 -} - -@media (min-width: 768px) { - .dl-horizontal dt { - float: left; - width: 160px; - overflow: hidden; - clear: left; - text-align: right; - text-overflow: ellipsis; - white-space: nowrap - } - - .dl-horizontal dd { - margin-left: 180px - } -} - -abbr[data-original-title], abbr[title] { - cursor: help; - border-bottom: 1px dotted #777 -} - -.initialism { - font-size: 90%; - text-transform: uppercase -} - -blockquote { - padding: 10px 20px; - margin: 0 0 20px; - font-size: 17.5px; - border-left: 5px solid #EEE -} - -blockquote ol:last-child, blockquote p:last-child, blockquote ul:last-child { - margin-bottom: 0 -} - -blockquote .small, blockquote footer, blockquote small { - display: block; - font-size: 80%; - line-height: 1.42857143; - color: #777 -} - -blockquote .small:before, blockquote footer:before, blockquote small:before { - content: '\2014 \00A0' -} - -.blockquote-reverse, blockquote.pull-right { - padding-right: 15px; - padding-left: 0; - text-align: right; - border-right: 5px solid #EEE; - border-left: 0 -} - -.blockquote-reverse .small:before, .blockquote-reverse footer:before, .blockquote-reverse small:before, blockquote.pull-right .small:before, blockquote.pull-right footer:before, blockquote.pull-right small:before { - content: '' -} - -.blockquote-reverse .small:after, .blockquote-reverse footer:after, .blockquote-reverse small:after, blockquote.pull-right .small:after, blockquote.pull-right footer:after, blockquote.pull-right small:after { - content: '\00A0 \2014' -} - -address { - margin-bottom: 20px; - font-style: normal; - line-height: 1.42857143 -} - -code, kbd, pre, samp { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace -} - -code { - padding: 2px 4px; - font-size: 90%; - color: #C7254E; - background-color: #F9F2F4; - border-radius: 4px -} - -kbd { - padding: 2px 4px; - font-size: 90%; - color: #FFF; - background-color: #333; - border-radius: 3px; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25) -} - -kbd kbd { - padding: 0; - font-size: 100%; - font-weight: 700; - -webkit-box-shadow: none; - box-shadow: none -} - -pre { - display: block; - padding: 9.5px; - margin: 0 0 10px; - font-size: 13px; - line-height: 1.42857143; - color: #333; - word-break: break-all; - word-wrap: break-word; - background-color: #F5F5F5; - border: 1px solid #CCC; - border-radius: 4px -} - -pre code { - padding: 0; - font-size: inherit; - color: inherit; - white-space: pre-wrap; - background-color: transparent; - border-radius: 0 -} - -.pre-scrollable { - max-height: 340px; - overflow-y: scroll -} - -.container { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto -} - -@media (min-width: 768px) { - .container { - width: 750px - } -} - -@media (min-width: 992px) { - .container { - width: 970px - } -} - -@media (min-width: 1200px) { - .container { - width: 1170px - } -} - -.container-fluid { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto -} - -.row { - margin-right: -15px; - margin-left: -15px -} - -.col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 { - position: relative; - min-height: 1px; - padding-right: 15px; - padding-left: 15px -} - -.col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 { - float: left -} - -.col-xs-12 { - width: 100% -} - -.col-xs-11 { - width: 91.66666667% -} - -.col-xs-10 { - width: 83.33333333% -} - -.col-xs-9 { - width: 75% -} - -.col-xs-8 { - width: 66.66666667% -} - -.col-xs-7 { - width: 58.33333333% -} - -.col-xs-6 { - width: 50% -} - -.col-xs-5 { - width: 41.66666667% -} - -.col-xs-4 { - width: 33.33333333% -} - -.col-xs-3 { - width: 25% -} - -.col-xs-2 { - width: 16.66666667% -} - -.col-xs-1 { - width: 8.33333333% -} - -.col-xs-pull-12 { - right: 100% -} - -.col-xs-pull-11 { - right: 91.66666667% -} - -.col-xs-pull-10 { - right: 83.33333333% -} - -.col-xs-pull-9 { - right: 75% -} - -.col-xs-pull-8 { - right: 66.66666667% -} - -.col-xs-pull-7 { - right: 58.33333333% -} - -.col-xs-pull-6 { - right: 50% -} - -.col-xs-pull-5 { - right: 41.66666667% -} - -.col-xs-pull-4 { - right: 33.33333333% -} - -.col-xs-pull-3 { - right: 25% -} - -.col-xs-pull-2 { - right: 16.66666667% -} - -.col-xs-pull-1 { - right: 8.33333333% -} - -.col-xs-pull-0 { - right: auto -} - -.col-xs-push-12 { - left: 100% -} - -.col-xs-push-11 { - left: 91.66666667% -} - -.col-xs-push-10 { - left: 83.33333333% -} - -.col-xs-push-9 { - left: 75% -} - -.col-xs-push-8 { - left: 66.66666667% -} - -.col-xs-push-7 { - left: 58.33333333% -} - -.col-xs-push-6 { - left: 50% -} - -.col-xs-push-5 { - left: 41.66666667% -} - -.col-xs-push-4 { - left: 33.33333333% -} - -.col-xs-push-3 { - left: 25% -} - -.col-xs-push-2 { - left: 16.66666667% -} - -.col-xs-push-1 { - left: 8.33333333% -} - -.col-xs-push-0 { - left: auto -} - -.col-xs-offset-12 { - margin-left: 100% -} - -.col-xs-offset-11 { - margin-left: 91.66666667% -} - -.col-xs-offset-10 { - margin-left: 83.33333333% -} - -.col-xs-offset-9 { - margin-left: 75% -} - -.col-xs-offset-8 { - margin-left: 66.66666667% -} - -.col-xs-offset-7 { - margin-left: 58.33333333% -} - -.col-xs-offset-6 { - margin-left: 50% -} - -.col-xs-offset-5 { - margin-left: 41.66666667% -} - -.col-xs-offset-4 { - margin-left: 33.33333333% -} - -.col-xs-offset-3 { - margin-left: 25% -} - -.col-xs-offset-2 { - margin-left: 16.66666667% -} - -.col-xs-offset-1 { - margin-left: 8.33333333% -} - -.col-xs-offset-0 { - margin-left: 0 -} - -@media (min-width: 768px) { - .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9 { - float: left - } - - .col-sm-12 { - width: 100% - } - - .col-sm-11 { - width: 91.66666667% - } - - .col-sm-10 { - width: 83.33333333% - } - - .col-sm-9 { - width: 75% - } - - .col-sm-8 { - width: 66.66666667% - } - - .col-sm-7 { - width: 58.33333333% - } - - .col-sm-6 { - width: 50% - } - - .col-sm-5 { - width: 41.66666667% - } - - .col-sm-4 { - width: 33.33333333% - } - - .col-sm-3 { - width: 25% - } - - .col-sm-2 { - width: 16.66666667% - } - - .col-sm-1 { - width: 8.33333333% - } - - .col-sm-pull-12 { - right: 100% - } - - .col-sm-pull-11 { - right: 91.66666667% - } - - .col-sm-pull-10 { - right: 83.33333333% - } - - .col-sm-pull-9 { - right: 75% - } - - .col-sm-pull-8 { - right: 66.66666667% - } - - .col-sm-pull-7 { - right: 58.33333333% - } - - .col-sm-pull-6 { - right: 50% - } - - .col-sm-pull-5 { - right: 41.66666667% - } - - .col-sm-pull-4 { - right: 33.33333333% - } - - .col-sm-pull-3 { - right: 25% - } - - .col-sm-pull-2 { - right: 16.66666667% - } - - .col-sm-pull-1 { - right: 8.33333333% - } - - .col-sm-pull-0 { - right: auto - } - - .col-sm-push-12 { - left: 100% - } - - .col-sm-push-11 { - left: 91.66666667% - } - - .col-sm-push-10 { - left: 83.33333333% - } - - .col-sm-push-9 { - left: 75% - } - - .col-sm-push-8 { - left: 66.66666667% - } - - .col-sm-push-7 { - left: 58.33333333% - } - - .col-sm-push-6 { - left: 50% - } - - .col-sm-push-5 { - left: 41.66666667% - } - - .col-sm-push-4 { - left: 33.33333333% - } - - .col-sm-push-3 { - left: 25% - } - - .col-sm-push-2 { - left: 16.66666667% - } - - .col-sm-push-1 { - left: 8.33333333% - } - - .col-sm-push-0 { - left: auto - } - - .col-sm-offset-12 { - margin-left: 100% - } - - .col-sm-offset-11 { - margin-left: 91.66666667% - } - - .col-sm-offset-10 { - margin-left: 83.33333333% - } - - .col-sm-offset-9 { - margin-left: 75% - } - - .col-sm-offset-8 { - margin-left: 66.66666667% - } - - .col-sm-offset-7 { - margin-left: 58.33333333% - } - - .col-sm-offset-6 { - margin-left: 50% - } - - .col-sm-offset-5 { - margin-left: 41.66666667% - } - - .col-sm-offset-4 { - margin-left: 33.33333333% - } - - .col-sm-offset-3 { - margin-left: 25% - } - - .col-sm-offset-2 { - margin-left: 16.66666667% - } - - .col-sm-offset-1 { - margin-left: 8.33333333% - } - - .col-sm-offset-0 { - margin-left: 0 - } -} - -@media (min-width: 992px) { - .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9 { - float: left - } - - .col-md-12 { - width: 100% - } - - .col-md-11 { - width: 91.66666667% - } - - .col-md-10 { - width: 83.33333333% - } - - .col-md-9 { - width: 75% - } - - .col-md-8 { - width: 66.66666667% - } - - .col-md-7 { - width: 58.33333333% - } - - .col-md-6 { - width: 50% - } - - .col-md-5 { - width: 41.66666667% - } - - .col-md-4 { - width: 33.33333333% - } - - .col-md-3 { - width: 25% - } - - .col-md-2 { - width: 16.66666667% - } - - .col-md-1 { - width: 8.33333333% - } - - .col-md-pull-12 { - right: 100% - } - - .col-md-pull-11 { - right: 91.66666667% - } - - .col-md-pull-10 { - right: 83.33333333% - } - - .col-md-pull-9 { - right: 75% - } - - .col-md-pull-8 { - right: 66.66666667% - } - - .col-md-pull-7 { - right: 58.33333333% - } - - .col-md-pull-6 { - right: 50% - } - - .col-md-pull-5 { - right: 41.66666667% - } - - .col-md-pull-4 { - right: 33.33333333% - } - - .col-md-pull-3 { - right: 25% - } - - .col-md-pull-2 { - right: 16.66666667% - } - - .col-md-pull-1 { - right: 8.33333333% - } - - .col-md-pull-0 { - right: auto - } - - .col-md-push-12 { - left: 100% - } - - .col-md-push-11 { - left: 91.66666667% - } - - .col-md-push-10 { - left: 83.33333333% - } - - .col-md-push-9 { - left: 75% - } - - .col-md-push-8 { - left: 66.66666667% - } - - .col-md-push-7 { - left: 58.33333333% - } - - .col-md-push-6 { - left: 50% - } - - .col-md-push-5 { - left: 41.66666667% - } - - .col-md-push-4 { - left: 33.33333333% - } - - .col-md-push-3 { - left: 25% - } - - .col-md-push-2 { - left: 16.66666667% - } - - .col-md-push-1 { - left: 8.33333333% - } - - .col-md-push-0 { - left: auto - } - - .col-md-offset-12 { - margin-left: 100% - } - - .col-md-offset-11 { - margin-left: 91.66666667% - } - - .col-md-offset-10 { - margin-left: 83.33333333% - } - - .col-md-offset-9 { - margin-left: 75% - } - - .col-md-offset-8 { - margin-left: 66.66666667% - } - - .col-md-offset-7 { - margin-left: 58.33333333% - } - - .col-md-offset-6 { - margin-left: 50% - } - - .col-md-offset-5 { - margin-left: 41.66666667% - } - - .col-md-offset-4 { - margin-left: 33.33333333% - } - - .col-md-offset-3 { - margin-left: 25% - } - - .col-md-offset-2 { - margin-left: 16.66666667% - } - - .col-md-offset-1 { - margin-left: 8.33333333% - } - - .col-md-offset-0 { - margin-left: 0 - } -} - -@media (min-width: 1200px) { - .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9 { - float: left - } - - .col-lg-12 { - width: 100% - } - - .col-lg-11 { - width: 91.66666667% - } - - .col-lg-10 { - width: 83.33333333% - } - - .col-lg-9 { - width: 75% - } - - .col-lg-8 { - width: 66.66666667% - } - - .col-lg-7 { - width: 58.33333333% - } - - .col-lg-6 { - width: 50% - } - - .col-lg-5 { - width: 41.66666667% - } - - .col-lg-4 { - width: 33.33333333% - } - - .col-lg-3 { - width: 25% - } - - .col-lg-2 { - width: 16.66666667% - } - - .col-lg-1 { - width: 8.33333333% - } - - .col-lg-pull-12 { - right: 100% - } - - .col-lg-pull-11 { - right: 91.66666667% - } - - .col-lg-pull-10 { - right: 83.33333333% - } - - .col-lg-pull-9 { - right: 75% - } - - .col-lg-pull-8 { - right: 66.66666667% - } - - .col-lg-pull-7 { - right: 58.33333333% - } - - .col-lg-pull-6 { - right: 50% - } - - .col-lg-pull-5 { - right: 41.66666667% - } - - .col-lg-pull-4 { - right: 33.33333333% - } - - .col-lg-pull-3 { - right: 25% - } - - .col-lg-pull-2 { - right: 16.66666667% - } - - .col-lg-pull-1 { - right: 8.33333333% - } - - .col-lg-pull-0 { - right: auto - } - - .col-lg-push-12 { - left: 100% - } - - .col-lg-push-11 { - left: 91.66666667% - } - - .col-lg-push-10 { - left: 83.33333333% - } - - .col-lg-push-9 { - left: 75% - } - - .col-lg-push-8 { - left: 66.66666667% - } - - .col-lg-push-7 { - left: 58.33333333% - } - - .col-lg-push-6 { - left: 50% - } - - .col-lg-push-5 { - left: 41.66666667% - } - - .col-lg-push-4 { - left: 33.33333333% - } - - .col-lg-push-3 { - left: 25% - } - - .col-lg-push-2 { - left: 16.66666667% - } - - .col-lg-push-1 { - left: 8.33333333% - } - - .col-lg-push-0 { - left: auto - } - - .col-lg-offset-12 { - margin-left: 100% - } - - .col-lg-offset-11 { - margin-left: 91.66666667% - } - - .col-lg-offset-10 { - margin-left: 83.33333333% - } - - .col-lg-offset-9 { - margin-left: 75% - } - - .col-lg-offset-8 { - margin-left: 66.66666667% - } - - .col-lg-offset-7 { - margin-left: 58.33333333% - } - - .col-lg-offset-6 { - margin-left: 50% - } - - .col-lg-offset-5 { - margin-left: 41.66666667% - } - - .col-lg-offset-4 { - margin-left: 33.33333333% - } - - .col-lg-offset-3 { - margin-left: 25% - } - - .col-lg-offset-2 { - margin-left: 16.66666667% - } - - .col-lg-offset-1 { - margin-left: 8.33333333% - } - - .col-lg-offset-0 { - margin-left: 0 - } -} - -table { - background-color: transparent -} - -caption { - padding-top: 8px; - padding-bottom: 8px; - color: #777; - text-align: left -} - -th { - text-align: left -} - -.table { - width: 100%; - max-width: 100%; - margin-bottom: 20px -} - -.table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th { - padding: 8px; - line-height: 1.42857143; - vertical-align: top; - border-top: 1px solid #DDD -} - -.table > thead > tr > th { - vertical-align: bottom; - border-bottom: 2px solid #DDD -} - -.table > caption + thead > tr:first-child > td, .table > caption + thead > tr:first-child > th, .table > colgroup + thead > tr:first-child > td, .table > colgroup + thead > tr:first-child > th, .table > thead:first-child > tr:first-child > td, .table > thead:first-child > tr:first-child > th { - border-top: 0 -} - -.table > tbody + tbody { - border-top: 2px solid #DDD -} - -.table .table { - background-color: #FFF -} - -.table-condensed > tbody > tr > td, .table-condensed > tbody > tr > th, .table-condensed > tfoot > tr > td, .table-condensed > tfoot > tr > th, .table-condensed > thead > tr > td, .table-condensed > thead > tr > th { - padding: 5px -} - -.table-bordered { - border: 1px solid #DDD -} - -.table-bordered > tbody > tr > td, .table-bordered > tbody > tr > th, .table-bordered > tfoot > tr > td, .table-bordered > tfoot > tr > th, .table-bordered > thead > tr > td, .table-bordered > thead > tr > th { - border: 1px solid #DDD -} - -.table-bordered > thead > tr > td, .table-bordered > thead > tr > th { - border-bottom-width: 2px -} - -.table-striped > tbody > tr:nth-of-type(odd) { - background-color: #F9F9F9 -} - -.table-hover > tbody > tr:hover { - background-color: #F5F5F5 -} - -table col[class*=col-] { - position: static; - display: table-column; - float: none -} - -table td[class*=col-], table th[class*=col-] { - position: static; - display: table-cell; - float: none -} - -.table > tbody > tr.active > td, .table > tbody > tr.active > th, .table > tbody > tr > td.active, .table > tbody > tr > th.active, .table > tfoot > tr.active > td, .table > tfoot > tr.active > th, .table > tfoot > tr > td.active, .table > tfoot > tr > th.active, .table > thead > tr.active > td, .table > thead > tr.active > th, .table > thead > tr > td.active, .table > thead > tr > th.active { - background-color: #F5F5F5 -} - -.table-hover > tbody > tr.active:hover > td, .table-hover > tbody > tr.active:hover > th, .table-hover > tbody > tr:hover > .active, .table-hover > tbody > tr > td.active:hover, .table-hover > tbody > tr > th.active:hover { - background-color: #E8E8E8 -} - -.table > tbody > tr.success > td, .table > tbody > tr.success > th, .table > tbody > tr > td.success, .table > tbody > tr > th.success, .table > tfoot > tr.success > td, .table > tfoot > tr.success > th, .table > tfoot > tr > td.success, .table > tfoot > tr > th.success, .table > thead > tr.success > td, .table > thead > tr.success > th, .table > thead > tr > td.success, .table > thead > tr > th.success { - background-color: #DFF0D8 -} - -.table-hover > tbody > tr.success:hover > td, .table-hover > tbody > tr.success:hover > th, .table-hover > tbody > tr:hover > .success, .table-hover > tbody > tr > td.success:hover, .table-hover > tbody > tr > th.success:hover { - background-color: #D0E9C6 -} - -.table > tbody > tr.info > td, .table > tbody > tr.info > th, .table > tbody > tr > td.info, .table > tbody > tr > th.info, .table > tfoot > tr.info > td, .table > tfoot > tr.info > th, .table > tfoot > tr > td.info, .table > tfoot > tr > th.info, .table > thead > tr.info > td, .table > thead > tr.info > th, .table > thead > tr > td.info, .table > thead > tr > th.info { - background-color: #D9EDF7 -} - -.table-hover > tbody > tr.info:hover > td, .table-hover > tbody > tr.info:hover > th, .table-hover > tbody > tr:hover > .info, .table-hover > tbody > tr > td.info:hover, .table-hover > tbody > tr > th.info:hover { - background-color: #C4E3F3 -} - -.table > tbody > tr.warning > td, .table > tbody > tr.warning > th, .table > tbody > tr > td.warning, .table > tbody > tr > th.warning, .table > tfoot > tr.warning > td, .table > tfoot > tr.warning > th, .table > tfoot > tr > td.warning, .table > tfoot > tr > th.warning, .table > thead > tr.warning > td, .table > thead > tr.warning > th, .table > thead > tr > td.warning, .table > thead > tr > th.warning { - background-color: #FCF8E3 -} - -.table-hover > tbody > tr.warning:hover > td, .table-hover > tbody > tr.warning:hover > th, .table-hover > tbody > tr:hover > .warning, .table-hover > tbody > tr > td.warning:hover, .table-hover > tbody > tr > th.warning:hover { - background-color: #FAF2CC -} - -.table > tbody > tr.danger > td, .table > tbody > tr.danger > th, .table > tbody > tr > td.danger, .table > tbody > tr > th.danger, .table > tfoot > tr.danger > td, .table > tfoot > tr.danger > th, .table > tfoot > tr > td.danger, .table > tfoot > tr > th.danger, .table > thead > tr.danger > td, .table > thead > tr.danger > th, .table > thead > tr > td.danger, .table > thead > tr > th.danger { - background-color: #F2DEDE -} - -.table-hover > tbody > tr.danger:hover > td, .table-hover > tbody > tr.danger:hover > th, .table-hover > tbody > tr:hover > .danger, .table-hover > tbody > tr > td.danger:hover, .table-hover > tbody > tr > th.danger:hover { - background-color: #EBCCCC -} - -.table-responsive { - min-height: .01%; - overflow-x: auto -} - -@media screen and (max-width: 767px) { - .table-responsive { - width: 100%; - margin-bottom: 15px; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - border: 1px solid #DDD - } - - .table-responsive > .table { - margin-bottom: 0 - } - - .table-responsive > .table > tbody > tr > td, .table-responsive > .table > tbody > tr > th, .table-responsive > .table > tfoot > tr > td, .table-responsive > .table > tfoot > tr > th, .table-responsive > .table > thead > tr > td, .table-responsive > .table > thead > tr > th { - white-space: nowrap - } - - .table-responsive > .table-bordered { - border: 0 - } - - .table-responsive > .table-bordered > tbody > tr > td:first-child, .table-responsive > .table-bordered > tbody > tr > th:first-child, .table-responsive > .table-bordered > tfoot > tr > td:first-child, .table-responsive > .table-bordered > tfoot > tr > th:first-child, .table-responsive > .table-bordered > thead > tr > td:first-child, .table-responsive > .table-bordered > thead > tr > th:first-child { - border-left: 0 - } - - .table-responsive > .table-bordered > tbody > tr > td:last-child, .table-responsive > .table-bordered > tbody > tr > th:last-child, .table-responsive > .table-bordered > tfoot > tr > td:last-child, .table-responsive > .table-bordered > tfoot > tr > th:last-child, .table-responsive > .table-bordered > thead > tr > td:last-child, .table-responsive > .table-bordered > thead > tr > th:last-child { - border-right: 0 - } - - .table-responsive > .table-bordered > tbody > tr:last-child > td, .table-responsive > .table-bordered > tbody > tr:last-child > th, .table-responsive > .table-bordered > tfoot > tr:last-child > td, .table-responsive > .table-bordered > tfoot > tr:last-child > th { - border-bottom: 0 - } -} - -fieldset { - min-width: 0; - padding: 0; - margin: 0; - border: 0 -} - -legend { - display: block; - width: 100%; - padding: 0; - margin-bottom: 20px; - font-size: 21px; - line-height: inherit; - color: #333; - border: 0; - border-bottom: 1px solid #E5E5E5 -} - -label { - display: inline-block; - max-width: 100%; - margin-bottom: 5px; - font-weight: 700 -} - -input[type=search] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box -} - -input[type=checkbox], input[type=radio] { - margin: 4px 0 0; - margin-top: 1px \9; - line-height: normal -} - -input[type=file] { - display: block -} - -input[type=range] { - display: block; - width: 100% -} - -select[multiple], select[size] { - height: auto -} - -input[type=file]:focus, input[type=checkbox]:focus, input[type=radio]:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px -} - -output { - display: block; - padding-top: 7px; - font-size: 14px; - line-height: 1.42857143; - color: #555 -} - -.form-control { - display: block; - width: 100%; - height: 34px; - padding: 6px 12px; - font-size: 14px; - line-height: 1.42857143; - color: #555; - background-color: #FFF; - background-image: none; - border: 1px solid #CCC; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; - -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; - transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s -} - -.form-control:focus { - border-color: #66AFE9; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6) -} - -.form-control::-moz-placeholder { - color: #999; - opacity: 1 -} - -.form-control:-ms-input-placeholder { - color: #999 -} - -.form-control::-webkit-input-placeholder { - color: #999 -} - -.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { - background-color: #EEE; - opacity: 1 -} - -.form-control[disabled], fieldset[disabled] .form-control { - cursor: not-allowed -} - -textarea.form-control { - height: auto -} - -input[type=search] { - -webkit-appearance: none -} - -@media screen and (-webkit-min-device-pixel-ratio: 0) { - input[type=date].form-control, input[type=time].form-control, input[type=datetime-local].form-control, input[type=month].form-control { - line-height: 34px - } - - .input-group-sm input[type=date], .input-group-sm input[type=time], .input-group-sm input[type=datetime-local], .input-group-sm input[type=month], input[type=date].input-sm, input[type=time].input-sm, input[type=datetime-local].input-sm, input[type=month].input-sm { - line-height: 30px - } - - .input-group-lg input[type=date], .input-group-lg input[type=time], .input-group-lg input[type=datetime-local], .input-group-lg input[type=month], input[type=date].input-lg, input[type=time].input-lg, input[type=datetime-local].input-lg, input[type=month].input-lg { - line-height: 46px - } -} - -.form-group { - margin-bottom: 15px -} - -.checkbox, .radio { - position: relative; - display: block; - margin-top: 10px; - margin-bottom: 10px -} - -.checkbox label, .radio label { - min-height: 20px; - padding-left: 20px; - margin-bottom: 0; - font-weight: 400; - cursor: pointer -} - -.checkbox input[type=checkbox], .checkbox-inline input[type=checkbox], .radio input[type=radio], .radio-inline input[type=radio] { - position: absolute; - margin-top: 4px \9; - margin-left: -20px -} - -.checkbox + .checkbox, .radio + .radio { - margin-top: -5px -} - -.checkbox-inline, .radio-inline { - position: relative; - display: inline-block; - padding-left: 20px; - margin-bottom: 0; - font-weight: 400; - vertical-align: middle; - cursor: pointer -} - -.checkbox-inline + .checkbox-inline, .radio-inline + .radio-inline { - margin-top: 0; - margin-left: 10px -} - -fieldset[disabled] input[type=checkbox], fieldset[disabled] input[type=radio], input[type=checkbox].disabled, input[type=checkbox][disabled], input[type=radio].disabled, input[type=radio][disabled] { - cursor: not-allowed -} - -.checkbox-inline.disabled, .radio-inline.disabled, fieldset[disabled] .checkbox-inline, fieldset[disabled] .radio-inline { - cursor: not-allowed -} - -.checkbox.disabled label, .radio.disabled label, fieldset[disabled] .checkbox label, fieldset[disabled] .radio label { - cursor: not-allowed -} - -.form-control-static { - min-height: 34px; - padding-top: 7px; - padding-bottom: 7px; - margin-bottom: 0 -} - -.form-control-static.input-lg, .form-control-static.input-sm { - padding-right: 0; - padding-left: 0 -} - -.input-sm { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -select.input-sm { - height: 30px; - line-height: 30px -} - -select[multiple].input-sm, textarea.input-sm { - height: auto -} - -.form-group-sm .form-control { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -.form-group-sm select.form-control { - height: 30px; - line-height: 30px -} - -.form-group-sm select[multiple].form-control, .form-group-sm textarea.form-control { - height: auto -} - -.form-group-sm .form-control-static { - height: 30px; - min-height: 32px; - padding: 6px 10px; - font-size: 12px; - line-height: 1.5 -} - -.input-lg { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px -} - -select.input-lg { - height: 46px; - line-height: 46px -} - -select[multiple].input-lg, textarea.input-lg { - height: auto -} - -.form-group-lg .form-control { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px -} - -.form-group-lg select.form-control { - height: 46px; - line-height: 46px -} - -.form-group-lg select[multiple].form-control, .form-group-lg textarea.form-control { - height: auto -} - -.form-group-lg .form-control-static { - height: 46px; - min-height: 38px; - padding: 11px 16px; - font-size: 18px; - line-height: 1.3333333 -} - -.has-feedback { - position: relative -} - -.has-feedback .form-control { - padding-right: 42.5px -} - -.form-control-feedback { - position: absolute; - top: 0; - right: 0; - z-index: 2; - display: block; - width: 34px; - height: 34px; - line-height: 34px; - text-align: center; - pointer-events: none -} - -.form-group-lg .form-control + .form-control-feedback, .input-group-lg + .form-control-feedback, .input-lg + .form-control-feedback { - width: 46px; - height: 46px; - line-height: 46px -} - -.form-group-sm .form-control + .form-control-feedback, .input-group-sm + .form-control-feedback, .input-sm + .form-control-feedback { - width: 30px; - height: 30px; - line-height: 30px -} - -.has-success .checkbox, .has-success .checkbox-inline, .has-success .control-label, .has-success .help-block, .has-success .radio, .has-success .radio-inline, .has-success.checkbox label, .has-success.checkbox-inline label, .has-success.radio label, .has-success.radio-inline label { - color: #3C763D -} - -.has-success .form-control { - border-color: #3C763D; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -.has-success .form-control:focus { - border-color: #2B542C; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67B168; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67B168 -} - -.has-success .input-group-addon { - color: #3C763D; - background-color: #DFF0D8; - border-color: #3C763D -} - -.has-success .form-control-feedback { - color: #3C763D -} - -.has-warning .checkbox, .has-warning .checkbox-inline, .has-warning .control-label, .has-warning .help-block, .has-warning .radio, .has-warning .radio-inline, .has-warning.checkbox label, .has-warning.checkbox-inline label, .has-warning.radio label, .has-warning.radio-inline label { - color: #8A6D3B -} - -.has-warning .form-control { - border-color: #8A6D3B; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -.has-warning .form-control:focus { - border-color: #66512C; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #C0A16B; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #C0A16B -} - -.has-warning .input-group-addon { - color: #8A6D3B; - background-color: #FCF8E3; - border-color: #8A6D3B -} - -.has-warning .form-control-feedback { - color: #8A6D3B -} - -.has-error .checkbox, .has-error .checkbox-inline, .has-error .control-label, .has-error .help-block, .has-error .radio, .has-error .radio-inline, .has-error.checkbox label, .has-error.checkbox-inline label, .has-error.radio label, .has-error.radio-inline label { - color: #A94442 -} - -.has-error .form-control { - border-color: #A94442; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -.has-error .form-control:focus { - border-color: #843534; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #CE8483; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #CE8483 -} - -.has-error .input-group-addon { - color: #A94442; - background-color: #F2DEDE; - border-color: #A94442 -} - -.has-error .form-control-feedback { - color: #A94442 -} - -.has-feedback label ~ .form-control-feedback { - top: 25px -} - -.has-feedback label.sr-only ~ .form-control-feedback { - top: 0 -} - -.help-block { - display: block; - margin-top: 5px; - margin-bottom: 10px; - color: #737373 -} - -@media (min-width: 768px) { - .form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle - } - - .form-inline .form-control { - display: inline-block; - width: auto; - vertical-align: middle - } - - .form-inline .form-control-static { - display: inline-block - } - - .form-inline .input-group { - display: inline-table; - vertical-align: middle - } - - .form-inline .input-group .form-control, .form-inline .input-group .input-group-addon, .form-inline .input-group .input-group-btn { - width: auto - } - - .form-inline .input-group > .form-control { - width: 100% - } - - .form-inline .control-label { - margin-bottom: 0; - vertical-align: middle - } - - .form-inline .checkbox, .form-inline .radio { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle - } - - .form-inline .checkbox label, .form-inline .radio label { - padding-left: 0 - } - - .form-inline .checkbox input[type=checkbox], .form-inline .radio input[type=radio] { - position: relative; - margin-left: 0 - } - - .form-inline .has-feedback .form-control-feedback { - top: 0 - } -} - -.form-horizontal .checkbox, .form-horizontal .checkbox-inline, .form-horizontal .radio, .form-horizontal .radio-inline { - padding-top: 7px; - margin-top: 0; - margin-bottom: 0 -} - -.form-horizontal .checkbox, .form-horizontal .radio { - min-height: 27px -} - -.form-horizontal .form-group { - margin-right: -15px; - margin-left: -15px -} - -@media (min-width: 768px) { - .form-horizontal .control-label { - padding-top: 7px; - margin-bottom: 0; - text-align: right - } -} - -.form-horizontal .has-feedback .form-control-feedback { - right: 15px -} - -@media (min-width: 768px) { - .form-horizontal .form-group-lg .control-label { - padding-top: 14.33px; - font-size: 18px - } -} - -@media (min-width: 768px) { - .form-horizontal .form-group-sm .control-label { - padding-top: 6px; - font-size: 12px - } -} - -.btn { - display: inline-block; - padding: 6px 12px; - margin-bottom: 0; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - text-align: center; - white-space: nowrap; - vertical-align: middle; - -ms-touch-action: manipulation; - touch-action: manipulation; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - background-image: none; - border: 1px solid transparent; - border-radius: 4px -} - -.btn.active.focus, .btn.active:focus, .btn.focus, .btn:active.focus, .btn:active:focus, .btn:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px -} - -.btn.focus, .btn:focus, .btn:hover { - color: #333; - text-decoration: none -} - -.btn.active, .btn:active { - background-image: none; - outline: 0; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125) -} - -.btn.disabled, .btn[disabled], fieldset[disabled] .btn { - cursor: not-allowed; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; - opacity: .65 -} - -a.btn.disabled, fieldset[disabled] a.btn { - pointer-events: none -} - -.btn-default { - color: #333; - background-color: #FFF; - border-color: #CCC -} - -.btn-default.focus, .btn-default:focus { - color: #333; - background-color: #E6E6E6; - border-color: #8C8C8C -} - -.btn-default:hover { - color: #333; - background-color: #E6E6E6; - border-color: #ADADAD -} - -.btn-default.active, .btn-default:active, .open > .dropdown-toggle.btn-default { - color: #333; - background-color: #E6E6E6; - border-color: #ADADAD -} - -.btn-default.active.focus, .btn-default.active:focus, .btn-default.active:hover, .btn-default:active.focus, .btn-default:active:focus, .btn-default:active:hover, .open > .dropdown-toggle.btn-default.focus, .open > .dropdown-toggle.btn-default:focus, .open > .dropdown-toggle.btn-default:hover { - color: #333; - background-color: #D4D4D4; - border-color: #8C8C8C -} - -.btn-default.active, .btn-default:active, .open > .dropdown-toggle.btn-default { - background-image: none -} - -.btn-default.disabled, .btn-default.disabled.active, .btn-default.disabled.focus, .btn-default.disabled:active, .btn-default.disabled:focus, .btn-default.disabled:hover, .btn-default[disabled], .btn-default[disabled].active, .btn-default[disabled].focus, .btn-default[disabled]:active, .btn-default[disabled]:focus, .btn-default[disabled]:hover, fieldset[disabled] .btn-default, fieldset[disabled] .btn-default.active, fieldset[disabled] .btn-default.focus, fieldset[disabled] .btn-default:active, fieldset[disabled] .btn-default:focus, fieldset[disabled] .btn-default:hover { - background-color: #FFF; - border-color: #CCC -} - -.btn-default .badge { - color: #FFF; - background-color: #333 -} - -.btn-primary { - color: #FFF; - background-color: #337AB7; - border-color: #2E6DA4 -} - -.btn-primary.focus, .btn-primary:focus { - color: #FFF; - background-color: #286090; - border-color: #122B40 -} - -.btn-primary:hover { - color: #FFF; - background-color: #286090; - border-color: #204D74 -} - -.btn-primary.active, .btn-primary:active, .open > .dropdown-toggle.btn-primary { - color: #FFF; - background-color: #286090; - border-color: #204D74 -} - -.btn-primary.active.focus, .btn-primary.active:focus, .btn-primary.active:hover, .btn-primary:active.focus, .btn-primary:active:focus, .btn-primary:active:hover, .open > .dropdown-toggle.btn-primary.focus, .open > .dropdown-toggle.btn-primary:focus, .open > .dropdown-toggle.btn-primary:hover { - color: #FFF; - background-color: #204D74; - border-color: #122B40 -} - -.btn-primary.active, .btn-primary:active, .open > .dropdown-toggle.btn-primary { - background-image: none -} - -.btn-primary.disabled, .btn-primary.disabled.active, .btn-primary.disabled.focus, .btn-primary.disabled:active, .btn-primary.disabled:focus, .btn-primary.disabled:hover, .btn-primary[disabled], .btn-primary[disabled].active, .btn-primary[disabled].focus, .btn-primary[disabled]:active, .btn-primary[disabled]:focus, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary, fieldset[disabled] .btn-primary.active, fieldset[disabled] .btn-primary.focus, fieldset[disabled] .btn-primary:active, fieldset[disabled] .btn-primary:focus, fieldset[disabled] .btn-primary:hover { - background-color: #337AB7; - border-color: #2E6DA4 -} - -.btn-primary .badge { - color: #337AB7; - background-color: #FFF -} - -.btn-success { - color: #FFF; - background-color: #5CB85C; - border-color: #4CAE4C -} - -.btn-success.focus, .btn-success:focus { - color: #FFF; - background-color: #449D44; - border-color: #255625 -} - -.btn-success:hover { - color: #FFF; - background-color: #449D44; - border-color: #398439 -} - -.btn-success.active, .btn-success:active, .open > .dropdown-toggle.btn-success { - color: #FFF; - background-color: #449D44; - border-color: #398439 -} - -.btn-success.active.focus, .btn-success.active:focus, .btn-success.active:hover, .btn-success:active.focus, .btn-success:active:focus, .btn-success:active:hover, .open > .dropdown-toggle.btn-success.focus, .open > .dropdown-toggle.btn-success:focus, .open > .dropdown-toggle.btn-success:hover { - color: #FFF; - background-color: #398439; - border-color: #255625 -} - -.btn-success.active, .btn-success:active, .open > .dropdown-toggle.btn-success { - background-image: none -} - -.btn-success.disabled, .btn-success.disabled.active, .btn-success.disabled.focus, .btn-success.disabled:active, .btn-success.disabled:focus, .btn-success.disabled:hover, .btn-success[disabled], .btn-success[disabled].active, .btn-success[disabled].focus, .btn-success[disabled]:active, .btn-success[disabled]:focus, .btn-success[disabled]:hover, fieldset[disabled] .btn-success, fieldset[disabled] .btn-success.active, fieldset[disabled] .btn-success.focus, fieldset[disabled] .btn-success:active, fieldset[disabled] .btn-success:focus, fieldset[disabled] .btn-success:hover { - background-color: #5CB85C; - border-color: #4CAE4C -} - -.btn-success .badge { - color: #5CB85C; - background-color: #FFF -} - -.btn-info { - color: #FFF; - background-color: #5BC0DE; - border-color: #46B8DA -} - -.btn-info.focus, .btn-info:focus { - color: #FFF; - background-color: #31B0D5; - border-color: #1B6D85 -} - -.btn-info:hover { - color: #FFF; - background-color: #31B0D5; - border-color: #269ABC -} - -.btn-info.active, .btn-info:active, .open > .dropdown-toggle.btn-info { - color: #FFF; - background-color: #31B0D5; - border-color: #269ABC -} - -.btn-info.active.focus, .btn-info.active:focus, .btn-info.active:hover, .btn-info:active.focus, .btn-info:active:focus, .btn-info:active:hover, .open > .dropdown-toggle.btn-info.focus, .open > .dropdown-toggle.btn-info:focus, .open > .dropdown-toggle.btn-info:hover { - color: #FFF; - background-color: #269ABC; - border-color: #1B6D85 -} - -.btn-info.active, .btn-info:active, .open > .dropdown-toggle.btn-info { - background-image: none -} - -.btn-info.disabled, .btn-info.disabled.active, .btn-info.disabled.focus, .btn-info.disabled:active, .btn-info.disabled:focus, .btn-info.disabled:hover, .btn-info[disabled], .btn-info[disabled].active, .btn-info[disabled].focus, .btn-info[disabled]:active, .btn-info[disabled]:focus, .btn-info[disabled]:hover, fieldset[disabled] .btn-info, fieldset[disabled] .btn-info.active, fieldset[disabled] .btn-info.focus, fieldset[disabled] .btn-info:active, fieldset[disabled] .btn-info:focus, fieldset[disabled] .btn-info:hover { - background-color: #5BC0DE; - border-color: #46B8DA -} - -.btn-info .badge { - color: #5BC0DE; - background-color: #FFF -} - -.btn-warning { - color: #FFF; - background-color: #F0AD4E; - border-color: #EEA236 -} - -.btn-warning.focus, .btn-warning:focus { - color: #FFF; - background-color: #EC971F; - border-color: #985F0D -} - -.btn-warning:hover { - color: #FFF; - background-color: #EC971F; - border-color: #D58512 -} - -.btn-warning.active, .btn-warning:active, .open > .dropdown-toggle.btn-warning { - color: #FFF; - background-color: #EC971F; - border-color: #D58512 -} - -.btn-warning.active.focus, .btn-warning.active:focus, .btn-warning.active:hover, .btn-warning:active.focus, .btn-warning:active:focus, .btn-warning:active:hover, .open > .dropdown-toggle.btn-warning.focus, .open > .dropdown-toggle.btn-warning:focus, .open > .dropdown-toggle.btn-warning:hover { - color: #FFF; - background-color: #D58512; - border-color: #985F0D -} - -.btn-warning.active, .btn-warning:active, .open > .dropdown-toggle.btn-warning { - background-image: none -} - -.btn-warning.disabled, .btn-warning.disabled.active, .btn-warning.disabled.focus, .btn-warning.disabled:active, .btn-warning.disabled:focus, .btn-warning.disabled:hover, .btn-warning[disabled], .btn-warning[disabled].active, .btn-warning[disabled].focus, .btn-warning[disabled]:active, .btn-warning[disabled]:focus, .btn-warning[disabled]:hover, fieldset[disabled] .btn-warning, fieldset[disabled] .btn-warning.active, fieldset[disabled] .btn-warning.focus, fieldset[disabled] .btn-warning:active, fieldset[disabled] .btn-warning:focus, fieldset[disabled] .btn-warning:hover { - background-color: #F0AD4E; - border-color: #EEA236 -} - -.btn-warning .badge { - color: #F0AD4E; - background-color: #FFF -} - -.btn-danger { - color: #FFF; - background-color: #D9534F; - border-color: #D43F3A -} - -.btn-danger.focus, .btn-danger:focus { - color: #FFF; - background-color: #C9302C; - border-color: #761C19 -} - -.btn-danger:hover { - color: #FFF; - background-color: #C9302C; - border-color: #AC2925 -} - -.btn-danger.active, .btn-danger:active, .open > .dropdown-toggle.btn-danger { - color: #FFF; - background-color: #C9302C; - border-color: #AC2925 -} - -.btn-danger.active.focus, .btn-danger.active:focus, .btn-danger.active:hover, .btn-danger:active.focus, .btn-danger:active:focus, .btn-danger:active:hover, .open > .dropdown-toggle.btn-danger.focus, .open > .dropdown-toggle.btn-danger:focus, .open > .dropdown-toggle.btn-danger:hover { - color: #FFF; - background-color: #AC2925; - border-color: #761C19 -} - -.btn-danger.active, .btn-danger:active, .open > .dropdown-toggle.btn-danger { - background-image: none -} - -.btn-danger.disabled, .btn-danger.disabled.active, .btn-danger.disabled.focus, .btn-danger.disabled:active, .btn-danger.disabled:focus, .btn-danger.disabled:hover, .btn-danger[disabled], .btn-danger[disabled].active, .btn-danger[disabled].focus, .btn-danger[disabled]:active, .btn-danger[disabled]:focus, .btn-danger[disabled]:hover, fieldset[disabled] .btn-danger, fieldset[disabled] .btn-danger.active, fieldset[disabled] .btn-danger.focus, fieldset[disabled] .btn-danger:active, fieldset[disabled] .btn-danger:focus, fieldset[disabled] .btn-danger:hover { - background-color: #D9534F; - border-color: #D43F3A -} - -.btn-danger .badge { - color: #D9534F; - background-color: #FFF -} - -.btn-link { - font-weight: 400; - color: #337AB7; - border-radius: 0 -} - -.btn-link, .btn-link.active, .btn-link:active, .btn-link[disabled], fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none -} - -.btn-link, .btn-link:active, .btn-link:focus, .btn-link:hover { - border-color: transparent -} - -.btn-link:focus, .btn-link:hover { - color: #23527C; - text-decoration: underline; - background-color: transparent -} - -.btn-link[disabled]:focus, .btn-link[disabled]:hover, fieldset[disabled] .btn-link:focus, fieldset[disabled] .btn-link:hover { - color: #777; - text-decoration: none -} - -.btn-group-lg > .btn, .btn-lg { - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px -} - -.btn-group-sm > .btn, .btn-sm { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -.btn-group-xs > .btn, .btn-xs { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -.btn-block { - display: block; - width: 100% -} - -.btn-block + .btn-block { - margin-top: 5px -} - -input[type=button].btn-block, input[type=reset].btn-block, input[type=submit].btn-block { - width: 100% -} - -.fade { - opacity: 0; - -webkit-transition: opacity .15s linear; - -o-transition: opacity .15s linear; - transition: opacity .15s linear -} - -.fade.in { - opacity: 1 -} - -.collapse { - display: none -} - -.collapse.in { - display: block -} - -tr.collapse.in { - display: table-row -} - -tbody.collapse.in { - display: table-row-group -} - -.collapsing { - position: relative; - height: 0; - overflow: hidden; - -webkit-transition-timing-function: ease; - -o-transition-timing-function: ease; - transition-timing-function: ease; - -webkit-transition-duration: .35s; - -o-transition-duration: .35s; - transition-duration: .35s; - -webkit-transition-property: height, visibility; - -o-transition-property: height, visibility; - transition-property: height, visibility -} - -.caret { - display: inline-block; - width: 0; - height: 0; - margin-left: 2px; - vertical-align: middle; - border-top: 4px dashed; - border-top: 4px solid \9; - border-right: 4px solid transparent; - border-left: 4px solid transparent -} - -.dropdown, .dropup { - position: relative -} - -.dropdown-toggle:focus { - outline: 0 -} - -.dropdown-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - min-width: 160px; - padding: 5px 0; - margin: 2px 0 0; - font-size: 14px; - text-align: left; - list-style: none; - background-color: #FFF; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #CCC; - border: 1px solid rgba(0, 0, 0, .15); - border-radius: 4px; - -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); - box-shadow: 0 6px 12px rgba(0, 0, 0, .175) -} - -.dropdown-menu.pull-right { - right: 0; - left: auto -} - -.dropdown-menu .divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #E5E5E5 -} - -.dropdown-menu > li > a { - display: block; - padding: 3px 20px; - clear: both; - font-weight: 400; - line-height: 1.42857143; - color: #333; - white-space: nowrap -} - -.dropdown-menu > li > a:focus, .dropdown-menu > li > a:hover { - color: #262626; - text-decoration: none; - background-color: #F5F5F5 -} - -.dropdown-menu > .active > a, .dropdown-menu > .active > a:focus, .dropdown-menu > .active > a:hover { - color: #FFF; - text-decoration: none; - background-color: #337AB7; - outline: 0 -} - -.dropdown-menu > .disabled > a, .dropdown-menu > .disabled > a:focus, .dropdown-menu > .disabled > a:hover { - color: #777 -} - -.dropdown-menu > .disabled > a:focus, .dropdown-menu > .disabled > a:hover { - text-decoration: none; - cursor: not-allowed; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false) -} - -.open > .dropdown-menu { - display: block -} - -.open > a { - outline: 0 -} - -.dropdown-menu-right { - right: 0; - left: auto -} - -.dropdown-menu-left { - right: auto; - left: 0 -} - -.dropdown-header { - display: block; - padding: 3px 20px; - font-size: 12px; - line-height: 1.42857143; - color: #777; - white-space: nowrap -} - -.dropdown-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 990 -} - -.pull-right > .dropdown-menu { - right: 0; - left: auto -} - -.dropup .caret, .navbar-fixed-bottom .dropdown .caret { - content: ""; - border-top: 0; - border-bottom: 4px dashed; - border-bottom: 4px solid \9 -} - -.dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { - top: auto; - bottom: 100%; - margin-bottom: 2px -} - -@media (min-width: 768px) { - .navbar-right .dropdown-menu { - right: 0; - left: auto - } - - .navbar-right .dropdown-menu-left { - right: auto; - left: 0 - } -} - -.btn-group, .btn-group-vertical { - position: relative; - display: inline-block; - vertical-align: middle -} - -.btn-group-vertical > .btn, .btn-group > .btn { - position: relative; - float: left -} - -.btn-group-vertical > .btn.active, .btn-group-vertical > .btn:active, .btn-group-vertical > .btn:focus, .btn-group-vertical > .btn:hover, .btn-group > .btn.active, .btn-group > .btn:active, .btn-group > .btn:focus, .btn-group > .btn:hover { - z-index: 2 -} - -.btn-group .btn + .btn, .btn-group .btn + .btn-group, .btn-group .btn-group + .btn, .btn-group .btn-group + .btn-group { - margin-left: -1px -} - -.btn-toolbar { - margin-left: -5px -} - -.btn-toolbar .btn, .btn-toolbar .btn-group, .btn-toolbar .input-group { - float: left -} - -.btn-toolbar > .btn, .btn-toolbar > .btn-group, .btn-toolbar > .input-group { - margin-left: 5px -} - -.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { - border-radius: 0 -} - -.btn-group > .btn:first-child { - margin-left: 0 -} - -.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.btn-group > .btn:last-child:not(:first-child), .btn-group > .dropdown-toggle:not(:first-child) { - border-top-left-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group > .btn-group { - float: left -} - -.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0 -} - -.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, .btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { - outline: 0 -} - -.btn-group > .btn + .dropdown-toggle { - padding-right: 8px; - padding-left: 8px -} - -.btn-group > .btn-lg + .dropdown-toggle { - padding-right: 12px; - padding-left: 12px -} - -.btn-group.open .dropdown-toggle { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125) -} - -.btn-group.open .dropdown-toggle.btn-link { - -webkit-box-shadow: none; - box-shadow: none -} - -.btn .caret { - margin-left: 0 -} - -.btn-lg .caret { - border-width: 5px 5px 0; - border-bottom-width: 0 -} - -.dropup .btn-lg .caret { - border-width: 0 5px 5px -} - -.btn-group-vertical > .btn, .btn-group-vertical > .btn-group, .btn-group-vertical > .btn-group > .btn { - display: block; - float: none; - width: 100%; - max-width: 100% -} - -.btn-group-vertical > .btn-group > .btn { - float: none -} - -.btn-group-vertical > .btn + .btn, .btn-group-vertical > .btn + .btn-group, .btn-group-vertical > .btn-group + .btn, .btn-group-vertical > .btn-group + .btn-group { - margin-top: -1px; - margin-left: 0 -} - -.btn-group-vertical > .btn:not(:first-child):not(:last-child) { - border-radius: 0 -} - -.btn-group-vertical > .btn:first-child:not(:last-child) { - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group-vertical > .btn:last-child:not(:first-child) { - border-top-left-radius: 0; - border-top-right-radius: 0; - border-bottom-left-radius: 4px -} - -.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0 -} - -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, .btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.btn-group-justified { - display: table; - width: 100%; - table-layout: fixed; - border-collapse: separate -} - -.btn-group-justified > .btn, .btn-group-justified > .btn-group { - display: table-cell; - float: none; - width: 1% -} - -.btn-group-justified > .btn-group .btn { - width: 100% -} - -.btn-group-justified > .btn-group .dropdown-menu { - left: auto -} - -[data-toggle=buttons] > .btn input[type=checkbox], [data-toggle=buttons] > .btn input[type=radio], [data-toggle=buttons] > .btn-group > .btn input[type=checkbox], [data-toggle=buttons] > .btn-group > .btn input[type=radio] { - position: absolute; - clip: rect(0, 0, 0, 0); - pointer-events: none -} - -.input-group { - position: relative; - display: table; - border-collapse: separate -} - -.input-group[class*=col-] { - float: none; - padding-right: 0; - padding-left: 0 -} - -.input-group .form-control { - position: relative; - z-index: 2; - float: left; - width: 100%; - margin-bottom: 0 -} - -.input-group-lg > .form-control, .input-group-lg > .input-group-addon, .input-group-lg > .input-group-btn > .btn { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px -} - -select.input-group-lg > .form-control, select.input-group-lg > .input-group-addon, select.input-group-lg > .input-group-btn > .btn { - height: 46px; - line-height: 46px -} - -select[multiple].input-group-lg > .form-control, select[multiple].input-group-lg > .input-group-addon, select[multiple].input-group-lg > .input-group-btn > .btn, textarea.input-group-lg > .form-control, textarea.input-group-lg > .input-group-addon, textarea.input-group-lg > .input-group-btn > .btn { - height: auto -} - -.input-group-sm > .form-control, .input-group-sm > .input-group-addon, .input-group-sm > .input-group-btn > .btn { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -select.input-group-sm > .form-control, select.input-group-sm > .input-group-addon, select.input-group-sm > .input-group-btn > .btn { - height: 30px; - line-height: 30px -} - -select[multiple].input-group-sm > .form-control, select[multiple].input-group-sm > .input-group-addon, select[multiple].input-group-sm > .input-group-btn > .btn, textarea.input-group-sm > .form-control, textarea.input-group-sm > .input-group-addon, textarea.input-group-sm > .input-group-btn > .btn { - height: auto -} - -.input-group .form-control, .input-group-addon, .input-group-btn { - display: table-cell -} - -.input-group .form-control:not(:first-child):not(:last-child), .input-group-addon:not(:first-child):not(:last-child), .input-group-btn:not(:first-child):not(:last-child) { - border-radius: 0 -} - -.input-group-addon, .input-group-btn { - width: 1%; - white-space: nowrap; - vertical-align: middle -} - -.input-group-addon { - padding: 6px 12px; - font-size: 14px; - font-weight: 400; - line-height: 1; - color: #555; - text-align: center; - background-color: #EEE; - border: 1px solid #CCC; - border-radius: 4px -} - -.input-group-addon.input-sm { - padding: 5px 10px; - font-size: 12px; - border-radius: 3px -} - -.input-group-addon.input-lg { - padding: 10px 16px; - font-size: 18px; - border-radius: 6px -} - -.input-group-addon input[type=checkbox], .input-group-addon input[type=radio] { - margin-top: 0 -} - -.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child > .btn, .input-group-btn:first-child > .btn-group > .btn, .input-group-btn:first-child > .dropdown-toggle, .input-group-btn:last-child > .btn-group:not(:last-child) > .btn, .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.input-group-addon:first-child { - border-right: 0 -} - -.input-group .form-control:last-child, .input-group-addon:last-child, .input-group-btn:first-child > .btn-group:not(:first-child) > .btn, .input-group-btn:first-child > .btn:not(:first-child), .input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group > .btn, .input-group-btn:last-child > .dropdown-toggle { - border-top-left-radius: 0; - border-bottom-left-radius: 0 -} - -.input-group-addon:last-child { - border-left: 0 -} - -.input-group-btn { - position: relative; - font-size: 0; - white-space: nowrap -} - -.input-group-btn > .btn { - position: relative -} - -.input-group-btn > .btn + .btn { - margin-left: -1px -} - -.input-group-btn > .btn:active, .input-group-btn > .btn:focus, .input-group-btn > .btn:hover { - z-index: 2 -} - -.input-group-btn:first-child > .btn, .input-group-btn:first-child > .btn-group { - margin-right: -1px -} - -.input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group { - z-index: 2; - margin-left: -1px -} - -.nav { - padding-left: 0; - margin-bottom: 0; - list-style: none -} - -.nav > li { - position: relative; - display: block -} - -.nav > li > a { - position: relative; - display: block; - padding: 10px 15px -} - -.nav > li > a:focus, .nav > li > a:hover { - text-decoration: none; - background-color: #EEE -} - -.nav > li.disabled > a { - color: #777 -} - -.nav > li.disabled > a:focus, .nav > li.disabled > a:hover { - color: #777; - text-decoration: none; - cursor: not-allowed; - background-color: transparent -} - -.nav .open > a, .nav .open > a:focus, .nav .open > a:hover { - background-color: #EEE; - border-color: #337AB7 -} - -.nav .nav-divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #E5E5E5 -} - -.nav > li > a > img { - max-width: none -} - -.nav-tabs { - border-bottom: 1px solid #DDD -} - -.nav-tabs > li { - float: left; - margin-bottom: -1px -} - -.nav-tabs > li > a { - margin-right: 2px; - line-height: 1.42857143; - border: 1px solid transparent; - border-radius: 4px 4px 0 0 -} - -.nav-tabs > li > a:hover { - border-color: #EEE #EEE #DDD -} - -.nav-tabs > li.active > a, .nav-tabs > li.active > a:focus, .nav-tabs > li.active > a:hover { - color: #555; - cursor: default; - background-color: #FFF; - border: 1px solid #DDD; - border-bottom-color: transparent -} - -.nav-tabs.nav-justified { - width: 100%; - border-bottom: 0 -} - -.nav-tabs.nav-justified > li { - float: none -} - -.nav-tabs.nav-justified > li > a { - margin-bottom: 5px; - text-align: center -} - -.nav-tabs.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto -} - -@media (min-width: 768px) { - .nav-tabs.nav-justified > li { - display: table-cell; - width: 1% - } - - .nav-tabs.nav-justified > li > a { - margin-bottom: 0 - } -} - -.nav-tabs.nav-justified > li > a { - margin-right: 0; - border-radius: 4px -} - -.nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:focus, .nav-tabs.nav-justified > .active > a:hover { - border: 1px solid #DDD -} - -@media (min-width: 768px) { - .nav-tabs.nav-justified > li > a { - border-bottom: 1px solid #DDD; - border-radius: 4px 4px 0 0 - } - - .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:focus, .nav-tabs.nav-justified > .active > a:hover { - border-bottom-color: #FFF - } -} - -.nav-pills > li { - float: left -} - -.nav-pills > li > a { - border-radius: 4px -} - -.nav-pills > li + li { - margin-left: 2px -} - -.nav-pills > li.active > a, .nav-pills > li.active > a:focus, .nav-pills > li.active > a:hover { - color: #FFF; - background-color: #337AB7 -} - -.nav-stacked > li { - float: none -} - -.nav-stacked > li + li { - margin-top: 2px; - margin-left: 0 -} - -.nav-justified { - width: 100% -} - -.nav-justified > li { - float: none -} - -.nav-justified > li > a { - margin-bottom: 5px; - text-align: center -} - -.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto -} - -@media (min-width: 768px) { - .nav-justified > li { - display: table-cell; - width: 1% - } - - .nav-justified > li > a { - margin-bottom: 0 - } -} - -.nav-tabs-justified { - border-bottom: 0 -} - -.nav-tabs-justified > li > a { - margin-right: 0; - border-radius: 4px -} - -.nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:focus, .nav-tabs-justified > .active > a:hover { - border: 1px solid #DDD -} - -@media (min-width: 768px) { - .nav-tabs-justified > li > a { - border-bottom: 1px solid #DDD; - border-radius: 4px 4px 0 0 - } - - .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:focus, .nav-tabs-justified > .active > a:hover { - border-bottom-color: #FFF - } -} - -.tab-content > .tab-pane { - display: none -} - -.tab-content > .active { - display: block -} - -.nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.navbar { - position: relative; - min-height: 50px; - margin-bottom: 20px; - border: 1px solid transparent -} - -@media (min-width: 768px) { - .navbar { - border-radius: 4px - } -} - -@media (min-width: 768px) { - .navbar-header { - float: left - } -} - -.navbar-collapse { - padding-right: 15px; - padding-left: 15px; - overflow-x: visible; - -webkit-overflow-scrolling: touch; - border-top: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1) -} - -.navbar-collapse.in { - overflow-y: auto -} - -@media (min-width: 768px) { - .navbar-collapse { - width: auto; - border-top: 0; - -webkit-box-shadow: none; - box-shadow: none - } - - .navbar-collapse.collapse { - display: block !important; - height: auto !important; - padding-bottom: 0; - overflow: visible !important - } - - .navbar-collapse.in { - overflow-y: visible - } - - .navbar-fixed-bottom .navbar-collapse, .navbar-fixed-top .navbar-collapse, .navbar-static-top .navbar-collapse { - padding-right: 0; - padding-left: 0 - } -} - -.navbar-fixed-bottom .navbar-collapse, .navbar-fixed-top .navbar-collapse { - max-height: 340px -} - -@media (max-device-width: 480px) and (orientation: landscape) { - .navbar-fixed-bottom .navbar-collapse, .navbar-fixed-top .navbar-collapse { - max-height: 200px - } -} - -.container-fluid > .navbar-collapse, .container-fluid > .navbar-header, .container > .navbar-collapse, .container > .navbar-header { - margin-right: -15px; - margin-left: -15px -} - -@media (min-width: 768px) { - .container-fluid > .navbar-collapse, .container-fluid > .navbar-header, .container > .navbar-collapse, .container > .navbar-header { - margin-right: 0; - margin-left: 0 - } -} - -.navbar-static-top { - z-index: 1000; - border-width: 0 0 1px -} - -@media (min-width: 768px) { - .navbar-static-top { - border-radius: 0 - } -} - -.navbar-fixed-bottom, .navbar-fixed-top { - position: fixed; - right: 0; - left: 0; - z-index: 1030 -} - -@media (min-width: 768px) { - .navbar-fixed-bottom, .navbar-fixed-top { - border-radius: 0 - } -} - -.navbar-fixed-top { - top: 0; - border-width: 0 0 1px -} - -.navbar-fixed-bottom { - bottom: 0; - margin-bottom: 0; - border-width: 1px 0 0 -} - -.navbar-brand { - float: left; - height: 50px; - padding: 15px 15px; - font-size: 18px; - line-height: 20px -} - -.navbar-brand:focus, .navbar-brand:hover { - text-decoration: none -} - -.navbar-brand > img { - display: block -} - -@media (min-width: 768px) { - .navbar > .container .navbar-brand, .navbar > .container-fluid .navbar-brand { - margin-left: -15px - } -} - -.navbar-toggle { - position: relative; - float: right; - padding: 9px 10px; - margin-top: 8px; - margin-right: 15px; - margin-bottom: 8px; - background-color: transparent; - background-image: none; - border: 1px solid transparent; - border-radius: 4px -} - -.navbar-toggle:focus { - outline: 0 -} - -.navbar-toggle .icon-bar { - display: block; - width: 22px; - height: 2px; - border-radius: 1px -} - -.navbar-toggle .icon-bar + .icon-bar { - margin-top: 4px -} - -@media (min-width: 768px) { - .navbar-toggle { - display: none - } -} - -.navbar-nav { - margin: 7.5px -15px -} - -.navbar-nav > li > a { - padding-top: 10px; - padding-bottom: 10px; - line-height: 20px -} - -@media (max-width: 767px) { - .navbar-nav .open .dropdown-menu { - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - -webkit-box-shadow: none; - box-shadow: none - } - - .navbar-nav .open .dropdown-menu .dropdown-header, .navbar-nav .open .dropdown-menu > li > a { - padding: 5px 15px 5px 25px - } - - .navbar-nav .open .dropdown-menu > li > a { - line-height: 20px - } - - .navbar-nav .open .dropdown-menu > li > a:focus, .navbar-nav .open .dropdown-menu > li > a:hover { - background-image: none - } -} - -@media (min-width: 768px) { - .navbar-nav { - float: left; - margin: 0 - } - - .navbar-nav > li { - float: left - } - - .navbar-nav > li > a { - padding-top: 15px; - padding-bottom: 15px - } -} - -.navbar-form { - padding: 10px 15px; - margin-top: 8px; - margin-right: -15px; - margin-bottom: 8px; - margin-left: -15px; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1) -} - -@media (min-width: 768px) { - .navbar-form .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle - } - - .navbar-form .form-control { - display: inline-block; - width: auto; - vertical-align: middle - } - - .navbar-form .form-control-static { - display: inline-block - } - - .navbar-form .input-group { - display: inline-table; - vertical-align: middle - } - - .navbar-form .input-group .form-control, .navbar-form .input-group .input-group-addon, .navbar-form .input-group .input-group-btn { - width: auto - } - - .navbar-form .input-group > .form-control { - width: 100% - } - - .navbar-form .control-label { - margin-bottom: 0; - vertical-align: middle - } - - .navbar-form .checkbox, .navbar-form .radio { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle - } - - .navbar-form .checkbox label, .navbar-form .radio label { - padding-left: 0 - } - - .navbar-form .checkbox input[type=checkbox], .navbar-form .radio input[type=radio] { - position: relative; - margin-left: 0 - } - - .navbar-form .has-feedback .form-control-feedback { - top: 0 - } -} - -@media (max-width: 767px) { - .navbar-form .form-group { - margin-bottom: 5px - } - - .navbar-form .form-group:last-child { - margin-bottom: 0 - } -} - -@media (min-width: 768px) { - .navbar-form { - width: auto; - padding-top: 0; - padding-bottom: 0; - margin-right: 0; - margin-left: 0; - border: 0; - -webkit-box-shadow: none; - box-shadow: none - } -} - -.navbar-nav > li > .dropdown-menu { - margin-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { - margin-bottom: 0; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.navbar-btn { - margin-top: 8px; - margin-bottom: 8px -} - -.navbar-btn.btn-sm { - margin-top: 10px; - margin-bottom: 10px -} - -.navbar-btn.btn-xs { - margin-top: 14px; - margin-bottom: 14px -} - -.navbar-text { - margin-top: 15px; - margin-bottom: 15px -} - -@media (min-width: 768px) { - .navbar-text { - float: left; - margin-right: 15px; - margin-left: 15px - } -} - -@media (min-width: 768px) { - .navbar-left { - float: left !important - } - - .navbar-right { - float: right !important; - margin-right: -15px - } - - .navbar-right ~ .navbar-right { - margin-right: 0 - } -} - -.navbar-default { - background-color: #F8F8F8; - border-color: #E7E7E7 -} - -.navbar-default .navbar-brand { - color: #777 -} - -.navbar-default .navbar-brand:focus, .navbar-default .navbar-brand:hover { - color: #5E5E5E; - background-color: transparent -} - -.navbar-default .navbar-text { - color: #777 -} - -.navbar-default .navbar-nav > li > a { - color: #777 -} - -.navbar-default .navbar-nav > li > a:focus, .navbar-default .navbar-nav > li > a:hover { - color: #333; - background-color: transparent -} - -.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:focus, .navbar-default .navbar-nav > .active > a:hover { - color: #555; - background-color: #E7E7E7 -} - -.navbar-default .navbar-nav > .disabled > a, .navbar-default .navbar-nav > .disabled > a:focus, .navbar-default .navbar-nav > .disabled > a:hover { - color: #CCC; - background-color: transparent -} - -.navbar-default .navbar-toggle { - border-color: #DDD -} - -.navbar-default .navbar-toggle:focus, .navbar-default .navbar-toggle:hover { - background-color: #DDD -} - -.navbar-default .navbar-toggle .icon-bar { - background-color: #888 -} - -.navbar-default .navbar-collapse, .navbar-default .navbar-form { - border-color: #E7E7E7 -} - -.navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:focus, .navbar-default .navbar-nav > .open > a:hover { - color: #555; - background-color: #E7E7E7 -} - -@media (max-width: 767px) { - .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #777 - } - - .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus, .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover { - color: #333; - background-color: transparent - } - - .navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover { - color: #555; - background-color: #E7E7E7 - } - - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover { - color: #CCC; - background-color: transparent - } -} - -.navbar-default .navbar-link { - color: #777 -} - -.navbar-default .navbar-link:hover { - color: #333 -} - -.navbar-default .btn-link { - color: #777 -} - -.navbar-default .btn-link:focus, .navbar-default .btn-link:hover { - color: #333 -} - -.navbar-default .btn-link[disabled]:focus, .navbar-default .btn-link[disabled]:hover, fieldset[disabled] .navbar-default .btn-link:focus, fieldset[disabled] .navbar-default .btn-link:hover { - color: #CCC -} - -.navbar-inverse { - background-color: #222; - border-color: #080808 -} - -.navbar-inverse .navbar-brand { - color: #9D9D9D -} - -.navbar-inverse .navbar-brand:focus, .navbar-inverse .navbar-brand:hover { - color: #FFF; - background-color: transparent -} - -.navbar-inverse .navbar-text { - color: #9D9D9D -} - -.navbar-inverse .navbar-nav > li > a { - color: #9D9D9D -} - -.navbar-inverse .navbar-nav > li > a:focus, .navbar-inverse .navbar-nav > li > a:hover { - color: #FFF; - background-color: transparent -} - -.navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:focus, .navbar-inverse .navbar-nav > .active > a:hover { - color: #FFF; - background-color: #080808 -} - -.navbar-inverse .navbar-nav > .disabled > a, .navbar-inverse .navbar-nav > .disabled > a:focus, .navbar-inverse .navbar-nav > .disabled > a:hover { - color: #444; - background-color: transparent -} - -.navbar-inverse .navbar-toggle { - border-color: #333 -} - -.navbar-inverse .navbar-toggle:focus, .navbar-inverse .navbar-toggle:hover { - background-color: #333 -} - -.navbar-inverse .navbar-toggle .icon-bar { - background-color: #FFF -} - -.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form { - border-color: #101010 -} - -.navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:focus, .navbar-inverse .navbar-nav > .open > a:hover { - color: #FFF; - background-color: #080808 -} - -@media (max-width: 767px) { - .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { - border-color: #080808 - } - - .navbar-inverse .navbar-nav .open .dropdown-menu .divider { - background-color: #080808 - } - - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { - color: #9D9D9D - } - - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus, .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover { - color: #FFF; - background-color: transparent - } - - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover { - color: #FFF; - background-color: #080808 - } - - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover { - color: #444; - background-color: transparent - } -} - -.navbar-inverse .navbar-link { - color: #9D9D9D -} - -.navbar-inverse .navbar-link:hover { - color: #FFF -} - -.navbar-inverse .btn-link { - color: #9D9D9D -} - -.navbar-inverse .btn-link:focus, .navbar-inverse .btn-link:hover { - color: #FFF -} - -.navbar-inverse .btn-link[disabled]:focus, .navbar-inverse .btn-link[disabled]:hover, fieldset[disabled] .navbar-inverse .btn-link:focus, fieldset[disabled] .navbar-inverse .btn-link:hover { - color: #444 -} - -.breadcrumb { - padding: 8px 15px; - margin-bottom: 20px; - list-style: none; - background-color: #F5F5F5; - border-radius: 4px -} - -.breadcrumb > li { - display: inline-block -} - -.breadcrumb > li + li:before { - padding: 0 5px; - color: #CCC; - content: "/\00a0" -} - -.breadcrumb > .active { - color: #777 -} - -.pagination { - display: inline-block; - padding-left: 0; - margin: 20px 0; - border-radius: 4px -} - -.pagination > li { - display: inline -} - -.pagination > li > a, .pagination > li > span { - position: relative; - float: left; - padding: 6px 12px; - margin-left: -1px; - line-height: 1.42857143; - color: #337AB7; - text-decoration: none; - background-color: #FFF; - border: 1px solid #DDD -} - -.pagination > li:first-child > a, .pagination > li:first-child > span { - margin-left: 0; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px -} - -.pagination > li:last-child > a, .pagination > li:last-child > span { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px -} - -.pagination > li > a:focus, .pagination > li > a:hover, .pagination > li > span:focus, .pagination > li > span:hover { - z-index: 3; - color: #23527C; - background-color: #EEE; - border-color: #DDD -} - -.pagination > .active > a, .pagination > .active > a:focus, .pagination > .active > a:hover, .pagination > .active > span, .pagination > .active > span:focus, .pagination > .active > span:hover { - z-index: 2; - color: #FFF; - cursor: default; - background-color: #337AB7; - border-color: #337AB7 -} - -.pagination > .disabled > a, .pagination > .disabled > a:focus, .pagination > .disabled > a:hover, .pagination > .disabled > span, .pagination > .disabled > span:focus, .pagination > .disabled > span:hover { - color: #777; - cursor: not-allowed; - background-color: #FFF; - border-color: #DDD -} - -.pagination-lg > li > a, .pagination-lg > li > span { - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333 -} - -.pagination-lg > li:first-child > a, .pagination-lg > li:first-child > span { - border-top-left-radius: 6px; - border-bottom-left-radius: 6px -} - -.pagination-lg > li:last-child > a, .pagination-lg > li:last-child > span { - border-top-right-radius: 6px; - border-bottom-right-radius: 6px -} - -.pagination-sm > li > a, .pagination-sm > li > span { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5 -} - -.pagination-sm > li:first-child > a, .pagination-sm > li:first-child > span { - border-top-left-radius: 3px; - border-bottom-left-radius: 3px -} - -.pagination-sm > li:last-child > a, .pagination-sm > li:last-child > span { - border-top-right-radius: 3px; - border-bottom-right-radius: 3px -} - -.pager { - padding-left: 0; - margin: 20px 0; - text-align: center; - list-style: none -} - -.pager li { - display: inline -} - -.pager li > a, .pager li > span { - display: inline-block; - padding: 5px 14px; - background-color: #FFF; - border: 1px solid #DDD; - border-radius: 15px -} - -.pager li > a:focus, .pager li > a:hover { - text-decoration: none; - background-color: #EEE -} - -.pager .next > a, .pager .next > span { - float: right -} - -.pager .previous > a, .pager .previous > span { - float: left -} - -.pager .disabled > a, .pager .disabled > a:focus, .pager .disabled > a:hover, .pager .disabled > span { - color: #777; - cursor: not-allowed; - background-color: #FFF -} - -.label { - display: inline; - padding: .2em .6em .3em; - font-size: 75%; - font-weight: 700; - line-height: 1; - color: #FFF; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25em -} - -a.label:focus, a.label:hover { - color: #FFF; - text-decoration: none; - cursor: pointer -} - -.label:empty { - display: none -} - -.btn .label { - position: relative; - top: -1px -} - -.label-default { - background-color: #777 -} - -.label-default[href]:focus, .label-default[href]:hover { - background-color: #5E5E5E -} - -.label-primary { - background-color: #337AB7 -} - -.label-primary[href]:focus, .label-primary[href]:hover { - background-color: #286090 -} - -.label-success { - background-color: #5CB85C -} - -.label-success[href]:focus, .label-success[href]:hover { - background-color: #449D44 -} - -.label-info { - background-color: #5BC0DE -} - -.label-info[href]:focus, .label-info[href]:hover { - background-color: #31B0D5 -} - -.label-warning { - background-color: #F0AD4E -} - -.label-warning[href]:focus, .label-warning[href]:hover { - background-color: #EC971F -} - -.label-danger { - background-color: #D9534F -} - -.label-danger[href]:focus, .label-danger[href]:hover { - background-color: #C9302C -} - -.badge { - display: inline-block; - min-width: 10px; - padding: 3px 7px; - font-size: 12px; - font-weight: 700; - line-height: 1; - color: #FFF; - text-align: center; - white-space: nowrap; - vertical-align: middle; - background-color: #777; - border-radius: 10px -} - -.badge:empty { - display: none -} - -.btn .badge { - position: relative; - top: -1px -} - -.btn-group-xs > .btn .badge, .btn-xs .badge { - top: 0; - padding: 1px 5px -} - -a.badge:focus, a.badge:hover { - color: #FFF; - text-decoration: none; - cursor: pointer -} - -.list-group-item.active > .badge, .nav-pills > .active > a > .badge { - color: #337AB7; - background-color: #FFF -} - -.list-group-item > .badge { - float: right -} - -.list-group-item > .badge + .badge { - margin-right: 5px -} - -.nav-pills > li > a > .badge { - margin-left: 3px -} - -.jumbotron { - padding-top: 30px; - padding-bottom: 30px; - margin-bottom: 30px; - color: inherit; - background-color: #EEE -} - -.jumbotron .h1, .jumbotron h1 { - color: inherit -} - -.jumbotron p { - margin-bottom: 15px; - font-size: 21px; - font-weight: 200 -} - -.jumbotron > hr { - border-top-color: #D5D5D5 -} - -.container .jumbotron, .container-fluid .jumbotron { - border-radius: 6px -} - -.jumbotron .container { - max-width: 100% -} - -@media screen and (min-width: 768px) { - .jumbotron { - padding-top: 48px; - padding-bottom: 48px - } - - .container .jumbotron, .container-fluid .jumbotron { - padding-right: 60px; - padding-left: 60px - } - - .jumbotron .h1, .jumbotron h1 { - font-size: 63px - } -} - -.thumbnail { - display: block; - padding: 4px; - margin-bottom: 20px; - line-height: 1.42857143; - background-color: #FFF; - border: 1px solid #DDD; - border-radius: 4px; - -webkit-transition: border .2s ease-in-out; - -o-transition: border .2s ease-in-out; - transition: border .2s ease-in-out -} - -.thumbnail a > img, .thumbnail > img { - margin-right: auto; - margin-left: auto -} - -a.thumbnail.active, a.thumbnail:focus, a.thumbnail:hover { - border-color: #337AB7 -} - -.thumbnail .caption { - padding: 9px; - color: #333 -} - -.alert { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px -} - -.alert h4 { - margin-top: 0; - color: inherit -} - -.alert .alert-link { - font-weight: 700 -} - -.alert > p, .alert > ul { - margin-bottom: 0 -} - -.alert > p + p { - margin-top: 5px -} - -.alert-dismissable, .alert-dismissible { - padding-right: 35px -} - -.alert-dismissable .close, .alert-dismissible .close { - position: relative; - top: -2px; - right: -21px; - color: inherit -} - -.alert-success { - color: #3C763D; - background-color: #DFF0D8; - border-color: #D6E9C6 -} - -.alert-success hr { - border-top-color: #C9E2B3 -} - -.alert-success .alert-link { - color: #2B542C -} - -.alert-info { - color: #31708F; - background-color: #D9EDF7; - border-color: #BCE8F1 -} - -.alert-info hr { - border-top-color: #A6E1EC -} - -.alert-info .alert-link { - color: #245269 -} - -.alert-warning { - color: #8A6D3B; - background-color: #FCF8E3; - border-color: #FAEBCC -} - -.alert-warning hr { - border-top-color: #F7E1B5 -} - -.alert-warning .alert-link { - color: #66512C -} - -.alert-danger { - color: #A94442; - background-color: #F2DEDE; - border-color: #EBCCD1 -} - -.alert-danger hr { - border-top-color: #E4B9C0 -} - -.alert-danger .alert-link { - color: #843534 -} - -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 40px 0 - } - to { - background-position: 0 0 - } -} - -@-o-keyframes progress-bar-stripes { - from { - background-position: 40px 0 - } - to { - background-position: 0 0 - } -} - -@keyframes progress-bar-stripes { - from { - background-position: 40px 0 - } - to { - background-position: 0 0 - } -} - -.progress { - height: 20px; - margin-bottom: 20px; - overflow: hidden; - background-color: #F5F5F5; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1) -} - -.progress-bar { - float: left; - width: 0; - height: 100%; - font-size: 12px; - line-height: 20px; - color: #FFF; - text-align: center; - background-color: #337AB7; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); - -webkit-transition: width .6s ease; - -o-transition: width .6s ease; - transition: width .6s ease -} - -.progress-bar-striped, .progress-striped .progress-bar { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - -webkit-background-size: 40px 40px; - background-size: 40px 40px -} - -.progress-bar.active, .progress.active .progress-bar { - -webkit-animation: progress-bar-stripes 2s linear infinite; - -o-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite -} - -.progress-bar-success { - background-color: #5CB85C -} - -.progress-striped .progress-bar-success { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent) -} - -.progress-bar-info { - background-color: #5BC0DE -} - -.progress-striped .progress-bar-info { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent) -} - -.progress-bar-warning { - background-color: #F0AD4E -} - -.progress-striped .progress-bar-warning { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent) -} - -.progress-bar-danger { - background-color: #D9534F -} - -.progress-striped .progress-bar-danger { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent) -} - -.media { - margin-top: 15px -} - -.media:first-child { - margin-top: 0 -} - -.media, .media-body { - overflow: hidden; - zoom: 1 -} - -.media-body { - width: 10000px -} - -.media-object { - display: block -} - -.media-object.img-thumbnail { - max-width: none -} - -.media-right, .media > .pull-right { - padding-left: 10px -} - -.media-left, .media > .pull-left { - padding-right: 10px -} - -.media-body, .media-left, .media-right { - display: table-cell; - vertical-align: top -} - -.media-middle { - vertical-align: middle -} - -.media-bottom { - vertical-align: bottom -} - -.media-heading { - margin-top: 0; - margin-bottom: 5px -} - -.media-list { - padding-left: 0; - list-style: none -} - -.list-group { - padding-left: 0; - margin-bottom: 20px -} - -.list-group-item { - position: relative; - display: block; - padding: 10px 15px; - margin-bottom: -1px; - background-color: #FFF; - border: 1px solid #DDD -} - -.list-group-item:first-child { - border-top-left-radius: 4px; - border-top-right-radius: 4px -} - -.list-group-item:last-child { - margin-bottom: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px -} - -a.list-group-item, button.list-group-item { - color: #555 -} - -a.list-group-item .list-group-item-heading, button.list-group-item .list-group-item-heading { - color: #333 -} - -a.list-group-item:focus, a.list-group-item:hover, button.list-group-item:focus, button.list-group-item:hover { - color: #555; - text-decoration: none; - background-color: #F5F5F5 -} - -button.list-group-item { - width: 100%; - text-align: left -} - -.list-group-item.disabled, .list-group-item.disabled:focus, .list-group-item.disabled:hover { - color: #777; - cursor: not-allowed; - background-color: #EEE -} - -.list-group-item.disabled .list-group-item-heading, .list-group-item.disabled:focus .list-group-item-heading, .list-group-item.disabled:hover .list-group-item-heading { - color: inherit -} - -.list-group-item.disabled .list-group-item-text, .list-group-item.disabled:focus .list-group-item-text, .list-group-item.disabled:hover .list-group-item-text { - color: #777 -} - -.list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover { - z-index: 2; - color: #FFF; - background-color: #337AB7; - border-color: #337AB7 -} - -.list-group-item.active .list-group-item-heading, .list-group-item.active .list-group-item-heading > .small, .list-group-item.active .list-group-item-heading > small, .list-group-item.active:focus .list-group-item-heading, .list-group-item.active:focus .list-group-item-heading > .small, .list-group-item.active:focus .list-group-item-heading > small, .list-group-item.active:hover .list-group-item-heading, .list-group-item.active:hover .list-group-item-heading > .small, .list-group-item.active:hover .list-group-item-heading > small { - color: inherit -} - -.list-group-item.active .list-group-item-text, .list-group-item.active:focus .list-group-item-text, .list-group-item.active:hover .list-group-item-text { - color: #C7DDEF -} - -.list-group-item-success { - color: #3C763D; - background-color: #DFF0D8 -} - -a.list-group-item-success, button.list-group-item-success { - color: #3C763D -} - -a.list-group-item-success .list-group-item-heading, button.list-group-item-success .list-group-item-heading { - color: inherit -} - -a.list-group-item-success:focus, a.list-group-item-success:hover, button.list-group-item-success:focus, button.list-group-item-success:hover { - color: #3C763D; - background-color: #D0E9C6 -} - -a.list-group-item-success.active, a.list-group-item-success.active:focus, a.list-group-item-success.active:hover, button.list-group-item-success.active, button.list-group-item-success.active:focus, button.list-group-item-success.active:hover { - color: #FFF; - background-color: #3C763D; - border-color: #3C763D -} - -.list-group-item-info { - color: #31708F; - background-color: #D9EDF7 -} - -a.list-group-item-info, button.list-group-item-info { - color: #31708F -} - -a.list-group-item-info .list-group-item-heading, button.list-group-item-info .list-group-item-heading { - color: inherit -} - -a.list-group-item-info:focus, a.list-group-item-info:hover, button.list-group-item-info:focus, button.list-group-item-info:hover { - color: #31708F; - background-color: #C4E3F3 -} - -a.list-group-item-info.active, a.list-group-item-info.active:focus, a.list-group-item-info.active:hover, button.list-group-item-info.active, button.list-group-item-info.active:focus, button.list-group-item-info.active:hover { - color: #FFF; - background-color: #31708F; - border-color: #31708F -} - -.list-group-item-warning { - color: #8A6D3B; - background-color: #FCF8E3 -} - -a.list-group-item-warning, button.list-group-item-warning { - color: #8A6D3B -} - -a.list-group-item-warning .list-group-item-heading, button.list-group-item-warning .list-group-item-heading { - color: inherit -} - -a.list-group-item-warning:focus, a.list-group-item-warning:hover, button.list-group-item-warning:focus, button.list-group-item-warning:hover { - color: #8A6D3B; - background-color: #FAF2CC -} - -a.list-group-item-warning.active, a.list-group-item-warning.active:focus, a.list-group-item-warning.active:hover, button.list-group-item-warning.active, button.list-group-item-warning.active:focus, button.list-group-item-warning.active:hover { - color: #FFF; - background-color: #8A6D3B; - border-color: #8A6D3B -} - -.list-group-item-danger { - color: #A94442; - background-color: #F2DEDE -} - -a.list-group-item-danger, button.list-group-item-danger { - color: #A94442 -} - -a.list-group-item-danger .list-group-item-heading, button.list-group-item-danger .list-group-item-heading { - color: inherit -} - -a.list-group-item-danger:focus, a.list-group-item-danger:hover, button.list-group-item-danger:focus, button.list-group-item-danger:hover { - color: #A94442; - background-color: #EBCCCC -} - -a.list-group-item-danger.active, a.list-group-item-danger.active:focus, a.list-group-item-danger.active:hover, button.list-group-item-danger.active, button.list-group-item-danger.active:focus, button.list-group-item-danger.active:hover { - color: #FFF; - background-color: #A94442; - border-color: #A94442 -} - -.list-group-item-heading { - margin-top: 0; - margin-bottom: 5px -} - -.list-group-item-text { - margin-bottom: 0; - line-height: 1.3 -} - -.panel { - margin-bottom: 20px; - background-color: #FFF; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: 0 1px 1px rgba(0, 0, 0, .05) -} - -.panel-body { - padding: 15px -} - -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-left-radius: 3px; - border-top-right-radius: 3px -} - -.panel-heading > .dropdown .dropdown-toggle { - color: inherit -} - -.panel-title { - margin-top: 0; - margin-bottom: 0; - font-size: 16px; - color: inherit -} - -.panel-title > .small, .panel-title > .small > a, .panel-title > a, .panel-title > small, .panel-title > small > a { - color: inherit -} - -.panel-footer { - padding: 10px 15px; - background-color: #F5F5F5; - border-top: 1px solid #DDD; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel > .list-group, .panel > .panel-collapse > .list-group { - margin-bottom: 0 -} - -.panel > .list-group .list-group-item, .panel > .panel-collapse > .list-group .list-group-item { - border-width: 1px 0; - border-radius: 0 -} - -.panel > .list-group:first-child .list-group-item:first-child, .panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { - border-top: 0; - border-top-left-radius: 3px; - border-top-right-radius: 3px -} - -.panel > .list-group:last-child .list-group-item:last-child, .panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { - border-bottom: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.panel-heading + .list-group .list-group-item:first-child { - border-top-width: 0 -} - -.list-group + .panel-footer { - border-top-width: 0 -} - -.panel > .panel-collapse > .table, .panel > .table, .panel > .table-responsive > .table { - margin-bottom: 0 -} - -.panel > .panel-collapse > .table caption, .panel > .table caption, .panel > .table-responsive > .table caption { - padding-right: 15px; - padding-left: 15px -} - -.panel > .table-responsive:first-child > .table:first-child, .panel > .table:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px -} - -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child, .panel > .table:first-child > thead:first-child > tr:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px -} - -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, .panel > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table:first-child > thead:first-child > tr:first-child th:first-child { - border-top-left-radius: 3px -} - -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, .panel > .table:first-child > thead:first-child > tr:first-child td:last-child, .panel > .table:first-child > thead:first-child > tr:first-child th:last-child { - border-top-right-radius: 3px -} - -.panel > .table-responsive:last-child > .table:last-child, .panel > .table:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child, .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child { - border-bottom-left-radius: 3px -} - -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child { - border-bottom-right-radius: 3px -} - -.panel > .panel-body + .table, .panel > .panel-body + .table-responsive, .panel > .table + .panel-body, .panel > .table-responsive + .panel-body { - border-top: 1px solid #DDD -} - -.panel > .table > tbody:first-child > tr:first-child td, .panel > .table > tbody:first-child > tr:first-child th { - border-top: 0 -} - -.panel > .table-bordered, .panel > .table-responsive > .table-bordered { - border: 0 -} - -.panel > .table-bordered > tbody > tr > td:first-child, .panel > .table-bordered > tbody > tr > th:first-child, .panel > .table-bordered > tfoot > tr > td:first-child, .panel > .table-bordered > tfoot > tr > th:first-child, .panel > .table-bordered > thead > tr > td:first-child, .panel > .table-bordered > thead > tr > th:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, .panel > .table-responsive > .table-bordered > thead > tr > td:first-child, .panel > .table-responsive > .table-bordered > thead > tr > th:first-child { - border-left: 0 -} - -.panel > .table-bordered > tbody > tr > td:last-child, .panel > .table-bordered > tbody > tr > th:last-child, .panel > .table-bordered > tfoot > tr > td:last-child, .panel > .table-bordered > tfoot > tr > th:last-child, .panel > .table-bordered > thead > tr > td:last-child, .panel > .table-bordered > thead > tr > th:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, .panel > .table-responsive > .table-bordered > thead > tr > td:last-child, .panel > .table-responsive > .table-bordered > thead > tr > th:last-child { - border-right: 0 -} - -.panel > .table-bordered > tbody > tr:first-child > td, .panel > .table-bordered > tbody > tr:first-child > th, .panel > .table-bordered > thead > tr:first-child > td, .panel > .table-bordered > thead > tr:first-child > th, .panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:first-child > th, .panel > .table-responsive > .table-bordered > thead > tr:first-child > td, .panel > .table-responsive > .table-bordered > thead > tr:first-child > th { - border-bottom: 0 -} - -.panel > .table-bordered > tbody > tr:last-child > td, .panel > .table-bordered > tbody > tr:last-child > th, .panel > .table-bordered > tfoot > tr:last-child > td, .panel > .table-bordered > tfoot > tr:last-child > th, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { - border-bottom: 0 -} - -.panel > .table-responsive { - margin-bottom: 0; - border: 0 -} - -.panel-group { - margin-bottom: 20px -} - -.panel-group .panel { - margin-bottom: 0; - border-radius: 4px -} - -.panel-group .panel + .panel { - margin-top: 5px -} - -.panel-group .panel-heading { - border-bottom: 0 -} - -.panel-group .panel-heading + .panel-collapse > .list-group, .panel-group .panel-heading + .panel-collapse > .panel-body { - border-top: 1px solid #DDD -} - -.panel-group .panel-footer { - border-top: 0 -} - -.panel-group .panel-footer + .panel-collapse .panel-body { - border-bottom: 1px solid #DDD -} - -.panel-default { - border-color: #DDD -} - -.panel-default > .panel-heading { - color: #333; - background-color: #F5F5F5; - border-color: #DDD -} - -.panel-default > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #DDD -} - -.panel-default > .panel-heading .badge { - color: #F5F5F5; - background-color: #333 -} - -.panel-default > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #DDD -} - -.panel-primary { - border-color: #337AB7 -} - -.panel-primary > .panel-heading { - color: #FFF; - background-color: #337AB7; - border-color: #337AB7 -} - -.panel-primary > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #337AB7 -} - -.panel-primary > .panel-heading .badge { - color: #337AB7; - background-color: #FFF -} - -.panel-primary > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #337AB7 -} - -.panel-success { - border-color: #D6E9C6 -} - -.panel-success > .panel-heading { - color: #3C763D; - background-color: #DFF0D8; - border-color: #D6E9C6 -} - -.panel-success > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #D6E9C6 -} - -.panel-success > .panel-heading .badge { - color: #DFF0D8; - background-color: #3C763D -} - -.panel-success > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #D6E9C6 -} - -.panel-info { - border-color: #BCE8F1 -} - -.panel-info > .panel-heading { - color: #31708F; - background-color: #D9EDF7; - border-color: #BCE8F1 -} - -.panel-info > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #BCE8F1 -} - -.panel-info > .panel-heading .badge { - color: #D9EDF7; - background-color: #31708F -} - -.panel-info > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #BCE8F1 -} - -.panel-warning { - border-color: #FAEBCC -} - -.panel-warning > .panel-heading { - color: #8A6D3B; - background-color: #FCF8E3; - border-color: #FAEBCC -} - -.panel-warning > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #FAEBCC -} - -.panel-warning > .panel-heading .badge { - color: #FCF8E3; - background-color: #8A6D3B -} - -.panel-warning > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #FAEBCC -} - -.panel-danger { - border-color: #EBCCD1 -} - -.panel-danger > .panel-heading { - color: #A94442; - background-color: #F2DEDE; - border-color: #EBCCD1 -} - -.panel-danger > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #EBCCD1 -} - -.panel-danger > .panel-heading .badge { - color: #F2DEDE; - background-color: #A94442 -} - -.panel-danger > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #EBCCD1 -} - -.embed-responsive { - position: relative; - display: block; - height: 0; - padding: 0; - overflow: hidden -} - -.embed-responsive .embed-responsive-item, .embed-responsive embed, .embed-responsive iframe, .embed-responsive object, .embed-responsive video { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - border: 0 -} - -.embed-responsive-16by9 { - padding-bottom: 56.25% -} - -.embed-responsive-4by3 { - padding-bottom: 75% -} - -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #F5F5F5; - border: 1px solid #E3E3E3; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05) -} - -.well blockquote { - border-color: #DDD; - border-color: rgba(0, 0, 0, .15) -} - -.well-lg { - padding: 24px; - border-radius: 6px -} - -.well-sm { - padding: 9px; - border-radius: 3px -} - -.close { - float: right; - font-size: 21px; - font-weight: 700; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #FFF; - filter: alpha(opacity=20); - opacity: .2 -} - -.close:focus, .close:hover { - color: #000; - text-decoration: none; - cursor: pointer; - filter: alpha(opacity=50); - opacity: .5 -} - -button.close { - -webkit-appearance: none; - padding: 0; - cursor: pointer; - background: 0 0; - border: 0 -} - -.modal-open { - overflow: hidden -} - -.modal { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1050; - display: none; - overflow: hidden; - -webkit-overflow-scrolling: touch; - outline: 0 -} - -.modal.fade .modal-dialog { - -webkit-transition: -webkit-transform .3s ease-out; - -o-transition: -o-transform .3s ease-out; - transition: transform .3s ease-out; - -webkit-transform: translate(0, -25%); - -ms-transform: translate(0, -25%); - -o-transform: translate(0, -25%); - transform: translate(0, -25%) -} - -.modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - -o-transform: translate(0, 0); - transform: translate(0, 0) -} - -.modal-open .modal { - overflow-x: hidden; - overflow-y: auto -} - -.modal-dialog { - position: relative; - width: auto; - margin: 10px -} - -.modal-content { - position: relative; - background-color: #FFF; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #999; - border: 1px solid rgba(0, 0, 0, .2); - border-radius: 6px; - outline: 0; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); - box-shadow: 0 3px 9px rgba(0, 0, 0, .5) -} - -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - background-color: #000 -} - -.modal-backdrop.fade { - filter: alpha(opacity=0); - opacity: 0 -} - -.modal-backdrop.in { - filter: alpha(opacity=50); - opacity: .5 -} - -.modal-header { - min-height: 16.43px; - padding: 15px; - border-bottom: 1px solid #E5E5E5 -} - -.modal-header .close { - margin-top: -2px -} - -.modal-title { - margin: 0; - line-height: 1.42857143 -} - -.modal-body { - position: relative; - padding: 15px -} - -.modal-footer { - padding: 15px; - text-align: right; - border-top: 1px solid #E5E5E5 -} - -.modal-footer .btn + .btn { - margin-bottom: 0; - margin-left: 5px -} - -.modal-footer .btn-group .btn + .btn { - margin-left: -1px -} - -.modal-footer .btn-block + .btn-block { - margin-left: 0 -} - -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll -} - -@media (min-width: 768px) { - .modal-dialog { - width: 600px; - margin: 30px auto - } - - .modal-content { - -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); - box-shadow: 0 5px 15px rgba(0, 0, 0, .5) - } - - .modal-sm { - width: 300px - } -} - -@media (min-width: 992px) { - .modal-lg { - width: 900px - } -} - -.tooltip { - position: absolute; - z-index: 1070; - display: block; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 12px; - font-style: normal; - font-weight: 400; - line-height: 1.42857143; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; - white-space: normal; - filter: alpha(opacity=0); - opacity: 0; - line-break: auto -} - -.tooltip.in { - filter: alpha(opacity=90); - opacity: .9 -} - -.tooltip.top { - padding: 5px 0; - margin-top: -3px -} - -.tooltip.right { - padding: 0 5px; - margin-left: 3px -} - -.tooltip.bottom { - padding: 5px 0; - margin-top: 3px -} - -.tooltip.left { - padding: 0 5px; - margin-left: -3px -} - -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #FFF; - text-align: center; - background-color: #000; - border-radius: 4px -} - -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid -} - -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000 -} - -.tooltip.top-left .tooltip-arrow { - right: 5px; - bottom: 0; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000 -} - -.tooltip.top-right .tooltip-arrow { - bottom: 0; - left: 5px; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000 -} - -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000 -} - -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000 -} - -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000 -} - -.tooltip.bottom-left .tooltip-arrow { - top: 0; - right: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000 -} - -.tooltip.bottom-right .tooltip-arrow { - top: 0; - left: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000 -} - -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1060; - display: none; - max-width: 276px; - padding: 1px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 1.42857143; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; - white-space: normal; - background-color: #FFF; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #CCC; - border: 1px solid rgba(0, 0, 0, .2); - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); - box-shadow: 0 5px 10px rgba(0, 0, 0, .2); - line-break: auto -} - -.popover.top { - margin-top: -10px -} - -.popover.right { - margin-left: 10px -} - -.popover.bottom { - margin-top: 10px -} - -.popover.left { - margin-left: -10px -} - -.popover-title { - padding: 8px 14px; - margin: 0; - font-size: 14px; - background-color: #F7F7F7; - border-bottom: 1px solid #EBEBEB; - border-radius: 5px 5px 0 0 -} - -.popover-content { - padding: 9px 14px -} - -.popover > .arrow, .popover > .arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid -} - -.popover > .arrow { - border-width: 11px -} - -.popover > .arrow:after { - content: ""; - border-width: 10px -} - -.popover.top > .arrow { - bottom: -11px; - left: 50%; - margin-left: -11px; - border-top-color: #999; - border-top-color: rgba(0, 0, 0, .25); - border-bottom-width: 0 -} - -.popover.top > .arrow:after { - bottom: 1px; - margin-left: -10px; - content: " "; - border-top-color: #FFF; - border-bottom-width: 0 -} - -.popover.right > .arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-right-color: #999; - border-right-color: rgba(0, 0, 0, .25); - border-left-width: 0 -} - -.popover.right > .arrow:after { - bottom: -10px; - left: 1px; - content: " "; - border-right-color: #FFF; - border-left-width: 0 -} - -.popover.bottom > .arrow { - top: -11px; - left: 50%; - margin-left: -11px; - border-top-width: 0; - border-bottom-color: #999; - border-bottom-color: rgba(0, 0, 0, .25) -} - -.popover.bottom > .arrow:after { - top: 1px; - margin-left: -10px; - content: " "; - border-top-width: 0; - border-bottom-color: #FFF -} - -.popover.left > .arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-right-width: 0; - border-left-color: #999; - border-left-color: rgba(0, 0, 0, .25) -} - -.popover.left > .arrow:after { - right: 1px; - bottom: -10px; - content: " "; - border-right-width: 0; - border-left-color: #FFF -} - -.carousel { - position: relative -} - -.carousel-inner { - position: relative; - width: 100%; - overflow: hidden -} - -.carousel-inner > .item { - position: relative; - display: none; - -webkit-transition: .6s ease-in-out left; - -o-transition: .6s ease-in-out left; - transition: .6s ease-in-out left -} - -.carousel-inner > .item > a > img, .carousel-inner > .item > img { - line-height: 1 -} - -@media all and (transform-3d),(-webkit-transform-3d) { - .carousel-inner > .item { - -webkit-transition: -webkit-transform .6s ease-in-out; - -o-transition: -o-transform .6s ease-in-out; - transition: transform .6s ease-in-out; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-perspective: 1000px; - perspective: 1000px - } - - .carousel-inner > .item.active.right, .carousel-inner > .item.next { - left: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0) - } - - .carousel-inner > .item.active.left, .carousel-inner > .item.prev { - left: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0) - } - - .carousel-inner > .item.active, .carousel-inner > .item.next.left, .carousel-inner > .item.prev.right { - left: 0; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0) - } -} - -.carousel-inner > .active, .carousel-inner > .next, .carousel-inner > .prev { - display: block -} - -.carousel-inner > .active { - left: 0 -} - -.carousel-inner > .next, .carousel-inner > .prev { - position: absolute; - top: 0; - width: 100% -} - -.carousel-inner > .next { - left: 100% -} - -.carousel-inner > .prev { - left: -100% -} - -.carousel-inner > .next.left, .carousel-inner > .prev.right { - left: 0 -} - -.carousel-inner > .active.left { - left: -100% -} - -.carousel-inner > .active.right { - left: 100% -} - -.carousel-control { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 15%; - font-size: 20px; - color: #FFF; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, .6); - filter: alpha(opacity=50); - opacity: .5 -} - -.carousel-control.left { - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0, rgba(0, 0, 0, .0001) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0, rgba(0, 0, 0, .0001) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001))); - background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0, rgba(0, 0, 0, .0001) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); - background-repeat: repeat-x -} - -.carousel-control.right { - right: 0; - left: auto; - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0, rgba(0, 0, 0, .5) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0, rgba(0, 0, 0, .5) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5))); - background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0, rgba(0, 0, 0, .5) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); - background-repeat: repeat-x -} - -.carousel-control:focus, .carousel-control:hover { - color: #FFF; - text-decoration: none; - filter: alpha(opacity=90); - outline: 0; - opacity: .9 -} - -.carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next, .carousel-control .icon-prev { - position: absolute; - top: 50%; - z-index: 5; - display: inline-block; - margin-top: -10px -} - -.carousel-control .glyphicon-chevron-left, .carousel-control .icon-prev { - left: 50%; - margin-left: -10px -} - -.carousel-control .glyphicon-chevron-right, .carousel-control .icon-next { - right: 50%; - margin-right: -10px -} - -.carousel-control .icon-next, .carousel-control .icon-prev { - width: 20px; - height: 20px; - font-family: serif; - line-height: 1 -} - -.carousel-control .icon-prev:before { - content: '\2039' -} - -.carousel-control .icon-next:before { - content: '\203a' -} - -.carousel-indicators { - position: absolute; - bottom: 10px; - left: 50%; - z-index: 15; - width: 60%; - padding-left: 0; - margin-left: -30%; - text-align: center; - list-style: none -} - -.carousel-indicators li { - display: inline-block; - width: 10px; - height: 10px; - margin: 1px; - text-indent: -999px; - cursor: pointer; - background-color: #000 \9; - background-color: rgba(0, 0, 0, 0); - border: 1px solid #FFF; - border-radius: 10px -} - -.carousel-indicators .active { - width: 12px; - height: 12px; - margin: 0; - background-color: #FFF -} - -.carousel-caption { - position: absolute; - right: 15%; - bottom: 20px; - left: 15%; - z-index: 10; - padding-top: 20px; - padding-bottom: 20px; - color: #FFF; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, .6) -} - -.carousel-caption .btn { - text-shadow: none -} - -@media screen and (min-width: 768px) { - .carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next, .carousel-control .icon-prev { - width: 30px; - height: 30px; - margin-top: -15px; - font-size: 30px - } - - .carousel-control .glyphicon-chevron-left, .carousel-control .icon-prev { - margin-left: -15px - } - - .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next { - margin-right: -15px - } - - .carousel-caption { - right: 20%; - left: 20%; - padding-bottom: 30px - } - - .carousel-indicators { - bottom: 20px - } -} - -.btn-group-vertical > .btn-group:after, .btn-group-vertical > .btn-group:before, .btn-toolbar:after, .btn-toolbar:before, .clearfix:after, .clearfix:before, .container-fluid:after, .container-fluid:before, .container:after, .container:before, .dl-horizontal dd:after, .dl-horizontal dd:before, .form-horizontal .form-group:after, .form-horizontal .form-group:before, .modal-footer:after, .modal-footer:before, .nav:after, .nav:before, .navbar-collapse:after, .navbar-collapse:before, .navbar-header:after, .navbar-header:before, .navbar:after, .navbar:before, .pager:after, .pager:before, .panel-body:after, .panel-body:before, .row:after, .row:before { - display: table; - content: " " -} - -.btn-group-vertical > .btn-group:after, .btn-toolbar:after, .clearfix:after, .container-fluid:after, .container:after, .dl-horizontal dd:after, .form-horizontal .form-group:after, .modal-footer:after, .nav:after, .navbar-collapse:after, .navbar-header:after, .navbar:after, .pager:after, .panel-body:after, .row:after { - clear: both -} - -.center-block { - display: block; - margin-right: auto; - margin-left: auto -} - -.pull-right { - float: right !important -} - -.pull-left { - float: left !important -} - -.hide { - display: none !important -} - -.show { - display: block !important -} - -.invisible { - visibility: hidden -} - -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0 -} - -.hidden { - display: none !important -} - -.affix { - position: fixed -} - -@-ms-viewport { - width: device-width -} - -.visible-lg, .visible-md, .visible-sm, .visible-xs { - display: none !important -} - -.visible-lg-block, .visible-lg-inline, .visible-lg-inline-block, .visible-md-block, .visible-md-inline, .visible-md-inline-block, .visible-sm-block, .visible-sm-inline, .visible-sm-inline-block, .visible-xs-block, .visible-xs-inline, .visible-xs-inline-block { - display: none !important -} - -@media (max-width: 767px) { - .visible-xs { - display: block !important - } - - table.visible-xs { - display: table !important - } - - tr.visible-xs { - display: table-row !important - } - - td.visible-xs, th.visible-xs { - display: table-cell !important - } -} - -@media (max-width: 767px) { - .visible-xs-block { - display: block !important - } -} - -@media (max-width: 767px) { - .visible-xs-inline { - display: inline !important - } -} - -@media (max-width: 767px) { - .visible-xs-inline-block { - display: inline-block !important - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm { - display: block !important - } - - table.visible-sm { - display: table !important - } - - tr.visible-sm { - display: table-row !important - } - - td.visible-sm, th.visible-sm { - display: table-cell !important - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-block { - display: block !important - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline { - display: inline !important - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline-block { - display: inline-block !important - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md { - display: block !important - } - - table.visible-md { - display: table !important - } - - tr.visible-md { - display: table-row !important - } - - td.visible-md, th.visible-md { - display: table-cell !important - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-block { - display: block !important - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline { - display: inline !important - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline-block { - display: inline-block !important - } -} - -@media (min-width: 1200px) { - .visible-lg { - display: block !important - } - - table.visible-lg { - display: table !important - } - - tr.visible-lg { - display: table-row !important - } - - td.visible-lg, th.visible-lg { - display: table-cell !important - } -} - -@media (min-width: 1200px) { - .visible-lg-block { - display: block !important - } -} - -@media (min-width: 1200px) { - .visible-lg-inline { - display: inline !important - } -} - -@media (min-width: 1200px) { - .visible-lg-inline-block { - display: inline-block !important - } -} - -@media (max-width: 767px) { - .hidden-xs { - display: none !important - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .hidden-sm { - display: none !important - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-md { - display: none !important - } -} - -@media (min-width: 1200px) { - .hidden-lg { - display: none !important - } -} - -.visible-print { - display: none !important -} - -@media print { - .visible-print { - display: block !important - } - - table.visible-print { - display: table !important - } - - tr.visible-print { - display: table-row !important - } - - td.visible-print, th.visible-print { - display: table-cell !important - } -} - -.visible-print-block { - display: none !important -} - -@media print { - .visible-print-block { - display: block !important - } -} - -.visible-print-inline { - display: none !important -} - -@media print { - .visible-print-inline { - display: inline !important - } -} - -.visible-print-inline-block { - display: none !important -} - -@media print { - .visible-print-inline-block { - display: inline-block !important - } -} - -@media print { - .hidden-print { - display: none !important - } -} diff --git a/old code/tray/css/font-awesome.min.css b/old code/tray/css/font-awesome.min.css deleted file mode 100755 index 0e90314..0000000 --- a/old code/tray/css/font-awesome.min.css +++ /dev/null @@ -1,2101 +0,0 @@ -/*! - * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */ -@font-face { - font-family: 'FontAwesome'; - src: url('../fonts/fontawesome-webfont.eot?v=4.2.0'); - src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg'); - font-weight: normal; - font-style: normal -} - -.fa { - display: inline-block; - font: normal normal normal 14px/1 FontAwesome; - font-size: inherit; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale -} - -.fa-lg { - font-size: 1.33333333em; - line-height: .75em; - vertical-align: -15% -} - -.fa-2x { - font-size: 2em -} - -.fa-3x { - font-size: 3em -} - -.fa-4x { - font-size: 4em -} - -.fa-5x { - font-size: 5em -} - -.fa-fw { - width: 1.28571429em; - text-align: center -} - -.fa-ul { - padding-left: 0; - margin-left: 2.14285714em; - list-style-type: none -} - -.fa-ul > li { - position: relative -} - -.fa-li { - position: absolute; - left: -2.14285714em; - width: 2.14285714em; - top: .14285714em; - text-align: center -} - -.fa-li.fa-lg { - left: -1.85714286em -} - -.fa-border { - padding: .2em .25em .15em; - border: solid .08em #EEE; - border-radius: .1em -} - -.pull-right { - float: right -} - -.pull-left { - float: left -} - -.fa.pull-left { - margin-right: .3em -} - -.fa.pull-right { - margin-left: .3em -} - -.fa-spin { - -webkit-animation: fa-spin 2s infinite linear; - animation: fa-spin 2s infinite linear -} - -@-webkit-keyframes fa-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg) - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg) - } -} - -@keyframes fa-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg) - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg) - } -} - -.fa-rotate-90 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); - -webkit-transform: rotate(90deg); - -ms-transform: rotate(90deg); - transform: rotate(90deg) -} - -.fa-rotate-180 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); - -webkit-transform: rotate(180deg); - -ms-transform: rotate(180deg); - transform: rotate(180deg) -} - -.fa-rotate-270 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); - -webkit-transform: rotate(270deg); - -ms-transform: rotate(270deg); - transform: rotate(270deg) -} - -.fa-flip-horizontal { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); - -webkit-transform: scale(-1, 1); - -ms-transform: scale(-1, 1); - transform: scale(-1, 1) -} - -.fa-flip-vertical { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); - -webkit-transform: scale(1, -1); - -ms-transform: scale(1, -1); - transform: scale(1, -1) -} - -:root .fa-rotate-90, :root .fa-rotate-180, :root .fa-rotate-270, :root .fa-flip-horizontal, :root .fa-flip-vertical { - filter: none -} - -.fa-stack { - position: relative; - display: inline-block; - width: 2em; - height: 2em; - line-height: 2em; - vertical-align: middle -} - -.fa-stack-1x, .fa-stack-2x { - position: absolute; - left: 0; - width: 100%; - text-align: center -} - -.fa-stack-1x { - line-height: inherit -} - -.fa-stack-2x { - font-size: 2em -} - -.fa-inverse { - color: #FFF -} - -.fa-glass:before { - content: "\f000" -} - -.fa-music:before { - content: "\f001" -} - -.fa-search:before { - content: "\f002" -} - -.fa-envelope-o:before { - content: "\f003" -} - -.fa-heart:before { - content: "\f004" -} - -.fa-star:before { - content: "\f005" -} - -.fa-star-o:before { - content: "\f006" -} - -.fa-user:before { - content: "\f007" -} - -.fa-film:before { - content: "\f008" -} - -.fa-th-large:before { - content: "\f009" -} - -.fa-th:before { - content: "\f00a" -} - -.fa-th-list:before { - content: "\f00b" -} - -.fa-check:before { - content: "\f00c" -} - -.fa-remove:before, .fa-close:before, .fa-times:before { - content: "\f00d" -} - -.fa-search-plus:before { - content: "\f00e" -} - -.fa-search-minus:before { - content: "\f010" -} - -.fa-power-off:before { - content: "\f011" -} - -.fa-signal:before { - content: "\f012" -} - -.fa-gear:before, .fa-cog:before { - content: "\f013" -} - -.fa-trash-o:before { - content: "\f014" -} - -.fa-home:before { - content: "\f015" -} - -.fa-file-o:before { - content: "\f016" -} - -.fa-clock-o:before { - content: "\f017" -} - -.fa-road:before { - content: "\f018" -} - -.fa-download:before { - content: "\f019" -} - -.fa-arrow-circle-o-down:before { - content: "\f01a" -} - -.fa-arrow-circle-o-up:before { - content: "\f01b" -} - -.fa-inbox:before { - content: "\f01c" -} - -.fa-play-circle-o:before { - content: "\f01d" -} - -.fa-rotate-right:before, .fa-repeat:before { - content: "\f01e" -} - -.fa-refresh:before { - content: "\f021" -} - -.fa-list-alt:before { - content: "\f022" -} - -.fa-lock:before { - content: "\f023" -} - -.fa-flag:before { - content: "\f024" -} - -.fa-headphones:before { - content: "\f025" -} - -.fa-volume-off:before { - content: "\f026" -} - -.fa-volume-down:before { - content: "\f027" -} - -.fa-volume-up:before { - content: "\f028" -} - -.fa-qrcode:before { - content: "\f029" -} - -.fa-barcode:before { - content: "\f02a" -} - -.fa-tag:before { - content: "\f02b" -} - -.fa-tags:before { - content: "\f02c" -} - -.fa-book:before { - content: "\f02d" -} - -.fa-bookmark:before { - content: "\f02e" -} - -.fa-print:before { - content: "\f02f" -} - -.fa-camera:before { - content: "\f030" -} - -.fa-font:before { - content: "\f031" -} - -.fa-bold:before { - content: "\f032" -} - -.fa-italic:before { - content: "\f033" -} - -.fa-text-height:before { - content: "\f034" -} - -.fa-text-width:before { - content: "\f035" -} - -.fa-align-left:before { - content: "\f036" -} - -.fa-align-center:before { - content: "\f037" -} - -.fa-align-right:before { - content: "\f038" -} - -.fa-align-justify:before { - content: "\f039" -} - -.fa-list:before { - content: "\f03a" -} - -.fa-dedent:before, .fa-outdent:before { - content: "\f03b" -} - -.fa-indent:before { - content: "\f03c" -} - -.fa-video-camera:before { - content: "\f03d" -} - -.fa-photo:before, .fa-image:before, .fa-picture-o:before { - content: "\f03e" -} - -.fa-pencil:before { - content: "\f040" -} - -.fa-map-marker:before { - content: "\f041" -} - -.fa-adjust:before { - content: "\f042" -} - -.fa-tint:before { - content: "\f043" -} - -.fa-edit:before, .fa-pencil-square-o:before { - content: "\f044" -} - -.fa-share-square-o:before { - content: "\f045" -} - -.fa-check-square-o:before { - content: "\f046" -} - -.fa-arrows:before { - content: "\f047" -} - -.fa-step-backward:before { - content: "\f048" -} - -.fa-fast-backward:before { - content: "\f049" -} - -.fa-backward:before { - content: "\f04a" -} - -.fa-play:before { - content: "\f04b" -} - -.fa-pause:before { - content: "\f04c" -} - -.fa-stop:before { - content: "\f04d" -} - -.fa-forward:before { - content: "\f04e" -} - -.fa-fast-forward:before { - content: "\f050" -} - -.fa-step-forward:before { - content: "\f051" -} - -.fa-eject:before { - content: "\f052" -} - -.fa-chevron-left:before { - content: "\f053" -} - -.fa-chevron-right:before { - content: "\f054" -} - -.fa-plus-circle:before { - content: "\f055" -} - -.fa-minus-circle:before { - content: "\f056" -} - -.fa-times-circle:before { - content: "\f057" -} - -.fa-check-circle:before { - content: "\f058" -} - -.fa-question-circle:before { - content: "\f059" -} - -.fa-info-circle:before { - content: "\f05a" -} - -.fa-crosshairs:before { - content: "\f05b" -} - -.fa-times-circle-o:before { - content: "\f05c" -} - -.fa-check-circle-o:before { - content: "\f05d" -} - -.fa-ban:before { - content: "\f05e" -} - -.fa-arrow-left:before { - content: "\f060" -} - -.fa-arrow-right:before { - content: "\f061" -} - -.fa-arrow-up:before { - content: "\f062" -} - -.fa-arrow-down:before { - content: "\f063" -} - -.fa-mail-forward:before, .fa-share:before { - content: "\f064" -} - -.fa-expand:before { - content: "\f065" -} - -.fa-compress:before { - content: "\f066" -} - -.fa-plus:before { - content: "\f067" -} - -.fa-minus:before { - content: "\f068" -} - -.fa-asterisk:before { - content: "\f069" -} - -.fa-exclamation-circle:before { - content: "\f06a" -} - -.fa-gift:before { - content: "\f06b" -} - -.fa-leaf:before { - content: "\f06c" -} - -.fa-fire:before { - content: "\f06d" -} - -.fa-eye:before { - content: "\f06e" -} - -.fa-eye-slash:before { - content: "\f070" -} - -.fa-warning:before, .fa-exclamation-triangle:before { - content: "\f071" -} - -.fa-plane:before { - content: "\f072" -} - -.fa-calendar:before { - content: "\f073" -} - -.fa-random:before { - content: "\f074" -} - -.fa-comment:before { - content: "\f075" -} - -.fa-magnet:before { - content: "\f076" -} - -.fa-chevron-up:before { - content: "\f077" -} - -.fa-chevron-down:before { - content: "\f078" -} - -.fa-retweet:before { - content: "\f079" -} - -.fa-shopping-cart:before { - content: "\f07a" -} - -.fa-folder:before { - content: "\f07b" -} - -.fa-folder-open:before { - content: "\f07c" -} - -.fa-arrows-v:before { - content: "\f07d" -} - -.fa-arrows-h:before { - content: "\f07e" -} - -.fa-bar-chart-o:before, .fa-bar-chart:before { - content: "\f080" -} - -.fa-twitter-square:before { - content: "\f081" -} - -.fa-facebook-square:before { - content: "\f082" -} - -.fa-camera-retro:before { - content: "\f083" -} - -.fa-key:before { - content: "\f084" -} - -.fa-gears:before, .fa-cogs:before { - content: "\f085" -} - -.fa-comments:before { - content: "\f086" -} - -.fa-thumbs-o-up:before { - content: "\f087" -} - -.fa-thumbs-o-down:before { - content: "\f088" -} - -.fa-star-half:before { - content: "\f089" -} - -.fa-heart-o:before { - content: "\f08a" -} - -.fa-sign-out:before { - content: "\f08b" -} - -.fa-linkedin-square:before { - content: "\f08c" -} - -.fa-thumb-tack:before { - content: "\f08d" -} - -.fa-external-link:before { - content: "\f08e" -} - -.fa-sign-in:before { - content: "\f090" -} - -.fa-trophy:before { - content: "\f091" -} - -.fa-github-square:before { - content: "\f092" -} - -.fa-upload:before { - content: "\f093" -} - -.fa-lemon-o:before { - content: "\f094" -} - -.fa-phone:before { - content: "\f095" -} - -.fa-square-o:before { - content: "\f096" -} - -.fa-bookmark-o:before { - content: "\f097" -} - -.fa-phone-square:before { - content: "\f098" -} - -.fa-twitter:before { - content: "\f099" -} - -.fa-facebook:before { - content: "\f09a" -} - -.fa-github:before { - content: "\f09b" -} - -.fa-unlock:before { - content: "\f09c" -} - -.fa-credit-card:before { - content: "\f09d" -} - -.fa-rss:before { - content: "\f09e" -} - -.fa-hdd-o:before { - content: "\f0a0" -} - -.fa-bullhorn:before { - content: "\f0a1" -} - -.fa-bell:before { - content: "\f0f3" -} - -.fa-certificate:before { - content: "\f0a3" -} - -.fa-hand-o-right:before { - content: "\f0a4" -} - -.fa-hand-o-left:before { - content: "\f0a5" -} - -.fa-hand-o-up:before { - content: "\f0a6" -} - -.fa-hand-o-down:before { - content: "\f0a7" -} - -.fa-arrow-circle-left:before { - content: "\f0a8" -} - -.fa-arrow-circle-right:before { - content: "\f0a9" -} - -.fa-arrow-circle-up:before { - content: "\f0aa" -} - -.fa-arrow-circle-down:before { - content: "\f0ab" -} - -.fa-globe:before { - content: "\f0ac" -} - -.fa-wrench:before { - content: "\f0ad" -} - -.fa-tasks:before { - content: "\f0ae" -} - -.fa-filter:before { - content: "\f0b0" -} - -.fa-briefcase:before { - content: "\f0b1" -} - -.fa-arrows-alt:before { - content: "\f0b2" -} - -.fa-group:before, .fa-users:before { - content: "\f0c0" -} - -.fa-chain:before, .fa-link:before { - content: "\f0c1" -} - -.fa-cloud:before { - content: "\f0c2" -} - -.fa-flask:before { - content: "\f0c3" -} - -.fa-cut:before, .fa-scissors:before { - content: "\f0c4" -} - -.fa-copy:before, .fa-files-o:before { - content: "\f0c5" -} - -.fa-paperclip:before { - content: "\f0c6" -} - -.fa-save:before, .fa-floppy-o:before { - content: "\f0c7" -} - -.fa-square:before { - content: "\f0c8" -} - -.fa-navicon:before, .fa-reorder:before, .fa-bars:before { - content: "\f0c9" -} - -.fa-list-ul:before { - content: "\f0ca" -} - -.fa-list-ol:before { - content: "\f0cb" -} - -.fa-strikethrough:before { - content: "\f0cc" -} - -.fa-underline:before { - content: "\f0cd" -} - -.fa-table:before { - content: "\f0ce" -} - -.fa-magic:before { - content: "\f0d0" -} - -.fa-truck:before { - content: "\f0d1" -} - -.fa-pinterest:before { - content: "\f0d2" -} - -.fa-pinterest-square:before { - content: "\f0d3" -} - -.fa-google-plus-square:before { - content: "\f0d4" -} - -.fa-google-plus:before { - content: "\f0d5" -} - -.fa-money:before { - content: "\f0d6" -} - -.fa-caret-down:before { - content: "\f0d7" -} - -.fa-caret-up:before { - content: "\f0d8" -} - -.fa-caret-left:before { - content: "\f0d9" -} - -.fa-caret-right:before { - content: "\f0da" -} - -.fa-columns:before { - content: "\f0db" -} - -.fa-unsorted:before, .fa-sort:before { - content: "\f0dc" -} - -.fa-sort-down:before, .fa-sort-desc:before { - content: "\f0dd" -} - -.fa-sort-up:before, .fa-sort-asc:before { - content: "\f0de" -} - -.fa-envelope:before { - content: "\f0e0" -} - -.fa-linkedin:before { - content: "\f0e1" -} - -.fa-rotate-left:before, .fa-undo:before { - content: "\f0e2" -} - -.fa-legal:before, .fa-gavel:before { - content: "\f0e3" -} - -.fa-dashboard:before, .fa-tachometer:before { - content: "\f0e4" -} - -.fa-comment-o:before { - content: "\f0e5" -} - -.fa-comments-o:before { - content: "\f0e6" -} - -.fa-flash:before, .fa-bolt:before { - content: "\f0e7" -} - -.fa-sitemap:before { - content: "\f0e8" -} - -.fa-umbrella:before { - content: "\f0e9" -} - -.fa-paste:before, .fa-clipboard:before { - content: "\f0ea" -} - -.fa-lightbulb-o:before { - content: "\f0eb" -} - -.fa-exchange:before { - content: "\f0ec" -} - -.fa-cloud-download:before { - content: "\f0ed" -} - -.fa-cloud-upload:before { - content: "\f0ee" -} - -.fa-user-md:before { - content: "\f0f0" -} - -.fa-stethoscope:before { - content: "\f0f1" -} - -.fa-suitcase:before { - content: "\f0f2" -} - -.fa-bell-o:before { - content: "\f0a2" -} - -.fa-coffee:before { - content: "\f0f4" -} - -.fa-cutlery:before { - content: "\f0f5" -} - -.fa-file-text-o:before { - content: "\f0f6" -} - -.fa-building-o:before { - content: "\f0f7" -} - -.fa-hospital-o:before { - content: "\f0f8" -} - -.fa-ambulance:before { - content: "\f0f9" -} - -.fa-medkit:before { - content: "\f0fa" -} - -.fa-fighter-jet:before { - content: "\f0fb" -} - -.fa-beer:before { - content: "\f0fc" -} - -.fa-h-square:before { - content: "\f0fd" -} - -.fa-plus-square:before { - content: "\f0fe" -} - -.fa-angle-double-left:before { - content: "\f100" -} - -.fa-angle-double-right:before { - content: "\f101" -} - -.fa-angle-double-up:before { - content: "\f102" -} - -.fa-angle-double-down:before { - content: "\f103" -} - -.fa-angle-left:before { - content: "\f104" -} - -.fa-angle-right:before { - content: "\f105" -} - -.fa-angle-up:before { - content: "\f106" -} - -.fa-angle-down:before { - content: "\f107" -} - -.fa-desktop:before { - content: "\f108" -} - -.fa-laptop:before { - content: "\f109" -} - -.fa-tablet:before { - content: "\f10a" -} - -.fa-mobile-phone:before, .fa-mobile:before { - content: "\f10b" -} - -.fa-circle-o:before { - content: "\f10c" -} - -.fa-quote-left:before { - content: "\f10d" -} - -.fa-quote-right:before { - content: "\f10e" -} - -.fa-spinner:before { - content: "\f110" -} - -.fa-circle:before { - content: "\f111" -} - -.fa-mail-reply:before, .fa-reply:before { - content: "\f112" -} - -.fa-github-alt:before { - content: "\f113" -} - -.fa-folder-o:before { - content: "\f114" -} - -.fa-folder-open-o:before { - content: "\f115" -} - -.fa-smile-o:before { - content: "\f118" -} - -.fa-frown-o:before { - content: "\f119" -} - -.fa-meh-o:before { - content: "\f11a" -} - -.fa-gamepad:before { - content: "\f11b" -} - -.fa-keyboard-o:before { - content: "\f11c" -} - -.fa-flag-o:before { - content: "\f11d" -} - -.fa-flag-checkered:before { - content: "\f11e" -} - -.fa-terminal:before { - content: "\f120" -} - -.fa-code:before { - content: "\f121" -} - -.fa-mail-reply-all:before, .fa-reply-all:before { - content: "\f122" -} - -.fa-star-half-empty:before, .fa-star-half-full:before, .fa-star-half-o:before { - content: "\f123" -} - -.fa-location-arrow:before { - content: "\f124" -} - -.fa-crop:before { - content: "\f125" -} - -.fa-code-fork:before { - content: "\f126" -} - -.fa-unlink:before, .fa-chain-broken:before { - content: "\f127" -} - -.fa-question:before { - content: "\f128" -} - -.fa-info:before { - content: "\f129" -} - -.fa-exclamation:before { - content: "\f12a" -} - -.fa-superscript:before { - content: "\f12b" -} - -.fa-subscript:before { - content: "\f12c" -} - -.fa-eraser:before { - content: "\f12d" -} - -.fa-puzzle-piece:before { - content: "\f12e" -} - -.fa-microphone:before { - content: "\f130" -} - -.fa-microphone-slash:before { - content: "\f131" -} - -.fa-shield:before { - content: "\f132" -} - -.fa-calendar-o:before { - content: "\f133" -} - -.fa-fire-extinguisher:before { - content: "\f134" -} - -.fa-rocket:before { - content: "\f135" -} - -.fa-maxcdn:before { - content: "\f136" -} - -.fa-chevron-circle-left:before { - content: "\f137" -} - -.fa-chevron-circle-right:before { - content: "\f138" -} - -.fa-chevron-circle-up:before { - content: "\f139" -} - -.fa-chevron-circle-down:before { - content: "\f13a" -} - -.fa-html5:before { - content: "\f13b" -} - -.fa-css3:before { - content: "\f13c" -} - -.fa-anchor:before { - content: "\f13d" -} - -.fa-unlock-alt:before { - content: "\f13e" -} - -.fa-bullseye:before { - content: "\f140" -} - -.fa-ellipsis-h:before { - content: "\f141" -} - -.fa-ellipsis-v:before { - content: "\f142" -} - -.fa-rss-square:before { - content: "\f143" -} - -.fa-play-circle:before { - content: "\f144" -} - -.fa-ticket:before { - content: "\f145" -} - -.fa-minus-square:before { - content: "\f146" -} - -.fa-minus-square-o:before { - content: "\f147" -} - -.fa-level-up:before { - content: "\f148" -} - -.fa-level-down:before { - content: "\f149" -} - -.fa-check-square:before { - content: "\f14a" -} - -.fa-pencil-square:before { - content: "\f14b" -} - -.fa-external-link-square:before { - content: "\f14c" -} - -.fa-share-square:before { - content: "\f14d" -} - -.fa-compass:before { - content: "\f14e" -} - -.fa-toggle-down:before, .fa-caret-square-o-down:before { - content: "\f150" -} - -.fa-toggle-up:before, .fa-caret-square-o-up:before { - content: "\f151" -} - -.fa-toggle-right:before, .fa-caret-square-o-right:before { - content: "\f152" -} - -.fa-euro:before, .fa-eur:before { - content: "\f153" -} - -.fa-gbp:before { - content: "\f154" -} - -.fa-dollar:before, .fa-usd:before { - content: "\f155" -} - -.fa-rupee:before, .fa-inr:before { - content: "\f156" -} - -.fa-cny:before, .fa-rmb:before, .fa-yen:before, .fa-jpy:before { - content: "\f157" -} - -.fa-ruble:before, .fa-rouble:before, .fa-rub:before { - content: "\f158" -} - -.fa-won:before, .fa-krw:before { - content: "\f159" -} - -.fa-bitcoin:before, .fa-btc:before { - content: "\f15a" -} - -.fa-file:before { - content: "\f15b" -} - -.fa-file-text:before { - content: "\f15c" -} - -.fa-sort-alpha-asc:before { - content: "\f15d" -} - -.fa-sort-alpha-desc:before { - content: "\f15e" -} - -.fa-sort-amount-asc:before { - content: "\f160" -} - -.fa-sort-amount-desc:before { - content: "\f161" -} - -.fa-sort-numeric-asc:before { - content: "\f162" -} - -.fa-sort-numeric-desc:before { - content: "\f163" -} - -.fa-thumbs-up:before { - content: "\f164" -} - -.fa-thumbs-down:before { - content: "\f165" -} - -.fa-youtube-square:before { - content: "\f166" -} - -.fa-youtube:before { - content: "\f167" -} - -.fa-xing:before { - content: "\f168" -} - -.fa-xing-square:before { - content: "\f169" -} - -.fa-youtube-play:before { - content: "\f16a" -} - -.fa-dropbox:before { - content: "\f16b" -} - -.fa-stack-overflow:before { - content: "\f16c" -} - -.fa-instagram:before { - content: "\f16d" -} - -.fa-flickr:before { - content: "\f16e" -} - -.fa-adn:before { - content: "\f170" -} - -.fa-bitbucket:before { - content: "\f171" -} - -.fa-bitbucket-square:before { - content: "\f172" -} - -.fa-tumblr:before { - content: "\f173" -} - -.fa-tumblr-square:before { - content: "\f174" -} - -.fa-long-arrow-down:before { - content: "\f175" -} - -.fa-long-arrow-up:before { - content: "\f176" -} - -.fa-long-arrow-left:before { - content: "\f177" -} - -.fa-long-arrow-right:before { - content: "\f178" -} - -.fa-apple:before { - content: "\f179" -} - -.fa-windows:before { - content: "\f17a" -} - -.fa-android:before { - content: "\f17b" -} - -.fa-linux:before { - content: "\f17c" -} - -.fa-dribbble:before { - content: "\f17d" -} - -.fa-skype:before { - content: "\f17e" -} - -.fa-foursquare:before { - content: "\f180" -} - -.fa-trello:before { - content: "\f181" -} - -.fa-female:before { - content: "\f182" -} - -.fa-male:before { - content: "\f183" -} - -.fa-gittip:before { - content: "\f184" -} - -.fa-sun-o:before { - content: "\f185" -} - -.fa-moon-o:before { - content: "\f186" -} - -.fa-archive:before { - content: "\f187" -} - -.fa-bug:before { - content: "\f188" -} - -.fa-vk:before { - content: "\f189" -} - -.fa-weibo:before { - content: "\f18a" -} - -.fa-renren:before { - content: "\f18b" -} - -.fa-pagelines:before { - content: "\f18c" -} - -.fa-stack-exchange:before { - content: "\f18d" -} - -.fa-arrow-circle-o-right:before { - content: "\f18e" -} - -.fa-arrow-circle-o-left:before { - content: "\f190" -} - -.fa-toggle-left:before, .fa-caret-square-o-left:before { - content: "\f191" -} - -.fa-dot-circle-o:before { - content: "\f192" -} - -.fa-wheelchair:before { - content: "\f193" -} - -.fa-vimeo-square:before { - content: "\f194" -} - -.fa-turkish-lira:before, .fa-try:before { - content: "\f195" -} - -.fa-plus-square-o:before { - content: "\f196" -} - -.fa-space-shuttle:before { - content: "\f197" -} - -.fa-slack:before { - content: "\f198" -} - -.fa-envelope-square:before { - content: "\f199" -} - -.fa-wordpress:before { - content: "\f19a" -} - -.fa-openid:before { - content: "\f19b" -} - -.fa-institution:before, .fa-bank:before, .fa-university:before { - content: "\f19c" -} - -.fa-mortar-board:before, .fa-graduation-cap:before { - content: "\f19d" -} - -.fa-yahoo:before { - content: "\f19e" -} - -.fa-google:before { - content: "\f1a0" -} - -.fa-reddit:before { - content: "\f1a1" -} - -.fa-reddit-square:before { - content: "\f1a2" -} - -.fa-stumbleupon-circle:before { - content: "\f1a3" -} - -.fa-stumbleupon:before { - content: "\f1a4" -} - -.fa-delicious:before { - content: "\f1a5" -} - -.fa-digg:before { - content: "\f1a6" -} - -.fa-pied-piper:before { - content: "\f1a7" -} - -.fa-pied-piper-alt:before { - content: "\f1a8" -} - -.fa-drupal:before { - content: "\f1a9" -} - -.fa-joomla:before { - content: "\f1aa" -} - -.fa-language:before { - content: "\f1ab" -} - -.fa-fax:before { - content: "\f1ac" -} - -.fa-building:before { - content: "\f1ad" -} - -.fa-child:before { - content: "\f1ae" -} - -.fa-paw:before { - content: "\f1b0" -} - -.fa-spoon:before { - content: "\f1b1" -} - -.fa-cube:before { - content: "\f1b2" -} - -.fa-cubes:before { - content: "\f1b3" -} - -.fa-behance:before { - content: "\f1b4" -} - -.fa-behance-square:before { - content: "\f1b5" -} - -.fa-steam:before { - content: "\f1b6" -} - -.fa-steam-square:before { - content: "\f1b7" -} - -.fa-recycle:before { - content: "\f1b8" -} - -.fa-automobile:before, .fa-car:before { - content: "\f1b9" -} - -.fa-cab:before, .fa-taxi:before { - content: "\f1ba" -} - -.fa-tree:before { - content: "\f1bb" -} - -.fa-spotify:before { - content: "\f1bc" -} - -.fa-deviantart:before { - content: "\f1bd" -} - -.fa-soundcloud:before { - content: "\f1be" -} - -.fa-database:before { - content: "\f1c0" -} - -.fa-file-pdf-o:before { - content: "\f1c1" -} - -.fa-file-word-o:before { - content: "\f1c2" -} - -.fa-file-excel-o:before { - content: "\f1c3" -} - -.fa-file-powerpoint-o:before { - content: "\f1c4" -} - -.fa-file-photo-o:before, .fa-file-picture-o:before, .fa-file-image-o:before { - content: "\f1c5" -} - -.fa-file-zip-o:before, .fa-file-archive-o:before { - content: "\f1c6" -} - -.fa-file-sound-o:before, .fa-file-audio-o:before { - content: "\f1c7" -} - -.fa-file-movie-o:before, .fa-file-video-o:before { - content: "\f1c8" -} - -.fa-file-code-o:before { - content: "\f1c9" -} - -.fa-vine:before { - content: "\f1ca" -} - -.fa-codepen:before { - content: "\f1cb" -} - -.fa-jsfiddle:before { - content: "\f1cc" -} - -.fa-life-bouy:before, .fa-life-buoy:before, .fa-life-saver:before, .fa-support:before, .fa-life-ring:before { - content: "\f1cd" -} - -.fa-circle-o-notch:before { - content: "\f1ce" -} - -.fa-ra:before, .fa-rebel:before { - content: "\f1d0" -} - -.fa-ge:before, .fa-empire:before { - content: "\f1d1" -} - -.fa-git-square:before { - content: "\f1d2" -} - -.fa-git:before { - content: "\f1d3" -} - -.fa-hacker-news:before { - content: "\f1d4" -} - -.fa-tencent-weibo:before { - content: "\f1d5" -} - -.fa-qq:before { - content: "\f1d6" -} - -.fa-wechat:before, .fa-weixin:before { - content: "\f1d7" -} - -.fa-send:before, .fa-paper-plane:before { - content: "\f1d8" -} - -.fa-send-o:before, .fa-paper-plane-o:before { - content: "\f1d9" -} - -.fa-history:before { - content: "\f1da" -} - -.fa-circle-thin:before { - content: "\f1db" -} - -.fa-header:before { - content: "\f1dc" -} - -.fa-paragraph:before { - content: "\f1dd" -} - -.fa-sliders:before { - content: "\f1de" -} - -.fa-share-alt:before { - content: "\f1e0" -} - -.fa-share-alt-square:before { - content: "\f1e1" -} - -.fa-bomb:before { - content: "\f1e2" -} - -.fa-soccer-ball-o:before, .fa-futbol-o:before { - content: "\f1e3" -} - -.fa-tty:before { - content: "\f1e4" -} - -.fa-binoculars:before { - content: "\f1e5" -} - -.fa-plug:before { - content: "\f1e6" -} - -.fa-slideshare:before { - content: "\f1e7" -} - -.fa-twitch:before { - content: "\f1e8" -} - -.fa-yelp:before { - content: "\f1e9" -} - -.fa-newspaper-o:before { - content: "\f1ea" -} - -.fa-wifi:before { - content: "\f1eb" -} - -.fa-calculator:before { - content: "\f1ec" -} - -.fa-paypal:before { - content: "\f1ed" -} - -.fa-google-wallet:before { - content: "\f1ee" -} - -.fa-cc-visa:before { - content: "\f1f0" -} - -.fa-cc-mastercard:before { - content: "\f1f1" -} - -.fa-cc-discover:before { - content: "\f1f2" -} - -.fa-cc-amex:before { - content: "\f1f3" -} - -.fa-cc-paypal:before { - content: "\f1f4" -} - -.fa-cc-stripe:before { - content: "\f1f5" -} - -.fa-bell-slash:before { - content: "\f1f6" -} - -.fa-bell-slash-o:before { - content: "\f1f7" -} - -.fa-trash:before { - content: "\f1f8" -} - -.fa-copyright:before { - content: "\f1f9" -} - -.fa-at:before { - content: "\f1fa" -} - -.fa-eyedropper:before { - content: "\f1fb" -} - -.fa-paint-brush:before { - content: "\f1fc" -} - -.fa-birthday-cake:before { - content: "\f1fd" -} - -.fa-area-chart:before { - content: "\f1fe" -} - -.fa-pie-chart:before { - content: "\f200" -} - -.fa-line-chart:before { - content: "\f201" -} - -.fa-lastfm:before { - content: "\f202" -} - -.fa-lastfm-square:before { - content: "\f203" -} - -.fa-toggle-off:before { - content: "\f204" -} - -.fa-toggle-on:before { - content: "\f205" -} - -.fa-bicycle:before { - content: "\f206" -} - -.fa-bus:before { - content: "\f207" -} - -.fa-ioxhost:before { - content: "\f208" -} - -.fa-angellist:before { - content: "\f209" -} - -.fa-cc:before { - content: "\f20a" -} - -.fa-shekel:before, .fa-sheqel:before, .fa-ils:before { - content: "\f20b" -} - -.fa-meanpath:before { - content: "\f20c" -} diff --git a/old code/tray/css/gh-fork-ribbon.min.css b/old code/tray/css/gh-fork-ribbon.min.css deleted file mode 100755 index b67dbd3..0000000 --- a/old code/tray/css/gh-fork-ribbon.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * "Fork me on GitHub" CSS ribbon v0.2.3 | MIT License - * https://github.com/simonwhitaker/github-fork-ribbon-css -*/.github-fork-ribbon{width:12.1em;height:12.1em;position:absolute;overflow:hidden;top:0;right:0;z-index:9999;pointer-events:none;font-size:13px;text-decoration:none;text-indent:-999999px}.github-fork-ribbon.fixed{position:fixed}.github-fork-ribbon:active,.github-fork-ribbon:hover{background-color:rgba(0,0,0,0)}.github-fork-ribbon:after,.github-fork-ribbon:before{position:absolute;display:block;width:15.38em;height:1.54em;top:3.23em;right:-3.23em;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.github-fork-ribbon:before{content:"";padding:.38em 0;background-color:#a00;background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(rgba(0,0,0,.15)));background-image:-webkit-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-moz-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-ms-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-o-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:linear-gradient(to bottom,rgba(0,0,0,0),rgba(0,0,0,.15));-webkit-box-shadow:0 .15em .23em 0 rgba(0,0,0,.5);-moz-box-shadow:0 .15em .23em 0 rgba(0,0,0,.5);box-shadow:0 .15em .23em 0 rgba(0,0,0,.5);pointer-events:auto}.github-fork-ribbon:after{content:attr(data-ribbon);color:#fff;font:700 1em "Helvetica Neue",Helvetica,Arial,sans-serif;line-height:1.54em;text-decoration:none;text-shadow:0 -.08em rgba(0,0,0,.5);text-align:center;text-indent:0;padding:.15em 0;margin:.15em 0;border-width:.08em 0;border-style:dotted;border-color:#fff;border-color:rgba(255,255,255,.7)}.github-fork-ribbon.left-bottom,.github-fork-ribbon.left-top{right:auto;left:0}.github-fork-ribbon.left-bottom,.github-fork-ribbon.right-bottom{top:auto;bottom:0}.github-fork-ribbon.left-bottom:after,.github-fork-ribbon.left-bottom:before,.github-fork-ribbon.left-top:after,.github-fork-ribbon.left-top:before{right:auto;left:-3.23em}.github-fork-ribbon.left-bottom:after,.github-fork-ribbon.left-bottom:before,.github-fork-ribbon.right-bottom:after,.github-fork-ribbon.right-bottom:before{top:auto;bottom:3.23em}.github-fork-ribbon.left-top:after,.github-fork-ribbon.left-top:before,.github-fork-ribbon.right-bottom:after,.github-fork-ribbon.right-bottom:before{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)} -/*# sourceMappingURL=gh-fork-ribbon.min.css.map */ -/* QZ Colors */ -.github-fork-ribbon:before { background-color: #3D994A; } \ No newline at end of file diff --git a/old code/tray/css/style.css b/old code/tray/css/style.css deleted file mode 100755 index 0fc8237..0000000 --- a/old code/tray/css/style.css +++ /dev/null @@ -1,427 +0,0 @@ -.btn-default { - color: #333; - background-color: #FFF; - border-color: #CCC; -} - -.btn-primary { - color: #FFFFFF; - background-color: #44AB53; - border-color: #3D994A; -} - -.btn-success { - color: #FFF; - background-color: #33658A; - border-color: #2C5777; -} - -.btn-warning { - color: #FFF; - background-color: #F6AE2D; - border-color: #F5A515; -} - -.btn-danger { - color: #FFF; - background-color: #F26419; - border-color: #E5570D; -} - -.btn-info { - color: #FFF; - background-color: #3680A8; - border-color: #307195; -} - -.btn-default:hover { - background-color: #E6E6E6; - border-color: #B3B3B3; -} - -.btn-primary:hover { - background-color: #358741; - border-color: #2E7438; -} - -.btn-success:hover { - background-color: #254A65; - border-color: #1E3C52; -} - -.btn-warning:hover { - background-color: #E6970A; - border-color: #CE8709; -} - -.btn-danger:hover { - background-color: #CC4E0C; - border-color: #B4450A; -} - -.btn-info:hover { - background-color: #2A6382; - border-color: #24546E; -} - -.btn-default:focus { - background-color: #F2F2F2; - border-color: #BFBFBF; -} - -.btn-primary:focus { - background-color: #3D994A; - border-color: #358741; -} - -.btn-success:focus { - background-color: #2C5777; - border-color: #254A65; -} - -.btn-warning:focus { - background-color: #F5A515; - border-color: #E6970A; -} - -.btn-danger:focus { - background-color: #E5570D; - border-color: #CC4E0C; -} - -.btn-info:focus { - background-color: #307195; - border-color: #2A6382; -} - -.btn-default:active { - background-color: #E6E6E6; - border-color: #B3B3B3; -} - -.btn-primary:active { - background-color: #358741; - border-color: #2E7438; -} - -.btn-success:active { - background-color: #254A65; - border-color: #1E3C52; -} - -.btn-warning:active { - background-color: #E6970A; - border-color: #CE8709; -} - -.btn-danger:active { - background-color: #CC4E0C; - border-color: #B4450A; -} - -.btn-info:active { - background-color: #2A6382; - border-color: #24546E; -} - -.btn-default.disabled { - background-color: #FFFFFF; - border-color: #CFCFCF; -} - -.btn-primary.disabled { - background-color: #45AF55; - border-color: #3E9C4C; -} - -.btn-success.disabled { - background-color: #34688E; - border-color: #2D5A7B; -} - -.btn-warning.disabled { - background-color: #F6B032; - border-color: #F5A619; -} - -.btn-danger.disabled { - background-color: #F2671E; - border-color: #E9590D; -} - -.btn-info.disabled { - background-color: #3783AC; - border-color: #317499; -} - -a { - color: #3680A8; -} - -a:hover, -a:focus { - color: #24546E; -} - -.text-primary { - color: #44AB53; -} - -.text-danger { - color: #F26419; -} - -.form-control .has-error { - border-color: #EED3D7; -} - -.form-control .has-success { - border-color: #D6E9C6; -} - -.navbar-default { - background-color: #44AB53; -} - -.navbar-default .navbar-nav > li > a, -.navbar-default .navbar-nav > li > a:hover, -.navbar-default .navbar-header .navbar-brand { - color: #FFF; -} - -@media (max-width: 768px) { - .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #FFF; - } -} - -.navbar-default .navbar-nav > li > a:hover { - background-color: #3D994A; -} - -.navbar-default .navbar-toggle > .icon-bar { - background-color: #FFF; -} - -.navbar-default .navbar-toggle:focus > .icon-bar { - background-color: #555; - color: #24546E; -} - -.navbar-default .navbar-toggle:hover > .icon-bar { - background-color: #FFF; -} - -.navbar-default .navbar-toggle:hover { - background-color: #3D994A; -} - -.panel.panel-primary { - border-color: #3D994A; -} - -.panel.panel-primary .panel-heading { - border-color: #3D994A; - background-color: #3D994A; -} - -.alert.alert-warning a { - color: #68522C; -} - -.alert.alert-danger a { - color: #B4450A; -} - -html { - position: relative; - min-height: 100%; -} - -body { - padding-bottom: 80px; -} - -table { - font-size: inherit; -} - -.versiontable > tbody > tr > th { - text-align: right; -} - -.versiontable > thead > tr > th { - vertical-align: top; -} - -.homesection + .homesection { - border-top: solid 1px #EEE; -} - -.homesection { - text-align: center; - margin: 40px 0; - padding: 40px 0; -} - -img.jumbo { - margin-top: -40px; - margin-left: -60px; -} - -h1.jumbo { - margin-top: 0; -} - -footer { - text-align: center; - height: 80px; - position: absolute; - bottom: 0; - width: 100%; -} - -@media (min-width: 768px) { - h1.jumbo, - h3.jumbo { - text-align: right; - } -} - -@media (max-width: 767px) { - h1.jumbo, - h3.jumbo { - text-align: center; - } -} - -@media (min-width: 1200px) { - h1.jumbo { - margin-top: 40px; - } -} - -@media (min-width: 768px) { - h3.jumbo { - margin-top: -6px; - } -} - -.vertical-align { - display: flex; - align-items: center; -} - -.hide_ { - display: none; -} - -.dropdown-submenu { - position: relative; -} - -.dropdown-submenu > .dropdown-menu { - top: 0; - left: 100%; - margin-top: -6px; - margin-left: 10px; - -webkit-border-radius: 0 6px 6px 6px; - -moz-border-radius: 0 6px 6px 6px; - border-radius: 0 6px 6px 6px; -} - -.drag-target { - /* color: white; */ - background: repeating-linear-gradient( - 45deg, - #dbf0de, - #dbf0de 10px, - #a5d9ad 10px, - #a5d9ad 20px - ); -} - -input[type="file"] { - display: none; -} - -button > .fa-caret-down { - height: 100%; - display: inline; - margin-left: -.75em; - margin-right: -1em; -} - -@media (min-width: 768px) { - .dropdown-submenu:hover > .dropdown-menu { - display: block; - } - - .dropdown-submenu > .dropdown-menu { - margin-left: -1px; - } -} - -.dropdown-submenu > a:after { - display: block; - content: " "; - float: right; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - border-width: 5px 0 5px 5px; - border-left-color: #CCCCCC; - margin-top: 5px; - margin-right: -10px; -} - -.dropdown-submenu:hover > a:after { - border-left-color: #FFFFFF; -} - -.dropdown-submenu.pull-left { - float: none; -} - -.dropdown-submenu.pull-left > .dropdown-menu { - left: -100%; - margin-left: 10px; - -webkit-border-radius: 6px 0 6px 6px; - -moz-border-radius: 6px 0 6px 6px; - border-radius: 6px 0 6px 6px; -} - -.tip { - border-bottom: 1px dashed; -} - -summary { - cursor: pointer; -} - -code { - color: #31708F; - background-color: #D9EDF7; -} - -input[type='radio'] { - margin-left: .5em; -} - -#printersLog { - max-height: 20em; - overflow: auto; -} - -#printersLog .INFO { - color: #303030; -} - -#printersLog .WARN { - color: #9F7435; -} - -#printersLog .FATAL { - color: #9F3535; -} diff --git a/old code/tray/fonts/FontAwesome.otf b/old code/tray/fonts/FontAwesome.otf deleted file mode 100755 index 681bdd4..0000000 Binary files a/old code/tray/fonts/FontAwesome.otf and /dev/null differ diff --git a/old code/tray/fonts/fontawesome-webfont.eot b/old code/tray/fonts/fontawesome-webfont.eot deleted file mode 100755 index a30335d..0000000 Binary files a/old code/tray/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/old code/tray/fonts/fontawesome-webfont.svg b/old code/tray/fonts/fontawesome-webfont.svg deleted file mode 100755 index 6fd19ab..0000000 --- a/old code/tray/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,640 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/old code/tray/fonts/fontawesome-webfont.ttf b/old code/tray/fonts/fontawesome-webfont.ttf deleted file mode 100755 index d7994e1..0000000 Binary files a/old code/tray/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/old code/tray/fonts/fontawesome-webfont.woff b/old code/tray/fonts/fontawesome-webfont.woff deleted file mode 100755 index 6fd4ede..0000000 Binary files a/old code/tray/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/old code/tray/fonts/fontawesome-webfont.woff2 b/old code/tray/fonts/fontawesome-webfont.woff2 deleted file mode 100755 index 5560193..0000000 Binary files a/old code/tray/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/old code/tray/js/.npmignore b/old code/tray/js/.npmignore deleted file mode 100755 index 64ff58d..0000000 --- a/old code/tray/js/.npmignore +++ /dev/null @@ -1,4 +0,0 @@ -/additional/ -/dependencies/ -sample/ -.DS_Store diff --git a/old code/tray/js/README.md b/old code/tray/js/README.md deleted file mode 100755 index 8d50d75..0000000 --- a/old code/tray/js/README.md +++ /dev/null @@ -1,23 +0,0 @@ -```js -const qz = require("qz-tray"); - -qz.websocket.connect().then(() => { - return qz.printers.find(); -}).then((printers) => { - console.log(printers); - let config = qz.configs.create('PDF'); - return qz.print(config, [{ - type: 'pixel', - format: 'html', - flavor: 'plain', - data: '

Hello JavaScript!

' - }]); -}).then(() => { - return qz.websocket.disconnect(); -}).then(() => { - // process.exit(0); -}).catch((err) => { - console.error(err); - // process.exit(1); -}); -``` diff --git a/old code/tray/js/package.json b/old code/tray/js/package.json deleted file mode 100755 index 0850c4b..0000000 --- a/old code/tray/js/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "qz-tray", - "version": "2.2.6-SNAPSHOT", - "description": "Connects a web client to the QZ Tray software. Enables printing and device communication from javascript. ", - "main": "qz-tray.js", - "browser": { - "path": false - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/qzind/tray.git" - }, - "keywords": [ - "Printing", - "USB", - "Serial", - "RS232", - "USB", - "Scales", - "Zebra", - "Epson", - "Star", - "Citizen", - "BOCA" - ], - "author": "QZ Industries, LLC", - "license": "LGPL-2.1", - "bugs": { - "url": "https://github.com/qzind/tray/issues" - }, - "homepage": "https://github.com/qzind/tray#readme" -} diff --git a/old code/tray/js/qz-tray.js b/old code/tray/js/qz-tray.js deleted file mode 100755 index 3c85483..0000000 --- a/old code/tray/js/qz-tray.js +++ /dev/null @@ -1,2862 +0,0 @@ -'use strict'; - -/** - * @version 2.2.6-SNAPSHOT - * @overview QZ Tray Connector - * @license LGPL-2.1-only - *

- * Connects a web client to the QZ Tray software. - * Enables printing and device communication from javascript. - */ -var qz = (function() { - -///// POLYFILLS ///// - - if (!Array.isArray) { - Array.isArray = function(arg) { - return Object.prototype.toString.call(arg) === '[object Array]'; - }; - } - - if (!Number.isInteger) { - Number.isInteger = function(value) { - return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; - }; - } - -///// PRIVATE METHODS ///// - - var _qz = { - VERSION: "2.2.6-SNAPSHOT", //must match @version above - DEBUG: false, - - log: { - /** Debugging messages */ - trace: function() { if (_qz.DEBUG) { console.log.apply(console, arguments); } }, - /** General messages */ - info: function() { console.info.apply(console, arguments); }, - /** General warnings */ - warn: function() { console.warn.apply(console, arguments); }, - /** Debugging errors */ - allay: function() { if (_qz.DEBUG) { console.warn.apply(console, arguments); } }, - /** General errors */ - error: function() { console.error.apply(console, arguments); } - }, - - - //stream types - streams: { - serial: 'SERIAL', usb: 'USB', hid: 'HID', printer: 'PRINTER', file: 'FILE', socket: 'SOCKET' - }, - - - websocket: { - /** The actual websocket object managing the connection. */ - connection: null, - /** Track if a connection attempt is being cancelled. */ - shutdown: false, - - /** Default parameters used on new connections. Override values using options parameter on {@link qz.websocket.connect}. */ - connectConfig: { - host: ["localhost", "localhost.qz.io"], //hosts QZ Tray can be running on - hostIndex: 0, //internal var - index on host array - usingSecure: true, //boolean use of secure protocol - protocol: { - secure: "wss://", //secure websocket - insecure: "ws://" //insecure websocket - }, - port: { - secure: [8181, 8282, 8383, 8484], //list of secure ports QZ Tray could be listening on - insecure: [8182, 8283, 8384, 8485], //list of insecure ports QZ Tray could be listening on - portIndex: 0 //internal var - index on active port array - }, - keepAlive: 60, //time between pings to keep connection alive, in seconds - retries: 0, //number of times to reconnect before failing - delay: 0 //seconds before firing a connection - }, - - setup: { - /** Loop through possible ports to open connection, sets web socket calls that will settle the promise. */ - findConnection: function(config, resolve, reject) { - if (_qz.websocket.shutdown) { - reject(new Error("Connection attempt cancelled by user")); - return; - } - - //force flag if missing ports - if (!config.port.secure.length) { - if (!config.port.insecure.length) { - reject(new Error("No ports have been specified to connect over")); - return; - } else if (config.usingSecure) { - _qz.log.error("No secure ports specified - forcing insecure connection"); - config.usingSecure = false; - } - } else if (!config.port.insecure.length && !config.usingSecure) { - _qz.log.trace("No insecure ports specified - forcing secure connection"); - config.usingSecure = true; - } - - var deeper = function() { - if (_qz.websocket.shutdown) { - //connection attempt was cancelled, bail out - reject(new Error("Connection attempt cancelled by user")); - return; - } - - config.port.portIndex++; - - if ((config.usingSecure && config.port.portIndex >= config.port.secure.length) - || (!config.usingSecure && config.port.portIndex >= config.port.insecure.length)) { - if (config.hostIndex >= config.host.length - 1) { - //give up, all hope is lost - reject(new Error("Unable to establish connection with QZ")); - return; - } else { - config.hostIndex++; - config.port.portIndex = 0; - } - } - - // recursive call until connection established or all ports are exhausted - _qz.websocket.setup.findConnection(config, resolve, reject); - }; - - var address; - if (config.usingSecure) { - address = config.protocol.secure + config.host[config.hostIndex] + ":" + config.port.secure[config.port.portIndex]; - } else { - address = config.protocol.insecure + config.host[config.hostIndex] + ":" + config.port.insecure[config.port.portIndex]; - } - - try { - _qz.log.trace("Attempting connection", address); - _qz.websocket.connection = new _qz.tools.ws(address); - } - catch(err) { - _qz.log.error(err); - deeper(); - return; - } - - if (_qz.websocket.connection != null) { - _qz.websocket.connection.established = false; - - //called on successful connection to qz, begins setup of websocket calls and resolves connect promise after certificate is sent - _qz.websocket.connection.onopen = function(evt) { - if (!_qz.websocket.connection.established) { - _qz.log.trace(evt); - _qz.log.info("Established connection with QZ Tray on " + address); - - _qz.websocket.setup.openConnection({ resolve: resolve, reject: reject }); - - if (config.keepAlive > 0) { - var interval = setInterval(function() { - if (!_qz.tools.isActive() || _qz.websocket.connection.interval !== interval) { - clearInterval(interval); - return; - } - - _qz.websocket.connection.send("ping"); - }, config.keepAlive * 1000); - - _qz.websocket.connection.interval = interval; - } - } - }; - - //called during websocket close during setup - _qz.websocket.connection.onclose = function() { - // Safari compatibility fix to raise error event - if (_qz.websocket.connection && typeof navigator !== 'undefined' && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { - _qz.websocket.connection.onerror(); - } - }; - - //called for errors during setup (such as invalid ports), reject connect promise only if all ports have been tried - _qz.websocket.connection.onerror = function(evt) { - _qz.log.trace(evt); - - _qz.websocket.connection = null; - - deeper(); - }; - } else { - reject(new Error("Unable to create a websocket connection")); - } - }, - - /** Finish setting calls on successful connection, sets web socket calls that won't settle the promise. */ - openConnection: function(openPromise) { - _qz.websocket.connection.established = true; - - //called when an open connection is closed - _qz.websocket.connection.onclose = function(evt) { - _qz.log.trace(evt); - - _qz.websocket.connection = null; - _qz.websocket.callClose(evt); - _qz.log.info("Closed connection with QZ Tray"); - - for(var uid in _qz.websocket.pendingCalls) { - if (_qz.websocket.pendingCalls.hasOwnProperty(uid)) { - _qz.websocket.pendingCalls[uid].reject(new Error("Connection closed before response received")); - } - } - - //if this is set, then an explicit close call was made - if (this.promise != undefined) { - this.promise.resolve(); - } - }; - - //called for any errors with an open connection - _qz.websocket.connection.onerror = function(evt) { - _qz.websocket.callError(evt); - }; - - //send JSON objects to qz - _qz.websocket.connection.sendData = function(obj) { - _qz.log.trace("Preparing object for websocket", obj); - - if (obj.timestamp == undefined) { - obj.timestamp = Date.now(); - if (typeof obj.timestamp !== 'number') { - obj.timestamp = new Date().getTime(); - } - } - if (obj.promise != undefined) { - obj.uid = _qz.websocket.setup.newUID(); - _qz.websocket.pendingCalls[obj.uid] = obj.promise; - } - - // track requesting monitor - obj.position = { - x: typeof screen !== 'undefined' ? ((screen.availWidth || screen.width) / 2) + (screen.left || screen.availLeft || 0) : 0, - y: typeof screen !== 'undefined' ? ((screen.availHeight || screen.height) / 2) + (screen.top || screen.availTop || 0) : 0 - }; - - try { - if (obj.call != undefined && obj.signature == undefined && _qz.security.needsSigned(obj.call)) { - var signObj = { - call: obj.call, - params: obj.params, - timestamp: obj.timestamp - }; - - //make a hashing promise if not already one - var hashing = _qz.tools.hash(_qz.tools.stringify(signObj)); - if (!hashing.then) { - hashing = _qz.tools.promise(function(resolve) { - resolve(hashing); - }); - } - - hashing.then(function(hashed) { - return _qz.security.callSign(hashed); - }).then(function(signature) { - _qz.log.trace("Signature for call", signature); - obj.signature = signature || ""; - obj.signAlgorithm = _qz.security.signAlgorithm; - - _qz.signContent = undefined; - _qz.websocket.connection.send(_qz.tools.stringify(obj)); - }).catch(function(err) { - _qz.log.error("Signing failed", err); - - if (obj.promise != undefined) { - obj.promise.reject(new Error("Failed to sign request")); - delete _qz.websocket.pendingCalls[obj.uid]; - } - }); - } else { - _qz.log.trace("Signature for call", obj.signature); - - //called for pre-signed content and (unsigned) setup calls - _qz.websocket.connection.send(_qz.tools.stringify(obj)); - } - } - catch(err) { - _qz.log.error(err); - - if (obj.promise != undefined) { - obj.promise.reject(err); - delete _qz.websocket.pendingCalls[obj.uid]; - } - } - }; - - //receive message from qz - _qz.websocket.connection.onmessage = function(evt) { - var returned = JSON.parse(evt.data); - - if (returned.uid == null) { - if (returned.type == null) { - //incorrect response format, likely connected to incompatible qz version - _qz.websocket.connection.close(4003, "Connected to incompatible QZ Tray version"); - - } else { - //streams (callbacks only, no promises) - switch(returned.type) { - case _qz.streams.serial: - if (!returned.event) { - returned.event = JSON.stringify({ portName: returned.key, output: returned.data }); - } - - _qz.serial.callSerial(JSON.parse(returned.event)); - break; - case _qz.streams.socket: - _qz.socket.callSocket(JSON.parse(returned.event)); - break; - case _qz.streams.usb: - if (!returned.event) { - returned.event = JSON.stringify({ vendorId: returned.key[0], productId: returned.key[1], output: returned.data }); - } - - _qz.usb.callUsb(JSON.parse(returned.event)); - break; - case _qz.streams.hid: - _qz.hid.callHid(JSON.parse(returned.event)); - break; - case _qz.streams.printer: - _qz.printers.callPrinter(JSON.parse(returned.event)); - break; - case _qz.streams.file: - _qz.file.callFile(JSON.parse(returned.event)); - break; - default: - _qz.log.allay("Cannot determine stream type for callback", returned); - break; - } - } - - return; - } - - _qz.log.trace("Received response from websocket", returned); - - var promise = _qz.websocket.pendingCalls[returned.uid]; - if (promise == undefined) { - _qz.log.allay('No promise found for returned response'); - } else { - if (returned.error != undefined) { - promise.reject(new Error(returned.error)); - } else { - promise.resolve(returned.result); - } - } - - delete _qz.websocket.pendingCalls[returned.uid]; - }; - - - //send up the certificate before making any calls - //also gives the user a chance to deny the connection - function sendCert(cert) { - if (cert === undefined) { cert = null; } - - //websocket setup, query what version is connected - qz.api.getVersion().then(function(version) { - _qz.websocket.connection.version = version; - _qz.websocket.connection.semver = version.toLowerCase().replace(/-rc\./g, "-rc").split(/[\\+\\.-]/g); - for(var i = 0; i < _qz.websocket.connection.semver.length; i++) { - try { - if (i == 3 && _qz.websocket.connection.semver[i].toLowerCase().indexOf("rc") == 0) { - // Handle "rc1" pre-release by negating build info - _qz.websocket.connection.semver[i] = -(_qz.websocket.connection.semver[i].replace(/\D/g, "")); - continue; - } - _qz.websocket.connection.semver[i] = parseInt(_qz.websocket.connection.semver[i]); - } - catch(ignore) {} - - if (_qz.websocket.connection.semver.length < 4) { - _qz.websocket.connection.semver[3] = 0; - } - } - - //algorithm can be declared before a connection, check for incompatibilities now that we have one - _qz.compatible.algorithm(true); - }).then(function() { - _qz.websocket.connection.sendData({ certificate: cert, promise: openPromise }); - }); - } - - _qz.security.callCert().then(sendCert).catch(function(error) { - _qz.log.warn("Failed to get certificate:", error); - - if (_qz.security.rejectOnCertFailure) { - openPromise.reject(error); - } else { - sendCert(null); - } - }); - }, - - /** Generate unique ID used to map a response to a call. */ - newUID: function() { - var len = 6; - return (new Array(len + 1).join("0") + (Math.random() * Math.pow(36, len) << 0).toString(36)).slice(-len) - } - }, - - dataPromise: function(callName, params, signature, signingTimestamp) { - return _qz.tools.promise(function(resolve, reject) { - var msg = { - call: callName, - promise: { resolve: resolve, reject: reject }, - params: params, - signature: signature, - timestamp: signingTimestamp - }; - - _qz.websocket.connection.sendData(msg); - }); - }, - - /** Library of promises awaiting a response, uid -> promise */ - pendingCalls: {}, - - /** List of functions to call on error from the websocket. */ - errorCallbacks: [], - /** Calls all functions registered to listen for errors. */ - callError: function(evt) { - if (Array.isArray(_qz.websocket.errorCallbacks)) { - for(var i = 0; i < _qz.websocket.errorCallbacks.length; i++) { - _qz.websocket.errorCallbacks[i](evt); - } - } else { - _qz.websocket.errorCallbacks(evt); - } - }, - - /** List of function to call on closing from the websocket. */ - closedCallbacks: [], - /** Calls all functions registered to listen for closing. */ - callClose: function(evt) { - if (Array.isArray(_qz.websocket.closedCallbacks)) { - for(var i = 0; i < _qz.websocket.closedCallbacks.length; i++) { - _qz.websocket.closedCallbacks[i](evt); - } - } else { - _qz.websocket.closedCallbacks(evt); - } - } - }, - - - printing: { - /** Default options used for new printer configs. Can be overridden using {@link qz.configs.setDefaults}. */ - defaultConfig: { - //value purposes are explained in the qz.configs.setDefaults docs - - bounds: null, - colorType: 'color', - copies: 1, - density: 0, - duplex: false, - fallbackDensity: null, - interpolation: 'bicubic', - jobName: null, - legacy: false, - margins: 0, - orientation: null, - paperThickness: null, - printerTray: null, - rasterize: false, - rotation: 0, - scaleContent: true, - size: null, - units: 'in', - - forceRaw: false, - encoding: null, - spool: null - } - }, - - - serial: { - /** List of functions called when receiving data from serial connection. */ - serialCallbacks: [], - /** Calls all functions registered to listen for serial events. */ - callSerial: function(streamEvent) { - if (Array.isArray(_qz.serial.serialCallbacks)) { - for(var i = 0; i < _qz.serial.serialCallbacks.length; i++) { - _qz.serial.serialCallbacks[i](streamEvent); - } - } else { - _qz.serial.serialCallbacks(streamEvent); - } - } - }, - - - socket: { - /** List of functions called when receiving data from network socket connection. */ - socketCallbacks: [], - /** Calls all functions registered to listen for network socket events. */ - callSocket: function(socketEvent) { - if (Array.isArray(_qz.socket.socketCallbacks)) { - for(var i = 0; i < _qz.socket.socketCallbacks.length; i++) { - _qz.socket.socketCallbacks[i](socketEvent); - } - } else { - _qz.socket.socketCallbacks(socketEvent); - } - } - }, - - - usb: { - /** List of functions called when receiving data from usb connection. */ - usbCallbacks: [], - /** Calls all functions registered to listen for usb events. */ - callUsb: function(streamEvent) { - if (Array.isArray(_qz.usb.usbCallbacks)) { - for(var i = 0; i < _qz.usb.usbCallbacks.length; i++) { - _qz.usb.usbCallbacks[i](streamEvent); - } - } else { - _qz.usb.usbCallbacks(streamEvent); - } - } - }, - - - hid: { - /** List of functions called when receiving data from hid connection. */ - hidCallbacks: [], - /** Calls all functions registered to listen for hid events. */ - callHid: function(streamEvent) { - if (Array.isArray(_qz.hid.hidCallbacks)) { - for(var i = 0; i < _qz.hid.hidCallbacks.length; i++) { - _qz.hid.hidCallbacks[i](streamEvent); - } - } else { - _qz.hid.hidCallbacks(streamEvent); - } - } - }, - - - printers: { - /** List of functions called when receiving data from printer connection. */ - printerCallbacks: [], - /** Calls all functions registered to listen for printer events. */ - callPrinter: function(streamEvent) { - if (Array.isArray(_qz.printers.printerCallbacks)) { - for(var i = 0; i < _qz.printers.printerCallbacks.length; i++) { - _qz.printers.printerCallbacks[i](streamEvent); - } - } else { - _qz.printers.printerCallbacks(streamEvent); - } - } - }, - - - file: { - /** List of functions called when receiving info regarding file changes. */ - fileCallbacks: [], - /** Calls all functions registered to listen for file events. */ - callFile: function(streamEvent) { - if (Array.isArray(_qz.file.fileCallbacks)) { - for(var i = 0; i < _qz.file.fileCallbacks.length; i++) { - _qz.file.fileCallbacks[i](streamEvent); - } - } else { - _qz.file.fileCallbacks(streamEvent); - } - } - }, - - - security: { - /** Function used to resolve promise when acquiring site's public certificate. */ - certHandler: function(resolve, reject) { reject(); }, - /** Called to create new promise (using {@link _qz.security.certHandler}) for certificate retrieval. */ - callCert: function() { - if (typeof _qz.security.certHandler.then === 'function') { - //already a promise - return _qz.security.certHandler; - } else if (_qz.security.certHandler.constructor.name === "AsyncFunction") { - //already callable as a promise - return _qz.security.certHandler(); - } else { - //turn into a promise - return _qz.tools.promise(_qz.security.certHandler); - } - }, - - /** Function used to create promise resolver when requiring signed calls. */ - signatureFactory: function() { return function(resolve) { resolve(); } }, - /** Called to create new promise (using {@link _qz.security.signatureFactory}) for signed calls. */ - callSign: function(toSign) { - if (_qz.security.signatureFactory.constructor.name === "AsyncFunction") { - //use directly - return _qz.security.signatureFactory(toSign); - } else { - //use in a promise - return _qz.tools.promise(_qz.security.signatureFactory(toSign)); - } - }, - - /** Signing algorithm used on signatures */ - signAlgorithm: "SHA1", - - rejectOnCertFailure: false, - - needsSigned: function(callName) { - const undialoged = [ - "printers.getStatus", - "printers.stopListening", - "usb.isClaimed", - "usb.closeStream", - "usb.releaseDevice", - "hid.stopListening", - "hid.isClaimed", - "hid.closeStream", - "hid.releaseDevice", - "file.stopListening", - "getVersion" - ]; - - return callName != null && undialoged.indexOf(callName) === -1; - } - }, - - - tools: { - /** Create a new promise */ - promise: function(resolver) { - //prefer global object for historical purposes - if (typeof RSVP !== 'undefined') { - return new RSVP.Promise(resolver); - } else if (typeof Promise !== 'undefined') { - return new Promise(resolver); - } else { - _qz.log.error("Promise/A+ support is required. See qz.api.setPromiseType(...)"); - } - }, - - /** Stub for rejecting with an Error from withing a Promise */ - reject: function(error) { - return _qz.tools.promise(function(resolve, reject) { - reject(error); - }); - }, - - stringify: function(object) { - //old versions of prototype affect stringify - var pjson = Array.prototype.toJSON; - delete Array.prototype.toJSON; - - function skipKeys(key, value) { - if (key === "promise") { - return undefined; - } - - return value; - } - - var result = JSON.stringify(object, skipKeys); - - if (pjson) { - Array.prototype.toJSON = pjson; - } - - return result; - }, - - hash: function(data) { - //prefer global object for historical purposes - if (typeof Sha256 !== 'undefined') { - return Sha256.hash(data); - } else { - return _qz.SHA.hash(data); - } - }, - - ws: typeof WebSocket !== 'undefined' ? WebSocket : null, - - absolute: function(loc) { - if (typeof window !== 'undefined' && typeof document.createElement === 'function') { - var a = document.createElement("a"); - a.href = loc; - return a.href; - } else if (typeof exports === 'object') { - //node.js - require('path').resolve(loc); - } - return loc; - }, - - relative: function(data) { - for(var i = 0; i < data.length; i++) { - if (data[i].constructor === Object) { - var absolute = false; - - if (data[i].data && data[i].data.search && data[i].data.search(/data:image\/\w+;base64,/) === 0) { - //upgrade from old base64 behavior - data[i].flavor = "base64"; - data[i].data = data[i].data.replace(/^data:image\/\w+;base64,/, ""); - } else if (data[i].flavor) { - //if flavor is known, we can directly check for absolute flavor types - if (["FILE", "XML"].indexOf(data[i].flavor.toUpperCase()) > -1) { - absolute = true; - } - } else if (data[i].format && ["HTML", "IMAGE", "PDF", "FILE", "XML"].indexOf(data[i].format.toUpperCase()) > -1) { - //if flavor is not known, all valid pixel formats default to file flavor - //previous v2.0 data also used format as what is now flavor, so we check for those values here too - absolute = true; - } else if (data[i].type && ((["PIXEL", "IMAGE", "PDF"].indexOf(data[i].type.toUpperCase()) > -1 && !data[i].format) - || (["HTML", "PDF"].indexOf(data[i].type.toUpperCase()) > -1 && (!data[i].format || data[i].format.toUpperCase() === "FILE")))) { - //if all we know is pixel type, then it is image's file flavor - //previous v2.0 data also used type as what is now format, so we check for those value here too - absolute = true; - } - - if (absolute) { - //change relative links to absolute - data[i].data = _qz.tools.absolute(data[i].data); - } - if (data[i].options && typeof data[i].options.overlay === 'string') { - data[i].options.overlay = _qz.tools.absolute(data[i].options.overlay); - } - } - } - }, - - /** Performs deep copy to target from remaining params */ - extend: function(target) { - //special case when reassigning properties as objects in a deep copy - if (typeof target !== 'object') { - target = {}; - } - - for(var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - if (!source) { continue; } - - for(var key in source) { - if (source.hasOwnProperty(key)) { - if (target === source[key]) { continue; } - - if (source[key] && source[key].constructor && source[key].constructor === Object) { - var clone; - if (Array.isArray(source[key])) { - clone = target[key] || []; - } else { - clone = target[key] || {}; - } - - target[key] = _qz.tools.extend(clone, source[key]); - } else if (source[key] !== undefined) { - target[key] = source[key]; - } - } - } - } - - return target; - }, - - versionCompare: function(major, minor, patch, build) { - if (_qz.tools.assertActive()) { - var semver = _qz.websocket.connection.semver; - if(Array.isArray(semver)) { - if (major != undefined && semver.length > 0 && semver[0] != major) { - return semver[0] - major; - } - if (minor != undefined && semver.length > 1 && semver[1] != minor) { - return semver[1] - minor; - } - if (patch != undefined && semver.length > 2 && semver[2] != patch) { - return semver[2] - patch; - } - if (build != undefined && semver.length > 3 && semver[3] != build) { - return Number.isInteger(semver[3]) && Number.isInteger(build) ? semver[3] - build : semver[3].toString().localeCompare(build.toString()); - } - } - return 0; - } - }, - - isVersion: function(major, minor, patch, build) { - return _qz.tools.versionCompare(major, minor, patch, build) == 0; - }, - - isActive: function() { - return !_qz.websocket.shutdown && _qz.websocket.connection != null - && (_qz.websocket.connection.readyState === _qz.tools.ws.OPEN - || _qz.websocket.connection.readyState === _qz.tools.ws.CONNECTING); - }, - - assertActive: function() { - if (_qz.tools.isActive()) { - return true; - } - // Promise won't reject on throw; yet better than 'undefined' - throw new Error("A connection to QZ has not been established yet"); - }, - - uint8ArrayToHex: function(uint8) { - return Array.from(uint8) - .map(function(i) { return i.toString(16).padStart(2, '0'); }) - .join(''); - }, - - uint8ArrayToBase64: function(uint8) { - /** - * Adapted from Egor Nepomnyaschih's code under MIT Licence (C) 2020 - * see https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727 - */ - var map = [ - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", - "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", - "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/" - ]; - - var result = '', i, l = uint8.length; - for (i = 2; i < l; i += 3) { - result += map[uint8[i - 2] >> 2]; - result += map[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)]; - result += map[((uint8[i - 1] & 0x0F) << 2) | (uint8[i] >> 6)]; - result += map[uint8[i] & 0x3F]; - } - if (i === l + 1) { // 1 octet yet to write - result += map[uint8[i - 2] >> 2]; - result += map[(uint8[i - 2] & 0x03) << 4]; - result += "=="; - } - if (i === l) { // 2 octets yet to write - result += map[uint8[i - 2] >> 2]; - result += map[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)]; - result += map[(uint8[i - 1] & 0x0F) << 2]; - result += "="; - } - return result; - }, - }, - - compatible: { - /** Converts message format to a previous version's */ - data: function(printData) { - // special handling for Uint8Array - for(var i = 0; i < printData.length; i++) { - if (printData[i].constructor === Object && printData[i].data instanceof Uint8Array) { - if (printData[i].flavor) { - var flavor = printData[i].flavor.toString().toUpperCase(); - switch(flavor) { - case 'BASE64': - printData[i].data = _qz.tools.uint8ArrayToBase64(printData[i].data); - break; - case 'HEX': - printData[i].data = _qz.tools.uint8ArrayToHex(printData[i].data); - break; - default: - throw new Error("Uint8Array conversion to '" + flavor + "' is not supported."); - } - } - } - } - - if(_qz.tools.versionCompare(2, 2, 4) < 0) { - for(var i = 0; i < printData.length; i++) { - if (printData[i].constructor === Object) { - // dotDensity: "double-legacy|single-legacy" since 2.2.4. Fallback to "double|single" - if (printData[i].options && typeof printData[i].options.dotDensity === 'string') { - printData[i].options.dotDensity = printData[i].options.dotDensity.toLowerCase().replace("-legacy", ""); - } - } - } - } - - if (_qz.tools.isVersion(2, 0)) { - /* - 2.0.x conversion - ----- - type=pixel -> use format as 2.0 type (unless 'command' format, which forces 2.0 'raw' type) - type=raw -> 2.0 type has to be 'raw' - if format is 'image' -> force 2.0 'image' format, ignore everything else (unsupported in 2.0) - - flavor translates straight to 2.0 format (unless forced to 'raw'/'image') - */ - _qz.log.trace("Converting print data to v2.0 for " + _qz.websocket.connection.version); - for(var i = 0; i < printData.length; i++) { - if (printData[i].constructor === Object) { - if (printData[i].type && printData[i].type.toUpperCase() === "RAW" && printData[i].format && printData[i].format.toUpperCase() === "IMAGE") { - if (printData[i].flavor && printData[i].flavor.toUpperCase() === "BASE64") { - //special case for raw base64 images - printData[i].data = "data:image/compat;base64," + printData[i].data; - } - printData[i].flavor = "IMAGE"; //forces 'image' format when shifting for conversion - } - if ((printData[i].type && printData[i].type.toUpperCase() === "RAW") || (printData[i].format && printData[i].format.toUpperCase() === "COMMAND")) { - printData[i].format = "RAW"; //forces 'raw' type when shifting for conversion - } - - printData[i].type = printData[i].format; - printData[i].format = printData[i].flavor; - delete printData[i].flavor; - } - } - } - }, - - /* Converts config defaults to match previous version */ - config: function(config, dirty) { - if (_qz.tools.isVersion(2, 0)) { - if (!dirty.rasterize) { - config.rasterize = true; - } - } - if(_qz.tools.versionCompare(2, 2) < 0) { - if(config.forceRaw !== 'undefined') { - config.altPrinting = config.forceRaw; - delete config.forceRaw; - } - } - if(_qz.tools.versionCompare(2, 1, 2, 11) < 0) { - if(config.spool) { - if(config.spool.size) { - config.perSpool = config.spool.size; - delete config.spool.size; - } - if(config.spool.end) { - config.endOfDoc = config.spool.end; - delete config.spool.end; - } - delete config.spool; - } - } - return config; - }, - - /** Compat wrapper with previous version **/ - networking: function(hostname, port, signature, signingTimestamp, mappingCallback) { - // Use 2.0 - if (_qz.tools.isVersion(2, 0)) { - return _qz.tools.promise(function(resolve, reject) { - _qz.websocket.dataPromise('websocket.getNetworkInfo', { - hostname: hostname, - port: port - }, signature, signingTimestamp).then(function(data) { - if (typeof mappingCallback !== 'undefined') { - resolve(mappingCallback(data)); - } else { - resolve(data); - } - }, reject); - }); - } - // Wrap 2.1 - return _qz.tools.promise(function(resolve, reject) { - _qz.websocket.dataPromise('networking.device', { - hostname: hostname, - port: port - }, signature, signingTimestamp).then(function(data) { - resolve({ ipAddress: data.ip, macAddress: data.mac }); - }, reject); - }); - }, - - /** Check if QZ version supports chosen algorithm */ - algorithm: function(quiet) { - //if not connected yet we will assume compatibility exists for the time being - //check semver to guard race condition for pending connections - if (_qz.tools.isActive() && _qz.websocket.connection.semver) { - if (_qz.tools.isVersion(2, 0)) { - if (!quiet) { - _qz.log.warn("Connected to an older version of QZ, alternate signature algorithms are not supported"); - } - return false; - } - } - - return true; - } - }, - - /** - * Adapted from Chris Veness's code under MIT Licence (C) 2002 - * see http://www.movable-type.co.uk/scripts/sha256.html - */ - SHA: { - //@formatter:off - keep this block compact - hash: function(msg) { - // add trailing '1' bit (+ 0's padding) to string [§5.1.1] - msg = _qz.SHA._utf8Encode(msg) + String.fromCharCode(0x80); - - // constants [§4.2.2] - var K = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - ]; - // initial hash value [§5.3.1] - var H = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ]; - - // convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1] - var l = msg.length / 4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length - var N = Math.ceil(l / 16); // number of 16-integer-blocks required to hold 'l' ints - var M = new Array(N); - - for(var i = 0; i < N; i++) { - M[i] = new Array(16); - for(var j = 0; j < 16; j++) { // encode 4 chars per integer, big-endian encoding - M[i][j] = (msg.charCodeAt(i * 64 + j * 4) << 24) | (msg.charCodeAt(i * 64 + j * 4 + 1) << 16) | - (msg.charCodeAt(i * 64 + j * 4 + 2) << 8) | (msg.charCodeAt(i * 64 + j * 4 + 3)); - } // note running off the end of msg is ok 'cos bitwise ops on NaN return 0 - } - // add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1] - // note: most significant word would be (len-1)*8 >>> 32, but since JS converts - // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators - M[N-1][14] = ((msg.length - 1) * 8) / Math.pow(2, 32); - M[N-1][14] = Math.floor(M[N-1][14]); - M[N-1][15] = ((msg.length - 1) * 8) & 0xffffffff; - - // HASH COMPUTATION [§6.1.2] - var W = new Array(64); var a, b, c, d, e, f, g, h; - for(var i = 0; i < N; i++) { - // 1 - prepare message schedule 'W' - for(var t = 0; t < 16; t++) { W[t] = M[i][t]; } - for(var t = 16; t < 64; t++) { W[t] = (_qz.SHA._dev1(W[t-2]) + W[t-7] + _qz.SHA._dev0(W[t-15]) + W[t-16]) & 0xffffffff; } - // 2 - initialise working variables a, b, c, d, e, f, g, h with previous hash value - a = H[0]; b = H[1]; c = H[2]; d = H[3]; e = H[4]; f = H[5]; g = H[6]; h = H[7]; - // 3 - main loop (note 'addition modulo 2^32') - for(var t = 0; t < 64; t++) { - var T1 = h + _qz.SHA._sig1(e) + _qz.SHA._ch(e, f, g) + K[t] + W[t]; - var T2 = _qz.SHA._sig0(a) + _qz.SHA._maj(a, b, c); - h = g; g = f; f = e; e = (d + T1) & 0xffffffff; - d = c; c = b; b = a; a = (T1 + T2) & 0xffffffff; - } - // 4 - compute the new intermediate hash value (note 'addition modulo 2^32') - H[0] = (H[0]+a) & 0xffffffff; H[1] = (H[1]+b) & 0xffffffff; H[2] = (H[2]+c) & 0xffffffff; H[3] = (H[3]+d) & 0xffffffff; - H[4] = (H[4]+e) & 0xffffffff; H[5] = (H[5]+f) & 0xffffffff; H[6] = (H[6]+g) & 0xffffffff; H[7] = (H[7]+h) & 0xffffffff; - } - - return _qz.SHA._hexStr(H[0]) + _qz.SHA._hexStr(H[1]) + _qz.SHA._hexStr(H[2]) + _qz.SHA._hexStr(H[3]) + - _qz.SHA._hexStr(H[4]) + _qz.SHA._hexStr(H[5]) + _qz.SHA._hexStr(H[6]) + _qz.SHA._hexStr(H[7]); - }, - - // Rotates right (circular right shift) value x by n positions - _rotr: function(n, x) { return (x >>> n) | (x << (32 - n)); }, - // logical functions - _sig0: function(x) { return _qz.SHA._rotr(2, x) ^ _qz.SHA._rotr(13, x) ^ _qz.SHA._rotr(22, x); }, - _sig1: function(x) { return _qz.SHA._rotr(6, x) ^ _qz.SHA._rotr(11, x) ^ _qz.SHA._rotr(25, x); }, - _dev0: function(x) { return _qz.SHA._rotr(7, x) ^ _qz.SHA._rotr(18, x) ^ (x >>> 3); }, - _dev1: function(x) { return _qz.SHA._rotr(17, x) ^ _qz.SHA._rotr(19, x) ^ (x >>> 10); }, - _ch: function(x, y, z) { return (x & y) ^ (~x & z); }, - _maj: function(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); }, - // note can't use toString(16) as it is implementation-dependant, and in IE returns signed numbers when used on full words - _hexStr: function(n) { var s = "", v; for(var i = 7; i >= 0; i--) { v = (n >>> (i * 4)) & 0xf; s += v.toString(16); } return s; }, - // implementation of deprecated unescape() based on https://cwestblog.com/2011/05/23/escape-unescape-deprecated/ (and comments) - _unescape: function(str) { - return str.replace(/%(u[\da-f]{4}|[\da-f]{2})/gi, function(seq) { - if (seq.length - 1) { - return String.fromCharCode(parseInt(seq.substring(seq.length - 3 ? 2 : 1), 16)) - } else { - var code = seq.charCodeAt(0); - return code < 256 ? "%" + (0 + code.toString(16)).slice(-2).toUpperCase() : "%u" + ("000" + code.toString(16)).slice(-4).toUpperCase() - } - }); - }, - _utf8Encode: function(str) { - return _qz.SHA._unescape(encodeURIComponent(str)); - } - //@formatter:on - }, - }; - - -///// CONFIG CLASS //// - - /** Object to handle configured printer options. */ - function Config(printer, opts) { - - this.config = _qz.tools.extend({}, _qz.printing.defaultConfig); //create a copy of the default options - this._dirtyOpts = {}; //track which config options have changed from the defaults - - /** - * Set the printer assigned to this config. - * @param {string|Object} newPrinter Name of printer. Use object type to specify printing to file or host. - * @param {string} [newPrinter.name] Name of printer to send printing. - * @param {string} [newPrinter.file] DEPRECATED: Name of file to send printing. - * @param {string} [newPrinter.host] IP address or host name to send printing. - * @param {string} [newPrinter.port] Port used by <printer.host>. - */ - this.setPrinter = function(newPrinter) { - if (typeof newPrinter === 'string') { - newPrinter = { name: newPrinter }; - } - this.printer = newPrinter; - }; - - /** - * @returns {Object} The printer currently assigned to this config. - */ - this.getPrinter = function() { - return this.printer; - }; - - /** - * Alter any of the printer options currently applied to this config. - * @param newOpts {Object} The options to change. See qz.configs.setDefaults docs for available values. - * - * @see qz.configs.setDefaults - */ - this.reconfigure = function(newOpts) { - for(var key in newOpts) { - if (newOpts[key] !== undefined) { - this._dirtyOpts[key] = true; - } - } - - _qz.tools.extend(this.config, newOpts); - }; - - /** - * @returns {Object} The currently applied options on this config. - */ - this.getOptions = function() { - return _qz.compatible.config(this.config, this._dirtyOpts); - }; - - // init calls for new config object - this.setPrinter(printer); - this.reconfigure(opts); - } - - /** - * Shortcut method for calling qz.print with a particular config. - * @param {Array} data Array of data being sent to the printer. See qz.print docs for available values. - * @param {boolean} [signature] Pre-signed signature of JSON string containing call, params, and timestamp. - * @param {number} [signingTimestamp] Required with signature. Timestamp used with pre-signed content. - * - * @example - * qz.print(myConfig, ...); // OR - * myConfig.print(...); - * - * @see qz.print - */ - Config.prototype.print = function(data, signature, signingTimestamp) { - qz.print(this, data, signature, signingTimestamp); - }; - - -///// PUBLIC METHODS ///// - - /** @namespace qz */ - var qz = { - - /** - * Calls related specifically to the web socket connection. - * @namespace qz.websocket - */ - websocket: { - /** - * Check connection status. Active connection is necessary for other calls to run. - * - * @returns {boolean} If there is an active connection with QZ Tray. - * - * @see connect - * - * @memberof qz.websocket - */ - isActive: function() { - return _qz.tools.isActive(); - }, - - /** - * Call to setup connection with QZ Tray on user's system. - * - * @param {Object} [options] Configuration options for the web socket connection. - * @param {string|Array} [options.host=['localhost', 'localhost.qz.io']] Host running the QZ Tray software. - * @param {Object} [options.port] Config options for ports to cycle. - * @param {Array} [options.port.secure=[8181, 8282, 8383, 8484]] Array of secure (WSS) ports to try - * @param {Array} [options.port.insecure=[8182, 8283, 8384, 8485]] Array of insecure (WS) ports to try - * @param {boolean} [options.usingSecure=true] If the web socket should try to use secure ports for connecting. - * @param {number} [options.keepAlive=60] Seconds between keep-alive pings to keep connection open. Set to 0 to disable. - * @param {number} [options.retries=0] Number of times to reconnect before failing. - * @param {number} [options.delay=0] Seconds before firing a connection. Ignored if options.retries is 0. - * - * @returns {Promise} - * - * @memberof qz.websocket - */ - connect: function(options) { - return _qz.tools.promise(function(resolve, reject) { - if (_qz.websocket.connection) { - const state = _qz.websocket.connection.readyState; - - if (state === _qz.tools.ws.OPEN) { - reject(new Error("An open connection with QZ Tray already exists")); - return; - } else if (state === _qz.tools.ws.CONNECTING) { - reject(new Error("The current connection attempt has not returned yet")); - return; - } else if (state === _qz.tools.ws.CLOSING) { - reject(new Error("Waiting for previous disconnect request to complete")); - return; - } - } - - if (!_qz.tools.ws) { - reject(new Error("WebSocket not supported by this browser")); - return; - } else if (!_qz.tools.ws.CLOSED || _qz.tools.ws.CLOSED == 2) { - reject(new Error("Unsupported WebSocket version detected: HyBi-00/Hixie-76")); - return; - } - - //ensure some form of options exists for value checks - if (options == undefined) { options = {}; } - - //disable secure ports if page is not secure - if (typeof location === 'undefined' || location.protocol !== 'https:') { - //respect forcing secure ports if it is defined, otherwise disable - if (typeof options.usingSecure === 'undefined') { - _qz.log.trace("Disabling secure ports due to insecure page"); - options.usingSecure = false; - } - } - - //ensure any hosts are passed to internals as an array - if (typeof options.host !== 'undefined' && !Array.isArray(options.host)) { - options.host = [options.host]; - } - - _qz.websocket.shutdown = false; //reset state for new connection attempt - var attempt = function(count) { - var tried = false; - var nextAttempt = function() { - if (!tried) { - tried = true; - - if (options && count < options.retries) { - attempt(count + 1); - } else { - _qz.websocket.connection = null; - reject.apply(null, arguments); - } - } - }; - - var delayed = function() { - var config = _qz.tools.extend({}, _qz.websocket.connectConfig, options); - _qz.websocket.setup.findConnection(config, resolve, nextAttempt) - }; - if (count == 0) { - delayed(); // only retries will be called with a delay - } else { - setTimeout(delayed, options.delay * 1000); - } - }; - - attempt(0); - }); - }, - - /** - * Stop any active connection with QZ Tray. - * - * @returns {Promise} - * - * @memberof qz.websocket - */ - disconnect: function() { - return _qz.tools.promise(function(resolve, reject) { - if (_qz.websocket.connection != null) { - if (_qz.tools.isActive()) { - // handles closing both 'connecting' and 'connected' states - _qz.websocket.shutdown = true; - _qz.websocket.connection.promise = { resolve: resolve, reject: reject }; - _qz.websocket.connection.close(); - } else { - reject(new Error("Current connection is still closing")); - } - } else { - reject(new Error("No open connection with QZ Tray")); - } - }); - }, - - /** - * List of functions called for any connections errors outside of an API call.

- * Also called if {@link websocket#connect} fails to connect. - * - * @param {Function|Array} calls Single or array of Function({Event} event) calls. - * - * @memberof qz.websocket - */ - setErrorCallbacks: function(calls) { - _qz.websocket.errorCallbacks = calls; - }, - - /** - * List of functions called for any connection closing event outside of an API call.

- * Also called when {@link websocket#disconnect} is called. - * - * @param {Function|Array} calls Single or array of Function({Event} event) calls. - * - * @memberof qz.websocket - */ - setClosedCallbacks: function(calls) { - _qz.websocket.closedCallbacks = calls; - }, - - /** - * @deprecated Since 2.1.0. Please use qz.networking.device() instead - * - * @param {string} [hostname] Hostname to try to connect to when determining network interfaces, defaults to "google.com" - * @param {number} [port] Port to use with custom hostname, defaults to 443 - * @param {string} [signature] Pre-signed signature of hashed JSON string containing call='websocket.getNetworkInfo', params object, and timestamp. - * @param {number} [signingTimestamp] Required with signature. Timestamp used with pre-signed content. - * - * @returns {Promise|Error>} Connected system's network information. - * - * @memberof qz.websocket - */ - getNetworkInfo: _qz.compatible.networking, - - /** - * @returns {Object<{socket: String, host: String, port: Number}>} Details of active websocket connection - * - * @memberof qz.websocket - */ - getConnectionInfo: function() { - if (_qz.tools.assertActive()) { - var url = _qz.websocket.connection.url.split(/[:\/]+/g); - return { socket: url[0], host: url[1], port: +url[2] }; - } - } - }, - - - /** - * Calls related to getting printer information from the connection. - * @namespace qz.printers - */ - printers: { - /** - * @param {string} [signature] Pre-signed signature of hashed JSON string containing call='printers.getDefault, params, and timestamp. - * @param {number} [signingTimestamp] Required with signature. Timestamp used with pre-signed content. - * - * @returns {Promise} Name of the connected system's default printer. - * - * @memberof qz.printers - */ - getDefault: function(signature, signingTimestamp) { - return _qz.websocket.dataPromise('printers.getDefault', null, signature, signingTimestamp); - }, - - /** - * @param {string} [query] Search for a specific printer. All printers are returned if not provided. - * @param {string} [signature] Pre-signed signature of hashed JSON string containing call='printers.find', params, and timestamp. - * @param {number} [signingTimestamp] Required with signature. Timestamp used with pre-signed content. - * - * @returns {Promise|string|Error>} The matched printer name if query is provided. - * Otherwise an array of printer names found on the connected system. - * - * @memberof qz.printers - */ - find: function(query, signature, signingTimestamp) { - return _qz.websocket.dataPromise('printers.find', { query: query }, signature, signingTimestamp); - }, - - /** - * Provides a list, with additional information, for each printer available to QZ. - * - * @returns {Promise|Object|Error>} - * - * @memberof qz.printers - */ - details: function() { - return _qz.websocket.dataPromise('printers.detail'); - }, - - /** - * Start listening for printer status events, such as paper_jam events. - * Reported under the ACTION type in the streamEvent on callbacks. - * - * @returns {Promise} - * @since 2.1.0 - * - * @see qz.printers.setPrinterCallbacks - * - * @param {null|string|Array} printers Printer or list of printers to listen to, null listens to all. - * @param {Object|null} [options] Printer listener options - * @param {null|boolean} [options.jobData=false] Flag indicating if raw spool file content should be return as well as status information (Windows only) - * @param {null|number} [options.maxJobData=-1] Maximum number of bytes to returns for raw spooled file content (Windows only) - * @param {null|string} [options.flavor="plain"] Flavor of data format returned. Valid flavors are [base64 | hex | plain*] (Windows only) - * - * @memberof qz.printers - */ - startListening: function(printers, options) { - if (!Array.isArray(printers)) { - printers = [printers]; - } - var params = { - printerNames: printers - }; - if (options && options.jobData == true) params.jobData = true; - if (options && options.maxJobData) params.maxJobData = options.maxJobData; - if (options && options.flavor) params.flavor = options.flavor; - return _qz.websocket.dataPromise('printers.startListening', params); - }, - - /** - * Clear the queue of a specified printer or printers. Does not delete retained jobs. - * - * @param {string|Object} [options] Name of printer to clear - * @param {string} [options.printerName] Name of printer to clear - * @param {number} [options.jobId] Cancel a job of a specific JobId instead of canceling all. Must include a printerName. - * - * @returns {Promise} - * @since 2.2.4 - * - * @memberof qz.printers - */ - clearQueue: function(options) { - if (typeof options !== 'object') { - options = { - printerName: options - }; - } - return _qz.websocket.dataPromise('printers.clearQueue', options); - }, - - /** - * Stop listening for printer status actions. - * - * @returns {Promise} - * @since 2.1.0 - * - * @see qz.printers.setPrinterCallbacks - * - * @memberof qz.printers - */ - stopListening: function() { - return _qz.websocket.dataPromise('printers.stopListening'); - }, - - /** - * Retrieve current printer status from any active listeners. - * - * @returns {Promise} - * @since 2.1.0 - * - * @see qz.printers.startListening - * - * @memberof qz.printers - */ - getStatus: function() { - return _qz.websocket.dataPromise('printers.getStatus'); - }, - - /** - * List of functions called for any printer status change. - * Event data will contain {string} printerName and {string} status for all types. - * For RECEIVE types, {Array} output (in hexadecimal format). - * For ERROR types, {string} exception. - * For ACTION types, {string} actionType. - * - * @param {Function|Array} calls Single or array of Function({Object} eventData) calls. - * @since 2.1.0 - * - * @memberof qz.printers - */ - setPrinterCallbacks: function(calls) { - _qz.printers.printerCallbacks = calls; - } - }, - - /** - * Calls related to setting up new printer configurations. - * @namespace qz.configs - */ - configs: { - /** - * Default options used by new configs if not overridden. - * Setting a value to NULL will use the printer's default options. - * Updating these will not update the options on any created config. - * - * @param {Object} options Default options used by printer configs if not overridden. - * - * @param {Object} [options.bounds=null] Bounding box rectangle. - * @param {number} [options.bounds.x=0] Distance from left for bounding box starting corner - * @param {number} [options.bounds.y=0] Distance from top for bounding box starting corner - * @param {number} [options.bounds.width=0] Width of bounding box - * @param {number} [options.bounds.height=0] Height of bounding box - * @param {string} [options.colorType='color'] Valid values [color | grayscale | blackwhite | default] - * @param {number} [options.copies=1] Number of copies to be printed. - * @param {number|Array|Object|Array|string} [options.density=0] Pixel density (DPI, DPMM, or DPCM depending on [options.units]). - * If provided as an array, uses the first supported density found (or the first entry if none found). - * If provided as a string, valid values are [best | draft], corresponding to highest or lowest reported density respectively. - * @param {number} [options.density.cross=0] Asymmetric pixel density for the cross feed direction. - * @param {number} [options.density.feed=0] Asymmetric pixel density for the feed direction. - * @param {boolean|string} [options.duplex=false] Double sided printing, Can specify duplex style by passing a string value: [one-sided | duplex | long-edge | tumble | short-edge] - * @param {number} [options.fallbackDensity=null] Value used when default density value cannot be read, or in cases where reported as "Normal" by the driver, (in DPI, DPMM, or DPCM depending on [options.units]). - * @param {string} [options.interpolation='bicubic'] Valid values [bicubic | bilinear | nearest-neighbor]. Controls how images are handled when resized. - * @param {string} [options.jobName=null] Name to display in print queue. - * @param {boolean} [options.legacy=false] If legacy style printing should be used. - * @param {Object|number} [options.margins=0] If just a number is provided, it is used as the margin for all sides. - * @param {number} [options.margins.top=0] - * @param {number} [options.margins.right=0] - * @param {number} [options.margins.bottom=0] - * @param {number} [options.margins.left=0] - * @param {string} [options.orientation=null] Valid values [portrait | landscape | reverse-landscape | null]. - * If set to null, orientation will be determined automatically. - * @param {number} [options.paperThickness=null] - * @param {string|number} [options.printerTray=null] Printer tray to pull from. The number N assumes string equivalent of 'Tray N'. Uses printer default if NULL. - * @param {boolean} [options.rasterize=false] Whether documents should be rasterized before printing. - * Specifying [options.density] for PDF print formats will set this to true. - * @param {number} [options.rotation=0] Image rotation in degrees. - * @param {boolean} [options.scaleContent=true] Scales print content to page size, keeping ratio. - * @param {Object} [options.size=null] Paper size. - * @param {number} [options.size.width=null] Page width. - * @param {number} [options.size.height=null] Page height. - * @param {string} [options.units='in'] Page units, applies to paper size, margins, and density. Valid value [in | cm | mm] - * - * @param {boolean} [options.forceRaw=false] Print the specified raw data using direct method, skipping the driver. Not yet supported on Windows. - * @param {string|Object} [options.encoding=null] Character set for commands. Can be provided as an object for converting encoding types for RAW types. - * @param {string} [options.encoding.from] If this encoding type is provided, RAW type commands will be parsed from this for the purpose of being converted to the encoding.to value. - * @param {string} [options.encoding.to] Encoding RAW type commands will be converted into. If encoding.from is not provided, this will be treated as if a string was passed for encoding. - * @param {string} [options.endOfDoc=null] DEPRECATED Raw only: Character(s) denoting end of a page to control spooling. - * @param {number} [options.perSpool=1] DEPRECATED: Raw only: Number of pages per spool. - * @param {boolean} [options.retainTemp=false] Retain any temporary files used. Ignored unless forceRaw true. - * @param {Object} [options.spool=null] Advanced spooling options. - * @param {number} [options.spool.size=null] Number of pages per spool. Default is no limit. If spool.end is provided, defaults to 1 - * @param {string} [options.spool.end=null] Raw only: Character(s) denoting end of a page to control spooling. - * - * @memberof qz.configs - */ - setDefaults: function(options) { - _qz.tools.extend(_qz.printing.defaultConfig, options); - }, - - /** - * Creates new printer config to be used in printing. - * - * @param {string|object} printer Name of printer. Use object type to specify printing to file or host. - * @param {string} [printer.name] Name of printer to send printing. - * @param {string} [printer.file] Name of file to send printing. - * @param {string} [printer.host] IP address or host name to send printing. - * @param {string} [printer.port] Port used by <printer.host>. - * @param {Object} [options] Override any of the default options for this config only. - * - * @returns {Config} The new config. - * - * @see configs.setDefaults - * - * @memberof qz.configs - */ - create: function(printer, options) { - return new Config(printer, options); - } - }, - - - /** - * Send data to selected config for printing. - * The promise for this method will resolve when the document has been sent to the printer. Actual printing may not be complete. - *

- * Optionally, print requests can be pre-signed: - * Signed content consists of a JSON object string containing no spacing, - * following the format of the "call" and "params" keys in the API call, with the addition of a "timestamp" key in milliseconds - * ex. '{"call":"","params":{...},"timestamp":1450000000}' - * - * @param {Object|Array>} configs Previously created config object or objects. - * @param {Array|Array>} data Array of data being sent to the printer.
- * String values are interpreted as {type: 'raw', format: 'command', flavor: 'plain', data: <string>}. - * @param {string} data.data - * @param {string} data.type Printing type. Valid types are [pixel | raw*]. *Default - * @param {string} data.format Format of data type used. *Default per type

- * For [pixel] types, valid formats are [html | image* | pdf].

- * For [raw] types, valid formats are [command* | html | image | pdf]. - * @param {string} data.flavor Flavor of data format used. *Default per format

- * For [command] formats, valid flavors are [base64 | file | hex | plain* | xml].

- * For [html] formats, valid flavors are [file* | plain].

- * For [image] formats, valid flavors are [base64 | file*].

- * For [pdf] formats, valid flavors are [base64 | file*]. - * @param {Object} [data.options] - * @param {string} [data.options.language] Required with [raw] type + [image] format. Printer language. - * @param {number} [data.options.x] Optional with [raw] type + [image] format. The X position of the image. - * @param {number} [data.options.y] Optional with [raw] type + [image] format. The Y position of the image. - * @param {string|number} [data.options.dotDensity] Optional with [raw] type + [image] format. - * @param {number} [data.precision=128] Optional with [raw] type [image] format. Bit precision of the ribbons. - * @param {boolean|string|Array>} [data.options.overlay=false] Optional with [raw] type [image] format. - * Boolean sets entire layer, string sets mask image, Array sets array of rectangles in format [x1,y1,x2,y2]. - * @param {string} [data.options.xmlTag] Required with [xml] flavor. Tag name containing base64 formatted data. - * @param {number} [data.options.pageWidth] Optional with [html | pdf] formats. Width of the rendering. - * Defaults to paper width. - * @param {number} [data.options.pageHeight] Optional with [html | pdf] formats. Height of the rendering. - * Defaults to paper height for [pdf], or auto sized for [html]. - * @param {string} [data.options.pageRanges] Optional with [pdf] formats. Comma-separated list of page ranges to include. - * @param {boolean} [data.options.ignoreTransparency=false] Optional with [pdf] formats. Instructs transparent PDF elements to be ignored. - * Transparent PDF elements are known to degrade performance and quality when printing. - * @param {boolean} [data.options.altFontRendering=false] Optional with [pdf] formats. Instructs PDF to be rendered using PDFBOX 1.8 techniques. - * Drastically improves low-DPI PDF print quality on Windows. - * @param {...*} [arguments] Additionally three more parameters can be specified:

- * {boolean} [resumeOnError=false] Whether the chain should continue printing if it hits an error on one the the prints.

- * {string|Array} [signature] Pre-signed signature(s) of the JSON string for containing call, params, and timestamp.

- * {number|Array} [signingTimestamps] Required to match with signature. Timestamps for each of the passed pre-signed content. - * - * @returns {Promise} - * - * @see qz.configs.create - * - * @memberof qz - */ - print: function(configs, data) { - var resumeOnError = false, - signatures = [], - signaturesTimestamps = []; - - //find optional parameters - if (arguments.length >= 3) { - if (typeof arguments[2] === 'boolean') { - resumeOnError = arguments[2]; - - if (arguments.length >= 5) { - signatures = arguments[3]; - signaturesTimestamps = arguments[4]; - } - } else if (arguments.length >= 4) { - signatures = arguments[2]; - signaturesTimestamps = arguments[3]; - } - - //ensure values are arrays for consistency - if (signatures && !Array.isArray(signatures)) { signatures = [signatures]; } - if (signaturesTimestamps && !Array.isArray(signaturesTimestamps)) { signaturesTimestamps = [signaturesTimestamps]; } - } - - if (!Array.isArray(configs)) { configs = [configs]; } //single config -> array of configs - if (!Array.isArray(data[0])) { data = [data]; } //single data array -> array of data arrays - - //clean up data formatting - for(var d = 0; d < data.length; d++) { - _qz.tools.relative(data[d]); - _qz.compatible.data(data[d]); - } - - var sendToPrint = function(mapping) { - var params = { - printer: mapping.config.getPrinter(), - options: mapping.config.getOptions(), - data: mapping.data - }; - - return _qz.websocket.dataPromise('print', params, mapping.signature, mapping.timestamp); - }; - - //chain instead of Promise.all, so resumeOnError can collect each error - var chain = []; - for(var i = 0; i < configs.length || i < data.length; i++) { - (function(i_) { - var map = { - config: configs[Math.min(i_, configs.length - 1)], - data: data[Math.min(i_, data.length - 1)], - signature: signatures[i_], - timestamp: signaturesTimestamps[i_] - }; - - chain.push(function() { return sendToPrint(map) }); - })(i); - } - - //setup to catch errors if needed - var fallThrough = null; - if (resumeOnError) { - var fallen = []; - fallThrough = function(err) { fallen.push(err); }; - - //final promise to reject any errors as a group - chain.push(function() { - return _qz.tools.promise(function(resolve, reject) { - fallen.length ? reject(fallen) : resolve(); - }); - }); - } - - var last = null; - chain.reduce(function(sequence, link) { - last = sequence.catch(fallThrough).then(link); //catch is ignored if fallThrough is null - return last; - }, _qz.tools.promise(function(r) { r(); })); //an immediately resolved promise to start off the chain - - //return last promise so users can chain off final action or catch when stopping on error - return last; - }, - - - /** - * Calls related to interaction with serial ports. - * @namespace qz.serial - */ - serial: { - /** - * @returns {Promise|Error>} Communication (RS232, COM, TTY) ports available on connected system. - * - * @memberof qz.serial - */ - findPorts: function() { - return _qz.websocket.dataPromise('serial.findPorts'); - }, - - /** - * List of functions called for any response from open serial ports. - * Event data will contain {string} portName for all types. - * For RECEIVE types, {string} output. - * For ERROR types, {string} exception. - * - * @param {Function|Array} calls Single or array of Function({object} streamEvent) calls. - * - * @memberof qz.serial - */ - setSerialCallbacks: function(calls) { - _qz.serial.serialCallbacks = calls; - }, - - /** - * Opens a serial port for sending and receiving data - * - * @param {string} port Name of serial port to open. - * @param {Object} [options] Serial port configurations. - * @param {number} [options.baudRate=9600] Serial port speed. Set to 0 for auto negotiation. - * @param {number} [options.dataBits=8] Serial port data bits. Set to 0 for auto negotiation. - * @param {number} [options.stopBits=1] Serial port stop bits. Set to 0 for auto negotiation. - * @param {string} [options.parity='NONE'] Serial port parity. Set to AUTO for auto negotiation. Valid values [NONE | EVEN | ODD | MARK | SPACE | AUTO] - * @param {string} [options.flowControl='NONE'] Serial port flow control. Set to AUTO for auto negotiation. Valid values [NONE | XONXOFF | XONXOFF_OUT | XONXOFF_IN | RTSCTS | RTSCTS_OUT | RTSCTS_IN | AUTO] - * @param {string} [options.encoding='UTF-8'] Character set for communications. - * @param {string} [options.start=0x0002] DEPRECATED: Legacy character denoting start of serial response. Use options.rx.start instead. - * @param {string} [options.end=0x000D] DEPRECATED: Legacy character denoting end of serial response. Use options.rx.end instead. - * @param {number} [options.width] DEPRECATED: Legacy use for fixed-width response serial communication. Use options.rx.width instead. - * @param {Object} [options.rx] Serial communications response definitions. If an object is passed but no options are defined, all response data will be sent back as it is received unprocessed. - * @param {string|Array} [options.rx.start] Character(s) denoting start of response bytes. Used in conjunction with `end`, `width`, or `lengthbit` property. - * @param {string} [options.rx.end] Character denoting end of response bytes. Used in conjunction with `start` property. - * @param {number} [options.rx.width] Fixed width size of response bytes (not including header if `start` is set). Used alone or in conjunction with `start` property. - * @param {boolean} [options.rx.untilNewline] Returns data between newline characters (`\n` or `\r`) Truncates empty responses. Overrides `start`, `end`, `width`. - * @param {number|Object} [options.rx.lengthBytes] If a number is passed it is treated as the length index. Other values are left as their defaults. - * @param {number} [options.rx.lengthBytes.index=0] Position of the response byte (not including response `start` bytes) used to denote the length of the remaining response data. - * @param {number} [options.rx.lengthBytes.length=1] Length of response length bytes after response header. - * @param {string} [options.rx.lengthBytes.endian='BIG'] Byte endian for multi-byte length values. Valid values [BIG | LITTLE] - * @param {number|Object} [options.rx.crcBytes] If a number is passed it is treated as the crc length. Other values are left as their defaults. - * @param {number} [options.rx.crcBytes.index=0] Position after the response data (not including length or data bytes) used to denote the crc. - * @param {number} [options.rx.crcBytes.length=1] Length of response crc bytes after the response data length. - * @param {boolean} [options.rx.includeHeader=false] Whether any of the header bytes (`start` bytes and any length bytes) should be included in the processed response. - * @param {string} [options.rx.encoding] Override the encoding used for response data. Uses the same value as options.encoding otherwise. - * - * @returns {Promise} - * - * @memberof qz.serial - */ - openPort: function(port, options) { - var params = { - port: port, - options: options - }; - return _qz.websocket.dataPromise('serial.openPort', params); - }, - - /** - * Send commands over a serial port. - * Any responses from the device will be sent to serial callback functions. - * - * @param {string} port An open serial port to send data. - * @param {string|Array|Object} data Data to be sent to the serial device. - * @param {string} [data.type='PLAIN'] Valid values [FILE | PLAIN | HEX | BASE64] - * @param {string|Array} data.data Data to be sent to the serial device. - * @param {Object} options Serial port configuration updates. See qz.serial.openPort `options` docs for available values. - * For best performance, it is recommended to only set these values on the port open call. - * - * @returns {Promise} - * - * @see qz.serial.setSerialCallbacks - * - * @memberof qz.serial - */ - sendData: function(port, data, options) { - if (_qz.tools.versionCompare(2, 1, 0, 12) >= 0) { - if (typeof data !== 'object') { - data = { - data: data, - type: "PLAIN" - } - } - - if (data.type && data.type.toUpperCase() == "FILE") { - data.data = _qz.tools.absolute(data.data); - } - } - - var params = { - port: port, - data: data, - options: options - }; - return _qz.websocket.dataPromise('serial.sendData', params); - }, - - /** - * @param {string} port Name of port to close. - * - * @returns {Promise} - * - * @memberof qz.serial - */ - closePort: function(port) { - return _qz.websocket.dataPromise('serial.closePort', { port: port }); - } - }, - - /** - * Calls related to interaction with communication sockets. - * @namespace qz.socket - */ - socket: { - /** - * Opens a network port for sending and receiving data. - * - * @param {string} host The connection hostname. - * @param {number} port The connection port number. - * @param {Object} [options] Network socket configuration. - * @param {string} [options.encoding='UTF-8'] Character set for communications. - * - * @memberof qz.socket - */ - open: function(host, port, options) { - var params = { - host: host, - port: port, - options: options - }; - return _qz.websocket.dataPromise("socket.open", params); - }, - - /** - * @param {string} host The connection hostname. - * @param {number} port The connection port number. - * - * @memberof qz.socket - */ - close: function(host, port) { - var params = { - host: host, - port: port - }; - return _qz.websocket.dataPromise("socket.close", params); - }, - - /** - * Send data over an open socket. - * - * @param {string} host The connection hostname. - * @param {number} port The connection port number. - * @param {string|Object} data Data to be sent over the port. - * @param {string} [data.type='PLAIN'] Valid values [PLAIN] - * @param {string} data.data Data to be sent over the port. - * - * @memberof qz.socket - */ - sendData: function(host, port, data) { - if (typeof data !== 'object') { - data = { - data: data, - type: "PLAIN" - }; - } - - var params = { - host: host, - port: port, - data: data - }; - return _qz.websocket.dataPromise("socket.sendData", params); - }, - - /** - * List of functions called for any response from open network sockets. - * Event data will contain {string} host and {number} port for all types. - * For RECEIVE types, {string} response. - * For ERROR types, {string} exception. - * - * @param {Function|Array} calls Single or array of Function({Object} eventData) calls. - * - * @memberof qz.socket - */ - setSocketCallbacks: function(calls) { - _qz.socket.socketCallbacks = calls; - } - }, - - /** - * Calls related to interaction with USB devices. - * @namespace qz.usb - */ - usb: { - /** - * List of available USB devices. Includes (hexadecimal) vendor ID, (hexadecimal) product ID, and hub status. - * If supported, also returns manufacturer and product descriptions. - * - * @param includeHubs Whether to include USB hubs. - * @returns {Promise|Error>} Array of JSON objects containing information on connected USB devices. - * - * @memberof qz.usb - */ - listDevices: function(includeHubs) { - return _qz.websocket.dataPromise('usb.listDevices', { includeHubs: includeHubs }); - }, - - /** - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of USB device's vendor ID. - * @param deviceInfo.productId Hex string of USB device's product ID. - * @returns {Promise|Error>} List of available (hexadecimal) interfaces on a USB device. - * - * @memberof qz.usb - */ - listInterfaces: function(deviceInfo) { - if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility - - return _qz.websocket.dataPromise('usb.listInterfaces', deviceInfo); - }, - - /** - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of USB device's vendor ID. - * @param deviceInfo.productId Hex string of USB device's product ID. - * @param deviceInfo.iface Hex string of interface on the USB device to search. - * @returns {Promise|Error>} List of available (hexadecimal) endpoints on a USB device's interface. - * - * @memberof qz.usb - */ - listEndpoints: function(deviceInfo) { - //backwards compatibility - if (typeof deviceInfo !== 'object') { - deviceInfo = { - vendorId: arguments[0], - productId: arguments[1], - interface: arguments[2] - }; - } - - return _qz.websocket.dataPromise('usb.listEndpoints', deviceInfo); - }, - - /** - * List of functions called for any response from open usb devices. - * Event data will contain {string} vendorId and {string} productId for all types. - * For RECEIVE types, {Array} output (in hexadecimal format). - * For ERROR types, {string} exception. - * - * @param {Function|Array} calls Single or array of Function({Object} eventData) calls. - * - * @memberof qz.usb - */ - setUsbCallbacks: function(calls) { - _qz.usb.usbCallbacks = calls; - }, - - /** - * Claim a USB device's interface to enable sending/reading data across an endpoint. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of USB device's vendor ID. - * @param deviceInfo.productId Hex string of USB device's product ID. - * @param deviceInfo.interface Hex string of interface on the USB device to claim. - * @returns {Promise} - * - * @memberof qz.usb - */ - claimDevice: function(deviceInfo) { - //backwards compatibility - if (typeof deviceInfo !== 'object') { - deviceInfo = { - vendorId: arguments[0], - productId: arguments[1], - interface: arguments[2] - }; - } - - return _qz.websocket.dataPromise('usb.claimDevice', deviceInfo); - }, - - /** - * Check the current claim state of a USB device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of USB device's vendor ID. - * @param deviceInfo.productId Hex string of USB device's product ID. - * @returns {Promise} - * - * @since 2.0.2 - * @memberOf qz.usb - */ - isClaimed: function(deviceInfo) { - if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility - - return _qz.websocket.dataPromise('usb.isClaimed', deviceInfo); - }, - - /** - * Send data to a claimed USB device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of USB device's vendor ID. - * @param deviceInfo.productId Hex string of USB device's product ID. - * @param deviceInfo.endpoint Hex string of endpoint on the claimed interface for the USB device. - * @param deviceInfo.data Bytes to send over specified endpoint. - * @param {string} [deviceInfo.type='PLAIN'] Valid values [FILE | PLAIN | HEX | BASE64] - * @returns {Promise} - * - * @memberof qz.usb - */ - sendData: function(deviceInfo) { - //backwards compatibility - if (typeof deviceInfo !== 'object') { - deviceInfo = { - vendorId: arguments[0], - productId: arguments[1], - endpoint: arguments[2], - data: arguments[3] - }; - } - - if (_qz.tools.versionCompare(2, 1, 0, 12) >= 0) { - if (typeof deviceInfo.data !== 'object') { - deviceInfo.data = { - data: deviceInfo.data, - type: "PLAIN" - } - } - - if (deviceInfo.data.type && deviceInfo.data.type.toUpperCase() == "FILE") { - deviceInfo.data.data = _qz.tools.absolute(deviceInfo.data.data); - } - } - - return _qz.websocket.dataPromise('usb.sendData', deviceInfo); - }, - - /** - * Read data from a claimed USB device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of USB device's vendor ID. - * @param deviceInfo.productId Hex string of USB device's product ID. - * @param deviceInfo.endpoint Hex string of endpoint on the claimed interface for the USB device. - * @param deviceInfo.responseSize Size of the byte array to receive a response in. - * @returns {Promise|Error>} List of (hexadecimal) bytes received from the USB device. - * - * @memberof qz.usb - */ - readData: function(deviceInfo) { - //backwards compatibility - if (typeof deviceInfo !== 'object') { - deviceInfo = { - vendorId: arguments[0], - productId: arguments[1], - endpoint: arguments[2], - responseSize: arguments[3] - }; - } - - return _qz.websocket.dataPromise('usb.readData', deviceInfo); - }, - - /** - * Provides a continuous stream of read data from a claimed USB device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of USB device's vendor ID. - * @param deviceInfo.productId Hex string of USB device's product ID. - * @param deviceInfo.endpoint Hex string of endpoint on the claimed interface for the USB device. - * @param deviceInfo.responseSize Size of the byte array to receive a response in. - * @param deviceInfo.interval=100 Frequency to send read data back, in milliseconds. - * @returns {Promise} - * - * @see qz.usb.setUsbCallbacks - * - * @memberof qz.usb - */ - openStream: function(deviceInfo) { - //backwards compatibility - if (typeof deviceInfo !== 'object') { - deviceInfo = { - vendorId: arguments[0], - productId: arguments[1], - endpoint: arguments[2], - responseSize: arguments[3], - interval: arguments[4] - }; - } - - return _qz.websocket.dataPromise('usb.openStream', deviceInfo); - }, - - /** - * Stops the stream of read data from a claimed USB device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of USB device's vendor ID. - * @param deviceInfo.productId Hex string of USB device's product ID. - * @param deviceInfo.endpoint Hex string of endpoint on the claimed interface for the USB device. - * @returns {Promise} - * - * @memberof qz.usb - */ - closeStream: function(deviceInfo) { - //backwards compatibility - if (typeof deviceInfo !== 'object') { - deviceInfo = { - vendorId: arguments[0], - productId: arguments[1], - endpoint: arguments[2] - }; - } - - return _qz.websocket.dataPromise('usb.closeStream', deviceInfo); - }, - - /** - * Release a claimed USB device to free resources after sending/reading data. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of USB device's vendor ID. - * @param deviceInfo.productId Hex string of USB device's product ID. - * @returns {Promise} - * - * @memberof qz.usb - */ - releaseDevice: function(deviceInfo) { - if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility - - return _qz.websocket.dataPromise('usb.releaseDevice', deviceInfo); - } - }, - - - /** - * Calls related to interaction with HID USB devices
- * Many of these calls can be accomplished from the qz.usb namespace, - * but HID allows for simpler interaction - * @namespace qz.hid - * @since 2.0.1 - */ - hid: { - /** - * List of available HID devices. Includes (hexadecimal) vendor ID and (hexadecimal) product ID. - * If available, also returns manufacturer and product descriptions. - * - * @returns {Promise|Error>} Array of JSON objects containing information on connected HID devices. - * @since 2.0.1 - * - * @memberof qz.hid - */ - listDevices: function() { - return _qz.websocket.dataPromise('hid.listDevices'); - }, - - /** - * Start listening for HID device actions, such as attach / detach events. - * Reported under the ACTION type in the streamEvent on callbacks. - * - * @returns {Promise} - * @since 2.0.1 - * - * @see qz.hid.setHidCallbacks - * - * @memberof qz.hid - */ - startListening: function() { - return _qz.websocket.dataPromise('hid.startListening'); - }, - - /** - * Stop listening for HID device actions. - * - * @returns {Promise} - * @since 2.0.1 - * - * @see qz.hid.setHidCallbacks - * - * @memberof qz.hid - */ - stopListening: function() { - return _qz.websocket.dataPromise('hid.stopListening'); - }, - - /** - * List of functions called for any response from open usb devices. - * Event data will contain {string} vendorId and {string} productId for all types. - * For RECEIVE types, {Array} output (in hexadecimal format). - * For ERROR types, {string} exception. - * For ACTION types, {string} actionType. - * - * @param {Function|Array} calls Single or array of Function({Object} eventData) calls. - * @since 2.0.1 - * - * @memberof qz.hid - */ - setHidCallbacks: function(calls) { - _qz.hid.hidCallbacks = calls; - }, - - /** - * Claim a HID device to enable sending/reading data across. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of HID device's vendor ID. - * @param deviceInfo.productId Hex string of HID device's product ID. - * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present. - * @param deviceInfo.serial Serial ID of HID device. - * @returns {Promise} - * @since 2.0.1 - * - * @memberof qz.hid - */ - claimDevice: function(deviceInfo) { - if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility - - return _qz.websocket.dataPromise('hid.claimDevice', deviceInfo); - }, - - /** - * Check the current claim state of a HID device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of HID device's vendor ID. - * @param deviceInfo.productId Hex string of HID device's product ID. - * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present. - * @param deviceInfo.serial Serial ID of HID device. - * @returns {Promise} - * - * @since 2.0.2 - * @memberOf qz.hid - */ - isClaimed: function(deviceInfo) { - if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility - - return _qz.websocket.dataPromise('hid.isClaimed', deviceInfo); - }, - - /** - * Send data to a claimed HID device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of HID device's vendor ID. - * @param deviceInfo.productId Hex string of HID device's product ID. - * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present. - * @param deviceInfo.serial Serial ID of HID device. - * @param deviceInfo.data Bytes to send over specified endpoint. - * @param deviceInfo.endpoint=0x00 First byte of the data packet signifying the HID report ID. - * Must be 0x00 for devices only supporting a single report. - * @param deviceInfo.reportId=0x00 Alias for deviceInfo.endpoint. Not used if endpoint is provided. - * @param {string} [deviceInfo.type='PLAIN'] Valid values [FILE | PLAIN | HEX | BASE64] - * @returns {Promise} - * @since 2.0.1 - * - * @memberof qz.hid - */ - sendData: function(deviceInfo) { - //backwards compatibility - if (typeof deviceInfo !== 'object') { - deviceInfo = { - vendorId: arguments[0], - productId: arguments[1], - data: arguments[2], - endpoint: arguments[3] - }; - } - - if (_qz.tools.versionCompare(2, 1, 0, 12) >= 0) { - if (typeof deviceInfo.data !== 'object') { - deviceInfo.data = { - data: deviceInfo.data, - type: "PLAIN" - } - } - - if (deviceInfo.data.type && deviceInfo.data.type.toUpperCase() == "FILE") { - deviceInfo.data.data = _qz.tools.absolute(deviceInfo.data.data); - } - } else { - if (typeof deviceInfo.data === 'object') { - if (deviceInfo.data.type.toUpperCase() !== "PLAIN" - || typeof deviceInfo.data.data !== "string") { - return _qz.tools.reject(new Error("Data format is not supported with connected QZ Tray version " + _qz.websocket.connection.version)); - } - - deviceInfo.data = deviceInfo.data.data; - } - } - - return _qz.websocket.dataPromise('hid.sendData', deviceInfo); - }, - - /** - * Read data from a claimed HID device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of HID device's vendor ID. - * @param deviceInfo.productId Hex string of HID device's product ID. - * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present. - * @param deviceInfo.serial Serial ID of HID device. - * @param deviceInfo.responseSize Size of the byte array to receive a response in. - * @returns {Promise|Error>} List of (hexadecimal) bytes received from the HID device. - * @since 2.0.1 - * - * @memberof qz.hid - */ - readData: function(deviceInfo) { - //backwards compatibility - if (typeof deviceInfo !== 'object') { - deviceInfo = { - vendorId: arguments[0], - productId: arguments[1], - responseSize: arguments[2] - }; - } - - return _qz.websocket.dataPromise('hid.readData', deviceInfo); - }, - - /** - * Send a feature report to a claimed HID device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of HID device's vendor ID. - * @param deviceInfo.productId Hex string of HID device's product ID. - * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present. - * @param deviceInfo.serial Serial ID of HID device. - * @param deviceInfo.data Bytes to send over specified endpoint. - * @param deviceInfo.endpoint=0x00 First byte of the data packet signifying the HID report ID. - * Must be 0x00 for devices only supporting a single report. - * @param deviceInfo.reportId=0x00 Alias for deviceInfo.endpoint. Not used if endpoint is provided. - * @param {string} [deviceInfo.type='PLAIN'] Valid values [FILE | PLAIN | HEX | BASE64] - * @returns {Promise} - * - * @memberof qz.hid - */ - sendFeatureReport: function(deviceInfo) { - return _qz.websocket.dataPromise('hid.sendFeatureReport', deviceInfo); - }, - - /** - * Get a feature report from a claimed HID device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of HID device's vendor ID. - * @param deviceInfo.productId Hex string of HID device's product ID. - * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present. - * @param deviceInfo.serial Serial ID of HID device. - * @param deviceInfo.responseSize Size of the byte array to receive a response in. - * @returns {Promise|Error>} List of (hexadecimal) bytes received from the HID device. - * - * @memberof qz.hid - */ - getFeatureReport: function(deviceInfo) { - return _qz.websocket.dataPromise('hid.getFeatureReport', deviceInfo); - }, - - /** - * Provides a continuous stream of read data from a claimed HID device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of HID device's vendor ID. - * @param deviceInfo.productId Hex string of HID device's product ID. - * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present. - * @param deviceInfo.serial Serial ID of HID device. - * @param deviceInfo.responseSize Size of the byte array to receive a response in. - * @param deviceInfo.interval=100 Frequency to send read data back, in milliseconds. - * @returns {Promise} - * @since 2.0.1 - * - * @see qz.hid.setHidCallbacks - * - * @memberof qz.hid - */ - openStream: function(deviceInfo) { - //backwards compatibility - if (typeof deviceInfo !== 'object') { - deviceInfo = { - vendorId: arguments[0], - productId: arguments[1], - responseSize: arguments[2], - interval: arguments[3] - }; - } - - return _qz.websocket.dataPromise('hid.openStream', deviceInfo); - }, - - /** - * Stops the stream of read data from a claimed HID device. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of HID device's vendor ID. - * @param deviceInfo.productId Hex string of HID device's product ID. - * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present. - * @param deviceInfo.serial Serial ID of HID device. - * @returns {Promise} - * @since 2.0.1 - * - * @memberof qz.hid - */ - closeStream: function(deviceInfo) { - if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility - - return _qz.websocket.dataPromise('hid.closeStream', deviceInfo); - }, - - /** - * Release a claimed HID device to free resources after sending/reading data. - * - * @param {object} deviceInfo Config details of the HID device. - * @param deviceInfo.vendorId Hex string of HID device's vendor ID. - * @param deviceInfo.productId Hex string of HID device's product ID. - * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present. - * @param deviceInfo.serial Serial ID of HID device. - * @returns {Promise} - * @since 2.0.1 - * - * @memberof qz.hid - */ - releaseDevice: function(deviceInfo) { - if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility - - return _qz.websocket.dataPromise('hid.releaseDevice', deviceInfo); - } - }, - - - /** - * Calls related to interactions with the filesystem - * @namespace qz.file - * @since 2.1 - */ - file: { - /** - * List of files available at the given directory.
- * Due to security reasons, paths are limited to the qz data directory unless overridden via properties file. - * - * @param {string} path Relative or absolute directory path. Must reside in qz data directory or a white-listed location. - * @param {Object} [params] Object containing file access parameters - * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections - * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user - * @returns {Promise|Error>} Array of files at the given path - * - * @memberof qz.file - */ - list: function(path, params) { - var param = _qz.tools.extend({ path: path }, params); - return _qz.websocket.dataPromise('file.list', param); - }, - - /** - * Reads contents of file at the given path.
- * Due to security reasons, paths are limited to the qz data directory unless overridden via properties file. - * - * @param {string} path Relative or absolute file path. Must reside in qz data directory or a white-listed location. - * @param {Object} [params] Object containing file access parameters - * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections - * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user - * @param {string} [params.flavor='plain'] Flavor of data format used, valid flavors are [base64 | hex | plain]. - * @returns {Promise} String containing the file contents - * - * @memberof qz.file - */ - read: function(path, params) { - var param = _qz.tools.extend({ path: path }, params); - return _qz.websocket.dataPromise('file.read', param); - }, - - /** - * Writes data to the file at the given path.
- * Due to security reasons, paths are limited to the qz data directory unless overridden via properties file. - * - * @param {string} path Relative or absolute file path. Must reside in qz data directory or a white-listed location. - * @param {Object} params Object containing file access parameters - * @param {string} params.data File data to be written - * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections - * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user - * @param {boolean} [params.append=false] Appends to the end of the file if set, otherwise overwrites existing contents - * @param {string} [params.flavor='plain'] Flavor of data format used, valid flavors are [base64 | file | hex | plain]. - * @returns {Promise} - * - * @memberof qz.file - */ - write: function(path, params) { - var param = _qz.tools.extend({ path: path }, params); - return _qz.websocket.dataPromise('file.write', param); - }, - - /** - * Deletes a file at given path.
- * Due to security reasons, paths are limited to the qz data directory unless overridden via properties file. - * - * @param {string} path Relative or absolute file path. Must reside in qz data directory or a white-listed location. - * @param {Object} [params] Object containing file access parameters - * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections - * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user - * @returns {Promise} - * - * @memberof qz.file - */ - remove: function(path, params) { - var param = _qz.tools.extend({ path: path }, params); - return _qz.websocket.dataPromise('file.remove', param); - }, - - /** - * Provides a continuous stream of events (and optionally data) from a local file. - * - * @param {string} path Relative or absolute directory path. Must reside in qz data directory or a white-listed location. - * @param {Object} [params] Object containing file access parameters - * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections - * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user - * @param {Object} [params.listener] If defined, file data will be returned on events - * @param {number} [params.listener.bytes=-1] Number of bytes to return or -1 for all - * @param {number} [params.listener.lines=-1] Number of lines to return or -1 for all - * @param {boolean} [params.listener.reverse] Controls whether data should be returned from the bottom of the file. Default value is true for line mode and false for byte mode. - * @param {string|Array} [params.include] File patterns to match. Blank values will be ignored. - * @param {string|Array} [params.exclude] File patterns to exclude. Blank values will be ignored. Takes priority over params.include. - * @param {boolean} [params.ignoreCase=true] Whether params.include or params.exclude are case-sensitive. - * @returns {Promise} - * @since 2.1.0 - * - * @see qz.file.setFileCallbacks - * - * @memberof qz.file - */ - startListening: function(path, params) { - if (params && typeof params.include !== 'undefined' && !Array.isArray(params.include)) { - params.include = [params.include]; - } - if (params && typeof params.exclude !== 'undefined' && !Array.isArray(params.exclude)) { - params.exclude = [params.exclude]; - } - var param = _qz.tools.extend({ path: path }, params); - return _qz.websocket.dataPromise('file.startListening', param); - }, - - /** - * Closes listeners with the provided settings. Omitting the path parameter will result in all listeners closing. - * - * @param {string} [path] Previously opened directory path of listener to close, or omit to close all. - * @param {Object} [params] Object containing file access parameters - * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections - * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user - * @returns {Promise} - * - * @memberof qz.file - */ - stopListening: function(path, params) { - var param = _qz.tools.extend({ path: path }, params); - return _qz.websocket.dataPromise('file.stopListening', param); - }, - - /** - * List of functions called for any response from a file listener. - * For ERROR types event data will contain, {string} message. - * For ACTION types event data will contain, {string} file {string} eventType {string} [data]. - * - * @param {Function|Array} calls Single or array of Function({Object} eventData) calls. - * @since 2.1.0 - * - * @memberof qz.file - */ - setFileCallbacks: function(calls) { - _qz.file.fileCallbacks = calls; - } - }, - - /** - * Calls related to networking information - * @namespace qz.networking - * @since 2.1.0 - */ - networking: { - /** - * @param {string} [hostname] Hostname to try to connect to when determining network interfaces, defaults to "google.com" - * @param {number} [port] Port to use with custom hostname, defaults to 443 - * @returns {Promise} Connected system's network information. - * - * @memberof qz.networking - * @since 2.1.0 - */ - device: function(hostname, port) { - // Wrap 2.0 - if (_qz.tools.isVersion(2, 0)) { - return _qz.compatible.networking(hostname, port, null, null, function(data) { - return { ip: data.ipAddress, mac: data.macAddress }; - }); - } - // Use 2.1 - return _qz.websocket.dataPromise('networking.device', { - hostname: hostname, - port: port - }); - }, - - /** - * Get computer hostname - * - * @param {string} [hostname] DEPRECATED Hostname to try to connect to when determining network interfaces, defaults to "google.com" - * @param {number} [port] DEPRECATED Port to use with custom hostname, defaults to 443 - * @returns {Promise} Connected system's hostname. - * - * @memberof qz.networking - * @since 2.2.2 - */ - hostname: function(hostname, port) { - // Wrap < 2.2.2 - if (_qz.tools.versionCompare(2, 2, 2) < 0) { - return _qz.tools.promise(function(resolve, reject) { - _qz.websocket.dataPromise('networking.device', { hostname: hostname, port: port }).then(function(device) { - console.log(device); - resolve(device.hostname); - }); - }); - } else { - return _qz.websocket.dataPromise('networking.hostname'); - } - }, - - /** - * @param {string} [hostname] Hostname to try to connect to when determining network interfaces, defaults to "google.com" - * @param {number} [port] Port to use with custom hostname, defaults to 443 - * @returns {Promise|Error>} Connected system's network information. - * - * @memberof qz.networking - * @since 2.1.0 - */ - devices: function(hostname, port) { - // Wrap 2.0 - if (_qz.tools.isVersion(2, 0)) { - return _qz.compatible.networking(hostname, port, null, null, function(data) { - return [{ ip: data.ipAddress, mac: data.macAddress }]; - }); - } - // Use 2.1 - return _qz.websocket.dataPromise('networking.devices', { - hostname: hostname, - port: port - }); - } - }, - - - /** - * Calls related to signing connection requests. - * @namespace qz.security - */ - security: { - /** - * Set promise resolver for calls to acquire the site's certificate. - * - * @param {Function|AsyncFunction|Promise} promiseHandler Either a function that will be used as a promise resolver (of format Function({function} resolve, {function}reject)), - * an async function, or a promise. Any of which should return the public certificate via their respective resolve call. - * @param {Object} [options] Configuration options for the certificate resolver - * @param {boolean} [options.rejectOnFailure=[false]] Overrides default behavior to call resolve with a blank certificate on failure. - * @memberof qz.security - */ - setCertificatePromise: function(promiseHandler, options) { - _qz.security.certHandler = promiseHandler; - _qz.security.rejectOnCertFailure = !!(options && options.rejectOnFailure); - }, - - /** - * Set promise factory for calls to sign API calls. - * - * @param {Function|AsyncFunction} promiseFactory Either a function that accepts a string parameter of the data to be signed - * and returns a function to be used as a promise resolver (of format Function({function} resolve, {function}reject)), - * or an async function that can take a string parameter of the data to be signed. Either of which should return the signed contents of - * the passed string parameter via their respective resolve call. - * - * @example - * qz.security.setSignaturePromise(function(dataToSign) { - * return function(resolve, reject) { - * $.ajax("/signing-url?data=" + dataToSign).then(resolve, reject); - * } - * }) - * - * @memberof qz.security - */ - setSignaturePromise: function(promiseFactory) { - _qz.security.signatureFactory = promiseFactory; - }, - - /** - * Set which signing algorithm QZ will check signatures against. - * - * @param {string} algorithm The algorithm used in signing. Valid values: [SHA1 | SHA256 | SHA512] - * @since 2.1.0 - * - * @memberof qz.security - */ - setSignatureAlgorithm: function(algorithm) { - //warn for incompatibilities if known - if (!_qz.compatible.algorithm()) { - return; - } - - if (["SHA1", "SHA256", "SHA512"].indexOf(algorithm.toUpperCase()) < 0) { - _qz.log.error("Signing algorithm '" + algorithm + "' is not supported."); - } else { - _qz.security.signAlgorithm = algorithm; - } - }, - - /** - * Get the signing algorithm QZ will be checking signatures against. - * - * @returns {string} The algorithm used in signing. - * @since 2.1.0 - * - * @memberof qz.security - */ - getSignatureAlgorithm: function() { - return _qz.security.signAlgorithm; - } - }, - - /** - * Calls related to compatibility adjustments - * @namespace qz.api - */ - api: { - /** - * Show or hide QZ api debugging statements in the browser console. - * - * @param {boolean} show Whether the debugging logs for QZ should be shown. Hidden by default. - * @returns {boolean} Value of debugging flag - * @memberof qz.api - */ - showDebug: function(show) { - return (_qz.DEBUG = show); - }, - - /** - * Get version of connected QZ Tray application. - * - * @returns {Promise} Version number of QZ Tray. - * - * @memberof qz.api - */ - getVersion: function() { - return _qz.websocket.dataPromise('getVersion'); - }, - - /** - * Checks for the specified version of connected QZ Tray application. - * - * @param {string|number} [major] Major version to check - * @param {string|number} [minor] Minor version to check - * @param {string|number} [patch] Patch version to check - * - * @memberof qz.api - */ - isVersion: _qz.tools.isVersion, - - /** - * Checks if the connected QZ Tray application is greater than the specified version. - * - * @param {string|number} major Major version to check - * @param {string|number} [minor] Minor version to check - * @param {string|number} [patch] Patch version to check - * @param {string|number} [build] Build version to check - * @returns {boolean} True if connected version is greater than the version specified. - * - * @memberof qz.api - * @since 2.1.0-4 - */ - isVersionGreater: function(major, minor, patch, build) { - return _qz.tools.versionCompare(major, minor, patch, build) > 0; - }, - - /** - * Checks if the connected QZ Tray application is less than the specified version. - * - * @param {string|number} major Major version to check - * @param {string|number} [minor] Minor version to check - * @param {string|number} [patch] Patch version to check - * @param {string|number} [build] Build version to check - * @returns {boolean} True if connected version is less than the version specified. - * - * @memberof qz.api - * @since 2.1.0-4 - */ - isVersionLess: function(major, minor, patch, build) { - return _qz.tools.versionCompare(major, minor, patch, build) < 0; - }, - - /** - * Change the promise library used by QZ API. - * Should be called before any initialization to avoid possible errors. - * - * @param {Function} promiser Function({function} resolver) called to create new promises. - * - * @memberof qz.api - */ - setPromiseType: function(promiser) { - _qz.tools.promise = promiser; - }, - - /** - * Change the SHA-256 hashing function used by QZ API. - * Should be called before any initialization to avoid possible errors. - * - * @param {Function} hasher Function({function} message) called to create hash of passed string. - * - * @memberof qz.api - */ - setSha256Type: function(hasher) { - _qz.tools.hash = hasher; - }, - - /** - * Change the WebSocket handler. - * Should be called before any initialization to avoid possible errors. - * - * @param {Function} ws Function({function} WebSocket) called to override the internal WebSocket handler. - * - * @memberof qz.api - */ - setWebSocketType: function(ws) { - _qz.tools.ws = ws; - } - }, - - /** - * Version of this JavaScript library - * - * @constant {string} - * - * @memberof qz - */ - version: _qz.VERSION - }; - - return qz; -})(); - - -(function() { - if (typeof define === 'function' && define.amd) { - define(qz); - } else if (typeof exports === 'object') { - module.exports = qz; - } else { - window.qz = qz; - } -})(); diff --git a/old code/tray/js/sample/array-from-pollyfill.js b/old code/tray/js/sample/array-from-pollyfill.js deleted file mode 100755 index 3cf8d54..0000000 --- a/old code/tray/js/sample/array-from-pollyfill.js +++ /dev/null @@ -1,76 +0,0 @@ -if (!Array.from) { - Array.from = (function () { - var toStr = Object.prototype.toString; - var isCallable = function (fn) { - return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; - }; - var toInteger = function (value) { - var number = Number(value); - if (isNaN(number)) { return 0; } - if (number === 0 || !isFinite(number)) { return number; } - return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); - }; - var maxSafeInteger = Math.pow(2, 53) - 1; - var toLength = function (value) { - var len = toInteger(value); - return Math.min(Math.max(len, 0), maxSafeInteger); - }; - - // The length property of the from method is 1. - return function from(arrayLike/*, mapFn, thisArg */) { - // 1. Let C be the this value. - var C = this; - - // 2. Let items be ToObject(arrayLike). - var items = Object(arrayLike); - - // 3. ReturnIfAbrupt(items). - if (arrayLike == null) { - throw new TypeError("Array.from requires an array-like object - not null or undefined"); - } - - // 4. If mapfn is undefined, then let mapping be false. - var mapFn = arguments.length > 1 ? arguments[1] : void undefined; - var T; - if (typeof mapFn !== 'undefined') { - // 5. else - // 5. a If IsCallable(mapfn) is false, throw a TypeError exception. - if (!isCallable(mapFn)) { - throw new TypeError('Array.from: when provided, the second argument must be a function'); - } - - // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (arguments.length > 2) { - T = arguments[2]; - } - } - - // 10. Let lenValue be Get(items, "length"). - // 11. Let len be ToLength(lenValue). - var len = toLength(items.length); - - // 13. If IsConstructor(C) is true, then - // 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len. - // 14. a. Else, Let A be ArrayCreate(len). - var A = isCallable(C) ? Object(new C(len)) : new Array(len); - - // 16. Let k be 0. - var k = 0; - // 17. Repeat, while k < len… (also steps a - h) - var kValue; - while (k < len) { - kValue = items[k]; - if (mapFn) { - A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); - } else { - A[k] = kValue; - } - k += 1; - } - // 18. Let putStatus be Put(A, "length", len, true). - A.length = len; - // 20. Return A. - return A; - }; - }()); -} \ No newline at end of file diff --git a/old code/tray/js/sample/bootstrap.min.js b/old code/tray/js/sample/bootstrap.min.js deleted file mode 100755 index 9f47837..0000000 --- a/old code/tray/js/sample/bootstrap.min.js +++ /dev/null @@ -1,678 +0,0 @@ -/*! - * Bootstrap v3.3.5 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under the MIT license - */ -if ("undefined" == typeof jQuery) { - throw new Error("Bootstrap's JavaScript requires jQuery"); -} -+function(a) { - "use strict"; - var b = a.fn.jquery.split(" ")[0].split("."); - if (b[0] < 2 && b[1] < 9 || 1 == b[0] && 9 == b[1] && b[2] < 1) { - throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher") - } -}(jQuery), +function(a) { - "use strict"; - function b() { - var a = document.createElement("bootstrap"), b = { - WebkitTransition: "webkitTransitionEnd", - MozTransition: "transitionend", - OTransition: "oTransitionEnd otransitionend", - transition: "transitionend" - }; - for(var c in b) { - if (void 0 !== a.style[c]) { - return { end: b[c] }; - } - } - return !1 - } - - a.fn.emulateTransitionEnd = function(b) { - var c = !1, d = this; - a(this).one("bsTransitionEnd", function() {c = !0}); - var e = function() {c || a(d).trigger(a.support.transition.end)}; - return setTimeout(e, b), this - }, a(function() { - a.support.transition = b(), a.support.transition && (a.event.special.bsTransitionEnd = { - bindType: a.support.transition.end, - delegateType: a.support.transition.end, - handle: function(b) {return a(b.target).is(this) ? b.handleObj.handler.apply(this, arguments) : void 0} - }) - }) -}(jQuery), +function(a) { - "use strict"; - function b(b) { - return this.each(function() { - var c = a(this), e = c.data("bs.alert"); - e || c.data("bs.alert", e = new d(this)), "string" == typeof b && e[b].call(c) - }) - } - - var c = '[data-dismiss="alert"]', d = function(b) {a(b).on("click", c, this.close)}; - d.VERSION = "3.3.5", d.TRANSITION_DURATION = 150, d.prototype.close = function(b) { - function c() {g.detach().trigger("closed.bs.alert").remove()} - - var e = a(this), f = e.attr("data-target"); - f || (f = e.attr("href"), f = f && f.replace(/.*(?=#[^\s]*$)/, "")); - var g = a(f); - b && b.preventDefault(), g.length || (g = e.closest(".alert")), g.trigger(b = a.Event("close.bs.alert")), b.isDefaultPrevented() || (g.removeClass("in"), a.support.transition && g.hasClass("fade") ? g.one("bsTransitionEnd", c).emulateTransitionEnd(d.TRANSITION_DURATION) : c()) - }; - var e = a.fn.alert; - a.fn.alert = b, a.fn.alert.Constructor = d, a.fn.alert.noConflict = function() {return a.fn.alert = e, this}, a(document).on("click.bs.alert.data-api", c, d.prototype.close) -}(jQuery), +function(a) { - "use strict"; - function b(b) { - return this.each(function() { - var d = a(this), e = d.data("bs.button"), f = "object" == typeof b && b; - e || d.data("bs.button", e = new c(this, f)), "toggle" == b ? e.toggle() : b && e.setState(b) - }) - } - - var c = function(b, d) {this.$element = a(b), this.options = a.extend({}, c.DEFAULTS, d), this.isLoading = !1}; - c.VERSION = "3.3.5", c.DEFAULTS = { loadingText: "loading..." }, c.prototype.setState = function(b) { - var c = "disabled", d = this.$element, e = d.is("input") ? "val" : "html", f = d.data(); - b += "Text", null == f.resetText && d.data("resetText", d[e]()), setTimeout(a.proxy(function() {d[e](null == f[b] ? this.options[b] : f[b]), "loadingText" == b ? (this.isLoading = !0, d.addClass(c).attr(c, c)) : this.isLoading && (this.isLoading = !1, d.removeClass(c).removeAttr(c))}, this), 0) - }, c.prototype.toggle = function() { - var a = !0, b = this.$element.closest('[data-toggle="buttons"]'); - if (b.length) { - var c = this.$element.find("input"); - "radio" == c.prop("type") ? (c.prop("checked") && (a = !1), b.find(".active").removeClass("active"), this.$element.addClass("active")) : "checkbox" == c.prop("type") && (c.prop("checked") !== this.$element.hasClass("active") && (a = !1), this.$element.toggleClass("active")), c.prop("checked", this.$element.hasClass("active")), a && c.trigger("change") - } else { - this.$element.attr("aria-pressed", !this.$element.hasClass("active")), this.$element.toggleClass("active") - } - }; - var d = a.fn.button; - a.fn.button = b, a.fn.button.Constructor = c, a.fn.button.noConflict = function() {return a.fn.button = d, this}, a(document).on("click.bs.button.data-api", '[data-toggle^="button"]', function(c) { - var d = a(c.target); - d.hasClass("btn") || (d = d.closest(".btn")), b.call(d, "toggle"), a(c.target).is('input[type="radio"]') || a(c.target).is('input[type="checkbox"]') || c.preventDefault() - }).on("focus.bs.button.data-api blur.bs.button.data-api", '[data-toggle^="button"]', function(b) {a(b.target).closest(".btn").toggleClass("focus", /^focus(in)?$/.test(b.type))}) -}(jQuery), +function(a) { - "use strict"; - function b(b) { - return this.each(function() { - var d = a(this), e = d.data("bs.carousel"), f = a.extend({}, c.DEFAULTS, d.data(), "object" == typeof b && b), g = "string" == typeof b ? b : f.slide; - e || d.data("bs.carousel", e = new c(this, f)), "number" == typeof b ? e.to(b) : g ? e[g]() : f.interval && e.pause().cycle() - }) - } - - var c = function(b, c) {this.$element = a(b), this.$indicators = this.$element.find(".carousel-indicators"), this.options = c, this.paused = null, this.sliding = null, this.interval = null, this.$active = null, this.$items = null, this.options.keyboard && this.$element.on("keydown.bs.carousel", a.proxy(this.keydown, this)), "hover" == this.options.pause && !("ontouchstart"in document.documentElement) && this.$element.on("mouseenter.bs.carousel", a.proxy(this.pause, this)).on("mouseleave.bs.carousel", a.proxy(this.cycle, this))}; - c.VERSION = "3.3.5", c.TRANSITION_DURATION = 600, c.DEFAULTS = { - interval: 5e3, - pause: "hover", - wrap: !0, - keyboard: !0 - }, c.prototype.keydown = function(a) { - if (!/input|textarea/i.test(a.target.tagName)) { - switch(a.which) { - case 37: - this.prev(); - break; - case 39: - this.next(); - break; - default: - return - } - a.preventDefault() - } - }, c.prototype.cycle = function(b) {return b || (this.paused = !1), this.interval && clearInterval(this.interval), this.options.interval && !this.paused && (this.interval = setInterval(a.proxy(this.next, this), this.options.interval)), this}, c.prototype.getItemIndex = function(a) {return this.$items = a.parent().children(".item"), this.$items.index(a || this.$active)}, c.prototype.getItemForDirection = function(a, b) { - var c = this.getItemIndex(b), d = "prev" == a && 0 === c || "next" == a && c == this.$items.length - 1; - if (d && !this.options.wrap) { - return b; - } - var e = "prev" == a ? -1 : 1, f = (c + e) % this.$items.length; - return this.$items.eq(f) - }, c.prototype.to = function(a) { - var b = this, c = this.getItemIndex(this.$active = this.$element.find(".item.active")); - return a > this.$items.length - 1 || 0 > a ? void 0 : this.sliding ? this.$element.one("slid.bs.carousel", function() {b.to(a)}) : c == a ? this.pause().cycle() : this.slide(a > c ? "next" : "prev", this.$items.eq(a)) - }, c.prototype.pause = function(b) {return b || (this.paused = !0), this.$element.find(".next, .prev").length && a.support.transition && (this.$element.trigger(a.support.transition.end), this.cycle(!0)), this.interval = clearInterval(this.interval), this}, c.prototype.next = function() {return this.sliding ? void 0 : this.slide("next")}, c.prototype.prev = function() {return this.sliding ? void 0 : this.slide("prev")}, c.prototype.slide = function(b, d) { - var e = this.$element.find(".item.active"), f = d || this.getItemForDirection(b, e), g = this.interval, h = "next" == b ? "left" : "right", i = this; - if (f.hasClass("active")) { - return this.sliding = !1; - } - var j = f[0], k = a.Event("slide.bs.carousel", { relatedTarget: j, direction: h }); - if (this.$element.trigger(k), !k.isDefaultPrevented()) { - if (this.sliding = !0, g && this.pause(), this.$indicators.length) { - this.$indicators.find(".active").removeClass("active"); - var l = a(this.$indicators.children()[this.getItemIndex(f)]); - l && l.addClass("active") - } - var m = a.Event("slid.bs.carousel", { relatedTarget: j, direction: h }); - return a.support.transition && this.$element.hasClass("slide") ? (f.addClass(b), f[0].offsetWidth, e.addClass(h), f.addClass(h), e.one("bsTransitionEnd", function() {f.removeClass([b, h].join(" ")).addClass("active"), e.removeClass(["active", h].join(" ")), i.sliding = !1, setTimeout(function() {i.$element.trigger(m)}, 0)}).emulateTransitionEnd(c.TRANSITION_DURATION)) : (e.removeClass("active"), f.addClass("active"), this.sliding = !1, this.$element.trigger(m)), g && this.cycle(), this - } - }; - var d = a.fn.carousel; - a.fn.carousel = b, a.fn.carousel.Constructor = c, a.fn.carousel.noConflict = function() {return a.fn.carousel = d, this}; - var e = function(c) { - var d, e = a(this), f = a(e.attr("data-target") || (d = e.attr("href")) && d.replace(/.*(?=#[^\s]+$)/, "")); - if (f.hasClass("carousel")) { - var g = a.extend({}, f.data(), e.data()), h = e.attr("data-slide-to"); - h && (g.interval = !1), b.call(f, g), h && f.data("bs.carousel").to(h), c.preventDefault() - } - }; - a(document).on("click.bs.carousel.data-api", "[data-slide]", e).on("click.bs.carousel.data-api", "[data-slide-to]", e), a(window).on("load", function() { - a('[data-ride="carousel"]').each(function() { - var c = a(this); - b.call(c, c.data()) - }) - }) -}(jQuery), +function(a) { - "use strict"; - function b(b) { - var c, d = b.attr("data-target") || (c = b.attr("href")) && c.replace(/.*(?=#[^\s]+$)/, ""); - return a(d) - } - - function c(b) { - return this.each(function() { - var c = a(this), e = c.data("bs.collapse"), f = a.extend({}, d.DEFAULTS, c.data(), "object" == typeof b && b); - !e && f.toggle && /show|hide/.test(b) && (f.toggle = !1), e || c.data("bs.collapse", e = new d(this, f)), "string" == typeof b && e[b]() - }) - } - - var d = function(b, c) {this.$element = a(b), this.options = a.extend({}, d.DEFAULTS, c), this.$trigger = a('[data-toggle="collapse"][href="#' + b.id + '"],[data-toggle="collapse"][data-target="#' + b.id + '"]'), this.transitioning = null, this.options.parent ? this.$parent = this.getParent() : this.addAriaAndCollapsedClass(this.$element, this.$trigger), this.options.toggle && this.toggle()}; - d.VERSION = "3.3.5", d.TRANSITION_DURATION = 350, d.DEFAULTS = { toggle: !0 }, d.prototype.dimension = function() { - var a = this.$element.hasClass("width"); - return a ? "width" : "height" - }, d.prototype.show = function() { - if (!this.transitioning && !this.$element.hasClass("in")) { - var b, e = this.$parent && this.$parent.children(".panel").children(".in, .collapsing"); - if (!(e && e.length && (b = e.data("bs.collapse"), b && b.transitioning))) { - var f = a.Event("show.bs.collapse"); - if (this.$element.trigger(f), !f.isDefaultPrevented()) { - e && e.length && (c.call(e, "hide"), b || e.data("bs.collapse", null)); - var g = this.dimension(); - this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded", !0), this.$trigger.removeClass("collapsed").attr("aria-expanded", !0), this.transitioning = 1; - var h = function() {this.$element.removeClass("collapsing").addClass("collapse in")[g](""), this.transitioning = 0, this.$element.trigger("shown.bs.collapse")}; - if (!a.support.transition) { - return h.call(this); - } - var i = a.camelCase(["scroll", g].join("-")); - this.$element.one("bsTransitionEnd", a.proxy(h, this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i]) - } - } - } - }, d.prototype.hide = function() { - if (!this.transitioning && this.$element.hasClass("in")) { - var b = a.Event("hide.bs.collapse"); - if (this.$element.trigger(b), !b.isDefaultPrevented()) { - var c = this.dimension(); - this.$element[c](this.$element[c]())[0].offsetHeight, this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded", !1), this.$trigger.addClass("collapsed").attr("aria-expanded", !1), this.transitioning = 1; - var e = function() {this.transitioning = 0, this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")}; - return a.support.transition ? void this.$element[c](0).one("bsTransitionEnd", a.proxy(e, this)).emulateTransitionEnd(d.TRANSITION_DURATION) : e.call(this) - } - } - }, d.prototype.toggle = function() {this[this.$element.hasClass("in") ? "hide" : "show"]()}, d.prototype.getParent = function() { - return a(this.options.parent).find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]').each(a.proxy(function(c, d) { - var e = a(d); - this.addAriaAndCollapsedClass(b(e), e) - }, this)).end() - }, d.prototype.addAriaAndCollapsedClass = function(a, b) { - var c = a.hasClass("in"); - a.attr("aria-expanded", c), b.toggleClass("collapsed", !c).attr("aria-expanded", c) - }; - var e = a.fn.collapse; - a.fn.collapse = c, a.fn.collapse.Constructor = d, a.fn.collapse.noConflict = function() {return a.fn.collapse = e, this}, a(document).on("click.bs.collapse.data-api", '[data-toggle="collapse"]', function(d) { - var e = a(this); - e.attr("data-target") || d.preventDefault(); - var f = b(e), g = f.data("bs.collapse"), h = g ? "toggle" : e.data(); - c.call(f, h) - }) -}(jQuery), +function(a) { - "use strict"; - function b(b) { - var c = b.attr("data-target"); - c || (c = b.attr("href"), c = c && /#[A-Za-z]/.test(c) && c.replace(/.*(?=#[^\s]*$)/, "")); - var d = c && a(c); - return d && d.length ? d : b.parent() - } - - function c(c) { - c && 3 === c.which || (a(e).remove(), a(f).each(function() { - var d = a(this), e = b(d), f = { relatedTarget: this }; - e.hasClass("open") && (c && "click" == c.type && /input|textarea/i.test(c.target.tagName) && a.contains(e[0], c.target) || (e.trigger(c = a.Event("hide.bs.dropdown", f)), c.isDefaultPrevented() || (d.attr("aria-expanded", "false"), e.removeClass("open").trigger("hidden.bs.dropdown", f)))) - })) - } - - function d(b) { - return this.each(function() { - var c = a(this), d = c.data("bs.dropdown"); - d || c.data("bs.dropdown", d = new g(this)), "string" == typeof b && d[b].call(c) - }) - } - - var e = ".dropdown-backdrop", f = '[data-toggle="dropdown"]', g = function(b) {a(b).on("click.bs.dropdown", this.toggle)}; - g.VERSION = "3.3.5", g.prototype.toggle = function(d) { - var e = a(this); - if (!e.is(".disabled, :disabled")) { - var f = b(e), g = f.hasClass("open"); - if (c(), !g) { - "ontouchstart"in document.documentElement && !f.closest(".navbar-nav").length && a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click", c); - var h = { relatedTarget: this }; - if (f.trigger(d = a.Event("show.bs.dropdown", h)), d.isDefaultPrevented()) { - return; - } - e.trigger("focus").attr("aria-expanded", "true"), f.toggleClass("open").trigger("shown.bs.dropdown", h) - } - return !1 - } - }, g.prototype.keydown = function(c) { - if (/(38|40|27|32)/.test(c.which) && !/input|textarea/i.test(c.target.tagName)) { - var d = a(this); - if (c.preventDefault(), c.stopPropagation(), !d.is(".disabled, :disabled")) { - var e = b(d), g = e.hasClass("open"); - if (!g && 27 != c.which || g && 27 == c.which) { - return 27 == c.which && e.find(f).trigger("focus"), d.trigger("click"); - } - var h = " li:not(.disabled):visible a", i = e.find(".dropdown-menu" + h); - if (i.length) { - var j = i.index(c.target); - 38 == c.which && j > 0 && j--, 40 == c.which && j < i.length - 1 && j++, ~j || (j = 0), i.eq(j).trigger("focus") - } - } - } - }; - var h = a.fn.dropdown; - a.fn.dropdown = d, a.fn.dropdown.Constructor = g, a.fn.dropdown.noConflict = function() {return a.fn.dropdown = h, this}, a(document).on("click.bs.dropdown.data-api", c).on("click.bs.dropdown.data-api", ".dropdown form", function(a) {a.stopPropagation()}).on("click.bs.dropdown.data-api", f, g.prototype.toggle).on("keydown.bs.dropdown.data-api", f, g.prototype.keydown).on("keydown.bs.dropdown.data-api", ".dropdown-menu", g.prototype.keydown) -}(jQuery), +function(a) { - "use strict"; - function b(b, d) { - return this.each(function() { - var e = a(this), f = e.data("bs.modal"), g = a.extend({}, c.DEFAULTS, e.data(), "object" == typeof b && b); - f || e.data("bs.modal", f = new c(this, g)), "string" == typeof b ? f[b](d) : g.show && f.show(d) - }) - } - - var c = function(b, c) {this.options = c, this.$body = a(document.body), this.$element = a(b), this.$dialog = this.$element.find(".modal-dialog"), this.$backdrop = null, this.isShown = null, this.originalBodyPad = null, this.scrollbarWidth = 0, this.ignoreBackdropClick = !1, this.options.remote && this.$element.find(".modal-content").load(this.options.remote, a.proxy(function() {this.$element.trigger("loaded.bs.modal")}, this))}; - c.VERSION = "3.3.5", c.TRANSITION_DURATION = 300, c.BACKDROP_TRANSITION_DURATION = 150, c.DEFAULTS = { - backdrop: !0, - keyboard: !0, - show: !0 - }, c.prototype.toggle = function(a) {return this.isShown ? this.hide() : this.show(a)}, c.prototype.show = function(b) { - var d = this, e = a.Event("show.bs.modal", { relatedTarget: b }); - this.$element.trigger(e), this.isShown || e.isDefaultPrevented() || (this.isShown = !0, this.checkScrollbar(), this.setScrollbar(), this.$body.addClass("modal-open"), this.escape(), this.resize(), this.$element.on("click.dismiss.bs.modal", '[data-dismiss="modal"]', a.proxy(this.hide, this)), this.$dialog.on("mousedown.dismiss.bs.modal", function() {d.$element.one("mouseup.dismiss.bs.modal", function(b) {a(b.target).is(d.$element) && (d.ignoreBackdropClick = !0)})}), this.backdrop(function() { - var e = a.support.transition && d.$element.hasClass("fade"); - d.$element.parent().length || d.$element.appendTo(d.$body), d.$element.show().scrollTop(0), d.adjustDialog(), e && d.$element[0].offsetWidth, d.$element.addClass("in"), d.enforceFocus(); - var f = a.Event("shown.bs.modal", { relatedTarget: b }); - e ? d.$dialog.one("bsTransitionEnd", function() {d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION) : d.$element.trigger("focus").trigger(f) - })) - }, c.prototype.hide = function(b) {b && b.preventDefault(), b = a.Event("hide.bs.modal"), this.$element.trigger(b), this.isShown && !b.isDefaultPrevented() && (this.isShown = !1, this.escape(), this.resize(), a(document).off("focusin.bs.modal"), this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"), this.$dialog.off("mousedown.dismiss.bs.modal"), a.support.transition && this.$element.hasClass("fade") ? this.$element.one("bsTransitionEnd", a.proxy(this.hideModal, this)).emulateTransitionEnd(c.TRANSITION_DURATION) : this.hideModal())}, c.prototype.enforceFocus = function() {a(document).off("focusin.bs.modal").on("focusin.bs.modal", a.proxy(function(a) {this.$element[0] === a.target || this.$element.has(a.target).length || this.$element.trigger("focus")}, this))}, c.prototype.escape = function() {this.isShown && this.options.keyboard ? this.$element.on("keydown.dismiss.bs.modal", a.proxy(function(a) {27 == a.which && this.hide()}, this)) : this.isShown || this.$element.off("keydown.dismiss.bs.modal")}, c.prototype.resize = function() {this.isShown ? a(window).on("resize.bs.modal", a.proxy(this.handleUpdate, this)) : a(window).off("resize.bs.modal")}, c.prototype.hideModal = function() { - var a = this; - this.$element.hide(), this.backdrop(function() {a.$body.removeClass("modal-open"), a.resetAdjustments(), a.resetScrollbar(), a.$element.trigger("hidden.bs.modal")}) - }, c.prototype.removeBackdrop = function() {this.$backdrop && this.$backdrop.remove(), this.$backdrop = null}, c.prototype.backdrop = function(b) { - var d = this, e = this.$element.hasClass("fade") ? "fade" : ""; - if (this.isShown && this.options.backdrop) { - var f = a.support.transition && e; - if (this.$backdrop = a(document.createElement("div")).addClass("modal-backdrop " + e).appendTo(this.$body), this.$element.on("click.dismiss.bs.modal", a.proxy(function(a) {return this.ignoreBackdropClick ? void(this.ignoreBackdropClick = !1) : void(a.target === a.currentTarget && ("static" == this.options.backdrop ? this.$element[0].focus() : this.hide()))}, this)), f && this.$backdrop[0].offsetWidth, this.$backdrop.addClass("in"), !b) { - return; - } - f ? this.$backdrop.one("bsTransitionEnd", b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION) : b() - } else if (!this.isShown && this.$backdrop) { - this.$backdrop.removeClass("in"); - var g = function() {d.removeBackdrop(), b && b()}; - a.support.transition && this.$element.hasClass("fade") ? this.$backdrop.one("bsTransitionEnd", g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION) : g() - } else { - b && b() - } - }, c.prototype.handleUpdate = function() {this.adjustDialog()}, c.prototype.adjustDialog = function() { - var a = this.$element[0].scrollHeight > document.documentElement.clientHeight; - this.$element.css({ - paddingLeft: !this.bodyIsOverflowing && a ? this.scrollbarWidth : "", - paddingRight: this.bodyIsOverflowing && !a ? this.scrollbarWidth : "" - }) - }, c.prototype.resetAdjustments = function() { - this.$element.css({ - paddingLeft: "", - paddingRight: "" - }) - }, c.prototype.checkScrollbar = function() { - var a = window.innerWidth; - if (!a) { - var b = document.documentElement.getBoundingClientRect(); - a = b.right - Math.abs(b.left) - } - this.bodyIsOverflowing = document.body.clientWidth < a, this.scrollbarWidth = this.measureScrollbar() - }, c.prototype.setScrollbar = function() { - var a = parseInt(this.$body.css("padding-right") || 0, 10); - this.originalBodyPad = document.body.style.paddingRight || "", this.bodyIsOverflowing && this.$body.css("padding-right", a + this.scrollbarWidth) - }, c.prototype.resetScrollbar = function() {this.$body.css("padding-right", this.originalBodyPad)}, c.prototype.measureScrollbar = function() { - var a = document.createElement("div"); - a.className = "modal-scrollbar-measure", this.$body.append(a); - var b = a.offsetWidth - a.clientWidth; - return this.$body[0].removeChild(a), b - }; - var d = a.fn.modal; - a.fn.modal = b, a.fn.modal.Constructor = c, a.fn.modal.noConflict = function() {return a.fn.modal = d, this}, a(document).on("click.bs.modal.data-api", '[data-toggle="modal"]', function(c) { - var d = a(this), e = d.attr("href"), f = a(d.attr("data-target") || e && e.replace(/.*(?=#[^\s]+$)/, "")), g = f.data("bs.modal") ? "toggle" : a.extend({ remote: !/#/.test(e) && e }, f.data(), d.data()); - d.is("a") && c.preventDefault(), f.one("show.bs.modal", function(a) {a.isDefaultPrevented() || f.one("hidden.bs.modal", function() {d.is(":visible") && d.trigger("focus")})}), b.call(f, g, this) - }) -}(jQuery), +function(a) { - "use strict"; - function b(b) { - return this.each(function() { - var d = a(this), e = d.data("bs.tooltip"), f = "object" == typeof b && b; - (e || !/destroy|hide/.test(b)) && (e || d.data("bs.tooltip", e = new c(this, f)), "string" == typeof b && e[b]()) - }) - } - - var c = function(a, b) {this.type = null, this.options = null, this.enabled = null, this.timeout = null, this.hoverState = null, this.$element = null, this.inState = null, this.init("tooltip", a, b)}; - c.VERSION = "3.3.5", c.TRANSITION_DURATION = 150, c.DEFAULTS = { - animation: !0, - placement: "top", - selector: !1, - template: '

', - trigger: "hover focus", - title: "", - delay: 0, - html: !1, - container: !1, - viewport: { selector: "body", padding: 0 } - }, c.prototype.init = function(b, c, d) { - if (this.enabled = !0, this.type = b, this.$element = a(c), this.options = this.getOptions(d), this.$viewport = this.options.viewport && a(a.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : this.options.viewport.selector || this.options.viewport), this.inState = { - click: !1, - hover: !1, - focus: !1 - }, this.$element[0]instanceof document.constructor && !this.options.selector) { - throw new Error("`selector` option must be specified when initializing " + this.type + " on the window.document object!"); - } - for(var e = this.options.trigger.split(" "), f = e.length; f--;) { - var g = e[f]; - if ("click" == g) { - this.$element.on("click." + this.type, this.options.selector, a.proxy(this.toggle, this)); - } else if ("manual" != g) { - var h = "hover" == g ? "mouseenter" : "focusin", i = "hover" == g ? "mouseleave" : "focusout"; - this.$element.on(h + "." + this.type, this.options.selector, a.proxy(this.enter, this)), this.$element.on(i + "." + this.type, this.options.selector, a.proxy(this.leave, this)) - } - } - this.options.selector ? this._options = a.extend({}, this.options, { trigger: "manual", selector: "" }) : this.fixTitle() - }, c.prototype.getDefaults = function() {return c.DEFAULTS}, c.prototype.getOptions = function(b) { - return b = a.extend({}, this.getDefaults(), this.$element.data(), b), b.delay && "number" == typeof b.delay && (b.delay = { - show: b.delay, - hide: b.delay - }), b - }, c.prototype.getDelegateOptions = function() { - var b = {}, c = this.getDefaults(); - return this._options && a.each(this._options, function(a, d) {c[a] != d && (b[a] = d)}), b - }, c.prototype.enter = function(b) { - var c = b instanceof this.constructor ? b : a(b.currentTarget).data("bs." + this.type); - return c || (c = new this.constructor(b.currentTarget, this.getDelegateOptions()), a(b.currentTarget).data("bs." + this.type, c)), b instanceof a.Event && (c.inState["focusin" == b.type ? "focus" : "hover"] = !0), c.tip().hasClass("in") || "in" == c.hoverState ? void(c.hoverState = "in") : (clearTimeout(c.timeout), c.hoverState = "in", c.options.delay && c.options.delay.show ? void(c.timeout = setTimeout(function() {"in" == c.hoverState && c.show()}, c.options.delay.show)) : c.show()) - }, c.prototype.isInStateTrue = function() { - for(var a in this.inState) { - if (this.inState[a]) { - return !0; - } - } - return !1 - }, c.prototype.leave = function(b) { - var c = b instanceof this.constructor ? b : a(b.currentTarget).data("bs." + this.type); - return c || (c = new this.constructor(b.currentTarget, this.getDelegateOptions()), a(b.currentTarget).data("bs." + this.type, c)), b instanceof a.Event && (c.inState["focusout" == b.type ? "focus" : "hover"] = !1), c.isInStateTrue() ? void 0 : (clearTimeout(c.timeout), c.hoverState = "out", c.options.delay && c.options.delay.hide ? void(c.timeout = setTimeout(function() {"out" == c.hoverState && c.hide()}, c.options.delay.hide)) : c.hide()) - }, c.prototype.show = function() { - var b = a.Event("show.bs." + this.type); - if (this.hasContent() && this.enabled) { - this.$element.trigger(b); - var d = a.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]); - if (b.isDefaultPrevented() || !d) { - return; - } - var e = this, f = this.tip(), g = this.getUID(this.type); - this.setContent(), f.attr("id", g), this.$element.attr("aria-describedby", g), this.options.animation && f.addClass("fade"); - var h = "function" == typeof this.options.placement ? this.options.placement.call(this, f[0], this.$element[0]) : this.options.placement, i = /\s?auto?\s?/i, j = i.test(h); - j && (h = h.replace(i, "") || "top"), f.detach().css({ - top: 0, - left: 0, - display: "block" - }).addClass(h).data("bs." + this.type, this), this.options.container ? f.appendTo(this.options.container) : f.insertAfter(this.$element), this.$element.trigger("inserted.bs." + this.type); - var k = this.getPosition(), l = f[0].offsetWidth, m = f[0].offsetHeight; - if (j) { - var n = h, o = this.getPosition(this.$viewport); - h = "bottom" == h && k.bottom + m > o.bottom ? "top" : "top" == h && k.top - m < o.top ? "bottom" : "right" == h && k.right + l > o.width ? "left" : "left" == h && k.left - l < o.left ? "right" : h, f.removeClass(n).addClass(h) - } - var p = this.getCalculatedOffset(h, k, l, m); - this.applyPlacement(p, h); - var q = function() { - var a = e.hoverState; - e.$element.trigger("shown.bs." + e.type), e.hoverState = null, "out" == a && e.leave(e) - }; - a.support.transition && this.$tip.hasClass("fade") ? f.one("bsTransitionEnd", q).emulateTransitionEnd(c.TRANSITION_DURATION) : q() - } - }, c.prototype.applyPlacement = function(b, c) { - var d = this.tip(), e = d[0].offsetWidth, f = d[0].offsetHeight, g = parseInt(d.css("margin-top"), 10), h = parseInt(d.css("margin-left"), 10); - isNaN(g) && (g = 0), isNaN(h) && (h = 0), b.top += g, b.left += h, a.offset.setOffset(d[0], a.extend({ - using: function(a) { - d.css({ - top: Math.round(a.top), - left: Math.round(a.left) - }) - } - }, b), 0), d.addClass("in"); - var i = d[0].offsetWidth, j = d[0].offsetHeight; - "top" == c && j != f && (b.top = b.top + f - j); - var k = this.getViewportAdjustedDelta(c, b, i, j); - k.left ? b.left += k.left : b.top += k.top; - var l = /top|bottom/.test(c), m = l ? 2 * k.left - e + i : 2 * k.top - f + j, n = l ? "offsetWidth" : "offsetHeight"; - d.offset(b), this.replaceArrow(m, d[0][n], l) - }, c.prototype.replaceArrow = function(a, b, c) {this.arrow().css(c ? "left" : "top", 50 * (1 - a / b) + "%").css(c ? "top" : "left", "")}, c.prototype.setContent = function() { - var a = this.tip(), b = this.getTitle(); - a.find(".tooltip-inner")[this.options.html ? "html" : "text"](b), a.removeClass("fade in top bottom left right") - }, c.prototype.hide = function(b) { - function d() {"in" != e.hoverState && f.detach(), e.$element.removeAttr("aria-describedby").trigger("hidden.bs." + e.type), b && b()} - - var e = this, f = a(this.$tip), g = a.Event("hide.bs." + this.type); - return this.$element.trigger(g), g.isDefaultPrevented() ? void 0 : (f.removeClass("in"), a.support.transition && f.hasClass("fade") ? f.one("bsTransitionEnd", d).emulateTransitionEnd(c.TRANSITION_DURATION) : d(), this.hoverState = null, this) - }, c.prototype.fixTitle = function() { - var a = this.$element; - (a.attr("title") || "string" != typeof a.attr("data-original-title")) && a.attr("data-original-title", a.attr("title") || "").attr("title", "") - }, c.prototype.hasContent = function() {return this.getTitle()}, c.prototype.getPosition = function(b) { - b = b || this.$element; - var c = b[0], d = "BODY" == c.tagName, e = c.getBoundingClientRect(); - null == e.width && (e = a.extend({}, e, { width: e.right - e.left, height: e.bottom - e.top })); - var f = d ? { - top: 0, - left: 0 - } : b.offset(), g = { scroll: d ? document.documentElement.scrollTop || document.body.scrollTop : b.scrollTop() }, h = d ? { - width: a(window).width(), - height: a(window).height() - } : null; - return a.extend({}, e, g, h, f) - }, c.prototype.getCalculatedOffset = function(a, b, c, d) { - return "bottom" == a ? { - top: b.top + b.height, - left: b.left + b.width / 2 - c / 2 - } : "top" == a ? { top: b.top - d, left: b.left + b.width / 2 - c / 2 } : "left" == a ? { - top: b.top + b.height / 2 - d / 2, - left: b.left - c - } : { top: b.top + b.height / 2 - d / 2, left: b.left + b.width } - }, c.prototype.getViewportAdjustedDelta = function(a, b, c, d) { - var e = { top: 0, left: 0 }; - if (!this.$viewport) { - return e; - } - var f = this.options.viewport && this.options.viewport.padding || 0, g = this.getPosition(this.$viewport); - if (/right|left/.test(a)) { - var h = b.top - f - g.scroll, i = b.top + f - g.scroll + d; - h < g.top ? e.top = g.top - h : i > g.top + g.height && (e.top = g.top + g.height - i) - } else { - var j = b.left - f, k = b.left + f + c; - j < g.left ? e.left = g.left - j : k > g.right && (e.left = g.left + g.width - k) - } - return e - }, c.prototype.getTitle = function() { - var a, b = this.$element, c = this.options; - return a = b.attr("data-original-title") || ("function" == typeof c.title ? c.title.call(b[0]) : c.title) - }, c.prototype.getUID = function(a) { - do { - a += ~~(1e6 * Math.random()); - } while(document.getElementById(a)); - return a - }, c.prototype.tip = function() { - if (!this.$tip && (this.$tip = a(this.options.template), 1 != this.$tip.length)) { - throw new Error(this.type + " `template` option must consist of exactly 1 top-level element!"); - } - return this.$tip - }, c.prototype.arrow = function() {return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")}, c.prototype.enable = function() {this.enabled = !0}, c.prototype.disable = function() {this.enabled = !1}, c.prototype.toggleEnabled = function() {this.enabled = !this.enabled}, c.prototype.toggle = function(b) { - var c = this; - b && (c = a(b.currentTarget).data("bs." + this.type), c || (c = new this.constructor(b.currentTarget, this.getDelegateOptions()), a(b.currentTarget).data("bs." + this.type, c))), b ? (c.inState.click = !c.inState.click, c.isInStateTrue() ? c.enter(c) : c.leave(c)) : c.tip().hasClass("in") ? c.leave(c) : c.enter(c) - }, c.prototype.destroy = function() { - var a = this; - clearTimeout(this.timeout), this.hide(function() {a.$element.off("." + a.type).removeData("bs." + a.type), a.$tip && a.$tip.detach(), a.$tip = null, a.$arrow = null, a.$viewport = null}) - }; - var d = a.fn.tooltip; - a.fn.tooltip = b, a.fn.tooltip.Constructor = c, a.fn.tooltip.noConflict = function() {return a.fn.tooltip = d, this} -}(jQuery), +function(a) { - "use strict"; - function b(b) { - return this.each(function() { - var d = a(this), e = d.data("bs.popover"), f = "object" == typeof b && b; - (e || !/destroy|hide/.test(b)) && (e || d.data("bs.popover", e = new c(this, f)), "string" == typeof b && e[b]()) - }) - } - - var c = function(a, b) {this.init("popover", a, b)}; - if (!a.fn.tooltip) { - throw new Error("Popover requires tooltip.js"); - } - c.VERSION = "3.3.5", c.DEFAULTS = a.extend({}, a.fn.tooltip.Constructor.DEFAULTS, { - placement: "right", - trigger: "click", - content: "", - template: '' - }), c.prototype = a.extend({}, a.fn.tooltip.Constructor.prototype), c.prototype.constructor = c, c.prototype.getDefaults = function() {return c.DEFAULTS}, c.prototype.setContent = function() { - var a = this.tip(), b = this.getTitle(), c = this.getContent(); - a.find(".popover-title")[this.options.html ? "html" : "text"](b), a.find(".popover-content").children().detach().end()[this.options.html ? "string" == typeof c ? "html" : "append" : "text"](c), a.removeClass("fade top bottom left right in"), a.find(".popover-title").html() || a.find(".popover-title").hide() - }, c.prototype.hasContent = function() {return this.getTitle() || this.getContent()}, c.prototype.getContent = function() { - var a = this.$element, b = this.options; - return a.attr("data-content") || ("function" == typeof b.content ? b.content.call(a[0]) : b.content) - }, c.prototype.arrow = function() {return this.$arrow = this.$arrow || this.tip().find(".arrow")}; - var d = a.fn.popover; - a.fn.popover = b, a.fn.popover.Constructor = c, a.fn.popover.noConflict = function() {return a.fn.popover = d, this} -}(jQuery), +function(a) { - "use strict"; - function b(c, d) {this.$body = a(document.body), this.$scrollElement = a(a(c).is(document.body) ? window : c), this.options = a.extend({}, b.DEFAULTS, d), this.selector = (this.options.target || "") + " .nav li > a", this.offsets = [], this.targets = [], this.activeTarget = null, this.scrollHeight = 0, this.$scrollElement.on("scroll.bs.scrollspy", a.proxy(this.process, this)), this.refresh(), this.process()} - - function c(c) { - return this.each(function() { - var d = a(this), e = d.data("bs.scrollspy"), f = "object" == typeof c && c; - e || d.data("bs.scrollspy", e = new b(this, f)), "string" == typeof c && e[c]() - }) - } - - b.VERSION = "3.3.5", b.DEFAULTS = { offset: 10 }, b.prototype.getScrollHeight = function() {return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)}, b.prototype.refresh = function() { - var b = this, c = "offset", d = 0; - this.offsets = [], this.targets = [], this.scrollHeight = this.getScrollHeight(), a.isWindow(this.$scrollElement[0]) || (c = "position", d = this.$scrollElement.scrollTop()), this.$body.find(this.selector).map(function() { - var b = a(this), e = b.data("target") || b.attr("href"), f = /^#./.test(e) && a(e); - return f && f.length && f.is(":visible") && [[f[c]().top + d, e]] || null - }).sort(function(a, b) {return a[0] - b[0]}).each(function() {b.offsets.push(this[0]), b.targets.push(this[1])}) - }, b.prototype.process = function() { - var a, b = this.$scrollElement.scrollTop() + this.options.offset, c = this.getScrollHeight(), d = this.options.offset + c - this.$scrollElement.height(), e = this.offsets, f = this.targets, g = this.activeTarget; - if (this.scrollHeight != c && this.refresh(), b >= d) { - return g != (a = f[f.length - 1]) && this.activate(a); - } - if (g && b < e[0]) { - return this.activeTarget = null, this.clear(); - } - for(a = e.length; a--;) { - g != f[a] && b >= e[a] && (void 0 === e[a + 1] || b < e[a + 1]) && this.activate(f[a]) - } - }, b.prototype.activate = function(b) { - this.activeTarget = b, this.clear(); - var c = this.selector + '[data-target="' + b + '"],' + this.selector + '[href="' + b + '"]', d = a(c).parents("li").addClass("active"); - d.parent(".dropdown-menu").length && (d = d.closest("li.dropdown").addClass("active")), - d.trigger("activate.bs.scrollspy") - }, b.prototype.clear = function() {a(this.selector).parentsUntil(this.options.target, ".active").removeClass("active")}; - var d = a.fn.scrollspy; - a.fn.scrollspy = c, a.fn.scrollspy.Constructor = b, a.fn.scrollspy.noConflict = function() {return a.fn.scrollspy = d, this}, a(window).on("load.bs.scrollspy.data-api", function() { - a('[data-spy="scroll"]').each(function() { - var b = a(this); - c.call(b, b.data()) - }) - }) -}(jQuery), +function(a) { - "use strict"; - function b(b) { - return this.each(function() { - var d = a(this), e = d.data("bs.tab"); - e || d.data("bs.tab", e = new c(this)), "string" == typeof b && e[b]() - }) - } - - var c = function(b) {this.element = a(b)}; - c.VERSION = "3.3.5", c.TRANSITION_DURATION = 150, c.prototype.show = function() { - var b = this.element, c = b.closest("ul:not(.dropdown-menu)"), d = b.data("target"); - if (d || (d = b.attr("href"), d = d && d.replace(/.*(?=#[^\s]*$)/, "")), !b.parent("li").hasClass("active")) { - var e = c.find(".active:last a"), f = a.Event("hide.bs.tab", { relatedTarget: b[0] }), g = a.Event("show.bs.tab", { relatedTarget: e[0] }); - if (e.trigger(f), b.trigger(g), !g.isDefaultPrevented() && !f.isDefaultPrevented()) { - var h = a(d); - this.activate(b.closest("li"), c), this.activate(h, h.parent(), function() { - e.trigger({ - type: "hidden.bs.tab", - relatedTarget: b[0] - }), b.trigger({ type: "shown.bs.tab", relatedTarget: e[0] }) - }) - } - } - }, c.prototype.activate = function(b, d, e) { - function f() {g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded", !1), b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded", !0), h ? (b[0].offsetWidth, b.addClass("in")) : b.removeClass("fade"), b.parent(".dropdown-menu").length && b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded", !0), e && e()} - - var g = d.find("> .active"), h = e && a.support.transition && (g.length && g.hasClass("fade") || !!d.find("> .fade").length); - g.length && h ? g.one("bsTransitionEnd", f).emulateTransitionEnd(c.TRANSITION_DURATION) : f(), g.removeClass("in") - }; - var d = a.fn.tab; - a.fn.tab = b, a.fn.tab.Constructor = c, a.fn.tab.noConflict = function() {return a.fn.tab = d, this}; - var e = function(c) {c.preventDefault(), b.call(a(this), "show")}; - a(document).on("click.bs.tab.data-api", '[data-toggle="tab"]', e).on("click.bs.tab.data-api", '[data-toggle="pill"]', e) -}(jQuery), +function(a) { - "use strict"; - function b(b) { - return this.each(function() { - var d = a(this), e = d.data("bs.affix"), f = "object" == typeof b && b; - e || d.data("bs.affix", e = new c(this, f)), "string" == typeof b && e[b]() - }) - } - - var c = function(b, d) {this.options = a.extend({}, c.DEFAULTS, d), this.$target = a(this.options.target).on("scroll.bs.affix.data-api", a.proxy(this.checkPosition, this)).on("click.bs.affix.data-api", a.proxy(this.checkPositionWithEventLoop, this)), this.$element = a(b), this.affixed = null, this.unpin = null, this.pinnedOffset = null, this.checkPosition()}; - c.VERSION = "3.3.5", c.RESET = "affix affix-top affix-bottom", c.DEFAULTS = { - offset: 0, - target: window - }, c.prototype.getState = function(a, b, c, d) { - var e = this.$target.scrollTop(), f = this.$element.offset(), g = this.$target.height(); - if (null != c && "top" == this.affixed) { - return c > e ? "top" : !1; - } - if ("bottom" == this.affixed) { - return null != c ? e + this.unpin <= f.top ? !1 : "bottom" : a - d >= e + g ? !1 : "bottom"; - } - var h = null == this.affixed, i = h ? e : f.top, j = h ? g : b; - return null != c && c >= e ? "top" : null != d && i + j >= a - d ? "bottom" : !1 - }, c.prototype.getPinnedOffset = function() { - if (this.pinnedOffset) { - return this.pinnedOffset; - } - this.$element.removeClass(c.RESET).addClass("affix"); - var a = this.$target.scrollTop(), b = this.$element.offset(); - return this.pinnedOffset = b.top - a - }, c.prototype.checkPositionWithEventLoop = function() {setTimeout(a.proxy(this.checkPosition, this), 1)}, c.prototype.checkPosition = function() { - if (this.$element.is(":visible")) { - var b = this.$element.height(), d = this.options.offset, e = d.top, f = d.bottom, g = Math.max(a(document).height(), a(document.body).height()); - "object" != typeof d && (f = e = d), "function" == typeof e && (e = d.top(this.$element)), "function" == typeof f && (f = d.bottom(this.$element)); - var h = this.getState(g, b, e, f); - if (this.affixed != h) { - null != this.unpin && this.$element.css("top", ""); - var i = "affix" + (h ? "-" + h : ""), j = a.Event(i + ".bs.affix"); - if (this.$element.trigger(j), j.isDefaultPrevented()) { - return; - } - this.affixed = h, this.unpin = "bottom" == h ? this.getPinnedOffset() : null, this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix", "affixed") + ".bs.affix") - } - "bottom" == h && this.$element.offset({ top: g - b - f }) - } - }; - var d = a.fn.affix; - a.fn.affix = b, a.fn.affix.Constructor = c, a.fn.affix.noConflict = function() {return a.fn.affix = d, this}, a(window).on("load", function() { - a('[data-spy="affix"]').each(function() { - var c = a(this), d = c.data(); - d.offset = d.offset || {}, null != d.offsetBottom && (d.offset.bottom = d.offsetBottom), null != d.offsetTop && (d.offset.top = d.offsetTop), b.call(c, d) - }) - }) -}(jQuery); diff --git a/old code/tray/js/sample/jquery-1.11.3.min.js b/old code/tray/js/sample/jquery-1.11.3.min.js deleted file mode 100755 index d273a7f..0000000 --- a/old code/tray/js/sample/jquery-1.11.3.min.js +++ /dev/null @@ -1,2832 +0,0 @@ -/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ -!function(a, b) { - "object" == typeof module && "object" == typeof module.exports ? module.exports = a.document ? b(a, !0) : function(a) { - if (!a.document) { - throw new Error("jQuery requires a window with a document"); - } - return b(a) - } : b(a) -}("undefined" != typeof window ? window : this, function(a, b) { - var c = [], d = c.slice, e = c.concat, f = c.push, g = c.indexOf, h = {}, i = h.toString, j = h.hasOwnProperty, k = {}, l = "1.11.3", m = function(a, b) {return new m.fn.init(a, b)}, n = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, o = /^-ms-/, p = /-([\da-z])/gi, q = function(a, b) {return b.toUpperCase()}; - m.fn = m.prototype = { - jquery: l, - constructor: m, - selector: "", - length: 0, - toArray: function() {return d.call(this)}, - get: function(a) {return null != a ? 0 > a ? this[a + this.length] : this[a] : d.call(this)}, - pushStack: function(a) { - var b = m.merge(this.constructor(), a); - return b.prevObject = this, b.context = this.context, b - }, - each: function(a, b) {return m.each(this, a, b)}, - map: function(a) {return this.pushStack(m.map(this, function(b, c) {return a.call(b, c, b)}))}, - slice: function() {return this.pushStack(d.apply(this, arguments))}, - first: function() {return this.eq(0)}, - last: function() {return this.eq(-1)}, - eq: function(a) { - var b = this.length, c = +a + (0 > a ? b : 0); - return this.pushStack(c >= 0 && b > c ? [this[c]] : []) - }, - end: function() {return this.prevObject || this.constructor(null)}, - push: f, - sort: c.sort, - splice: c.splice - }, m.extend = m.fn.extend = function() { - var a, b, c, d, e, f, g = arguments[0] || {}, h = 1, i = arguments.length, j = !1; - for("boolean" == typeof g && (j = g, g = arguments[h] || {}, h++), "object" == typeof g || m.isFunction(g) || (g = {}), h === i && (g = this, h--); i > h; h++) { - if (null != (e = arguments[h])) { - for(d in e) { - a = g[d], c = e[d], g !== c && (j && c && (m.isPlainObject(c) || (b = m.isArray(c))) ? (b ? (b = !1, f = a && m.isArray(a) ? a : []) : f = a && m.isPlainObject(a) ? a : {}, g[d] = m.extend(j, f, c)) : void 0 !== c && (g[d] = c)); - } - } - } - return g - }, m.extend({ - expando: "jQuery" + (l + Math.random()).replace(/\D/g, ""), - isReady: !0, - error: function(a) {throw new Error(a)}, - noop: function() {}, - isFunction: function(a) {return "function" === m.type(a)}, - isArray: Array.isArray || function(a) {return "array" === m.type(a)}, - isWindow: function(a) {return null != a && a == a.window}, - isNumeric: function(a) {return !m.isArray(a) && a - parseFloat(a) + 1 >= 0}, - isEmptyObject: function(a) { - var b; - for(b in a) { - return !1; - } - return !0 - }, - isPlainObject: function(a) { - var b; - if (!a || "object" !== m.type(a) || a.nodeType || m.isWindow(a)) { - return !1; - } - try { - if (a.constructor && !j.call(a, "constructor") && !j.call(a.constructor.prototype, "isPrototypeOf")) { - return !1 - } - } - catch(c) {return !1} - if (k.ownLast) { - for(b in a) { - return j.call(a, b); - } - } - for(b in a) { - ; - } - return void 0 === b || j.call(a, b) - }, - type: function(a) {return null == a ? a + "" : "object" == typeof a || "function" == typeof a ? h[i.call(a)] || "object" : typeof a}, - globalEval: function(b) {b && m.trim(b) && (a.execScript || function(b) {a.eval.call(a, b)})(b)}, - camelCase: function(a) {return a.replace(o, "ms-").replace(p, q)}, - nodeName: function(a, b) {return a.nodeName && a.nodeName.toLowerCase() === b.toLowerCase()}, - each: function(a, b, c) { - var d, e = 0, f = a.length, g = r(a); - if (c) { - if (g) { - for(; f > e; e++) { - if (d = b.apply(a[e], c), d === !1) { - break - } - } - } else { - for(e in a) { - if (d = b.apply(a[e], c), d === !1) { - break - } - } - } - } else if (g) { - for(; f > e; e++) { - if (d = b.call(a[e], e, a[e]), d === !1) { - break - } - } - } else { - for(e in a) { - if (d = b.call(a[e], e, a[e]), d === !1) { - break; - } - } - } - return a - }, - trim: function(a) {return null == a ? "" : (a + "").replace(n, "")}, - makeArray: function(a, b) { - var c = b || []; - return null != a && (r(Object(a)) ? m.merge(c, "string" == typeof a ? [a] : a) : f.call(c, a)), c - }, - inArray: function(a, b, c) { - var d; - if (b) { - if (g) { - return g.call(b, a, c); - } - for(d = b.length, c = c ? 0 > c ? Math.max(0, d + c) : c : 0; d > c; c++) { - if (c in b && b[c] === a) { - return c - } - } - } - return -1 - }, - merge: function(a, b) { - var c = +b.length, d = 0, e = a.length; - while(c > d) { - a[e++] = b[d++]; - } - if (c !== c) { - while(void 0 !== b[d]) { - a[e++] = b[d++]; - } - } - return a.length = e, a - }, - grep: function(a, b, c) { - for(var d, e = [], f = 0, g = a.length, h = !c; g > f; f++) { - d = !b(a[f], f), d !== h && e.push(a[f]); - } - return e - }, - map: function(a, b, c) { - var d, f = 0, g = a.length, h = r(a), i = []; - if (h) { - for(; g > f; f++) { - d = b(a[f], f, c), null != d && i.push(d); - } - } else { - for(f in a) { - d = b(a[f], f, c), null != d && i.push(d); - } - } - return e.apply([], i) - }, - guid: 1, - proxy: function(a, b) { - var c, e, f; - return "string" == typeof b && (f = a[b], b = a, a = f), m.isFunction(a) ? (c = d.call(arguments, 2), e = function() {return a.apply(b || this, c.concat(d.call(arguments)))}, e.guid = a.guid = a.guid || m.guid++, e) : void 0 - }, - now: function() {return +new Date}, - support: k - }), m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(a, b) {h["[object " + b + "]"] = b.toLowerCase()}); - function r(a) { - var b = "length"in a && a.length, c = m.type(a); - return "function" === c || m.isWindow(a) ? !1 : 1 === a.nodeType && b ? !0 : "array" === c || 0 === b || "number" == typeof b && b > 0 && b - 1 in a - } - - var s = function(a) { - var b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u = "sizzle" + 1 * new Date, v = a.document, w = 0, x = 0, y = ha(), z = ha(), A = ha(), B = function(a, b) {return a === b && (l = !0), 0}, C = 1 << 31, D = {}.hasOwnProperty, E = [], F = E.pop, G = E.push, H = E.push, I = E.slice, J = function(a, b) { - for(var c = 0, d = a.length; d > c; c++) { - if (a[c] === b) { - return c; - } - } - return -1 - }, K = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", L = "[\\x20\\t\\r\\n\\f]", M = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", N = M.replace("w", "w#"), O = "\\[" + L + "*(" + M + ")(?:" + L + "*([*^$|!~]?=)" + L + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + N + "))|)" + L + "*\\]", P = ":(" + M + ")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|" + O + ")*)|.*)\\)|)", Q = new RegExp(L + "+", "g"), R = new RegExp("^" + L + "+|((?:^|[^\\\\])(?:\\\\.)*)" + L + "+$", "g"), S = new RegExp("^" + L + "*," + L + "*"), T = new RegExp("^" + L + "*([>+~]|" + L + ")" + L + "*"), U = new RegExp("=" + L + "*([^\\]'\"]*?)" + L + "*\\]", "g"), V = new RegExp(P), W = new RegExp("^" + N + "$"), X = { - ID: new RegExp("^#(" + M + ")"), - CLASS: new RegExp("^\\.(" + M + ")"), - TAG: new RegExp("^(" + M.replace("w", "w*") + ")"), - ATTR: new RegExp("^" + O), - PSEUDO: new RegExp("^" + P), - CHILD: new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + L + "*(even|odd|(([+-]|)(\\d*)n|)" + L + "*(?:([+-]|)" + L + "*(\\d+)|))" + L + "*\\)|)", "i"), - bool: new RegExp("^(?:" + K + ")$", "i"), - needsContext: new RegExp("^" + L + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + L + "*((?:-\\d)?\\d*)" + L + "*\\)|)(?=[^-]|$)", "i") - }, Y = /^(?:input|select|textarea|button)$/i, Z = /^h\d$/i, $ = /^[^{]+\{\s*\[native \w/, _ = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, aa = /[+~]/, ba = /'|\\/g, ca = new RegExp("\\\\([\\da-f]{1,6}" + L + "?|(" + L + ")|.)", "ig"), da = function(a, b, c) { - var d = "0x" + b - 65536; - return d !== d || c ? b : 0 > d ? String.fromCharCode(d + 65536) : String.fromCharCode(d >> 10 | 55296, 1023 & d | 56320) - }, ea = function() {m()}; - try {H.apply(E = I.call(v.childNodes), v.childNodes), E[v.childNodes.length].nodeType} - catch(fa) { - H = { - apply: E.length ? function(a, b) {G.apply(a, I.call(b))} : function(a, b) { - var c = a.length, d = 0; - while(a[c++] = b[d++]) { - ; - } - a.length = c - 1 - } - } - } - function ga(a, b, d, e) { - var f, h, j, k, l, o, r, s, w, x; - if ((b ? b.ownerDocument || b : v) !== n && m(b), b = b || n, d = d || [], k = b.nodeType, "string" != typeof a || !a || 1 !== k && 9 !== k && 11 !== k) { - return d; - } - if (!e && p) { - if (11 !== k && (f = _.exec(a))) { - if (j = f[1]) { - if (9 === k) { - if (h = b.getElementById(j), !h || !h.parentNode) { - return d; - } - if (h.id === j) { - return d.push(h), d - } - } else if (b.ownerDocument && (h = b.ownerDocument.getElementById(j)) && t(b, h) && h.id === j) { - return d.push(h), d - } - } else { - if (f[2]) { - return H.apply(d, b.getElementsByTagName(a)), d; - } - if ((j = f[3]) && c.getElementsByClassName) { - return H.apply(d, b.getElementsByClassName(j)), d - } - } - } - if (c.qsa && (!q || !q.test(a))) { - if (s = r = u, w = b, x = 1 !== k && a, 1 === k && "object" !== b.nodeName.toLowerCase()) { - o = g(a), (r = b.getAttribute("id")) ? s = r.replace(ba, "\\$&") : b.setAttribute("id", s), s = "[id='" + s + "'] ", l = o.length; - while(l--) { - o[l] = s + ra(o[l]); - } - w = aa.test(a) && pa(b.parentNode) || b, x = o.join(",") - } - if (x) { - try {return H.apply(d, w.querySelectorAll(x)), d} - catch(y) {} - finally {r || b.removeAttribute("id")} - } - } - } - return i(a.replace(R, "$1"), b, d, e) - } - - function ha() { - var a = []; - - function b(c, e) {return a.push(c + " ") > d.cacheLength && delete b[a.shift()], b[c + " "] = e} - - return b - } - - function ia(a) {return a[u] = !0, a} - - function ja(a) { - var b = n.createElement("div"); - try {return !!a(b)} - catch(c) {return !1} - finally {b.parentNode && b.parentNode.removeChild(b), b = null} - } - - function ka(a, b) { - var c = a.split("|"), e = a.length; - while(e--) { - d.attrHandle[c[e]] = b - } - } - - function la(a, b) { - var c = b && a, d = c && 1 === a.nodeType && 1 === b.nodeType && (~b.sourceIndex || C) - (~a.sourceIndex || C); - if (d) { - return d; - } - if (c) { - while(c = c.nextSibling) { - if (c === b) { - return -1; - } - } - } - return a ? 1 : -1 - } - - function ma(a) { - return function(b) { - var c = b.nodeName.toLowerCase(); - return "input" === c && b.type === a - } - } - - function na(a) { - return function(b) { - var c = b.nodeName.toLowerCase(); - return ("input" === c || "button" === c) && b.type === a - } - } - - function oa(a) { - return ia(function(b) { - return b = +b, ia(function(c, d) { - var e, f = a([], c.length, b), g = f.length; - while(g--) { - c[e = f[g]] && (c[e] = !(d[e] = c[e])) - } - }) - }) - } - - function pa(a) {return a && "undefined" != typeof a.getElementsByTagName && a} - - c = ga.support = {}, f = ga.isXML = function(a) { - var b = a && (a.ownerDocument || a).documentElement; - return b ? "HTML" !== b.nodeName : !1 - }, m = ga.setDocument = function(a) { - var b, e, g = a ? a.ownerDocument || a : v; - return g !== n && 9 === g.nodeType && g.documentElement ? (n = g, o = g.documentElement, e = g.defaultView, e && e !== e.top && (e.addEventListener ? e.addEventListener("unload", ea, !1) : e.attachEvent && e.attachEvent("onunload", ea)), p = !f(g), c.attributes = ja(function(a) {return a.className = "i", !a.getAttribute("className")}), c.getElementsByTagName = ja(function(a) {return a.appendChild(g.createComment("")), !a.getElementsByTagName("*").length}), c.getElementsByClassName = $.test(g.getElementsByClassName), c.getById = ja(function(a) {return o.appendChild(a).id = u, !g.getElementsByName || !g.getElementsByName(u).length}), c.getById ? (d.find.ID = function(a, b) { - if ("undefined" != typeof b.getElementById && p) { - var c = b.getElementById(a); - return c && c.parentNode ? [c] : [] - } - }, d.filter.ID = function(a) { - var b = a.replace(ca, da); - return function(a) {return a.getAttribute("id") === b} - }) : (delete d.find.ID, d.filter.ID = function(a) { - var b = a.replace(ca, da); - return function(a) { - var c = "undefined" != typeof a.getAttributeNode && a.getAttributeNode("id"); - return c && c.value === b - } - }), d.find.TAG = c.getElementsByTagName ? function(a, b) {return "undefined" != typeof b.getElementsByTagName ? b.getElementsByTagName(a) : c.qsa ? b.querySelectorAll(a) : void 0} : function(a, b) { - var c, d = [], e = 0, f = b.getElementsByTagName(a); - if ("*" === a) { - while(c = f[e++]) { - 1 === c.nodeType && d.push(c); - } - return d - } - return f - }, d.find.CLASS = c.getElementsByClassName && function(a, b) {return p ? b.getElementsByClassName(a) : void 0}, r = [], q = [], (c.qsa = $.test(g.querySelectorAll)) && (ja(function(a) {o.appendChild(a).innerHTML = "", a.querySelectorAll("[msallowcapture^='']").length && q.push("[*^$]=" + L + "*(?:''|\"\")"), a.querySelectorAll("[selected]").length || q.push("\\[" + L + "*(?:value|" + K + ")"), a.querySelectorAll("[id~=" + u + "-]").length || q.push("~="), a.querySelectorAll(":checked").length || q.push(":checked"), a.querySelectorAll("a#" + u + "+*").length || q.push(".#.+[+~]")}), ja(function(a) { - var b = g.createElement("input"); - b.setAttribute("type", "hidden"), a.appendChild(b).setAttribute("name", "D"), a.querySelectorAll("[name=d]").length && q.push("name" + L + "*[*^$|!~]?="), a.querySelectorAll(":enabled").length || q.push(":enabled", ":disabled"), a.querySelectorAll("*,:x"), q.push(",.*:") - })), (c.matchesSelector = $.test(s = o.matches || o.webkitMatchesSelector || o.mozMatchesSelector || o.oMatchesSelector || o.msMatchesSelector)) && ja(function(a) {c.disconnectedMatch = s.call(a, "div"), s.call(a, "[s!='']:x"), r.push("!=", P)}), q = q.length && new RegExp(q.join("|")), r = r.length && new RegExp(r.join("|")), b = $.test(o.compareDocumentPosition), t = b || $.test(o.contains) ? function(a, b) { - var c = 9 === a.nodeType ? a.documentElement : a, d = b && b.parentNode; - return a === d || !(!d || 1 !== d.nodeType || !(c.contains ? c.contains(d) : a.compareDocumentPosition && 16 & a.compareDocumentPosition(d))) - } : function(a, b) { - if (b) { - while(b = b.parentNode) { - if (b === a) { - return !0; - } - } - } - return !1 - }, B = b ? function(a, b) { - if (a === b) { - return l = !0, 0; - } - var d = !a.compareDocumentPosition - !b.compareDocumentPosition; - return d ? d : (d = (a.ownerDocument || a) === (b.ownerDocument || b) ? a.compareDocumentPosition(b) : 1, 1 & d || !c.sortDetached && b.compareDocumentPosition(a) === d ? a === g || a.ownerDocument === v && t(v, a) ? -1 : b === g || b.ownerDocument === v && t(v, b) ? 1 : k ? J(k, a) - J(k, b) : 0 : 4 & d ? -1 : 1) - } : function(a, b) { - if (a === b) { - return l = !0, 0; - } - var c, d = 0, e = a.parentNode, f = b.parentNode, h = [a], i = [b]; - if (!e || !f) { - return a === g ? -1 : b === g ? 1 : e ? -1 : f ? 1 : k ? J(k, a) - J(k, b) : 0; - } - if (e === f) { - return la(a, b); - } - c = a; - while(c = c.parentNode) { - h.unshift(c); - } - c = b; - while(c = c.parentNode) { - i.unshift(c); - } - while(h[d] === i[d]) { - d++; - } - return d ? la(h[d], i[d]) : h[d] === v ? -1 : i[d] === v ? 1 : 0 - }, g) : n - }, ga.matches = function(a, b) {return ga(a, null, null, b)}, ga.matchesSelector = function(a, b) { - if ((a.ownerDocument || a) !== n && m(a), b = b.replace(U, "='$1']"), !(!c.matchesSelector || !p || r && r.test(b) || q && q.test(b))) { - try { - var d = s.call(a, b); - if (d || c.disconnectedMatch || a.document && 11 !== a.document.nodeType) { - return d - } - } - catch(e) {} - } - return ga(b, n, null, [a]).length > 0 - }, ga.contains = function(a, b) {return (a.ownerDocument || a) !== n && m(a), t(a, b)}, ga.attr = function(a, b) { - (a.ownerDocument || a) !== n && m(a); - var e = d.attrHandle[b.toLowerCase()], f = e && D.call(d.attrHandle, b.toLowerCase()) ? e(a, b, !p) : void 0; - return void 0 !== f ? f : c.attributes || !p ? a.getAttribute(b) : (f = a.getAttributeNode(b)) && f.specified ? f.value : null - }, ga.error = function(a) {throw new Error("Syntax error, unrecognized expression: " + a)}, ga.uniqueSort = function(a) { - var b, d = [], e = 0, f = 0; - if (l = !c.detectDuplicates, k = !c.sortStable && a.slice(0), a.sort(B), l) { - while(b = a[f++]) { - b === a[f] && (e = d.push(f)); - } - while(e--) { - a.splice(d[e], 1) - } - } - return k = null, a - }, e = ga.getText = function(a) { - var b, c = "", d = 0, f = a.nodeType; - if (f) { - if (1 === f || 9 === f || 11 === f) { - if ("string" == typeof a.textContent) { - return a.textContent; - } - for(a = a.firstChild; a; a = a.nextSibling) { - c += e(a) - } - } else if (3 === f || 4 === f) { - return a.nodeValue - } - } else { - while(b = a[d++]) { - c += e(b); - } - } - return c - }, d = ga.selectors = { - cacheLength: 50, - createPseudo: ia, - match: X, - attrHandle: {}, - find: {}, - relative: { - ">": { dir: "parentNode", first: !0 }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: !0 }, - "~": { dir: "previousSibling" } - }, - preFilter: { - ATTR: function(a) {return a[1] = a[1].replace(ca, da), a[3] = (a[3] || a[4] || a[5] || "").replace(ca, da), "~=" === a[2] && (a[3] = " " + a[3] + " "), a.slice(0, 4)}, - CHILD: function(a) {return a[1] = a[1].toLowerCase(), "nth" === a[1].slice(0, 3) ? (a[3] || ga.error(a[0]), a[4] = +(a[4] ? a[5] + (a[6] || 1) : 2 * ("even" === a[3] || "odd" === a[3])), a[5] = +(a[7] + a[8] || "odd" === a[3])) : a[3] && ga.error(a[0]), a}, - PSEUDO: function(a) { - var b, c = !a[6] && a[2]; - return X.CHILD.test(a[0]) ? null : (a[3] ? a[2] = a[4] || a[5] || "" : c && V.test(c) && (b = g(c, !0)) && (b = c.indexOf(")", c.length - b) - c.length) && (a[0] = a[0].slice(0, b), a[2] = c.slice(0, b)), a.slice(0, 3)) - } - }, - filter: { - TAG: function(a) { - var b = a.replace(ca, da).toLowerCase(); - return "*" === a ? function() {return !0} : function(a) {return a.nodeName && a.nodeName.toLowerCase() === b} - }, CLASS: function(a) { - var b = y[a + " "]; - return b || (b = new RegExp("(^|" + L + ")" + a + "(" + L + "|$)")) && y(a, function(a) {return b.test("string" == typeof a.className && a.className || "undefined" != typeof a.getAttribute && a.getAttribute("class") || "")}) - }, ATTR: function(a, b, c) { - return function(d) { - var e = ga.attr(d, a); - return null == e ? "!=" === b : b ? (e += "", "=" === b ? e === c : "!=" === b ? e !== c : "^=" === b ? c && 0 === e.indexOf(c) : "*=" === b ? c && e.indexOf(c) > -1 : "$=" === b ? c && e.slice(-c.length) === c : "~=" === b ? (" " + e.replace(Q, " ") + " ").indexOf(c) > -1 : "|=" === b ? e === c || e.slice(0, c.length + 1) === c + "-" : !1) : !0 - } - }, CHILD: function(a, b, c, d, e) { - var f = "nth" !== a.slice(0, 3), g = "last" !== a.slice(-4), h = "of-type" === b; - return 1 === d && 0 === e ? function(a) {return !!a.parentNode} : function(b, c, i) { - var j, k, l, m, n, o, p = f !== g ? "nextSibling" : "previousSibling", q = b.parentNode, r = h && b.nodeName.toLowerCase(), s = !i && !h; - if (q) { - if (f) { - while(p) { - l = b; - while(l = l[p]) { - if (h ? l.nodeName.toLowerCase() === r : 1 === l.nodeType) { - return !1; - } - } - o = p = "only" === a && !o && "nextSibling" - } - return !0 - } - if (o = [g ? q.firstChild : q.lastChild], g && s) { - k = q[u] || (q[u] = {}), j = k[a] || [], n = j[0] === w && j[1], m = j[0] === w && j[2], l = n && q.childNodes[n]; - while(l = ++n && l && l[p] || (m = n = 0) || o.pop()) { - if (1 === l.nodeType && ++m && l === b) { - k[a] = [w, n, m]; - break - } - } - } else if (s && (j = (b[u] || (b[u] = {}))[a]) && j[0] === w) { - m = j[1]; - } else { - while(l = ++n && l && l[p] || (m = n = 0) || o.pop()) { - if ((h ? l.nodeName.toLowerCase() === r : 1 === l.nodeType) && ++m && (s && ((l[u] || (l[u] = {}))[a] = [w, m]), l === b)) { - break; - } - } - } - return m -= e, m === d || m % d === 0 && m / d >= 0 - } - } - }, PSEUDO: function(a, b) { - var c, e = d.pseudos[a] || d.setFilters[a.toLowerCase()] || ga.error("unsupported pseudo: " + a); - return e[u] ? e(b) : e.length > 1 ? (c = [a, a, "", b], d.setFilters.hasOwnProperty(a.toLowerCase()) ? ia(function(a, c) { - var d, f = e(a, b), g = f.length; - while(g--) { - d = J(a, f[g]), a[d] = !(c[d] = f[g]) - } - }) : function(a) {return e(a, 0, c)}) : e - } - }, - pseudos: { - not: ia(function(a) { - var b = [], c = [], d = h(a.replace(R, "$1")); - return d[u] ? ia(function(a, b, c, e) { - var f, g = d(a, null, e, []), h = a.length; - while(h--) { - (f = g[h]) && (a[h] = !(b[h] = f)) - } - }) : function(a, e, f) {return b[0] = a, d(b, null, f, c), b[0] = null, !c.pop()} - }), - has: ia(function(a) {return function(b) {return ga(a, b).length > 0}}), - contains: ia(function(a) {return a = a.replace(ca, da), function(b) {return (b.textContent || b.innerText || e(b)).indexOf(a) > -1}}), - lang: ia(function(a) { - return W.test(a || "") || ga.error("unsupported lang: " + a), a = a.replace(ca, da).toLowerCase(), function(b) { - var c; - do { - if (c = p ? b.lang : b.getAttribute("xml:lang") || b.getAttribute("lang")) { - return c = c.toLowerCase(), c === a || 0 === c.indexOf(a + "-"); - } - } while((b = b.parentNode) && 1 === b.nodeType); - return !1 - } - }), - target: function(b) { - var c = a.location && a.location.hash; - return c && c.slice(1) === b.id - }, - root: function(a) {return a === o}, - focus: function(a) {return a === n.activeElement && (!n.hasFocus || n.hasFocus()) && !!(a.type || a.href || ~a.tabIndex)}, - enabled: function(a) {return a.disabled === !1}, - disabled: function(a) {return a.disabled === !0}, - checked: function(a) { - var b = a.nodeName.toLowerCase(); - return "input" === b && !!a.checked || "option" === b && !!a.selected - }, - selected: function(a) {return a.parentNode && a.parentNode.selectedIndex, a.selected === !0}, - empty: function(a) { - for(a = a.firstChild; a; a = a.nextSibling) { - if (a.nodeType < 6) { - return !1; - } - } - return !0 - }, - parent: function(a) {return !d.pseudos.empty(a)}, - header: function(a) {return Z.test(a.nodeName)}, - input: function(a) {return Y.test(a.nodeName)}, - button: function(a) { - var b = a.nodeName.toLowerCase(); - return "input" === b && "button" === a.type || "button" === b - }, - text: function(a) { - var b; - return "input" === a.nodeName.toLowerCase() && "text" === a.type && (null == (b = a.getAttribute("type")) || "text" === b.toLowerCase()) - }, - first: oa(function() {return [0]}), - last: oa(function(a, b) {return [b - 1]}), - eq: oa(function(a, b, c) {return [0 > c ? c + b : c]}), - even: oa(function(a, b) { - for(var c = 0; b > c; c += 2) { - a.push(c); - } - return a - }), - odd: oa(function(a, b) { - for(var c = 1; b > c; c += 2) { - a.push(c); - } - return a - }), - lt: oa(function(a, b, c) { - for(var d = 0 > c ? c + b : c; --d >= 0;) { - a.push(d); - } - return a - }), - gt: oa(function(a, b, c) { - for(var d = 0 > c ? c + b : c; ++d < b;) { - a.push(d); - } - return a - }) - } - }, d.pseudos.nth = d.pseudos.eq; - for(b in{ radio: !0, checkbox: !0, file: !0, password: !0, image: !0 }) { - d.pseudos[b] = ma(b); - } - for(b in{ submit: !0, reset: !0 }) { - d.pseudos[b] = na(b); - } - function qa() {} - - qa.prototype = d.filters = d.pseudos, d.setFilters = new qa, g = ga.tokenize = function(a, b) { - var c, e, f, g, h, i, j, k = z[a + " "]; - if (k) { - return b ? 0 : k.slice(0); - } - h = a, i = [], j = d.preFilter; - while(h) { - (!c || (e = S.exec(h))) && (e && (h = h.slice(e[0].length) || h), i.push(f = [])), c = !1, (e = T.exec(h)) && (c = e.shift(), f.push({ - value: c, - type: e[0].replace(R, " ") - }), h = h.slice(c.length)); - for(g in d.filter) { - !(e = X[g].exec(h)) || j[g] && !(e = j[g](e)) || (c = e.shift(), f.push({ - value: c, - type: g, - matches: e - }), h = h.slice(c.length)); - } - if (!c) { - break - } - } - return b ? h.length : h ? ga.error(a) : z(a, i).slice(0) - }; - function ra(a) { - for(var b = 0, c = a.length, d = ""; c > b; b++) { - d += a[b].value; - } - return d - } - - function sa(a, b, c) { - var d = b.dir, e = c && "parentNode" === d, f = x++; - return b.first ? function(b, c, f) { - while(b = b[d]) { - if (1 === b.nodeType || e) { - return a(b, c, f) - } - } - } : function(b, c, g) { - var h, i, j = [w, f]; - if (g) { - while(b = b[d]) { - if ((1 === b.nodeType || e) && a(b, c, g)) { - return !0 - } - } - } else { - while(b = b[d]) { - if (1 === b.nodeType || e) { - if (i = b[u] || (b[u] = {}), (h = i[d]) && h[0] === w && h[1] === f) { - return j[2] = h[2]; - } - if (i[d] = j, j[2] = a(b, c, g)) { - return !0 - } - } - } - } - } - } - - function ta(a) { - return a.length > 1 ? function(b, c, d) { - var e = a.length; - while(e--) { - if (!a[e](b, c, d)) { - return !1; - } - } - return !0 - } : a[0] - } - - function ua(a, b, c) { - for(var d = 0, e = b.length; e > d; d++) { - ga(a, b[d], c); - } - return c - } - - function va(a, b, c, d, e) { - for(var f, g = [], h = 0, i = a.length, j = null != b; i > h; h++) { - (f = a[h]) && (!c || c(f, d, e)) && (g.push(f), j && b.push(h)); - } - return g - } - - function wa(a, b, c, d, e, f) { - return d && !d[u] && (d = wa(d)), e && !e[u] && (e = wa(e, f)), ia(function(f, g, h, i) { - var j, k, l, m = [], n = [], o = g.length, p = f || ua(b || "*", h.nodeType ? [h] : h, []), q = !a || !f && b ? p : va(p, m, a, h, i), r = c ? e || (f ? a : o || d) ? [] : g : q; - if (c && c(q, r, h, i), d) { - j = va(r, n), d(j, [], h, i), k = j.length; - while(k--) { - (l = j[k]) && (r[n[k]] = !(q[n[k]] = l)) - } - } - if (f) { - if (e || a) { - if (e) { - j = [], k = r.length; - while(k--) { - (l = r[k]) && j.push(q[k] = l); - } - e(null, r = [], j, i) - } - k = r.length; - while(k--) { - (l = r[k]) && (j = e ? J(f, l) : m[k]) > -1 && (f[j] = !(g[j] = l)) - } - } - } else { - r = va(r === g ? r.splice(o, r.length) : r), e ? e(null, g, r, i) : H.apply(g, r) - } - }) - } - - function xa(a) { - for(var b, c, e, f = a.length, g = d.relative[a[0].type], h = g || d.relative[" "], i = g ? 1 : 0, k = sa(function(a) {return a === b}, h, !0), l = sa(function(a) {return J(b, a) > -1}, h, !0), m = [function(a, c, d) { - var e = !g && (d || c !== j) || ((b = c).nodeType ? k(a, c, d) : l(a, c, d)); - return b = null, e - }]; f > i; i++) { - if (c = d.relative[a[i].type]) { - m = [sa(ta(m), c)]; - } else { - if (c = d.filter[a[i].type].apply(null, a[i].matches), c[u]) { - for(e = ++i; f > e; e++) { - if (d.relative[a[e].type]) { - break; - } - } - return wa(i > 1 && ta(m), i > 1 && ra(a.slice(0, i - 1).concat({ value: " " === a[i - 2].type ? "*" : "" })).replace(R, "$1"), c, e > i && xa(a.slice(i, e)), f > e && xa(a = a.slice(e)), f > e && ra(a)) - } - m.push(c) - } - } - return ta(m) - } - - function ya(a, b) { - var c = b.length > 0, e = a.length > 0, f = function(f, g, h, i, k) { - var l, m, o, p = 0, q = "0", r = f && [], s = [], t = j, u = f || e && d.find.TAG("*", k), v = w += null == t ? 1 : Math.random() || .1, x = u.length; - for(k && (j = g !== n && g); q !== x && null != (l = u[q]); q++) { - if (e && l) { - m = 0; - while(o = a[m++]) { - if (o(l, g, h)) { - i.push(l); - break - } - } - k && (w = v) - } - c && ((l = !o && l) && p--, f && r.push(l)) - } - if (p += q, c && q !== p) { - m = 0; - while(o = b[m++]) { - o(r, s, g, h); - } - if (f) { - if (p > 0) { - while(q--) { - r[q] || s[q] || (s[q] = F.call(i)); - } - } - s = va(s) - } - H.apply(i, s), k && !f && s.length > 0 && p + b.length > 1 && ga.uniqueSort(i) - } - return k && (w = v, j = t), r - }; - return c ? ia(f) : f - } - - return h = ga.compile = function(a, b) { - var c, d = [], e = [], f = A[a + " "]; - if (!f) { - b || (b = g(a)), c = b.length; - while(c--) { - f = xa(b[c]), f[u] ? d.push(f) : e.push(f); - } - f = A(a, ya(e, d)), f.selector = a - } - return f - }, i = ga.select = function(a, b, e, f) { - var i, j, k, l, m, n = "function" == typeof a && a, o = !f && g(a = n.selector || a); - if (e = e || [], 1 === o.length) { - if (j = o[0] = o[0].slice(0), j.length > 2 && "ID" === (k = j[0]).type && c.getById && 9 === b.nodeType && p && d.relative[j[1].type]) { - if (b = (d.find.ID(k.matches[0].replace(ca, da), b) || [])[0], !b) { - return e; - } - n && (b = b.parentNode), a = a.slice(j.shift().value.length) - } - i = X.needsContext.test(a) ? 0 : j.length; - while(i--) { - if (k = j[i], d.relative[l = k.type]) { - break; - } - if ((m = d.find[l]) && (f = m(k.matches[0].replace(ca, da), aa.test(j[0].type) && pa(b.parentNode) || b))) { - if (j.splice(i, 1), a = f.length && ra(j), !a) { - return H.apply(e, f), e; - } - break - } - } - } - return (n || h(a, o))(f, b, !p, e, aa.test(a) && pa(b.parentNode) || b), e - }, c.sortStable = u.split("").sort(B).join("") === u, c.detectDuplicates = !!l, m(), c.sortDetached = ja(function(a) {return 1 & a.compareDocumentPosition(n.createElement("div"))}), ja(function(a) {return a.innerHTML = "", "#" === a.firstChild.getAttribute("href")}) || ka("type|href|height|width", function(a, b, c) {return c ? void 0 : a.getAttribute(b, "type" === b.toLowerCase() ? 1 : 2)}), c.attributes && ja(function(a) {return a.innerHTML = "", a.firstChild.setAttribute("value", ""), "" === a.firstChild.getAttribute("value")}) || ka("value", function(a, b, c) {return c || "input" !== a.nodeName.toLowerCase() ? void 0 : a.defaultValue}), ja(function(a) {return null == a.getAttribute("disabled")}) || ka(K, function(a, b, c) { - var d; - return c ? void 0 : a[b] === !0 ? b.toLowerCase() : (d = a.getAttributeNode(b)) && d.specified ? d.value : null - }), ga - }(a); - m.find = s, m.expr = s.selectors, m.expr[":"] = m.expr.pseudos, m.unique = s.uniqueSort, m.text = s.getText, m.isXMLDoc = s.isXML, m.contains = s.contains; - var t = m.expr.match.needsContext, u = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, v = /^.[^:#\[\.,]*$/; - - function w(a, b, c) { - if (m.isFunction(b)) { - return m.grep(a, function(a, d) {return !!b.call(a, d, a) !== c}); - } - if (b.nodeType) { - return m.grep(a, function(a) {return a === b !== c}); - } - if ("string" == typeof b) { - if (v.test(b)) { - return m.filter(b, a, c); - } - b = m.filter(b, a) - } - return m.grep(a, function(a) {return m.inArray(a, b) >= 0 !== c}) - } - - m.filter = function(a, b, c) { - var d = b[0]; - return c && (a = ":not(" + a + ")"), 1 === b.length && 1 === d.nodeType ? m.find.matchesSelector(d, a) ? [d] : [] : m.find.matches(a, m.grep(b, function(a) {return 1 === a.nodeType})) - }, m.fn.extend({ - find: function(a) { - var b, c = [], d = this, e = d.length; - if ("string" != typeof a) { - return this.pushStack(m(a).filter(function() { - for(b = 0; e > b; b++) { - if (m.contains(d[b], this)) { - return !0 - } - } - })); - } - for(b = 0; e > b; b++) { - m.find(a, d[b], c); - } - return c = this.pushStack(e > 1 ? m.unique(c) : c), c.selector = this.selector ? this.selector + " " + a : a, c - }, - filter: function(a) {return this.pushStack(w(this, a || [], !1))}, - not: function(a) {return this.pushStack(w(this, a || [], !0))}, - is: function(a) {return !!w(this, "string" == typeof a && t.test(a) ? m(a) : a || [], !1).length} - }); - var x, y = a.document, z = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, A = m.fn.init = function(a, b) { - var c, d; - if (!a) { - return this; - } - if ("string" == typeof a) { - if (c = "<" === a.charAt(0) && ">" === a.charAt(a.length - 1) && a.length >= 3 ? [null, a, null] : z.exec(a), !c || !c[1] && b) { - return !b || b.jquery ? (b || x).find(a) : this.constructor(b).find(a); - } - if (c[1]) { - if (b = b instanceof m ? b[0] : b, m.merge(this, m.parseHTML(c[1], b && b.nodeType ? b.ownerDocument || b : y, !0)), u.test(c[1]) && m.isPlainObject(b)) { - for(c in b) { - m.isFunction(this[c]) ? this[c](b[c]) : this.attr(c, b[c]); - } - } - return this - } - if (d = y.getElementById(c[2]), d && d.parentNode) { - if (d.id !== c[2]) { - return x.find(a); - } - this.length = 1, this[0] = d - } - return this.context = y, this.selector = a, this - } - return a.nodeType ? (this.context = this[0] = a, this.length = 1, this) : m.isFunction(a) ? "undefined" != typeof x.ready ? x.ready(a) : a(m) : (void 0 !== a.selector && (this.selector = a.selector, this.context = a.context), m.makeArray(a, this)) - }; - A.prototype = m.fn, x = m(y); - var B = /^(?:parents|prev(?:Until|All))/, C = { children: !0, contents: !0, next: !0, prev: !0 }; - m.extend({ - dir: function(a, b, c) { - var d = [], e = a[b]; - while(e && 9 !== e.nodeType && (void 0 === c || 1 !== e.nodeType || !m(e).is(c))) { - 1 === e.nodeType && d.push(e), e = e[b]; - } - return d - }, sibling: function(a, b) { - for(var c = []; a; a = a.nextSibling) { - 1 === a.nodeType && a !== b && c.push(a); - } - return c - } - }), m.fn.extend({ - has: function(a) { - var b, c = m(a, this), d = c.length; - return this.filter(function() { - for(b = 0; d > b; b++) { - if (m.contains(this, c[b])) { - return !0 - } - } - }) - }, - closest: function(a, b) { - for(var c, d = 0, e = this.length, f = [], g = t.test(a) || "string" != typeof a ? m(a, b || this.context) : 0; e > d; d++) { - for(c = this[d]; c && c !== b; c = c.parentNode) { - if (c.nodeType < 11 && (g ? g.index(c) > -1 : 1 === c.nodeType && m.find.matchesSelector(c, a))) { - f.push(c); - break - } - } - } - return this.pushStack(f.length > 1 ? m.unique(f) : f) - }, - index: function(a) {return a ? "string" == typeof a ? m.inArray(this[0], m(a)) : m.inArray(a.jquery ? a[0] : a, this) : this[0] && this[0].parentNode ? this.first().prevAll().length : -1}, - add: function(a, b) {return this.pushStack(m.unique(m.merge(this.get(), m(a, b))))}, - addBack: function(a) {return this.add(null == a ? this.prevObject : this.prevObject.filter(a))} - }); - function D(a, b) { - do { - a = a[b]; - } while(a && 1 !== a.nodeType); - return a - } - - m.each({ - parent: function(a) { - var b = a.parentNode; - return b && 11 !== b.nodeType ? b : null - }, - parents: function(a) {return m.dir(a, "parentNode")}, - parentsUntil: function(a, b, c) {return m.dir(a, "parentNode", c)}, - next: function(a) {return D(a, "nextSibling")}, - prev: function(a) {return D(a, "previousSibling")}, - nextAll: function(a) {return m.dir(a, "nextSibling")}, - prevAll: function(a) {return m.dir(a, "previousSibling")}, - nextUntil: function(a, b, c) {return m.dir(a, "nextSibling", c)}, - prevUntil: function(a, b, c) {return m.dir(a, "previousSibling", c)}, - siblings: function(a) {return m.sibling((a.parentNode || {}).firstChild, a)}, - children: function(a) {return m.sibling(a.firstChild)}, - contents: function(a) {return m.nodeName(a, "iframe") ? a.contentDocument || a.contentWindow.document : m.merge([], a.childNodes)} - }, function(a, b) { - m.fn[a] = function(c, d) { - var e = m.map(this, b, c); - return "Until" !== a.slice(-5) && (d = c), d && "string" == typeof d && (e = m.filter(d, e)), this.length > 1 && (C[a] || (e = m.unique(e)), B.test(a) && (e = e.reverse())), this.pushStack(e) - } - }); - var E = /\S+/g, F = {}; - - function G(a) { - var b = F[a] = {}; - return m.each(a.match(E) || [], function(a, c) {b[c] = !0}), b - } - - m.Callbacks = function(a) { - a = "string" == typeof a ? F[a] || G(a) : m.extend({}, a); - var b, c, d, e, f, g, h = [], i = !a.once && [], j = function(l) { - for(c = a.memory && l, d = !0, f = g || 0, g = 0, e = h.length, b = !0; h && e > f; f++) { - if (h[f].apply(l[0], l[1]) === !1 && a.stopOnFalse) { - c = !1; - break - } - } - b = !1, h && (i ? i.length && j(i.shift()) : c ? h = [] : k.disable()) - }, k = { - add: function() { - if (h) { - var d = h.length; - !function f(b) { - m.each(b, function(b, c) { - var d = m.type(c); - "function" === d ? a.unique && k.has(c) || h.push(c) : c && c.length && "string" !== d && f(c) - }) - }(arguments), b ? e = h.length : c && (g = d, j(c)) - } - return this - }, - remove: function() { - return h && m.each(arguments, function(a, c) { - var d; - while((d = m.inArray(c, h, d)) > -1) { - h.splice(d, 1), b && (e >= d && e--, f >= d && f--) - } - }), this - }, - has: function(a) {return a ? m.inArray(a, h) > -1 : !(!h || !h.length)}, - empty: function() {return h = [], e = 0, this}, - disable: function() {return h = i = c = void 0, this}, - disabled: function() {return !h}, - lock: function() {return i = void 0, c || k.disable(), this}, - locked: function() {return !i}, - fireWith: function(a, c) {return !h || d && !i || (c = c || [], c = [a, c.slice ? c.slice() : c], b ? i.push(c) : j(c)), this}, - fire: function() {return k.fireWith(this, arguments), this}, - fired: function() {return !!d} - }; - return k - }, m.extend({ - Deferred: function(a) { - var b = [["resolve", "done", m.Callbacks("once memory"), "resolved"], ["reject", "fail", m.Callbacks("once memory"), "rejected"], ["notify", "progress", m.Callbacks("memory")]], c = "pending", d = { - state: function() {return c}, - always: function() {return e.done(arguments).fail(arguments), this}, - then: function() { - var a = arguments; - return m.Deferred(function(c) { - m.each(b, function(b, f) { - var g = m.isFunction(a[b]) && a[b]; - e[f[1]](function() { - var a = g && g.apply(this, arguments); - a && m.isFunction(a.promise) ? a.promise().done(c.resolve).fail(c.reject).progress(c.notify) : c[f[0] + "With"](this === d ? c.promise() : this, g ? [a] : arguments) - }) - }), a = null - }).promise() - }, - promise: function(a) {return null != a ? m.extend(a, d) : d} - }, e = {}; - return d.pipe = d.then, m.each(b, function(a, f) { - var g = f[2], h = f[3]; - d[f[1]] = g.add, h && g.add(function() {c = h}, b[1 ^ a][2].disable, b[2][2].lock), e[f[0]] = function() {return e[f[0] + "With"](this === e ? d : this, arguments), this}, e[f[0] + "With"] = g.fireWith - }), d.promise(e), a && a.call(e, e), e - }, - when: function(a) { - var b = 0, c = d.call(arguments), e = c.length, f = 1 !== e || a && m.isFunction(a.promise) ? e : 0, g = 1 === f ? a : m.Deferred(), h = function(a, b, c) {return function(e) {b[a] = this, c[a] = arguments.length > 1 ? d.call(arguments) : e, c === i ? g.notifyWith(b, c) : --f || g.resolveWith(b, c)}}, i, j, k; - if (e > 1) { - for(i = new Array(e), j = new Array(e), k = new Array(e); e > b; b++) { - c[b] && m.isFunction(c[b].promise) ? c[b].promise().done(h(b, k, c)).fail(g.reject).progress(h(b, j, i)) : --f; - } - } - return f || g.resolveWith(k, c), g.promise() - } - }); - var H; - m.fn.ready = function(a) {return m.ready.promise().done(a), this}, m.extend({ - isReady: !1, - readyWait: 1, - holdReady: function(a) {a ? m.readyWait++ : m.ready(!0)}, - ready: function(a) { - if (a === !0 ? !--m.readyWait : !m.isReady) { - if (!y.body) { - return setTimeout(m.ready); - } - m.isReady = !0, a !== !0 && --m.readyWait > 0 || (H.resolveWith(y, [m]), m.fn.triggerHandler && (m(y).triggerHandler("ready"), m(y).off("ready"))) - } - } - }); - function I() {y.addEventListener ? (y.removeEventListener("DOMContentLoaded", J, !1), a.removeEventListener("load", J, !1)) : (y.detachEvent("onreadystatechange", J), a.detachEvent("onload", J))} - - function J() {(y.addEventListener || "load" === event.type || "complete" === y.readyState) && (I(), m.ready())} - - m.ready.promise = function(b) { - if (!H) { - if (H = m.Deferred(), "complete" === y.readyState) { - setTimeout(m.ready); - } else if (y.addEventListener) { - y.addEventListener("DOMContentLoaded", J, !1), a.addEventListener("load", J, !1); - } else { - y.attachEvent("onreadystatechange", J), a.attachEvent("onload", J); - var c = !1; - try {c = null == a.frameElement && y.documentElement} - catch(d) {} - c && c.doScroll && !function e() { - if (!m.isReady) { - try {c.doScroll("left")} - catch(a) {return setTimeout(e, 50)} - I(), m.ready() - } - }() - } - } - return H.promise(b) - }; - var K = "undefined", L; - for(L in m(k)) { - break; - } - k.ownLast = "0" !== L, k.inlineBlockNeedsLayout = !1, m(function() { - var a, b, c, d; - c = y.getElementsByTagName("body")[0], c && c.style && (b = y.createElement("div"), d = y.createElement("div"), d.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px", c.appendChild(d).appendChild(b), typeof b.style.zoom !== K && (b.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1", k.inlineBlockNeedsLayout = a = 3 === b.offsetWidth, a && (c.style.zoom = 1)), c.removeChild(d)) - }), function() { - var a = y.createElement("div"); - if (null == k.deleteExpando) { - k.deleteExpando = !0; - try {delete a.test} - catch(b) {k.deleteExpando = !1} - } - a = null - }(), m.acceptData = function(a) { - var b = m.noData[(a.nodeName + " ").toLowerCase()], c = +a.nodeType || 1; - return 1 !== c && 9 !== c ? !1 : !b || b !== !0 && a.getAttribute("classid") === b - }; - var M = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, N = /([A-Z])/g; - - function O(a, b, c) { - if (void 0 === c && 1 === a.nodeType) { - var d = "data-" + b.replace(N, "-$1").toLowerCase(); - if (c = a.getAttribute(d), "string" == typeof c) { - try {c = "true" === c ? !0 : "false" === c ? !1 : "null" === c ? null : +c + "" === c ? +c : M.test(c) ? m.parseJSON(c) : c} - catch(e) {} - m.data(a, b, c) - } else { - c = void 0 - } - } - return c - } - - function P(a) { - var b; - for(b in a) { - if (("data" !== b || !m.isEmptyObject(a[b])) && "toJSON" !== b) { - return !1; - } - } - - return !0 - } - - function Q(a, b, d, e) { - if (m.acceptData(a)) { - var f, g, h = m.expando, i = a.nodeType, j = i ? m.cache : a, k = i ? a[h] : a[h] && h; - if (k && j[k] && (e || j[k].data) || void 0 !== d || "string" != typeof b) { - return k || (k = i ? a[h] = c.pop() || m.guid++ : h), j[k] || (j[k] = i ? {} : { toJSON: m.noop }), ("object" == typeof b || "function" == typeof b) && (e ? j[k] = m.extend(j[k], b) : j[k].data = m.extend(j[k].data, b)), g = j[k], e || (g.data || (g.data = {}), g = g.data), void 0 !== d && (g[m.camelCase(b)] = d), "string" == typeof b ? (f = g[b], null == f && (f = g[m.camelCase(b)])) : f = g, f - } - } - } - - function R(a, b, c) { - if (m.acceptData(a)) { - var d, e, f = a.nodeType, g = f ? m.cache : a, h = f ? a[m.expando] : m.expando; - if (g[h]) { - if (b && (d = c ? g[h] : g[h].data)) { - m.isArray(b) ? b = b.concat(m.map(b, m.camelCase)) : b in d ? b = [b] : (b = m.camelCase(b), b = b in d ? [b] : b.split(" ")), e = b.length; - while(e--) { - delete d[b[e]]; - } - if (c ? !P(d) : !m.isEmptyObject(d)) { - return - } - } - (c || (delete g[h].data, P(g[h]))) && (f ? m.cleanData([a], !0) : k.deleteExpando || g != g.window ? delete g[h] : g[h] = null) - } - } - } - - m.extend({ - cache: {}, - noData: { "applet ": !0, "embed ": !0, "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" }, - hasData: function(a) {return a = a.nodeType ? m.cache[a[m.expando]] : a[m.expando], !!a && !P(a)}, - data: function(a, b, c) {return Q(a, b, c)}, - removeData: function(a, b) {return R(a, b)}, - _data: function(a, b, c) {return Q(a, b, c, !0)}, - _removeData: function(a, b) {return R(a, b, !0)} - }), m.fn.extend({ - data: function(a, b) { - var c, d, e, f = this[0], g = f && f.attributes; - if (void 0 === a) { - if (this.length && (e = m.data(f), 1 === f.nodeType && !m._data(f, "parsedAttrs"))) { - c = g.length; - while(c--) { - g[c] && (d = g[c].name, 0 === d.indexOf("data-") && (d = m.camelCase(d.slice(5)), O(f, d, e[d]))); - } - m._data(f, "parsedAttrs", !0) - } - return e - } - return "object" == typeof a ? this.each(function() {m.data(this, a)}) : arguments.length > 1 ? this.each(function() {m.data(this, a, b)}) : f ? O(f, a, m.data(f, a)) : void 0 - }, removeData: function(a) {return this.each(function() {m.removeData(this, a)})} - }), m.extend({ - queue: function(a, b, c) { - var d; - return a ? (b = (b || "fx") + "queue", d = m._data(a, b), c && (!d || m.isArray(c) ? d = m._data(a, b, m.makeArray(c)) : d.push(c)), d || []) : void 0 - }, dequeue: function(a, b) { - b = b || "fx"; - var c = m.queue(a, b), d = c.length, e = c.shift(), f = m._queueHooks(a, b), g = function() {m.dequeue(a, b)}; - "inprogress" === e && (e = c.shift(), d--), e && ("fx" === b && c.unshift("inprogress"), delete f.stop, e.call(a, g, f)), !d && f && f.empty.fire() - }, _queueHooks: function(a, b) { - var c = b + "queueHooks"; - return m._data(a, c) || m._data(a, c, { empty: m.Callbacks("once memory").add(function() {m._removeData(a, b + "queue"), m._removeData(a, c)}) }) - } - }), m.fn.extend({ - queue: function(a, b) { - var c = 2; - return "string" != typeof a && (b = a, a = "fx", c--), arguments.length < c ? m.queue(this[0], a) : void 0 === b ? this : this.each(function() { - var c = m.queue(this, a, b); - m._queueHooks(this, a), "fx" === a && "inprogress" !== c[0] && m.dequeue(this, a) - }) - }, - dequeue: function(a) {return this.each(function() {m.dequeue(this, a)})}, - clearQueue: function(a) {return this.queue(a || "fx", [])}, - promise: function(a, b) { - var c, d = 1, e = m.Deferred(), f = this, g = this.length, h = function() {--d || e.resolveWith(f, [f])}; - "string" != typeof a && (b = a, a = void 0), a = a || "fx"; - while(g--) { - c = m._data(f[g], a + "queueHooks"), c && c.empty && (d++, c.empty.add(h)); - } - return h(), e.promise(b) - } - }); - var S = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, T = ["Top", "Right", "Bottom", "Left"], U = function(a, b) {return a = b || a, "none" === m.css(a, "display") || !m.contains(a.ownerDocument, a)}, V = m.access = function(a, b, c, d, e, f, g) { - var h = 0, i = a.length, j = null == c; - if ("object" === m.type(c)) { - e = !0; - for(h in c) { - m.access(a, b, h, c[h], !0, f, g) - } - } else if (void 0 !== d && (e = !0, m.isFunction(d) || (g = !0), j && (g ? (b.call(a, d), b = null) : (j = b, b = function(a, b, c) {return j.call(m(a), c)})), b)) { - for(; i > h; h++) { - b(a[h], c, g ? d : d.call(a[h], h, b(a[h], c))); - } - } - return e ? a : j ? b.call(a) : i ? b(a[0], c) : f - }, W = /^(?:checkbox|radio)$/i; - !function() { - var a = y.createElement("input"), b = y.createElement("div"), c = y.createDocumentFragment(); - if (b.innerHTML = "
a", k.leadingWhitespace = 3 === b.firstChild.nodeType, k.tbody = !b.getElementsByTagName("tbody").length, k.htmlSerialize = !!b.getElementsByTagName("link").length, k.html5Clone = "<:nav>" !== y.createElement("nav").cloneNode(!0).outerHTML, a.type = "checkbox", a.checked = !0, c.appendChild(a), k.appendChecked = a.checked, b.innerHTML = "", k.noCloneChecked = !!b.cloneNode(!0).lastChild.defaultValue, c.appendChild(b), b.innerHTML = "", k.checkClone = b.cloneNode(!0).cloneNode(!0).lastChild.checked, k.noCloneEvent = !0, b.attachEvent && (b.attachEvent("onclick", function() {k.noCloneEvent = !1}), b.cloneNode(!0).click()), null == k.deleteExpando) { - k.deleteExpando = !0; - try {delete b.test} - catch(d) {k.deleteExpando = !1} - } - }(), function() { - var b, c, d = y.createElement("div"); - for(b in{ - submit: !0, - change: !0, - focusin: !0 - }) { - c = "on" + b, (k[b + "Bubbles"] = c in a) || (d.setAttribute(c, "t"), k[b + "Bubbles"] = d.attributes[c].expando === !1); - } - d = null - }(); - var X = /^(?:input|select|textarea)$/i, Y = /^key/, Z = /^(?:mouse|pointer|contextmenu)|click/, $ = /^(?:focusinfocus|focusoutblur)$/, _ = /^([^.]*)(?:\.(.+)|)$/; - - function aa() {return !0} - - function ba() {return !1} - - function ca() { - try {return y.activeElement} - catch(a) {} - } - - m.event = { - global: {}, - add: function(a, b, c, d, e) { - var f, g, h, i, j, k, l, n, o, p, q, r = m._data(a); - if (r) { - c.handler && (i = c, c = i.handler, e = i.selector), c.guid || (c.guid = m.guid++), (g = r.events) || (g = r.events = {}), (k = r.handle) || (k = r.handle = function(a) {return typeof m === K || a && m.event.triggered === a.type ? void 0 : m.event.dispatch.apply(k.elem, arguments)}, k.elem = a), b = (b || "").match(E) || [""], h = b.length; - while(h--) { - f = _.exec(b[h]) || [], o = q = f[1], p = (f[2] || "").split(".").sort(), o && (j = m.event.special[o] || {}, o = (e ? j.delegateType : j.bindType) || o, j = m.event.special[o] || {}, l = m.extend({ - type: o, - origType: q, - data: d, - handler: c, - guid: c.guid, - selector: e, - needsContext: e && m.expr.match.needsContext.test(e), - namespace: p.join(".") - }, i), (n = g[o]) || (n = g[o] = [], n.delegateCount = 0, j.setup && j.setup.call(a, d, p, k) !== !1 || (a.addEventListener ? a.addEventListener(o, k, !1) : a.attachEvent && a.attachEvent("on" + o, k))), j.add && (j.add.call(a, l), l.handler.guid || (l.handler.guid = c.guid)), e ? n.splice(n.delegateCount++, 0, l) : n.push(l), m.event.global[o] = !0); - } - a = null - } - }, - remove: function(a, b, c, d, e) { - var f, g, h, i, j, k, l, n, o, p, q, r = m.hasData(a) && m._data(a); - if (r && (k = r.events)) { - b = (b || "").match(E) || [""], j = b.length; - while(j--) { - if (h = _.exec(b[j]) || [], o = q = h[1], p = (h[2] || "").split(".").sort(), o) { - l = m.event.special[o] || {}, o = (d ? l.delegateType : l.bindType) || o, n = k[o] || [], h = h[2] && new RegExp("(^|\\.)" + p.join("\\.(?:.*\\.|)") + "(\\.|$)"), i = f = n.length; - while(f--) { - g = n[f], !e && q !== g.origType || c && c.guid !== g.guid || h && !h.test(g.namespace) || d && d !== g.selector && ("**" !== d || !g.selector) || (n.splice(f, 1), g.selector && n.delegateCount--, l.remove && l.remove.call(a, g)); - } - i && !n.length && (l.teardown && l.teardown.call(a, p, r.handle) !== !1 || m.removeEvent(a, o, r.handle), delete k[o]) - } else { - for(o in k) { - m.event.remove(a, o + b[j], c, d, !0); - } - } - } - m.isEmptyObject(k) && (delete r.handle, m._removeData(a, "events")) - } - }, - trigger: function(b, c, d, e) { - var f, g, h, i, k, l, n, o = [d || y], p = j.call(b, "type") ? b.type : b, q = j.call(b, "namespace") ? b.namespace.split(".") : []; - if (h = l = d = d || y, 3 !== d.nodeType && 8 !== d.nodeType && !$.test(p + m.event.triggered) && (p.indexOf(".") >= 0 && (q = p.split("."), p = q.shift(), q.sort()), g = p.indexOf(":") < 0 && "on" + p, b = b[m.expando] ? b : new m.Event(p, "object" == typeof b && b), b.isTrigger = e ? 2 : 3, b.namespace = q.join("."), b.namespace_re = b.namespace ? new RegExp("(^|\\.)" + q.join("\\.(?:.*\\.|)") + "(\\.|$)") : null, b.result = void 0, b.target || (b.target = d), c = null == c ? [b] : m.makeArray(c, [b]), k = m.event.special[p] || {}, e || !k.trigger || k.trigger.apply(d, c) !== !1)) { - if (!e && !k.noBubble && !m.isWindow(d)) { - for(i = k.delegateType || p, $.test(i + p) || (h = h.parentNode); h; h = h.parentNode) { - o.push(h), l = h; - } - l === (d.ownerDocument || y) && o.push(l.defaultView || l.parentWindow || a) - } - n = 0; - while((h = o[n++]) && !b.isPropagationStopped()) { - b.type = n > 1 ? i : k.bindType || p, f = (m._data(h, "events") || {})[b.type] && m._data(h, "handle"), f && f.apply(h, c), f = g && h[g], f && f.apply && m.acceptData(h) && (b.result = f.apply(h, c), b.result === !1 && b.preventDefault()); - } - if (b.type = p, !e && !b.isDefaultPrevented() && (!k._default || k._default.apply(o.pop(), c) === !1) && m.acceptData(d) && g && d[p] && !m.isWindow(d)) { - l = d[g], l && (d[g] = null), m.event.triggered = p; - try {d[p]()} - catch(r) {} - m.event.triggered = void 0, l && (d[g] = l) - } - return b.result - } - }, - dispatch: function(a) { - a = m.event.fix(a); - var b, c, e, f, g, h = [], i = d.call(arguments), j = (m._data(this, "events") || {})[a.type] || [], k = m.event.special[a.type] || {}; - if (i[0] = a, a.delegateTarget = this, !k.preDispatch || k.preDispatch.call(this, a) !== !1) { - h = m.event.handlers.call(this, a, j), b = 0; - while((f = h[b++]) && !a.isPropagationStopped()) { - a.currentTarget = f.elem, g = 0; - while((e = f.handlers[g++]) && !a.isImmediatePropagationStopped()) { - (!a.namespace_re || a.namespace_re.test(e.namespace)) && (a.handleObj = e, a.data = e.data, c = ((m.event.special[e.origType] || {}).handle || e.handler).apply(f.elem, i), void 0 !== c && (a.result = c) === !1 && (a.preventDefault(), a.stopPropagation())) - } - } - return k.postDispatch && k.postDispatch.call(this, a), a.result - } - }, - handlers: function(a, b) { - var c, d, e, f, g = [], h = b.delegateCount, i = a.target; - if (h && i.nodeType && (!a.button || "click" !== a.type)) { - for(; i != this; i = i.parentNode || this) { - if (1 === i.nodeType && (i.disabled !== !0 || "click" !== a.type)) { - for(e = [], f = 0; h > f; f++) { - d = b[f], c = d.selector + " ", void 0 === e[c] && (e[c] = d.needsContext ? m(c, this).index(i) >= 0 : m.find(c, this, null, [i]).length), e[c] && e.push(d); - } - e.length && g.push({ elem: i, handlers: e }) - } - } - } - return h < b.length && g.push({ elem: this, handlers: b.slice(h) }), g - }, - fix: function(a) { - if (a[m.expando]) { - return a; - } - var b, c, d, e = a.type, f = a, g = this.fixHooks[e]; - g || (this.fixHooks[e] = g = Z.test(e) ? this.mouseHooks : Y.test(e) ? this.keyHooks : {}), d = g.props ? this.props.concat(g.props) : this.props, a = new m.Event(f), b = d.length; - while(b--) { - c = d[b], a[c] = f[c]; - } - return a.target || (a.target = f.srcElement || y), 3 === a.target.nodeType && (a.target = a.target.parentNode), a.metaKey = !!a.metaKey, g.filter ? g.filter(a, f) : a - }, - props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - fixHooks: {}, - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function(a, b) {return null == a.which && (a.which = null != b.charCode ? b.charCode : b.keyCode), a} - }, - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function(a, b) { - var c, d, e, f = b.button, g = b.fromElement; - return null == a.pageX && null != b.clientX && (d = a.target.ownerDocument || y, e = d.documentElement, c = d.body, a.pageX = b.clientX + (e && e.scrollLeft || c && c.scrollLeft || 0) - (e && e.clientLeft || c && c.clientLeft || 0), a.pageY = b.clientY + (e && e.scrollTop || c && c.scrollTop || 0) - (e && e.clientTop || c && c.clientTop || 0)), !a.relatedTarget && g && (a.relatedTarget = g === a.target ? b.toElement : g), a.which || void 0 === f || (a.which = 1 & f ? 1 : 2 & f ? 3 : 4 & f ? 2 : 0), a - } - }, - special: { - load: { noBubble: !0 }, - focus: { - trigger: function() { - if (this !== ca() && this.focus) { - try {return this.focus(), !1} - catch(a) {} - } - }, delegateType: "focusin" - }, - blur: { trigger: function() {return this === ca() && this.blur ? (this.blur(), !1) : void 0}, delegateType: "focusout" }, - click: { - trigger: function() {return m.nodeName(this, "input") && "checkbox" === this.type && this.click ? (this.click(), !1) : void 0}, - _default: function(a) {return m.nodeName(a.target, "a")} - }, - beforeunload: { postDispatch: function(a) {void 0 !== a.result && a.originalEvent && (a.originalEvent.returnValue = a.result)} } - }, - simulate: function(a, b, c, d) { - var e = m.extend(new m.Event, c, { type: a, isSimulated: !0, originalEvent: {} }); - d ? m.event.trigger(e, null, b) : m.event.dispatch.call(b, e), e.isDefaultPrevented() && c.preventDefault() - } - }, m.removeEvent = y.removeEventListener ? function(a, b, c) {a.removeEventListener && a.removeEventListener(b, c, !1)} : function(a, b, c) { - var d = "on" + b; - a.detachEvent && (typeof a[d] === K && (a[d] = null), a.detachEvent(d, c)) - }, m.Event = function(a, b) {return this instanceof m.Event ? (a && a.type ? (this.originalEvent = a, this.type = a.type, this.isDefaultPrevented = a.defaultPrevented || void 0 === a.defaultPrevented && a.returnValue === !1 ? aa : ba) : this.type = a, b && m.extend(this, b), this.timeStamp = a && a.timeStamp || m.now(), void(this[m.expando] = !0)) : new m.Event(a, b)}, m.Event.prototype = { - isDefaultPrevented: ba, - isPropagationStopped: ba, - isImmediatePropagationStopped: ba, - preventDefault: function() { - var a = this.originalEvent; - this.isDefaultPrevented = aa, a && (a.preventDefault ? a.preventDefault() : a.returnValue = !1) - }, - stopPropagation: function() { - var a = this.originalEvent; - this.isPropagationStopped = aa, a && (a.stopPropagation && a.stopPropagation(), a.cancelBubble = !0) - }, - stopImmediatePropagation: function() { - var a = this.originalEvent; - this.isImmediatePropagationStopped = aa, a && a.stopImmediatePropagation && a.stopImmediatePropagation(), this.stopPropagation() - } - }, m.each({ - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" - }, function(a, b) { - m.event.special[a] = { - delegateType: b, bindType: b, handle: function(a) { - var c, d = this, e = a.relatedTarget, f = a.handleObj; - return (!e || e !== d && !m.contains(d, e)) && (a.type = f.origType, c = f.handler.apply(this, arguments), a.type = b), c - } - } - }), k.submitBubbles || (m.event.special.submit = { - setup: function() { - return m.nodeName(this, "form") ? !1 : void m.event.add(this, "click._submit keypress._submit", function(a) { - var b = a.target, c = m.nodeName(b, "input") || m.nodeName(b, "button") ? b.form : void 0; - c && !m._data(c, "submitBubbles") && (m.event.add(c, "submit._submit", function(a) {a._submit_bubble = !0}), m._data(c, "submitBubbles", !0)) - }) - }, - postDispatch: function(a) {a._submit_bubble && (delete a._submit_bubble, this.parentNode && !a.isTrigger && m.event.simulate("submit", this.parentNode, a, !0))}, - teardown: function() {return m.nodeName(this, "form") ? !1 : void m.event.remove(this, "._submit")} - }), k.changeBubbles || (m.event.special.change = { - setup: function() { - return X.test(this.nodeName) ? (("checkbox" === this.type || "radio" === this.type) && (m.event.add(this, "propertychange._change", function(a) {"checked" === a.originalEvent.propertyName && (this._just_changed = !0)}), m.event.add(this, "click._change", function(a) {this._just_changed && !a.isTrigger && (this._just_changed = !1), m.event.simulate("change", this, a, !0)})), !1) : void m.event.add(this, "beforeactivate._change", function(a) { - var b = a.target; - X.test(b.nodeName) && !m._data(b, "changeBubbles") && (m.event.add(b, "change._change", function(a) {!this.parentNode || a.isSimulated || a.isTrigger || m.event.simulate("change", this.parentNode, a, !0)}), m._data(b, "changeBubbles", !0)) - }) - }, handle: function(a) { - var b = a.target; - return this !== b || a.isSimulated || a.isTrigger || "radio" !== b.type && "checkbox" !== b.type ? a.handleObj.handler.apply(this, arguments) : void 0 - }, teardown: function() {return m.event.remove(this, "._change"), !X.test(this.nodeName)} - }), k.focusinBubbles || m.each({ - focus: "focusin", - blur: "focusout" - }, function(a, b) { - var c = function(a) {m.event.simulate(b, a.target, m.event.fix(a), !0)}; - m.event.special[b] = { - setup: function() { - var d = this.ownerDocument || this, e = m._data(d, b); - e || d.addEventListener(a, c, !0), m._data(d, b, (e || 0) + 1) - }, teardown: function() { - var d = this.ownerDocument || this, e = m._data(d, b) - 1; - e ? m._data(d, b, e) : (d.removeEventListener(a, c, !0), m._removeData(d, b)) - } - } - }), m.fn.extend({ - on: function(a, b, c, d, e) { - var f, g; - if ("object" == typeof a) { - "string" != typeof b && (c = c || b, b = void 0); - for(f in a) { - this.on(f, b, c, a[f], e); - } - return this - } - if (null == c && null == d ? (d = b, c = b = void 0) : null == d && ("string" == typeof b ? (d = c, c = void 0) : (d = c, c = b, b = void 0)), d === !1) { - d = ba; - } else if (!d) { - return this; - } - return 1 === e && (g = d, d = function(a) {return m().off(a), g.apply(this, arguments)}, d.guid = g.guid || (g.guid = m.guid++)), this.each(function() {m.event.add(this, a, d, c, b)}) - }, one: function(a, b, c, d) {return this.on(a, b, c, d, 1)}, off: function(a, b, c) { - var d, e; - if (a && a.preventDefault && a.handleObj) { - return d = a.handleObj, m(a.delegateTarget).off(d.namespace ? d.origType + "." + d.namespace : d.origType, d.selector, d.handler), this; - } - if ("object" == typeof a) { - for(e in a) { - this.off(e, b, a[e]); - } - return this - } - return (b === !1 || "function" == typeof b) && (c = b, b = void 0), c === !1 && (c = ba), this.each(function() {m.event.remove(this, a, c, b)}) - }, trigger: function(a, b) {return this.each(function() {m.event.trigger(a, b, this)})}, triggerHandler: function(a, b) { - var c = this[0]; - return c ? m.event.trigger(a, b, c, !0) : void 0 - } - }); - function da(a) { - var b = ea.split("|"), c = a.createDocumentFragment(); - if (c.createElement) { - while(b.length) { - c.createElement(b.pop()); - } - } - return c - } - - var ea = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", fa = / jQuery\d+="(?:null|\d+)"/g, ga = new RegExp("<(?:" + ea + ")[\\s/>]", "i"), ha = /^\s+/, ia = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, ja = /<([\w:]+)/, ka = /\s*$/g, ra = { - option: [1, ""], - legend: [1, "
", "
"], - area: [1, "", ""], - param: [1, "", ""], - thead: [1, "", "
"], - tr: [2, "", "
"], - col: [2, "", "
"], - td: [3, "", "
"], - _default: k.htmlSerialize ? [0, "", ""] : [1, "X
", "
"] - }, sa = da(y), ta = sa.appendChild(y.createElement("div")); - ra.optgroup = ra.option, ra.tbody = ra.tfoot = ra.colgroup = ra.caption = ra.thead, ra.th = ra.td; - function ua(a, b) { - var c, d, e = 0, f = typeof a.getElementsByTagName !== K ? a.getElementsByTagName(b || "*") : typeof a.querySelectorAll !== K ? a.querySelectorAll(b || "*") : void 0; - if (!f) { - for(f = [], c = a.childNodes || a; null != (d = c[e]); e++) { - !b || m.nodeName(d, b) ? f.push(d) : m.merge(f, ua(d, b)); - } - } - return void 0 === b || b && m.nodeName(a, b) ? m.merge([a], f) : f - } - - function va(a) {W.test(a.type) && (a.defaultChecked = a.checked)} - - function wa(a, b) {return m.nodeName(a, "table") && m.nodeName(11 !== b.nodeType ? b : b.firstChild, "tr") ? a.getElementsByTagName("tbody")[0] || a.appendChild(a.ownerDocument.createElement("tbody")) : a} - - function xa(a) {return a.type = (null !== m.find.attr(a, "type")) + "/" + a.type, a} - - function ya(a) { - var b = pa.exec(a.type); - return b ? a.type = b[1] : a.removeAttribute("type"), a - } - - function za(a, b) { - for(var c, d = 0; null != (c = a[d]); d++) { - m._data(c, "globalEval", !b || m._data(b[d], "globalEval")) - } - } - - function Aa(a, b) { - if (1 === b.nodeType && m.hasData(a)) { - var c, d, e, f = m._data(a), g = m._data(b, f), h = f.events; - if (h) { - delete g.handle, g.events = {}; - for(c in h) { - for(d = 0, e = h[c].length; e > d; d++) { - m.event.add(b, c, h[c][d]) - } - } - } - g.data && (g.data = m.extend({}, g.data)) - } - } - - function Ba(a, b) { - var c, d, e; - if (1 === b.nodeType) { - if (c = b.nodeName.toLowerCase(), !k.noCloneEvent && b[m.expando]) { - e = m._data(b); - for(d in e.events) { - m.removeEvent(b, d, e.handle); - } - b.removeAttribute(m.expando) - } - "script" === c && b.text !== a.text ? (xa(b).text = a.text, ya(b)) : "object" === c ? (b.parentNode && (b.outerHTML = a.outerHTML), k.html5Clone && a.innerHTML && !m.trim(b.innerHTML) && (b.innerHTML = a.innerHTML)) : "input" === c && W.test(a.type) ? (b.defaultChecked = b.checked = a.checked, b.value !== a.value && (b.value = a.value)) : "option" === c ? b.defaultSelected = b.selected = a.defaultSelected : ("input" === c || "textarea" === c) && (b.defaultValue = a.defaultValue) - } - } - - m.extend({ - clone: function(a, b, c) { - var d, e, f, g, h, i = m.contains(a.ownerDocument, a); - if (k.html5Clone || m.isXMLDoc(a) || !ga.test("<" + a.nodeName + ">") ? f = a.cloneNode(!0) : (ta.innerHTML = a.outerHTML, ta.removeChild(f = ta.firstChild)), !(k.noCloneEvent && k.noCloneChecked || 1 !== a.nodeType && 11 !== a.nodeType || m.isXMLDoc(a))) { - for(d = ua(f), h = ua(a), g = 0; null != (e = h[g]); ++g) { - d[g] && Ba(e, d[g]); - } - } - if (b) { - if (c) { - for(h = h || ua(a), d = d || ua(f), g = 0; null != (e = h[g]); g++) { - Aa(e, d[g]); - } - } else { - Aa(a, f); - } - } - return d = ua(f, "script"), d.length > 0 && za(d, !i && ua(a, "script")), d = h = e = null, f - }, - buildFragment: function(a, b, c, d) { - for(var e, f, g, h, i, j, l, n = a.length, o = da(b), p = [], q = 0; n > q; q++) { - if (f = a[q], f || 0 === f) { - if ("object" === m.type(f)) { - m.merge(p, f.nodeType ? [f] : f); - } else if (la.test(f)) { - h = h || o.appendChild(b.createElement("div")), i = (ja.exec(f) || ["", ""])[1].toLowerCase(), l = ra[i] || ra._default, h.innerHTML = l[1] + f.replace(ia, "<$1>") + l[2], e = l[0]; - while(e--) { - h = h.lastChild; - } - if (!k.leadingWhitespace && ha.test(f) && p.push(b.createTextNode(ha.exec(f)[0])), !k.tbody) { - f = "table" !== i || ka.test(f) ? "" !== l[1] || ka.test(f) ? 0 : h : h.firstChild, e = f && f.childNodes.length; - while(e--) { - m.nodeName(j = f.childNodes[e], "tbody") && !j.childNodes.length && f.removeChild(j) - } - } - m.merge(p, h.childNodes), h.textContent = ""; - while(h.firstChild) { - h.removeChild(h.firstChild); - } - h = o.lastChild - } else { - p.push(b.createTextNode(f)); - } - } - } - h && o.removeChild(h), k.appendChecked || m.grep(ua(p, "input"), va), q = 0; - while(f = p[q++]) { - if ((!d || -1 === m.inArray(f, d)) && (g = m.contains(f.ownerDocument, f), h = ua(o.appendChild(f), "script"), g && za(h), c)) { - e = 0; - while(f = h[e++]) { - oa.test(f.type || "") && c.push(f) - } - } - } - return h = null, o - }, - cleanData: function(a, b) { - for(var d, e, f, g, h = 0, i = m.expando, j = m.cache, l = k.deleteExpando, n = m.event.special; null != (d = a[h]); h++) { - if ((b || m.acceptData(d)) && (f = d[i], g = f && j[f])) { - if (g.events) { - for(e in g.events) { - n[e] ? m.event.remove(d, e) : m.removeEvent(d, e, g.handle); - } - } - j[f] && (delete j[f], l ? delete d[i] : typeof d.removeAttribute !== K ? d.removeAttribute(i) : d[i] = null, c.push(f)) - } - } - } - }), m.fn.extend({ - text: function(a) {return V(this, function(a) {return void 0 === a ? m.text(this) : this.empty().append((this[0] && this[0].ownerDocument || y).createTextNode(a))}, null, a, arguments.length)}, - append: function() { - return this.domManip(arguments, function(a) { - if (1 === this.nodeType || 11 === this.nodeType || 9 === this.nodeType) { - var b = wa(this, a); - b.appendChild(a) - } - }) - }, - prepend: function() { - return this.domManip(arguments, function(a) { - if (1 === this.nodeType || 11 === this.nodeType || 9 === this.nodeType) { - var b = wa(this, a); - b.insertBefore(a, b.firstChild) - } - }) - }, - before: function() {return this.domManip(arguments, function(a) {this.parentNode && this.parentNode.insertBefore(a, this)})}, - after: function() {return this.domManip(arguments, function(a) {this.parentNode && this.parentNode.insertBefore(a, this.nextSibling)})}, - remove: function(a, b) { - for(var c, d = a ? m.filter(a, this) : this, e = 0; null != (c = d[e]); e++) { - b || 1 !== c.nodeType || m.cleanData(ua(c)), c.parentNode && (b && m.contains(c.ownerDocument, c) && za(ua(c, "script")), c.parentNode.removeChild(c)); - } - return this - }, - empty: function() { - for(var a, b = 0; null != (a = this[b]); b++) { - 1 === a.nodeType && m.cleanData(ua(a, !1)); - while(a.firstChild) { - a.removeChild(a.firstChild); - } - a.options && m.nodeName(a, "select") && (a.options.length = 0) - } - return this - }, - clone: function(a, b) {return a = null == a ? !1 : a, b = null == b ? a : b, this.map(function() {return m.clone(this, a, b)})}, - html: function(a) { - return V(this, function(a) { - var b = this[0] || {}, c = 0, d = this.length; - if (void 0 === a) { - return 1 === b.nodeType ? b.innerHTML.replace(fa, "") : void 0; - } - if (!("string" != typeof a || ma.test(a) || !k.htmlSerialize && ga.test(a) || !k.leadingWhitespace && ha.test(a) || ra[(ja.exec(a) || ["", ""])[1].toLowerCase()])) { - a = a.replace(ia, "<$1>"); - try { - for(; d > c; c++) { - b = this[c] || {}, 1 === b.nodeType && (m.cleanData(ua(b, !1)), b.innerHTML = a); - } - b = 0 - } - catch(e) {} - } - b && this.empty().append(a) - }, null, a, arguments.length) - }, - replaceWith: function() { - var a = arguments[0]; - return this.domManip(arguments, function(b) {a = this.parentNode, m.cleanData(ua(this)), a && a.replaceChild(b, this)}), a && (a.length || a.nodeType) ? this : this.remove() - }, - detach: function(a) {return this.remove(a, !0)}, - domManip: function(a, b) { - a = e.apply([], a); - var c, d, f, g, h, i, j = 0, l = this.length, n = this, o = l - 1, p = a[0], q = m.isFunction(p); - if (q || l > 1 && "string" == typeof p && !k.checkClone && na.test(p)) { - return this.each(function(c) { - var d = n.eq(c); - q && (a[0] = p.call(this, c, d.html())), d.domManip(a, b) - }); - } - if (l && (i = m.buildFragment(a, this[0].ownerDocument, !1, this), c = i.firstChild, 1 === i.childNodes.length && (i = c), c)) { - for(g = m.map(ua(i, "script"), xa), f = g.length; l > j; j++) { - d = i, j !== o && (d = m.clone(d, !0, !0), f && m.merge(g, ua(d, "script"))), b.call(this[j], d, j); - } - if (f) { - for(h = g[g.length - 1].ownerDocument, m.map(g, ya), j = 0; f > j; j++) { - d = g[j], oa.test(d.type || "") && !m._data(d, "globalEval") && m.contains(h, d) && (d.src ? m._evalUrl && m._evalUrl(d.src) : m.globalEval((d.text || d.textContent || d.innerHTML || "").replace(qa, ""))); - } - } - i = c = null - } - return this - } - }), m.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" - }, function(a, b) { - m.fn[a] = function(a) { - for(var c, d = 0, e = [], g = m(a), h = g.length - 1; h >= d; d++) { - c = d === h ? this : this.clone(!0), m(g[d])[b](c), f.apply(e, c.get()); - } - return this.pushStack(e) - } - }); - var Ca, Da = {}; - - function Ea(b, c) { - var d, e = m(c.createElement(b)).appendTo(c.body), f = a.getDefaultComputedStyle && (d = a.getDefaultComputedStyle(e[0])) ? d.display : m.css(e[0], "display"); - return e.detach(), f - } - - function Fa(a) { - var b = y, c = Da[a]; - return c || (c = Ea(a, b), "none" !== c && c || (Ca = (Ca || m("