diff --git a/.travis.yml b/.travis.yml
index f6c2be7f3cde48ddd0aa8b22ce4a3de31de4f056..a407988ff1f463848318020b9108601ac11a0567 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,6 @@ install:
     - travis_retry pip install -r requirements.txt
 
 script:
-    - python manage.py migrate database
     - python manage.py test
 
 #branches:
diff --git a/opds_catalog/dl.py b/opds_catalog/dl.py
index f1e44c187097a330b1fcfccc0a80edeafcf2deda..0728f9e1e564616494e6bb7c766d841b0524eb97 100644
--- a/opds_catalog/dl.py
+++ b/opds_catalog/dl.py
@@ -11,15 +11,16 @@ from django.http import HttpResponse, Http404
 from opds_catalog.models import Book, bookshelf
 from opds_catalog import settings, utils, opdsdb, fb2parse
 import opds_catalog.zipf as zipfile
+from constance import config
 
 def Download(request, book_id, zip_flag):
     """ Загрузка файла книги """
     book = Book.objects.get(id=book_id)
 
-    if settings.AUTH and request.user.is_authenticated():
+    if config.SOPDS_AUTH and request.user.is_authenticated():
         bookshelf.objects.get_or_create(user=request.user, book=book)
 
-    full_path=os.path.join(settings.ROOT_LIB,book.path)
+    full_path=os.path.join(config.SOPDS_ROOT_LIB,book.path)
     
     if book.cat_type==opdsdb.CAT_INP:
         # Убираем из пути INPX файл
@@ -27,7 +28,7 @@ def Download(request, book_id, zip_flag):
         path, inpx_file = os.path.split(inpx_path)
         full_path = os.path.join(path,zip_name)
         
-    if settings.TITLE_AS_FILENAME:
+    if config.SOPDS_TITLE_AS_FILENAME:
         transname=utils.translit(book.title+'.'+book.format)
     else:
         transname=utils.translit(book.filename)
@@ -98,7 +99,7 @@ def Cover(request, book_id):
     book = Book.objects.get(id=book_id)
     response = HttpResponse()
     c0=0
-    full_path=os.path.join(settings.ROOT_LIB,book.path)
+    full_path=os.path.join(config.SOPDS_ROOT_LIB,book.path)
     if book.cat_type==opdsdb.CAT_INP:
         # Убираем из пути INPX файл
         inpx_path, zip_name = os.path.split(full_path)
@@ -132,9 +133,9 @@ def Cover(request, book_id):
                 c0=0
 
     if c0==0:
-        if os.path.exists(settings.NOCOVER_PATH):
+        if os.path.exists(config.SOPDS_NOCOVER_PATH):
             response["Content-Type"]='image/jpeg'
-            f=open(settings.NOCOVER_PATH,"rb")
+            f=open(config.SOPDS_NOCOVER_PATH,"rb")
             response.write(f.read())
             f.close()
         else:
@@ -149,17 +150,17 @@ def ConvertFB2(request, book_id, convert_type):
     if book.format!='fb2':
         raise Http404
 
-    if settings.AUTH and request.user.is_authenticated():
+    if config.SOPDS_AUTH and request.user.is_authenticated():
         bookshelf.objects.get_or_create(user=request.user, book=book)
 
-    full_path=os.path.join(settings.ROOT_LIB,book.path)
+    full_path=os.path.join(config.SOPDS_ROOT_LIB,book.path)
     if book.cat_type==opdsdb.CAT_INP:
         # Убираем из пути INPX файл
         inpx_path, zip_name = os.path.split(full_path)
         path, inpx_file = os.path.split(inpx_path)
         full_path = os.path.join(path,zip_name)  
             
-    if settings.TITLE_AS_FILENAME:
+    if config.SOPDS_TITLE_AS_FILENAME:
         transname=utils.translit(book.title+'.'+book.format)
     else:
         transname=utils.translit(book.filename)      
@@ -170,10 +171,10 @@ def ConvertFB2(request, book_id, convert_type):
     dlfilename="%s.%s"%(n,convert_type)
     
     if convert_type=='epub':
-        converter_path=settings.FB2TOEPUB
+        converter_path=config.SOPDS_FB2TOEPUB
         content_type='application/epub+zip'
     elif convert_type=='mobi':
-        converter_path=settings.FB2TOMOBI
+        converter_path=config.SOPDS_FB2TOMOBI
         content_type='application/x-mobipocket-ebook'
     else:
         content_type='application/octet-stream'
@@ -187,11 +188,11 @@ def ConvertFB2(request, book_id, convert_type):
         except FileNotFoundError:
             raise Http404        
         z = zipfile.ZipFile(fz, 'r', allowZip64=True)
-        z.extract(book.filename,settings.TEMP_DIR)
-        tmp_fb2_path=os.path.join(settings.TEMP_DIR,book.filename)
+        z.extract(book.filename,config.SOPDS_TEMP_DIR)
+        tmp_fb2_path=os.path.join(config.SOPDS_TEMP_DIR,book.filename)
         file_path=tmp_fb2_path        
         
-    tmp_conv_path=os.path.join(settings.TEMP_DIR,dlfilename)
+    tmp_conv_path=os.path.join(config.SOPDS_TEMP_DIR,dlfilename)
     popen_args = ("\"%s\" \"%s\" \"%s\""%(converter_path,file_path,tmp_conv_path))
     proc = subprocess.Popen(popen_args, shell=True, stdout=subprocess.PIPE)
     #proc = subprocess.Popen((converter_path.encode('utf8'),file_path.encode('utf8'),tmp_conv_path.encode('utf8')), shell=True, stdout=subprocess.PIPE)
diff --git a/opds_catalog/feeds.py b/opds_catalog/feeds.py
index e379ae0d206c1c52d4b97fc3c35ca4fabe2d70aa..47cdf6ec2b841ed511160464f0b41edbcc0fb1e9 100644
--- a/opds_catalog/feeds.py
+++ b/opds_catalog/feeds.py
@@ -15,11 +15,13 @@ from opds_catalog import settings
 from opds_catalog.opds_middleware import BasicAuthMiddleware
 from opds_catalog.opds_paginator import Paginator as OPDS_Paginator
 
+from constance import config
+
 class AuthFeed(Feed):
     request = None
     def __call__(self,request,*args,**kwargs):
         self.request = request
