├── README.md ├── appname ├── __init__.py ├── admin.py ├── apps.py ├── models.py ├── templates │ └── appname │ │ └── home.html ├── tests.py ├── urls.py └── views.py ├── manage.py ├── myproject ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── requirements.txt ├── static └── css │ └── main.css └── templates └── base.html /README.md: -------------------------------------------------------------------------------- 1 | ## Django Frameworkida qilingan loyihamizni Debian/Ubuntu 20.04 serveriga joylash, Postgres, Nginx, Gunicorn paketlarini sozlash va ishga tushurish 2 | 3 | ESLATMA: 4 | - Loyiha nomi `project_name` 5 | - Ma'lumotlar bazasining nomi `database_name` 6 | - Ma'lumotlar bazasining foydalanuvchisining ismi `user_name` 7 | - Ma'lumotlar bazasining paroli `password` 8 | - Ubuntu foydalanuvchi nomi `sammy` 9 | Ushbu o'zgaruvchilar orniga uzingizni ma'lumotlaringizni kiriting!!! 10 | ``` 11 | **Ushbu qollanmada men quyidagi loyihadan foydalanaman, sizning loyihangizni tuzilishi menikidan farq qilishi mumkin** 12 | ├── projectname 13 | ├── appname 14 | │ ├── __init__.py 15 | │ ├── admin.py 16 | │ ├── apps.py 17 | │ ├── models.py 18 | │ ├── views.py 19 | │ └── urls.py 20 | ├── projectname 21 | │ ├── __init__.py 22 | │ ├── settings.py 23 | │ ├── urls.py 24 | │ └── wsgi.py 25 | ├── templates 26 | ├── static 27 | ├── media 28 | ├── manage.py 29 | └── requirements.txt 30 | 31 | ``` 32 | Ushbu qollanmani root foydalanuvchi sifatida bajarish tavsiya etilmaydi, Foydalanuvchi [yaratish va unga sudo huquqini](https://www.digitalocean.com/community/tutorials/how-to-create-a-new-sudo-enabled-user-on-ubuntu-20-04-quickstart) berish. 33 | ### Kerakli paketlarni o'rnatish 34 | ```sh 35 | $ sudo apt update 36 | $ sudo apt install -y python-pip python-dev libpq-dev vim git htop postgresql postgresql-contrib nginx redis-server 37 | ``` 38 | ### PostgreSQL ni sozlash 39 | Oldin ma'lumotlar bazasini va shu ma'lumotlar bazasidan foydalanuvchi yaratib olamiz. 40 | 41 | PostgreSQL ma'lumotlar bazasini o'rnatgandan so'ng PostgreSQL ma'lumotlar bazasi postgresql nomli foydalanuvchi yaratadi, biz ma'lumotlar bazasini sozlashda o'sha foydalanuvchidan foydalanamiz, biz `sudo` komandasi `-u` parametri bilan foydalanuvchi nomini kiritishimiz kerak 42 | ``` 43 | $ sudo -u postgres psql 44 | ``` 45 | Ma'lumotlar bazasini yaratib olamiz. 46 | ``` 47 | postgres=# CREATE DATABASE database_name; 48 | ``` 49 | Yaratilgan ma'lumotlar bazasidan foydalanuvchi yaratamiz. 50 | ```sh 51 | postgres=# CREATE USER user_name WITH PASSWORD 'password'; 52 | ``` 53 | Ma'lumotlar bazasini sozlab olamiz 54 | - Kodirofkani utf8 ga o'zgartiramiz 55 | - Tranzaktsiyalarni kutilmagan ma'lumotlar bazasi foydalanuvchisidan cheklab qoyamiz 56 | - Timezone ni UTC ga o'zgartirish (agarda siz loyihangizni boshqa UTC ishlatsangiz shunga o'zgartirish tavsfiya etiladi) 57 | ```sh 58 | postgres=# ALTER ROLE user_name SET client_encoding TO 'utf8'; 59 | postgres=# ALTER ROLE user_name SET default_transaction_isolation TO 'read committed'; 60 | postgres=# ALTER ROLE user_name SET timezone TO 'UTC'; 61 | ``` 62 | Foydalanuvchiga ma'lumotlar bazasini boshqarishga huquq berish 63 | ```sh 64 | postgres=# GRANT ALL PRIVILEGES ON DATABASE user_name TO database_name; 65 | ``` 66 | Endi PostgreSQL dan chiqamiz. 67 | ```sh 68 | postgres=# \q 69 | ``` 70 | ### Loyihani git repositoriyasidan yuklab olish 71 | ```sh 72 | $ git clone your_repository_link 73 | ``` 74 | ### Virtual muhit 75 | Birinchi navbatda [Virtual muhitni](https://docs.python.org/3/library/venv.html) yaratib olamiz. 76 | ```sh 77 | $ cd my_project 78 | $ python3 -m venv venv 79 | ``` 80 | Virtual muhitni aktivatsiya qilish va kerakli kutubxonalarni o'rnatish 81 | ```sh 82 | $ . venv/bin/activate && pip3 insatll -r requirements.txt 83 | ``` 84 | Agarda siz loyihangizda boshqa qo'shimcha kutubxonalarni ishlatgan bolsangiz requirements.txt ga qo'shib qo'yishingiz kerak bo'ladi 85 | ### Loyihani sozlash 86 | Loyihamizni serverda ishga tushurish uchun oldin loyihani sozlab olishimiz kerak, loyiha sozlamari `settings.py` faylida joylashishi bilsangiz kerak? xa albatta bilasiz degan ummida man, `ALLOWED_HOSTS` ro'yhatimizda loyihani ishga tushirilgan server IP va domen nomlarini kiritishimiz kerak bu Django loyihamiz qaysi serverdan kelgan xabarlarga javob qaytarishi bilishi uchun kerak bo'ladi. 87 | ```python 88 | ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP'] 89 | ``` 90 | Ma'lumotlar bazasini sozlamarini saqlaydigan dictga o'zgartirish kirishimiz kerak, ya'ni qaysi ma'lumotlar bazasiga ulanish, ma'lumotlar bazasini foydalanuvchising ismi va paroli, ma'lumotlar bazasimiz qaysi port da ishlab turganini kiritishimiz kerak 91 | ```python 92 | DATABASES = { 93 | 'default': { 94 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 95 | 'NAME': 'database_name', 96 | 'USER': 'user_name', 97 | 'PASSWORD': 'password', 98 | 'HOST': 'localhost', 99 | 'PORT': '', 100 | } 101 | } 102 | ``` 103 | Statik fayllarni qaerga jo'ylashtirish keraklini bildiradigan o'zgaruvchi yaratishimiz kerak, django loyihamizni localhost da ishlatganimizda bu o'zgaruvchi kerak bolmaydi chunki `DEBUG=True` holatda statik fayllarni django qayta ishlaydi `DEBUG=False` xolatda esa statik fayllarni Nginx(proxy-server) qayta ishlaydi. 104 | settings.py faylni oxiriga `STATIC_ROOT` o'zgaruvchi elon qilamiz va `BASE_DIR` (loyihamiz joylashgan joy) ga statik fayllarni saqlash uchun mo'ljallangan `staticfiles` nomli directoriyani qo'shib qoyamiz 105 | ```python 106 | STATIC_ROOT = BASE_DIR / 'staticfiles' 107 | ``` 108 | Migratsiyalarni yaratib ularni ma'lumotlar bazamizga saqlaymiz, `python3 manage.py makemigrations` komandasi modelimizni holatini migratsiya faylida saqlab qoyadi va `python3 manage.py migrate` komandasi esa migratsiya fayllarini ma'lumotlar bazamizga saqlaydi 109 | ```sh 110 | (venv)$ python3 manage.py makemigrations 111 | (venv)$ python3 manage.py migrate 112 | ``` 113 | Endilikda admin paneliga kira olishimiz uchun superuser yaratib olamiz. 114 | ```sh 115 | (venv)$ python3 manage.py createsuperuser 116 | ``` 117 | Nginxga statik fayllarni qaysi direktoriya(papkada) dan izlash keraklikini ko'rsatishimiz uchun statik fayllarni bir joyga jamlab olamiz. 118 | ```sh 119 | (venv)$ python3 manage.py collectstatic 120 | ``` 121 | Va nihoyat biz loyihamizni tog'ri sozlaganimizni bilishimiz uchun loyihani ishga tushirib ko'rishimiz mumkin 122 | ```sh 123 | python3 manage.py runserver 0.0.0.0:8000 124 | ``` 125 | Brauzeringizda server ipisiga 8000-portni qo'shib yozib tekshirib ko'rishingiz mumkin 126 | example: server_ip:8000 127 | Tushunarliki bunday qilib loyihani ishlatib qoyib bolmaydi chunki loyihamizni real serverga joylaganimizda `DEBUG=FALSE` bo'lishi kerak bu foydalanuvchiga loyihamizda yuz bergan xatoliklarni ko'rsatmaslikimiz uchun kerak. 128 | Virtual muhitni deaktivatsiya qilishimizdan oldin gunicorn kelgan habarlga javob qayta olishini tekshirib ko'rishimiz kerak, biz loyihamiz katalogiga kirib, `gunicorn` yordamida loyihaning WSGI modulini yuklashga urinib ko'ramiz: 129 | ```sh 130 | cd ~/myproject 131 | gunicorn --bind 0.0.0.0:8000 myproject.wsgi 132 | ``` 133 | Bu komanda orqali Gunicorn orqali Django loyihamizni ishga tushiramiz.Orqaga qaytib loyihamiz ko'rsatilgan ip orqali ishlayotganini qayta sinab ko'rishingiz mumkin. CTRL+C tugmachasini bosib gunicorn ni toxtatib virtual muhitni deaktivatsiya qilamiz. 134 | ```sh 135 | (venv)$ deactivate 136 | ``` 137 | ### Gunicorn ni sozlash 138 | Django Loyihamizni serverda ishlatib qoyishimiz uchun [Nginx](https://nginx.org/ru/) va [Gunicorn](https://gunicorn.org/) dan foydalanamiz 139 | Gunicorn uchun systemd ni sozlab olishimiz kerak, systemd Linux xizmatlarini ishga tushurish/boshqarish uchun qulay tizim hisoblanadi. 140 | ``` 141 | $ sudo nano /etc/systemd/system/gunicorn.service 142 | ``` 143 | Yuqoridaki komanda orqali `/etc/systemd/system/` katoligida gunicorn.service faylini yaratamiz, va quyidaki sozlamarni kiritib `ctrl+x+y+y+ENTER` tugmachasini bosamiz. 144 | ```commandline 145 | [Unit] 146 | Description=gunicorn daemon 147 | After=network.target 148 | 149 | [Service] 150 | User=sammy 151 | Group=www-data 152 | WorkingDirectory=/home/sammy/myproject 153 | ExecStart=/home/sammy/myproject/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/sammy/myproject/myproject.sock myproject.wsgi:application 154 | 155 | [Install] 156 | WantedBy=multi-user.target 157 | ``` 158 | - `[Unit]` bo'limida biz qanday xizmat uchun sozlamar kirityapganimizni va qachon ishga tushirilishi keraklikni kiritamiz. 159 | - `[Service]` bo'limida foydalanuvchi nomini va qaysi guruhga mansub ekanligini kiritamiz, nginx va gunicorn muloqat qila olishi uchun foydalanuvchi guruhi sifatida `www-data` ni kiritamiz. `WorkingDirectory` da qaysi direktoriyada ishlashni bildirishimiz uchun kerak bo'ladi, `ExecStart` esa qaysi komanda orqali ishga tushirimiz keraklikini kiritamiz. 160 | - `[Install]` bo'limi nimaga keraklikini uzim ham bilmaymiz ammo buni yozmasak ishlamaydida)) 161 | Endi systemctl komandasi orqali yuqorida yozgan xizmatimizni ishga tushiramiz va OS qayta ishga tushgan paytida avtomatik tarzda ishga tushirilishi keraklikini aytamiz. 162 | ```sh 163 | $ sudo systemctl start gunicorn 164 | $ sudo systemctl enable gunicorn 165 | ``` 166 | Endi Gunicorn ni holatini tekshirib ko'ramiz 167 | ```sh 168 | $ sudo systemctl status gunicorn 169 | ``` 170 | Qollanmani davom ettirishdan oldin gunicorn holati aktiv ekanligiga ishonch hosil qiling!!! 171 | Agarda siz biron bir sabablarga ko'ra gunicorn loglarini ko'rmoqchi bolsangiz quyidaki komanda orqali buni amalga oshirishingiz mumkin 172 | ```sh 173 | $ sudo journalctl -u gunicorn 174 | ``` 175 | `gunicorn.service` fayliga o'zgarish kiritsangiz gunicorn daemoni va gunicorn xizmatini qayta ishga tushurishingiz kerak boladi 176 | ```sh 177 | $ sudo systemctl daemon-reload 178 | $ sudo systemctl restart gunicorn 179 | ``` 180 | Agarda Gunicorn ishlayotgan bo'lsa loyihangiz katoligida `myproject.sock` fayli paydo bo'ladi!!! 181 | ### Nginxni sozlash 182 | Loyihamiz uchun Nginx sozlamarini saqlaydigan yangi fayl yaratamiz. 183 | ```sh 184 | $ sudo nano /etc/nginx/sites-available/myproject 185 | ``` 186 | Va quyidaki sozlamarni nusxasini ko'chirib olamiz 187 | ```editorconfig 188 | server { 189 | server_name server_domain_or_IP; 190 | 191 | location = /favicon.ico { access_log off; log_not_found off; } 192 | location /static/ { 193 | alias /home/sammy/myproject/staticfiles/; 194 | } 195 | location /media/ { 196 | alias /home/sammy/myproject/media/; 197 | } 198 | location / { 199 | include proxy_params; 200 | proxy_pass http://unix:/home/sammy/myproject/myproject.sock; 201 | } 202 | } 203 | ``` 204 | Endi biz yuqoridaki sozlamarni saytlar katalogiga bog'lab uni faollashtiramiz: 205 | ```sh 206 | $ sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled 207 | ``` 208 | Nginx sozlamalarini kiritishda sintaksis xatolik qilmaganimizni quyidaki komanda orqali tekshirishimiz mumkin. 209 | ```sh 210 | $ sudo nginx -t 211 | ``` 212 | Agar xatoliklar yo'q bolsa Nginx qayta ishga tushuring. 213 | ```sh 214 | $ sudo systemctl restart nginx 215 | ``` 216 | Va nihoyat serverni sozlab boldik!!! Siz brauzeringizda server IP si yo'ki domenini kiritib buni tekshirib ko'rishingiz mumkin, ha aytkancha serveringiz uchun [SSL sertifikat olish](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04)ni unitmang 217 | -------------------------------------------------------------------------------- /appname/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sayfullaev1999/deployment_django_project/4df5a82832474416c41914dcdf13d10d7b469968/appname/__init__.py -------------------------------------------------------------------------------- /appname/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /appname/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AppnameConfig(AppConfig): 5 | name = 'appname' 6 | -------------------------------------------------------------------------------- /appname/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /appname/templates/appname/home.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | 4 | {% block title %} 5 | Home page 6 | {% endblock %} 7 | 8 | 9 | {% block content %} 10 |

