Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# --- [API]: Root
.env
.env.production
database/infra/data
tmp

# --- [API]: Storage
Expand Down
4 changes: 3 additions & 1 deletion config/makefile/app.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ format:
gofmt -w -s .

fresh:
rm -rf $(DB_INFRA_DATA_PATH) && \
docker compose down --remove-orphans && \
docker container prune -f && \
docker image prune -f && \
docker volume prune -f && \
docker network prune -f && \
docker system prune -a --volumes -f && \
docker ps -aq | xargs --no-run-if-empty docker stop && \
docker ps -aq | xargs --no-run-if-empty docker rm && \
Comment on lines +12 to +14
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix the order of Docker cleanup operations and reduce redundancy.

The current sequence has several issues:

  1. Incorrect order: Lines 13-14 attempt to stop/remove containers AFTER docker system prune has already run, making them redundant or potentially problematic.

  2. Redundancy: docker system prune -a --volumes -f already handles most cleanup that the individual prune commands (lines 8-11) perform.

  3. Safety concern: These commands affect ALL Docker resources system-wide, not just project-related ones.

Consider this improved sequence:

 fresh:
 	docker compose down --remove-orphans && \
-	docker container prune -f && \
-	docker image prune -f && \
-	docker volume prune -f && \
-	docker network prune -f && \
-	docker system prune -a --volumes -f && \
-	docker ps -aq | xargs --no-run-if-empty docker stop && \
-	docker ps -aq | xargs --no-run-if-empty docker rm && \
+	docker system prune -a --volumes -f && \
 	docker ps

This simplified version:

  • Removes redundant individual prune commands
  • Eliminates the problematic container stop/remove operations that run after system prune
  • Maintains the comprehensive cleanup while being more logical and safe
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
docker system prune -a --volumes -f && \
docker ps -aq | xargs --no-run-if-empty docker stop && \
docker ps -aq | xargs --no-run-if-empty docker rm && \
fresh:
docker compose down --remove-orphans && \
docker system prune -a --volumes -f && \
docker ps
🤖 Prompt for AI Agents
In config/makefile/app.mk around lines 12 to 14, reorder the Docker cleanup
commands to run container stop and remove operations before running docker
system prune, as the current order makes stopping/removing containers redundant
and ineffective. Remove redundant individual prune commands from earlier lines
since docker system prune -a --volumes -f already covers them. Adjust the
sequence to first stop and remove containers safely, then run system prune for
comprehensive cleanup, ensuring the commands target only project-related
resources if possible to avoid affecting the entire Docker system.

docker ps

audit:
Expand Down
83 changes: 33 additions & 50 deletions config/makefile/db.mk
Original file line number Diff line number Diff line change
@@ -1,83 +1,66 @@
# --- Metadata
.PHONY: db\:local db\:up db\:ping db\:bash db\:fresh db\:logs
.PHONY: db\:delete db\:secure db\:secure\:show db\:chmod db\:seed
.PHONY: db\:migrate db\:rollback db\:migrate\:create db\:migrate\:force
.PHONY: db\:sh db\:up db\:down db\:logs db\:bash db\:fresh
.PHONY: db\:secure db\:seed db\:migrate db\:migrate\:create db\:migrate\:force db\:rollback

# --- Docker
DB_DOCKER_SERVICE_NAME := "api-db"
# --- Docker Services
DB_DOCKER_SERVICE_NAME := api-db
DB_DOCKER_CONTAINER_NAME := oullin_db
DB_MIGRATE_SERVICE_NAME := api-db-migrate

# --- Paths
# Define root paths for clarity. Assume ROOT_PATH is exported or defined.
DB_SEEDER_ROOT_PATH := $(ROOT_PATH)/database/seeder
DB_INFRA_ROOT_PATH := $(ROOT_PATH)/database/infra
DB_INFRA_SSL_PATH := $(DB_INFRA_ROOT_PATH)/ssl
DB_INFRA_DATA_PATH := $(DB_INFRA_ROOT_PATH)/data
DB_INFRA_SCRIPTS_PATH := $(DB_INFRA_ROOT_PATH)/scripts

# --- SSL
# --- SSL Certificate Files
DB_INFRA_SERVER_CRT := $(DB_INFRA_SSL_PATH)/server.crt
DB_INFRA_SERVER_CSR := $(DB_INFRA_SSL_PATH)/server.csr
DB_INFRA_SERVER_KEY := $(DB_INFRA_SSL_PATH)/server.key