-        if settings.AUTH:
+        if config.SOPDS_AUTH:
             if request.user.is_authenticated():
                 return super().__call__(request,*args,**kwargs)
         
@@ -159,16 +161,16 @@ class MainFeed(AuthFeed):
         mainitems = [
                     {"id":1, "title":_("By catalogs"), "link":"opds_catalog:catalogs",
                      "descr": _("Catalogs: %(catalogs)s, books: %(books)s."),"counters":{"catalogs":Counter.objects.get_counter(models.counter_allcatalogs),"books":Counter.objects.get_counter(models.counter_allbooks)}},
-                    {"id":2, "title":_("By authors"), "link":("opds_catalog:lang_authors" if settings.ALPHABET_MENU else "opds_catalog:nolang_authors"),
+                    {"id":2, "title":_("By authors"), "link":("opds_catalog:lang_authors" if config.SOPDS_ALPHABET_MENU else "opds_catalog:nolang_authors"),
                      "descr": _("Authors: %(authors)s."),"counters":{"authors":Counter.objects.get_counter(models.counter_allauthors)}},
-                    {"id":3, "title":_("By titles"), "link":("opds_catalog:lang_books" if settings.ALPHABET_MENU else "opds_catalog:nolang_books"),
+                    {"id":3, "title":_("By titles"), "link":("opds_catalog:lang_books" if config.SOPDS_ALPHABET_MENU else "opds_catalog:nolang_books"),
                      "descr": _("Books: %(books)s."),"counters":{"books":Counter.objects.get_counter(models.counter_allbooks)}},
                     {"id":4, "title":_("By genres"), "link":"opds_catalog:genres",
                      "descr": _("Genres: %(genres)s."),"counters":{"genres":Counter.objects.get_counter(models.counter_allgenres)}},
-                    {"id":5, "title":_("By series"), "link":("opds_catalog:lang_series" if settings.ALPHABET_MENU else "opds_catalog:nolang_series"),
+                    {"id":5, "title":_("By series"), "link":("opds_catalog:lang_series" if config.SOPDS_ALPHABET_MENU else "opds_catalog:nolang_series"),
                      "descr": _("Series: %(series)s."),"counters":{"series":Counter.objects.get_counter(models.counter_allseries)}},
         ]
-        if settings.AUTH and self.request.user.is_authenticated():
+        if config.SOPDS_AUTH and self.request.user.is_authenticated():
             mainitems += [
                         {"id":6, "title":_("%(username)s Book shelf")%({"username":self.request.user.username}), "link":"opds_catalog:bookshelf",
                          "descr":_("%(username)s books readed: %(bookshelf)s."),"counters":{"bookshelf":bookshelf.objects.filter(user=self.request.user).count(),"username":self.request.user.username}},
@@ -223,7 +225,7 @@ class CatalogsFeed(AuthFeed):
         books_count = books_list.count()
         
         # Получаем результирующий список
-        op = OPDS_Paginator(catalogs_count, books_count, page_num, settings.MAXITEMS)
+        op = OPDS_Paginator(catalogs_count, books_count, page_num, config.SOPDS_MAXITEMS)
         items = []
         
         for row in catalogs_list[op.d1_first_pos:op.d1_last_pos+1]:
@@ -372,7 +374,7 @@ class SearchBooksFeed(AuthFeed):
     subtitle = settings.SUBTITLE
     
     def title(self, obj):
-        return "%s | %s (%s)"%(settings.TITLE,_("Books found"),_("doubles hide") if settings.DOUBLES_HIDE else _("doubles show"))    
+        return "%s | %s (%s)"%(settings.TITLE,_("Books found"),_("doubles hide") if config.SOPDS_DOUBLES_HIDE else _("doubles show"))    
 
     def get_object(self, request, searchtype="m", searchterms=None, searchterms0=None, page=1):   
         if not isinstance(page, int):
@@ -423,7 +425,7 @@ class SearchBooksFeed(AuthFeed):
             books = Book.objects.filter(genres=genre_id).order_by('search_title','-docdate')    
         # Поиск книг на книжной полке            
         elif searchtype == 'u':
-            if settings.AUTH:
+            if config.SOPDS_AUTH:
                 books = Book.objects.filter(bookshelf__user=request.user).order_by('-bookshelf__readtime')
             else:
                 books=Book.objects.filter(id=0)  
@@ -439,7 +441,7 @@ class SearchBooksFeed(AuthFeed):
                  
         # Фильтруем дубликаты
         books_count = books.count()
-        op = OPDS_Paginator(books_count, 0, page_num,settings.MAXITEMS)
+        op = OPDS_Paginator(books_count, 0, page_num,config.SOPDS_MAXITEMS)
         items = []
         
         prev_title = ''
@@ -447,7 +449,7 @@ class SearchBooksFeed(AuthFeed):
         
         # Начаинам анализ с последнего элемента на предидущей странице, чторбы он "вытянул" с этой страницы
         # свои дубликаты если они есть
-        summary_DOUBLES_HIDE =  settings.DOUBLES_HIDE and (searchtype != 'd')
+        summary_DOUBLES_HIDE =  config.SOPDS_DOUBLES_HIDE and (searchtype != 'd')
         start = op.d1_first_pos if ((op.d1_first_pos==0) or (not summary_DOUBLES_HIDE)) else op.d1_first_pos-1
         finish = op.d1_last_pos
         
@@ -534,9 +536,9 @@ class SearchBooksFeed(AuthFeed):
             opdsEnclosure(reverse("opds_catalog:download", kwargs={"book_id":item['id'],"zip_flag":1}),"application/%s+zip"%item['format'], "http://opds-spec.org/acquisition/open-access"),
             opdsEnclosure(reverse("opds_catalog:cover", kwargs={"book_id":item['id']}),"image/jpeg", "http://opds-spec.org/image"),
         ]
-        if (settings.FB2TOEPUB!="") and (item['format']=='fb2'):
+        if (config.SOPDS_FB2TOEPUB!="") and (item['format']=='fb2'):
             enclosure += [opdsEnclosure(reverse("opds_catalog:convert", kwargs={"book_id":item['id'],"convert_type":"epub"}),"application/epub+zip","http://opds-spec.org/acquisition/open-access")] 
-        if (settings.FB2TOMOBI!="") and (item['format']=='fb2'):
+        if (config.SOPDS_FB2TOMOBI!="") and (item['format']=='fb2'):
             enclosure += [opdsEnclosure(reverse("opds_catalog:convert", kwargs={"book_id":item['id'],"convert_type":"mobi"}),"application/mobi","http://opds-spec.org/acquisition/open-access")] 
 
         return enclosure
@@ -634,7 +636,7 @@ class SearchAuthorsFeed(AuthFeed):
             
         # Создаем результирующее множество
         authors_count = authors.count()
-        op = OPDS_Paginator(authors_count, 0, page_num, settings.MAXITEMS)        
+        op = OPDS_Paginator(authors_count, 0, page_num, config.SOPDS_MAXITEMS)        
         items = []
         
         for row in authors[op.d1_first_pos:op.d1_last_pos+1]:
@@ -712,7 +714,7 @@ class SearchSeriesFeed(AuthFeed):
         
         # Создаем результирующее множество
         series_count = series.count()
-        op = OPDS_Paginator(series_count, 0, page_num, settings.MAXITEMS)        
+        op = OPDS_Paginator(series_count, 0, page_num, config.SOPDS_MAXITEMS)        
         items = []
         
         for row in series[op.d1_first_pos:op.d1_last_pos+1]:
@@ -860,7 +862,7 @@ class BooksFeed(AuthFeed):
 
     def item_link(self, item):
         title_full = len(item.id)<item.l
-        if item.cnt>=settings.SPLITITEMS and not title_full:
+        if item.cnt>=config.SOPDS_SPLITITEMS and not title_full:
             return reverse("opds_catalog:chars_books", kwargs={"lang_code":self.lang_code,"chars":item.id})
         else:
             return reverse("opds_catalog:searchbooks", \
@@ -918,7 +920,7 @@ class AuthorsFeed(AuthFeed):
 
     def item_link(self, item):
         last_name_full = len(item.id)<item.l
-        if (item.cnt>=settings.SPLITITEMS) and not last_name_full:
+        if (item.cnt>=config.SOPDS_SPLITITEMS) and not last_name_full:
             return reverse("opds_catalog:chars_authors", kwargs={"lang_code":self.lang_code,"chars":item.id})
         else:
             return reverse("opds_catalog:searchauthors", \
@@ -976,7 +978,7 @@ class SeriesFeed(AuthFeed):
 
     def item_link(self, item):
         series_full = len(item.id)<item.l
-        if item.cnt>=settings.SPLITITEMS and not series_full:
+        if item.cnt>=config.SOPDS_SPLITITEMS and not series_full:
             return reverse("opds_catalog:chars_series", kwargs={"lang_code":self.lang_code,"chars":item.id})
         else:
             return reverse("opds_catalog:searchseries", \
diff --git a/opds_catalog/inpx_parser.py b/opds_catalog/inpx_parser.py
index 525c25e48c77f038eaecf77b85290a7fd0db8c58..b781962679e518cc130bd7d4431ad3f700b053e1 100644
--- a/opds_catalog/inpx_parser.py
+++ b/opds_catalog/inpx_parser.py
@@ -7,7 +7,8 @@ Created on 14 нояб. 2016 г.
 # -*- coding: utf-8 -*-
 import os
 import zipfile
-from opds_catalog import settings
+#from opds_catalog import settings
+from constance import config
 
 sAuthor = 'AUTHOR'
 sGenre  = 'GENRE'
@@ -32,8 +33,8 @@ class Inpx:
         self.inpx_itemseparator = ':'
         self.append_callback = append_callback
         self.inpskip_callback = inpskip_callback
-        self.TEST_ZIP = settings.INPX_TEST_ZIP
-        self.TEST_FILES = settings.INPX_TEST_FILES
+        self.TEST_ZIP = config.SOPDS_INPX_TEST_ZIP
+        self.TEST_FILES = config.SOPDS_INPX_TEST_FILES
         self.error = 0       
         
     def parse(self):
diff --git a/opds_catalog/management/commands/sopds_scanner.py b/opds_catalog/management/commands/sopds_scanner.py
index 317ad33fc958fb3235d05e078753ad4ba2076e93..5ffba26a6e7e771d1db7bd3b3ea5b6dda4a0bb5a 100644
--- a/opds_catalog/management/commands/sopds_scanner.py
+++ b/opds_catalog/management/commands/sopds_scanner.py
@@ -14,8 +14,7 @@ from opds_catalog.models import Counter
 from opds_catalog.sopdscan import opdsScanner
 #from opds_catalog.settings import SCANNER_LOG, SCAN_SHED_DAY, SCAN_SHED_DOW, SCAN_SHED_HOUR, SCAN_SHED_MIN, LOGLEVEL, SCANNER_PID
 from opds_catalog import settings 
-
-
+from constance import config
 
 class Command(BaseCommand):
     help = 'Scan Books Collection.'
@@ -26,7 +25,7 @@ class Command(BaseCommand):
         parser.add_argument('--daemon',action='store_true', dest='daemonize', default=False, help='Daemonize server')
         
     def handle(self, *args, **options): 
-        self.pidfile = os.path.join(main_settings.BASE_DIR, settings.SCANNER_PID)
+        self.pidfile = os.path.join(main_settings.BASE_DIR, config.SOPDS_SCANNER_PID)
         action = options['command']            
         self.logger = logging.getLogger('')
         self.logger.setLevel(logging.DEBUG)
@@ -34,7 +33,7 @@ class Command(BaseCommand):
 
         if settings.LOGLEVEL!=logging.NOTSET:
             # Создаем обработчик для записи логов в файл
-            fh = logging.FileHandler(settings.SCANNER_LOG)
+            fh = logging.FileHandler(config.SOPDS_SCANNER_LOG)
             fh.setLevel(settings.LOGLEVEL)
             fh.setFormatter(formatter)
             self.logger.addHandler(fh)
@@ -78,26 +77,28 @@ class Command(BaseCommand):
         Counter.objects.update_known_counters()  
         
     def update_shedule(self):
-        self.SCAN_SHED_DAY = settings.SCAN_SHED_DAY
-        self.SCAN_SHED_DOW = settings.SCAN_SHED_DOW
-        self.SCAN_SHED_HOUR = settings.SCAN_SHED_HOUR
-        self.SCAN_SHED_MIN = settings.SCAN_SHED_MIN
+        self.SCAN_SHED_DAY = config.SOPDS_SCAN_SHED_DAY
+        self.SCAN_SHED_DOW = config.SOPDS_SCAN_SHED_DOW
+        self.SCAN_SHED_HOUR = config.SOPDS_SCAN_SHED_HOUR
+        self.SCAN_SHED_MIN = config.SOPDS_SCAN_SHED_MIN
         self.stdout.write('Reconfigure scheduled book-scan (min=%s, hour=%s, day_of_week=%s, day=%s).'%(self.SCAN_SHED_MIN,self.SCAN_SHED_HOUR,self.SCAN_SHED_DOW,self.SCAN_SHED_DAY))
         self.sched.reschedule_job('scan', trigger='cron', day=self.SCAN_SHED_DAY, day_of_week=self.SCAN_SHED_DOW, hour=self.SCAN_SHED_HOUR, minute=self.SCAN_SHED_MIN)
     
     def check_settings(self):
-        settings.constance_update_shedules()
-        if self.SCAN_SHED_MIN==settings.SCAN_SHED_MIN and self.SCAN_SHED_HOUR==settings.SCAN_SHED_HOUR and self.SCAN_SHED_DOW==settings.SCAN_SHED_DOW and self.SCAN_SHED_DAY==settings.SCAN_SHED_DAY:
-            return
         settings.constance_update_all()
+        if self.SCAN_SHED_MIN==config.SOPDS_SCAN_SHED_MIN and \
+           self.SCAN_SHED_HOUR==config.SOPDS_SCAN_SHED_HOUR and \
+           self.SCAN_SHED_DOW==config.SOPDS_SCAN_SHED_DOW and \
+           self.SCAN_SHED_DAY==config.SOPDS_SCAN_SHED_DAY:
+            return
         self.update_shedule()
             
     def start(self):
         writepid(self.pidfile)
-        self.SCAN_SHED_DAY = settings.SCAN_SHED_DAY
-        self.SCAN_SHED_DOW = settings.SCAN_SHED_DOW
-        self.SCAN_SHED_HOUR = settings.SCAN_SHED_HOUR
-        self.SCAN_SHED_MIN = settings.SCAN_SHED_MIN
+        self.SCAN_SHED_DAY = config.SOPDS_SCAN_SHED_DAY
+        self.SCAN_SHED_DOW = config.SOPDS_SCAN_SHED_DOW
+        self.SCAN_SHED_HOUR = config.SOPDS_SCAN_SHED_HOUR
+        self.SCAN_SHED_MIN = config.SOPDS_SCAN_SHED_MIN
         self.stdout.write('Startup scheduled book-scan (min=%s, hour=%s, day_of_week=%s, day=%s).'%(self.SCAN_SHED_MIN,self.SCAN_SHED_HOUR,self.SCAN_SHED_DOW,self.SCAN_SHED_DAY))
         self.sched = BlockingScheduler()
         self.sched.add_job(self.scan, 'cron', day=self.SCAN_SHED_DAY, day_of_week=self.SCAN_SHED_DOW, hour=self.SCAN_SHED_HOUR, minute=self.SCAN_SHED_MIN, id='scan')
@@ -141,7 +142,7 @@ def daemonize():
     os.umask(0)
 
     std_in = open("/dev/null", 'r')
-    std_out = open(settings.SCANNER_LOG, 'a+')
+    std_out = open(config.SOPDS_SCANNER_LOG, 'a+')
     os.dup2(std_in.fileno(), sys.stdin.fileno())
     os.dup2(std_out.fileno(), sys.stdout.fileno())
     os.dup2(std_out.fileno(), sys.stderr.fileno())    
diff --git a/opds_catalog/management/commands/sopds_server.py b/opds_catalog/management/commands/sopds_server.py
index 68030715c19db962b1aaa4a5ef807749ced1b061..8af848560062b0c75860c01c5921656ab2436271 100644
--- a/opds_catalog/management/commands/sopds_server.py
+++ b/opds_catalog/management/commands/sopds_server.py
@@ -7,7 +7,8 @@ from django.core.management.base import BaseCommand
 from django.core.management import call_command
 
 #from opds_catalog.settings import SERVER_LOG, SERVER_PID
-from opds_catalog import settings
+#from opds_catalog import settings
+from constance import config
 
 class Command(BaseCommand):
     help = 'HTTP/OPDS built-in server'
@@ -20,7 +21,7 @@ class Command(BaseCommand):
 
 
     def handle(self, *args, **options):
-        self.pidfile = os.path.join(main_settings.BASE_DIR, settings.SERVER_PID)
+        self.pidfile = os.path.join(main_settings.BASE_DIR, config.SOPDS_SERVER_PID)
         action = options['command']
         self.addr = options['host']
         self.port = int(options['port'])
@@ -76,7 +77,7 @@ def daemonize():
     os.umask(0)
 
     std_in = open("/dev/null", 'r')
-    std_out = open(settings.SERVER_LOG, 'a+')
+    std_out = open(config.SOPDS_SERVER_LOG, 'a+')
     os.dup2(std_in.fileno(), sys.stdin.fileno())
     os.dup2(std_out.fileno(), sys.stdout.fileno())
     os.dup2(std_out.fileno(), sys.stderr.fileno())    
diff --git a/opds_catalog/opds_middleware.py b/opds_catalog/opds_middleware.py
index 07f07c08f93019fa6d0e9cfaad817294011132c0..490bbd261e2bb7e1b4af99a2bea8abc5ce62c806 100644
--- a/opds_catalog/opds_middleware.py
+++ b/opds_catalog/opds_middleware.py
@@ -5,8 +5,8 @@ from django.contrib import auth
 from django.core.exceptions import ImproperlyConfigured
 from django.core.urlresolvers import resolve
 
-from opds_catalog import settings
-
+#from opds_catalog import settings
+from constance import config
 
 class BasicAuthMiddleware(object):
     header = "HTTP_AUTHORIZATION"
@@ -19,7 +19,7 @@ class BasicAuthMiddleware(object):
         return response
 
     def process_request(self,request):
-        if not settings.AUTH:
+        if not config.SOPDS_AUTH:
             return
             
         # AuthenticationMiddleware is required so that request.user exists.
diff --git a/opds_catalog/settings.py b/opds_catalog/settings.py
index 3c1077e355e53132496c78395f6f2f6dc8f4accb..9c10cacf5eb9c093c196ef9f1b15f247198389aa 100644
--- a/opds_catalog/settings.py
+++ b/opds_catalog/settings.py
@@ -6,102 +6,6 @@ from constance import config
 loglevels={'debug':logging.DEBUG,'info':logging.INFO,'warning':logging.WARNING,'error':logging.ERROR,'critical':logging.CRITICAL,'none':logging.NOTSET}
 
 VERSION = "0.40"
-
-# ROOT_LIB содержит путь к каталогу в котором расположена ваша коллекция книг
-ROOT_LIB = config.SOPDS_ROOT_LIB
-
-# Списк форматов книг, которые будут включаться в каталог
-BOOK_EXTENSIONS = config.SOPDS_BOOK_EXTENSIONS.split()
-
-# Скрывает, найденные дубликаты в выдачах книг
-DOUBLES_HIDE = config.SOPDS_DOUBLES_HIDE
-
-# Извлекать метаинформацию из книг fb2
-FB2PARSE = config.SOPDS_FB2PARSE
-
-# cover_show - способ показа обложек:
-# False - не показывать, 
-# True - извлекать обложки на лету и показывать 
-COVER_SHOW = config.SOPDS_COVER_SHOW
-
-# ZIPSCAN = True  - Приводит к сканированию файлов архива
-ZIPSCAN = config.SOPDS_ZIPSCAN
-
-# Указываем какая кодировка для названий файлов используется в ZIP-архивах
-# доступные кодировки: cp437, cp866, cp1251, utf-8
-# по умолчанию применяется кодировка cp437
-# Поскольку в самом ZIP архиве сведения о кодировке, в которой находятся имена файлов - отсутствуют
-# то автоматически определить правильную кодировку для имен файлов не представляется возможным
-# поэтому для того чтобы кириллические имена файлов не ваыглядели как крякозябры следует применять кодировку cp866
-# по умолчанию также используется значение zip_codepage = cp866
-ZIPCODEPAGE = config.SOPDS_ZIPCODEPAGE
-
-# Если INPX_ENABLE = True, то при обнаружении INPX файла в каталоге, сканер не сканирует его содержимое вместе с подгаталогами, а загружает
-# данные из найденного INPX файла. Сканер считает что сами архивыс книгами расположены в этом же каталоге. 
-# Т.е. INPX-файл должен находится именно в папке с архивами книг
-INPX_ENABLE = config.SOPDS_INPX_ENABLE
-
-# Если INPX_SKIP_UNCHANGED = True, то сканер пропускает повторное сканирование, если размер INPX не изменялся
-INPX_SKIP_UNCHANGED = config.SOPDS_INPX_SKIP_UNCHANGED
-
-# Если INPX_TEST_ZIP = True, то сканер пытается найти описанный в INPX архив. Если какой-то архив не обнаруживается, 
-# то сканер не будет добавлять вязанные с ним данные из INPX в базу данных
-# соответсвенно, если INPX_TEST_ZIP = False, то никаких проверок сканер не производит, а просто добавляет данные из INPX в БД
-# это гораздо быстрее
-INPX_TEST_ZIP = config.SOPDS_INPX_TEST_ZIP
-
-# Если INPX_TEST_FILES = True, то сканер пытается найти описанный в INPX конкретный файл с книгой (уже внутри архивов). Если какой-то файл не обнаруживается, 
-# то сканер не будет добавлять эту книгу в базу данных
-# соответсвенно, если INPX_TEST_FILES = False, то никаких проверок сканер не производит, а просто добавляет книгу из INPX в БД
-# это гораздо быстрее
-INPX_TEST_FILES = config.SOPDS_INPX_TEST_FILES
-
-# Установка DELETE_LOGICAL=True приведет к тому, что при обнаружении сканером, что книга удалена, запись в БД об этой книге будет удалена логически (avail=0)
-# Если DELETE_LOGICAL=False, то произойдет физическое удаление таких записей из базы данных
-# пока работает только DELETE_LOGICAL = False
-DELETE_LOGICAL = config.SOPDS_DELETE_LOGICAL
-
-SPLITITEMS = config.SOPDS_SPLITITEMS
-
-# Количество выдаваемых результатов на одну страницу
-MAXITEMS = config.SOPDS_MAXITEMS
-
-# FB2TOEPUB и FB2TOMOBI задают пути к програмам - конвертерам из FB2 в EPUB и MOBI
-FB2TOEPUB = config.SOPDS_FB2TOEPUB
-FB2TOMOBI = config.SOPDS_FB2TOMOBI
-
-# TEMP_DIR задает путь к временному каталогу, который используется для копирования оригинала и результата конвертации
-TEMP_DIR = config.SOPDS_TEMP_DIR
-
-# При скачивании вместо оригинального имени файла книги выдает транслитерацию названия книги
-TITLE_AS_FILENAME = config.SOPDS_TITLE_AS_FILENAME
-
-# Включение дополнительного меню выбора алфавита
-ALPHABET_MENU = config.SOPDS_ALPHABET_MENU
-
-# Обложка, которая будет демонстрироваться для книг без обложек
-NOCOVER_PATH = config.SOPDS_NOCOVER_PATH
-
-# Включение BASIC - авторизации
-AUTH = config.SOPDS_AUTH
-
-# параметры SERVER_LOG и SCANNER_LOG задают размещение LOG файлов этих процессов
-SERVER_LOG = config.SOPDS_SERVER_LOG
-SCANNER_LOG = config.SOPDS_SCANNER_LOG
-
-# параметры SERVER_PID и SCANNER_PID задают размещение PID файлов этих процессов при демонизации
-SERVER_PID = config.SOPDS_SERVER_PID
-SCANNER_PID = config.SOPDS_SCANNER_PID
-
-# SCAN_SHED устанавливают значения шедулера, для периодического сканирования коллекции книг
-# при помощи manage.py sopds_scanner ...
-# Возможные значения можно найти на следующей странице; 
-# https://apscheduler.readthedocs.io/en/latest/modules/triggers/cron.html#module-apscheduler.triggers.cron
-SCAN_SHED_MIN = config.SOPDS_SCAN_SHED_MIN
-SCAN_SHED_HOUR = config.SOPDS_SCAN_SHED_HOUR
-SCAN_SHED_DAY = config.SOPDS_SCAN_SHED_DAY
-SCAN_SHED_DOW = config.SOPDS_SCAN_SHED_DOW
-
 TITLE = getattr(settings, "SOPDS_TITLE", "SimpleOPDS")
 SUBTITLE = getattr(settings, "SOPDS_SUBTITLE", "SimpleOPDS Catalog by www.sopds.ru. Version %s."%VERSION)
 ICON = getattr(settings, "SOPDS_ICON", "/static/images/favicon.ico")
@@ -112,31 +16,13 @@ if loglevel.lower() in loglevels:
 else:
     LOGLEVEL=logging.NOTSET
     
-# Отработка изменения конфигурации    
-import sys
-from constance.signals import config_updated
-from django.dispatch import receiver
-
-@receiver(config_updated)
-def constance_updated(sender, updated_key, new_value, **kwargs):
-    if updated_key == 'SOPDS_BOOK_EXTENSIONS':
-        value = new_value.split()
-    else:
-        value = new_value
-    key=updated_key.replace('SOPDS_','')
-    setattr(sys.modules[__name__], key, value)
- 
-def constance_update_shedules():
-    setattr(sys.modules[__name__], 'SCAN_SHED_MIN', config.SOPDS_SCAN_SHED_MIN)
-    setattr(sys.modules[__name__], 'SCAN_SHED_HOUR', config.SOPDS_SCAN_SHED_HOUR)
-    setattr(sys.modules[__name__], 'SCAN_SHED_DAY', config.SOPDS_SCAN_SHED_DAY)
-    setattr(sys.modules[__name__], 'SCAN_SHED_DOW', config.SOPDS_SCAN_SHED_DOW)   
-
+    
 def constance_update_all():
     pass
     
 # Переопределяем некоторые функции для SQLite, которые работают неправлено
 from django.db.backends.signals import connection_created
+from django.dispatch import receiver
 
 def sopds_upper(s):
     return s.upper()
diff --git a/opds_catalog/sopdscan.py b/opds_catalog/sopdscan.py
index e4816db2b9d22a3a7c805fcb9a1e4d241a16532b..e89204cdbe73fdbc60cd4cfe339c1e80d17d00a1 100644
--- a/opds_catalog/sopdscan.py
+++ b/opds_catalog/sopdscan.py
@@ -8,10 +8,13 @@ import re
 
 from django.db import transaction
 
-from opds_catalog import fb2parse, settings, opdsdb
+from opds_catalog import fb2parse, opdsdb
 from opds_catalog import inpx_parser
+#from opds_catalog import settings
 import opds_catalog.zipf as zipfile
 
+from constance import config
+
 class opdsScanner:
     def __init__(self, logger=None):
         self.fb2parser=None
@@ -44,17 +47,17 @@ class opdsScanner:
     def log_options(self):
         self.logger.info(' ***** Starting sopds-scan...')
         self.logger.debug('OPTIONS SET')
-        if settings.ROOT_LIB!=None:       self.logger.debug('root_lib = '+settings.ROOT_LIB)
-        if settings.FB2TOEPUB!=None: self.logger.debug('fb2toepub = '+settings.FB2TOEPUB)
-        if settings.FB2TOMOBI!=None: self.logger.debug('fb2tomobi = '+settings.FB2TOMOBI)
-        if settings.TEMP_DIR!=None:       self.logger.debug('temp_dir = '+settings.TEMP_DIR)
+        if config.SOPDS_ROOT_LIB!=None:       self.logger.debug('root_lib = '+config.SOPDS_ROOT_LIB)
+        if config.SOPDS_FB2TOEPUB!=None: self.logger.debug('fb2toepub = '+config.SOPDS_FB2TOEPUB)
+        if config.SOPDS_FB2TOMOBI!=None: self.logger.debug('fb2tomobi = '+config.SOPDS_FB2TOMOBI)
+        if config.SOPDS_TEMP_DIR!=None:       self.logger.debug('temp_dir = '+config.SOPDS_TEMP_DIR)
 
     def log_stats(self):
         self.t2=datetime.timedelta(seconds=time.time())
         self.logger.info('Books added      : '+str(self.books_added))
         self.logger.info('Books skipped    : '+str(self.books_skipped))
         self.logger.info('Bad books        : '+str(self.bad_books))
-        if settings.DELETE_LOGICAL:
+        if config.SOPDS_DELETE_LOGICAL:
             self.logger.info('Books deleted    : '+str(self.books_deleted))
         else:
             self.logger.info('Books DB entries deleted : '+str(self.books_deleted))
@@ -78,9 +81,9 @@ class opdsScanner:
                     
         opdsdb.avail_check_prepare()
             
-        for full_path, dirs, files in os.walk(settings.ROOT_LIB, followlinks=True):
+        for full_path, dirs, files in os.walk(config.SOPDS_ROOT_LIB, followlinks=True):
             # Если разрешена обработка inpx, то при нахождении inpx обрабатываем его и прекращаем обработку текущего каталога
-            if settings.INPX_ENABLE:
+            if config.SOPDS_INPX_ENABLE:
                 inpx_files = [inpx for inpx in files if re.match('.*(.inpx|.INPX)$', inpx)]
                 # Пропускаем обработку файлов в текущем каталоге, если найдены inpx
                 if inpx_files:
@@ -93,13 +96,13 @@ class opdsScanner:
                 file=os.path.join(full_path,name)
                 (n,e)=os.path.splitext(name)
                 if (e.lower() == '.zip'):
-                    if settings.ZIPSCAN:
+                    if config.SOPDS_ZIPSCAN:
                         self.processzip(name,full_path,file)
                 else:
                     file_size=os.path.getsize(file)
                     self.processfile(name,full_path,file,None,0,file_size)                   
 
-        #if settings.DELETE_LOGICAL:
+        #if config.SOPDS_DELETE_LOGICAL:
         #    self.books_deleted=opdsdb.books_del_logical()
         #else:
         #    self.books_deleted=opdsdb.books_del_phisical()
@@ -111,7 +114,7 @@ class opdsScanner:
     def inpskip_callback(self, inpx, inp_name, inp_size):
         
         self.zip_file = os.path.join(inpx,"%s%s"%(inp_name,'.zip'))
-        self.rel_path=os.path.relpath(self.zip_file,settings.ROOT_LIB)            
+        self.rel_path=os.path.relpath(self.zip_file,config.SOPDS_ROOT_LIB)            
         
         if opdsdb.arc_skip(self.rel_path,inp_size):
             self.logger.info('Skip ZIP for INP archive '+self.zip_file+'. Not changed.')
@@ -150,20 +153,20 @@ class opdsScanner:
             opdsdb.addbseries(book,ser,0)                         
                    
     def processinpx(self,name,full_path,file):
-        rel_file=os.path.relpath(file,settings.ROOT_LIB)
+        rel_file=os.path.relpath(file,config.SOPDS_ROOT_LIB)
         inpx_size = os.path.getsize(file)
-        if settings.INPX_SKIP_UNCHANGED and opdsdb.inpx_skip(rel_file,inpx_size):
+        if config.SOPDS_INPX_SKIP_UNCHANGED and opdsdb.inpx_skip(rel_file,inpx_size):
             self.logger.info('Skip INPX file = '+file+'. Not changed.')
         else:    
             self.logger.info('Start process INPX file = '+file)
             opdsdb.addcattree(rel_file, opdsdb.CAT_INPX, inpx_size)
             inpx = inpx_parser.Inpx(file, self.inpx_callback, self.inpskip_callback)       
-            inpx.INPX_TEST_ZIP = settings.INPX_TEST_ZIP  
-            inpx.INPX_TEST_FILES = settings.INPX_TEST_FILES 
+            inpx.INPX_TEST_ZIP = config.SOPDS_INPX_TEST_ZIP  
+            inpx.INPX_TEST_FILES = config.SOPDS_INPX_TEST_FILES 
             inpx.parse()
 
     def processzip(self,name,full_path,file):
-        rel_file=os.path.relpath(file,settings.ROOT_LIB)
+        rel_file=os.path.relpath(file,config.SOPDS_ROOT_LIB)
         zsize = os.path.getsize(file)
         if opdsdb.arc_skip(rel_file,zsize):
             self.arch_skipped+=1
@@ -193,8 +196,8 @@ class opdsScanner:
 
     def processfile(self,name,full_path,file,cat,archive=0,file_size=0):
         (n,e)=os.path.splitext(name)
-        if e.lower() in settings.BOOK_EXTENSIONS:
-            rel_path=os.path.relpath(full_path,settings.ROOT_LIB)
+        if e.lower() in config.SOPDS_BOOK_EXTENSIONS.split():
+            rel_path=os.path.relpath(full_path,config.SOPDS_ROOT_LIB)
             self.logger.debug("Attempt to add book "+rel_path+"/"+name)
             self.fb2parser.reset()
             if opdsdb.findbook(name,rel_path,1)==None:
@@ -206,7 +209,7 @@ class opdsScanner:
                 docdate=''
                 book_is_valid = True
 
-                if e.lower()=='.fb2' and settings.FB2PARSE:
+                if e.lower()=='.fb2' and config.SOPDS_FB2PARSE:
                     if isinstance(file, str):
                         f=open(file,'rb')
                     else:
diff --git a/opds_catalog/tests/test_feeds.py b/opds_catalog/tests/test_feeds.py
index 5224dbabd550011f9f85ce7e314179e7c2b75b41..877b893a7d5980cd92ec712a49e9c6b0cb2cfe3d 100644
--- a/opds_catalog/tests/test_feeds.py
+++ b/opds_catalog/tests/test_feeds.py
@@ -4,14 +4,16 @@ from django.core.urlresolvers import reverse
 from django.test import TestCase, Client
 from django.utils.translation import ugettext as _
 
-from opds_catalog import settings, opdsdb
+from opds_catalog import opdsdb
+from opds_catalog import settings
+from constance import config
 
 
 class feedsTestCase(TestCase):
     fixtures = ['testdb.json']
     
     def setUp(self):
-        settings.AUTH=False           
+        config.SOPDS_AUTH=False           
   
     def test_MainFeed(self):
         c = Client()
@@ -111,7 +113,7 @@ class feedsTestCase(TestCase):
         c = Client()
         response = c.get('/opds/books/0/')
         self.assertEquals(response.status_code, 200)
-        if settings.ALPHABET_MENU:
+        if config.SOPDS_ALPHABET_MENU:
             response = c.get(reverse('opds:lang_books'));
             self.assertEquals(response.status_code, 200)
             self.assertIn(_("Cyrillic"), response.content.decode()) 
@@ -122,7 +124,7 @@ class feedsTestCase(TestCase):
         c = Client()
         response = c.get('/opds/authors/0/')
         self.assertEquals(response.status_code, 200)
-        if settings.ALPHABET_MENU:        
+        if config.SOPDS_ALPHABET_MENU:        
             response = c.get(reverse('opds:lang_authors'));
             self.assertEquals(response.status_code, 200)
             self.assertIn(_("Cyrillic"), response.content.decode())  
diff --git a/opds_catalog/tests/test_models.py b/opds_catalog/tests/test_models.py
index 6240d5d063dbbad73881ba05be12baaec8a22dce..8c85181b76c264e0507202c55229216494c0a29c 100644
--- a/opds_catalog/tests/test_models.py
+++ b/opds_catalog/tests/test_models.py
@@ -3,7 +3,7 @@ from datetime import datetime
 from django.test import TestCase
 from django.utils import timezone
 from django.contrib.auth.models import User
-from django.conf import settings
+from django.conf import settings as main_settings
 
 from opds_catalog.models import Book, Catalog, Author, Genre, Series, bookshelf, Counter, bauthor, bgenre, bseries
 from opds_catalog import models
@@ -11,7 +11,7 @@ from opds_catalog import opdsdb
 
 class modelsTestCase(TestCase):
     testdatetime = datetime(2016, 1, 1, 0, 0)
-    if settings.USE_TZ:
+    if main_settings.USE_TZ:
         testdatetime = testdatetime.replace(tzinfo=timezone.get_current_timezone())
 
     def setUp(self):
diff --git a/opds_catalog/tests/test_scan.py b/opds_catalog/tests/test_scan.py
index fb123b4dc6ea9e41598d70a20e4fdd0719bcb859..b6a323c3704fef50c1aa7057920eecd643930a5a 100644
--- a/opds_catalog/tests/test_scan.py
+++ b/opds_catalog/tests/test_scan.py
@@ -4,9 +4,11 @@ from django.test import TestCase
 
 from opds_catalog import opdsdb
 from opds_catalog.sopdscan import opdsScanner
-from opds_catalog import settings
+#from opds_catalog import settings
 from opds_catalog.models import Book, Catalog, Author, Genre, Series
 
+from constance import config
+
 class scanTestCase(TestCase):
     test_module_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
     test_ROOTLIB = os.path.join(test_module_path, 'tests/data')
@@ -14,7 +16,7 @@ class scanTestCase(TestCase):
     test_zip = "books.zip"
 
     def setUp(self):
-        settings.ROOT_LIB = self.test_ROOTLIB
+        config.SOPDS_ROOT_LIB = self.test_ROOTLIB
 
     def test_processfile(self):
         """ Тестирование процедуры processfile (извлекает метаданные из книги и помещает в БД) """
diff --git a/sopds_web_backend/views.py b/sopds_web_backend/views.py
index 797df3353fa82cfbe42cb921cb0b5bfdcc6619d1..578efc3a994fb498085e9cb623153fc0828d19e0 100644
--- a/sopds_web_backend/views.py
+++ b/sopds_web_backend/views.py
@@ -12,7 +12,8 @@ from django.core.urlresolvers import reverse, reverse_lazy
 from opds_catalog import models
 from opds_catalog.models import Book, Author, Series, bookshelf, Counter, Catalog, Genre
 #from opds_catalog.settings import MAXITEMS, DOUBLES_HIDE, AUTH, VERSION, ALPHABET_MENU, SPLITITEMS, FB2TOEPUB, FB2TOMOBI
-from opds_catalog import settings as settings
+from opds_catalog import settings
+from constance import config
 from opds_catalog.models import lang_menu
 from opds_catalog.opds_paginator import Paginator as OPDS_Paginator
 
@@ -20,7 +21,7 @@ from sopds_web_backend.settings import HALF_PAGES_LINKS
 
 def sopds_login(function=None, redirect_field_name=REDIRECT_FIELD_NAME, url=None):
     actual_decorator = user_passes_test(
-        lambda u: (u.is_authenticated() if settings.AUTH else True),
+        lambda u: (u.is_authenticated() if config.SOPDS_AUTH else True),
         login_url=reverse_lazy(url),
         redirect_field_name=redirect_field_name
     ) 
@@ -30,16 +31,16 @@ def sopds_login(function=None, redirect_field_name=REDIRECT_FIELD_NAME, url=None
 
 def sopds_processor(request):
     args={}
-    args['sopds_auth']=settings.AUTH
+    args['sopds_auth']=config.SOPDS_AUTH
     args['sopds_version']=settings.VERSION
-    args['alphabet'] = settings.ALPHABET_MENU
-    args['splititems'] = settings.SPLITITEMS
-    args['fb2tomobi'] = (settings.FB2TOMOBI!="")
-    args['fb2toepub'] = (settings.FB2TOEPUB!="")
-    if settings.ALPHABET_MENU:
+    args['alphabet'] = config.SOPDS_ALPHABET_MENU
+    args['splititems'] = config.SOPDS_SPLITITEMS
+    args['fb2tomobi'] = (config.SOPDS_FB2TOMOBI!="")
+    args['fb2toepub'] = (config.SOPDS_FB2TOEPUB!="")
+    if config.SOPDS_ALPHABET_MENU:
         args['lang_menu'] = lang_menu
     
-    if settings.AUTH:
+    if config.SOPDS_AUTH:
         user=request.user
         if user.is_authenticated():
             result=[]
@@ -137,7 +138,7 @@ def SearchBooksView(request):
                                    
         # Поиск книг на книжной полке            
         elif searchtype == 'u':
-            if settings.AUTH:
+            if config.SOPDS_AUTH:
                 books = Book.objects.filter(bookshelf__user=request.user).order_by('-bookshelf__readtime')
                 args['breadcrumbs'] = [_('Books'),_('Bookshelf'),request.user.username]
                 #books = bookshelf.objects.filter(user=request.user).select_related('book')              
@@ -176,7 +177,7 @@ def SearchBooksView(request):
         
         # Фильтруем дубликаты и формируем выдачу затребованной страницы
         books_count = books.count()
-        op = OPDS_Paginator(books_count, 0, page_num, settings.MAXITEMS, HALF_PAGES_LINKS)
+        op = OPDS_Paginator(books_count, 0, page_num, config.SOPDS_MAXITEMS, HALF_PAGES_LINKS)
         items = []
         
         prev_title = ''
@@ -184,7 +185,7 @@ def SearchBooksView(request):
         
         # Начаинам анализ с последнего элемента на предидущей странице, чторбы он "вытянул" с этой страницы
         # свои дубликаты если они есть
-        summary_DOUBLES_HIDE =  settings.DOUBLES_HIDE and (searchtype != 'd')
+        summary_DOUBLES_HIDE =  config.SOPDS_DOUBLES_HIDE and (searchtype != 'd')
         start = op.d1_first_pos if ((op.d1_first_pos==0) or (not summary_DOUBLES_HIDE)) else op.d1_first_pos-1
         finish = op.d1_last_pos
         
@@ -252,7 +253,7 @@ def SearchSeriesView(request):
             
         # Создаем результирующее множество
         series_count = series.count()
-        op = OPDS_Paginator(series_count, 0, page_num, settings.MAXITEMS, HALF_PAGES_LINKS)        
+        op = OPDS_Paginator(series_count, 0, page_num, config.SOPDS_MAXITEMS, HALF_PAGES_LINKS)        
         items = []
         for row in series[op.d1_first_pos:op.d1_last_pos+1]:
             #p = {'id':row.id, 'ser':row.ser, 'lang_code': row.lang_code, 'book_count': Book.objects.filter(series=row).count()}
@@ -291,7 +292,7 @@ def SearchAuthorsView(request):
                         
         # Создаем результирующее множество
         authors_count = authors.count()
-        op = OPDS_Paginator(authors_count, 0, page_num, settings.MAXITEMS, HALF_PAGES_LINKS)        
+        op = OPDS_Paginator(authors_count, 0, page_num, config.SOPDS_MAXITEMS, HALF_PAGES_LINKS)        
         items = []
         
         for row in authors[op.d1_first_pos:op.d1_last_pos+1]:
@@ -335,7 +336,7 @@ def CatalogsView(request):
     books_count = books_list.count()
     
     # Получаем результирующий список
-    op = OPDS_Paginator(catalogs_count, books_count, page_num, settings.MAXITEMS, HALF_PAGES_LINKS)
+    op = OPDS_Paginator(catalogs_count, books_count, page_num, config.SOPDS_MAXITEMS, HALF_PAGES_LINKS)
     items = []
     
     for row in catalogs_list[op.d1_first_pos:op.d1_last_pos+1]: