diff --git a/.gitignore b/.gitignore index 45793a2..62ea1cf 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,12 @@ htmlcov/ # Production *.pid *.sock + +# Misc +information/deprecated/ +planning/ +*.7z +*.zip +.htaccess_fixed +teacher_retention_trend.svg +wordpress_.htaccess \ No newline at end of file diff --git a/app/.htaccess b/app/.htaccess deleted file mode 100644 index b8f9850..0000000 --- a/app/.htaccess +++ /dev/null @@ -1,7 +0,0 @@ -# Apache configuration for Flask subdirectory deployment -# Passenger configuration ONLY - minimal to avoid blocking issues - -PassengerEnabled on -PassengerAppRoot /home/bmdwtjuw/product-finder -PassengerPython /home/bmdwtjuw/virtualenv/product-finder/3.13/bin/python3.13_bin -SetEnv APPLICATION_ROOT /product-finder diff --git a/app/.htaccess.minimal b/app/.htaccess.minimal deleted file mode 100644 index 99eb75e..0000000 --- a/app/.htaccess.minimal +++ /dev/null @@ -1,4 +0,0 @@ -# MINIMAL .htaccess for troubleshooting -# If you're getting 403/404, try this simplified version first - -PassengerEnabled on diff --git a/product_app/README.md b/app/README.md similarity index 100% rename from product_app/README.md rename to app/README.md diff --git a/app/admin/README.md b/app/admin/README.md deleted file mode 100644 index 7a614e7..0000000 --- a/app/admin/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# Admin Utilities - -This folder contains administrative tools and utilities for maintaining the CGW Product Finder application. - -## šŸ› ļø Available Tools - -### fix_default_locations.py -**Purpose**: Ensures all users have their default location marked as accessible. - -**Usage**: -```bash -cd app/admin -python fix_default_locations.py -``` - -**What it does**: -- Scans all users in `data/users.json` -- Checks if each user's default location is marked as accessible -- Automatically fixes any users where the default location is not accessible -- Reports results for each user - -**When to use**: -- After manual edits to users.json -- After importing users from backup -- If users report they can't access their default location -- As a maintenance check - -### test_password_security.py -**Purpose**: Demonstrates and tests the password hashing security implementation. - -**Usage**: -```bash -cd app/admin -python test_password_security.py -``` - -**What it does**: -- Demonstrates PBKDF2-SHA256 password hashing -- Shows security features (iterations, salt, etc.) -- Verifies password verification works correctly -- Useful for understanding the security implementation - -**When to use**: -- To verify password hashing is working correctly -- To demonstrate security to stakeholders -- For educational purposes -- When troubleshooting password-related issues - -## šŸ“‹ Running Admin Tools - -All admin tools should be run from within the `app/admin` directory to ensure correct file paths. - -**Example**: -```bash -# Navigate to admin folder -cd "C:\Users\Work\Desktop\CGW Product Finder\app\admin" - -# Run a tool -python fix_default_locations.py -``` - -## āš ļø Important Notes - -- **Backup First**: Always backup `data/users.json` before running utilities that modify data -- **Test Environment**: Test utilities in a development environment before running in production -- **File Paths**: These tools assume they're being run from the `app/admin` directory -- **Python Version**: Requires Python 3.7 or higher - -## šŸ”’ Security Considerations - -- These tools have direct access to user data -- Do not expose these tools to web-facing directories -- Keep this folder secure with appropriate file permissions -- Never commit sensitive user data to version control - -## šŸ“ Adding New Admin Tools - -When adding new administrative tools to this folder: - -1. Add the Python script file -2. Update this README with documentation -3. Include clear usage instructions -4. Document any data modifications it makes -5. Include error handling and user feedback - -## šŸ› Troubleshooting - -**"File not found" errors**: -- Ensure you're running from the `app/admin` directory -- Check that `../data/users.json` exists - -**Permission denied**: -- Ensure the application is not running -- Check file permissions on `data/users.json` - -**Import errors**: -- Ensure all required dependencies are installed: `pip install -r ../requirements.txt` -- Verify Python version: `python --version` diff --git a/app/admin/fix_default_locations.py b/app/admin/fix_default_locations.py deleted file mode 100644 index 2b2f982..0000000 --- a/app/admin/fix_default_locations.py +++ /dev/null @@ -1,65 +0,0 @@ -""" -Utility script to fix existing users by ensuring their default location -is marked as accessible in their locationSettings. -""" - -import json -import os - -# Get the directory where this script is located -basedir = os.path.abspath(os.path.dirname(__file__)) -USERS_FILE = os.path.join(basedir, '..', 'data', 'users.json') - -def fix_default_locations(): - """ - Ensure all users have their default location marked as accessible. - """ - if not os.path.exists(USERS_FILE): - print("No users.json file found.") - return - - # Load users - with open(USERS_FILE, 'r') as f: - users = json.load(f) - - print(f"Found {len(users)} users to check...") - - changes_made = 0 - for user in users: - username = user.get('username', 'Unknown') - default_location = user.get('defaultLocation') - - if not default_location: - print(f"āš ļø User '{username}' has no default location - skipping") - continue - - location_settings = user.get('locationSettings', {}) - - # Check if default location is in settings and accessible - if default_location not in location_settings: - print(f"āœ“ Adding default location '{default_location}' for user '{username}'") - location_settings[default_location] = {'accessible': True} - user['locationSettings'] = location_settings - changes_made += 1 - elif not location_settings[default_location].get('accessible', False): - print(f"āœ“ Marking default location '{default_location}' as accessible for user '{username}'") - location_settings[default_location]['accessible'] = True - changes_made += 1 - else: - print(f" User '{username}' - default location already accessible") - - if changes_made > 0: - # Save updated users - with open(USERS_FILE, 'w') as f: - json.dump(users, f, indent=2) - print(f"\nāœ“ Fixed {changes_made} user(s) and saved to users.json") - else: - print("\nāœ“ All users already have correct default location settings") - -if __name__ == '__main__': - print("=" * 60) - print("DEFAULT LOCATION FIX UTILITY") - print("=" * 60) - print() - fix_default_locations() - print() diff --git a/app/admin/test_password_security.py b/app/admin/test_password_security.py deleted file mode 100644 index b2ce388..0000000 --- a/app/admin/test_password_security.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Test script to demonstrate password hashing and verification -""" - -from werkzeug.security import generate_password_hash, check_password_hash - -# Example: Creating a hashed password -plain_password = "mySecurePassword123" -hashed_password = generate_password_hash(plain_password, method='pbkdf2:sha256') - -print("=" * 60) -print("PASSWORD HASHING DEMONSTRATION") -print("=" * 60) -print() -print(f"Original Password: {plain_password}") -print() -print(f"Hashed Password: {hashed_password}") -print() -print(f"Hash Length: {len(hashed_password)} characters") -print() -print("=" * 60) -print("SECURITY FEATURES") -print("=" * 60) -print("āœ“ Algorithm: PBKDF2-SHA256") -print("āœ“ Iterations: 600,000+") -print("āœ“ Unique salt per password") -print("āœ“ Cannot be reversed to plain text") -print("āœ“ Industry-standard security") -print() -print("=" * 60) -print("PASSWORD VERIFICATION TEST") -print("=" * 60) -print() - -# Test correct password -correct = check_password_hash(hashed_password, "mySecurePassword123") -print(f"Testing correct password: {correct} āœ“") - -# Test incorrect password -incorrect = check_password_hash(hashed_password, "wrongPassword") -print(f"Testing incorrect password: {incorrect} āœ—") -print() - -# Show that the same password produces different hashes (due to unique salts) -print("=" * 60) -print("UNIQUE SALT DEMONSTRATION") -print("=" * 60) -print() -print("Hashing the same password twice produces different hashes:") -print() -hash1 = generate_password_hash("password123", method='pbkdf2:sha256') -hash2 = generate_password_hash("password123", method='pbkdf2:sha256') -print(f"Hash 1: {hash1}") -print(f"Hash 2: {hash2}") -print() -print(f"Are they different? {hash1 != hash2}") -print("Both hashes are valid and will verify correctly!") -print(f"Hash 1 verifies: {check_password_hash(hash1, 'password123')}") -print(f"Hash 2 verifies: {check_password_hash(hash2, 'password123')}") -print() diff --git a/app/app.py b/app/app.py index 57b4149..64efd40 100644 --- a/app/app.py +++ b/app/app.py @@ -1,25 +1,6 @@ -from flask import Flask, render_template, send_from_directory, jsonify, request, send_file, session, redirect, url_for -import os -from io import BytesIO -import base64 -import json -from werkzeug.security import generate_password_hash, check_password_hash -from functools import wraps +from flask import Flask, session, redirect, url_for import secrets - -# Import image generator -try: - from image_generator import ProductImageGenerator, image_to_base64 - IMAGE_GENERATOR_AVAILABLE = True - print("āœ“ Image generation available") -except ImportError as e: - IMAGE_GENERATOR_AVAILABLE = False - print(f"Warning: Could not import image generator: {e}") - print("Image generation endpoints will be disabled.") -except Exception as e: - IMAGE_GENERATOR_AVAILABLE = False - print(f"Error loading image generator: {e}") - print("Image generation endpoints will be disabled.") +import os # Get the directory where this script is located basedir = os.path.abspath(os.path.dirname(__file__)) @@ -34,962 +15,76 @@ app.secret_key = secrets.token_hex(32) app.config['SESSION_COOKIE_HTTPONLY'] = True app.config['SESSION_COOKIE_SAMESITE'] = 'Lax' -# Configure static folders -app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0 # Disable caching during development +# Import and register blueprints +from blueprints.auth import auth_bp +from blueprints.users import users_bp +from blueprints.products import products_bp -# Support for subdirectory deployments (e.g., /product-finder/) -# Auto-detect production environment based on Python path -import sys -if 'virtualenv/product-finder' in sys.executable or '/home/bmdwtjuw' in sys.executable: - # Running on production server - app.config['APPLICATION_ROOT'] = '/product-finder' - print("[OK] Production environment detected - using /product-finder") -else: - # Local development - app.config['APPLICATION_ROOT'] = os.environ.get('APPLICATION_ROOT', '/') - print(f"[OK] Development environment - using {app.config['APPLICATION_ROOT']}") - -# ===== SUBDIRECTORY DEPLOYMENT MIDDLEWARE ===== - -class PrefixMiddleware: - """ - Middleware to handle subdirectory deployments. - This ensures Flask knows about the /product-finder prefix when deployed. - """ - def __init__(self, app, prefix=''): - self.app = app - self.prefix = prefix.rstrip('/') # Remove trailing slash if present - - def __call__(self, environ, start_response): - # Only apply prefix if not already in SCRIPT_NAME and prefix is set - if self.prefix and self.prefix != '/': - # Check if the URL path starts with our prefix - path = environ.get('PATH_INFO', '') - script_name = environ.get('SCRIPT_NAME', '') - - # If prefix not already in SCRIPT_NAME, add it - if not script_name.startswith(self.prefix): - environ['SCRIPT_NAME'] = self.prefix + script_name - - # Remove prefix from PATH_INFO if it's there - if path.startswith(self.prefix): - environ['PATH_INFO'] = path[len(self.prefix):] - - return self.app(environ, start_response) - -# Apply middleware if APPLICATION_ROOT is set to a subdirectory -application_root = app.config.get('APPLICATION_ROOT', '/') -if application_root and application_root != '/': - app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix=application_root) - print(f"āœ“ PrefixMiddleware applied for subdirectory: {application_root}") - -# Make base URL available to all templates -@app.context_processor -def inject_base_url(): - """Inject base URL into all templates for relative paths""" - return { - 'base_url': request.script_root or '', - 'url_for': url_for - } - -# ===== AUTHENTICATION HELPERS ===== - -def login_required(f): - """Decorator to require login for routes""" - @wraps(f) - def decorated_function(*args, **kwargs): - if 'user_id' not in session: - return redirect(url_for('login_page')) - - # Check if user is active - users = load_users() - if session['user_id'] >= len(users): - session.clear() - return redirect(url_for('login_page', message='User not found')) - - user = users[session['user_id']] - if not user.get('active', True): - session.clear() - return redirect(url_for('login_page', message='Account is inactive')) - - return f(*args, **kwargs) - return decorated_function - -def get_current_user(): - """Get the currently logged in user""" - if 'user_id' not in session: - return None - - users = load_users() - if session['user_id'] >= len(users): - return None - - return users[session['user_id']] - -def can_user(permission, location=None): - """ - Check if current user has a specific permission. - WordPress-style permission checking. - - Args: - permission (str): Permission name (e.g., 'manage_users', 'create_quotes') - location (str, optional): Check permission for specific location. - If None, uses current session location. - If 'global', checks global permissions only. - - Returns: - bool: True if user has permission, False otherwise - - Examples: - can_user('manage_users') # Check global permission - can_user('create_quotes') # Check at current location - can_user('view_reports', 'LINDS') # Check at specific location - """ - user = get_current_user() - if not user: - return False - - # Check if user is active - if not user.get('active', True): - return False - - # Check global permissions first - global_permissions = user.get('permissions', {}) - if permission in global_permissions: - return global_permissions[permission] is True - - # If location is 'global', only check global permissions - if location == 'global': - return False - - # Determine which location to check - check_location = location if location else session.get('currentLocation') - - if not check_location: - return False - - # Check location-specific permissions - location_settings = user.get('locationSettings', {}) - if check_location in location_settings: - loc_permissions = location_settings[check_location].get('permissions', {}) - if permission in loc_permissions: - return loc_permissions[permission] is True - - return False - -def user_has_any_permission(permissions, location=None): - """ - Check if user has ANY of the provided permissions. - - Args: - permissions (list): List of permission names - location (str, optional): Location to check - - Returns: - bool: True if user has at least one permission - """ - return any(can_user(perm, location) for perm in permissions) - -def user_has_all_permissions(permissions, location=None): - """ - Check if user has ALL of the provided permissions. - - Args: - permissions (list): List of permission names - location (str, optional): Location to check - - Returns: - bool: True if user has all permissions - """ - return all(can_user(perm, location) for perm in permissions) - -def permission_required(permission, location=None): - """ - Decorator to require specific permission for a route. - Similar to @login_required but checks permissions. - - Args: - permission (str): Required permission name - location (str, optional): Location to check permission for - - Example: - @app.route('/admin/users') - @login_required - @permission_required('manage_users') - def manage_users_page(): - return render_template('user_manager.html') - """ - def decorator(f): - @wraps(f) - def decorated_function(*args, **kwargs): - if not can_user(permission, location): - return render_template('access_denied.html', - required_permission=permission), 403 - return f(*args, **kwargs) - return decorated_function - return decorator - -def get_user_permissions(location=None): - """ - Get all permissions for the current user. - - Args: - location (str, optional): Get permissions for specific location. - If None, returns global + current location. - - Returns: - dict: Dictionary of permission_name: True/False - """ - user = get_current_user() - if not user: - return {} - - permissions = {} - - # Get global permissions - global_perms = user.get('permissions', {}) - permissions.update(global_perms) - - # Get location-specific permissions - if location != 'global': - check_location = location if location else session.get('currentLocation') - if check_location: - location_settings = user.get('locationSettings', {}) - if check_location in location_settings: - loc_perms = location_settings[check_location].get('permissions', {}) - permissions.update(loc_perms) - - return permissions - -# ===== USER MANAGEMENT FUNCTIONS (moved here for use in auth) ===== - -USERS_FILE = os.path.join(basedir, 'data', 'users.json') - -def load_users(): - """Load users from JSON file""" - if os.path.exists(USERS_FILE): - try: - with open(USERS_FILE, 'r') as f: - return json.load(f) - except: - return [] - return [] - -def save_users(users): - """Save users to JSON file""" - with open(USERS_FILE, 'w') as f: - json.dump(users, f, indent=2) - -# ===== AUTHENTICATION ROUTES ===== - -@app.route('/login') -def login_page(): - """Serve the login page""" - # If already logged in, redirect to main app - if 'user_id' in session: - return redirect(url_for('index')) - return render_template('login.html') - -@app.route('/select-location') -def select_location_page(): - """Serve the location selection page""" - if 'user_id' not in session: - return redirect(url_for('login_page')) - return render_template('select_location.html') - -@app.route('/api/login', methods=['POST']) -def login(): - """Authenticate user and create session""" - try: - data = request.json - username = data.get('username') - password = data.get('password') - - if not username or not password: - return jsonify({ - 'status': 'error', - 'message': 'Username and password are required' - }), 400 - - users = load_users() - - # Find user by username - user_index = None - user = None - for i, u in enumerate(users): - if u['username'] == username: - user_index = i - user = u - break - - if not user: - return jsonify({ - 'status': 'error', - 'message': 'Invalid username or password' - }), 401 - - # Check if user is active - if not user.get('active', True): - return jsonify({ - 'status': 'error', - 'message': 'Account is inactive. Please contact an administrator.' - }), 403 - - # Verify password - if not check_password_hash(user['password'], password): - return jsonify({ - 'status': 'error', - 'message': 'Invalid username or password' - }), 401 - - # Create session - session['user_id'] = user_index - session['username'] = user['username'] - session['defaultLocation'] = user.get('defaultLocation') - - # Get accessible locations - accessible_locations = [] - if 'locationSettings' in user: - for loc_code, settings in user['locationSettings'].items(): - if settings.get('accessible', False): - accessible_locations.append(loc_code) - - session['accessibleLocations'] = accessible_locations - - # Check if user needs to select a location - requiresLocationSelection = len(accessible_locations) > 1 - - # If only one location or no accessible locations, auto-select default - if not requiresLocationSelection: - session['currentLocation'] = user.get('defaultLocation') - - return jsonify({ - 'status': 'success', - 'message': 'Login successful', - 'requiresLocationSelection': requiresLocationSelection - }) - - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -@app.route('/api/logout', methods=['POST']) -def logout(): - """Log out user and clear session""" - session.clear() - return jsonify({ - 'status': 'success', - 'message': 'Logged out successfully' - }) - -@app.route('/api/session', methods=['GET']) -def get_session(): - """Get current session information""" - if 'user_id' not in session: - return jsonify({ - 'status': 'error', - 'message': 'Not logged in' - }), 401 - - return jsonify({ - 'status': 'success', - 'username': session.get('username'), - 'defaultLocation': session.get('defaultLocation'), - 'currentLocation': session.get('currentLocation'), - 'accessibleLocations': session.get('accessibleLocations', []) - }) - -@app.route('/api/select-location', methods=['POST']) -def select_location(): - """Select a location for the current session""" - if 'user_id' not in session: - return jsonify({ - 'status': 'error', - 'message': 'Not logged in' - }), 401 - - try: - data = request.json - location = data.get('location') - - # Verify user has access to this location - accessible = session.get('accessibleLocations', []) - if location not in accessible: - return jsonify({ - 'status': 'error', - 'message': 'You do not have access to this location' - }), 403 - - session['currentLocation'] = location - - return jsonify({ - 'status': 'success', - 'message': 'Location selected', - 'currentLocation': location - }) - - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -# ===== PERMISSION CHECK ENDPOINT ===== - -@app.route('/api/check-permission', methods=['POST']) -@login_required -def check_permission(): - """Check if current user has specific permission(s)""" - try: - data = request.json - permission = data.get('permission') - location = data.get('location') # Optional, defaults to current location - - if not permission: - return jsonify({ - 'status': 'error', - 'message': 'Permission name required' - }), 400 - - has_permission = can_user(permission, location) - - return jsonify({ - 'status': 'success', - 'hasPermission': has_permission, - 'permission': permission, - 'location': location if location else session.get('currentLocation', 'global') - }) - - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -@app.route('/api/user-permissions', methods=['GET']) -@login_required -def get_user_permissions_endpoint(): - """Get all permissions for current user""" - try: - location = request.args.get('location') # Optional query parameter - permissions = get_user_permissions(location) - - return jsonify({ - 'status': 'success', - 'permissions': permissions, - 'location': location if location else session.get('currentLocation', 'global') - }) - - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -# ===== MAIN APPLICATION ROUTES ===== +app.register_blueprint(auth_bp) +app.register_blueprint(users_bp) +app.register_blueprint(products_bp) +# Home route @app.route('/') -def index(): - """Serve the quiz page as the main page or redirect to login""" - # Simple test to see if app is running - if 'username' not in session: - return redirect(url_for('login_page')) +def home(): + """Redirect to login if not authenticated, otherwise show home""" + if 'user_id' not in session: + return redirect(url_for('auth.login_page')) # If user hasn't selected a location yet, redirect to selection if not session.get('currentLocation') and len(session.get('accessibleLocations', [])) > 1: - return redirect(url_for('select_location_page')) - return render_template('index2.html') - -@app.route('/test') -def test_route(): - """Simple test route to verify app is running - NO AUTH REQUIRED""" - import sys - info = { - 'status': 'OK', - 'message': 'Flask app is running!', - 'python': sys.version, - 'application_root': app.config.get('APPLICATION_ROOT'), - 'middleware': type(app.wsgi_app).__name__, - 'routes': len(list(app.url_map.iter_rules())) - } + return redirect(url_for('auth.select_location_page')) + return f""" - App Test - -

āœ“ Flask App is Running!

+ Home + +

Welcome, {session.get('username', 'User')}!

+

Current Location: {session.get('currentLocation', 'Not selected')}

-

Go to Login

""" -@app.route('/quiz') -@login_required -def quiz(): - """Serve the quiz page""" - return render_template('index2.html') - -@app.route('/image-test') -@login_required -def image_test(): - """Serve the image generation test page""" - return render_template('image_test.html') - -@app.route('/css/') -def serve_css(filename): - """Serve CSS files""" - return send_from_directory(os.path.join(basedir, 'css'), filename) - -@app.route('/js/') -def serve_js(filename): - """Serve JavaScript files""" - return send_from_directory(os.path.join(basedir, 'js'), filename) - -@app.route('/images/') -def serve_images(filename): - """Serve image files""" - return send_from_directory(os.path.join(basedir, 'images'), filename) - -@app.route('/data/') -def serve_data(filename): - """Serve data files (JSON)""" - return send_from_directory(os.path.join(basedir, 'data'), filename) - -# API endpoint for future expansion (e.g., saving user selections) -@app.route('/api/save-selection', methods=['POST']) -def save_selection(): - """API endpoint to save user selections""" - data = request.json - # Here you could save to a database or file - # For now, just return success - return jsonify({ - 'status': 'success', - 'message': 'Selection saved', - 'data': data - }) - -@app.route('/api/get-products', methods=['GET']) -def get_products(): - """API endpoint to get product data""" - # This could fetch from a database in the future - return jsonify({ - 'status': 'success', - 'products': [] - }) - -# ===== DYNAMIC IMAGE GENERATION ENDPOINTS ===== - -@app.route('/api/product-image/') -def generate_product_image(product_code): +@app.route('/test') +def test(): + """Test route to verify app is running""" + import sys + return f""" + + Test Page + +

Flask App is Running!

+
    +
  • Python: {sys.version}
  • +
  • Routes: {len(list(app.url_map.iter_rules()))}
  • +
+

Login