# --- Migrations
DB_MIGRATE_PATH := $(DB_INFRA_ROOT_PATH)/migrations
DB_MIGRATE_VOL_MAP := $(DB_MIGRATE_PATH):$(DB_MIGRATE_PATH)

db\:local:
# --- Works with your local PG installation.
cd $(EN_DB_BIN_DIR) && \
./psql -h $(ENV_DB_HOST) -U $(ENV_DB_USER_NAME) -d $(ENV_DB_DATABASE_NAME) -p $(ENV_DB_PORT)

db\:seed:
go run $(DB_SEEDER_ROOT_PATH)/main.go
db\:sh:
chmod +x $(DB_INFRA_SCRIPTS_PATH)/healthcheck.sh
chmod +x $(DB_INFRA_SCRIPTS_PATH)/run-migration.sh

db\:up:
docker compose up $(DB_DOCKER_SERVICE_NAME) -d && \
make db:logs
docker compose up $(DB_DOCKER_SERVICE_NAME) -d

db\:down:
docker compose stop $(DB_DOCKER_SERVICE_NAME)

db\:ping:
docker port $(DB_DOCKER_CONTAINER_NAME)
db\:logs:
docker logs -f $(DB_DOCKER_CONTAINER_NAME)

db\:bash:
docker exec -it $(DB_DOCKER_CONTAINER_NAME) bash

db\:fresh:
make db:delete && make db:up

db\:logs:
docker logs -f $(DB_DOCKER_CONTAINER_NAME)
make db:delete
make db:up

db\:delete:
docker compose down $(DB_DOCKER_SERVICE_NAME) --remove-orphans && \
sudo rm -rf $(DB_INFRA_DATA_PATH) && \
docker ps
docker compose down -v --remove-orphans

db\:secure:
rm -rf $(DB_INFRA_SERVER_CRT) && rm -rf $(DB_INFRA_SERVER_CSR) && rm -rf $(DB_INFRA_SERVER_KEY) && \
openssl genpkey -algorithm RSA -out $(DB_INFRA_SERVER_KEY) && \
openssl req -new -key $(DB_INFRA_SERVER_KEY) -out $(DB_INFRA_SERVER_CSR) && \
openssl x509 -req -days 365 -in $(DB_INFRA_SERVER_CSR) -signkey $(DB_INFRA_SERVER_KEY) -out $(DB_INFRA_SERVER_CRT) && \
make db:chmod

db\:chmod:
sudo chmod 600 $(DB_INFRA_SERVER_KEY) && sudo chmod 644 $(DB_INFRA_SERVER_CRT)
rm -f $(DB_INFRA_SERVER_CRT) $(DB_INFRA_SERVER_CSR) $(DB_INFRA_SERVER_KEY)
openssl genpkey -algorithm RSA -out $(DB_INFRA_SERVER_KEY)
openssl req -new -key $(DB_INFRA_SERVER_KEY) -out $(DB_INFRA_SERVER_CSR) -subj "/CN=oullin-db-ssl"
openssl x509 -req -days 365 -in $(DB_INFRA_SERVER_CSR) -signkey $(DB_INFRA_SERVER_KEY) -out $(DB_INFRA_SERVER_CRT)

db\:secure\:show:
docker exec -it $(DB_DOCKER_CONTAINER_NAME) ls -l /etc/ssl/private/server.key && \
docker exec -it $(DB_DOCKER_CONTAINER_NAME) ls -l /etc/ssl/certs/server.crt
db\:seed:
go run $(DB_SEEDER_ROOT_PATH)/main.go

# -------------------------------------------------------------------------------------------------------------------- #
# --- Migrations
# -------------------------------------------------------------------------------------------------------------------- #
db\:migrate:
@printf "\n$(BLUE)[DB]$(NC) Migration has started.\n"
@docker run -v $(DB_MIGRATE_VOL_MAP) --network $(ROOT_NETWORK) migrate/migrate -verbose -path=$(DB_MIGRATE_PATH) -database $(ENV_DB_URL) up
@printf "$(GREEN)[DB]$(NC) Migration has finished.\n\n"
docker-compose run --rm $(DB_MIGRATE_SERVICE_NAME) up

