718 lines
17 KiB
Markdown
718 lines
17 KiB
Markdown
# 🚀 **Application Container Scripts (ct/AppName.sh)**
|
|
|
|
**Modern Guide to Creating LXC Container Installation Scripts**
|
|
|
|
> **Updated**: December 2025
|
|
> **Context**: Fully integrated with build.func, advanced_settings wizard, and defaults system
|
|
> **Example Used**: `/ct/pihole.sh`, `/ct/docker.sh`
|
|
|
|
---
|
|
|
|
## 📋 Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Architecture & Flow](#architecture--flow)
|
|
- [File Structure](#file-structure)
|
|
- [Complete Script Template](#complete-script-template)
|
|
- [Function Reference](#function-reference)
|
|
- [Advanced Features](#advanced-features)
|
|
- [Real Examples](#real-examples)
|
|
- [Troubleshooting](#troubleshooting)
|
|
- [Contribution Checklist](#contribution-checklist)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
### Purpose
|
|
|
|
Container scripts (`ct/AppName.sh`) are **entry points for creating LXC containers** with specific applications pre-installed. They:
|
|
|
|
1. Define container defaults (CPU, RAM, disk, OS)
|
|
2. Call the main build orchestrator (`build.func`)
|
|
3. Implement application-specific update mechanisms
|
|
4. Provide user-facing success messages
|
|
|
|
### Execution Context
|
|
|
|
```
|
|
Proxmox Host
|
|
↓
|
|
ct/AppName.sh sourced (runs as root on host)
|
|
↓
|
|
build.func: Creates LXC container + runs install script inside
|
|
↓
|
|
install/AppName-install.sh (runs inside container)
|
|
↓
|
|
Container ready with app installed
|
|
```
|
|
|
|
### Key Integration Points
|
|
|
|
- **build.func** - Main orchestrator (container creation, storage, variable management)
|
|
- **install.func** - Container-specific setup (OS update, package management)
|
|
- **tools.func** - Tool installation helpers (repositories, GitHub releases)
|
|
- **core.func** - UI/messaging functions (colors, spinners, validation)
|
|
- **error_handler.func** - Error handling and signal management
|
|
|
|
---
|
|
|
|
## Architecture & Flow
|
|
|
|
### Container Creation Flow
|
|
|
|
```
|
|
START: bash ct/pihole.sh
|
|
↓
|
|
[1] Set APP, var_*, defaults
|
|
↓
|
|
[2] header_info() → Display ASCII art
|
|
↓
|
|
[3] variables() → Parse arguments & load build.func
|
|
↓
|
|
[4] color() → Setup ANSI codes
|
|
↓
|
|
[5] catch_errors() → Setup trap handlers
|
|
↓
|
|
[6] install_script() → Show mode menu (5 options)
|
|
↓
|
|
├─ INSTALL_MODE="0" (Default)
|
|
├─ INSTALL_MODE="1" (Advanced - 19-step wizard)
|
|
├─ INSTALL_MODE="2" (User Defaults)
|
|
├─ INSTALL_MODE="3" (App Defaults)
|
|
└─ INSTALL_MODE="4" (Settings Menu)
|
|
↓
|
|
[7] advanced_settings() → Collect user configuration (if mode=1)
|
|
↓
|
|
[8] start() → Confirm or re-edit settings
|
|
↓
|
|
[9] build_container() → Create LXC + execute install script
|
|
↓
|
|
[10] description() → Set container description
|
|
↓
|
|
[11] SUCCESS → Display access URL
|
|
↓
|
|
END
|
|
```
|
|
|
|
### Default Values Precedence
|
|
|
|
```
|
|
Priority 1 (Highest): Environment Variables (var_cpu, var_ram, etc.)
|
|
Priority 2: App-Specific Defaults (/defaults/AppName.vars)
|
|
Priority 3: User Global Defaults (/default.vars)
|
|
Priority 4 (Lowest): Built-in Defaults (in build.func)
|
|
```
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
### Minimal ct/AppName.sh Template
|
|
|
|
```
|
|
#!/usr/bin/env bash # [1] Shebang
|
|
# [2] Copyright/License
|
|
source <(curl -s .../misc/build.func) # [3] Import functions
|
|
# [4] APP metadata
|
|
APP="AppName" # [5] Default values
|
|
var_tags="tag1;tag2"
|
|
var_cpu="2"
|
|
var_ram="2048"
|
|
...
|
|
|
|
header_info "$APP" # [6] Display header
|
|
variables # [7] Process arguments
|
|
color # [8] Setup colors
|
|
catch_errors # [9] Setup error handling
|
|
|
|
function update_script() { ... } # [10] Update function (optional)
|
|
|
|
start # [11] Launch container creation
|
|
build_container
|
|
description
|
|
msg_ok "Completed Successfully!\n"
|
|
```
|
|
|
|
---
|
|
|
|
## Complete Script Template
|
|
|
|
### 1. File Header & Imports
|
|
|
|
```bash
|
|
#!/usr/bin/env bash
|
|
# Copyright (c) 2021-2025 community-scripts ORG
|
|
# Author: YourUsername
|
|
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
|
# Source: https://github.com/example/project
|
|
|
|
# Import main orchestrator
|
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
|
|
```
|
|
|
|
> **⚠️ IMPORTANT**: Before opening a PR, change URL to `community-scripts` repo!
|
|
|
|
### 2. Application Metadata
|
|
|
|
```bash
|
|
# Application Configuration
|
|
APP="ApplicationName"
|
|
var_tags="tag1;tag2;tag3" # Max 3-4 tags, no spaces, semicolon-separated
|
|
|
|
# Container Resources
|
|
var_cpu="2" # CPU cores
|
|
var_ram="2048" # RAM in MB
|
|
var_disk="10" # Disk in GB
|
|
|
|
# Container Type & OS
|
|
var_os="debian" # Options: alpine, debian, ubuntu
|
|
var_version="12" # Alpine: 3.20+, Debian: 11-13, Ubuntu: 20.04+
|
|
var_unprivileged="1" # 1=unprivileged (secure), 0=privileged (rarely needed)
|
|
```
|
|
|
|
**Variable Naming Convention**:
|
|
- Variables exposed to user: `var_*` (e.g., `var_cpu`, `var_hostname`, `var_ssh`)
|
|
- Internal variables: lowercase (e.g., `container_id`, `app_version`)
|
|
|
|
### 3. Display & Initialization
|
|
|
|
```bash
|
|
# Display header ASCII art
|
|
header_info "$APP"
|
|
|
|
# Process command-line arguments and load configuration
|
|
variables
|
|
|
|
# Setup ANSI color codes and formatting
|
|
color
|
|
|
|
# Initialize error handling (trap ERR, EXIT, INT, TERM)
|
|
catch_errors
|
|
```
|
|
|
|
### 4. Update Function (Highly Recommended)
|
|
|
|
```bash
|
|
function update_script() {
|
|
header_info
|
|
|
|
# Always start with these checks
|
|
check_container_storage
|
|
check_container_resources
|
|
|
|
# Verify app is installed
|
|
if [[ ! -d /opt/appname ]]; then
|
|
msg_error "No ${APP} Installation Found!"
|
|
exit
|
|
fi
|
|
|
|
# Get latest version from GitHub
|
|
RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | \
|
|
grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
|
|
|
|
# Compare with saved version
|
|
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
|
|
msg_info "Updating ${APP} to v${RELEASE}"
|
|
|
|
# Backup user data
|
|
cp -r /opt/appname /opt/appname-backup
|
|
|
|
# Perform update
|
|
cd /opt
|
|
wget -q "https://github.com/user/repo/releases/download/v${RELEASE}/app-${RELEASE}.tar.gz"
|
|
tar -xzf app-${RELEASE}.tar.gz
|
|
|
|
# Restore user data
|
|
cp /opt/appname-backup/config/* /opt/appname/config/
|
|
|
|
# Cleanup
|
|
rm -rf app-${RELEASE}.tar.gz /opt/appname-backup
|
|
|
|
# Save new version
|
|
echo "${RELEASE}" > /opt/${APP}_version.txt
|
|
|
|
msg_ok "Updated ${APP} to v${RELEASE}"
|
|
else
|
|
msg_ok "No update required. ${APP} is already at v${RELEASE}."
|
|
fi
|
|
|
|
exit
|
|
}
|
|
```
|
|
|
|
### 5. Script Launch
|
|
|
|
```bash
|
|
# Start the container creation workflow
|
|
start
|
|
|
|
# Build the container with selected configuration
|
|
build_container
|
|
|
|
# Set container description/notes in Proxmox UI
|
|
description
|
|
|
|
# Display success message
|
|
msg_ok "Completed Successfully!\n"
|
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
|
```
|
|
|
|
---
|
|
|
|
## Function Reference
|
|
|
|
### Core Functions (From build.func)
|
|
|
|
#### `variables()`
|
|
|
|
**Purpose**: Initialize container variables, load user arguments, setup orchestration
|
|
|
|
**Triggered by**: Called automatically at script start
|
|
|
|
**Behavior**:
|
|
1. Parse command-line arguments (if any)
|
|
2. Generate random UUID for session tracking
|
|
3. Load container storage from Proxmox
|
|
4. Initialize application-specific defaults
|
|
5. Setup SSH/environment configuration
|
|
|
|
**Example Output**:
|
|
```
|
|
Setting up variables...
|
|
Container ID: 100
|
|
Storage: local-lvm
|
|
Install method: Default
|
|
```
|
|
|
|
#### `start()`
|
|
|
|
**Purpose**: Launch the container creation menu with 5 installation modes
|
|
|
|
**Triggered by**: Called just before `build_container()`
|
|
|
|
**Menu Options**:
|
|
```
|
|
1. Default Installation (Quick setup, predefined settings)
|
|
2. Advanced Installation (19-step wizard with full control)
|
|
3. User Defaults (Load ~/.community-scripts/default.vars)
|
|
4. App Defaults (Load /defaults/AppName.vars)
|
|
5. Settings Menu (Interactive mode selection)
|
|
```
|
|
|
|
**User Flow**:
|
|
```
|
|
Select installation mode:
|
|
1) Default
|
|
2) Advanced
|
|
3) User Defaults
|
|
4) App Defaults
|
|
5) Settings Menu
|
|
Enter choice: 2
|
|
```
|
|
|
|
#### `build_container()`
|
|
|
|
**Purpose**: Main orchestrator for LXC container creation
|
|
|
|
**Operations**:
|
|
1. Validates all variables
|
|
2. Creates LXC container via `pct create`
|
|
3. Executes `install/AppName-install.sh` inside container
|
|
4. Monitors installation progress
|
|
5. Handles errors and rollback on failure
|
|
|
|
**Exit Codes**:
|
|
- `0` - Success
|
|
- `1-255` - Various error conditions (see error_handler.func)
|
|
|
|
#### `description()`
|
|
|
|
**Purpose**: Set container description/notes visible in Proxmox UI
|
|
|
|
**Format**:
|
|
```
|
|
AppName
|
|
IP: [IP]
|
|
Version: [Version]
|
|
Tags: [Tags]
|
|
```
|
|
|
|
#### `header_info()`
|
|
|
|
**Purpose**: Display ASCII art header for application
|
|
|
|
**Sources**:
|
|
- Tries `/usr/local/community-scripts/headers/ct/appname` (cached)
|
|
- Falls back to remote fetch from GitHub
|
|
- Returns silently if not found
|
|
|
|
---
|
|
|
|
## Advanced Features
|
|
|
|
### 1. Integration with Defaults System
|
|
|
|
#### Save App Defaults After Installation
|
|
|
|
```bash
|
|
# At end of install script, after successful setup:
|
|
maybe_offer_save_app_defaults
|
|
|
|
# Output:
|
|
# "Save these settings as App Defaults for AppName? (Y/n)"
|
|
# Yes → Saves to /defaults/appname.vars
|
|
# No → Skips saving
|
|
```
|
|
|
|
#### Load Saved Defaults During Container Creation
|
|
|
|
```bash
|
|
# In ct/AppName.sh, user selects "App Defaults" mode
|
|
# Automatically loads /defaults/appname.vars
|
|
# Container uses previously saved configuration
|
|
```
|
|
|
|
### 2. Custom Configuration Menus
|
|
|
|
If your app has additional setup beyond standard vars:
|
|
|
|
```bash
|
|
# In ct/AppName.sh, after variables()
|
|
custom_app_settings() {
|
|
CONFIGURE_DB=$(whiptail --title "Database Setup" \
|
|
--yesno "Would you like to configure a custom database?" 8 60)
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
DB_HOST=$(whiptail --inputbox "Database Host:" 8 60 3>&1 1>&2 2>&3)
|
|
DB_PORT=$(whiptail --inputbox "Database Port:" 8 60 "3306" 3>&1 1>&2 2>&3)
|
|
fi
|
|
}
|
|
|
|
custom_app_settings
|
|
```
|
|
|
|
### 3. Version Tracking
|
|
|
|
Save installed version for update checks:
|
|
|
|
```bash
|
|
# In install script, after successful app download:
|
|
RELEASE="1.2.3"
|
|
echo "${RELEASE}" > /opt/${APP}_version.txt
|
|
|
|
# In update function, compare:
|
|
CURRENT=$(cat /opt/${APP}_version.txt 2>/dev/null)
|
|
LATEST=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | jq -r '.tag_name')
|
|
|
|
if [[ "$LATEST" != "$CURRENT" ]]; then
|
|
echo "Update available: $CURRENT → $LATEST"
|
|
fi
|
|
```
|
|
|
|
### 4. Health Check Functions
|
|
|
|
Add custom validation:
|
|
|
|
```bash
|
|
function health_check() {
|
|
header_info
|
|
|
|
if [[ ! -d /opt/appname ]]; then
|
|
msg_error "Application not found!"
|
|
exit 1
|
|
fi
|
|
|
|
if ! systemctl is-active --quiet appname; then
|
|
msg_error "Application service not running"
|
|
exit 1
|
|
fi
|
|
|
|
msg_ok "Health check passed"
|
|
}
|
|
|
|
# Called via: bash ct/appname.sh health_check
|
|
```
|
|
|
|
---
|
|
|
|
## Real Examples
|
|
|
|
### Example 1: Simple Web App (Debian-based)
|
|
|
|
```bash
|
|
#!/usr/bin/env bash
|
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
|
|
|
|
APP="Homarr"
|
|
var_tags="dashboard;homepage"
|
|
var_cpu="2"
|
|
var_ram="1024"
|
|
var_disk="5"
|
|
var_os="debian"
|
|
var_version="12"
|
|
var_unprivileged="1"
|
|
|
|
header_info "$APP"
|
|
variables
|
|
color
|
|
catch_errors
|
|
|
|
function update_script() {
|
|
header_info
|
|
check_container_storage
|
|
check_container_resources
|
|
|
|
if [[ ! -d /opt/homarr ]]; then
|
|
msg_error "No ${APP} Installation Found!"
|
|
exit
|
|
fi
|
|
|
|
RELEASE=$(curl -fsSL https://api.github.com/repos/ajnart/homarr/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4)}')
|
|
|
|
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
|
|
msg_info "Updating ${APP} to v${RELEASE}"
|
|
systemctl stop homarr
|
|
|
|
cd /opt/homarr
|
|
wget -q "https://github.com/ajnart/homarr/releases/download/v${RELEASE}/docker-compose.yml"
|
|
docker-compose up -d
|
|
|
|
echo "${RELEASE}" > /opt/${APP}_version.txt
|
|
msg_ok "Updated ${APP} to v${RELEASE}"
|
|
else
|
|
msg_ok "No update required. ${APP} is already at v${RELEASE}."
|
|
fi
|
|
exit
|
|
}
|
|
|
|
start
|
|
build_container
|
|
description
|
|
|
|
msg_ok "Completed Successfully!\n"
|
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5100${CL}"
|
|
```
|
|
|
|
### Example 2: Database App (Alpine-based)
|
|
|
|
```bash
|
|
#!/usr/bin/env bash
|
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func)
|
|
|
|
APP="PostgreSQL"
|
|
var_tags="database;sql"
|
|
var_cpu="4"
|
|
var_ram="4096"
|
|
var_disk="20"
|
|
var_os="alpine"
|
|
var_version="3.20"
|
|
var_unprivileged="1"
|
|
|
|
header_info "$APP"
|
|
variables
|
|
color
|
|
catch_errors
|
|
|
|
function update_script() {
|
|
header_info
|
|
check_container_storage
|
|
|
|
if ! command -v psql &>/dev/null; then
|
|
msg_error "PostgreSQL not installed!"
|
|
exit
|
|
fi
|
|
|
|
msg_info "Updating Alpine packages"
|
|
apk update
|
|
apk upgrade
|
|
msg_ok "Updated Alpine packages"
|
|
exit
|
|
}
|
|
|
|
start
|
|
build_container
|
|
description
|
|
|
|
msg_ok "Completed Successfully!\n"
|
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
|
echo -e "${INFO}${YW} Connect using:${CL}"
|
|
echo -e "${TAB}${GATEWAY}${BGN}psql -h ${IP} -U postgres${CL}"
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Container Creation Fails
|
|
|
|
**Symptom**: `pct create` exits with error code 209
|
|
|
|
**Causes**:
|
|
1. CTID already exists: `pct list` shows duplicate
|
|
2. Storage full: Check storage space
|
|
3. Network template unavailable
|
|
|
|
**Solution**:
|
|
```bash
|
|
# Check existing containers
|
|
pct list | grep CTID
|
|
|
|
# Remove conflicting container
|
|
pct destroy CTID
|
|
|
|
# Retry ct/AppName.sh
|
|
```
|
|
|
|
### Update Function Doesn't Detect New Version
|
|
|
|
**Symptom**: Update available but script says "already at latest"
|
|
|
|
**Causes**:
|
|
1. Version file missing: `/opt/AppName_version.txt`
|
|
2. GitHub API rate limit exceeded
|
|
3. Release tag format mismatch
|
|
|
|
**Debug**:
|
|
```bash
|
|
# Check version file
|
|
cat /opt/AppName_version.txt
|
|
|
|
# Test GitHub API
|
|
curl -fsSL https://api.github.com/repos/user/repo/releases/latest | grep tag_name
|
|
|
|
# Inside container
|
|
bash ct/appname.sh update_script
|
|
```
|
|
|
|
### Header ASCII Art Not Displaying
|
|
|
|
**Symptom**: Container script runs but no header shown
|
|
|
|
**Causes**:
|
|
1. Header file not in repository
|
|
2. Caching issue
|
|
|
|
**Solution**:
|
|
```bash
|
|
# Create header file manually
|
|
mkdir -p /usr/local/community-scripts/headers/ct
|
|
echo "Your ASCII art here" > /usr/local/community-scripts/headers/ct/appname
|
|
|
|
# Or remove cache to force re-download
|
|
rm -f /usr/local/community-scripts/headers/ct/appname
|
|
```
|
|
|
|
---
|
|
|
|
## Contribution Checklist
|
|
|
|
Before submitting a PR:
|
|
|
|
### Script Structure
|
|
- [ ] Shebang is `#!/usr/bin/env bash`
|
|
- [ ] Imports `build.func` from community-scripts repo (not personal fork)
|
|
- [ ] Copyright header with author and source URL
|
|
- [ ] APP variable matches filename
|
|
- [ ] `var_tags` are semicolon-separated (no spaces)
|
|
|
|
### Default Values
|
|
- [ ] `var_cpu` set appropriately (2-4 for most apps)
|
|
- [ ] `var_ram` set appropriately (1024-4096 MB minimum)
|
|
- [ ] `var_disk` sufficient for app + data (5-20 GB)
|
|
- [ ] `var_os` is realistic (Alpine if lightweight, Debian/Ubuntu otherwise)
|
|
- [ ] `var_unprivileged="1"` unless app absolutely needs privileges
|
|
|
|
### Functions
|
|
- [ ] `update_script()` implemented (or marked as unavailable)
|
|
- [ ] Update function checks if app installed
|
|
- [ ] Update function checks for new version
|
|
- [ ] Update function performs cleanup after update
|
|
- [ ] Proper error handling with `msg_error` on failure
|
|
|
|
### Output
|
|
- [ ] Success message displayed with access URL
|
|
- [ ] URL format: `http://IP:PORT/path` (if web-based)
|
|
- [ ] Uses `msg_ok`, `msg_info`, `msg_error` for feedback
|
|
|
|
### Testing
|
|
- [ ] Script tested with default installation
|
|
- [ ] Script tested with advanced (19-step) installation
|
|
- [ ] Update function tested on existing installation
|
|
- [ ] Error handling tested (invalid settings, network issues)
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
### ✅ DO:
|
|
|
|
1. **Use meaningful defaults**
|
|
```bash
|
|
var_cpu="2" # ✅ Good: Typical workload
|
|
var_cpu="128" # ❌ Bad: Unrealistic
|
|
```
|
|
|
|
2. **Implement version tracking**
|
|
```bash
|
|
echo "${RELEASE}" > /opt/${APP}_version.txt # ✅ Good
|
|
# ❌ Bad: No version tracking
|
|
```
|
|
|
|
3. **Handle edge cases**
|
|
```bash
|
|
if [[ ! -f /opt/${APP}_version.txt ]]; then
|
|
msg_info "First installation detected"
|
|
fi
|
|
```
|
|
|
|
4. **Use proper messaging**
|
|
```bash
|
|
msg_info "Updating..." # ✅ Good: Clear status
|
|
echo "Updating..." # ❌ Bad: No formatting
|
|
```
|
|
|
|
### ❌ DON'T:
|
|
|
|
1. **Hardcode versions**
|
|
```bash
|
|
RELEASE="1.2.3" # ❌ Bad: Won't auto-update
|
|
```
|
|
|
|
2. **Use custom color codes**
|
|
```bash
|
|
echo -e "\033[32mSuccess" # ❌ Bad: Use $GN instead
|
|
```
|
|
|
|
3. **Forget error handling**
|
|
```bash
|
|
wget file.zip # ❌ Bad: No error check
|
|
if ! wget -q file.zip; then # ✅ Good
|
|
msg_error "Download failed"
|
|
fi
|
|
```
|
|
|
|
4. **Leave temporary files**
|
|
```bash
|
|
rm -rf /opt/file.zip # ✅ Always cleanup
|
|
```
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [install/AppName-install.sh Guide](UPDATED_APP-install.md)
|
|
- [build.func Wiki](../misc/build.func.md)
|
|
- [tools.func Wiki](../misc/tools.func.md)
|
|
- [Defaults System Guide](../DEFAULTS_SYSTEM_GUIDE.md)
|
|
|
|
---
|
|
|
|
**Last Updated**: December 2025
|
|
**Compatibility**: ProxmoxVED with build.func v3+
|
|
**Questions?** Open an issue in the repository
|