+ + """ - Generate a product image with specified configuration. - - URL Parameters: - color: Color name (default: 'white') - hinge: Hinge side - 'left' or 'right' (default: 'right') - material: Material type (default: 'aluminum') - format: Return format - 'image' or 'json' (default: 'image') - - Examples: - /api/product-image/cobrai?color=black&hinge=left - /api/product-image/cobrai?color=bronze&hinge=right&format=json - """ - if not IMAGE_GENERATOR_AVAILABLE: - return jsonify({ - 'error': 'Image generation not available. Please install Pillow: pip install Pillow' - }), 500 - - try: - # Get parameters - color = request.args.get('color', 'white').lower() - hinge = request.args.get('hinge', 'right').lower() - material = request.args.get('material', 'aluminum').lower() - return_format = request.args.get('format', 'image').lower() - use_cache = request.args.get('cache', 'true').lower() == 'true' - - # Initialize generator - generator = ProductImageGenerator() - - # Generate image - image = generator.generate_product_image( - product_code=product_code, - color=color, - hinge=hinge, - material=material, - use_cache=use_cache - ) - - # Return based on format - if return_format == 'json': - # Return base64 encoded image in JSON - img_base64 = image_to_base64(image, format='PNG') - return jsonify({ - 'status': 'success', - 'productCode': product_code, - 'color': color, - 'hinge': hinge, - 'material': material, - 'image': img_base64, - 'format': 'base64' - }) - else: - # Return raw image file - img_io = BytesIO() - image.save(img_io, 'PNG', optimize=True) - img_io.seek(0) - return send_file(img_io, mimetype='image/png') - - except ValueError as e: - return jsonify({'error': str(e)}), 404 - except FileNotFoundError as e: - return jsonify({'error': str(e)}), 404 - except Exception as e: - return jsonify({'error': f'Error generating image: {str(e)}'}), 500 - -@app.route('/api/product-config/') -def get_product_image_config(product_code): - """ - Get the image configuration for a product. - - Returns JSON with available colors, hardware positions, and other metadata. - - Example: - /api/product-config/cobrai - """ - if not IMAGE_GENERATOR_AVAILABLE: - return jsonify({ - 'error': 'Image generation not available. Please install Pillow: pip install Pillow' - }), 500 - - try: - generator = ProductImageGenerator() - config = generator.get_product_config(product_code) - - if not config: - return jsonify({ - 'error': f'Configuration for product {product_code} not found' - }), 404 - - return jsonify({ - 'status': 'success', - 'productCode': product_code, - 'config': config - }) - - except Exception as e: - return jsonify({'error': str(e)}), 500 - -@app.route('/api/clear-image-cache', methods=['POST']) -def clear_image_cache(): - """ - Clear the image cache. - - Optional JSON body: - { "productCode": "cobrai" } - Clear cache for specific product - - Example: - POST /api/clear-image-cache - POST /api/clear-image-cache with body: {"productCode": "cobrai"} - """ - if not IMAGE_GENERATOR_AVAILABLE: - return jsonify({ - 'error': 'Image generation not available.' - }), 500 - - try: - data = request.json or {} - product_code = data.get('productCode') - - generator = ProductImageGenerator() - generator.clear_cache(product_code) - - return jsonify({ - 'status': 'success', - 'message': f'Cache cleared for {product_code}' if product_code else 'All cache cleared' - }) - - except Exception as e: - return jsonify({'error': str(e)}), 500 - -# ===== END DYNAMIC IMAGE GENERATION ENDPOINTS ===== - -# ===== USER MANAGEMENT ENDPOINTS ===== - -@app.route('/users') -@login_required -@permission_required('manage_users') -def user_manager(): - """Serve the user management page""" - return render_template('user_manager.html') - -@app.route('/api/users', methods=['GET']) -@login_required -@permission_required('manage_users') -def get_users(): - """Get all users""" - users = load_users() - return jsonify({ - 'status': 'success', - 'users': users - }) - -@app.route('/api/users', methods=['POST']) -@login_required -@permission_required('manage_users') -def add_user(): - """Add a new user with hashed password""" - try: - data = request.json - - # Validate required fields - if not data.get('username') or not data.get('password') or not data.get('defaultLocation'): - return jsonify({ - 'status': 'error', - 'message': 'Username, password, and default location are required' - }), 400 - - users = load_users() - - # Check if username already exists - if any(user['username'] == data['username'] for user in users): - return jsonify({ - 'status': 'error', - 'message': 'Username already exists' - }), 400 - - # Hash the password using pbkdf2:sha256 (secure) - hashed_password = generate_password_hash(data['password'], method='pbkdf2:sha256') - - # Get location settings and ensure default location is marked as accessible - location_settings = data.get('locationSettings', {}) - default_location = data['defaultLocation'] - - # Ensure default location exists in settings and is marked as accessible - if default_location not in location_settings: - location_settings[default_location] = {} - location_settings[default_location]['accessible'] = True - - # Create new user - new_user = { - 'username': data['username'], - 'password': hashed_password, - 'defaultLocation': default_location, - 'locationSettings': location_settings, - 'active': data.get('active', True) # Default to active - } - - users.append(new_user) - save_users(users) - - return jsonify({ - 'status': 'success', - 'message': 'User added successfully', - 'users': users - }) - - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -@app.route('/api/users//active', methods=['PATCH']) -@login_required -@permission_required('manage_users') -def toggle_user_active(user_index): - """Toggle user active status""" - try: - data = request.json - users = load_users() - - if user_index < 0 or user_index >= len(users): - return jsonify({ - 'status': 'error', - 'message': 'Invalid user index' - }), 400 - - # Update active status - users[user_index]['active'] = data.get('active', True) - save_users(users) - - return jsonify({ - 'status': 'success', - 'message': 'User status updated', - 'users': users - }) - - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -@app.route('/api/users/', methods=['DELETE']) -@login_required -@permission_required('manage_users') -def delete_user(user_index): - """Delete a specific user by index""" - try: - users = load_users() - - if user_index < 0 or user_index >= len(users): - return jsonify({ - 'status': 'error', - 'message': 'Invalid user index' - }), 400 - - users.pop(user_index) - save_users(users) - - return jsonify({ - 'status': 'success', - 'message': 'User deleted successfully', - 'users': users - }) - - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -@app.route('/api/users//change-password', methods=['POST']) -@login_required -@permission_required('manage_users') -def change_user_password(user_index): - """Change a user's password with current user verification""" - try: - data = request.json - new_password = data.get('newPassword') - current_user_password = data.get('currentUserPassword') - - # Validate required fields - if not new_password or not current_user_password: - return jsonify({ - 'status': 'error', - 'message': 'New password and current user password are required' - }), 400 - - # Validate password length - if len(new_password) < 6: - return jsonify({ - 'status': 'error', - 'message': 'Password must be at least 6 characters long' - }), 400 - - # Get current logged-in user - current_user = get_current_user() - if not current_user: - return jsonify({ - 'status': 'error', - 'message': 'Not authenticated' - }), 401 - - # Verify current user's password - if not check_password_hash(current_user['password'], current_user_password): - return jsonify({ - 'status': 'error', - 'message': 'Your password is incorrect. Password change denied for security reasons.' - }), 403 - - # Load users and validate index - users = load_users() - if user_index < 0 or user_index >= len(users): - return jsonify({ - 'status': 'error', - 'message': 'Invalid user index' - }), 400 - - # Hash the new password - hashed_password = generate_password_hash(new_password, method='pbkdf2:sha256') - - # Update the target user's password - target_username = users[user_index]['username'] - users[user_index]['password'] = hashed_password - save_users(users) - - return jsonify({ - 'status': 'success', - 'message': f'Password changed successfully for user "{target_username}"' - }) - - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -@app.route('/api/users/clear', methods=['DELETE']) -def clear_all_users(): - """Clear all users""" - try: - save_users([]) - return jsonify({ - 'status': 'success', - 'message': 'All users cleared' - }) - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -@app.route('/api/users/download') -def download_users(): - """Download users as JSON file""" - try: - users = load_users() - - if not users: - return jsonify({ - 'status': 'error', - 'message': 'No users to download' - }), 400 - - # Create JSON file in memory - json_data = json.dumps(users, indent=2) - - # Send as downloadable file - return send_file( - BytesIO(json_data.encode()), - mimetype='application/json', - as_attachment=True, - download_name='users.json' - ) - - except Exception as e: - return jsonify({ - 'status': 'error', - 'message': str(e) - }), 500 - -# ===== END USER MANAGEMENT ENDPOINTS ===== # Error handlers @app.errorhandler(404) def page_not_found(e): - return render_template('404.html'), 404 + return "

404 - Page Not Found

", 404 @app.errorhandler(500) def internal_error(e): - return "Internal Server Error", 500 + return "

500 - Internal Server Error

", 500 + +# This is the critical line for Passenger +application = app if __name__ == '__main__': # Create necessary directories - os.makedirs(os.path.join(basedir, 'images'), exist_ok=True) os.makedirs(os.path.join(basedir, 'templates'), exist_ok=True) - os.makedirs(os.path.join(basedir, 'css'), exist_ok=True) - os.makedirs(os.path.join(basedir, 'js'), exist_ok=True) os.makedirs(os.path.join(basedir, 'data'), exist_ok=True) # Run the application - # Set debug=False for production - # Port 8080 is used instead of 5000 (Windows reserves port 5000) - app.run(debug=True, host='0.0.0.0', port=8080) + app.run(debug=True, host='0.0.0.0', port=8080) \ No newline at end of file diff --git a/product_app/blueprints/__init__.py b/app/blueprints/__init__.py similarity index 100% rename from product_app/blueprints/__init__.py rename to app/blueprints/__init__.py diff --git a/product_app/blueprints/auth.py b/app/blueprints/auth.py similarity index 100% rename from product_app/blueprints/auth.py rename to app/blueprints/auth.py diff --git a/app/blueprints/products.py b/app/blueprints/products.py new file mode 100644 index 0000000..318483b --- /dev/null +++ b/app/blueprints/products.py @@ -0,0 +1,38 @@ +""" +Product Finder Blueprint +Handles the product quiz and recommendations +""" +from flask import Blueprint, render_template, send_from_directory +from blueprints.auth import login_required +import os + +products_bp = Blueprint('products', __name__, url_prefix='/quiz') + +# Get base directory +basedir = os.path.dirname(os.path.dirname(__file__)) + +@products_bp.route('/') +@login_required +def product_finder(): + """Serve the product finder quiz page""" + return render_template('product_finder.html') + +@products_bp.route('/css/') +def serve_css(filename): + """Serve CSS files""" + return send_from_directory(os.path.join(basedir, 'static', 'css'), filename) + +@products_bp.route('/js/') +def serve_js(filename): + """Serve JavaScript files""" + return send_from_directory(os.path.join(basedir, 'static', 'js'), filename) + +@products_bp.route('/images/') +def serve_images(filename): + """Serve image files""" + return send_from_directory(os.path.join(basedir, 'static', 'images'), filename) + +@products_bp.route('/data/') +def serve_data(filename): + """Serve data files (JSON)""" + return send_from_directory(os.path.join(basedir, 'data'), filename) diff --git a/product_app/blueprints/users.py b/app/blueprints/users.py similarity index 95% rename from product_app/blueprints/users.py rename to app/blueprints/users.py index fd6b018..330e9d8 100644 --- a/product_app/blueprints/users.py +++ b/app/blueprints/users.py @@ -2,7 +2,7 @@ User Management Blueprint Handles user CRUD operations """ -from flask import Blueprint, render_template, request, jsonify, send_file +from flask import Blueprint, render_template, request, jsonify, send_file, session from werkzeug.security import generate_password_hash, check_password_hash from blueprints.auth import login_required, can_user, get_current_user from io import BytesIO @@ -52,7 +52,8 @@ def user_manager(): """Serve the user management page""" if not can_user('manage_users'): return "

403 - Permission Denied

You don't have permission to manage users.

", 403 - return render_template('user_manager.html') + current_user_id = session.get('user_id', -1) + return render_template('user_manager.html', current_user_id=current_user_id) @users_bp.route('/api', methods=['GET']) @login_required diff --git a/app/cache/product_images/05385681982b54969ad4a32750bdaa8e.png b/app/cache/product_images/05385681982b54969ad4a32750bdaa8e.png deleted file mode 100644 index b7735f8..0000000 Binary files a/app/cache/product_images/05385681982b54969ad4a32750bdaa8e.png and /dev/null differ diff --git a/app/config.py b/app/config.py deleted file mode 100644 index 3a975fe..0000000 --- a/app/config.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Configuration file for Flask application -""" -import os - -class Config: - """Base configuration""" - SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-change-in-production' - DEBUG = False - TESTING = False - - # Application root for subdirectory deployments - # Defaults to '/' (root) for local development - # Set to '/product-finder' for production deployment - APPLICATION_ROOT = os.environ.get('APPLICATION_ROOT', '/') - -class DevelopmentConfig(Config): - """Development configuration""" - DEBUG = True - ENV = 'development' - # Development runs at root - APPLICATION_ROOT = os.environ.get('APPLICATION_ROOT', '/') - -class ProductionConfig(Config): - """Production configuration""" - DEBUG = False - ENV = 'production' - # Production deployed to /product-finder subdirectory - APPLICATION_ROOT = os.environ.get('APPLICATION_ROOT', '/product-finder') - # Add production-specific settings here - # DATABASE_URI = os.environ.get('DATABASE_URL') - -class TestingConfig(Config): - """Testing configuration""" - TESTING = True - DEBUG = True - -# Configuration dictionary -config = { - 'development': DevelopmentConfig, - 'production': ProductionConfig, - 'testing': TestingConfig, - 'default': DevelopmentConfig -} diff --git a/app/data/bitwise_legend.json b/app/data/bitwise_legend.json deleted file mode 100644 index 2ae6992..0000000 --- a/app/data/bitwise_legend.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "description": "Bitwise flag system for product classification", - "bit_definitions": { - "base_attributes": { - "bit_0 (1)": "Base Type = Door", - "bit_1 (2)": "Base Type = Window", - "bit_2 (4)": "Is Accessory", - "bit_3 (8)": "Specific Item Link" - }, - "materials": { - "bit_4 (16)": "Material = Aluminum", - "bit_5 (32)": "Material = Vinyl" - }, - "colors": { - "bit_6 (64)": "Color = Black", - "bit_7 (128)": "Color = White", - "bit_8 (256)": "Color = Bronze", - "bit_9 (512)": "Color = Tan", - "bit_10 (1024)": "Color = Mill", - "bit_11 (2048)": "Color = Sandstone" - }, - "subtypes": { - "bit_12 (4096)": "Subtype = Patio Door", - "bit_13 (8192)": "Subtype = Primary Window", - "bit_14 (16384)": "Subtype = Storm Door", - "bit_15 (32768)": "Subtype = Storm Window" - } - }, - "usage_examples": { - "check_if_door": "bit_value & 1", - "check_if_window": "bit_value & 2", - "check_if_aluminum": "bit_value & 16", - "check_if_white": "bit_value & 128", - "check_multiple": "(bit_value & 1) and (bit_value & 16) # Door AND Aluminum", - "check_subtype_patio_door": "bit_value & 4096", - "check_subtype_primary_window": "bit_value & 8192", - "check_subtype_storm_door": "bit_value & 16384", - "check_subtype_storm_window": "bit_value & 32768" - } -} \ No newline at end of file diff --git a/app/data/door_accessories_data.csv b/app/data/door_accessories_data.csv deleted file mode 100644 index 62c500b..0000000 --- a/app/data/door_accessories_data.csv +++ /dev/null @@ -1,15 +0,0 @@ -Product_Name,Image_URL,Product_Type,Notes -Brass Lever,http://columbiawindows.com/wp-content/uploads/2014/12/CR2DLEC.jpg,Hardware, -Brass Lever (White),http://columbiawindows.com/wp-content/uploads/2014/12/CR2DLEC.jpg,Hardware,Also comes in white -Brass Lever (MT Gold),http://columbiawindows.com/wp-content/uploads/2014/12/MT-MET-GOLD.jpg,Hardware, -Brass Lever (550 Gold),http://columbiawindows.com/wp-content/uploads/2014/12/550-met-gold.jpg,Hardware, -Brass Pull,http://columbiawindows.com/wp-content/uploads/2014/12/dx-ecoat.jpg,Hardware, -Brass Pull (White),http://columbiawindows.com/wp-content/uploads/2014/12/CR3SEC.jpg,Hardware,Also comes in white -Brass Pull (MT Gold),http://columbiawindows.com/wp-content/uploads/2014/12/MT-MET-GOLD.jpg,Hardware, -Brass Pull (550 Gold),http://columbiawindows.com/wp-content/uploads/2014/12/550-met-gold.jpg,Hardware, -Satin Pull,http://columbiawindows.com/wp-content/uploads/2014/12/dx-satin-finish.jpg,Hardware, -Satin Pull (Silver),http://columbiawindows.com/wp-content/uploads/2014/12/MT-satin-silver.jpg,Hardware, -Black Pull Handle,http://columbiawindows.com/wp-content/uploads/2014/12/VPBLACK.jpg,Hardware, -White Pull Handle,http://columbiawindows.com/wp-content/uploads/2014/12/VPWHITE.jpg,Hardware, -Bevel Cut Insert,http://columbiawindows.com/wp-content/uploads/2014/12/bevel.jpg,Insert, -Brass Kick Panel,http://columbiawindows.com/wp-content/uploads/2014/12/brasskp.jpg,Panel, diff --git a/app/data/example_user_structure.json b/app/data/example_user_structure.json deleted file mode 100644 index 7d0f8a0..0000000 --- a/app/data/example_user_structure.json +++ /dev/null @@ -1,68 +0,0 @@ -[ - { - "username": "admin_user", - "password": "pbkdf2:sha256:1000000$examplehash$...", - "defaultLocation": "LINDS", - "active": true, - "permissions": { - "manage_users": true, - "view_reports": true, - "create_quotes": true - }, - "locationSettings": { - "LINDS": { - "accessible": true, - "permissions": { - "manage_inventory": true, - "approve_quotes": true - } - }, - "IOLA": { - "accessible": true, - "permissions": { - "manage_inventory": false, - "approve_quotes": true - } - }, - "KC": { - "accessible": false - }, - "BMD": { - "accessible": false - } - } - }, - { - "username": "standard_user", - "password": "pbkdf2:sha256:1000000$examplehash2$...", - "defaultLocation": "KC", - "active": true, - "permissions": { - "manage_users": false, - "view_reports": true, - "create_quotes": true - }, - "locationSettings": { - "LINDS": { - "accessible": true, - "permissions": { - "manage_inventory": false, - "approve_quotes": false - } - }, - "IOLA": { - "accessible": true - }, - "KC": { - "accessible": true, - "permissions": { - "manage_inventory": false, - "approve_quotes": false - } - }, - "BMD": { - "accessible": true - } - } - } -] diff --git a/app/data/image_configs.json b/app/data/image_configs.json deleted file mode 100644 index ea2b310..0000000 --- a/app/data/image_configs.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "cobrai": { - "sourceImage": "images/cobrai", - "productCode": "COBRAI", - "description": "Storm Door - Full View with Screen", - "availableColors": { - "white": {"rgb": [255, 255, 255], "name": "White"}, - "black": {"rgb": [30, 30, 30], "name": "Black"}, - "bronze": {"rgb": [110, 80, 50], "name": "Bronze"}, - "sandstone": {"rgb": [210, 190, 165], "name": "Sandstone"} - }, - "colorableRegions": [ - { - "name": "region_name", - "topLeft": [24, 23], - "bottomRight": [505, 1022], - "description": "Width: 481px, Height: 999px" - }, - { - "name": "frame", - "topLeft": [0, 0], - "bottomRight": [100, 1450], - "description": "Vertical frame left side" - }, - { - "name": "frame_right", - "topLeft": [620, 0], - "bottomRight": [720, 1450], - "description": "Vertical frame right side" - }, - { - "name": "top_rail", - "topLeft": [0, 0], - "bottomRight": [720, 80], - "description": "Top horizontal rail" - }, - { - "name": "mid_rail", - "topLeft": [0, 590], - "bottomRight": [720, 680], - "description": "Middle horizontal rail" - }, - { - "name": "bottom_panel", - "topLeft": [100, 1090], - "bottomRight": [620, 1450], - "description": "Bottom kickplate panel" - } - ], - "hardwarePositions": { - "handle_right": { - "x": 580, - "y": 730, - "image": "images/hardware/handle-lever.png" - }, - "handle_left": { - "x": 140, - "y": 730, - "image": "images/hardware/handle-lever.png", - "flip": true - }, - "lock": { - "x": 360, - "y": 800, - "image": "images/hardware/lock.png" - } - }, - "glassRegions": [ - { - "name": "top_glass", - "topLeft": [100, 80], - "bottomRight": [620, 590], - "description": "Top screen/glass area" - }, - { - "name": "bottom_glass", - "topLeft": [100, 680], - "bottomRight": [620, 1090], - "description": "Bottom screen/glass area" - } - ], - "metadata": { - "imageWidth": 720, - "imageHeight": 1450, - "defaultColor": "white", - "defaultHinge": "right" - }, - "cache": { - "enabled": true, - "directory": "cache/product_images", - "maxAge": 86400 - } - } -} diff --git a/app/data/product_bitwise.csv b/app/data/product_bitwise.csv deleted file mode 100644 index ea70c36..0000000 --- a/app/data/product_bitwise.csv +++ /dev/null @@ -1,922 +0,0 @@ -PROD_CODE,BIT_VALUE,BIT_HEX,BIT_BINARY,DISCONTINUED,FLAGS -1650-10,16,0x10,10000,False,Aluminum -404,35282,0x89D2,1000100111010010,False,Window | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Window -450,35282,0x89D2,1000100111010010,False,Window | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Window -606,35282,0x89D2,1000100111010010,False,Window | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Window -650,33234,0x81D2,1000000111010010,False,Window | Aluminum | Black | White | Bronze | Subtype:Storm Window -1400,160,0xA0,10100000,False,Vinyl | White -1500,8354,0x20A2,10000010100010,False,Window | Vinyl | White | Subtype:Primary Window -1510,160,0xA0,10100000,False,Vinyl | White -1650,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -1700,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -1710,16,0x10,10000,False,Aluminum -2000,8594,0x2192,10000110010010,False,Window | Aluminum | White | Bronze | Subtype:Primary Window -2100,16,0x10,10000,False,Aluminum -2200,16,0x10,10000,False,Aluminum -2650,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -2700,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -2710,16,0x10,10000,False,Aluminum -3000,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -3100,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -3200,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -3300,400,0x190,110010000,False,Aluminum | White | Bronze -3302,400,0x190,110010000,False,Aluminum | White | Bronze -3303,400,0x190,110010000,False,Aluminum | White | Bronze -3310,400,0x190,110010000,False,Aluminum | White | Bronze -3700,400,0x190,110010000,False,Aluminum | White | Bronze -3710,16,0x10,10000,False,Aluminum -4700,400,0x190,110010000,False,Aluminum | White | Bronze -4710,16,0x10,10000,False,Aluminum -5200,4769,0x12A1,1001010100001,False,Door | Vinyl | White | Tan | Subtype:Patio Door -5700,400,0x190,110010000,False,Aluminum | White | Bronze -6700,16,0x10,10000,False,Aluminum -265010,16,0x10,10000,False,Aluminum -1400SCR,144,0x90,10010000,False,Aluminum | White -1650SCR,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -1650VS,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -1700CSC,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -1700CV,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -1700ESC,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -1700EV,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -1700SCR,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -1700VS,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -2000SCR,400,0x190,110010000,False,Aluminum | White | Bronze -2100EV,400,0x190,110010000,False,Aluminum | White | Bronze -2200PDG,16,0x10,10000,False,Aluminum -2650SCR,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -2650VP,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -2700CV,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -2700EV,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -2700SCR,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -2700VS,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -3000SCR,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -305INS,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -306INS,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -3100EV,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -3100SCR,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -310PSCR,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -3700SCR,400,0x190,110010000,False,Aluminum | White | Bronze -3700VP,400,0x190,110010000,False,Aluminum | White | Bronze -404ONE,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -450ONE,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -4700SCR,400,0x190,110010000,False,Aluminum | White | Bronze -606ONE,1488,0x5D0,10111010000,False,Aluminum | Black | White | Bronze | Mill -6100I,16785,0x4191,100000110010001,False,Door | Aluminum | White | Bronze | Subtype:Storm Door -650ONE,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -8100I,16785,0x4191,100000110010001,False,Door | Aluminum | White | Bronze | Subtype:Storm Door -BELMONT,672,0x2A0,1010100000,False,Vinyl | White | Tan -BGI,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -BGI404,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -BGI606,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -BGIST,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -C-500,2448,0x990,100110010000,False,Aluminum | White | Bronze | Sandstone -C1150,160,0xA0,10100000,False,Vinyl | White -C1621,16,0x10,10000,False,Aluminum -C1622,16,0x10,10000,False,Aluminum -C1626VA,16,0x10,10000,False,Aluminum -C1710,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -C1721,16,0x10,10000,False,Aluminum -C1722,16,0x10,10000,False,Aluminum -C1724,16,0x10,10000,False,Aluminum -C1800,33170,0x8192,1000000110010010,False,Window | Aluminum | White | Bronze | Subtype:Storm Window -C2021,16,0x10,10000,False,Aluminum -C2022,16,0x10,10000,False,Aluminum -C2026,16,0x10,10000,False,Aluminum -C2710,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -C300,16,0x10,10000,False,Aluminum -C3221,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -C3222,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -C3223,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -C3224,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -C3300,400,0x190,110010000,False,Aluminum | White | Bronze -C3700,16,0x10,10000,False,Aluminum -C400,160,0xA0,10100000,False,Vinyl | White -C500,2448,0x990,100110010000,False,Aluminum | White | Bronze | Sandstone -C500GL,0,0x0,0,False,None -C500GLP,0,0x0,0,False,None -C500PP,2448,0x990,100110010000,False,Aluminum | White | Bronze | Sandstone -C500SCR,2448,0x990,100110010000,False,Aluminum | White | Bronze | Sandstone -C500VP,2448,0x990,100110010000,False,Aluminum | White | Bronze | Sandstone -C521,400,0x190,110010000,False,Aluminum | White | Bronze -C522,400,0x190,110010000,False,Aluminum | White | Bronze -C526,400,0x190,110010000,False,Aluminum | White | Bronze -C900,400,0x190,110010000,False,Aluminum | White | Bronze -C900EV,400,0x190,110010000,False,Aluminum | White | Bronze -C900SCR,400,0x190,110010000,False,Aluminum | White | Bronze -C910,16,0x10,10000,False,Aluminum -C910PP,16,0x10,10000,False,Aluminum -C921,400,0x190,110010000,False,Aluminum | White | Bronze -C922,400,0x190,110010000,False,Aluminum | White | Bronze -C924,400,0x190,110010000,False,Aluminum | White | Bronze -C931,400,0x190,110010000,False,Aluminum | White | Bronze -C939,400,0x190,110010000,False,Aluminum | White | Bronze -C940,400,0x190,110010000,False,Aluminum | White | Bronze -C949,400,0x190,110010000,False,Aluminum | White | Bronze -C960,16,0x10,10000,False,Aluminum -COBRAI,18897,0x49D1,100100111010001,False,Door | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Door -COBRATI,18897,0x49D1,100100111010001,False,Door | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Door -CRWNFVI,16401,0x4011,100000000010001,False,Door | Aluminum | Subtype:Storm Door -CRWNSDI,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -D770,8354,0x20A2,10000010100010,False,Window | Vinyl | White | Subtype:Primary Window -DSGLASS,0,0x0,0,False,None -DURASEA,0,0x0,0,False,None -EXPAND,16,0x10,10000,False,Aluminum -FULLSCR,16,0x10,10000,False,Aluminum -FVGI,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -FVSI,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -GOLIATH,16401,0x4011,100000000010001,False,Door | Aluminum | Subtype:Storm Door -HERCULE,16401,0x4011,100000000010001,False,Door | Aluminum | Subtype:Storm Door -IMPERIL,4561,0x11D1,1000111010001,False,Door | Aluminum | Black | White | Bronze | Subtype:Patio Door -INSGLAS,0,0x0,0,False,None -ISP,464,0x1D0,111010000,False,Aluminum | Black | White | Bronze -IVP,4561,0x11D1,1000111010001,False,Door | Aluminum | Black | White | Bronze | Subtype:Patio Door -JET,4497,0x1191,1000110010001,False,Door | Aluminum | White | Bronze | Subtype:Patio Door -JSP,400,0x190,110010000,False,Aluminum | White | Bronze -JVP,4497,0x1191,1000110010001,False,Door | Aluminum | White | Bronze | Subtype:Patio Door -KINGDVI,18897,0x49D1,100100111010001,False,Door | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Door -KINGFSC,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -KINGI,18897,0x49D1,100100111010001,False,Door | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Door -KINGSDI,18897,0x49D1,100100111010001,False,Door | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Door -M1200,4497,0x1191,1000110010001,False,Door | Aluminum | White | Bronze | Subtype:Patio Door -M306,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -OUTSIDE,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -PATIOSC,6609,0x19D1,1100111010001,False,Door | Aluminum | Black | White | Bronze | Sandstone | Subtype:Patio Door -PDSCRTT,6609,0x19D1,1100111010001,False,Door | Aluminum | Black | White | Bronze | Sandstone | Subtype:Patio Door -PRPDS,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -PRSCR,3984,0xF90,111110010000,False,Aluminum | White | Bronze | Tan | Mill | Sandstone -PRSCR11,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -PSINS,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -PWS,4048,0xFD0,111111010000,False,Aluminum | Black | White | Bronze | Tan | Mill | Sandstone -PWSINS,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -R1150,160,0xA0,10100000,False,Vinyl | White -R1400,8354,0x20A2,10000010100010,False,Window | Vinyl | White | Subtype:Primary Window -R1500,8354,0x20A2,10000010100010,False,Window | Vinyl | White | Subtype:Primary Window -R1510,32,0x20,100000,False,Vinyl -R2000,8594,0x2192,10000110010010,False,Window | Aluminum | White | Bronze | Subtype:Primary Window -R2100,400,0x190,110010000,False,Aluminum | White | Bronze -R2100EV,400,0x190,110010000,False,Aluminum | White | Bronze -R2200,400,0x190,110010000,False,Aluminum | White | Bronze -R300,16,0x10,10000,False,Aluminum -R3302,400,0x190,110010000,False,Aluminum | White | Bronze -R400,160,0xA0,10100000,False,Vinyl | White -R770,8354,0x20A2,10000010100010,False,Window | Vinyl | White | Subtype:Primary Window -R770SCR,16,0x10,10000,False,Aluminum -RCKTRAP,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -REWIRE,16,0x10,10000,False,Aluminum -RNDROCK,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -ROCKET,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -RROCKET,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -SCRI,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -SCRI404,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -SCRI606,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -SCRI808,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -SSGLASS,0,0x0,0,False,None -SSSCR,16,0x10,10000,False,Aluminum -TBGI,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -TBR,4561,0x11D1,1000111010001,False,Door | Aluminum | Black | White | Bronze | Subtype:Patio Door -TGI,1424,0x590,10110010000,False,Aluminum | White | Bronze | Mill -TGI404,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -TGI606,3536,0xDD0,110111010000,False,Aluminum | Black | White | Bronze | Mill | Sandstone -TGIODD,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -THOR,16401,0x4011,100000000010001,False,Door | Aluminum | Subtype:Storm Door -TVI,18897,0x49D1,100100111010001,False,Door | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Door -VKI,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -VP3700,400,0x190,110010000,False,Aluminum | White | Bronze -WINDGAT,672,0x2A0,1010100000,False,Vinyl | White | Tan -ZBARS,2512,0x9D0,100111010000,False,Aluminum | Black | White | Bronze | Sandstone -COBRATK,18897,0x49D1,100100111010001,False,Door | Aluminum | Black | White | Bronze | Sandstone | Subtype:Storm Door -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None -,0,0x0,0,False,None diff --git a/app/data/product_code_mapping.json b/app/data/product_code_mapping.json deleted file mode 100644 index 6cb5c98..0000000 --- a/app/data/product_code_mapping.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "COBRAI": "1100", - "COBRATI": "1100", - "TVI": "1100", - "TRTI": "1100", - "1400": "1400", - "1500": "1500", - "1650": "1650", - "2000": "2000", - "1700": "1700", - "2100": "2100", - "2700": "2700", - "3100": "3100", - "1510": "1510", - "2200": "2200", - "3200": "3200", - "3300": "3300", - "3302": "3302", - "3303": "3303", - "3310": "3310", - "2400": "2400" -} diff --git a/app/data/products-old.csv b/app/data/products-old.csv deleted file mode 100644 index 594dc3b..0000000 --- a/app/data/products-old.csv +++ /dev/null @@ -1,1000 +0,0 @@ -,,,,,,Base,Sub-type,,Accessory,,Materials,,Colors,,,,,, -DISCONT,LOC_CODE,PROD_CODE,CATEGORY,CATEGORY_NEW,DESCRIPTION,Type,Door,Window,Yes,This Item,Aluminum,Vinyl,Black,White,Bronze,Tan,Mill,Sandstone,~ -FALSE,Iola,2100EV,2000SLI,,SERIES 2100 3-PANEL SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3000,3000DHP,,SERIES 3000 D.H. T.B REPLACEMENT WD,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3100,3000DHP,,SERIES 3100 T.B. REPLACEMENT SLIDER,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3100EV,3000DHP,,SERIES 3100 3-PANEL SLIDER,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,LINCOLN,3000DHP,,LINCOLN PRIMARY WOOD WINDOWS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,3200,3000FPP,,SERIES 3200 T.B. PICTURE WINDOW,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,BELMONT,3000FPP,,BELMONT ALLIANCE DOUBLE HUNG WINDOW,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE, -FALSE,Iola,C300,BSMT,,C-300 ALUM INSERTS FOR BASEMENT BUCKS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C400,BSMT,,C-400 VINYL INSERT FOR BASEMENT BUCKS,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1800,C1800,,C-1800 INSIDE SLIDING STORM WINDOW,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3300,CASEMNT,,3300 1-PANEL T.B. CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3302,CASEMNT,,3300 2-PANEL T.B. CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3303,CASEMNT,,3300 3-PANEL T.B. CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3310,CASEMNT,,3310 FIXED CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,3400,CASEMNT,,3400 1 PANEL VINYL CLAD CASEMENT,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3402,CASEMNT,,3400 2 PANEL VINYL CLAD CASEMENT,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3403,CASEMNT,,3400 3 PANEL VINYL CLAD CASEMENT,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3500,CASEMNT,,3500 1-PANEL WOOD INTERIOR CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3502,CASEMNT,,3500 2-PANEL WOOD INTERIOR CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3503,CASEMNT,,3503 3-PANEL WOOD INTERIOR CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1150,CASEMNT,,C1150-VINYL AWNING WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C3300,CASEMNT,,3300 1-PANEL T.B. CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,C610,CASEMNT,,C610 VINYL CASEMENT WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R3302,CASEMNT,,3302 2-PANEL T.B. CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,C1500AR,CIR TOP,,C-1510 VINYL ARCH TOP-OPERATING WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C1510AR,CIR TOP,,C-1510 VINYL ARCH TOP WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C1521,CIR TOP,,C-1521 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C1526,CIR TOP,,C-1526 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1621,CIR TOP,,C-1621 INSULATED CIRCLE TOP,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1622,CIR TOP,,C-1622 INSULATED CIRCLE TOP,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1626VA,CIR TOP,,C-1626VA INSULATED CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1721,CIR TOP,,C-1721 INSULATED CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1722,CIR TOP,,C-1722 INSULATED CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1724,CIR TOP,,C-1724 INSULATED CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C2021,CIR TOP,,C-2021 T.B CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C2022,CIR TOP,,C-2022 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C2026,CIR TOP,,C-2026 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C3221,CIR TOP,,C-3221 T.B CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C3222,CIR TOP,,C-3222 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C3223,CIR TOP,,C-3223 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C3224,CIR TOP,,C-3224 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C521,CIR TOP,,C-521 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C522,CIR TOP,,C-522 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C526,CIR TOP,,C-526 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,C621,CIR TOP,,C-621 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C626,CIR TOP,,C-626 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C826,CIR TOP,,C-826 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C828,CIR TOP,,C-828 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C8321,CIR TOP,,C-8321 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C8326,CIR TOP,,C-8326 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C921,CIR TOP,,C-921 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C922,CIR TOP,,C-922 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C924,CIR TOP,,C-924 T.B. CIRCLE TOPS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C931,CIR TOP,,C-931 T.B. ROUND PRIMARY WINDOW,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C939,CIR TOP,,C-939 T.B. ROUND PRIMARY WINDOW,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C940,CIR TOP,,C-940 T.B. OCTAGON PRIMARY,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C949,CIR TOP,,C949 OCTAGON THERMAL BREAK WINDOW,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,EXPAND,EXPANDR,,SILL EXPANDERS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1510,FPPW,,1510 VINYL INSULATED FIXED LITE,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1650-10,FPPW,,#1650-10 INSULATED FIXED LITE,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1710,FPPW,,C-1710 FIXED LITE,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,2200,FPPW,,SERIES 2200 T.B. FIXED LITE,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,2200PDG,FPPW,,SERIES 2200 TB FIXED LITE W/TEMP GLASS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,265010,FPPW,,#2650-10 SINGLE GLAZED FIXED LITE,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,2710,FPPW,,C-2710 FIXED LITE - SINGLE GLAZED,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,3710,FPPW,,C-3710 INSULATED FIXED LITE,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,4710,FPPW,,#4710 SINGLE GLAZED FIXED LITE,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C620,FPPW,,C620 VINYL AWNING WINDOWS,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C640,FPPW,,C-640 VINYL FIXED CASEMENT WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C910,FPPW,,C-910 INSULATED T.B. FIXED LITE,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C910PP,FPPW,,C-910 ARCH TOP,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C960,FPPW,,C-960 INSULATED T.B. CIRCLE TOP,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,D832,FPPW,,D832 FIXED VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,DURASEA,FPPW,,"DURASEAL 5/8"" (GRAY) PER REEL",,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R1510,FPPW,,SERIES 1510 FIXED LITE VINYL PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R822,FPPW,,S822 FIXED VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R832,FPPW,,R832 FIXED VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,S822,FPPW,,S822 FIXED VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,G3000,GARDEN,,COLUMBIA COMFORT 3000 VINYL GARDEN WD,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,DSGLASS,GLASS,,DOUBLE STRENGTH GLASS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,INSGLAS,GLASS,,INSULATED GLASS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,SSGLASS,GLASS,,SINGLE STRENGTH GLASS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,305INS,INSERTS,,#305 SASH WINDCHECK INSERTS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,306INS,INSERTS,,#306 SCHLEGEL GLASS INSERTS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,BGI,INSERTS,,BOTTOM GL INSERTS FOR ECONOMY ST WDS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,BGI404,INSERTS,,BOTTOM GL INSERTS FOR #404/450 ST WDS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,BGI606,INSERTS,,BOTTOM GL INSERTS FOR #606/650 ST WDS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,BGIST,INSERTS,,INSERTS FOR STORM DOORS,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,FVGI,INSERTS,,GLASS INSERTS FOR KING ONE LITE,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,FVSI,INSERTS,,FULL SCREENS ONLY FOR KING ONE-LITES,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,KINGFSC,INSERTS,,FULL SCREEN FOR KING ONE-LITE,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,M306,INSERTS,,M-306 SCHLEGEL GLASS INSERTS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,PSINS,INSERTS,,PLAIN SASH INSERTS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,PWSINS,INSERTS,,INSERTS ONLY FOR PIN-ON PICTURE WINDOW,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,RCKTRAP,INSERTS,,ROCKET TRAPEZOIDS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,RNDROCK,INSERTS,,ROUND ROCKET INSERT,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,ROCKET,INSERTS,,ROCKET INSERTS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,RROCKET,INSERTS,,RADIUS ROCKETS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,SCRI,INSERTS,,SCREEN INSERTS FOR ECONOMY STORM WDS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,SCRI404,INSERTS,,SCREEN INSERTS FOR #404/450 STORM WDS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,SCRI606,INSERTS,,SCREEN INSERTS FOR #606/650 STORM WDS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,SCRI808,INSERTS,,SCREEN INSERTS FOR #808/850 STORM WIND,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,SSSCR,INSERTS,,SCREEN INSERT FOR SELF STORING DOORS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,TBGI,INSERTS,,TEMPERED GLASS INSERTS FOR SS DOORS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,TGI,INSERTS,,TOP GL INSERTS FOR ECONOMY ST WDS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,TGI404,INSERTS,,TOP GLASS INSERTS FOR #404/450 ST WDS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,TGI606,INSERTS,,TOP GLASS INSERTS FOR #606/650 ST WDS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,TGIODD,INSERTS,,TOP GLASS INSERTS FOR STORM DOORS,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,TVGROOV,INSERTS,,TEMPERED V-GROOVE ONE-LITE INSERTS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,XBUCKIN,INSERTS,,TEMPERED GLASS INSERTS FOR CROSSBUCKS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,2400,PD,,2400 ROYAL CROWN PATIO DOOR,Door,Patio Door,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,5200,PD,,5200 VINYL PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE, -TRUE,Iola,C4260,PD,,C-4260 STEEL MIRROR DOOR,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,IMPERIL,PD,,IMPERIAL PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,ISP,PD,,STATIONARY PANELS FOR IMPERIAL DOORS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,IVP,PD,,VENT PANELS FOR IMPERIAL PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,JET,PD,,COLUMBIA JET PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,JSP,PD,,STATIONARY PANELS FOR JET DOORS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,JVP,PD,,VENT PANELS FOR JET PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,LINCPDR,PD,,LINCOLN FRENCH PATIO DOOR,Door,Patio Door,,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,M1200,PD,,M1200 PATIO STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,TBR,PD,,IMPERIAL T.B.R. REPLACEMENT PATIO DOOR,Door,Patio Door,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,PRSCR,PSCREEN,,SCREENS FOR PRIME MADE FROM #19-88,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE, -FALSE,Iola,PRSCR11,PSCREEN,,SCREEN FOR PRIME MADE FROM #19-11,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,R2100EV,R2000SL,,SERIES 2100 3-PANEL T.B. SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,R300,RBSMT,,C-300 ALUM INSERTS FOR BASEMENT BUCKS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R400,RBSMT,,C-400 VINYL INSERT FOR BASEMENT BUCKS,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,4100,REPLACE,,SERIES 4100 VINYL SLIDER,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C4000,REPLACE,,C-4000 SINGLE HUNGE PRIMARY WINDOW,Window,,Primary Window,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R1150,REPLACE,,R-1150 VINYL AWNING WINDOWS,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R1400,REPLACE,,SERIES 1400 VINYL SLIDING PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R1500,REPLACE,,SERIES 1500 S.H. TILT VINYL PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R2000,REPLACE,,SERIES 2000 S.H. T.B. TILT PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,R2100,REPLACE,,SERIES 2100 THERMAL BREAK SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,R5000,REPLACE,,R-5000 INSULATED ALUMINUM SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R770,REPLACE,,R770 D.H. TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R780,REPLACE,,R780 VINYL SLIDING PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R820,REPLACE,,R820 S.H. TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R821,REPLACE,,S821 SINGLE SLIDE VINYL PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R830,REPLACE,,R830 D.H.TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R2200,RFPPW,,SERIES 2200 T.B. FIXED LITE,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,1650SCR,SCREENS,,SCREENS FOR #1650,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700CSC,SCREENS,,SCREEN FOR #1700 CENTER VENT SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700ESC,SCREENS,,SCREEN FOR #1700 ENDS VENT SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700SCR,SCREENS,,SCREEN FOR #1700 SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2650SCR,SCREENS,,SCREENS FOR 2650,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700SCR,SCREENS,,SCREENS FOR #2700,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,3000SCR,SCREENS,,SCREENS FOR #3000,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3100SCR,SCREENS,,SCREENS FOR #3100,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3700SCR,SCREENS,,SCREEN FOR #3700 POLE BARN WD,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,4700SCR,SCREENS,,SCREENS FOR #4700,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,5000SCR,SCREENS,,SCREEN FOR R5000 SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C500SCR,SCREENS,,C-500 SCREEN,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,C900SCR,SCREENS,,SCREEN FOR C-900,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,FULLSCR,SCREENS,,FULL SCREEN,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,PATIOSC,SCREENS,,PATIO DOOR SCREENS,Door,Patio Door,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,PDSCRTT,SCREENS,,SPECIAL SIZE SCREENS FOR PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,PRPDS,SCREENS,,SCREENS MADE FROM PLAIN PATIO SCR RAIL,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,R770SCR,SCREENS,,FULL SCREEN,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,REWIRE,SCREENS,,REWIRED SCREENS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,310PSCR,SCRINS,,#310 PLAIN SCREENS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,1500,SHPT,,SERIES 1500 S.H. TILT VINYL PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,2000,SHPT,,SERIES 2000 S.H. T.B. TILT PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,2000SCR,SHPT,,C-2000 SCREEN,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,2100,SHPT,,SERIES 2100 THERMAL BREAK SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,6300,SHPT,,SERIES 6300 S.H. TILT VINYL PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,D770,SHPT,,D770 D.H. TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,D830,SHPT,,D830 D.H.TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,D830SCR,SHPT,,D830 SCREEN,Window,,Primary Window,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,S820,SHPT,,S820 S.H. TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1400,SHPW,,SERIES 1400 VINYL SLIDING PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1400SCR,SHPW,,1400 SCREEN,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1650,SHPW,,#1650 INSULATED SINGLE HUNG,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1650VS,SHPW,,1650 BOTTOM SASH,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700,SHPW,,#1700 INSULATED SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700CV,SHPW,,1700 CENTER VENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700EV,SHPW,,1700 END VENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700VS,SHPW,,#1700 VENT SASH,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2650,SHPW,,#2650 SINGLE HUNG SINGLE GLAZED PRIME,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2650VP,SHPW,,#2650 VENT PANEL - SINGLE HUNGE,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700,SHPW,,#2700 SINGLE GLAZED SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700CV,SHPW,,C-2700 - CENTER VENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700EV,SHPW,,C-2700 - END VENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700VS,SHPW,,#2700 VENT SASH,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,3700,SHPW,,#3700 INSULATED SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3700VP,SHPW,,#3700 VENT PANEL,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,4700,SHPW,,#4700 SINGLE GLAZED SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,5700,SHPW,,#5700 INSULATED SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,6301,SHPW,,SERIES 6301 VINYL SLIDING PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,6700,SHPW,,#6700 SINGLE GLAZED SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C-500,SHPW,,C-500 SH THERMAL BREAK INS.,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,C1710,SHPW,,#1710 PICTURE OVER SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,C2710,SHPW,,#2710 PICTURE OVER SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,C3700,SHPW,,C-3700 INSULATED SLIDING POLE BARN WND,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C500,SHPW,,C-500 INS THERMAL BREAK SINGLE HUNG,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,C500PP,SHPW,,C-500 INS THERMAL BREAK SINGLE HUNG,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,C900,SHPW,,C-900 INS THERMAL BREAK SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C900EV,SHPW,,C-900 ENDS VENT SLIDER,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,D780,SHPW,,D780 DOUBLE SLIDE VINYL PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,S821,SHPW,,S821 SINGLE SLIDE VINYL PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,6100I,STD,,STAR 6100 FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,6100L,STD,,STAR 6100 FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,7100I,STD,,STAR 7100 FULL VIEW SELF STORING DOOR,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,7100L,STD,,STAR 7100 FULL VIEW SELF STORING DOOR,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,8100I,STD,,STAR 8100 FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,8100L,STD,,STAR 8100 FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,COBRAI,STD,,COLUMBIA COBRA STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,COBRAL,STD,,COLUMBIA COBRA STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,COBRATI,STD,,COLUMBIA COBRA STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,COBRATL,STD,,COLUMBIA COBRA STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,CRWNFVI,STD,,CROWN FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,CRWNFVL,STD,,CROWN FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,CRWNSDI,STD,,COLUMBIA CROWN SCREEN DOOR,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,CRWNSDL,STD,,COLUMBIA CROWN SCREEN DOOR,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,FV10I,STD,,KING FV-10 DECORATOR STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,FV10L,STD,,KING FV-10 DECORATOR STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,FV3I,STD,,KING FV-3 DECORATOR STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,FV3L,STD,,KING FV-3 DECORATOR STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,GOLIATH,STD,,GOLIATH STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,HERCULE,STD,,HERCULES STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,KINGDVI,STD,,KING DUAL VENT STORM DOORS,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,KINGDVL,STD,,KING DUAL VENT STORM DOORS,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,KINGI,STD,,KING ONE-LITE STORM DOORS,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,KINGL,STD,,KING ONE-LITE STORM DOORS,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,KINGSDI,STD,,KING ONE-LITE SCREEN DOOR ONLY,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,KINGSDL,STD,,KING ONE-LITE SCREEN DOOR ONLY,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,ROYAL,STD,,COLUMBIA ROYAL STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,SS10I,STD,,COBRA SS-10 DECORATOR STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,SS10L,STD,,COBRA SS-10 DECORATOR STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,SS3I,STD,,COBRA SS-3 DECORATOR STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,SS3L,STD,,COBRA SS-3 DECORATOR STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,THOR,STD,,THOR - STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,TIARAI,STD,,COLUMBIA TIARA SELF STORING STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,TIARAL,STD,,COLUMBIA TIARA SELF STORING STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,TVI,STD,,COLUMBIA COBRA TWIN VENT STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,TVL,STD,,COLUMBIA COBRA TWIN VENT STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,OUTSIDE,STDMISC,,OUTSIDE DOOR SWEEPS - ALUM + VINYL,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,ZBARS,STDMISC,,Z-BARS FOR STORM DOORS,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,VKI,STOCK,,VENTILATOR KICKPANEL FOR KING ONELITE,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,VKS,STOCK,,VENTILATOR SCREEN FOR KING ONE LITE,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,303,STORMS,,#303 DART STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,350,STORMS,,#350 ARROW STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,404,STORMS,,#404 FALCON STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,450,STORMS,,#450 RAVEN STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,606,STORMS,,#606 LION STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,650,STORMS,,#650 LYNX STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,808,STORMS,,808 HAWK STORM WINDOW,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,850,STORMS,,#850 KENT STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,404ONE,STPW,,#404 ONE-LITE ST WD,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,450ONE,STPW,,#450 ONE-LITE ST WD,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,606ONE,STPW,,#606 ONE-LITE ST WD,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,650ONE,STPW,,#650 ONE-LITE ST WD,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -TRUE,Iola,808ONE,STPW,,#808 ONE-LITE ST WD,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,850ONE,STPW,,#850 ONE-LITE ST WD,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,PWS,STPW,,PIN-ON PICTURE WINDOWS,,,,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE, -FALSE,Iola,WINDGAT,VACW,,ALLIANCE WINDGATE CASEMENT WINDOW,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE, -FALSE,Iola,C500GL,VENTS,,LITES OF INSULATED GLASS FOR C-500'S,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C500GLP,VENTS,,LITES OF INSULATED GLASS FOR C-500'S,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C500VP,VENTS,,VENT PANELS FOR C-500,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,VP3700,VENTS,,VENT PANELS FOR #3700,,,,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,KC,,,,Cobra aluminum storm door,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,KC,,,,Cobra Twin-Vent aluminum storm door,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,KC,,,,Cobra aluminum storm door with Glass Kick Panel,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, \ No newline at end of file diff --git a/app/data/products.csv b/app/data/products.csv deleted file mode 100644 index 002b3ff..0000000 --- a/app/data/products.csv +++ /dev/null @@ -1,998 +0,0 @@ -,,,,,,Base,Sub-type,,Accessory,,Materials,,Colors,,,,,, -DISCONT,LOC_CODE,PROD_CODE,CATEGORY,CATEGORY_NEW,DESCRIPTION,Type,Door,Window,Yes,This Item,Aluminum,Vinyl,Black,White,Bronze,Tan,Mill,Sandstone,~ -FALSE,Iola,1650-10,FPPW,,#1650-10 INSULATED FIXED LITE,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,303,STORMS,,#303 DART STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,350,STORMS,,#350 ARROW STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,404,STORMS,,#404 FALCON STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,450,STORMS,,#450 RAVEN STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,606,STORMS,,#606 LION STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,650,STORMS,,#650 LYNX STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,808,STORMS,,808 HAWK STORM WINDOW,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,850,STORMS,,#850 KENT STORM WINDOWS,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1400,SHPW,,SERIES 1400 VINYL SLIDING PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1500,SHPT,,SERIES 1500 S.H. TILT VINYL PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1510,FPPW,,1510 VINYL INSULATED FIXED LITE,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1650,SHPW,,#1650 INSULATED SINGLE HUNG,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700,SHPW,,#1700 INSULATED SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1710,FPPW,,C-1710 FIXED LITE,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,2000,SHPT,,SERIES 2000 S.H. T.B. TILT PRIMARY,Window,,Primary Window,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,2100,SHPT,,SERIES 2100 THERMAL BREAK SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,2200,FPPW,,SERIES 2200 T.B. FIXED LITE,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,2400,PD,,2400 ROYAL CROWN PATIO DOOR,Door,Patio Door,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,2650,SHPW,,#2650 SINGLE HUNG SINGLE GLAZED PRIME,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700,SHPW,,#2700 SINGLE GLAZED SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2710,FPPW,,C-2710 FIXED LITE - SINGLE GLAZED,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,3000,3000DHP,#N/A,SERIES 3000 D.H. T.B REPLACEMENT WD,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3100,3000DHP,#N/A,SERIES 3100 T.B. REPLACEMENT SLIDER,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3200,3000FPP,#N/A,SERIES 3200 T.B. PICTURE WINDOW,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3300,CASEMNT,,3300 1-PANEL T.B. CASEMENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3302,CASEMNT,,3300 2-PANEL T.B. CASEMENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3303,CASEMNT,,3300 3-PANEL T.B. CASEMENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3310,CASEMNT,,3310 FIXED CASEMENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,3400,CASEMNT,,3400 1 PANEL VINYL CLAD CASEMENT,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3402,CASEMNT,,3400 2 PANEL VINYL CLAD CASEMENT,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3403,CASEMNT,,3400 3 PANEL VINYL CLAD CASEMENT,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3500,CASEMNT,,3500 1-PANEL WOOD INTERIOR CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3502,CASEMNT,,3500 2-PANEL WOOD INTERIOR CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,3503,CASEMNT,,3503 3-PANEL WOOD INTERIOR CASEMENT,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,3700,SHPW,,#3700 INSULATED SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3710,FPPW,,C-3710 INSULATED FIXED LITE,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,4100,REPLACE,,SERIES 4100 VINYL SLIDER,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,4700,SHPW,,#4700 SINGLE GLAZED SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,4710,FPPW,,#4710 SINGLE GLAZED FIXED LITE,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,5200,PD,,5200 VINYL PATIO DOORS,Door,Patio Door,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE, -FALSE,Iola,5700,SHPW,,#5700 INSULATED SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,6300,SHPT,,SERIES 6300 S.H. TILT VINYL PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,6301,SHPW,,SERIES 6301 VINYL SLIDING PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,6700,SHPW,,#6700 SINGLE GLAZED SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,265010,FPPW,,#2650-10 SINGLE GLAZED FIXED LITE,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1400SCR,SHPW,,1400 SCREEN,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,1650SCR,SCREENS,,SCREENS FOR #1650,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1650VS,SHPW,,1650 BOTTOM SASH,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700CSC,SCREENS,,SCREEN FOR #1700 CENTER VENT SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700CV,SHPW,,1700 CENTER VENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700ESC,SCREENS,,SCREEN FOR #1700 ENDS VENT SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700EV,SHPW,,1700 END VENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700SCR,SCREENS,,SCREEN FOR #1700 SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,1700VS,SHPW,,#1700 VENT SASH,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2000SCR,SHPT,,C-2000 SCREEN,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,2100EV,2000SLI,#N/A,SERIES 2100 3-PANEL SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,2200PDG,FPPW,,SERIES 2200 TB FIXED LITE W/TEMP GLASS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,2650SCR,SCREENS,,SCREENS FOR 2650,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2650VP,SHPW,,#2650 VENT PANEL - SINGLE HUNGE,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700CV,SHPW,,C-2700 - CENTER VENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700EV,SHPW,,C-2700 - END VENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700SCR,SCREENS,,SCREENS FOR #2700,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,2700VS,SHPW,,#2700 VENT SASH,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,3000SCR,SCREENS,,SCREENS FOR #3000,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,305INS,INSERTS,,#305 SASH WINDCHECK INSERTS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,306INS,INSERTS,,#306 SCHLEGEL GLASS INSERTS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,3100EV,3000DHP,#N/A,SERIES 3100 3-PANEL SLIDER,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3100SCR,SCREENS,,SCREENS FOR #3100,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,310PSCR,SCRINS,,#310 PLAIN SCREENS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,3700SCR,SCREENS,,SCREEN FOR #3700 POLE BARN WD,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,3700VP,SHPW,,#3700 VENT PANEL,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,404ONE,STPW,,#404 ONE-LITE ST WD,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,450ONE,STPW,,#450 ONE-LITE ST WD,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,4700SCR,SCREENS,,SCREENS FOR #4700,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,5000SCR,SCREENS,,SCREEN FOR R5000 SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,606ONE,STPW,,#606 ONE-LITE ST WD,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,6100I,STD,,STAR 6100 FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,6100L,STD,,STAR 6100 FULL VIEW STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,650ONE,STPW,,#650 ONE-LITE ST WD,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -TRUE,Iola,7100I,STD,,STAR 7100 FULL VIEW SELF STORING DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,7100L,STD,,STAR 7100 FULL VIEW SELF STORING DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,808ONE,STPW,,#808 ONE-LITE ST WD,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,8100I,STD,,STAR 8100 FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,8100L,STD,,STAR 8100 FULL VIEW STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,850ONE,STPW,,#850 ONE-LITE ST WD,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,BELMONT,3000FPP,#N/A,BELMONT ALLIANCE DOUBLE HUNG WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE, -FALSE,Iola,BGI,INSERTS,,BOTTOM GL INSERTS FOR ECONOMY ST WDS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,BGI404,INSERTS,,BOTTOM GL INSERTS FOR #404/450 ST WDS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,BGI606,INSERTS,,BOTTOM GL INSERTS FOR #606/650 ST WDS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,BGIST,INSERTS,,INSERTS FOR STORM DOORS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,C-500,SHPW,,C-500 SH THERMAL BREAK INS.,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,C1150,CASEMNT,,C1150-VINYL AWNING WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C1500AR,CIR TOP,,C-1510 VINYL ARCH TOP-OPERATING WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C1510AR,CIR TOP,,C-1510 VINYL ARCH TOP WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C1521,CIR TOP,,C-1521 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C1526,CIR TOP,,C-1526 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1621,CIR TOP,,C-1621 INSULATED CIRCLE TOP,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1622,CIR TOP,,C-1622 INSULATED CIRCLE TOP,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1626VA,CIR TOP,,C-1626VA INSULATED CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1710,SHPW,,#1710 PICTURE OVER SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,C1721,CIR TOP,,C-1721 INSULATED CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1722,CIR TOP,,C-1722 INSULATED CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1724,CIR TOP,,C-1724 INSULATED CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C1800,C1800,#N/A,C-1800 INSIDE SLIDING STORM WINDOW,Window,,Storm Window,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C2021,CIR TOP,,C-2021 T.B CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C2022,CIR TOP,,C-2022 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C2026,CIR TOP,,C-2026 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C2710,SHPW,,#2710 PICTURE OVER SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,C300,BSMT,#N/A,C-300 ALUM INSERTS FOR BASEMENT BUCKS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C3221,CIR TOP,,C-3221 T.B CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C3222,CIR TOP,,C-3222 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C3223,CIR TOP,,C-3223 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C3224,CIR TOP,,C-3224 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C3300,CASEMNT,,3300 1-PANEL T.B. CASEMENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C3700,SHPW,,C-3700 INSULATED SLIDING POLE BARN WND,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C400,BSMT,#N/A,C-400 VINYL INSERT FOR BASEMENT BUCKS,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C4000,REPLACE,,C-4000 SINGLE HUNGE PRIMARY WINDOW,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C4260,PD,,C-4260 STEEL MIRROR DOOR,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C500,SHPW,,C-500 INS THERMAL BREAK SINGLE HUNG,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,C500GL,VENTS,,LITES OF INSULATED GLASS FOR C-500'S,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C500GLP,VENTS,,LITES OF INSULATED GLASS FOR C-500'S,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C500PP,SHPW,,C-500 INS THERMAL BREAK SINGLE HUNG,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,C500SCR,SCREENS,,C-500 SCREEN,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,C500VP,VENTS,,VENT PANELS FOR C-500,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,C521,CIR TOP,,C-521 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C522,CIR TOP,,C-522 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C526,CIR TOP,,C-526 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -TRUE,Iola,C610,CASEMNT,,C610 VINYL CASEMENT WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C620,FPPW,,C620 VINYL AWNING WINDOWS,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C621,CIR TOP,,C-621 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C626,CIR TOP,,C-626 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C640,FPPW,,C-640 VINYL FIXED CASEMENT WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C826,CIR TOP,,C-826 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C828,CIR TOP,,C-828 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C8321,CIR TOP,,C-8321 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,C8326,CIR TOP,,C-8326 VINYL CIRCLE TOP,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C900,SHPW,,C-900 INS THERMAL BREAK SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C900EV,SHPW,,C-900 ENDS VENT SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C900SCR,SCREENS,,SCREEN FOR C-900,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C910,FPPW,,C-910 INSULATED T.B. FIXED LITE,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C910PP,FPPW,,C-910 ARCH TOP,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,C921,CIR TOP,,C-921 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C922,CIR TOP,,C-922 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C924,CIR TOP,,C-924 T.B. CIRCLE TOPS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C931,CIR TOP,,C-931 T.B. ROUND PRIMARY WINDOW,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C939,CIR TOP,,C-939 T.B. ROUND PRIMARY WINDOW,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C940,CIR TOP,,C-940 T.B. OCTAGON PRIMARY,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C949,CIR TOP,,C949 OCTAGON THERMAL BREAK WINDOW,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,C960,FPPW,,C-960 INSULATED T.B. CIRCLE TOP,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,COBRAI,STD,,COLUMBIA COBRA STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,COBRAL,STD,,COLUMBIA COBRA STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,COBRATI,STD,,COLUMBIA COBRA STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,COBRATL,STD,,COLUMBIA COBRA STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,CRWNFVI,STD,,CROWN FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,CRWNFVL,STD,,CROWN FULL VIEW STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,CRWNSDI,STD,,COLUMBIA CROWN SCREEN DOOR,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,CRWNSDL,STD,,COLUMBIA CROWN SCREEN DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,D770,SHPT,,D770 D.H. TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,D780,SHPW,,D780 DOUBLE SLIDE VINYL PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,D830,SHPT,,D830 D.H.TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,D830SCR,SHPT,,D830 SCREEN,Window,,Primary Window,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,D832,FPPW,,D832 FIXED VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,DSGLASS,GLASS,,DOUBLE STRENGTH GLASS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,DURASEA,FPPW,,"DURASEAL 5/8"" (GRAY) PER REEL",,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,EXPAND,EXPANDR,,SILL EXPANDERS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,FULLSCR,SCREENS,,FULL SCREEN,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,FV10I,STD,,KING FV-10 DECORATOR STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,FV10L,STD,,KING FV-10 DECORATOR STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,FV3I,STD,,KING FV-3 DECORATOR STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,FV3L,STD,,KING FV-3 DECORATOR STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,FVGI,INSERTS,,GLASS INSERTS FOR KING ONE LITE,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,FVSI,INSERTS,,FULL SCREENS ONLY FOR KING ONE-LITES,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,G3000,GARDEN,,COLUMBIA COMFORT 3000 VINYL GARDEN WD,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,GOLIATH,STD,,GOLIATH STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,HERCULE,STD,,HERCULES STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,IMPERIL,PD,,IMPERIAL PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,INSGLAS,GLASS,,INSULATED GLASS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,ISP,PD,,STATIONARY PANELS FOR IMPERIAL DOORS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,IVP,PD,,VENT PANELS FOR IMPERIAL PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,JET,PD,,COLUMBIA JET PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,JSP,PD,,STATIONARY PANELS FOR JET DOORS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,JVP,PD,,VENT PANELS FOR JET PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,KINGDVI,STD,,KING DUAL VENT STORM DOORS,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,KINGDVL,STD,,KING DUAL VENT STORM DOORS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,KINGFSC,INSERTS,,FULL SCREEN FOR KING ONE-LITE,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,KINGI,STD,,KING ONE-LITE STORM DOORS,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,KINGL,STD,,KING ONE-LITE STORM DOORS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,KINGSDI,STD,,KING ONE-LITE SCREEN DOOR ONLY,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,KINGSDL,STD,,KING ONE-LITE SCREEN DOOR ONLY,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,LINCOLN,3000DHP,#N/A,LINCOLN PRIMARY WOOD WINDOWS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,LINCPDR,PD,,LINCOLN FRENCH PATIO DOOR,Door,Patio Door,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,M1200,PD,,M1200 PATIO STORM DOOR,Door,Patio Door,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,M306,INSERTS,,M-306 SCHLEGEL GLASS INSERTS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,OUTSIDE,STDMISC,,OUTSIDE DOOR SWEEPS - ALUM + VINYL,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,PATIOSC,SCREENS,,PATIO DOOR SCREENS,Door,Patio Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,PDSCRTT,SCREENS,,SPECIAL SIZE SCREENS FOR PATIO DOORS,Door,Patio Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,PRPDS,SCREENS,,SCREENS MADE FROM PLAIN PATIO SCR RAIL,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,PRSCR,PSCREEN,,SCREENS FOR PRIME MADE FROM #19-88,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE, -FALSE,Iola,PRSCR11,PSCREEN,,SCREEN FOR PRIME MADE FROM #19-11,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,PSINS,INSERTS,,PLAIN SASH INSERTS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,PWS,STPW,,PIN-ON PICTURE WINDOWS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE, -FALSE,Iola,PWSINS,INSERTS,,INSERTS ONLY FOR PIN-ON PICTURE WINDOW,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,R1150,REPLACE,,R-1150 VINYL AWNING WINDOWS,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R1400,REPLACE,,SERIES 1400 VINYL SLIDING PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R1500,REPLACE,,SERIES 1500 S.H. TILT VINYL PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R1510,FPPW,,SERIES 1510 FIXED LITE VINYL PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R2000,REPLACE,,SERIES 2000 S.H. T.B. TILT PRIMARY,Window,,Primary Window,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,R2100,REPLACE,,SERIES 2100 THERMAL BREAK SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,R2100EV,R2000SL,,SERIES 2100 3-PANEL T.B. SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,R2200,RFPPW,,SERIES 2200 T.B. FIXED LITE,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,R300,RBSMT,,C-300 ALUM INSERTS FOR BASEMENT BUCKS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R3302,CASEMNT,,3302 2-PANEL T.B. CASEMENT,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,R400,RBSMT,,C-400 VINYL INSERT FOR BASEMENT BUCKS,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R5000,REPLACE,,R-5000 INSULATED ALUMINUM SLIDER,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R770,REPLACE,,R770 D.H. TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,R770SCR,SCREENS,,FULL SCREEN,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R780,REPLACE,,R780 VINYL SLIDING PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R820,REPLACE,,R820 S.H. TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R821,REPLACE,,S821 SINGLE SLIDE VINYL PRIMARY,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R822,FPPW,,S822 FIXED VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R830,REPLACE,,R830 D.H.TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,R832,FPPW,,R832 FIXED VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,RCKTRAP,INSERTS,,ROCKET TRAPEZOIDS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,REWIRE,SCREENS,,REWIRED SCREENS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,RNDROCK,INSERTS,,ROUND ROCKET INSERT,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,ROCKET,INSERTS,,ROCKET INSERTS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -TRUE,Iola,ROYAL,STD,,COLUMBIA ROYAL STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,RROCKET,INSERTS,,RADIUS ROCKETS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -TRUE,Iola,S820,SHPT,,S820 S.H. TILT VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,S821,SHPW,,S821 SINGLE SLIDE VINYL PRIMARY,,,,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,S822,FPPW,,S822 FIXED VINYL PRIMARY WINDOWS,Window,,Primary Window,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,SCRI,INSERTS,,SCREEN INSERTS FOR ECONOMY STORM WDS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,SCRI404,INSERTS,,SCREEN INSERTS FOR #404/450 STORM WDS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,SCRI606,INSERTS,,SCREEN INSERTS FOR #606/650 STORM WDS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,SCRI808,INSERTS,,SCREEN INSERTS FOR #808/850 STORM WIND,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -TRUE,Iola,SS10I,STD,,COBRA SS-10 DECORATOR STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,SS10L,STD,,COBRA SS-10 DECORATOR STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,SS3I,STD,,COBRA SS-3 DECORATOR STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,SS3L,STD,,COBRA SS-3 DECORATOR STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,SSGLASS,GLASS,,SINGLE STRENGTH GLASS,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,SSSCR,INSERTS,,SCREEN INSERT FOR SELF STORING DOORS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,TBGI,INSERTS,,TEMPERED GLASS INSERTS FOR SS DOORS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,TBR,PD,,IMPERIAL T.B.R. REPLACEMENT PATIO DOOR,Door,Patio Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,TGI,INSERTS,,TOP GL INSERTS FOR ECONOMY ST WDS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE,FALSE, -FALSE,Iola,TGI404,INSERTS,,TOP GLASS INSERTS FOR #404/450 ST WDS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,TGI606,INSERTS,,TOP GLASS INSERTS FOR #606/650 ST WDS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE, -FALSE,Iola,TGIODD,INSERTS,,TOP GLASS INSERTS FOR STORM DOORS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,THOR,STD,,THOR - STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,TIARAI,STD,,COLUMBIA TIARA SELF STORING STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,TIARAL,STD,,COLUMBIA TIARA SELF STORING STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -TRUE,Iola,TVGROOV,INSERTS,,TEMPERED V-GROOVE ONE-LITE INSERTS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,TVI,STD,,COLUMBIA COBRA TWIN VENT STORM DOOR,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,TVL,STD,,COLUMBIA COBRA TWIN VENT STORM DOOR,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,VKI,STOCK,,VENTILATOR KICKPANEL FOR KING ONELITE,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -TRUE,Iola,VKS,STOCK,,VENTILATOR SCREEN FOR KING ONE LITE,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,Iola,VP3700,VENTS,,VENT PANELS FOR #3700,,,,FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE, -FALSE,Iola,WINDGAT,VACW,,ALLIANCE WINDGATE CASEMENT WINDOW,,,,FALSE,FALSE,FALSE,TRUE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE, -TRUE,Iola,XBUCKIN,INSERTS,,TEMPERED GLASS INSERTS FOR CROSSBUCKS,,,,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,Iola,ZBARS,STDMISC,,Z-BARS FOR STORM DOORS,,,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,KC,COBRATK,STD,,Cobra aluminum storm door with Glass Kick Panel,Door,Storm Door,,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, -FALSE,~,,,,,,,,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, \ No newline at end of file diff --git a/app/data/users.json b/app/data/users.json index 1a176c8..a35b3c6 100644 --- a/app/data/users.json +++ b/app/data/users.json @@ -4,12 +4,7 @@ "password": "pbkdf2:sha256:1000000$tPRmseRGKLveXTxS$87eda9a20db29d12838fcb607f1f3536141f743ec9879702dc2a0dd893b4078d", "defaultLocation": "KC", "permissions": { - "manage_users": true, - "view_reports": true, - "create_quotes": true, - "approve_quotes": true, - "manage_products": true, - "manage_inventory": true + "manage_users": true }, "locationSettings": { "LINDS": { @@ -25,74 +20,42 @@ "accessible": true } }, - "active": true + "active": true, + "superAdmin": true }, { "username": "Darlene", - "password": "pbkdf2:sha256:1000000$8sblSWLWIvsjcta2$d974d13956f67cc42e1fa88191d68c896d4daa663ae2d76d7988beb569647d27", + "password": "pbkdf2:sha256:1000000$TSAG3KNMWuEQr3Jl$7e8eda7495bc11a43161df75465ce06a53c29f47e766928914dfeb42388a0a5b", "defaultLocation": "IOLA", - "permissions": { - "manage_users": false, - "view_reports": true, - "create_quotes": true, - "approve_quotes": false, - "manage_products": false, - "manage_inventory": false - }, "locationSettings": { "LINDS": { - "accessible": true + "accessible": true, + "permissions": {} }, "IOLA": { - "accessible": true - }, - "KC": { - "accessible": true - }, - "BMD": { - "accessible": false + "accessible": true, + "permissions": {} } }, + "permissions": { + "manage_users": true, + "create_quotes": true + }, "active": true }, { "username": "Toni", - "password": "pbkdf2:sha256:1000000$5k3daJKZt7hqNAkq$e77819a2b2ee4bf9955dc10b3b4da7b14de2b4ecda5ce5f553daf3783b0a316c", + "password": "pbkdf2:sha256:1000000$kf8fP8xO1ghC5Fig$e3b4155b7922a651e0680e73c984a48c7d4de2b02a43254d9080498c1071baca", "defaultLocation": "LINDS", "locationSettings": { "LINDS": { - "accessible": true - }, - "IOLA": { - "accessible": false - }, - "KC": { - "accessible": false - }, - "BMD": { - "accessible": false + "accessible": true, + "permissions": {} } }, + "permissions": { + "create_quotes": true + }, "active": true - }, - { - "username": "Jason", - "password": "pbkdf2:sha256:1000000$rNSYLqRWZ6tdny1G$cad2afda9193b7cb50b9e9423f95ff83bc14428c8a2d98607cd6e5ce17cb70c7", - "defaultLocation": "KC", - "locationSettings": { - "LINDS": { - "accessible": true - }, - "IOLA": { - "accessible": true - }, - "KC": { - "accessible": true - }, - "BMD": { - "accessible": true - } - }, - "active": false } ] \ No newline at end of file diff --git a/app/debug_startup.py b/app/debug_startup.py deleted file mode 100644 index d814c1e..0000000 --- a/app/debug_startup.py +++ /dev/null @@ -1,111 +0,0 @@ -""" -Debug startup script - writes detailed logs to file -Upload this and temporarily set it as the startup file to diagnose issues -""" -import sys -import os -from datetime import datetime - -# Create log file -log_file = '/home/bmdwtjuw/product-finder/startup_debug.log' - -def log(message): - with open(log_file, 'a') as f: - timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - f.write(f"[{timestamp}] {message}\n") - -try: - log("="*70) - log("STARTUP DEBUG - BEGIN") - log("="*70) - - # Python info - log(f"Python version: {sys.version}") - log(f"Python executable: {sys.executable}") - log(f"Current directory: {os.getcwd()}") - - # Environment variables - log("\nEnvironment Variables:") - log(f" APPLICATION_ROOT: {os.environ.get('APPLICATION_ROOT', 'NOT SET')}") - log(f" FLASK_ENV: {os.environ.get('FLASK_ENV', 'NOT SET')}") - - # Python path - log(f"\nPython path: {sys.path}") - - # Check Flask installation - log("\nChecking Flask installation...") - try: - import flask - log(f" āœ“ Flask version: {flask.__version__ if hasattr(flask, '__version__') else 'unknown'}") - except ImportError as e: - log(f" āœ— Flask NOT installed: {e}") - log(" RUN: pip install Flask==3.0.0 Werkzeug==3.0.1") - - # Check Werkzeug - try: - import werkzeug - log(f" āœ“ Werkzeug version: {werkzeug.__version__ if hasattr(werkzeug, '__version__') else 'unknown'}") - except ImportError as e: - log(f" āœ— Werkzeug NOT installed: {e}") - - # Check if app.py exists - log("\nChecking files...") - app_py_path = os.path.join(os.path.dirname(__file__), 'app.py') - if os.path.exists(app_py_path): - log(f" āœ“ app.py exists at {app_py_path}") - else: - log(f" āœ— app.py NOT FOUND at {app_py_path}") - - # Try importing app - log("\nAttempting to import Flask app...") - try: - from app import app - log(f" āœ“ Successfully imported Flask app") - log(f" APPLICATION_ROOT config: {app.config.get('APPLICATION_ROOT', 'NOT SET')}") - - # Count routes - routes = list(app.url_map.iter_rules()) - log(f" āœ“ Registered routes: {len(routes)}") - - # Create WSGI application - def application(environ, start_response): - log(f"\nRequest received: {environ.get('PATH_INFO', '/')}") - return app(environ, start_response) - - log("\nāœ“ APPLICATION READY - Check site now") - log("="*70) - - except Exception as e: - log(f" āœ— Failed to import app:") - log(f" Error: {e}") - - import traceback - log(f"\nFull traceback:") - log(traceback.format_exc()) - - # Create error application - def application(environ, start_response): - status = '500 Internal Server Error' - output = f'Import Error - Check {log_file}\n\n{traceback.format_exc()}'.encode('utf-8') - response_headers = [('Content-type', 'text/plain'), - ('Content-Length', str(len(output)))] - start_response(status, response_headers) - return [output] - - log("="*70) - -except Exception as e: - # Catch-all for any errors - import traceback - log(f"\nFATAL ERROR during startup:") - log(str(e)) - log(traceback.format_exc()) - log("="*70) - - def application(environ, start_response): - status = '500 Internal Server Error' - output = f'Startup Error - Check {log_file}'.encode('utf-8') - response_headers = [('Content-type', 'text/plain'), - ('Content-Length', str(len(output)))] - start_response(status, response_headers) - return [output] diff --git a/app/fix_passenger_file.py b/app/fix_passenger_file.py deleted file mode 100644 index 2f1883c..0000000 --- a/app/fix_passenger_file.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python3 -""" -Fix Passenger Configuration -============================ -This script renames the corrupted passenger_wsgi.py file so Passenger -will use the control panel settings instead. -""" -import os -import sys - -def main(): - print("=" * 70) - print("FIXING PASSENGER CONFIGURATION") - print("=" * 70) - - # Check if passenger_wsgi.py exists - if os.path.exists('passenger_wsgi.py'): - print("\nFound passenger_wsgi.py - this file is causing the problem") - print("Renaming it to passenger_wsgi.py.DISABLED...") - - try: - os.rename('passenger_wsgi.py', 'passenger_wsgi.py.DISABLED') - print("SUCCESS: passenger_wsgi.py renamed to passenger_wsgi.py.DISABLED") - print("\nPassenger will now use the control panel settings:") - print(" Application startup file: wsgi.py") - print(" Application Entry point: app") - except Exception as e: - print(f"ERROR: Could not rename file: {e}") - return 1 - else: - print("\npassenger_wsgi.py not found - already fixed or doesn't exist") - - print("\n" + "=" * 70) - print("NEXT STEPS:") - print("=" * 70) - print("1. Restart your Python application in the control panel") - print("2. Visit: https://columbiawindows.com/product-finder/test") - print("3. If it works, you're done!") - print("=" * 70) - - return 0 - -if __name__ == '__main__': - sys.exit(main()) diff --git a/app/fix_passenger_lock.sh b/app/fix_passenger_lock.sh deleted file mode 100644 index 60813da..0000000 --- a/app/fix_passenger_lock.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -# Fix Passenger lock file permissions -# Run this on the server to resolve "Can't acquire lock" error - -echo "==========================================" -echo "FIXING PASSENGER LOCK FILE ISSUES" -echo "==========================================" -echo "" - -# Navigate to app directory -cd ~/product-finder - -# Remove any stale lock files -echo "🧹 Cleaning stale lock files..." -if [ -d "tmp" ]; then - rm -rf tmp/* - echo " āœ“ tmp directory cleaned" -else - echo " āš ļø tmp directory doesn't exist - will create it" -fi - -# Create tmp directory with correct permissions -echo "" -echo "šŸ“ Setting up tmp directory..." -mkdir -p tmp -chmod 755 tmp -echo " āœ“ tmp directory created with 755 permissions" - -# Create restart file -echo "" -echo "šŸ”„ Restarting Passenger..." -touch tmp/restart.txt -chmod 644 tmp/restart.txt -echo " āœ“ tmp/restart.txt created" - -# Set correct permissions for app files -echo "" -echo "šŸ”’ Setting file permissions..." -chmod 755 . -chmod 644 passenger_wsgi.py -chmod 644 app.py -chmod 644 .htaccess -chmod -R 755 data 2>/dev/null || mkdir -p data && chmod 755 data -chmod -R 755 templates -chmod -R 755 static 2>/dev/null || true -echo " āœ“ File permissions set" - -# Show current tmp directory status -echo "" -echo "šŸ“Š Current tmp directory status:" -ls -la tmp/ -echo "" - -echo "==========================================" -echo "āœ“ LOCK FILE ISSUE FIXED" -echo "==========================================" -echo "" -echo "Next steps:" -echo "1. Wait 30 seconds for Passenger to restart" -echo "2. Test: https://columbiawindows.com/product-finder/" -echo "" -echo "If still failing, check error log:" -echo "tail -50 ~/logs/error_log" -echo "" diff --git a/app/generate_bitwise_helper.py b/app/generate_bitwise_helper.py deleted file mode 100644 index 015728b..0000000 --- a/app/generate_bitwise_helper.py +++ /dev/null @@ -1,295 +0,0 @@ -""" -Generate Bitwise Helper File for Product Classification -Creates a helper file with bitwise flags based on product attributes (columns G-S) -""" - -import csv -import json -from collections import defaultdict - -# Bit position definitions -BIT_DEFINITIONS = { - # Base Type (Bits 0-1) - 'base_door': 0, # 2^0 = 1 - 'base_window': 1, # 2^1 = 2 - - # Product Flags (Bits 2-3) - 'is_accessory': 2, # 2^2 = 4 - 'specific_item': 3, # 2^3 = 8 - - # Materials (Bits 4-5) - 'material_aluminum': 4, # 2^4 = 16 - 'material_vinyl': 5, # 2^5 = 32 - - # Colors (Bits 6-11) - 'color_black': 6, # 2^6 = 64 - 'color_white': 7, # 2^7 = 128 - 'color_bronze': 8, # 2^8 = 256 - 'color_tan': 9, # 2^9 = 512 - 'color_mill': 10, # 2^10 = 1024 - 'color_sandstone': 11, # 2^11 = 2048 -} - -# Sub-type bits will be assigned dynamically (starting at bit 12) -SUBTYPE_BIT_START = 12 - -def parse_bool(value): - """Parse TRUE/FALSE string to boolean""" - if isinstance(value, str): - return value.strip().upper() == 'TRUE' - return bool(value) - -def calculate_bit_value(row, subtype_map): - """Calculate the bitwise value for a product row""" - bit_value = 0 - explanation = [] - - # Base Type (Column G - index 6) - base_type = row[6].strip() if len(row) > 6 and row[6] else "" - if base_type.lower() == 'door': - bit_value |= (1 << BIT_DEFINITIONS['base_door']) - explanation.append('Door') - elif base_type.lower() == 'window': - bit_value |= (1 << BIT_DEFINITIONS['base_window']) - explanation.append('Window') - - # Accessory Flag (Column J - index 9) - if len(row) > 9 and parse_bool(row[9]): - bit_value |= (1 << BIT_DEFINITIONS['is_accessory']) - explanation.append('Accessory') - - # Specific Item Link (Column K - index 10) - if len(row) > 10 and parse_bool(row[10]): - bit_value |= (1 << BIT_DEFINITIONS['specific_item']) - explanation.append('SpecificItem') - - # Materials - if len(row) > 11 and parse_bool(row[11]): # Aluminum (Column L) - bit_value |= (1 << BIT_DEFINITIONS['material_aluminum']) - explanation.append('Aluminum') - - if len(row) > 12 and parse_bool(row[12]): # Vinyl (Column M) - bit_value |= (1 << BIT_DEFINITIONS['material_vinyl']) - explanation.append('Vinyl') - - # Colors - color_columns = [ - (13, 'color_black', 'Black'), - (14, 'color_white', 'White'), - (15, 'color_bronze', 'Bronze'), - (16, 'color_tan', 'Tan'), - (17, 'color_mill', 'Mill'), - (18, 'color_sandstone', 'Sandstone'), - ] - - for col_idx, bit_key, color_name in color_columns: - if len(row) > col_idx and parse_bool(row[col_idx]): - bit_value |= (1 << BIT_DEFINITIONS[bit_key]) - explanation.append(color_name) - - # Sub-types (Columns H and I - indices 7 and 8) - door_subtype = row[7].strip() if len(row) > 7 and row[7] else "" - window_subtype = row[8].strip() if len(row) > 8 and row[8] else "" - - if door_subtype and door_subtype in subtype_map: - bit_pos = subtype_map[door_subtype] - bit_value |= (1 << bit_pos) - explanation.append(f'Subtype:{door_subtype}') - - if window_subtype and window_subtype in subtype_map: - bit_pos = subtype_map[window_subtype] - bit_value |= (1 << bit_pos) - explanation.append(f'Subtype:{window_subtype}') - - return bit_value, explanation - -def collect_subtypes(csv_path): - """Collect all unique sub-types from the CSV""" - subtypes = set() - - with open(csv_path, 'r', encoding='utf-8') as f: - reader = csv.reader(f) - next(reader) # Skip first header row - next(reader) # Skip second header row - - for row in reader: - if len(row) < 8: - continue - - # Skip discontinued items - if len(row) > 0 and parse_bool(row[0]): - continue - - # Collect door subtype (column H - index 7) - if len(row) > 7 and row[7].strip(): - subtypes.add(row[7].strip()) - - # Collect window subtype (column I - index 8) - if len(row) > 8 and row[8].strip(): - subtypes.add(row[8].strip()) - - return sorted(subtypes) - -def generate_helper_files(csv_path): - """Generate helper CSV and JSON files with bitwise values""" - - print("Analyzing product data...") - - # First pass: collect all unique sub-types - subtypes = collect_subtypes(csv_path) - - # Create subtype bit mapping - subtype_map = {} - for idx, subtype in enumerate(subtypes): - subtype_map[subtype] = SUBTYPE_BIT_START + idx - - print(f"Found {len(subtypes)} unique sub-types") - - # Second pass: calculate bit values - results = [] - - with open(csv_path, 'r', encoding='utf-8') as f: - reader = csv.reader(f) - next(reader) # Skip first header row - next(reader) # Skip second header row - - for row in reader: - if len(row) < 3: - continue - - prod_code = row[2].strip() # Column C - PROD_CODE - discontinued = parse_bool(row[0]) # Column A - DISCONT - - bit_value, explanation = calculate_bit_value(row, subtype_map) - - results.append({ - 'PROD_CODE': prod_code, - 'BIT_VALUE': bit_value, - 'BIT_HEX': f"0x{bit_value:X}", - 'BIT_BINARY': f"{bit_value:b}", - 'DISCONTINUED': discontinued, - 'FLAGS': ' | '.join(explanation) if explanation else 'None' - }) - - # Filter out discontinued products for output files - active_results = [r for r in results if not r['DISCONTINUED']] - - print(f"Total products processed: {len(results)}") - print(f"Active products: {len(active_results)}") - print(f"Discontinued products (filtered out): {len(results) - len(active_results)}") - - # Write CSV helper file (only active products) - csv_output = 'data/product_bitwise.csv' - with open(csv_output, 'w', newline='', encoding='utf-8') as f: - writer = csv.DictWriter(f, fieldnames=['PROD_CODE', 'BIT_VALUE', 'BIT_HEX', 'BIT_BINARY', 'DISCONTINUED', 'FLAGS']) - writer.writeheader() - writer.writerows(active_results) - - print(f"āœ“ Created {csv_output}") - - # Write JSON helper file (only active products) - json_output = 'data/product_bitwise.json' - with open(json_output, 'w', encoding='utf-8') as f: - json.dump(active_results, f, indent=2) - - print(f"āœ“ Created {json_output}") - - # Create bit legend/documentation - legend = { - 'description': 'Bitwise flag system for product classification', - 'bit_definitions': { - 'base_attributes': { - 'bit_0 (1)': 'Base Type = Door', - 'bit_1 (2)': 'Base Type = Window', - 'bit_2 (4)': 'Is Accessory', - 'bit_3 (8)': 'Specific Item Link', - }, - 'materials': { - 'bit_4 (16)': 'Material = Aluminum', - 'bit_5 (32)': 'Material = Vinyl', - }, - 'colors': { - 'bit_6 (64)': 'Color = Black', - 'bit_7 (128)': 'Color = White', - 'bit_8 (256)': 'Color = Bronze', - 'bit_9 (512)': 'Color = Tan', - 'bit_10 (1024)': 'Color = Mill', - 'bit_11 (2048)': 'Color = Sandstone', - }, - 'subtypes': {} - }, - 'usage_examples': { - 'check_if_door': 'bit_value & 1', - 'check_if_window': 'bit_value & 2', - 'check_if_aluminum': 'bit_value & 16', - 'check_if_white': 'bit_value & 128', - 'check_multiple': '(bit_value & 1) and (bit_value & 16) # Door AND Aluminum', - } - } - - # Add subtype mappings to legend - for subtype, bit_pos in sorted(subtype_map.items(), key=lambda x: x[1]): - bit_value = 1 << bit_pos - legend['bit_definitions']['subtypes'][f'bit_{bit_pos} ({bit_value})'] = f'Subtype = {subtype}' - legend['usage_examples'][f'check_subtype_{subtype.replace(" ", "_").lower()}'] = f'bit_value & {bit_value}' - - # Write legend file - legend_output = 'data/bitwise_legend.json' - with open(legend_output, 'w', encoding='utf-8') as f: - json.dump(legend, f, indent=2) - - print(f"āœ“ Created {legend_output}") - - # Generate statistics - stats = { - 'total_products': len([r for r in results if not r['DISCONTINUED']]), - 'total_discontinued': len([r for r in results if r['DISCONTINUED']]), - 'total_accessories': len([r for r in results if not r['DISCONTINUED'] and (r['BIT_VALUE'] & 4)]), - 'doors': len([r for r in results if not r['DISCONTINUED'] and (r['BIT_VALUE'] & 1)]), - 'windows': len([r for r in results if not r['DISCONTINUED'] and (r['BIT_VALUE'] & 2)]), - 'aluminum_products': len([r for r in results if not r['DISCONTINUED'] and (r['BIT_VALUE'] & 16)]), - 'vinyl_products': len([r for r in results if not r['DISCONTINUED'] and (r['BIT_VALUE'] & 32)]), - 'multi_material': len([r for r in results if not r['DISCONTINUED'] and (r['BIT_VALUE'] & 16) and (r['BIT_VALUE'] & 32)]), - } - - print("\n" + "="*60) - print("STATISTICS") - print("="*60) - print(f"Total Active Products: {stats['total_products']}") - print(f"Total Discontinued: {stats['total_discontinued']}") - print(f"Accessories: {stats['total_accessories']}") - print(f"Doors: {stats['doors']}") - print(f"Windows: {stats['windows']}") - print(f"Aluminum Products: {stats['aluminum_products']}") - print(f"Vinyl Products: {stats['vinyl_products']}") - print(f"Multi-Material Products: {stats['multi_material']}") - print(f"Unique Sub-types: {len(subtypes)}") - print("="*60) - - # Show example products - print("\nEXAMPLE PRODUCTS:") - print("-"*60) - for i, result in enumerate(active_results[:5]): - print(f"{result['PROD_CODE']:12} | {result['BIT_VALUE']:6} | {result['BIT_HEX']:8} | {result['FLAGS']}") - print("-"*60) - - return active_results, legend, subtype_map - -if __name__ == '__main__': - csv_path = 'data/products.csv' - - try: - results, legend, subtype_map = generate_helper_files(csv_path) - print("\nāœ“ All helper files generated successfully!") - print("\nGenerated files:") - print(" - data/product_bitwise.csv (CSV format with bit values)") - print(" - data/product_bitwise.json (JSON format with bit values)") - print(" - data/bitwise_legend.json (Bit mapping documentation)") - - except FileNotFoundError: - print(f"Error: Could not find {csv_path}") - print("Make sure products.csv exists in the data/ folder") - except Exception as e: - print(f"Error: {e}") - import traceback - traceback.print_exc() diff --git a/app/image_generator.py b/app/image_generator.py deleted file mode 100644 index 82bdb3e..0000000 --- a/app/image_generator.py +++ /dev/null @@ -1,297 +0,0 @@ -""" -Dynamic Product Image Generator -Generates product images with configurable colors, hardware positions, and other options. -Uses PIL/Pillow for image manipulation. -""" - -import os -import json -import hashlib -from io import BytesIO -from PIL import Image, ImageDraw, ImageEnhance, ImageColor -from pathlib import Path - - -class ProductImageGenerator: - """Handles dynamic generation of product images based on configuration.""" - - def __init__(self, config_file='data/image_configs.json'): - """Initialize with configuration file.""" - self.config_file = config_file - self.configs = self._load_configs() - self.cache_dir = Path('cache/product_images') - self.cache_dir.mkdir(parents=True, exist_ok=True) - - def _load_configs(self): - """Load image configuration from JSON file.""" - try: - with open(self.config_file, 'r') as f: - return json.load(f) - except Exception as e: - print(f"Error loading image configs: {e}") - return {} - - def _find_image(self, image_path): - """ - Find image file, trying different extensions if needed. - - Args: - image_path: Path to image (e.g., 'images/cobrai.jpg') - - Returns: - Actual path to image file, or None if not found - """ - # Try the exact path first - if os.path.exists(image_path): - return image_path - - # Get base path without extension - base_path = os.path.splitext(image_path)[0] - - # Try common image extensions - for ext in ['.png', '.jpg', '.jpeg', '.PNG', '.JPG', '.JPEG']: - test_path = base_path + ext - if os.path.exists(test_path): - return test_path - - return None - - def generate_product_image(self, product_code, color='white', hinge='right', - material='aluminum', use_cache=True): - """ - Generate a product image with specified configuration. - - Args: - product_code: Product identifier (e.g., 'cobrai') - color: Color name (e.g., 'white', 'black', 'bronze') - hinge: Hinge side ('right' or 'left') - material: Material type (for future use) - use_cache: Whether to use cached images - - Returns: - PIL Image object - """ - product_code = product_code.lower() - - # Check if product config exists - if product_code not in self.configs: - raise ValueError(f"Product {product_code} not found in configuration") - - config = self.configs[product_code] - - # Check cache first - if use_cache: - cache_key = self._get_cache_key(product_code, color, hinge, material) - cached_image = self._get_cached_image(cache_key) - if cached_image: - return cached_image - - # Load base image - base_image_path = config['sourceImage'] - - # Try to find the image with different extensions if needed - image_path = self._find_image(base_image_path) - - if not image_path: - raise FileNotFoundError(f"Could not load base image: {base_image_path}. Tried .jpg, .png, .jpeg") - - try: - base_image = Image.open(image_path).convert('RGBA') - except Exception as e: - raise FileNotFoundError(f"Could not load base image: {image_path}. Error: {e}") - - # Apply color to regions - if color in config['availableColors']: - color_rgb = tuple(config['availableColors'][color]['rgb']) - base_image = self._apply_color_to_regions( - base_image, - config['colorableRegions'], - color_rgb - ) - - # Apply hardware (handles, locks) - if hinge in config.get('hardwarePositions', {}): - base_image = self._apply_hardware( - base_image, - config['hardwarePositions'], - hinge - ) - - # Flip image if left hinge - if hinge == 'left': - base_image = base_image.transpose(Image.FLIP_LEFT_RIGHT) - - # Cache the result - if use_cache: - self._cache_image(cache_key, base_image) - - return base_image - - def _apply_color_to_regions(self, image, regions, target_color): - """ - Apply color to specific regions of the image. - - This method attempts to recolor the frame/panel areas while preserving - shadows, highlights, and texture. - """ - img_copy = image.copy() - pixels = img_copy.load() - width, height = img_copy.size - - # Get the average brightness of the target color - target_brightness = sum(target_color) / 3 - - for region in regions: - x1, y1 = region['topLeft'] - x2, y2 = region['bottomRight'] - - # Ensure coordinates are within bounds - x1 = max(0, min(x1, width - 1)) - x2 = max(0, min(x2, width)) - y1 = max(0, min(y1, height - 1)) - y2 = max(0, min(y2, height)) - - # Apply color to region while preserving luminosity - for y in range(y1, y2): - for x in range(x1, x2): - try: - r, g, b, a = pixels[x, y] - - # Calculate original brightness - original_brightness = (r + g + b) / 3 - - # Preserve relative brightness - if original_brightness > 0: - brightness_factor = original_brightness / 255.0 - - # Apply target color with brightness preservation - new_r = int(target_color[0] * brightness_factor) - new_g = int(target_color[1] * brightness_factor) - new_b = int(target_color[2] * brightness_factor) - - # Ensure values are in valid range - new_r = max(0, min(255, new_r)) - new_g = max(0, min(255, new_g)) - new_b = max(0, min(255, new_b)) - - pixels[x, y] = (new_r, new_g, new_b, a) - except IndexError: - continue - - return img_copy - - def _apply_hardware(self, image, hardware_positions, hinge_side): - """Apply hardware (handles, locks) to the image.""" - img_copy = image.copy() - - hardware_key = f"handle_{hinge_side}" - if hardware_key in hardware_positions: - hardware_config = hardware_positions[hardware_key] - hardware_path = hardware_config.get('image') - - if hardware_path: - # Try to find the hardware image with different extensions - actual_path = self._find_image(hardware_path) - - if actual_path: - try: - hardware_img = Image.open(actual_path).convert('RGBA') - - # Flip if needed - if hardware_config.get('flip', False): - hardware_img = hardware_img.transpose(Image.FLIP_LEFT_RIGHT) - - # Paste hardware at specified position - x, y = hardware_config['x'], hardware_config['y'] - img_copy.paste(hardware_img, (x, y), hardware_img) - except Exception as e: - print(f"Could not apply hardware: {e}") - - return img_copy - - def _get_cache_key(self, product_code, color, hinge, material): - """Generate a unique cache key for the configuration.""" - key_string = f"{product_code}_{color}_{hinge}_{material}" - return hashlib.md5(key_string.encode()).hexdigest() - - def _get_cached_image(self, cache_key): - """Retrieve cached image if available.""" - cache_path = self.cache_dir / f"{cache_key}.png" - if cache_path.exists(): - try: - return Image.open(cache_path) - except Exception: - return None - return None - - def _cache_image(self, cache_key, image): - """Save image to cache.""" - cache_path = self.cache_dir / f"{cache_key}.png" - try: - image.save(cache_path, 'PNG', optimize=True) - except Exception as e: - print(f"Could not cache image: {e}") - - def get_product_config(self, product_code): - """Get configuration for a specific product.""" - return self.configs.get(product_code.lower()) - - def clear_cache(self, product_code=None): - """Clear cached images. If product_code provided, only clear that product's cache.""" - if product_code: - # Clear specific product cache (would need to track cache keys) - pass - else: - # Clear all cache - for cache_file in self.cache_dir.glob('*.png'): - try: - cache_file.unlink() - except Exception: - pass - - -def recolor_image_advanced(image, source_color_range, target_color): - """ - Advanced recoloring that replaces pixels within a color range. - - Args: - image: PIL Image - source_color_range: Dict with 'min' and 'max' RGB tuples - target_color: Target RGB tuple - """ - img_copy = image.copy() - pixels = img_copy.load() - width, height = img_copy.size - - min_r, min_g, min_b = source_color_range['min'] - max_r, max_g, max_b = source_color_range['max'] - - for y in range(height): - for x in range(width): - r, g, b, a = pixels[x, y] - - # Check if pixel is within source color range - if (min_r <= r <= max_r and - min_g <= g <= max_g and - min_b <= b <= max_b): - - # Calculate brightness factor - brightness = (r + g + b) / 3 / 255.0 - - # Apply target color with brightness - new_r = int(target_color[0] * brightness) - new_g = int(target_color[1] * brightness) - new_b = int(target_color[2] * brightness) - - pixels[x, y] = (new_r, new_g, new_b, a) - - return img_copy - - -def image_to_base64(image, format='PNG'): - """Convert PIL Image to base64 string.""" - import base64 - buffered = BytesIO() - image.save(buffered, format=format) - img_str = base64.b64encode(buffered.getvalue()).decode() - return f"data:image/{format.lower()};base64,{img_str}" diff --git a/app/images/cobrai-black-black.png b/app/images/cobrai-black-black.png deleted file mode 100644 index 9f99647..0000000 Binary files a/app/images/cobrai-black-black.png and /dev/null differ diff --git a/app/images/cobrai-bronze-bronze.png b/app/images/cobrai-bronze-bronze.png deleted file mode 100644 index e3f6456..0000000 Binary files a/app/images/cobrai-bronze-bronze.png and /dev/null differ diff --git a/app/images/cobrai-sandstone-bronze.png b/app/images/cobrai-sandstone-bronze.png deleted file mode 100644 index 2dd970a..0000000 Binary files a/app/images/cobrai-sandstone-bronze.png and /dev/null differ diff --git a/app/images/cobrai-white-white.png b/app/images/cobrai-white-white.png deleted file mode 100644 index 9be2626..0000000 Binary files a/app/images/cobrai-white-white.png and /dev/null differ diff --git a/app/images/storm-door-background.png b/app/images/storm-door-background.png deleted file mode 100644 index 7b03e3d..0000000 Binary files a/app/images/storm-door-background.png and /dev/null differ diff --git a/app/js/encoding_helper.js b/app/js/encoding_helper.js deleted file mode 100644 index bcb93ed..0000000 --- a/app/js/encoding_helper.js +++ /dev/null @@ -1,451 +0,0 @@ -/** - * Product Encoding/Decoding Helper - * - * Provides functions to encode and decode product configurations into compact - * hex-based URL strings. Uses bit-packing for efficient, stable encoding. - * - * Format: v-T-C-M-HHHH-HHHH-HHHH - * See /planning/ENCODING_SYSTEM.md for detailed documentation - */ - -// ============================================================================ -// LOOKUP TABLES -// ============================================================================ - -const ENCODING_VERSION = 0; - -// Main Product Attributes (single hex character, 0-15) -const PRODUCT_TYPE = { - 'PATIO_DOOR': 1, - 'STORM_DOOR': 3, - 'STORM_WINDOW': 5, - 'PRIMARY_WINDOW': 7 -}; - -const PRODUCT_TYPE_REVERSE = { - 1: 'PATIO_DOOR', - 3: 'STORM_DOOR', - 5: 'STORM_WINDOW', - 7: 'PRIMARY_WINDOW' -}; - -const PRODUCT_COLOR = { - 'BLACK': 1, - 'BRONZE': 2, - 'SANDSTONE': 3, - 'WHITE': 4, - 'TAN': 5, - 'MILL': 6 -}; - -const PRODUCT_COLOR_REVERSE = { - 1: 'BLACK', - 2: 'BRONZE', - 3: 'SANDSTONE', - 4: 'WHITE', - 5: 'TAN', - 6: 'MILL' -}; - -const PRODUCT_MATERIAL = { - 'ALUMINUM': 1, - 'VINYL': 2 -}; - -const PRODUCT_MATERIAL_REVERSE = { - 1: 'ALUMINUM', - 2: 'VINYL' -}; - -// Hardware Fields (5 bits each, 0-31) -const HARDWARE_TYPE = { - 'NONE': 0, - 'LEVER': 1, - 'PULL': 2, - 'PULL_HANDLE': 3, - 'DEADBOLT': 4, - 'HINGE': 5 -}; - -const HARDWARE_TYPE_REVERSE = { - 0: 'NONE', - 1: 'LEVER', - 2: 'PULL', - 3: 'PULL_HANDLE', - 4: 'DEADBOLT', - 5: 'HINGE' -}; - -const HARDWARE_STYLE = { - 'NONE': 0, - 'STANDARD': 1, - 'PUSH': 2, - 'ALTERNATIVE': 3, - 'CONTEMPORARY': 4, - 'TRADITIONAL': 5 -}; - -const HARDWARE_STYLE_REVERSE = { - 0: 'NONE', - 1: 'STANDARD', - 2: 'PUSH', - 3: 'ALTERNATIVE', - 4: 'CONTEMPORARY', - 5: 'TRADITIONAL' -}; - -const HARDWARE_COLOR = { - 'NONE': 0, - 'BRASS': 1, - 'WHITE': 2, - 'BLACK': 3, - 'SATIN': 4, - 'NICKEL': 5, - 'BRONZE': 6 -}; - -const HARDWARE_COLOR_REVERSE = { - 0: 'NONE', - 1: 'BRASS', - 2: 'WHITE', - 3: 'BLACK', - 4: 'SATIN', - 5: 'NICKEL', - 6: 'BRONZE' -}; - -// ============================================================================ -// ENCODING FUNCTIONS -// ============================================================================ - -/** - * Encode a hardware configuration into a 4-character hex string - * Uses 5 bits per field (32 values each) - * - * @param {number} type - Hardware type (0-31) - * @param {number} style - Hardware style (0-31) - * @param {number} color - Hardware color (0-31) - * @returns {string} 4-character hex string (e.g., "0421") - */ -function encodeHardware(type, style, color) { - // Validate inputs - if (type < 0 || type > 31) throw new Error(`Invalid hardware type: ${type} (must be 0-31)`); - if (style < 0 || style > 31) throw new Error(`Invalid hardware style: ${style} (must be 0-31)`); - if (color < 0 || color > 31) throw new Error(`Invalid hardware color: ${color} (must be 0-31)`); - - // Pack into 16 bits: [reserved(1)][type(5)][style(5)][color(5)] - const value = ((type & 0x1F) << 10) | // Bits 10-14 - ((style & 0x1F) << 5) | // Bits 5-9 - (color & 0x1F); // Bits 0-4 - - return value.toString(16).toUpperCase().padStart(4, '0'); -} - -/** - * Encode a complete product configuration into a URL string - * - * @param {Object} config - Product configuration - * @param {number} config.type - Product type (0-15) - * @param {number} config.color - Product color (0-15) - * @param {number} config.material - Product material (0-15) - * @param {Array} config.hardware - Array of hardware items (optional) - * @param {number} config.hardware[].type - Hardware type (0-31) - * @param {number} config.hardware[].style - Hardware style (0-31) - * @param {number} config.hardware[].color - Hardware color (0-31) - * @returns {string} Encoded URL string (e.g., "0-1-4-1-0421") - */ -function encodeProduct(config) { - // Validate main attributes - if (config.type < 0 || config.type > 15) { - throw new Error(`Invalid product type: ${config.type} (must be 0-15)`); - } - if (config.color < 0 || config.color > 15) { - throw new Error(`Invalid product color: ${config.color} (must be 0-15)`); - } - if (config.material < 0 || config.material > 15) { - throw new Error(`Invalid product material: ${config.material} (must be 0-15)`); - } - - // Build base string: version-type-color-material - const parts = [ - ENCODING_VERSION.toString(16).toUpperCase(), - config.type.toString(16).toUpperCase(), - config.color.toString(16).toUpperCase(), - config.material.toString(16).toUpperCase() - ]; - - // Add hardware items if present - if (config.hardware && config.hardware.length > 0) { - config.hardware.forEach(hw => { - parts.push(encodeHardware(hw.type, hw.style, hw.color)); - }); - } - - return parts.join('-'); -} - -/** - * Encode using named constants (convenience function) - * - * @param {Object} config - Product configuration with named values - * @param {string} config.type - Product type name (e.g., 'PATIO_DOOR') - * @param {string} config.color - Color name (e.g., 'WHITE') - * @param {string} config.material - Material name (e.g., 'ALUMINUM') - * @param {Array} config.hardware - Array of hardware items (optional) - * @returns {string} Encoded URL string - */ -function encodeProductByName(config) { - const numericConfig = { - type: PRODUCT_TYPE[config.type], - color: PRODUCT_COLOR[config.color], - material: PRODUCT_MATERIAL[config.material], - hardware: [] - }; - - if (config.hardware && config.hardware.length > 0) { - numericConfig.hardware = config.hardware.map(hw => ({ - type: HARDWARE_TYPE[hw.type], - style: HARDWARE_STYLE[hw.style], - color: HARDWARE_COLOR[hw.color] - })); - } - - return encodeProduct(numericConfig); -} - -// ============================================================================ -// DECODING FUNCTIONS -// ============================================================================ - -/** - * Decode a hardware hex string back to its components - * - * @param {string} hex - 4-character hex string (e.g., "0421") - * @returns {Object} Decoded hardware configuration - */ -function decodeHardware(hex) { - if (typeof hex !== 'string' || hex.length !== 4) { - throw new Error(`Invalid hardware hex string: ${hex} (must be 4 characters)`); - } - - const value = parseInt(hex, 16); - - if (isNaN(value)) { - throw new Error(`Invalid hex value: ${hex}`); - } - - return { - type: (value >> 10) & 0x1F, // Extract bits 10-14 - style: (value >> 5) & 0x1F, // Extract bits 5-9 - color: value & 0x1F // Extract bits 0-4 - }; -} - -/** - * Decode a complete product URL string - * - * @param {string} encodedString - Encoded URL string (e.g., "0-1-4-1-0421") - * @returns {Object} Decoded product configuration - */ -function decodeProduct(encodedString) { - if (typeof encodedString !== 'string') { - throw new Error('Invalid encoded string: must be a string'); - } - - const parts = encodedString.split('-'); - - if (parts.length < 4) { - throw new Error(`Invalid encoded string: ${encodedString} (must have at least 4 parts)`); - } - - // Parse version - const version = parseInt(parts[0], 16); - if (version !== ENCODING_VERSION) { - throw new Error(`Unsupported encoding version: ${version} (current: ${ENCODING_VERSION})`); - } - - // Parse main attributes - const config = { - version: version, - type: parseInt(parts[1], 16), - color: parseInt(parts[2], 16), - material: parseInt(parts[3], 16), - hardware: [] - }; - - // Parse hardware items (if present) - for (let i = 4; i < parts.length; i++) { - config.hardware.push(decodeHardware(parts[i])); - } - - return config; -} - -/** - * Decode and return named values (convenience function) - * - * @param {string} encodedString - Encoded URL string - * @returns {Object} Decoded product with named values - */ -function decodeProductToNames(encodedString) { - const numeric = decodeProduct(encodedString); - - return { - version: numeric.version, - type: PRODUCT_TYPE_REVERSE[numeric.type] || `UNKNOWN_${numeric.type}`, - color: PRODUCT_COLOR_REVERSE[numeric.color] || `UNKNOWN_${numeric.color}`, - material: PRODUCT_MATERIAL_REVERSE[numeric.material] || `UNKNOWN_${numeric.material}`, - hardware: numeric.hardware.map(hw => ({ - type: HARDWARE_TYPE_REVERSE[hw.type] || `UNKNOWN_${hw.type}`, - style: HARDWARE_STYLE_REVERSE[hw.style] || `UNKNOWN_${hw.style}`, - color: HARDWARE_COLOR_REVERSE[hw.color] || `UNKNOWN_${hw.color}` - })) - }; -} - -// ============================================================================ -// UTILITY FUNCTIONS -// ============================================================================ - -/** - * Get the binary representation of a hex string (for debugging) - * - * @param {string} hex - Hex string - * @returns {string} Binary string with spaces every 4 bits - */ -function hexToBinary(hex) { - const value = parseInt(hex, 16); - const binary = value.toString(2).padStart(16, '0'); - return binary.match(/.{1,4}/g).join(' '); -} - -/** - * Validate that a configuration uses only defined values - * - * @param {Object} config - Product configuration - * @returns {Object} Validation result with errors array - */ -function validateConfiguration(config) { - const errors = []; - - if (!PRODUCT_TYPE_REVERSE[config.type]) { - errors.push(`Invalid product type: ${config.type}`); - } - if (!PRODUCT_COLOR_REVERSE[config.color]) { - errors.push(`Invalid product color: ${config.color}`); - } - if (!PRODUCT_MATERIAL_REVERSE[config.material]) { - errors.push(`Invalid product material: ${config.material}`); - } - - if (config.hardware) { - config.hardware.forEach((hw, index) => { - if (!HARDWARE_TYPE_REVERSE[hw.type]) { - errors.push(`Invalid hardware ${index + 1} type: ${hw.type}`); - } - if (!HARDWARE_STYLE_REVERSE[hw.style]) { - errors.push(`Invalid hardware ${index + 1} style: ${hw.style}`); - } - if (!HARDWARE_COLOR_REVERSE[hw.color]) { - errors.push(`Invalid hardware ${index + 1} color: ${hw.color}`); - } - }); - } - - return { - valid: errors.length === 0, - errors: errors - }; -} - -// ============================================================================ -// EXPORTS (for Node.js / Module usage) -// ============================================================================ - -if (typeof module !== 'undefined' && module.exports) { - module.exports = { - // Constants - ENCODING_VERSION, - PRODUCT_TYPE, - PRODUCT_COLOR, - PRODUCT_MATERIAL, - HARDWARE_TYPE, - HARDWARE_STYLE, - HARDWARE_COLOR, - - // Encoding functions - encodeHardware, - encodeProduct, - encodeProductByName, - - // Decoding functions - decodeHardware, - decodeProduct, - decodeProductToNames, - - // Utilities - hexToBinary, - validateConfiguration - }; -} - -// ============================================================================ -// EXAMPLE USAGE -// ============================================================================ - -/* -// Example 1: Encode by numeric values -const encoded1 = encodeProduct({ - type: 1, // Patio Door - color: 4, // White - material: 1, // Aluminum - hardware: [ - { type: 1, style: 1, color: 1 } // Lever, Standard, Brass - ] -}); -console.log(encoded1); // "0-1-4-1-0421" - -// Example 2: Encode by named values -const encoded2 = encodeProductByName({ - type: 'STORM_DOOR', - color: 'WHITE', - material: 'ALUMINUM', - hardware: [ - { type: 'LEVER', style: 'STANDARD', color: 'BRASS' }, - { type: 'PULL_HANDLE', style: 'ALTERNATIVE', color: 'SATIN' } - ] -}); -console.log(encoded2); // "0-3-4-1-0421-0C64" - -// Example 3: Decode back to numeric values -const decoded1 = decodeProduct("0-1-4-1-0421"); -console.log(decoded1); -// { version: 0, type: 1, color: 4, material: 1, hardware: [{ type: 1, style: 1, color: 1 }] } - -// Example 4: Decode to named values -const decoded2 = decodeProductToNames("0-3-4-1-0421-0C64"); -console.log(decoded2); -// { -// version: 0, -// type: 'STORM_DOOR', -// color: 'WHITE', -// material: 'ALUMINUM', -// hardware: [ -// { type: 'LEVER', style: 'STANDARD', color: 'BRASS' }, -// { type: 'PULL_HANDLE', style: 'ALTERNATIVE', color: 'SATIN' } -// ] -// } - -// Example 5: Debug hardware encoding -const hwHex = encodeHardware(3, 12, 20); -console.log(hwHex); // "0D94" -console.log(hexToBinary(hwHex)); // "0000 1101 1001 0100" -console.log(decodeHardware(hwHex)); // { type: 3, style: 12, color: 20 } - -// Example 6: Validate configuration -const validation = validateConfiguration({ - type: 1, color: 4, material: 1, - hardware: [{ type: 1, style: 1, color: 1 }] -}); -console.log(validation); // { valid: true, errors: [] } -*/ diff --git a/app/parse_csv_to_json.py b/app/parse_csv_to_json.py deleted file mode 100644 index 6f8eb17..0000000 --- a/app/parse_csv_to_json.py +++ /dev/null @@ -1,652 +0,0 @@ -""" -CSV to JSON Parser - Generate Navigation, Products, and Accessories JSON Files -Based on AI_PARSING_INSTRUCTIONS.md - -This script reads data/products.csv and generates: -1. data/navigation.json - Question flow with conditional logic -2. data/products.json - Product catalog -3. data/accessories.json - Accessory options with compatibility rules - -Run: python parse_csv_to_json.py -""" - -import csv -import json -from collections import defaultdict -from typing import Dict, List, Set, Tuple - -def parse_bool(value): - """Parse TRUE/FALSE string to boolean""" - if isinstance(value, str): - return value.strip().upper() == 'TRUE' - return bool(value) - -def clean_string(value): - """Clean and strip string values""" - if isinstance(value, str): - return value.strip() - return value or "" - -class CSVParser: - def __init__(self, csv_path: str): - self.csv_path = csv_path - self.products = [] - self.accessories = [] - self.base_types = set() - self.door_subtypes = defaultdict(list) # subtype -> [products] - self.window_subtypes = defaultdict(list) - self.material_counts = defaultdict(lambda: {'aluminum': 0, 'vinyl': 0}) - self.color_counts = defaultdict(lambda: defaultdict(int)) # subtype -> {color: count} - self.color_by_material = defaultdict(lambda: defaultdict(set)) # subtype -> {material: {colors}} - self.detailed_products = {} # Load from questions.json - - def load_detailed_product_info(self): - """Load detailed product info from questions.json""" - try: - # Load the code mapping - try: - with open('data/product_code_mapping.json', 'r', encoding='utf-8') as f: - code_mapping = json.load(f) - except FileNotFoundError: - code_mapping = {} - - with open('data/questions.json', 'r', encoding='utf-8') as f: - questions_data = json.load(f) - - # Extract all product nodes - for key, value in questions_data.items(): - if key.startswith('prod-') and value.get('type') == 'product': - code = value.get('code') - if code: - detailed_info = { - 'title': value.get('title'), - 'detailedDescription': value.get('description'), - 'features': value.get('features', []), - 'image': value.get('image'), - 'url': value.get('url'), - 'brochure': value.get('brochure'), - 'measureGuide': value.get('measureGuide') - } - - # Store under the simplified code - self.detailed_products[code] = detailed_info - - # Also store under all mapped codes - for csv_code, simple_code in code_mapping.items(): - if simple_code == code: - self.detailed_products[csv_code] = detailed_info - - print(f"āœ“ Loaded {len(self.detailed_products)} detailed product descriptions") - except FileNotFoundError: - print("⚠ questions.json not found - skipping detailed product info") - except Exception as e: - print(f"⚠ Error loading product details: {e}") - - def parse_csv(self): - """Parse the CSV file and separate products from accessories""" - print("šŸ“– Reading CSV file...") - - with open(self.csv_path, 'r', encoding='utf-8', errors='ignore') as f: - reader = csv.reader(f) - - # Skip first two header rows - next(reader) # Row 1: Category headers - header_row = next(reader) # Row 2: Column names - - row_count = 0 - for row in reader: - if len(row) < 11: # Need at least up to column K - continue - - row_count += 1 - - # Skip discontinued items - if parse_bool(row[0]): # DISCONT column - continue - - # Extract basic info - prod_code = clean_string(row[2]) # PROD_CODE - category = clean_string(row[3]) # CATEGORY - description = clean_string(row[5]) # DESCRIPTION - location = clean_string(row[1]) # LOC_CODE - - base_type = clean_string(row[6]) if len(row) > 6 else "" # Base Type (G) - door_subtype = clean_string(row[7]) if len(row) > 7 else "" # Sub-type Door (H) - window_subtype = clean_string(row[8]) if len(row) > 8 else "" # Sub-type Window (I) - is_accessory = parse_bool(row[9]) if len(row) > 9 else False # Accessory Yes (J) - specific_item = parse_bool(row[10]) if len(row) > 10 else False # This Item (K) - - # Parse materials (L, M) - materials = [] - if len(row) > 11 and parse_bool(row[11]): - materials.append('Aluminum') - if len(row) > 12 and parse_bool(row[12]): - materials.append('Vinyl') - - # Parse colors (N through S+) - colors = [] - color_columns = [ - (13, 'Black'), (14, 'White'), (15, 'Bronze'), - (16, 'Tan'), (17, 'Mill'), (18, 'Sandstone') - ] - for col_idx, color_name in color_columns: - if len(row) > col_idx and parse_bool(row[col_idx]): - colors.append(color_name) - - # Build item data - item_data = { - 'id': prod_code, - 'productCode': prod_code, - 'category': category, - 'description': description, - 'discontinued': False, - 'location': location, - 'baseType': base_type, - 'subType': { - 'door': door_subtype if door_subtype else None, - 'window': window_subtype if window_subtype else None - }, - 'materials': materials, - 'colors': colors - } - - # Separate accessories from products - if is_accessory: - # Build accessory-specific data - accessory = { - **item_data, - 'accessoryCode': prod_code, - 'compatibilityRules': self._build_compatibility_rules( - door_subtype, window_subtype, category, specific_item - ), - 'optionType': self._infer_option_type(description), - 'metadata': { - 'specificItemLink': specific_item - } - } - self.accessories.append(accessory) - else: - # Build product-specific data - product = { - **item_data, - 'isAccessory': False, - 'compatibleAccessories': [] # Will be populated later - } - - # Merge detailed info if available - if prod_code in self.detailed_products: - detailed = self.detailed_products[prod_code] - product.update({ - 'title': detailed['title'], - 'detailedDescription': detailed['detailedDescription'], - 'features': detailed['features'], - 'image': detailed['image'], - 'url': detailed['url'], - 'brochure': detailed.get('brochure'), - 'measureGuide': detailed.get('measureGuide') - }) - - self.products.append(product) - - # Track for navigation building - if base_type: - self.base_types.add(base_type) - - # Track subtypes per type - if door_subtype: - self.door_subtypes[door_subtype].append(product) - if window_subtype: - self.window_subtypes[window_subtype].append(product) - - # Count materials per subtype - subtype_key = door_subtype or window_subtype or "none" - if 'Aluminum' in materials: - self.material_counts[subtype_key]['aluminum'] += 1 - # Track colors per material - for color in colors: - self.color_by_material[subtype_key]['Aluminum'].add(color) - if 'Vinyl' in materials: - self.material_counts[subtype_key]['vinyl'] += 1 - # Track colors per material - for color in colors: - self.color_by_material[subtype_key]['Vinyl'].add(color) - - # Count colors per subtype (overall) - for color in colors: - self.color_counts[subtype_key][color] += 1 - - print(f"āœ“ Parsed {row_count} rows") - print(f"āœ“ Found {len(self.products)} products") - print(f"āœ“ Found {len(self.accessories)} accessories") - - def _build_compatibility_rules(self, door_subtype, window_subtype, category, specific_item): - """Build compatibility rules for accessories""" - rules = { - 'type': 'category', # Default - 'subTypeDoor': door_subtype if door_subtype else None, - 'subTypeWindow': window_subtype if window_subtype else None, - 'categories': [category] if category else [], - 'specificProducts': [], - 'requiresMatch': { - 'material': True, # Usually accessories need matching material - 'color': False # Colors usually don't need to match - } - } - - # Determine rule type - if specific_item: - rules['type'] = 'specific' - elif door_subtype or window_subtype: - rules['type'] = 'subType' - - return rules - - def _infer_option_type(self, description): - """Infer option type from description""" - desc_upper = description.upper() - - if 'HANDLE' in desc_upper: - return 'handle' - elif 'INSERT' in desc_upper or 'GLASS' in desc_upper: - return 'insert' - elif 'HARDWARE' in desc_upper: - return 'hardware' - elif 'SCREEN' in desc_upper: - return 'screen' - else: - return 'option' - - def link_accessories_to_products(self): - """Link compatible accessories to products""" - print("šŸ”— Linking accessories to products...") - - linked_count = 0 - for product in self.products: - compatible = [] - - for accessory in self.accessories: - rules = accessory['compatibilityRules'] - - # Check by subtype - if rules['type'] == 'subType': - prod_door = product['subType']['door'] - prod_window = product['subType']['window'] - acc_door = rules['subTypeDoor'] - acc_window = rules['subTypeWindow'] - - if (prod_door and prod_door == acc_door) or \ - (prod_window and prod_window == acc_window): - # Check material compatibility if required - if rules['requiresMatch']['material']: - # Check if they share any materials - if any(m in product['materials'] for m in accessory['materials']): - compatible.append(accessory['id']) - linked_count += 1 - else: - compatible.append(accessory['id']) - linked_count += 1 - - # Check by category - elif rules['type'] == 'category': - if product['category'] in rules['categories']: - compatible.append(accessory['id']) - linked_count += 1 - - product['compatibleAccessories'] = compatible - - print(f"āœ“ Created {linked_count} product-accessory links") - - def build_navigation(self): - """Build navigation JSON with conditional logic""" - print("šŸ—ŗļø Building navigation flow...") - - navigation = {} - - # Question 1: Base Type Selection - navigation['start'] = { - 'type': 'question', - 'inputType': 'button', - 'title': 'What are you looking for?', - 'subtitle': 'Select the product category', - 'answers': [] - } - - # Add base type options - sorted_types = sorted(self.base_types) - for base_type in sorted_types: - emoji = '🚪' if 'door' in base_type.lower() else '🪟' - next_key = f'q-{base_type.lower()}-type' - - navigation['start']['answers'].append({ - 'caption': base_type, - 'image': emoji, - 'next': next_key, - 'filter': { - 'baseType': base_type - } - }) - - # Question 2: Sub-type Selection for Doors - if self.door_subtypes: - door_subtypes = sorted(self.door_subtypes.keys()) - navigation['q-door-type'] = { - 'type': 'question', - 'inputType': 'button', - 'title': 'What type of door?', - 'subtitle': 'Select the door category', - 'answers': [] - } - - for subtype in door_subtypes: - products = self.door_subtypes[subtype] - - # Check if material question is needed - needs_material = self._needs_material_question(subtype) - - # Determine next question - if needs_material: - next_key = f'q-material-{subtype.lower().replace(" ", "-")}' - else: - # No material choice needed - determine single material and check colors - single_material = 'Aluminum' if self.material_counts[subtype]['aluminum'] > 0 else 'Vinyl' - needs_color = self._needs_color_question(subtype, single_material) - next_key = f'q-color-{subtype.lower().replace(" ", "-")}-{single_material.lower()}' if needs_color else 'q-dimensions' - - # Auto-apply material if only one - filter_obj = { - 'baseType': 'Door', - 'subType': subtype - } - - if not needs_material: - # Auto-apply the single material - if self.material_counts[subtype]['aluminum'] > 0: - filter_obj['material'] = 'Aluminum' - elif self.material_counts[subtype]['vinyl'] > 0: - filter_obj['material'] = 'Vinyl' - - # If no color question either, auto-apply single color - single_material = filter_obj['material'] - if not self._needs_color_question(subtype, single_material): - colors = list(self.color_by_material[subtype][single_material]) - if len(colors) == 1: - filter_obj['color'] = colors[0] - - navigation['q-door-type']['answers'].append({ - 'caption': subtype, - 'image': '🚪', - 'next': next_key, - 'filter': filter_obj - }) - - # Create material question if needed - if needs_material: - self._create_material_question(navigation, subtype, 'Door') - # Create color question if material skipped but color needed - elif next_key.startswith('q-color-'): - single_material = 'Aluminum' if self.material_counts[subtype]['aluminum'] > 0 else 'Vinyl' - self._create_color_question(navigation, subtype, single_material, 'Door') - - # Question 2: Sub-type Selection for Windows - if self.window_subtypes: - window_subtypes = sorted(self.window_subtypes.keys()) - navigation['q-window-type'] = { - 'type': 'question', - 'inputType': 'button', - 'title': 'What type of window?', - 'subtitle': 'Select the window category', - 'answers': [] - } - - for subtype in window_subtypes: - needs_material = self._needs_material_question(subtype) - - # Determine next question - if needs_material: - next_key = f'q-material-{subtype.lower().replace(" ", "-")}' - else: - # No material choice needed - determine single material and check colors - single_material = 'Aluminum' if self.material_counts[subtype]['aluminum'] > 0 else 'Vinyl' - needs_color = self._needs_color_question(subtype, single_material) - next_key = f'q-color-{subtype.lower().replace(" ", "-")}-{single_material.lower()}' if needs_color else 'q-dimensions' - - filter_obj = { - 'baseType': 'Window', - 'subType': subtype - } - - if not needs_material: - if self.material_counts[subtype]['aluminum'] > 0: - filter_obj['material'] = 'Aluminum' - elif self.material_counts[subtype]['vinyl'] > 0: - filter_obj['material'] = 'Vinyl' - - # If no color question either, auto-apply single color - single_material = filter_obj['material'] - if not self._needs_color_question(subtype, single_material): - colors = list(self.color_by_material[subtype][single_material]) - if len(colors) == 1: - filter_obj['color'] = colors[0] - - navigation['q-window-type']['answers'].append({ - 'caption': subtype, - 'image': '🪟', - 'next': next_key, - 'filter': filter_obj - }) - - if needs_material: - self._create_material_question(navigation, subtype, 'Window') - # Create color question if material skipped but color needed - elif next_key.startswith('q-color-'): - single_material = 'Aluminum' if self.material_counts[subtype]['aluminum'] > 0 else 'Vinyl' - self._create_color_question(navigation, subtype, single_material, 'Window') - - # Final Question: Dimensions - navigation['q-dimensions'] = { - 'type': 'question', - 'inputType': 'form', - 'title': 'Enter Product Dimensions', - 'subtitle': 'Please provide the measurements', - 'fields': [ - { - 'name': 'width', - 'label': 'Width (inches)', - 'type': 'number', - 'required': True, - 'placeholder': 'e.g., 36' - }, - { - 'name': 'height', - 'label': 'Height (inches)', - 'type': 'number', - 'required': True, - 'placeholder': 'e.g., 80' - } - ], - 'next': 'results' - } - - print(f"āœ“ Created {len(navigation)} navigation nodes") - return navigation - - def _needs_material_question(self, subtype): - """Check if a subtype needs a material selection question""" - aluminum = self.material_counts[subtype]['aluminum'] - vinyl = self.material_counts[subtype]['vinyl'] - - # Show material question if both materials exist - return aluminum > 0 and vinyl > 0 - - def _create_material_question(self, navigation, subtype, base_type): - """Create a material selection question""" - question_key = f'q-material-{subtype.lower().replace(" ", "-")}' - - navigation[question_key] = { - 'type': 'question', - 'inputType': 'button', - 'title': 'Select Material', - 'subtitle': f'Choose your preferred material for {subtype}', - 'conditional': { - 'type': 'material', - 'fallbackNext': 'q-dimensions' - }, - 'answers': [] - } - - # Add material options - if self.material_counts[subtype]['aluminum'] > 0: - # Check if color question needed after aluminum selection - needs_color = self._needs_color_question(subtype, 'Aluminum') - next_key_al = f'q-color-{subtype.lower().replace(" ", "-")}-aluminum' if needs_color else 'q-dimensions' - - navigation[question_key]['answers'].append({ - 'caption': 'Aluminum', - 'image': 'šŸ”©', - 'next': next_key_al, - 'filter': { - 'baseType': base_type, - 'subType': subtype, - 'material': 'Aluminum' - } - }) - - if self.material_counts[subtype]['vinyl'] > 0: - # Check if color question needed after vinyl selection - needs_color = self._needs_color_question(subtype, 'Vinyl') - next_key_vin = f'q-color-{subtype.lower().replace(" ", "-")}-vinyl' if needs_color else 'q-dimensions' - - navigation[question_key]['answers'].append({ - 'caption': 'Vinyl', - 'image': '🪟', - 'next': next_key_vin, - 'filter': { - 'baseType': base_type, - 'subType': subtype, - 'material': 'Vinyl' - } - }) - - # Create color questions for each material option - if self.material_counts[subtype]['aluminum'] > 0 and self._needs_color_question(subtype, 'Aluminum'): - self._create_color_question(navigation, subtype, 'Aluminum', base_type) - if self.material_counts[subtype]['vinyl'] > 0 and self._needs_color_question(subtype, 'Vinyl'): - self._create_color_question(navigation, subtype, 'Vinyl', base_type) - - def _needs_color_question(self, subtype, material): - """Check if a subtype+material combination needs a color selection question""" - colors = self.color_by_material[subtype][material] - # Show color question if multiple colors exist - return len(colors) > 1 - - def _create_color_question(self, navigation, subtype, material, base_type): - """Create a color selection question""" - question_key = f'q-color-{subtype.lower().replace(" ", "-")}-{material.lower()}' - - navigation[question_key] = { - 'type': 'question', - 'inputType': 'button', - 'title': 'Select Color', - 'subtitle': f'Choose your preferred color for {material} {subtype}', - 'conditional': { - 'type': 'color', - 'fallbackNext': 'q-dimensions' - }, - 'answers': [] - } - - # Get available colors for this subtype+material - colors = sorted(self.color_by_material[subtype][material]) - - # Color emoji mapping - color_emojis = { - 'Black': '⬛', - 'White': '⬜', - 'Bronze': '🟫', - 'Tan': '🟤', - 'Mill': '⚪', - 'Sandstone': '🟨' - } - - for color in colors: - navigation[question_key]['answers'].append({ - 'caption': color, - 'image': color_emojis.get(color, 'šŸŽØ'), - 'next': 'q-dimensions', - 'filter': { - 'baseType': base_type, - 'subType': subtype, - 'material': material, - 'color': color - } - }) - - def save_json_files(self, navigation): - """Save all three JSON files""" - print("šŸ’¾ Saving JSON files...") - - # Save products.json - with open('data/products.json', 'w', encoding='utf-8') as f: - json.dump(self.products, f, indent=2) - print(f"āœ“ Saved data/products.json ({len(self.products)} products)") - - # Save accessories.json - with open('data/accessories.json', 'w', encoding='utf-8') as f: - json.dump(self.accessories, f, indent=2) - print(f"āœ“ Saved data/accessories.json ({len(self.accessories)} accessories)") - - # Save navigation.json - with open('data/navigation.json', 'w', encoding='utf-8') as f: - json.dump(navigation, f, indent=2) - print(f"āœ“ Saved data/navigation.json ({len(navigation)} nodes)") - - def print_statistics(self): - """Print parsing statistics""" - print("\n" + "="*60) - print("PARSING STATISTICS") - print("="*60) - print(f"Total Products: {len(self.products)}") - print(f"Total Accessories: {len(self.accessories)}") - print(f"Base Types: {', '.join(sorted(self.base_types))}") - print(f"Door Subtypes: {len(self.door_subtypes)}") - print(f"Window Subtypes: {len(self.window_subtypes)}") - print() - print("Material Distribution:") - for subtype, counts in sorted(self.material_counts.items()): - if counts['aluminum'] > 0 or counts['vinyl'] > 0: - needs_q = "āœ“ Material Q" if (counts['aluminum'] > 0 and counts['vinyl'] > 0) else "āœ— Skip" - print(f" {subtype:20} - Al:{counts['aluminum']:3} Vinyl:{counts['vinyl']:3} [{needs_q}]") - print("="*60) - -def main(): - csv_path = 'data/products.csv' - - print("šŸš€ CSV to JSON Parser") - print("="*60) - - try: - parser = CSVParser(csv_path) - parser.load_detailed_product_info() - parser.parse_csv() - parser.link_accessories_to_products() - navigation = parser.build_navigation() - parser.save_json_files(navigation) - parser.print_statistics() - - print("\nāœ… All JSON files generated successfully!") - print("\nNext steps:") - print("1. Review data/navigation.json for question flow") - print("2. Review data/products.json for product data") - print("3. Review data/accessories.json for accessory compatibility") - print("4. Test the application in your browser") - - except FileNotFoundError: - print(f"āŒ Error: Could not find {csv_path}") - print(" Make sure products.csv exists in the data/ folder") - except Exception as e: - print(f"āŒ Error: {e}") - import traceback - traceback.print_exc() - -if __name__ == '__main__': - main() diff --git a/app/passenger_wsgi.py b/app/passenger_wsgi.py index 90d062f..d221b58 100644 --- a/app/passenger_wsgi.py +++ b/app/passenger_wsgi.py @@ -1,47 +1,17 @@ -""" -Passenger WSGI file for Flask application -Compatible with Python 3.13+ -Auto-detects /product-finder subdirectory deployment -""" -import sys +import importlib.machinery +import importlib.util import os +import sys -# Get the directory where this file is located -CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -# Add the application directory to Python path -sys.path.insert(0, CURRENT_DIR) +sys.path.insert(0, os.path.dirname(__file__)) -# Import the Flask application directly from app.py -# Note: app.py now auto-detects production environment -try: - from app import app as application - print("āœ“ Flask application loaded successfully") - -except ImportError as e: - # Fallback error handler that shows the actual error - def application(environ, start_response): - import traceback - status = '500 Internal Server Error' - error_details = f'Import Error: {str(e)}\n\nTraceback:\n{traceback.format_exc()}\n\nPython Path:\n{sys.path}' - output = error_details.encode('utf-8') - response_headers = [('Content-type', 'text/plain; charset=utf-8'), - ('Content-Length', str(len(output)))] - start_response(status, response_headers) - return [output] - print(f"āœ— Failed to import Flask app: {e}") +def load_source(modname, filename): + loader = importlib.machinery.SourceFileLoader(modname, filename) + spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + return module -except Exception as e: - # Catch any other startup errors - def application(environ, start_response): - import traceback - status = '500 Internal Server Error' - error_details = f'Startup Error: {str(e)}\n\nTraceback:\n{traceback.format_exc()}' - output = error_details.encode('utf-8') - response_headers = [('Content-type', 'text/plain; charset=utf-8'), - ('Content-Length', str(len(output)))] - start_response(status, response_headers) - return [output] - print(f"āœ— Error starting app: {e}") - -# Passenger requires the application object to be named 'application' +wsgi = load_source('wsgi', 'app.py') +application = wsgi.application diff --git a/app/region_helper.py b/app/region_helper.py deleted file mode 100644 index 0956860..0000000 --- a/app/region_helper.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -Interactive Region Coordinate Helper -Opens an image and helps you find pixel coordinates for colorable regions. -Click on the image to see coordinates. - -Usage: - python region_helper.py images/cobrai.jpg -""" - -import sys -from PIL import Image, ImageDraw, ImageFont -import tkinter as tk -from tkinter import Canvas -from PIL import ImageTk - - -class RegionHelper: - def __init__(self, image_path): - self.image_path = image_path - self.image = Image.open(image_path) - self.width, self.height = self.image.size - - # Setup UI - self.root = tk.Tk() - self.root.title(f"Region Helper - {image_path}") - - # Scale image if too large - self.scale = 1.0 - max_display_width = 1000 - max_display_height = 800 - - if self.width > max_display_width or self.height > max_display_height: - scale_w = max_display_width / self.width - scale_h = max_display_height / self.height - self.scale = min(scale_w, scale_h) - - new_width = int(self.width * self.scale) - new_height = int(self.height * self.scale) - self.display_image = self.image.resize((new_width, new_height), Image.LANCZOS) - else: - self.display_image = self.image.copy() - - # Setup canvas - self.canvas = Canvas( - self.root, - width=self.display_image.width, - height=self.display_image.height - ) - self.canvas.pack(side=tk.LEFT) - - # Display image - self.photo = ImageTk.PhotoImage(self.display_image) - self.canvas.create_image(0, 0, anchor=tk.NW, image=self.photo) - - # Info panel - info_frame = tk.Frame(self.root, width=300) - info_frame.pack(side=tk.RIGHT, fill=tk.BOTH, padx=10, pady=10) - - tk.Label(info_frame, text="Image Dimensions:", font=('Arial', 12, 'bold')).pack(anchor=tk.W, pady=5) - tk.Label(info_frame, text=f"{self.width} x {self.height} pixels").pack(anchor=tk.W) - - if self.scale != 1.0: - tk.Label(info_frame, text=f"Scaled: {self.scale:.2%}").pack(anchor=tk.W) - - tk.Label(info_frame, text="\nClick to get coordinates:", font=('Arial', 12, 'bold')).pack(anchor=tk.W, pady=(20, 5)) - - self.coord_label = tk.Label(info_frame, text="X: -, Y: -", font=('Arial', 14)) - self.coord_label.pack(anchor=tk.W, pady=5) - - tk.Label(info_frame, text="\nFirst click = Top-Left", fg='blue').pack(anchor=tk.W) - tk.Label(info_frame, text="Second click = Bottom-Right", fg='blue').pack(anchor=tk.W) - - tk.Label(info_frame, text="\nRegion JSON:", font=('Arial', 12, 'bold')).pack(anchor=tk.W, pady=(20, 5)) - - self.json_text = tk.Text(info_frame, height=15, width=35, font=('Courier', 9)) - self.json_text.pack(fill=tk.BOTH, expand=True) - - tk.Button(info_frame, text="Clear Points", command=self.clear_points).pack(pady=10) - tk.Button(info_frame, text="Copy JSON", command=self.copy_json).pack() - - # Bind events - self.canvas.bind('', self.on_mouse_move) - self.canvas.bind('', self.on_click) - - # Store points - self.points = [] - self.point_ids = [] - - self.update_json() - - def on_mouse_move(self, event): - """Show current mouse coordinates.""" - x = int(event.x / self.scale) - y = int(event.y / self.scale) - self.coord_label.config(text=f"X: {x}, Y: {y}") - - def on_click(self, event): - """Record clicked point.""" - x = int(event.x / self.scale) - y = int(event.y / self.scale) - - # Limit to 2 points (top-left, bottom-right) - if len(self.points) >= 2: - self.clear_points() - - self.points.append((x, y)) - - # Draw point on canvas - color = 'blue' if len(self.points) == 1 else 'red' - point_id = self.canvas.create_oval( - event.x - 5, event.y - 5, - event.x + 5, event.y + 5, - fill=color, outline='white', width=2 - ) - self.point_ids.append(point_id) - - # Draw rectangle if we have both points - if len(self.points) == 2: - x1, y1 = self.points[0] - x2, y2 = self.points[1] - - # Draw on canvas (scaled) - rect_id = self.canvas.create_rectangle( - x1 * self.scale, y1 * self.scale, - x2 * self.scale, y2 * self.scale, - outline='green', width=2, dash=(5, 5) - ) - self.point_ids.append(rect_id) - - self.update_json() - - def clear_points(self): - """Clear all points and rectangles.""" - for point_id in self.point_ids: - self.canvas.delete(point_id) - - self.points = [] - self.point_ids = [] - self.update_json() - - def update_json(self): - """Update the JSON display.""" - self.json_text.delete('1.0', tk.END) - - if len(self.points) == 0: - self.json_text.insert('1.0', '{\n "name": "region_name",\n "topLeft": [?, ?],\n "bottomRight": [?, ?],\n "description": "..."\n}') - elif len(self.points) == 1: - x, y = self.points[0] - self.json_text.insert('1.0', f'{{\n "name": "region_name",\n "topLeft": [{x}, {y}],\n "bottomRight": [?, ?],\n "description": "..."\n}}') - else: - x1, y1 = self.points[0] - x2, y2 = self.points[1] - - # Calculate dimensions - width = abs(x2 - x1) - height = abs(y2 - y1) - - json_str = f'''{{\n "name": "region_name",\n "topLeft": [{x1}, {y1}],\n "bottomRight": [{x2}, {y2}],\n "description": "Width: {width}px, Height: {height}px"\n}}''' - self.json_text.insert('1.0', json_str) - - def copy_json(self): - """Copy JSON to clipboard.""" - json_str = self.json_text.get('1.0', tk.END).strip() - self.root.clipboard_clear() - self.root.clipboard_append(json_str) - self.root.update() - - def run(self): - """Start the GUI.""" - self.root.mainloop() - - -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Usage: python region_helper.py ") - print("Example: python region_helper.py images/cobrai.jpg") - sys.exit(1) - - image_path = sys.argv[1] - - try: - helper = RegionHelper(image_path) - helper.run() - except FileNotFoundError: - print(f"Error: Image file not found: {image_path}") - sys.exit(1) - except Exception as e: - print(f"Error: {e}") - sys.exit(1) diff --git a/app/requirements.txt b/app/requirements.txt index 0d5627b..02ae215 100644 --- a/app/requirements.txt +++ b/app/requirements.txt @@ -1,4 +1 @@ -Flask>=3.0.0 -Werkzeug>=3.0.0 -# Pillow>=10.0.0 # Optional - only needed for dynamic image generation -# If you need image generation, install separately: pip install Pillow +Flask==3.1.3 diff --git a/app/css/styles.css b/app/static/css/styles.css similarity index 92% rename from app/css/styles.css rename to app/static/css/styles.css index 1bb3ea6..e430104 100644 --- a/app/css/styles.css +++ b/app/static/css/styles.css @@ -28,29 +28,26 @@ body { } .user-info-bar { - position: absolute; - top: 10px; - right: 20px; display: flex; + justify-content: space-between; align-items: center; - gap: 15px; + padding: 2px 10px; + background-color: #f5f5f5; + border-bottom: 1px solid #ddd; font-size: 14px; } .logout-btn { - background-color: #f56565; - color: white; + background: none; border: none; - padding: 6px 12px; - border-radius: 4px; cursor: pointer; - font-size: 13px; - font-weight: 600; - transition: background-color 0.3s; + font-size: 24px; + padding: 5px 10px; + transition: transform 0.2s; } .logout-btn:hover { - background-color: #e53e3e; + transform: scale(1.1); } .question-container { diff --git a/app/js/script.js b/app/static/js/script.js similarity index 96% rename from app/js/script.js rename to app/static/js/script.js index 334c6d7..83eefb1 100644 --- a/app/js/script.js +++ b/app/static/js/script.js @@ -41,12 +41,15 @@ function init() { // Load question data and other JSON files function loadQuestionData() { + // Use the data path from the blueprint + const dataPath = '/quiz/data/'; + // Load all data files in parallel Promise.all([ - fetch('data/navigation.json').then(r => r.ok ? r.json() : Promise.reject('navigation.json not found')), - fetch('data/products.json').then(r => r.ok ? r.json() : []).catch(() => []), - fetch('data/accessories.json').then(r => r.ok ? r.json() : []).catch(() => []), - fetch('data/product_bitwise.json').then(r => r.ok ? r.json() : []).catch(() => []) + fetch(dataPath + 'navigation.json').then(r => r.ok ? r.json() : Promise.reject('navigation.json not found')), + fetch(dataPath + 'products.json').then(r => r.ok ? r.json() : []).catch(() => []), + fetch(dataPath + 'accessories.json').then(r => r.ok ? r.json() : []).catch(() => []), + fetch(dataPath + 'product_bitwise.json').then(r => r.ok ? r.json() : []).catch(() => []) ]) .then(([questions, products, accessories, bitwise]) => { questionData = questions; diff --git a/app/templates/404.html b/app/templates/404.html deleted file mode 100644 index 2a10638..0000000 --- a/app/templates/404.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - 404 - Page Not Found - - - -
-

