Map

1

5/4/2019 6:35:03 PM

Details

diff --git a/ModelData/BusinessModel/MainEntities/MapPoint.cs b/ModelData/BusinessModel/MainEntities/MapPoint.cs
index 3db420f..5a85c23 100644
--- a/ModelData/BusinessModel/MainEntities/MapPoint.cs
+++ b/ModelData/BusinessModel/MainEntities/MapPoint.cs
@@ -19,7 +19,7 @@ namespace ModelData.BusinessModel.MainEntities
     /// \author Denis
     /// \date   31.03.2019
 
-    public class MapPoint : BaseAndInterface.BaseOntologyEntity
+    public class MapPoint : BaseAndInterface.BaseOntologyEntity, IComparable<MapPoint>
     {
         /// \property   public string Position
         ///
@@ -39,7 +39,7 @@ namespace ModelData.BusinessModel.MainEntities
         /// Установлен атрибут IndexAttrib со значением 3.
         /// \returns    The population.
 
-        [IndexAttrib(3)] public string Population { set; get; }
+        [IndexAttrib(3)] public int Population { set; get; }
 
 
 
@@ -95,12 +95,27 @@ namespace ModelData.BusinessModel.MainEntities
                 ["URL"] = this.URL ?? "",
                 ["Название"] = this.Title ?? "",
                 ["Координаты"] = this.Position ?? "",
-                ["Количество населения"] = this.Population,
+                ["Количество населения"] = this.Population.ToString(),
                 ["Тип поселения"] = Concat(this.Type),
                 ["В составе региона"] = Concat(this.Region)
             };
         }
 
+
+
+        /// \fn public int CompareTo(MapPoint p)
+        ///
+        /// \brief  Функция сравнения двух объектов
+        /// Реализует интерфейс IComparable<MapPoint> для сравнения двух объектов и выполнения сортировки массива объектов.
+        /// \warning Сортировка выполняется по убыванию!
+        /// \author Denis
+        /// \date   03.05.2019
+        /// 
+        public int CompareTo(MapPoint p)
+        {
+            return (-1) * this.Population.CompareTo(p.Population);
+        }
+
     }
     /// @}
 }
diff --git a/ModelData/BusinessModel/UnitOfWork/Context.cs b/ModelData/BusinessModel/UnitOfWork/Context.cs
index 19e98a5..8a110b0 100644
--- a/ModelData/BusinessModel/UnitOfWork/Context.cs
+++ b/ModelData/BusinessModel/UnitOfWork/Context.cs
@@ -47,7 +47,7 @@ namespace ModelData.BusinessModel.UnitOfWork
                         URL = str,
                         Title = Convert(elem["title"])/*elem["title"].ToString()*/,
                         Position = Convert(elem["long"]) + " " + Convert(elem["lat"]),                        
-                        Population = Convert(elem["maxPop"])
+                        Population = Int32.Parse(Convert(elem["maxPop"]))
                     };
                     MapPoints.Add(mapPoint);
                 }
diff --git a/ModelData/WebModel/WebDataManager.cs b/ModelData/WebModel/WebDataManager.cs
index 8d22479..f7e5ba8 100644
--- a/ModelData/WebModel/WebDataManager.cs
+++ b/ModelData/WebModel/WebDataManager.cs
@@ -41,14 +41,15 @@ namespace ModelData.WebModel
         public Model GetMapPoints(int YearMin, int YearMax)
         {
             Model model = new Model();
-
-            int maxPop = 0, pop;
+            
             List<string> temp = new List<string>();
 
             BusinessDataManager businessData = BusinessDataManager.Get();
-            var context = businessData.GetSettlements(YearMin, YearMax);
+            var context = businessData.GetSettlements(YearMin, YearMax);           
 
             model.arraySettlements = context.MapPoints.ToArray();
+            //  Сортировка массива по убыванию количества населения
+            Array.Sort(model.arraySettlements);
 
             foreach (var type in context.SettlementTypes)
                 temp.Add(type.Title);
@@ -58,18 +59,24 @@ namespace ModelData.WebModel
             foreach (var region in context.Regions)
                 temp.Add(region.Title);
             model.arrayNameRegions = temp.ToArray();
-            temp.Clear();           
+            temp.Clear();
 
             foreach (var settlement in context.MapPoints)
-            {
-                pop = int.Parse(settlement.Population);
-                if (pop > maxPop) maxPop = pop;
-
                 temp.Add(settlement.Title);
-            }
             model.arrayNameSettlements = temp.ToArray();
-
-            model.InitZoom(maxPop);
+            //  Инициализация уровней приближения убрана в связи с тем, что не найдено решения для оптимального отображения на карте
+            //  Вместо этого будут отображаться первые 40-50-100 самых крупных поселений (значение регулируется в JS коде)
+            //  Для этого в c# коде производится сортировка списка поселений по количеству населения
+
+            //int maxPop = 0;
+            //foreach (var settlement in context.MapPoints)
+            //{
+            //    if (settlement.Population > maxPop)
+            //        maxPop = settlement.Population;
+
+            //    temp.Add(settlement.Title);
+            //}         
+            //model.InitZoom(maxPop);
 
             return model;
         }
diff --git a/Tools/Tools.csproj b/Tools/Tools.csproj
index 9dca9fe..4ff2472 100644
--- a/Tools/Tools.csproj
+++ b/Tools/Tools.csproj
@@ -76,6 +76,8 @@
     <Compile Include="Interfaces\I_MySerializable.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Main\SerializeService.cs" />
+    <Compile Include="Users\User.cs" />
+    <Compile Include="Users\UserContext.cs" />
     <Compile Include="Word\DocXWrite.cs" />
   </ItemGroup>
   <ItemGroup>