db\:rollback:
@printf "\n$(RED)[DB]$(NC) Migration rollback has started.\n"
@docker run -v $(DB_MIGRATE_VOL_MAP) --network $(ROOT_NETWORK) migrate/migrate -verbose -path=$(DB_MIGRATE_PATH) -database $(ENV_DB_URL) down 1
@printf "$(GREEN)[DB]$(NC) Migration rollback has finished.\n\n"
docker-compose run --rm $(DB_MIGRATE_SERVICE_NAME) down 1

# --- Migrations
db\:migrate\:create:
docker run -v $(DB_MIGRATE_VOL_MAP) --network $(ROOT_NETWORK) migrate/migrate create -ext sql -dir $(DB_MIGRATE_PATH) -seq $(name)
docker-compose run --rm $(DB_MIGRATE_SERVICE_NAME) create -ext sql -dir /migrations -seq $(name)

db\:migrate\:force:
docker run -v $(DB_MIGRATE_VOL_MAP) --network $(ROOT_NETWORK) migrate/migrate migrate -path $(DB_MIGRATE_PATH) -database $(ENV_DB_URL) force $(version)
docker-compose run --rm $(DB_MIGRATE_SERVICE_NAME) force $(version)
6 changes: 0 additions & 6 deletions config/makefile/infra.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,19 @@
___API__SUPERVISOR := oullin-api

supv\:api\:status:
@printf "\n$(YELLOW)[supervisor]$(NC) - $(CYAN)$(___API__SUPERVISOR) status.$(NC)"
@sudo supervisorctl status $(___API__SUPERVISOR)

supv\:api\:start:
@printf "\n$(YELLOW)[supervisor]$(NC) - $(CYAN)$(___API__SUPERVISOR) start command sent.$(NC)"
@sudo supervisorctl start $(___API__SUPERVISOR)

supv\:api\:stop:
@printf "\n$(YELLOW)[supervisor]$(NC) - $(CYAN)$(___API__SUPERVISOR) stop command sent.$(NC)"
@sudo supervisorctl stop $(___API__SUPERVISOR)

supv\:api\:restart:
@printf "\n$(YELLOW)[supervisor]$(NC) - $(CYAN)$(___API__SUPERVISOR) restart command sent.$(NC)"
@sudo supervisorctl restart $(___API__SUPERVISOR)

supv\:api\:logs:
@printf "\n$(YELLOW)[supervisor]$(NC) - $(CYAN)$(___API__SUPERVISOR) logs. (Press Ctrl+C to exit)$(NC)"
@sudo tail -f /var/log/supervisor/$(___API__SUPERVISOR).log

supv\:api\:logs-err:
@printf "\n$(YELLOW)[supervisor]$(NC) - $(CYAN)$(___API__SUPERVISOR) error logs. (Press Ctrl+C to exit)$(NC)"
@sudo tail -f /var/log/supervisor/$(___API__SUPERVISOR).err.log
41 changes: 0 additions & 41 deletions database/infra/docker-entrypoint-initdb.d/init-user-db.sh

This file was deleted.

19 changes: 19 additions & 0 deletions database/infra/scripts/healthcheck.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/sh

# Exit immediately if any command fails.
set -e

# Read the secrets into variables. This is more robust than direct command substitution.
DB_USER=$(cat /run/secrets/postgres_user)
DB_NAME=$(cat /run/secrets/postgres_db)

# Explicitly check if the user variable is empty. If it is, fail immediately.
# This prevents the "role -d does not exist" error.
if [ -z "$DB_USER" ]; then
echo "Healthcheck Error: The postgres_user secret is empty or could not be read." >&2
exit 1
fi

# Execute the final command. 'exec' replaces the shell process, which is slightly more efficient.
# The variables are double-quoted to handle any special characters safely.
exec pg_isready -U "$DB_USER" -d "$DB_NAME"
16 changes: 16 additions & 0 deletions database/infra/scripts/run-migration.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

# Exit immediately if a command exits with a non-zero status.
set -e

# Read the credentials from the Docker Secret files
DB_USER=$(cat /run/secrets/postgres_user)
DB_PASSWORD=$(cat /run/secrets/postgres_password)
DB_NAME=$(cat /run/secrets/postgres_db)

# Construct the database URL using the values from the secrets
DATABASE_URL="postgres://${DB_USER}:${DB_PASSWORD}@api-db:5432/${DB_NAME}?sslmode=disable"

# Execute the migrate tool, passing the constructed URL and any other arguments
# The "$@" passes along any arguments from the docker-compose command (like "up", "down 1", etc.)
migrate -path /migrations -database "${DATABASE_URL}" "$@"
1 change: 1 addition & 0 deletions database/infra/secrets/postgres_db
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
oullin_db
1 change: 1 addition & 0 deletions database/infra/secrets/postgres_password
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
gocanto-password
1 change: 1 addition & 0 deletions database/infra/secrets/postgres_user
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
gocanto-user
35 changes: 16 additions & 19 deletions database/infra/ssl/server.crt
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgIUWxAMKcyluk3SNEt4TcADDjHJXkIwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCU0cxEjAQBgNVBAgMCVNpbmdhcG9yZTESMBAGA1UEBwwJ
U2luZ2Fwb3JlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcN
MjUwNjEyMDU0MDU5WhcNMjYwNjEyMDU0MDU5WjBYMQswCQYDVQQGEwJTRzESMBAG
A1UECAwJU2luZ2Fwb3JlMRIwEAYDVQQHDAlTaW5nYXBvcmUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAMTiv4dRLuAQxDTnqGpNsbzVcpURFQVVPrMHh0NErl+2lFJX0TsFT+RH
yZ7vLHIdDZml+q20wcjSufme1o9N6xfQgulR/gIC2+23nRZm346Djeln8jrKXuhc
hqJvXJ5kJHohqvqakJcZr917dCPgAj8+Oi1b0bqKvc9EFmj/13E1CNg/93SZMZ/b
5sKsb5lLnrFrPj3zOQ00s8nsHbKcgroQqn2/+fuB+VsqvWIOPvc3hp+LNW3oKB87
SZoup8BcimFt0010dHW01mnUwEyWQKYbAW3Xo7VIG8nXlrYdnVxrTFMLFfIH4ovy
9/IcpQLjY8kThDOJpFMnlEEjsZM4b88CAwEAAaMhMB8wHQYDVR0OBBYEFDnRqEBr
jtJNNQ5Q64hJI2NrAEGvMA0GCSqGSIb3DQEBCwUAA4IBAQBdEYLNEA2hC63zu8Mw
n3LFU2xqFhSSB9HtsevEg7aurK8vVMCgsB6leqAIIw+/6eOyjz68qi587LijhrNU
Lgr91uNjTG2p0XFey/y3BdAQUQDE5Cq5rjiMRjFdVQ2U6rZ7htgN34vbfarMTNTc
o+Wp3qQMRYupN6dQfQBNRZRCtGYmgr/TD57l8nq2vAD0EOZGyDI3dFIOX0n5Rgtw
0KPf1ETRtmIF5Mvu8sRwwBhwyCML51w96nl6LTafe3aWPiA+s2lNrjTYeo5Fo1OW
U3cmz6QU2V7g3D66Q/uR41j31vXD/YmdP/4rMPs4HMh6czQe2lX0AbQt2gsZOMLH
nMMy
MIIC3zCCAcegAwIBAgIUXlaSxCWlFCDRoFRl/8l3DMcjpdMwDQYJKoZIhvcNAQEL
BQAwGDEWMBQGA1UEAwwNb3VsbGluLWRiLXNzbDAeFw0yNTA2MjcwODQ4MjZaFw0y
NjA2MjcwODQ4MjZaMBgxFjAUBgNVBAMMDW91bGxpbi1kYi1zc2wwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3cPhltyNaQs4WMcZI7iAwwCGvJpqVp2dh
kcAnpiAaMmDrZ9h9UmjuykbsLZ3RX8FCg24x8+9SxQ74hQCMxvteXzLxLiafA2Js
OZxo5525oF6n3aQ4XLzgGChGN03DkwbUfSVsDknUGckgYEF5tWwxFsIj1dqUD7YK
uf181DgNBu2i65nJVFykprSgteGWhYX5j+LJLf6zMgdtoSwQEhpw+BmJhpFDtyOm
YzkZ/FBMqAwXMwcBXuwodQS9jju4JVrX/weJaO8NPKkQUuPVsWoe42KRyax8Fl7J
As9vdGEmNiR8mHjefmXQ9du/ZFK5x8lGgsC2w1Xxz9KMmKRK+nLlAgMBAAGjITAf
MB0GA1UdDgQWBBRAGDkpPnop/4bkOuQWGtmKPbFQ9zANBgkqhkiG9w0BAQsFAAOC
AQEAD/KdBU3KRNUc5nuDAt1f8A0lyfiWLI3oDzKzHrQJcBiIq6Pr13Bm0AR8iE7N
W/kae4P6jMHkT59G+rY5oyyiUZVd2MRTIAoOxygZKWYxhY8/w2pysEvRwt9K0EUE
L7DmUA6Ej9TpaoqsJxXudvIj0yYEAivGbX2bwUjYQ7e/ZEPiOWZuG59WxEpOOvYa
ArcwuDJWLy7PQGrYPemq3+5CWK8J90Bbfo+XaMoxwxoJeQfsi5Rv7h1mgoQw/0Sq
3rE6AGABB1qITaiNeEs7R70usZRbD/0vp7LCjTDWcB+57CyYH0XyroZMjB6ppZaA
S5KG2GORDjqu+CKJjn2ne0YxWQ==
-----END CERTIFICATE-----
28 changes: 13 additions & 15 deletions database/infra/ssl/server.csr
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICnTCCAYUCAQAwWDELMAkGA1UEBhMCU0cxEjAQBgNVBAgMCVNpbmdhcG9yZTES
MBAGA1UEBwwJU2luZ2Fwb3JlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0
eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDE4r+HUS7gEMQ0
56hqTbG81XKVERUFVT6zB4dDRK5ftpRSV9E7BU/kR8me7yxyHQ2ZpfqttMHI0rn5
ntaPTesX0ILpUf4CAtvtt50WZt+Og43pZ/I6yl7oXIaib1yeZCR6Iar6mpCXGa/d
e3Qj4AI/PjotW9G6ir3PRBZo/9dxNQjYP/d0mTGf2+bCrG+ZS56xaz498zkNNLPJ
7B2ynIK6EKp9v/n7gflbKr1iDj73N4afizVt6CgfO0maLqfAXIphbdNNdHR1tNZp
1MBMlkCmGwFt16O1SBvJ15a2HZ1ca0xTCxXyB+KL8vfyHKUC42PJE4QziaRTJ5RB
I7GTOG/PAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAw3nsoZiDVo7JxZu3fopX
7Ms/mV+BC9eEchwfxoYb5wxP3N59FJyeD6EgBXl95D+64JYUPN3eJKR8y5oZdmPb
I+W8zsYR2j49KYl4ml5enP516LG4eeraoHxYk8P/4ediOpNqHqi5cSx8S2/WCs8E
zXj36eVgJ5JkvRqRIVJwN97GM25/jkRYKd7bgDS/rsZrx4GZ9zjtHwNWO2cqGlNR
uTcxZmq6rDwFY9y6OAyB7C+7RdtbpX7tWVLVEg/Jhe18nR6fBYuo7WQzM6TUt/B7
IZsABy6wllGEq3TpKJcfgJWQfO97kiS5BQM9AKGsViPEa/XyKxX+5JbHliQ3K9ci
oA==
MIICXTCCAUUCAQAwGDEWMBQGA1UEAwwNb3VsbGluLWRiLXNzbDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBALdw+GW3I1pCzhYxxkjuIDDAIa8mmpWnZ2GR
wCemIBoyYOtn2H1SaO7KRuwtndFfwUKDbjHz71LFDviFAIzG+15fMvEuJp8DYmw5
nGjnnbmgXqfdpDhcvOAYKEY3TcOTBtR9JWwOSdQZySBgQXm1bDEWwiPV2pQPtgq5
/XzUOA0G7aLrmclUXKSmtKC14ZaFhfmP4skt/rMyB22hLBASGnD4GYmGkUO3I6Zj
ORn8UEyoDBczBwFe7Ch1BL2OO7glWtf/B4lo7w08qRBS49Wxah7jYpHJrHwWXskC
z290YSY2JHyYeN5+ZdD1279kUrnHyUaCwLbDVfHP0oyYpEr6cuUCAwEAAaAAMA0G
CSqGSIb3DQEBCwUAA4IBAQAAxwg4Y2e16tACOm4iFETAkT7zhmZHG3zWiXPrTM5a
kSGGbQNkbpCqBxB+8V6PEXOUVI7CwSz7O/qq46Y4Py+qHwjhH2NKSUiXuAne92Z7
FKawYaK8LLafISZrGl/FfUE9wIyILnYfKl/RJa21Rj66nZlUfbVhA8NfIeHHz5Am
Gma8LEkhPt4cX6fdEsw6fsyGOpxc3WAoEk73p0AjahvnyS5MFINasftvdAs1H8ef
8wgIQbVblS+NSwcDc3hnSsm9itdcmzG6hpyD1aaJkX7Y/+zWJnhyW6EEVPJWGqNj
c4ENieqTtCOWKG1fV/tRd2UpGT2T95+2JpJISD26TPcJ
-----END CERTIFICATE REQUEST-----
52 changes: 26 additions & 26 deletions database/infra/ssl/server.key
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDE4r+HUS7gEMQ0
56hqTbG81XKVERUFVT6zB4dDRK5ftpRSV9E7BU/kR8me7yxyHQ2ZpfqttMHI0rn5
ntaPTesX0ILpUf4CAtvtt50WZt+Og43pZ/I6yl7oXIaib1yeZCR6Iar6mpCXGa/d
e3Qj4AI/PjotW9G6ir3PRBZo/9dxNQjYP/d0mTGf2+bCrG+ZS56xaz498zkNNLPJ
7B2ynIK6EKp9v/n7gflbKr1iDj73N4afizVt6CgfO0maLqfAXIphbdNNdHR1tNZp
1MBMlkCmGwFt16O1SBvJ15a2HZ1ca0xTCxXyB+KL8vfyHKUC42PJE4QziaRTJ5RB
I7GTOG/PAgMBAAECggEAPQPgQzk/g6TuiU65fKgzSsgDSHsQvqRaV/UfUBN6zqKw
eIxKhTXyOlac/yoz5fFnA5TSiP6Zh3j2tYsqByMolirCRzhntYvZSGQ8xHKBGZNf
aVQTV3Db1LrH5pMIavWx8D9600sPQCRvwf2+UlfbmmnYcbIg3uScSh1ZrJSM2cIA
lifcZfkBlN4/Z7dm09XHcM9+tTmMvc+L5DwYjvmRhNByoFJ0w4kAgDA5I9YTL1mh
TP7u4ABEt2QG4Yic4T1o0pc/dbSGqCYSdizyow6ybtUCScIp1kOKZNdLt8PX+E2m
ZrOVIUHiLdJhwogmGXWXV/emV49j8CuA0sD/5TNEAQKBgQDmnKgBut406Ef7enld
jE1baq5YnZsIUI+ex7b+2Um9ivQS0HXF27mZ6uK6wCknWU8D4wZ0oo8bRUUnwAir
+CTX0e5RJ7AJRFWRtsQNCGUyRR0gANEQ4mE2fzmKdqkGiXFUKV++1EFax4UZ9LnP
UyPI0GKoMJL2zrC6c4aZYSJVAQKBgQDaj5XPYmNKL82LQqsipeeowugpgXwwixRv
YvX2GOZDbVqQW0U/uHPyUWQNK0uUiTOAAYNrLALM3+bGwF2deeOF48WQdFHJpLhz
daNBstfsM3iI4ZzgT8vjZV5JXfBetNsuFLh5+FopsKh1b3v8T+Gtm02hw1BHH3un
OuxYH7G0zwKBgQC4ZkOhPn835xTH7aLmPq4Mjz1h9oRlHaX53NBi7/Sa72VDNhU2
ZQAAJ2Ws1sMRh8Q642niEapEsBsgMdm9SOqM+HyLwCRvBIk3vuD9Wt0wWTt0v7Js
wdfh79Fe+oslgvlvxrWcrbSkli3EF4AMW/qdNKPuwQiC+bsvG/lg497EAQKBgQCO
qU6mMZiR4iYOkpPWZ+iQtbiI7yY7IW1TT4sw+gvDU2vb8ld/Qk0cjJf8KJiK+guN
sG8x02Z4iGXAsevpUJh82rIommSQdF6Zrt3DkpNycB5raqjVmgCCC7bBuPmfN/oh
WBEaPEvODqvHC+AoT5QFl+vSfQS3iAtUmxeOZhG+7QKBgQC2JBiOMKQOW0rYsM1l
Ujx1uBXDM7QQCWHsUN10PHAnveQIcI1isqEv0/3ORqEygex28pcVoyiAedOXqbxK
cvUVx4rq59UZZNAMnHDu9Dm51oREznpIfbJuAMHWaWrx0pxoTnC7ofDw7gt7GphX
FEnxdXYANHYh0S2EiXIsS8oNlA==
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3cPhltyNaQs4W
McZI7iAwwCGvJpqVp2dhkcAnpiAaMmDrZ9h9UmjuykbsLZ3RX8FCg24x8+9SxQ74
hQCMxvteXzLxLiafA2JsOZxo5525oF6n3aQ4XLzgGChGN03DkwbUfSVsDknUGckg
YEF5tWwxFsIj1dqUD7YKuf181DgNBu2i65nJVFykprSgteGWhYX5j+LJLf6zMgdt
oSwQEhpw+BmJhpFDtyOmYzkZ/FBMqAwXMwcBXuwodQS9jju4JVrX/weJaO8NPKkQ
UuPVsWoe42KRyax8Fl7JAs9vdGEmNiR8mHjefmXQ9du/ZFK5x8lGgsC2w1Xxz9KM
mKRK+nLlAgMBAAECggEAF5wnrFfE6hIdGkgvwCU96WhhLXzneomASdOLis7b5ONF
DCdiesbHkKxiMnWwkUkkw53M6gr+a4XHZn8f0f6uTbgtA1OwTtkNquZDVlExQLn+
VNa3EzYEbUdOr7LghGKBB4pP7bdtEyp6c3tQEg0irrLCLACTUGkxQfIsSQu7Zxmb
qWjMPDNX3llG8Fe5m87O1Kn4UoHzksgZHTzo+1dioRDITqYpUMPWI498TgdXlf7u
ayzH8mr65eGs4kQuzBxvYP0rRl0mlWU5TGQvVFDDr1KlLvPVzGz3PEdNjpac9l+O
q4LJ5MhW5DvWr4gxvrtqcl0/q/Zc8yqcblamTXQ0QQKBgQD+4aLQH1NRG7yxon7U
xVyQXPmsrx+AGz15JW+PztlclzpN7/0Pl38hh+kMugeKHfK0wFcgmBupvR10RvG4
EoMAHO6Y4FadNRkXstu4Lxm1oDNqjMnZzWP8odDY5jfRkroAOa5ttgbigXp3h28c
ouR0Zzyr9EstwTTimWF9VGUstQKBgQC4PxHtHNR1jkgWTpdhsGZl87oVy5BbymBM
7cf8k8MEEO9gHkXMH3O9Td1Ue0gYipd25lixx1lf9CvtsxDnTn45Lm/vU77cClfe
pa7mrlQ1Db76ASTywRDIB513ftJKKqvpKxsq4vV5ZilUB+r5msh3cnqtFBvtQ9R2
VxgN+3Q7cQKBgQCEXcPDF/GZ9rCpA72gXBq1MkPLxWqzifID30gvw/moFzWFUjP3
C/NPA5kpLddKiEEKU7UrzTLYlMkeINXZhWuY/G2A4Ui5/eBZKV7oKTXN2DO7iwAs
53ics6CVdAHbCbsk8M/AVD8BFML4HlK66XGBbjfZCVadnXAMmiFCCDk+3QKBgFf+
p00ba80JOxyMRHh/iyg+Ey29nyB3sy6KkezrlUQn4muBicxHaTuMKJzklDZEWrqK
oOmnT+Qn9aL81qHiNx6QMx2WXZ0xw22uq624rLb57a/xQ/g8hQtDt80OYNjTMG+Y
Cs2cv6hPRoW/klXLutpxbm2jIQNcVeh/CBoFcinBAoGACQfApcPTA05j8WXfIpla
VR+lpN9msvArCw3XPkwOMvVGATpTckvutC3wo6QnRaTrlXm1q26hcmElb4Sd32Xn
KxQt2QpHTfsqi3in/kuqZAKl4l+Ah1Qt5++pTJ8o2bsRA9fqkWr2dSyCB3E3IjbJ
R3uIEjvEUKqYUCu8SoEQhm4=
-----END PRIVATE KEY-----
Loading
Loading