404

-

Page Not Found

-

Sorry, the page you're looking for doesn't exist or has been moved.

- Go Home - Start Quiz -
- - diff --git a/app/templates/access_denied.html b/app/templates/access_denied.html deleted file mode 100644 index e0b0029..0000000 --- a/app/templates/access_denied.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - Access Denied - CGW Product Finder - - - -
-
🚫
-

Access Denied

-

- You do not have permission to access this page or perform this action. -

- - {% if required_permission %} -
- Required Permission: {{ required_permission }} -
- {% endif %} - -

- If you believe this is an error, please contact your administrator. -

- - - -
- Need help? Contact your system administrator to request access. -
-
- - diff --git a/app/templates/image_test.html b/app/templates/image_test.html deleted file mode 100644 index 6a30037..0000000 --- a/app/templates/image_test.html +++ /dev/null @@ -1,381 +0,0 @@ - - - - - - Dynamic Image Generation - Test Page - - - -
-

šŸŽØ Dynamic Image Generation API

-

Test the product image generation endpoints

- -
-

How It Works

-

- This demo uses server-side image processing to dynamically generate product images - with different colors and configurations. Select options below to see the image update in real-time. -

-
- -
-

Product Configuration

- -
- - -
- -
- - -
- -
- -
- - -
-
- -
- -
- - - - -
- -
-
-