Tools/Users/User.cs 17(+17 -0)

diff --git a/Tools/Users/User.cs b/Tools/Users/User.cs
new file mode 100644
index 0000000..4d2fe16
--- /dev/null
+++ b/Tools/Users/User.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tools.Users
+{
+    public class User
+    {
+        public string Login { set; get; }
+        public string Password { set; get; }
+
+        //Пользователь уже авторизован
+        public bool IsAuth { set; get; }
+    }
+}
diff --git a/Tools/Users/UserContext.cs b/Tools/Users/UserContext.cs
new file mode 100644
index 0000000..5eb600c
--- /dev/null
+++ b/Tools/Users/UserContext.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tools.Config;
+
+namespace Tools.Users
+{
+    public class UserContext
+    {
+
+        private static UserContext context;
+
+        public static UserContext Get()
+        {
+            if (context == null)
+                context = new UserContext();
+
+            return context;
+        }
+
+        private UserContext()
+        {
+            ConfigManager configManager = ConfigManager.Get();
+            Users = new List<User>(new User[]
+            {
+                
+                new User()
+                {
+                    Login = configManager.ModeratorName,
+                    Password = configManager.ModeratorPassword
+                }
+            });
+
+
+        }
+
+
+
+        public List<User> Users { private set; get; }
+
+
+
+    }
+}
diff --git a/web-map/Content/Site.css b/web-map/Content/Site.css
index 79de3a0..46ca91d 100644
--- a/web-map/Content/Site.css
+++ b/web-map/Content/Site.css
@@ -25,9 +25,9 @@ textarea {
 
 
 /* ---------------------------------------------------
-        SIDEBAR STYLE
+        sidebar-left STYLE
     ----------------------------------------------------- */
-#sidebar {
+#sidebar-left {
     width: 250px;
     position: fixed;
     top: 55px;
@@ -41,56 +41,63 @@ textarea {
     overflow-y: auto;
 }
 
-#sidebar.active {
+#sidebar-left.active {
     transform: translateX(-115%);
 }
 
-#sidebar .sidebar-header {
+#sidebar-left .sidebar-left-header {
     position: sticky;
     top: 0px;
     padding: 15px;
     background: #4d4d4d; /*#343a40;*/ /*.bg-dark*/
 }
 
-#sidebar .sidebar-text {
+#sidebar-left .sidebar-left-text {
     padding: 0.2rem 0.2rem;
 }
-#sidebar-text .sidebar-text-element {
+#sidebar-left-text .sidebar-left-text-element {
     margin-bottom: 0.5rem;
     padding: 0.5rem 0.5rem;
     background-color: #696969;
     border-radius: .3rem;
 }
 
-#sidebar p {
+/*цвет ссылки в панели*/
+.sidebar-left-text-element p a,
+.sidebar-left-text-element a {
+    color: #32CD32;
+}
+
+#sidebar-left p {
     margin-bottom: 0.2rem;
 }
 
 
-#sidebar ul.components {
+#sidebar-left ul.components {
     padding: 20px 0;
     border-bottom: 1px solid #47748b;
 }
 
-#sidebar ul p {
+#sidebar-left ul p {
     color: #fff;
     padding: 10px;
 }
 
-#sidebar ul li a {
+#sidebar-left ul li a {
     padding: 10px;
     font-size: 1.1em;
     display: block;
 }
 
-    #sidebar ul li a:hover {
+    #sidebar-left ul li a:hover {
         color: #7386D5;
         background: #fff;
     }
 
-#sidebar ul li.active > a, a[aria-expanded="true"] {
+#sidebar-left ul li.active > a, a[aria-expanded="true"] {
     color: #fff;
-    background: #6d7fcc;
+    /*бэкграунд меняет цвет элемента в навбаре при выборе (например при выборе дроп-даун меню)*/
+    /*background: #6d7fcc;*/
 }
 
 
