Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deploy the app #511

Merged
merged 108 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 74 commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
b7b9a63
chore(client): bootstrap client application (#506)
umitcan07 Oct 11, 2024
d61e1c3
feat(client): implement login page and routing (#508)
hks1444 Oct 11, 2024
55ab5a1
feat(be): implement token obtain pair (login) and register endopints …
MucahitErdoganUnlu Oct 13, 2024
b06ae04
chore(mobile): bootstrap mobile app (#522)
Meminseeker Oct 13, 2024
b14955c
fix(be): remove cache from git
MucahitErdoganUnlu Oct 13, 2024
1cb4157
fix(be): add pycache from migrations folder to gitignore
MucahitErdoganUnlu Oct 13, 2024
cfc8990
feat(be): add username, full_name, and email fields to token view res…
MucahitErdoganUnlu Oct 13, 2024
1b744d7
feat(mobile): add auth context (#523)
Meminseeker Oct 14, 2024
33e2fda
feat(client): implement register page and routing (#512)
umitcan07 Oct 14, 2024
a048a8d
w3c(client): add relevant aria attributes to toast modal (#530)
umitcan07 Oct 14, 2024
4d2ad88
fix(be): change paths of login and register endpoints to /auth/
MucahitErdoganUnlu Oct 14, 2024
7a7a96d
docs(be): add /swagger.yaml/ path to generate yaml file for swagger d…
MucahitErdoganUnlu Oct 14, 2024
4f20d0e
docs(be): add swagger.yaml file that contains /auth/ and /token/ paths
MucahitErdoganUnlu Oct 14, 2024
26c74d1
feat(client): implement logger utility (#531)
hks1444 Oct 15, 2024
fd7f9b6
chore(mobile): remove unnecessary .idea files
Meminseeker Oct 15, 2024
eecc9de
chore(mobile): update .gitignore
Meminseeker Oct 15, 2024
5d8c6d0
feat(client): implement quizzes route & msw (#540)
umitcan07 Oct 16, 2024
241da4f
chore(mobile): implement mock server for forum pages (#542)
Meminseeker Oct 17, 2024
c9dda0b
feat(devops): add Dockerfile and update settings.py
ozankrkya Oct 18, 2024
61af956
feat(devops): add wait-for-it.sh script and docker-compose.yml
ozankrkya Oct 18, 2024
175a137
[wip]feat(devops): Add Dockerfile for client containerization
ozankrkya Oct 18, 2024
561c201
feat(devops): update Dockerfile and dependencies
Meminseeker Oct 18, 2024
52600f7
feat(devops): Update Dockerfile and docker-compose.yml for client ser…
ozankrkya Oct 18, 2024
9b0ca00
feat(devops): Add nginx container and configuration
ozankrkya Oct 18, 2024
7ff3cd3
chore(devops): build client app
Meminseeker Oct 18, 2024
fafee2a
feat(devops): dockerize application (#555)
ozankrkya Oct 19, 2024
9f19159
feat(devops): add nginx Dockerfile
Meminseeker Oct 19, 2024
9ca7dd6
feat(devops): add docker-compose.dev.yml for development environment …
Meminseeker Oct 19, 2024
dbebe7d
feat(devops): add AWS Dev deployment workflow for GitHub Actions
Meminseeker Oct 19, 2024
3281dfc
refactor(devops): refactor GitHub Actions secrets
Meminseeker Oct 19, 2024
d25717d
feat(client): add quizzes route and page & more configuration through…
umitcan07 Oct 19, 2024
b5219fa
feat(client): implement quiz id route (#548)
hks1444 Oct 19, 2024
a63875b
chore(client): configure project and meta tags (#557)
umitcan07 Oct 19, 2024
ff89730
refactor(devops): update client build command in docker-compose.dev.yml
Meminseeker Oct 19, 2024
b22071f
feat(client): generate mock data for quizzes (#560)
hks1444 Oct 19, 2024
40ddf73
des(client): improve design, add necessary components (#558)
umitcan07 Oct 19, 2024
2202872
chore(gitignore): update gitignore file
Meminseeker Oct 19, 2024
6c72b9c
fix(devops): fix docker-compose.dev.yml for development environment
Meminseeker Oct 19, 2024
89f213e
fix(devops): update aws.dev.yml build command
Meminseeker Oct 19, 2024
dc5cfd6
feat(be): implement forum-question endpoint and tagging endpoint (#546)
MucahitErdoganUnlu Oct 19, 2024
6f62acb
chore(devops): update .gitignore file
Meminseeker Oct 20, 2024
4e5ad73
chore(devops): update ALLOWED_HOSTS in settings.py to be set by .env …
Meminseeker Oct 20, 2024
5e1c694
feat(devops): Add Makefile for development environment setup with Doc…
Meminseeker Oct 20, 2024
cff8f91
feat(devops): Add dev-deploy target to Makefile
Meminseeker Oct 20, 2024
a7c7a07
Merge branch 'development' into devops
Meminseeker Oct 20, 2024
43f48b1
feat(mobile): implement forumQuestionDetail screen and enhance forum …
Meminseeker Oct 20, 2024
35ea2cb
chore(mobile): add prettier as a dev dependency for mobile applicatio…
Meminseeker Oct 20, 2024
e4da6ba
feat(mobile): implement CreateQuestion on forum screen (#576)
yunuskaydin Oct 20, 2024
ebe40d4
des(client): refine quiz card, quiz page, page heads, router (#572)
umitcan07 Oct 20, 2024
65ca0f6
feat(client): add quiz start screen, timer, progress bar and overall …
umitcan07 Oct 21, 2024
3ac57e7
feat(client): add a simple leaderboard table (#579)
umitcan07 Oct 21, 2024
bcf51c6
chore(mobile): update .gitignore to temporarily ignore some newly cre…
Meminseeker Oct 21, 2024
8116941
Merge branch 'development' into devops
Meminseeker Oct 21, 2024
c2bc647
Merge pull request #570 from bounswe/devops
ozankrkya Oct 21, 2024
d6f696c
feat(mobile): build mobile app (#580)
Meminseeker Oct 21, 2024
caff62a
fix(client): prevent id duplication (#581)
umitcan07 Oct 21, 2024
e80b560
feat(client): refine leaderboard (#582)
umitcan07 Oct 21, 2024
9156f7d
fix(be): extend the expiration of jwt token
MucahitErdoganUnlu Oct 21, 2024
ecb6ccb
update(be): update forum-question fields to mock question metadata su…
MucahitErdoganUnlu Oct 21, 2024
e65d8ec
docs(be): update swagger.yaml to include forum question mock meta data
MucahitErdoganUnlu Oct 21, 2024
0844c8a
feat(be): add random avatar generation for users
MucahitErdoganUnlu Oct 21, 2024
a81d383
feat(client): add content to home and refine leaderboard data & desig…
umitcan07 Oct 21, 2024
b95c20b
feat(mobile): update navigation and add Register screen (#585)
yunuskaydin Oct 21, 2024
fe39cb3
feat(mobile): add bottom Tab (#584)
yunuskaydin Oct 21, 2024
d95f902
chore(client): add more mock data to home and changed names on the l…
hks1444 Oct 21, 2024
36ccf31
feat(mobile): connect mobile to backend and implement tagging for for…
Meminseeker Oct 21, 2024
84aa9e3
feat(devops): add prod-mobile target in Makefile for releasing Androi…
Meminseeker Oct 22, 2024
591dc82
chore(mobile): add expo-build-properties plugin for Android app confi…
Meminseeker Oct 22, 2024
3bc41e6
fix(mobile): fix app.json for Android configs
Meminseeker Oct 22, 2024
84d9622
fix(be): add if block to check if the returned box from babelnet pars…
MucahitErdoganUnlu Oct 25, 2024
0f610a7
fix(be): move all backend endpoints to /api/v1/
MucahitErdoganUnlu Oct 25, 2024
ff3d24c
feat(be): add seeder json file for models in backend
MucahitErdoganUnlu Oct 25, 2024
334ec2a
Merge branch 'main' into development
umitcan07 Oct 25, 2024
8c5a3e1
Merge branch 'main' into development
umitcan07 Oct 25, 2024
8751f20
chore: delete redundant files on root
umitcan07 Oct 25, 2024
981bd92
feature(client): implemented forum post feed (#591)
hks1444 Nov 12, 2024
7e21eee
feat(be): implement quiz and rate-quiz CRUD endpoints (#624)
MucahitErdoganUnlu Nov 15, 2024
92c3c58
fix(be): change user field to author in quizSerializer
MucahitErdoganUnlu Nov 15, 2024
d924246
feat(be): implement bookmark functionality for forum questions and tests
ceydanursen Nov 15, 2024
5e2f654
feat(be): add new model QuizQuestionChoice to efficiently handle choi…
MucahitErdoganUnlu Nov 15, 2024
2aeb323
Merge branch 'development' into backend/forum-bookmark
ceydanursen Nov 16, 2024
7d6eeba
resolve(be): resolve conflict on migrations
MucahitErdoganUnlu Nov 16, 2024
8a507b8
feat(be): implement TakeQuiz ModelViewset endpoints. implement unit t…
MucahitErdoganUnlu Nov 16, 2024
88def9b
feat(be): implement forum upvote and downvote endpoints and tests (#641)
meminciftci Nov 16, 2024
6bb9794
feat(be): Implement Forum Answers (#642)
ozankrkya Nov 17, 2024
2ed45c2
feat(be): connect upvote, downvote, bookmark to forum question fields…
Nov 17, 2024
044f827
fix: fix a Docker-compose build error
Meminseeker Nov 18, 2024
a540279
fix(devops): update docker-compose.dev.yml to remove restart on failu…
Meminseeker Nov 18, 2024
ac8c70a
lab(client): lab6 work (#613)
hks1444 Nov 19, 2024
dffb29f
feat(be) prepare at least 1 fixture for each model (#645)
MucahitErdoganUnlu Nov 19, 2024
43a50ab
chore(be): update swagger.yaml
MucahitErdoganUnlu Nov 19, 2024
a0b3774
fix(devops): fix errors preventing Docker builds
Meminseeker Nov 20, 2024
4c3785e
lab: work done for lab7 & forum integration (#646)
umitcan07 Nov 20, 2024
bcac431
Merge branch 'main' into development
umitcan07 Nov 20, 2024
6c186f7
feat(be): implement forum-answer-upvote and downvote (#662)
MucahitErdoganUnlu Nov 20, 2024
3ae6d96
feat(mobile): add Leaderboard Screen (#654)
yunuskaydin Nov 20, 2024
dc10e12
chore(backend): fix forum upvote downvote answer serializers
umitcan07 Nov 20, 2024
a261471
fix(backend): use correct serializer fields
umitcan07 Nov 20, 2024
51695d1
feat(client): implement forum answer posting
umitcan07 Nov 20, 2024
03801b3
feat(client): update swagger to include forum-answer-upvote and downvote
MucahitErdoganUnlu Nov 20, 2024
3b3710f
feat(client): implement forum answer upvote downvote mechanism and in…
umitcan07 Nov 20, 2024
96f4b29
chore(client): dispose mock server
umitcan07 Nov 20, 2024
96ffe25
implement more control for forum pagination and refine questions
umitcan07 Nov 20, 2024
2f054b9
feat(client): implement create a forum question with dummy tags
umitcan07 Nov 20, 2024
a43186f
feat(backend): add is my forum question field to the serializer
umitcan07 Nov 20, 2024
f4b7c6e
fix(client): redirect to forum page upon deleting a forum question
umitcan07 Nov 20, 2024
67feee8
refactor(client, backend): add pagination controls to quiz, refactor …
umitcan07 Nov 20, 2024
01e7cd2
chore(backend): add is my quiz field to the serializer
umitcan07 Nov 20, 2024
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
6 changes: 6 additions & 0 deletions .env.makefile.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
PEM_FILE=<YOUR_PEM_FILE_FOR_SSH&SCP>
SSH_USER=<YOUR_SSH_USER>
SSH_HOST=<YOUR_SSH_HOST>
FILES_TO_COPY="FILE1 FILE2 ... FILEN"
TARGET_DIR=<PROJECT_ROOT_DIR_IN_DEPLOYMENT_SERVER>
ANDROID_DIR=<YOUR_MOBILE_APP_ANDROID_BUILD_DIR>
108 changes: 108 additions & 0 deletions .github/workflows/aws_dev.yml
Copy link
Contributor

Choose a reason for hiding this comment

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

  • This workflow is currently generated for development environment in AWS.
  • It will be re-configured with environment variables and secrets, this version is not completed.
  • Also another workflow will be configured for prod environment.

Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Deploy to AWS Dev (Docker Hub + EC2)

on:
push:
branches: ["development"]

env:
AWS_REGION: ${{ secrets.AWS_REGION }}
CONTAINER_REPOSITORY: ${{ secrets.CONTAINER_REPOSITORY }}
IMAGE_TAG: ${{ github.sha }} #! ??
BACKEND_IMAGE_TAG: ${{ secrets.BACKEND_IMAGE }}
CLIENT_IMAGE_TAG: ${{ secrets.CLIENT_IMAGE }}
NGINX_IMAGE_TAG: ${{ secrets.NGINX_IMAGE }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
PROJECT_DIR: ${{ secrets.PROJECT_DIR }}
MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }}
MYSQL_USER: ${{ secrets.MYSQL_USER }}
MYSQL_PASSWORD: ${{ secrets.MYSQL_PASSWORD }}
DB_NAME: ${{ secrets.DB_NAME }}
DB_HOST: ${{ secrets.DB_HOST }}
DB_PORT: ${{ secrets.DB_PORT }}
CORS_ALLOWED_ORIGINS: ${{ secrets.CORS_ALLOWED_ORIGINS }}
VITE_BACKEND_URL: ${{ secrets.VITE_BACKEND_URL }}
VITE_ENABLE_MOCKS: ${{ secrets.VITE_ENABLE_MOCKS }}
VITE_LOGGING: ${{ secrets.VITE_LOGGING }}

permissions:
contents: read

jobs:
deploy:
name: Deploy to AWS Dev
runs-on: ubuntu-latest
environment: development

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

- name: Login to Docker Hub
id: login-docker-hub
run: |
echo "${{ secrets.DOCKER_HUB_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_HUB_USERNAME }}" --password-stdin

- name: Build, tag, and push images to Docker Hub
id: build-image
run: |
docker-compose -f docker-compose.dev.yml build
docker push $CONTAINER_REPOSITORY:$BACKEND_IMAGE_TAG
docker push $CONTAINER_REPOSITORY:$CLIENT_IMAGE_TAG
docker push $CONTAINER_REPOSITORY:$NGINX_IMAGE_TAG
echo "image=$CONTAINER_REPOSITORY:$BACKEND_IMAGE_TAG" >> $GITHUB_OUTPUT
echo "image=$CONTAINER_REPOSITORY:$CLIENT_IMAGE_TAG" >> $GITHUB_OUTPUT
echo "image=$CONTAINER_REPOSITORY:$NGINX_IMAGE_TAG" >> $GITHUB_OUTPUT

- name: Configure .env.dev file
run: |
cat >> .env.dev <<END
MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
MYSQL_USER=$MYSQL_USER
MYSQL_PASSWORD=$MYSQL_PASSWORD
DB_NAME=$DB_NAME
DB_HOST=$DB_HOST
DB_PORT=$DB_PORT
CORS_ALLOWED_ORIGINS=$CORS_ALLOWED_ORIGINS
VITE_BACKEND_URL=$VITE_BACKEND_URL
VITE_ENABLE_MOCKS=$VITE_ENABLE_MOCKS
VITE_LOGGING=$VITE_LOGGING
END

- name: Configure SSH
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/aws_dev.pem
chmod 400 ~/.ssh/aws_dev.pem

- name: SSH to AWS EC2 and down the containers
run: |
ssh -i ~/.ssh/aws_dev.pem $SSH_USER@$SSH_HOST << 'ENDSSH'
cd $PROJECT_DIR
docker-compose -f docker-compose.dev.yml down
ENDSSH

- name: SCP .env.dev and docker-compose.dev.yml to AWS EC2
run: |
scp -i ~/.ssh/aws_dev.pem \
-r $(pwd)/{.env.dev,docker-compose.dev.yml} \
$SSH_USER@$SSH_HOST:$PROJECT_DIR

- name: SSH to AWS EC2 and deploy
run: |
ssh -i ~/.ssh/aws_dev.pem $SSH_USER@$SSH_HOST << 'ENDSSH'
cd $PROJECT_DIR
docker pull $CONTAINER_REPOSITORY:$BACKEND_IMAGE_TAG
docker pull $CONTAINER_REPOSITORY:$CLIENT_IMAGE_TAG
docker pull $CONTAINER_REPOSITORY/$NGINX_IMAGE_TAG
docker-compose -f docker-compose.staging.yml up -d
docker-compose -f docker-compose.staging.yml exec backend python manage.py migrate --noinput
ENDSSH
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
.DS_Store

# Legacy web project
web/
web/

.idea/

# Env files
.env
.env.dev
.env.stage
.env.prod
.env.makefile
29 changes: 29 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.tslint": "explicit",
"source.organizeImports": "explicit",
"source.fixAll.ts": "explicit",
"source.sortImports": "explicit"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.formatOnSave": true,
"tailwindCSS.experimental.classRegex": [
["clsx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)", "cva\\(([^)]*)\\)"]
],
"[ignore]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[dotenv]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
}
}
93 changes: 93 additions & 0 deletions Makefile
Copy link
Contributor

Choose a reason for hiding this comment

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

This makefile is currently in use (Milestone 1) since workflows are not ready to execute.

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Load secrets from a .env file (optional)
ifneq (,$(wildcard .env.makefile))
include .env.makefile
export
endif

# variables
COMPOSE_FILE=docker-compose.dev.yml
CONTAINER_REPOSITORY=meminseeker/turquiz
SERVICES=backend client nginx

# Variables from the env file
PEM_FILE ?= $(PEM_FILE)
SSH_USER ?= $(SSH_USER)
SSH_HOST ?= $(SSH_HOST)
FILES_TO_COPY ?= $(FILES_TO_COPY)
TARGET_DIR ?= $(TARGET_DIR)
ANDROID_DIR ?= $(ANDROID_DIR)

# command for building images from dev
dev-build:
docker-compose -f $(COMPOSE_FILE) build

# command for pushing dev images to Docker Hub
dev-push:
@for service in $(SERVICES); do \
docker push $(CONTAINER_REPOSITORY):$$service; \
done

# command for down containers
dev-down:
@if [ -z "$(PEM_FILE)" ] || [ -z "$(SSH_USER)" ] || [ -z "$(SSH_HOST)" ] || [ -z "$(TARGET_DIR)" ] || [ -z "$(COMPOSE_FILE)" ]; then \
echo "Error: Please set PEM_FILE, SSH_USER, SSH_HOST, TARGET_DIR, and COMPOSE_FILE environment variables"; \
exit 1; \
fi
ssh -i $(PEM_FILE) $(SSH_USER)@$(SSH_HOST) \
'cd $(TARGET_DIR) || { echo "Failed to change directory to $(TARGET_DIR)"; exit 1; }; \
echo "Successfully changed directory to $(TARGET_DIR)"; \
~/.docker/cli-plugins/docker-compose -f $(COMPOSE_FILE) down; \
exit'

# command for SCP files to a remote server
dev-scp:
@if [ -z "$(PEM_FILE)" ] || [ -z "$(SSH_USER)" ] || [ -z "$(SSH_HOST)" ] || [ -z "$(FILES_TO_COPY)" ] || [ -z "$(TARGET_DIR)" ]; then \
echo "Error: Please set PEM_FILE, SSH_USER, SSH_HOST, FILES_TO_COPY, and TARGET_DIR environment variables"; \
exit 1; \
fi
@for file in $(FILES_TO_COPY); do \
if [ ! -f $$file ]; then \
echo "Error: File $$file does not exist"; \
exit 1; \
fi; \
scp -i $(PEM_FILE) $$file $(SSH_USER)@$(SSH_HOST):$(TARGET_DIR); \
done

# command for deployment to a remote server
dev-up:
@if [ -z "$(PEM_FILE)" ] || [ -z "$(SSH_USER)" ] || [ -z "$(SSH_HOST)" ] || [ -z "$(TARGET_DIR)" ] || [ -z "$(COMPOSE_FILE)" ] || [ -z "$(CONTAINER_REPOSITORY)" ] || [ -z "$(SERVICES)" ]; then \
echo "Error: Please set PEM_FILE, SSH_USER, SSH_HOST, TARGET_DIR, COMPOSE_FILE, CONTAINER_REPOSITORY, and SERVICES environment variables"; \
exit 1; \
fi
ssh -i $(PEM_FILE) $(SSH_USER)@$(SSH_HOST) \
'cd $(TARGET_DIR) || { echo "Failed to change directory to $(TARGET_DIR)"; exit 1; }; \
echo "Successfully changed directory to $(TARGET_DIR)"; \
docker pull $(CONTAINER_REPOSITORY):backend; \
docker pull $(CONTAINER_REPOSITORY):client; \
docker pull $(CONTAINER_REPOSITORY):nginx; \
~/.docker/cli-plugins/docker-compose -f $(COMPOSE_FILE) up -d; \
~/.docker/cli-plugins/docker-compose -f docker-compose.dev.yml exec backend python manage.py migrate --noinput; \
exit'

# Composition of the commands
dev-bp: dev-build dev-push
dev-dsu: dev-down dev-scp dev-up
dev-deploy: dev-bp dev-dsu

dev-mobile:
@if [ -z "$(ANDROID_DIR)" ]; then \
echo "Error: Please set ANDROID_BUILDER_PATH environment variable"; \
exit 1; \
fi
cd $(ANDROID_DIR) && \
./gradlew assembleDebug

prod-mobile:
@if [ -z "$(ANDROID_DIR)" ]; then \
echo "Error: Please set ANDROID_BUILDER_PATH environment variable"; \
exit 1; \
fi
cd $(ANDROID_DIR) && \
./gradlew assembleRelease

.PHONY: dev-build dev-push dev-down dev-scp dev-up dev-bp dev-dsu dev-deploy dev-mobile prod-mobile
Loading
Loading