Direct Image URL Method

-

- Using: <img src="..."> -

- Product -
Loading...
-
- -
-

JSON/Base64 Method

-

- Using: fetch() + base64 -

- Product -
Loading...
-
-
- - - - - -
-

API Endpoints Used

-
    -
  • GET /api/product-image/{product}?color={color}&hinge={hinge}
  • -
  • GET /api/product-image/{product}?color={color}&hinge={hinge}&format=json
  • -
  • GET /api/product-config/{product}
  • -
  • POST /api/clear-image-cache
  • -
-
-
- - - - diff --git a/app/templates/index.html b/app/templates/index.html deleted file mode 100644 index be21f87..0000000 --- a/app/templates/index.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - Product Details Form - - - -
-
- - -
- -
- - -
- -
- - -
- -
- - -
- - - - - -
- - -
- - - -
-

Possible questions for customers based on what is selected or missing

-
[list - checkbox per question]
-
-
- - - - diff --git a/app/templates/index2.html b/app/templates/index2.html deleted file mode 100644 index b6ce836..0000000 --- a/app/templates/index2.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - Product Finder - - - -
-
-

Product Finder

- -
- - - -
- -
-
- - - - - - diff --git a/app/templates/login.html b/app/templates/login.html index 63b4662..0360fb1 100644 --- a/app/templates/login.html +++ b/app/templates/login.html @@ -3,14 +3,10 @@ - Login - CGW Product Finder + Login