Hello, World

11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /appname/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /appname/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from .views import home 3 | 4 | 5 | urlpatterns = [ 6 | path('', home, name='home_url'), 7 | ] 8 | -------------------------------------------------------------------------------- /appname/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | def home(request): 4 | return render(request, 'appname/home.html') 5 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /myproject/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sayfullaev1999/deployment_django_project/4df5a82832474416c41914dcdf13d10d7b469968/myproject/__init__.py -------------------------------------------------------------------------------- /myproject/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for myproject project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /myproject/settings.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 4 | BASE_DIR = Path(__file__).resolve().parent.parent 5 | 6 | 7 | # Quick-start development settings - unsuitable for production 8 | # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ 9 | 10 | # SECURITY WARNING: keep the secret key used in production secret! 11 | SECRET_KEY = 's#$%llot*kurwv#k&bqa4bo489x_fr+y@-s*3w@&8%7f=2tts$' 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = True 15 | 16 | ALLOWED_HOSTS = [] 17 | 18 | 19 | # Application definition 20 | 21 | INSTALLED_APPS = [ 22 | 'django.contrib.admin', 23 | 'django.contrib.auth', 24 | 'django.contrib.contenttypes', 25 | 'django.contrib.sessions', 26 | 'django.contrib.messages', 27 | 'django.contrib.staticfiles', 28 | 29 | # My apps 30 | 'appname.apps.AppnameConfig' 31 | ] 32 | 33 | MIDDLEWARE = [ 34 | 'django.middleware.security.SecurityMiddleware', 35 | 'django.contrib.sessions.middleware.SessionMiddleware', 36 | 'django.middleware.common.CommonMiddleware', 37 | 'django.middleware.csrf.CsrfViewMiddleware', 38 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 39 | 'django.contrib.messages.middleware.MessageMiddleware', 40 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 41 | ] 42 | 43 | ROOT_URLCONF = 'myproject.urls' 44 | 45 | TEMPLATES = [ 46 | { 47 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 48 | 'DIRS': [ 49 | BASE_DIR / 'templates' 50 | ], 51 | 'APP_DIRS': True, 52 | 'OPTIONS': { 53 | 'context_processors': [ 54 | 'django.template.context_processors.debug', 55 | 'django.template.context_processors.request', 56 | 'django.contrib.auth.context_processors.auth', 57 | 'django.contrib.messages.context_processors.messages', 58 | ], 59 | }, 60 | }, 61 | ] 62 | 63 | WSGI_APPLICATION = 'myproject.wsgi.application' 64 | 65 | 66 | # Database 67 | # https://docs.djangoproject.com/en/3.1/ref/settings/#databases 68 | 69 | DATABASES = { 70 | 'default': { 71 | 'ENGINE': 'django.db.backends.sqlite3', 72 | 'NAME': BASE_DIR / 'db.sqlite3', 73 | } 74 | } 75 | 76 | 77 | # Password validation 78 | # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators 79 | 80 | AUTH_PASSWORD_VALIDATORS = [ 81 | { 82 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 83 | }, 84 | { 85 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 86 | }, 87 | { 88 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 89 | }, 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 92 | }, 93 | ] 94 | 95 | 96 | # Internationalization 97 | # https://docs.djangoproject.com/en/3.1/topics/i18n/ 98 | 99 | LANGUAGE_CODE = 'en-us' 100 | 101 | TIME_ZONE = 'UTC' 102 | 103 | USE_I18N = True 104 | 105 | USE_L10N = True 106 | 107 | USE_TZ = True 108 | 109 | 110 | # Static files (CSS, JavaScript, Images) 111 | # https://docs.djangoproject.com/en/3.1/howto/static-files/ 112 | 113 | STATIC_URL = '/static/' 114 | STATIC_ROOT = BASE_DIR / 'staticfiles' 115 | STATICFILES_DIRS = [ 116 | BASE_DIR / 'static', 117 | ] 118 | -------------------------------------------------------------------------------- /myproject/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path 3 | from django.urls import include 4 | from django.conf import settings 5 | from django.conf.urls.static import static 6 | 7 | urlpatterns = [ 8 | path('admin/', admin.site.urls), 9 | path('', include('appname.urls')), 10 | ] 11 | 12 | if settings.DEBUG: 13 | urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 14 | -------------------------------------------------------------------------------- /myproject/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for myproject project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.3.1 2 | Django==3.1.6 3 | gunicorn==20.0.4 4 | pytz==2021.1 5 | sqlparse==0.4.1 6 | -------------------------------------------------------------------------------- /static/css/main.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: red; 3 | } 4 | h2 { 5 | color: green; 6 | } 7 | -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | {% block title %} Title {% endblock %} 8 | 9 | 10 |

Home page

11 | {% block content %} 12 | Content 13 | {% endblock %} 14 | 15 | 16 | --------------------------------------------------------------------------------