@@ -99,7 +106,7 @@ a[data-toggle="collapse"] {
 }
 
 a[aria-expanded="false"]::before, a[aria-expanded="true"]::before {
-    content: '\e259';
+    /*content: '\e259';*/
     display: block;
     position: absolute;
     right: 20px;
@@ -108,7 +115,7 @@ a[aria-expanded="false"]::before, a[aria-expanded="true"]::before {
 }
 
 a[aria-expanded="true"]::before {
-    content: '\e260';
+    /*content: '\e260';*/
 }
 
 
@@ -151,3 +158,25 @@ a.article, a.article:hover {
     .hideLine [type="checkbox"]:checked ~ p {
         display: block;
     }
+
+
+/* ---------------------------------------------------
+        sidebar-right STYLE
+    ----------------------------------------------------- */
+#sidebar-right {
+    width: 250px;
+    position: fixed;
+    top: 55px;
+    right: 0px;
+    bottom: 30px;
+    z-index: 999;
+    background: #5a6268; /*#6c757d;*/ /*.bg-secondary*/
+    color: #fff;
+    transition: all 0.3s;
+    overflow-x: auto;
+    overflow-y: auto;
+}
+
+#sidebar-right.active {
+    transform: translateX(+115%);
+}
diff --git a/web-map/Controllers/AccountController.cs b/web-map/Controllers/AccountController.cs
new file mode 100644
index 0000000..05d43ca
--- /dev/null
+++ b/web-map/Controllers/AccountController.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Web.Mvc;
+using System.Web.Security;
+
+using Tools.Users;
+using web_map.Models;
+
+namespace web_map.Controllers
+{
+    public class AccountController : BaseController
+    {
+        UserContext userContext = UserContext.Get();
+
+
+        [HttpGet]
+        public ActionResult Index()
+        {
+            //if (User.Identity.IsAuthenticated)
+            //    ViewBag.User = User.Identity.Name;
+            //else
+            //    ViewBag.User = "NoAuth";
+
+            return View();
+        }
+
+
+        [HttpGet]
+        public ActionResult Login()
+        {
+            if (User.Identity.IsAuthenticated)
+                Redirect("/Home/Index");
+                //RedirectToAction("Index");
+
+            return View(new AuthModel());
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public ActionResult Login(AuthModel model)
+        {
+            if (User.Identity.IsAuthenticated)
+                Redirect("/Home/Index");
+                //RedirectToAction("Index");
+
+            // поиск пользователя в бд
+            var user = userContext.Users.
+                FirstOrDefault(e => e.Login == model.Login
+                && e.Password == model.Password);
+
+            if (user != null)
+            {
+                if (!user.IsAuth)
+                {
+                    FormsAuthentication.SetAuthCookie(user.Login, true);
+                    user.IsAuth = true;
+                    return Redirect("/Home/Index");
+                            //RedirectToAction("Index");
+                }
+                else
+                {
+                    return View(new AuthModel
+                    {
+                        AuthError = true,
+                        ErrorMsg = "Пользователь уже авторизован"
+                    });
+                }
+            }
+            else
+            {
+                return View(new AuthModel
+                {
+                    AuthError = true,
+                    ErrorMsg = "Пользователя с таким логином и паролем нет"
+                });
+            }
+
+        }
+
+
+        [HttpGet]
+        public ActionResult Logoff()
+        {
+
+            if (User.Identity.IsAuthenticated)
+            {
+                // поиск пользователя в бд
+                var user = userContext.Users.
+                    FirstOrDefault(e => e.Login == User.Identity.Name);
+
+                if (user != null)
+                    user.IsAuth = false;
+            }
+
+            FormsAuthentication.SignOut();
+            return Redirect("/Home/Index");
+            //RedirectToAction("Index");
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/web-map/Controllers/BaseController.cs b/web-map/Controllers/BaseController.cs
new file mode 100644
index 0000000..83d35bb
--- /dev/null
+++ b/web-map/Controllers/BaseController.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Web.Mvc;
+
+using System.Web.Security;
+using System.Web.Routing;
+
+namespace web_map.Controllers
+{
+    public abstract class BaseController : Controller
+    {
+
+        protected override void Initialize(RequestContext requestContext)
+        {
+            base.Initialize(requestContext);
+
+            ViewBag.isAuth = User.Identity.IsAuthenticated;
+            ViewBag.UserName = (User.Identity.IsAuthenticated) ? User.Identity.Name : "NoAuth";
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/web-map/Controllers/HomeController.cs b/web-map/Controllers/HomeController.cs
index f9e7cf0..afc3531 100644
--- a/web-map/Controllers/HomeController.cs
+++ b/web-map/Controllers/HomeController.cs
@@ -8,7 +8,7 @@ using Tools.Word;
 
 namespace web_map.Controllers
 {
-    public class HomeController : Controller
+    public class HomeController : BaseController
     {
         //SerialazService serialazService = 
         //    new SerialazService();
diff --git a/web-map/Controllers/MapController.cs b/web-map/Controllers/MapController.cs
index b0c1b54..b398a78 100644
--- a/web-map/Controllers/MapController.cs
+++ b/web-map/Controllers/MapController.cs
@@ -7,7 +7,7 @@ using System.Web.Mvc;
 
 namespace web_map.Controllers
 {
-    public class MapController : Controller
+    public class MapController : BaseController
     {
         // GET: Map
         public ActionResult Map()
diff --git a/web-map/Models/AuthModel.cs b/web-map/Models/AuthModel.cs
new file mode 100644
index 0000000..97cad2c
--- /dev/null
+++ b/web-map/Models/AuthModel.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace web_map.Models
+{
+    public class AuthModel
+    {
+        public string Login { set; get; }
+        public string Password { set; get; }
+
+        public bool AuthError { set; get; }
+        public string ErrorMsg { set; get; }
+
+    }
+}
\ No newline at end of file
diff --git a/web-map/Scripts/SiteScripts/AjaxQuery.js b/web-map/Scripts/SiteScripts/AjaxQuery.js
index c971e0d..48e8f6a 100644
--- a/web-map/Scripts/SiteScripts/AjaxQuery.js
+++ b/web-map/Scripts/SiteScripts/AjaxQuery.js
@@ -37,16 +37,16 @@ function GetAllPoints(YearMin, YearMax) {
         },
         success: function (data) {
             //  Заполнить массивы из полученного результата
-            FillDataArrays(data);
-            //  Выбрать, какие именно данные нужно отобразить
+            //  Заполнить коллекцию геообъектами
+            //  
             //  Затем: 
-            //  Загрузить получившийся массив в коллекцию
+            //  Нужно ли делать выборку
             //                     |
             //                     |
             //                     | Выгрузить коллекцию на карту
             //                     |     |
             //                     |     |
-            SelectDataFromArrays(true, true);
+            FillDataArrays(data, true, true);            
         },
 
         error: function (response) {
diff --git a/web-map/Scripts/SiteScripts/Events.js b/web-map/Scripts/SiteScripts/Events.js
index 957b959..2161e9c 100644
--- a/web-map/Scripts/SiteScripts/Events.js
+++ b/web-map/Scripts/SiteScripts/Events.js
@@ -2,99 +2,76 @@
 function SliderOnFinishMoving(data) {   
     CurrentMinYear = data.min;
     CurrentMaxYear = data.max;
-    console.log(CurrentMinYear + " " + CurrentMaxYear);
     GetAllPoints(CurrentMinYear, CurrentMaxYear);
 }
 
+function OnFindNameUsing(name) {
+    //  Добавить в коллекцию, чтобы гарантировать что данный объект появится на карте
+    Collections.FindName = name;
+    //  Найти метку в коллекции всех меток
+    var placemark = Collections.AllGeoObjects.search('options.Name = "' + name + '"').get(0);
+    //  Установить новый цвет
+    placemark.options.set('preset', 'islands#greenStretchyIcon');
+    //  Отцентрировать карту и приблизить
+    Map.setCenter(placemark.geometry.getCoordinates(), 13);
+    //  Через 5 секунд вернуть обратно прежний цвет
+    setTimeout(changePlacemarkPreset, 5000, placemark, 'islands#redStretchyIcon');
+}
+
+function changePlacemarkPreset(placemark, preset) {
+    placemark.options.set('preset', preset);
+}
+
 //  Заполнение массивов из исходного (response.data)
 //  В соответствии с параметрами поселения
-function FillDataArrays(fromData) {
+function FillDataArrays(fromData, isNeedSelect = false, isNeedPlaceCollection = false) {
+
+    Collections.AllGeoObjects.removeFromMap(Map);
+
     Collections.All = new Array();
+    Collections.AllGeoObjects = new ymaps.geoQuery();
     Collections.SettlementTypes = new Array();
     Collections.Regions = new Array();
-    Collections.Zoom_8 = new Array();
-    Collections.Zoom_9 = new Array();
-    Collections.Zoom_10 = new Array();
-    Collections.Zoom_11 = new Array();
-    Collections.Zoom_12 = new Array();
-    Collections.Zoom_13 = new Array();
-    Collections.Zoom_14 = new Array();
-    Collections.Zoom_15 = new Array();
-    Collections.Zoom_16 = new Array();
-    Collections.Zoom_17 = new Array();
-    Collections.Zoom_18 = new Array();
-    Collections.Zoom_19 = new Array();
     Collections.Names = new Array();
+    Collections.FindName = '';
 
+    console.log('Количество загруженных поселений ' + fromData.arraySettlements.length);
+    
     Collections.Names = fromData.arrayNameSettlements;
     Collections.SettlementTypes = fromData.arrayNameTypes;
-    Collections.Regions = fromData.arrayNameRegions;
-
-    console.log(fromData.arraySettlements.length);
-
-    fromData.arraySettlements.forEach(function (element)
-    {
-        //Collections.All.push(element); //   В массив All идут все данные
-        var pop = Number.parseInt(element.Population);  //  Получить числовое представления для сравнения с ключом константы
-        //  Для каждой константы (пара ключ-значение, где 
-        //                                                ключ = имя массива, в который нужно добавить поселение
-        //                                                значение = минимальное количество населения для попадания в массив 
-        //                        )
-        //  Выполнить сравнение количества населения и, если удовлетворяет условию, внести поселение в массив
-        for (var key in fromData.ZoomLevel)
-        {
-            var value = fromData.ZoomLevel[key];
-            if (pop > value)
-                Collections[key].push(element);
-        }          
-    });
-
+    Collections.Regions = fromData.arrayNameRegions;   
     AutoCompleteInit(Collections.Names);
-}
 
-function OnFindNameUsing(name)
-{
-    console.log(name);
+    Collections.All = fromData.arraySettlements;
+    LoadCollection(fromData.arraySettlements, isNeedSelect, isNeedPlaceCollection);
 }
 
+//  Функция заполнения Яндекс-коллекций Яндекс-объектами из JSON массива
+function LoadCollection(fromData, isNeedSelect = false, isNeedPlaceCollection = false) {
+    fromData.forEach(function (element) {
+        Collections.AllGeoObjects = Collections.AllGeoObjects.add(CreateYandexPlacemark(element)); //  Добавление
+    });
+    if (isNeedSelect)
+        SelectDataFromArrays(isNeedPlaceCollection);
+}
 
 //  Согласно текущим установленным фильтрам собрать нужный массив данных
-function SelectDataFromArrays(isNeedLoadCollection = false, isNeedPlaceCollection = false) {
-    var ResultDataArray = new Array();
-
-    switch (CurrentZoom) {
-        case 8: { ResultDataArray = Collections.Zoom_8; break; }
-        case 9: { ResultDataArray = Collections.Zoom_9; break; }
-        case 10: { ResultDataArray = Collections.Zoom_10; break; }
-        case 11: { ResultDataArray = Collections.Zoom_11; break; }
-        case 12: { ResultDataArray = Collections.Zoom_12; break; }
-        case 13: { ResultDataArray = Collections.Zoom_13; break; }
-        case 14: { ResultDataArray = Collections.Zoom_14; break; }
-        case 15: { ResultDataArray = Collections.Zoom_15; break; }
-        case 16: { ResultDataArray = Collections.Zoom_16; break; }
-        case 17: { ResultDataArray = Collections.Zoom_17; break; }
-        case 18: { ResultDataArray = Collections.Zoom_18; break; }
-        case 19: { ResultDataArray = Collections.Zoom_19; break; }
-        default: ResultDataArray = new Array()/*Collections.All*/;
-    }   
-
-    if (isNeedLoadCollection)
-        LoadCollection(ResultDataArray, isNeedPlaceCollection);
+function SelectDataFromArrays(isNeedPlaceCollection = false) {
+    var ResultDataArray = new Array();   
+
+    var CollectionVisible = Collections.AllGeoObjects.searchInside(Map).slice(0, Collections.VisibleCount).addToMap(Map);
+    // Оставшиеся объекты будем удалять с карты.
+    Collections.AllGeoObjects.remove(CollectionVisible).removeFromMap(Map).getLength();
+
+    //for (var i = 0; i < Collections.All.length && i < Collections.VisibleCount; i++) {
+    //    ResultDataArray.push(Collections.All[i]);
+    //}
+
+    //if (isNeedPlaceCollection)
+    //    PlaceFromCollection(geo_query);
     return ResultDataArray;
 }
 
-//  Функция заполнения Яндекс-коллекций Яндекс-объектами из JSON массива
-function LoadCollection(fromData, bool = false)
-{    
-    //  Очистка коллекции от старых элементов. Параметры остаются прежними
-    CollectionVisible.removeAll(); 
-    fromData.forEach(function (element)
-    {
-        CollectionVisible.add(CreateYandexPlacemark(element)); //  Добавление
-    });
-    if (bool)
-        PlaceFromCollection();
-}
 
 //  Функция создания Яндекс-объекта из одного элемента JSON массива
 function CreateYandexPlacemark(fromElement) {
@@ -103,34 +80,38 @@ function CreateYandexPlacemark(fromElement) {
         {
             iconContent: fromElement.Title,   //  Содержимое названия
             hintContent: fromElement.Position//  Содержимое подписи при наведении
+        },
+        {
+            preset: 'islands#redStretchyIcon'
         }
     );
 
     //Добавить свойство - Имя поселения
     placemark.options.set('Name', fromElement.Title);
     placemark.options.set('URL', fromElement.URL);
+    placemark.options.set('Population', fromElement.Population);
+    placemark.options.set('Types', fromElement.Type);
+    placemark.options.set('Regions', fromElement.Region);
 
     //  Переопределяем стадартный обработчик нажатия
     placemark.events.add('click', function (e) {
         e.preventDefault(); //  Запрещаем стандартный обработчик
 
-        var targetName = e.get('target').options.get('Name');
         var targetURL = e.get('target').options.get('URL');
 
         //  Вызов запроса на получение данных о поселении
         GetInfoAboutSettlement(targetURL, PrintInfoAboutSettlement);
-
         //  Показать боковую панель
-        if ($('#sidebar, #content').hasClass('active')) {
+        if ($('#sidebar-left, #content').hasClass('active')) {
             //  Панель скрыта. Должна выехать
-            $('#sidebar, #content').removeClass('active');
+            $('#sidebar-left, #content').removeClass('active');
             $('.collapse.in').toggleClass('in');
             $('a[aria-expanded=true]').attr('aria-expanded', 'false');
         }
         else
             //  Панель есть. Выбор, нужно ли её скрывать
-            if (targetName == document.getElementById('sidebar-header').getElementsByTagName('*')[0].innerHTML) {
-                $('#sidebar, #content').addClass('active');
+            if (targetURL == document.getElementById('settlement-url').innerHTML) {
+                $('#sidebar-left, #content').addClass('active');
                 $('.collapse.in').toggleClass('in');
                 $('a[aria-expanded=true]').attr('aria-expanded', 'false');
             }
@@ -138,4 +119,30 @@ function CreateYandexPlacemark(fromElement) {
 
     });
     return placemark;
-}
\ No newline at end of file
+}
+
+
+// функция динамической сортировки
+function compareValues(key, order = 'asc') {
+    return function (a, b) {
+        if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
+            // свойства нет ни в одном из объектов
+            return 0;
+        }
+
+        const varA = (typeof a[key] === 'string') ?
+            a[key].toUpperCase() : a[key];
+        const varB = (typeof b[key] === 'string') ?
+            b[key].toUpperCase() : b[key];
+
+        let comparison = 0;
+        if (varA > varB) {
+            comparison = 1;
+        } else if (varA < varB) {
+            comparison = -1;
+        }
+        return (
+            (order == 'desc') ? (comparison * -1) : comparison
+        );
+    };
+}   
\ No newline at end of file
diff --git a/web-map/Scripts/SiteScripts/Init.js b/web-map/Scripts/SiteScripts/Init.js
index 596ec21..eb4cf0f 100644
--- a/web-map/Scripts/SiteScripts/Init.js
+++ b/web-map/Scripts/SiteScripts/Init.js
@@ -9,7 +9,6 @@ function MapInit()
 }
 
 var Collections;
-var CollectionVisible;
 
 var Map;
 var CurrentZoom;
@@ -42,12 +41,20 @@ function YandexMapInit()
     // Будем отслеживать зум карты при смене видимых границ (движение карты и смена zoom)
     Map.events.add('boundschange', function (event)
     {
-        CurrentZoom = event.get('newZoom');       
-        if (CurrentZoom != event.get('oldZoom'))
-        {
-            //console.log(event.get('oldZoom') + " " + CurrentZoom);
-            SelectDataFromArrays(true, true);
-        }
+        // фильтрация поселений в принципе при движении по карте
+
+        //                 Выгрузить коллекцию на карту
+        //                     |
+        //                     |
+        SelectDataFromArrays(true);
+
+        //  фильтрация поселений при зуммировании
+        //CurrentZoom = event.get('newZoom');       
+        //if (CurrentZoom != event.get('oldZoom'))
+        //{
+        //    //console.log(event.get('oldZoom') + " " + CurrentZoom);
+        //    SelectDataFromArrays(true, true);
+        //}
     });
 
     // Загрузим регионы.
@@ -153,12 +160,31 @@ function SliderInit() {
             OnFindNameUsing(resultName);
     });
 
-    //  Обработчик кнопки скорытия боковой панели
-    $('#sidebar-close').bind('click', function () {
-        $('#sidebar, #content').addClass('active');
+    //  Обработчик кнопки сокрытия левой боковой панели
+    $('#sidebar-left-close').bind('click', function () {
+        $('#sidebar-left, #content').addClass('active');
         $('.collapse.in').toggleClass('in');
         $('a[aria-expanded=true]').attr('aria-expanded', 'false');
     });
+
+    // Кнопка сокрытия правой боковой панели
+    $('#sidebar-right-export').bind('click', OpenCloseRightPanel);
+    
+}
+
+//  Обработчик кнопки сокрытия правой боковой панели
+function OpenCloseRightPanel() {
+    if ($('#sidebar-right, #content').hasClass('active')) {
+        //  Панель скрыта. Должна выехать
+        $('#sidebar-right, #content').removeClass('active');
+        $('.collapse.in').toggleClass('in');
+        $('a[aria-expanded=true]').attr('aria-expanded', 'false');
+    }
+    else {
+        $('#sidebar-right, #content').addClass('active');
+        $('.collapse.in').toggleClass('in');
+        $('a[aria-expanded=true]').attr('aria-expanded', 'false');
+    }
 }
 
 function AutoCompleteInit(data) {
@@ -174,11 +200,6 @@ function AutoCompleteInit(data) {
             })
             response(results.slice(0, 10));
         },
-        //source: function (request, response) {
-        //    var results = $.ui.autocomplete.filter(data, request.term);
-
-        //    response(results.slice(0, 10));
-        //},
         minLength: 2,
         delay: 300,
         select: function(event, ui) {
@@ -194,27 +215,11 @@ function CollectionsInit() {
 
     Collections = new Object();
     Collections.All = new Array();
+    Collections.AllGeoObjects = new ymaps.geoQuery();
     Collections.SettlementTypes = new Array();
     Collections.Regions = new Array();
-    Collections.Zoom_8 = new Array();
-    Collections.Zoom_9 = new Array();
-    Collections.Zoom_10 = new Array();
-    Collections.Zoom_11 = new Array();
-    Collections.Zoom_12 = new Array();
-    Collections.Zoom_13 = new Array();
-    Collections.Zoom_14 = new Array();
-    Collections.Zoom_15 = new Array();
-    Collections.Zoom_16 = new Array();
-    Collections.Zoom_17 = new Array();
-    Collections.Zoom_18 = new Array();
-    Collections.Zoom_19 = new Array();
-    Collections.FindName = new Array();
+    Collections.FindName = '';
+    Collections.VisibleCount = 50;
     Collections.Names = new Array();
     Collections.Export = new Array();
-    //  Коллекция для отражения данных на карте.
-    CollectionVisible = new ymaps.GeoObjectCollection({},
-        {
-            //  Параметр коллекции всех элементов, отображающий название в красной рамке
-            preset: 'islands#redStretchyIcon'
-        });
 }
\ No newline at end of file
diff --git a/web-map/Scripts/SiteScripts/Output.js b/web-map/Scripts/SiteScripts/Output.js
index f2b9377..935e892 100644
--- a/web-map/Scripts/SiteScripts/Output.js
+++ b/web-map/Scripts/SiteScripts/Output.js
@@ -4,10 +4,11 @@ function PrintInfoAboutSettlement(info)
     // ВНИМАНИЕ! я никудышный верстальщик, поэтому делаю как умею. никогда этому не учился, и никто меня не учил
 
     document.getElementById('settlement-title').innerHTML = info.Title;
+    document.getElementById('settlement-url').innerHTML = info.URL;
 
     //jumbotron
 
-    var text = '<div class="sidebar-text-element">';
+    var text = '<div class="sidebar-left-text-element">';
     text += '<p>' + 'Координаты: ' + info.Coordinate.Lat + ' ' + info.Coordinate.Long + '</p>';
     if (info.Founder != null)
         text += '<p>' + 'Основатель: ' + info.Founder + '</p>';
@@ -15,16 +16,18 @@ function PrintInfoAboutSettlement(info)
     if (info.Legend != null)
     {
         //text += '<p>' + 'Легенда:</p>';
-        text += '<div class="hideLine"><label for="hideLine1">Легенда: [показать]</label><input type="checkbox" id="hideLine1"/>';
+        //  тут часть текста ("показать") выделяется другим цветом
+        text += '<div class="hideLine"><label for="hideLine1">Легенда: <span style="color: #32CD32">[показать]</span></label><input type="checkbox" id="hideLine1"/>';
         text += '<p class="content">' + info.Legend + '</p></div>';
     }
     if (info.hasBeginning != null)
         text += '<p>' + 'Время основания: ' + info.hasBeginning + '</p>';
 
-    text += '</div>';
+    text += '</div>'; 
+    text += '<hr style="border: none; background-color: #32CD32; color: #32CD32; height: 2px;">';
     if (info.EditedSettlements != null)
         info.EditedSettlements.forEach(function (element) {
-            text += '<div class="sidebar-text-element">';
+            text += '<div class="sidebar-left-text-element">';
 
             if (element.PopulationAll != null)
                 text += '<p>' + 'Количество населения: ' + element.PopulationAll + '</p>';
@@ -48,12 +51,13 @@ function PrintInfoAboutSettlement(info)
             text += '</div>';
         });    
 
-    document.getElementById('sidebar-text').innerHTML = text;
+    document.getElementById('sidebar-left-text').innerHTML = text;
 }
 
 //  Функция выгружает все гео-объекты из данной коллекции на карту
 function PlaceFromCollection() {
-    Map.geoObjects.add(CollectionVisible);
+    CollectionVisible.addToMap(Map);
+    //Map.geoObjects.add(CollectionVisible);
 
     //var arr = [];
     //var i = 0;
diff --git a/web-map/Views/Account/Index.cshtml b/web-map/Views/Account/Index.cshtml
new file mode 100644
index 0000000..540d01a
--- /dev/null
+++ b/web-map/Views/Account/Index.cshtml
@@ -0,0 +1,11 @@
+@{
+    ViewBag.Title = "Index";
+}
+
+<h3>Index</h3>
+
+<p>Login: @ViewBag.UserName;</p>
+<p>тут можно будет изменить пароль</p>
+
+
+
diff --git a/web-map/Views/Account/Login.cshtml b/web-map/Views/Account/Login.cshtml
new file mode 100644
index 0000000..4b1ae16
--- /dev/null
+++ b/web-map/Views/Account/Login.cshtml
@@ -0,0 +1,27 @@
+@model web_map.Models.AuthModel
+
+@{
+    ViewBag.Title = "Login";
+}
+
+
+<form class="px-4 py-4" action="/Account/Login" method="post">
+
+    @if (Model.AuthError)
+    {
+        <div class="control-group error">
+            <span class="text-danger"><b>@Model.ErrorMsg</b></span>
+        </div>
+    }
+    @Html.AntiForgeryToken()
+    @Html.ValidationSummary(true)
+    <div class="form-group">
+        <label for="Login"><b>Login</b></label>
+        <input type="text" class="form-control" id="Login" name="Login" placeholder="Ваш логин" value="">
+    </div>
+    <div class="form-group">
+        <label for="Password"><b>Password</b></label>
+        <input type="password" class="form-control" id="Password" name="Password" placeholder="Ваш пароль" value="">
+    </div>
+    <button type="submit" class="btn btn-secondary">Вход</button>
+</form>       
\ No newline at end of file
diff --git a/web-map/Views/Map/Map.cshtml b/web-map/Views/Map/Map.cshtml
index 2ac0702..f6a2cbd 100644
--- a/web-map/Views/Map/Map.cshtml
+++ b/web-map/Views/Map/Map.cshtml
@@ -3,27 +3,53 @@
 }
 
 <div class="wrapper">
-    <!-- боковая панель -->
-    <nav id="sidebar" class="active rounded-right">
-        <div id="sidebar-header" class="sidebar-header display-3 rounded-right">
+    <!-- боковая левая панель -->
+    <nav id="sidebar-left" class="active rounded-right">
+        <div id="sidebar-left-header" class="sidebar-left-header display-3 rounded-right">
             <h2 id="settlement-title" class="text-center"></h2>
+            <label id="settlement-url" hidden>111111</label>
             <div class="d-flex justify-content-center  btn-group w-100" role="group">
-                <button id="sidebar-close" class="btn btn-secondary" type="button">Скрыть<br>панель</button>
+                <button id="sidebar-left-close" class="btn btn-secondary" type="button">Скрыть<br>панель</button>
                 <button id="add-to-export-group" class="btn btn-secondary" type="button">Добавить<br>в экспорт</button>
             </div>
         </div>
-        <div id="sidebar-text" class="sidebar-text">
+        <div id="sidebar-left-text" class="sidebar-left-text">
         </div>
     </nav>
 </div>
 
-<div class="input-group mt-3 mb-2">
-    <span class="input-group-btn">
-        <button id="buttonSearch" class="btn btn-secondary" type="button">Найти</button>
-    </span>
-    <input id="inputName" type="text" class="form-control" placeholder="Введите название">
+<div class="wrapper">
+    <!-- боковая правая панель -->
+    <nav id="sidebar-right" class="active rounded-right">
+        @*<div id="sidebar-right-header" class="sidebar-right-header display-3 rounded-right">
+            <h2 id="settlement-title" class="text-center"></h2>
+            <label id="settlement-url" hidden>111111</label>
+            <div class="d-flex justify-content-center  btn-group w-100" role="group">
+                <button id="sidebar-right-close" class="btn btn-secondary" type="button">Скрыть<br>панель</button>
+                <button id="add-to-export-group" class="btn btn-secondary" type="button">Добавить<br>в экспорт</button>
+            </div>
+        </div>
+        <div id="sidebar-right-text" class="sidebar-right-text">
+        </div>*@
+        <h2>тут что-то есть</h2>
+    </nav>
 </div>
 
+<div class="row">
+    <div class="input-group mt-3 mb-2 col-md-6">
+        <span class="input-group-btn">
+            <button id="buttonSearch" class="btn btn-secondary" type="button">Найти</button>
+        </span>
+        <input id="inputName" type="text" class="form-control" placeholder="Введите название">
+    </div>
+    <div class="btn-group mt-3 mb-2 col-md-6" role="group">
+        <button id="sidebar-right-export" type="button" class="btn btn-secondary">Экспорт</button>
+        @if ((bool)ViewBag.isAuth)
+        {
+            <button id="sidebar-import-export" type="button" class="btn btn-secondary">Импорт</button>
+        }
+    </div>
+</div>
 <div id="slider"></div>
 
 <div class="input-group w-100 mb-3 mt-1">
@@ -47,4 +73,4 @@
 
 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" />
 <link rel="stylesheet" href="http://bootstraptema.ru/plugins/2018/irs/ion.rangeSlider.css" />
-<link rel="stylesheet" href="http://bootstraptema.ru/plugins/2018/irs/ion.rangeSlider.skin.css" />
\ No newline at end of file
+<link rel="stylesheet" href="http://bootstraptema.ru/plugins/2018/irs/ion.rangeSlider.skin.css" />
diff --git a/web-map/Views/Shared/_Layout.cshtml b/web-map/Views/Shared/_Layout.cshtml
index 574b37d..a1afbee 100644
--- a/web-map/Views/Shared/_Layout.cshtml
+++ b/web-map/Views/Shared/_Layout.cshtml
@@ -10,18 +10,55 @@
 </head>
 <body>
     <nav class="navbar navbar-expand-sm navbar-dark fixed-top bg-dark">
-        <div class="container">
             <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                 <span class="navbar-toggler-icon"></span>
             </button>
-            <div class="navbar-collapse collapse" id="navbarSupportedContent">
-                <ul class="nav navbar-nav mr-auto">
-                    <li class="nav-item">@Html.ActionLink("О проекте", "Index", "Home", null, new { @class = "nav-link" })</li>
-                    <li class="nav-item">@Html.ActionLink("Карта", "Map", "Map", null, new { @class = "nav-link" })</li>
-                    <li class="nav-item">@Html.ActionLink("Инструкция", "FAQ", "Home", null, new { @class = "nav-link" })</li>
+
+            <div class="collapse navbar-collapse" id="navbarSupportedContent">
+                <ul class="navbar-nav mr-auto">
+                    <li class="nav-item">
+                        <a class="nav-link" href="/Home">О проекте@*<span class="sr-only">(current)</span>*@</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/Map/Map">Карта</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/Home/FAQ">Инструкция</a>
+                    </li>
+                    <li class="nav-item dropdown">
+                        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown1" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Аккаунт</a>
+                        <div class="dropdown-menu" aria-labelledby="navbarDropdown1">
+
+                            @if ((bool)ViewBag.isAuth)
+                            {
+                                <a class="dropdown-item" href="/Account"><b>@ViewBag.UserName</b></a>
+                                <div class="dropdown-divider"></div>
+                                <a class="dropdown-item" href="/Account/Logoff">Выход</a>
+                            }
+                            else
+                            {
+                                <form class="px-3 py-3" action="/Account/Login" method="post">
+                                    @Html.AntiForgeryToken()
+                                    @Html.ValidationSummary(true)
+                                    <div class="form-group">
+                                        <label for="Login"><b>Login</b></label>
+                                        <input type="text" class="form-control" id="Login" name="Login" placeholder="Ваш логин" value="">
+                                    </div>
+                                    <div class="form-group">
+                                        <label for="Password"><b>Password</b></label>
+                                        <input type="password" class="form-control" id="Password" name="Password" placeholder="Ваш пароль" value="">
+                                    </div>
+                                    <button type="submit" class="btn btn-secondary">Вход</button>
+                                </form>
+                            }
+                        </div>
+                    </li>
                 </ul>
+                @*<form class="form-inline my-2 my-lg-0">
+                    <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
+                    <button class="btn btn-outline-info my-2 my-sm-0" type="submit">Search</button>
+                </form>*@
             </div>
-        </div>
     </nav>
     <div class="container body-content">
         @RenderBody()
diff --git a/web-map/Web.config b/web-map/Web.config
index 0d45d2a..3d3854b 100644
--- a/web-map/Web.config
+++ b/web-map/Web.config
@@ -25,6 +25,12 @@
       <add name="TelemetryCorrelationHttpModule" type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation" />
       <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" />
     </httpModules>
+
+    <!--Auth -->
+    <authentication mode="Forms">
+      <forms name="AuthCookies" timeout="120" loginUrl="~/Account/Login" />
+    </authentication>
+    
   </system.web>
   <system.webServer>
     <modules>
diff --git a/web-map/web-map.csproj b/web-map/web-map.csproj
index c2f92bd..b986cad 100644
--- a/web-map/web-map.csproj
+++ b/web-map/web-map.csproj
@@ -162,12 +162,15 @@
     <Compile Include="App_Start\FilterConfig.cs" />
     <Compile Include="App_Start\RouteConfig.cs" />
     <Compile Include="App_Start\WebApiConfig.cs" />
+    <Compile Include="Controllers\AccountController.cs" />
+    <Compile Include="Controllers\BaseController.cs" />
     <Compile Include="Controllers\HomeController.cs" />
     <Compile Include="Controllers\MapAPIController.cs" />
     <Compile Include="Controllers\MapController.cs" />
     <Compile Include="Global.asax.cs">
       <DependentUpon>Global.asax</DependentUpon>
     </Compile>
+    <Compile Include="Models\AuthModel.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -184,7 +187,6 @@
     <Content Include="Content\jquery-ui\jquery-ui.structure.min.css" />
     <Content Include="Content\jquery-ui\jquery-ui.theme.css" />
     <Content Include="Content\jquery-ui\jquery-ui.theme.min.css" />
-    <Content Include="Content\bootstrap-slider.min.css" />
     <Content Include="favicon.ico" />
     <Content Include="Global.asax" />
     <Content Include="Content\Site.css" />
@@ -199,7 +201,6 @@
     <Content Include="Content\bootstrap-grid.css.map" />
     <None Include="packages.config" />
     <None Include="Properties\PublishProfiles\FolderProfile.pubxml" />
-    <Content Include="Scripts\bootstrap-slider.min.js" />
     <Content Include="Scripts\bootstrap.bundle.js" />
     <Content Include="Scripts\bootstrap.bundle.min.js" />
     <Content Include="Scripts\bootstrap.js" />
@@ -267,10 +268,12 @@
     <Content Include="Scripts\popper.js.map" />
     <Content Include="Scripts\popper-utils.min.js.map" />
     <Content Include="Scripts\popper-utils.js.map" />
+    <Content Include="Views\Account\Index.cshtml" />
+    <Content Include="Views\Account\Login.cshtml" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="App_Data\" />
-    <Folder Include="Models\" />
+    <Folder Include="Views\Base\" />
     <Folder Include="Views\MapAPI\" />
   </ItemGroup>
   <ItemGroup>