šŸ“ Select Your Location

-

Choose a location to access the Product Finder

+

Choose which location you'll be working from today

- diff --git a/app/templates/user_manager.html b/app/templates/user_manager.html index 5056936..17827fb 100644 --- a/app/templates/user_manager.html +++ b/app/templates/user_manager.html @@ -3,13 +3,9 @@ - User Manager - CGW Product Finder + User Manager
-

šŸ” User Manager

-

Create and manage user accounts with secure password encoding

+

šŸ‘„ User Manager

+ ← Back to Home
+

Add New User

-
+
- - + +
- - + +
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Default Location * - -
- - - -
- - - -
- - - -
- - - -
+ + +
+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ +
+
+ + +
+
+ + +
+
- -
-
-
0
-
Total Users
-
-
+
-

User List

-
-

No users added yet.

-
- -
- - -
-
- - ← Back to Product Finder -
- - - diff --git a/app/test_app.py b/app/test_app.py deleted file mode 100644 index 59dba54..0000000 --- a/app/test_app.py +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/env python3 -""" -Comprehensive app test script -Run this through control panel to diagnose issues -Writes detailed logs to test_app.log -""" -import sys -import os -from datetime import datetime - -# Setup logging -log_file = os.path.join(os.path.dirname(__file__), 'test_app.log') - -def log(message, also_print=True): - """Write to log file and optionally print""" - timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - full_message = f"[{timestamp}] {message}" - - with open(log_file, 'a') as f: - f.write(full_message + '\n') - - if also_print: - print(full_message) - -try: - log("="*70) - log("APP TEST SCRIPT - START") - log("="*70) - - # 1. Environment Info - log("\n1. PYTHON ENVIRONMENT") - log(f" Python: {sys.version}") - log(f" Executable: {sys.executable}") - log(f" CWD: {os.getcwd()}") - - # 2. Check environment variables - log("\n2. ENVIRONMENT VARIABLES") - log(f" APPLICATION_ROOT: {os.environ.get('APPLICATION_ROOT', 'NOT SET')}") - log(f" FLASK_ENV: {os.environ.get('FLASK_ENV', 'NOT SET')}") - log(f" SECRET_KEY: {'SET' if os.environ.get('SECRET_KEY') else 'NOT SET'}") - - # 3. Check critical files - log("\n3. FILE STRUCTURE CHECK") - files_to_check = [ - 'app.py', - 'passenger_wsgi.py', - 'config.py', - 'data/users.json', - 'templates/login.html', - 'templates/index2.html', - 'templates/select_location.html', - 'templates/user_manager.html' - ] - - all_files_exist = True - for file_path in files_to_check: - full_path = os.path.join(os.path.dirname(__file__), file_path) - exists = os.path.exists(full_path) - status = "āœ“" if exists else "āœ— MISSING" - log(f" {status} {file_path}") - if not exists: - all_files_exist = False - - if not all_files_exist: - log("\nāš ļø CRITICAL: Missing files detected!") - - # 4. Check dependencies - log("\n4. PYTHON PACKAGES") - packages = [ - ('flask', 'Flask'), - ('werkzeug', 'Werkzeug') - ] - - all_packages_ok = True - for module_name, display_name in packages: - try: - module = __import__(module_name) - try: - from importlib.metadata import version - ver = version(module_name) - except: - ver = getattr(module, '__version__', 'unknown') - log(f" āœ“ {display_name}: {ver}") - except ImportError as e: - log(f" āœ— {display_name}: NOT INSTALLED ({e})") - all_packages_ok = False - - if not all_packages_ok: - log("\nāš ļø CRITICAL: Missing packages! Run: pip install Flask==3.0.0 Werkzeug==3.0.1") - sys.exit(1) - - # 5. Try importing app - log("\n5. APP IMPORT TEST") - log(" Attempting to import Flask app...") - - try: - # Make sure current directory is in path - current_dir = os.path.dirname(__file__) - if current_dir not in sys.path: - sys.path.insert(0, current_dir) - - from app import app - log(" āœ“ Flask app imported successfully!") - - # Check app config - log("\n6. APP CONFIGURATION") - log(f" APPLICATION_ROOT: {app.config.get('APPLICATION_ROOT', 'NOT SET')}") - log(f" DEBUG: {app.config.get('DEBUG')}") - log(f" SECRET_KEY: {'SET (' + str(len(app.config.get('SECRET_KEY', ''))) + ' chars)' if app.config.get('SECRET_KEY') else 'NOT SET'}") - - # Check if middleware applied - log(f" WSGI App Type: {type(app.wsgi_app).__name__}") - if 'PrefixMiddleware' in str(type(app.wsgi_app)): - log(" āœ“ PrefixMiddleware is active") - else: - log(" āš ļø PrefixMiddleware NOT active (may cause issues at /product-finder)") - - # Count routes - log("\n7. ROUTES CHECK") - routes = list(app.url_map.iter_rules()) - log(f" Total routes: {len(routes)}") - - # Check critical routes - critical_routes = ['/login', '/api/login', '/users', '/select-location'] - log(" Critical routes:") - for route_path in critical_routes: - found = any(str(rule) == route_path or str(rule).startswith(route_path + '<') for rule in routes) - status = "āœ“" if found else "āœ— MISSING" - log(f" {status} {route_path}") - - # 8. Test loading users - log("\n8. USER DATA TEST") - try: - users_file = os.path.join(current_dir, 'data', 'users.json') - if os.path.exists(users_file): - import json - with open(users_file, 'r') as f: - users = json.load(f) - log(f" āœ“ Users file loaded: {len(users)} users") - log(f" Usernames: {', '.join([u.get('username', '?') for u in users])}") - else: - log(f" āœ— Users file NOT FOUND at {users_file}") - except Exception as e: - log(f" āœ— Error loading users: {e}") - - # 9. Test a simple request - log("\n9. REQUEST TEST") - log(" Testing if app can handle requests...") - - with app.test_client() as client: - # Test root redirect - try: - response = client.get('/') - log(f" GET / -> Status: {response.status_code}") - if response.status_code == 302: - log(f" Redirects to: {response.location}") - except Exception as e: - log(f" āœ— Error testing /: {e}") - - # Test login page - try: - response = client.get('/login') - log(f" GET /login -> Status: {response.status_code}") - if response.status_code != 200: - log(f" āš ļø Login page returned {response.status_code} instead of 200") - except Exception as e: - log(f" āœ— Error testing /login: {e}") - - # 10. Summary - log("\n" + "="*70) - log("TEST SUMMARY") - log("="*70) - - if all_files_exist and all_packages_ok: - log("āœ“ All files present") - log("āœ“ All packages installed") - log("āœ“ App imports successfully") - log(f"āœ“ {len(routes)} routes registered") - - app_root = app.config.get('APPLICATION_ROOT', '/') - if app_root == '/product-finder': - log("āœ“ Configured for /product-finder deployment") - else: - log(f"āš ļø APPLICATION_ROOT is '{app_root}' (should be '/product-finder' for production)") - - log("\nšŸŽ‰ APP APPEARS READY!") - log("\nIf still getting 500 errors:") - log("1. Check that data/users.json exists") - log("2. Verify APPLICATION_ROOT env var is set to /product-finder") - log("3. Check Apache error log for runtime errors") - log("4. Ensure .htaccess is correct") - - else: - log("\nāš ļø ISSUES FOUND - Fix these before deployment") - - log("="*70) - log(f"\nLog saved to: {log_file}") - - except ImportError as e: - log(f" āœ— FAILED to import app!") - log(f" Error: {e}") - - import traceback - log("\nFull traceback:") - log(traceback.format_exc()) - - log("\nāŒ CRITICAL ERROR: Cannot import Flask app") - log("Check that app.py exists and has no syntax errors") - - except Exception as e: - log(f" āœ— Unexpected error during import!") - log(f" Error: {e}") - - import traceback - log("\nFull traceback:") - log(traceback.format_exc()) - -except Exception as e: - log(f"\nāŒ FATAL ERROR: {e}") - import traceback - log(traceback.format_exc()) - -finally: - log("\n" + "="*70) - log("TEST COMPLETE") - log("="*70) - print(f"\nšŸ“„ Full log saved to: {log_file}") - print("Download this file to see all test results") diff --git a/app/test_deployment.py b/app/test_deployment.py deleted file mode 100644 index 5ef53f7..0000000 --- a/app/test_deployment.py +++ /dev/null @@ -1,171 +0,0 @@ -""" -Deployment diagnostic script for /product-finder -Run this on the server to verify configuration -""" -import os -import sys - -print("=" * 70) -print("CGW PRODUCT FINDER - DEPLOYMENT DIAGNOSTIC") -print("=" * 70) -print() - -# Check Python version -print("šŸ“Œ Python Environment:") -print(f" Version: {sys.version}") -print(f" Executable: {sys.executable}") -print(f" Current Directory: {os.getcwd()}") -print() - -# Check environment variable -print("šŸ“Œ Environment Variables:") -app_root_env = os.environ.get('APPLICATION_ROOT') -if app_root_env: - print(f" APPLICATION_ROOT: {app_root_env} āœ“") -else: - print(f" APPLICATION_ROOT: NOT SET āš ļø") - print(f" Setting temporarily for test: /product-finder") - os.environ['APPLICATION_ROOT'] = '/product-finder' -print() - -# Try importing Flask -print("šŸ“Œ Flask Installation:") -try: - import flask - print(f" Flask version: {flask.__version__} āœ“") -except ImportError as e: - print(f" āœ— Flask not installed: {e}") - sys.exit(1) - -# Try importing app -print() -print("šŸ“Œ Application Import:") -try: - from app import app - print(f" āœ“ App imported successfully") -except Exception as e: - print(f" āœ— Error importing app:") - print(f" {e}") - import traceback - traceback.print_exc() - sys.exit(1) - -# Check app configuration -print() -print("šŸ“Œ Application Configuration:") -print(f" APPLICATION_ROOT: {app.config.get('APPLICATION_ROOT')}") -print(f" SECRET_KEY set: {'Yes' if app.config.get('SECRET_KEY') else 'No'}") -print(f" DEBUG mode: {app.config.get('DEBUG')}") -print(f" ENV: {app.config.get('ENV', 'not set')}") -print() - -# Check middleware -print("šŸ“Œ WSGI Middleware:") -wsgi_app_type = type(app.wsgi_app).__name__ -if 'PrefixMiddleware' in str(type(app.wsgi_app)): - print(f" āœ“ PrefixMiddleware applied") - print(f" Type: {wsgi_app_type}") -elif wsgi_app_type == 'Flask': - print(f" āš ļø No middleware applied (running at root)") - print(f" Type: {wsgi_app_type}") -else: - print(f" Middleware type: {wsgi_app_type}") -print() - -# Check routes -print("šŸ“Œ Registered Routes:") -routes_count = len(list(app.url_map.iter_rules())) -print(f" Total routes: {routes_count}") - -# Check critical routes -critical_routes = ['/login', '/api/login', '/users', '/api/session'] -print(f" Critical routes:") -for route in critical_routes: - found = any(str(rule) == route for rule in app.url_map.iter_rules()) - status = "āœ“" if found else "āœ—" - print(f" {status} {route}") -print() - -# Check file structure -print("šŸ“Œ File Structure:") -critical_files = [ - 'app.py', - 'passenger_wsgi.py', - 'config.py', - 'templates/login.html', - 'templates/index2.html', - 'data/users.json' -] - -for file_path in critical_files: - exists = os.path.exists(file_path) - status = "āœ“" if exists else "āœ—" - print(f" {status} {file_path}") -print() - -# Check dependencies -print("šŸ“Œ Python Dependencies:") -deps = [ - ('werkzeug', 'Werkzeug'), - ('flask', 'Flask'), -] - -try: - from PIL import Image - deps.append(('PIL', 'Pillow')) -except ImportError: - pass - -for module_name, display_name in deps: - try: - module = __import__(module_name) - version = getattr(module, '__version__', 'unknown') - print(f" āœ“ {display_name}: {version}") - except ImportError: - print(f" āœ— {display_name}: NOT INSTALLED") -print() - -# Summary -print("=" * 70) -print("DEPLOYMENT STATUS") -print("=" * 70) - -issues = [] - -if not os.environ.get('APPLICATION_ROOT'): - issues.append("APPLICATION_ROOT not set in environment") - -if app.config.get('APPLICATION_ROOT') == '/': - issues.append("APPLICATION_ROOT is '/' but should be '/product-finder' for production") - -if not os.path.exists('templates/login.html'): - issues.append("Template files missing") - -if not os.path.exists('data/users.json'): - issues.append("User data file missing") - -if issues: - print() - print("āš ļø ISSUES FOUND:") - for issue in issues: - print(f" - {issue}") - print() - print("šŸ“ NEXT STEPS:") - print(" 1. Upload missing files to server") - print(" 2. Set APPLICATION_ROOT environment variable") - print(" 3. Restart Passenger: touch tmp/restart.txt") - print(" 4. Check error logs for details") -else: - print() - print("āœ“ All checks passed!") - print() - print("šŸš€ DEPLOYMENT READY") - print() - print("To restart Passenger:") - print(" mkdir -p tmp && touch tmp/restart.txt") - print() - print("To test:") - print(" https://columbiawindows.com/product-finder/") - -print() -print("=" * 70) diff --git a/app/test_routes.py b/app/test_routes.py deleted file mode 100644 index 96aa65d..0000000 --- a/app/test_routes.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -Quick test to verify Flask routes are registered correctly -Run this from the app folder: python test_routes.py -""" - -import sys -import os - -# Add current directory to path -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -try: - from app import app - - print("=" * 60) - print("FLASK ROUTES TEST") - print("=" * 60) - print() - print("āœ“ Flask app imported successfully") - print() - print("Registered routes:") - print("-" * 60) - - routes = [] - for rule in app.url_map.iter_rules(): - routes.append({ - 'endpoint': rule.endpoint, - 'methods': ', '.join(sorted(rule.methods - {'HEAD', 'OPTIONS'})), - 'path': str(rule) - }) - - # Sort by path - routes.sort(key=lambda x: x['path']) - - # Find all login-related routes - login_routes = [r for r in routes if 'login' in r['path'].lower() or 'login' in r['endpoint'].lower()] - user_routes = [r for r in routes if 'user' in r['path'].lower()] - - print("\nšŸ“ Login & Authentication Routes:") - for route in login_routes: - print(f" {route['path']:40} [{route['methods']:15}] -> {route['endpoint']}") - - print("\nšŸ‘„ User Management Routes:") - for route in user_routes: - print(f" {route['path']:40} [{route['methods']:15}] -> {route['endpoint']}") - - print("\nšŸ“Š Total routes registered:", len(routes)) - print() - print("=" * 60) - print("āœ“ All routes loaded successfully!") - print("=" * 60) - print() - print("To start the server:") - print(" python app.py") - print() - print("Then access:") - print(" http://localhost:8080/login") - print(" http://localhost:8080/users") - print() - -except ImportError as e: - print("=" * 60) - print("āŒ IMPORT ERROR") - print("=" * 60) - print() - print(f"Failed to import Flask app: {e}") - print() - print("This might be because:") - print(" 1. Flask is not installed: pip install Flask") - print(" 2. Werkzeug is not installed: pip install Werkzeug") - print(" 3. There's a syntax error in app.py") - print() - print("Try running:") - print(" pip install -r requirements.txt") - print() - -except Exception as e: - print("=" * 60) - print("āŒ ERROR") - print("=" * 60) - print() - print(f"Error: {e}") - print() - import traceback - traceback.print_exc() - print() diff --git a/app/troubleshoot_server.py b/app/troubleshoot_server.py deleted file mode 100644 index 8707495..0000000 --- a/app/troubleshoot_server.py +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env python3 -""" -Server troubleshooting script for 403/404 errors -Run this on the server to diagnose Apache/Passenger issues -""" -import os -import sys - -print("=" * 70) -print("TROUBLESHOOTING 403/404 ERRORS") -print("=" * 70) -print() - -# Check current directory -current_dir = os.getcwd() -print(f"šŸ“ Current directory: {current_dir}") -print() - -# Check file permissions -print("šŸ“Œ File Permissions Check:") -files_to_check = [ - 'passenger_wsgi.py', - '.htaccess', - 'app.py', - 'data/users.json', - 'templates/login.html' -] - -for file in files_to_check: - if os.path.exists(file): - stat_info = os.stat(file) - perms = oct(stat_info.st_mode)[-3:] - print(f" āœ“ {file:<30} Permissions: {perms}") - else: - print(f" āœ— {file:<30} NOT FOUND") -print() - -# Check directory permissions -print("šŸ“Œ Directory Permissions:") -dirs_to_check = ['.', 'templates', 'data', 'static', 'tmp'] -for dir_path in dirs_to_check: - if os.path.exists(dir_path): - stat_info = os.stat(dir_path) - perms = oct(stat_info.st_mode)[-3:] - print(f" āœ“ {dir_path:<30} Permissions: {perms}") - else: - print(f" āš ļø {dir_path:<30} NOT FOUND (might be OK)") -print() - -# Check for tmp/restart.txt -print("šŸ“Œ Passenger Restart Check:") -if os.path.exists('tmp/restart.txt'): - from datetime import datetime - mtime = os.path.getmtime('tmp/restart.txt') - mtime_str = datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S') - print(f" āœ“ tmp/restart.txt exists (last modified: {mtime_str})") -else: - print(f" āœ— tmp/restart.txt NOT FOUND") - print(f" Create it with: mkdir -p tmp && touch tmp/restart.txt") -print() - -# Check environment variables -print("šŸ“Œ Environment Variables:") -print(f" APPLICATION_ROOT: {os.environ.get('APPLICATION_ROOT', 'NOT SET')}") -print(f" HOME: {os.environ.get('HOME', 'NOT SET')}") -print(f" USER: {os.environ.get('USER', 'NOT SET')}") -print() - -# Check .htaccess content -print("šŸ“Œ .htaccess Configuration:") -if os.path.exists('.htaccess'): - print(f" āœ“ .htaccess exists") - with open('.htaccess', 'r') as f: - content = f.read() - if 'PassengerEnabled' in content: - print(f" āœ“ PassengerEnabled directive found") - else: - print(f" āœ— PassengerEnabled directive NOT FOUND") - - if 'PassengerAppRoot' in content: - print(f" āœ“ PassengerAppRoot directive found") - # Extract the path - for line in content.split('\n'): - if 'PassengerAppRoot' in line: - print(f" Value: {line.strip()}") - else: - print(f" āœ— PassengerAppRoot NOT FOUND") - - if 'PassengerPython' in content: - print(f" āœ“ PassengerPython directive found") - for line in content.split('\n'): - if 'PassengerPython' in line: - print(f" Value: {line.strip()}") - python_path = line.split()[-1] if len(line.split()) > 1 else '' - if os.path.exists(python_path): - print(f" āœ“ Python executable exists") - else: - print(f" āœ— Python executable NOT FOUND at {python_path}") -else: - print(f" āœ— .htaccess NOT FOUND") -print() - -# Try importing Flask -print("šŸ“Œ Flask Import Test:") -try: - sys.path.insert(0, current_dir) - from app import app - print(f" āœ“ Flask app imported successfully") - print(f" Routes registered: {len(list(app.url_map.iter_rules()))}") -except Exception as e: - print(f" āœ— Error importing app: {e}") -print() - -# Recommendations -print("=" * 70) -print("COMMON FIXES FOR 403/404 ERRORS:") -print("=" * 70) -print() -print("1ļøāƒ£ RESTART PASSENGER:") -print(" mkdir -p tmp") -print(" touch tmp/restart.txt") -print() -print("2ļøāƒ£ CHECK FILE PERMISSIONS:") -print(" chmod 644 passenger_wsgi.py") -print(" chmod 644 .htaccess") -print(" chmod 755 .") -print() -print("3ļøāƒ£ VERIFY PATHS IN .htaccess:") -print(" PassengerAppRoot should point to: " + current_dir) -print() -print("4ļøāƒ£ CHECK APACHE ERROR LOG:") -print(" tail -50 ~/logs/error_log") -print(" (Look for Passenger errors)") -print() -print("5ļøāƒ£ VERIFY .htaccess IS BEING READ:") -print(" If AllowOverride is not set in Apache config, .htaccess is ignored") -print() -print("6ļøāƒ£ SIMPLER .htaccess (if still failing):") -print(" Try creating a minimal .htaccess with just:") -print(" PassengerEnabled on") -print() -print("=" * 70) diff --git a/app/wsgi.py b/app/wsgi.py deleted file mode 100644 index d8b19e3..0000000 --- a/app/wsgi.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -WSGI entry point for production deployment -Use with Gunicorn: gunicorn wsgi:app -""" -from app import app - -if __name__ == "__main__": - app.run() diff --git a/app_simple/README.md b/app_simple/README.md deleted file mode 100644 index fb2d35e..0000000 --- a/app_simple/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Simple Flask Test App - -A minimal 2-page Flask application to test Passenger WSGI deployment. - -## Pages -- `/` - Home page (Hello World) -- `/about` - About page -- `/test` - Test page (shows system info) - -## Local Testing -```bash -cd app_simple -python app.py -``` -Visit: http://localhost:8080/ - -## Server Deployment - -### Upload these files to: `/home/bmdwtjuw/product-finder/` -- `app.py` -- `wsgi.py` -- `templates/home.html` -- `templates/about.html` - -### Control Panel Configuration -- **Application startup file:** `wsgi.py` -- **Application Entry point:** `app` -- **Python version:** 3.13.11 - -### Test URLs (after deployment) -- https://columbiawindows.com/product-finder/ -- https://columbiawindows.com/product-finder/about -- https://columbiawindows.com/product-finder/test - -## What This Tests -āœ“ Python 3.13.11 compatibility -āœ“ Flask framework loading -āœ“ Template rendering -āœ“ URL routing -āœ“ Passenger WSGI configuration - -Once this works, you can add back the login/user management features from `app2` folder. diff --git a/app_simple/app.py b/app_simple/app.py deleted file mode 100644 index c2a108e..0000000 --- a/app_simple/app.py +++ /dev/null @@ -1,37 +0,0 @@ -from flask import Flask, render_template - -# Initialize Flask -app = Flask(__name__) - -@app.route('/') -def home(): - """Home page - Hello World""" - return render_template('home.html') - -@app.route('/about') -def about(): - """About page""" - return render_template('about.html') - -@app.route('/test') -def test(): - """Test route - no template needed""" - import sys - return f""" - - Test Page - -

Flask App is Running!

-
    -
  • Python: {sys.version}
  • -
  • Flask: Working
  • -
  • Routes: {len(list(app.url_map.iter_rules()))}
  • -
-

Home | About

- - - """ - -if __name__ == '__main__': - # Run locally on port 8080 - app.run(debug=True, host='0.0.0.0', port=8080) diff --git a/app_simple/check_deployment.py b/app_simple/check_deployment.py deleted file mode 100644 index e9cbbb7..0000000 --- a/app_simple/check_deployment.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 -""" -Deployment Check Script -Run this on the server to verify configuration -""" -import os -import sys - -print("=" * 70) -print("DEPLOYMENT CONFIGURATION CHECK") -print("=" * 70) - -# Check Python version -print(f"\nPython Version: {sys.version}") -print(f"Python Executable: {sys.executable}") - -# Check current directory -print(f"\nCurrent Directory: {os.getcwd()}") - -# Check for required files -print("\n" + "=" * 70) -print("CHECKING FILES") -print("=" * 70) - -files_to_check = ['app.py', 'wsgi.py', 'templates/home.html', 'templates/about.html'] -for file in files_to_check: - exists = "āœ“ EXISTS" if os.path.exists(file) else "āœ— MISSING" - print(f"{exists}: {file}") - -# Check for passenger_wsgi.py (should NOT exist) -if os.path.exists('passenger_wsgi.py'): - print("āœ— WARNING: passenger_wsgi.py exists - DELETE THIS FILE!") -else: - print("āœ“ GOOD: passenger_wsgi.py does not exist") - -# Try importing Flask -print("\n" + "=" * 70) -print("CHECKING FLASK") -print("=" * 70) -try: - import flask - print(f"āœ“ Flask version: {flask.__version__}") -except ImportError as e: - print(f"āœ— Flask not installed: {e}") - -# Try importing the app -print("\n" + "=" * 70) -print("CHECKING APP IMPORT") -print("=" * 70) -try: - from app import app - print("āœ“ App imported successfully") - print(f"āœ“ App name: {app.name}") - print(f"āœ“ Routes count: {len(list(app.url_map.iter_rules()))}") -except Exception as e: - print(f"āœ— Error importing app: {e}") - import traceback - traceback.print_exc() - -print("\n" + "=" * 70) -print("DONE") -print("=" * 70) diff --git a/app_simple/requirements.txt b/app_simple/requirements.txt deleted file mode 100644 index f31cf55..0000000 --- a/app_simple/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -Flask==3.0.0 -Werkzeug==3.0.1 diff --git a/app_simple/templates/about.html b/app_simple/templates/about.html deleted file mode 100644 index 9248f53..0000000 --- a/app_simple/templates/about.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - About - Simple Flask App - - - -
-

About This App

-

This is a simple 2-page Flask application created to test server deployment configuration.

-

Purpose: Verify that Passenger WSGI configuration works correctly.

- -

Configuration:

-
    -
  • Startup file: wsgi.py
  • -
  • Entry point: app
  • -
  • Framework: Flask 3.0.0
  • -
  • Python: 3.13.11
  • -
- - -
- - diff --git a/app_simple/templates/home.html b/app_simple/templates/home.html deleted file mode 100644 index 35f1690..0000000 --- a/app_simple/templates/home.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - Home - Simple Flask App - - - -
-

Hello World!

-

Welcome to the simple Flask application.

-

This is a minimal test to verify the server configuration works correctly.

- - -
- - diff --git a/app_simple/wsgi.py b/app_simple/wsgi.py deleted file mode 100644 index 3c50ab1..0000000 --- a/app_simple/wsgi.py +++ /dev/null @@ -1,4 +0,0 @@ -from app import app - -if __name__ == "__main__": - app.run() diff --git a/product_app/app.py b/product_app/app.py deleted file mode 100644 index f3cd72c..0000000 --- a/product_app/app.py +++ /dev/null @@ -1,87 +0,0 @@ -from flask import Flask, session, redirect, url_for -import secrets -import os - -# Get the directory where this script is located -basedir = os.path.abspath(os.path.dirname(__file__)) - -# Initialize Flask with explicit paths -app = Flask(__name__, - template_folder=os.path.join(basedir, 'templates'), - static_folder=os.path.join(basedir, 'static')) - -# Configure session - generate a random secret key -app.secret_key = secrets.token_hex(32) -app.config['SESSION_COOKIE_HTTPONLY'] = True -app.config['SESSION_COOKIE_SAMESITE'] = 'Lax' - -# Import and register blueprints -from blueprints.auth import auth_bp -from blueprints.users import users_bp - -app.register_blueprint(auth_bp) -app.register_blueprint(users_bp) - -# Home route -@app.route('/') -def home(): - """Redirect to login if not authenticated, otherwise show home""" - if 'user_id' not in session: - return redirect(url_for('auth.login_page')) - - # If user hasn't selected a location yet, redirect to selection - if not session.get('currentLocation') and len(session.get('accessibleLocations', [])) > 1: - return redirect(url_for('auth.select_location_page')) - - return f""" - - Home - -

Welcome, {session.get('username', 'User')}!

-

Current Location: {session.get('currentLocation', 'Not selected')}

- - - - """ - -@app.route('/test') -def test(): - """Test route to verify app is running""" - import sys - return f""" - - Test Page - -

Flask App is Running!

-
    -
  • Python: {sys.version}
  • -
  • Routes: {len(list(app.url_map.iter_rules()))}
  • -
-

Login

- - - """ - -# Error handlers -@app.errorhandler(404) -def page_not_found(e): - return "

404 - Page Not Found

", 404 - -@app.errorhandler(500) -def internal_error(e): - return "

500 - Internal Server Error

", 500 - -# This is the critical line for Passenger -application = app - -if __name__ == '__main__': - # Create necessary directories - os.makedirs(os.path.join(basedir, 'templates'), exist_ok=True) - os.makedirs(os.path.join(basedir, 'data'), exist_ok=True) - - # Run the application - app.run(debug=True, host='0.0.0.0', port=8080) \ No newline at end of file diff --git a/product_app/data/users.json b/product_app/data/users.json deleted file mode 100644 index 649a86e..0000000 --- a/product_app/data/users.json +++ /dev/null @@ -1,25 +0,0 @@ -[ - { - "username": "Master", - "password": "pbkdf2:sha256:1000000$tPRmseRGKLveXTxS$87eda9a20db29d12838fcb607f1f3536141f743ec9879702dc2a0dd893b4078d", - "defaultLocation": "KC", - "permissions": { - "manage_users": true - }, - "locationSettings": { - "LINDS": { - "accessible": true - }, - "IOLA": { - "accessible": true - }, - "KC": { - "accessible": true - }, - "BMD": { - "accessible": true - } - }, - "active": true - } -] diff --git a/product_app/passenger_wsgi.py b/product_app/passenger_wsgi.py deleted file mode 100644 index d221b58..0000000 --- a/product_app/passenger_wsgi.py +++ /dev/null @@ -1,17 +0,0 @@ -import importlib.machinery -import importlib.util -import os -import sys - - -sys.path.insert(0, os.path.dirname(__file__)) - -def load_source(modname, filename): - loader = importlib.machinery.SourceFileLoader(modname, filename) - spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module - -wsgi = load_source('wsgi', 'app.py') -application = wsgi.application diff --git a/product_app/requirements.txt b/product_app/requirements.txt deleted file mode 100644 index 02ae215..0000000 --- a/product_app/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -Flask==3.1.3 diff --git a/product_app/templates/login.html b/product_app/templates/login.html deleted file mode 100644 index 9e34433..0000000 --- a/product_app/templates/login.html +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - Login - - - - - - - - diff --git a/product_app/templates/select_location.html b/product_app/templates/select_location.html deleted file mode 100644 index e21f02e..0000000 --- a/product_app/templates/select_location.html +++ /dev/null @@ -1,375 +0,0 @@ - - - - - - Select Location - - - -
-
-

šŸ“ Select Your Location

-

Choose which location you'll be working from today

-
- - - -
- -
- -
- - - - -
- - - - diff --git a/product_app/templates/user_manager.html b/product_app/templates/user_manager.html deleted file mode 100644 index 957a6e1..0000000 --- a/product_app/templates/user_manager.html +++ /dev/null @@ -1,498 +0,0 @@ - - - - - - User Manager - - - -
-
-

šŸ‘„ User Manager

- ← Back to Home -
- -
-
- - -
-

Add New User

-
-
- - -
- -
- - -
- -
- - -
- -
- -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- -
- -
-
- - -
-
- - -
-
-
- - -
-
- - -
-

Existing Users

-
-
-
- - - -