diff --git a/media/js/admin/students/add.js b/media/js/admin/students/add.js
index 80eeae09a0c94e227a00eb5e0d1eacc6ff50fef8..e02cdc8df339c7cb319baa07efc4e59bc2750fb1 100644
--- a/media/js/admin/students/add.js
+++ b/media/js/admin/students/add.js
@@ -25,33 +25,20 @@ $(function () {
         }
     });
 
+    let groupSelect = getGroupLoader($groupSelect,
+        () => ({FacultyID: +$facultySelect.val(), 'GradeID': +$gradeSelect.val()})
+    ).setOnChange(OptionLoader.stubFoo);
+
     // Выбор курса
-    $gradeSelect.change(function () {
+    $gradeSelect.change(() => {
         $searchResults.html('');
-        $groupSelect.attr('disabled', 'disabled');
-        $groupSelect.html('<option value="0">— Учебная группа —</option>');
-
-        if (($gradeSelect.find('option:selected').val() != '0')) {
-            $.post(URLdir + 'handler/students/getGroups', {
-                'facultyID': $facultySelect.find('option:selected').val(),
-                'gradeNum': $gradeSelect.find('option:selected').val()
-            }, function (data) {
-                $.each(data, function (i) {
-                    $groupSelect.append('<optgroup label="' + data[i].SpecName + '">');
-                    $.each(data[i].Groups, function (j) {
-                        $groupSelect.append('<option value="' + data[i].Groups[j].ID + '">' + data[i].Groups[j].Num + ' РіСЂСѓРїРїР°</option>');
-                    });
-                    $groupSelect.append('</optgroup>');
-                });
-                $groupSelect.removeAttr('disabled');
-            }, 'json');
-        }
+        groupSelect.reload();
     });
 
     // Выбор группы
     $groupSelect.change(function () {
         if (($groupSelect.find('option:selected').val() != '0')) {
-            $inputGroupSubmit.removeAttr('disabled');
+            $inputGroupSubmit.turnOn();
         }
     });
 
diff --git a/media/js/admin/students/profile.js b/media/js/admin/students/profile.js
index 5747bc95e1a16047c80ded3d94693a0ff4c38080..e92c3145933cb8241e06078cb59ba78228960b92 100644
--- a/media/js/admin/students/profile.js
+++ b/media/js/admin/students/profile.js
@@ -1,23 +1,12 @@
 $(function () {
+    // todo: used in dead url (see office/students/action_profile)
+    // todo: название переменной не соответствует содержимому - group, grade
     var $grade = $("#SelectGroup");
+    var $groupSelect = $("#SelectGroup")
 
-    $grade.change(function () {
-        $grade.html('');
-        $grade.attr('disabled', 'disabled');
-        $.post(URLdir + 'handler/students/getGroups', {
-                'facultyID': facultyID,
-                'gradeNum': $grade.find('option:selected').val()
-            },
-            function (data) {
-                $.each(data, function (i) {
-                    var grade = data[i];
-                    $.each(grade.Groups, function (j) {
-                        var group = grade.Groups[j];
-                        var option = '<option value="' + group.ID + '">' + group.Num + ' РіСЂСѓРїРїР° (' + grade.SpecAbbr + ')</option>';
-                        $("#SelectGroup").append(option);
-                    });
-                });
-                $grade.removeAttr("disabled");
-            }, "json");  // fixme what is it?
-    });
+    let groupSelect = getGroupLoader($groupSelect,
+        () => ({FacultyID: facultyID, 'GradeID': +$grade.find('option:selected').val()})
+    ).setOnChange(OptionLoader.stubFoo);
+
+    $grade.change(() => groupSelect.reload());
 });
diff --git a/media/js/config.js b/media/js/config.js
index 451cdfc8c237c73a69d16cfbaa0236e42caafbb9..16bdcb30c212443ee2788048622899afdf2e1a98 100644
--- a/media/js/config.js
+++ b/media/js/config.js
@@ -97,3 +97,10 @@ Element.prototype.toggleClass = function (className) {
         this.className += ' ' + className;
     }
 };
+
+let getSettings = (() => {
+    let $hiddenInfo = $('#hidden_div');
+    let settings = $.parseJSON($hiddenInfo.html());
+    $hiddenInfo.remove();
+    return settings;
+});
diff --git a/media/js/controls/search.js b/media/js/controls/search.js
index 04e457e7ae85a47ea6148190daf2f4bc8180851c..d9f92f2f25a98f1c16dd719b12d121c84ed7dae2 100644
--- a/media/js/controls/search.js
+++ b/media/js/controls/search.js
@@ -1,3 +1,6 @@
+// todo: unused file
+// todo: depends on optionLoader.js
+
 // Класс поисковой формы
 function cSearch() {
     this._jSearchResultContainer = $('.SearchResult');
@@ -80,28 +83,21 @@ function SearchStudent(jName, jFacultySelect, jGradeSelect, jGroupSelect) {
             });
         };
 
+
+        let groupSelect = getGroupLoader(jGroupSelect,
+            () => ({FacultyID: +jFacultySelect.val(), 'GradeID': +jGradeSelect.val()})
+        ).setOnChange(OptionLoader.stubFoo);
+
         jName.keyup(typeWatcher).bind("paste", typeWatcher);
         jFacultySelect.change(function (){
             jGradeSelect.find('option[value=0]').attr("selected", "selected");
-            jGroupSelect.html("").attr("disabled", "disabled").append('<option>-- Фильтр по группе --</option>');
+            groupSelect.nullify();
             self.Search();
         });
+
         jGradeSelect.change(function () {
             self.Search();
-            jGroupSelect.html("").attr("disabled", "disabled").append('<option>-- Фильтр по группе --</option>');
-            $.post(URLdir + 'handler/students/getGroups',
-                {
-                    facultyID: jFacultySelect.find('option:selected').val(),
-                    gradeNum: jGradeSelect.find('option:selected').val() // FIXME: хендлеру нужен gadeNum
-                },
-                function (response) {
-                    jGroupSelect.removeAttr("disabled");
-                    $.each(response, function (i) {
-                        var option = Mustache.render("<option value='{{ ID }}'>{{ Num }} РіСЂСѓРїРїР° ({{ SpecName }})</option>", response[i]);
-                        jGroupSelect.append(option);
-                    });
-                },
-                "json");
+            groupSelect.reload();
         });
         jGroupSelect.change(self.Search);
     }
diff --git a/media/js/dean/bill.js b/media/js/dean/bill.js
index 84c2be2e410e2ad9b3ac920f37da6d96de9b81de..d78464331e3e6a8752ee73cc199739af62439989 100644
--- a/media/js/dean/bill.js
+++ b/media/js/dean/bill.js
@@ -1,10 +1,5 @@
 $(function () {
-    let settings = (() => {
-        let $hiddenInfo = $('#hidden_div');
-        let settings = $.parseJSON($hiddenInfo.html());
-        $hiddenInfo.remove();
-        return settings;
-    })();
+    let settings = getSettings();
 
     let $semesterSelect = $('#semesterSelect');
     let $gradeSelect = $('#gradeSelect');
diff --git a/media/js/dean/dean.js b/media/js/dean/dean.js
index 8cdd8114ecae250d2f3c76f1aaacfa16c782efb3..4911436750f02da1e4125d8797c2baf09ad59532 100644
--- a/media/js/dean/dean.js
+++ b/media/js/dean/dean.js
@@ -1,73 +1,54 @@
 var $ = jQuery;
 var langNotChosen = '– Не выбрана –';
 
-$(function() {
-	
-	function controlVisualization() {
-		var disciplineType = $("input[name=DisciplineType]:checked").val();
-		if (disciplineType === 'exam') {
-			$("#SelectDisciplineDiv").show();
-			$("#DownloadStatement").hide();
-		} else if (disciplineType === 'credit') {
-			$("#SelectDisciplineDiv").hide();
-			$("#DownloadStatement").show();
-		}
-	}
+$(function () {
+
+    let settings = getSettings();
+
+    function controlVisualization() {
+        var disciplineType = $("input[name=DisciplineType]:checked").val();
+        if (disciplineType === 'exam') {
+            $("#SelectDisciplineDiv").show();
+            $("#DownloadStatement").hide();
+        } else if (disciplineType === 'credit') {
+            $("#SelectDisciplineDiv").hide();
+            $("#DownloadStatement").show();
+        }
+    }
 
     // on page loaded
     controlVisualization();
 
     var jDownloadStatement = $("#DownloadStatement");
     var jDownloadExamDocument = $("#DownloadExamDocument");
-	var jSelectGroup = $("#SelectGroup");
-	var jSelectDiscipline = $("#SelectDiscipline");
+    var jSelectGroup = $("#SelectGroup");
+    var jSelectDiscipline = $("#SelectDiscipline");
     var jDownloadXML = $("#DownloadXML");
+    let $grade = $("#SelectGrade");
+
 
     $("#ExamChoice").change(controlVisualization);
+
     $("#CreditChoice").change(controlVisualization);
-	
 
-    //Получить список групп по ID курса
-    $("#SelectGrade").change(function() {
-        var gradeID = parseInt($(this).val()) || 0;
-        if (gradeID > 0) {
-            $.post(
-                g_URLdir + "handler/GetData/GetGroups",
-                {   
-                    "GradeID": gradeID 
-                },
-                function(d){
-                    d = $.parseJSON(d);
-                    if(d.success === true) {
-                    	console.log(d.data);
-                    	var i = 0;
-                    	jSelectGroup.html("<option>" + langNotChosen + "</option>");
-						jSelectDiscipline.html("<option>" + langNotChosen + "</option>");
-                    	for (i in d.data)
-                    	{
-                    		group = d.data[i];
-                    		jSelectGroup.append("<option value='"+ group.ID +"'>Группа "+ group.GroupNum +" ("+ group.SpecAbbr +")</option>");
-                    	}
-                    	if (i > 0 )
-                    		jSelectGroup.removeAttr("disabled");
-                    }
-                }
-            );
-        }
-        else 
-        {
-        	jSelectGroup.attr("disabled", "disabled");
-        	jSelectGroup.html("<option>" + langNotChosen + "</option>");
+    let groupSelect = getGroupLoader(jSelectGroup,
+        () => ({FacultyID: settings.facultyID, 'GradeID': +$grade.val()})
+    ).setOnChange(OptionLoader.stubFoo);
 
-        	jDownloadStatement.attr("disabled", "disabled");
-        }
-		jDownloadExamDocument.attr("disabled", "disabled");
-        jDownloadXML.attr("disabled", "disabled");
+    //Получить список групп по ID курса
+    $grade.change(function () {
+        let gradeID = +$grade.val();
+        if (gradeID > 0)
+            groupSelect.reload();
+        else
+            jDownloadStatement.turnOff();
+        jDownloadExamDocument.turnOff();
+        jDownloadXML.turnOff();
     });
 
-    $("#SelectGroup").change(function() {
-        var groupID = parseInt($(this).val()) || 0;
-	 	if (groupID > 0) {
+    jSelectGroup.change(function () {
+        var groupID = +jSelectGroup.val();
+        if (groupID > 0) {
             jDownloadStatement.removeAttr("disabled");
 
             // Заполнить список дисциплин
@@ -80,7 +61,6 @@ $(function() {
                 function (d) {
                     d = $.parseJSON(d);
                     if (d.success === true) {
-                        console.log(d.data);
                         var i = 0;
                         jSelectDiscipline.html("<option>" + langNotChosen + "</option>");
                         for (i in d.data) {
@@ -95,15 +75,15 @@ $(function() {
                 }
             );
         }
-	 	else jDownloadStatement.attr("disabled", "disabled");
-		
+        else jDownloadStatement.attr("disabled", "disabled");
+
         jDownloadXML.attr("disabled", "disabled");
-		jDownloadExamDocument.attr("disabled", "disabled");
-	});
+        jDownloadExamDocument.attr("disabled", "disabled");
+    });
 
-    $("#SelectDiscipline").change(function() {
+    jSelectDiscipline.change(function () {
         var disciplineID = parseInt($(this).val()) || 0;
-        if (disciplineID > 0){
+        if (disciplineID > 0) {
             jDownloadExamDocument.removeAttr("disabled");
             jDownloadXML.removeAttr("disabled");
         }
@@ -114,11 +94,10 @@ $(function() {
     });
 
     // Скачать ведомость
-    $('body').on('click', '#DownloadStatement', function(){
-        $.fileDownload( g_URLdir + 'handler/FileCreator/GenerateFinalFormsForGroup', {
+    $('body').on('click', '#DownloadStatement', function () {
+        $.fileDownload(g_URLdir + 'handler/FileCreator/GenerateFinalFormsForGroup', {
             httpMethod: "POST",
-            data: 
-            {
+            data: {
                 "GroupID": parseInt($("#SelectGroup").val())//,
                 //"ExamType": $("input[name=DisciplineType]:checked").val()
             },
@@ -132,11 +111,10 @@ $(function() {
     });
 
     // Печать ведомости
-    $('body').on('click', '#DownloadExamDocument', function(){
-        $.fileDownload( g_URLdir + 'handler/FileCreator/GenerateFinalForm', {
+    $('body').on('click', '#DownloadExamDocument', function () {
+        $.fileDownload(g_URLdir + 'handler/FileCreator/GenerateFinalForm', {
             httpMethod: "POST",
-            data:
-            {
+            data: {
                 "disciplineID": parseInt($("#SelectDiscipline").val()),
                 "studyGroupID": parseInt($("#SelectGroup").val())
             },
@@ -150,11 +128,10 @@ $(function() {
     });
 
 
-    $('body').on('click', '#DownloadXML', function(){
+    $('body').on('click', '#DownloadXML', function () {
         $.fileDownload(g_URLdir + 'handler/XMLCreator/GenerateXMLFile', {
             httpMethod: "POST",
-            data:
-            {
+            data: {
                 "disciplineID": parseInt($("#SelectDiscipline").val()),
                 "studyGroupID": parseInt($("#SelectGroup").val())
             },
@@ -165,7 +142,7 @@ $(function() {
 
             }
         });
-        });
+    });
 
     // Блокирование дисциплины
 
diff --git a/media/js/discipline/editStudents.js b/media/js/discipline/editStudents.js
index 3484e5a90b73ba4155de1035e78efcf2db544409..9ce5f82ee9252457b9f01f7fddf7415e8396da26 100644
--- a/media/js/discipline/editStudents.js
+++ b/media/js/discipline/editStudents.js
@@ -88,7 +88,7 @@ $(function() {
 
 
     let groupSelect = getGroupLoader($groupSelect,
-        () => ({'FacultyID': g_facultyID, 'GradeID': +$gradeSelect.val()})
+        () => ({FacultyID, 'GradeID': +$gradeSelect.val()})
     ).setOnChange(OptionLoader.stubFoo);
 
     $gradeSelect.change(() => groupSelect.reload());
diff --git a/media/js/optionLoader.js b/media/js/optionLoader.js
index 5eb195f868a8723db4fbcc968f14d78b1a55e3c9..d0abc9cebbfe1b626f153e3646f2220187e83463 100644
--- a/media/js/optionLoader.js
+++ b/media/js/optionLoader.js
@@ -45,12 +45,18 @@ class OptionLoader {
     reload() {
         $.postJSON(this.url, this.genParams(), data => {
             let html = this.placeholder + OptionLoader.constructSelectData(data, this.factory);
+            this.$select.turnOff();
             this.$select.empty();
             this.$select.append($(html));
+            this.$select.turnOn();
             this.onReload();
         });
     }
 
+    nullify() {
+        this.$select.html(this.placeholder);
+    }
+
     setPlaceholder(placeholder) {
         this.placeholder = OptionLoader.generatePlaceholderOption(placeholder);
         return this;
@@ -100,7 +106,7 @@ let getGroupLoader = ($select, genParams) => {
 
 
 // ============================
-//      groups
+//      grades
 // ============================
 
 /**
diff --git a/media/js/transfer.js b/media/js/transfer.js
index 33beaa02a5d5529a3a4d3d91a565a535cbe98779..8a011233998c69ab5dac130f385a5ad8edc10429 100644
--- a/media/js/transfer.js
+++ b/media/js/transfer.js
@@ -1,9 +1,11 @@
+var settings = {};
+
 function GroupFunction(type) {
     var jSemesters = $('#semesters' + type);
     var jGrades = $('#grades' + type);
-    var jGroupTransfer = $('#groupTransfer' + type);
+    // var jGroupTransfer = $('#groupTransfer' + type);
     var jGroupSelect = $('#group' + type);
-    var jItemContainer = $('.TransferListItem');
+    // var jItemContainer = $('.TransferListItem');
     var jList = $("#" + type + "ItemsList");
 
     jGrades.find('option[value=-1]').attr('selected', 'selected');
@@ -23,21 +25,17 @@ function GroupFunction(type) {
         jList.html('');
     });
 
-    jGrades.change(function () {
-        var gr_id = jGrades.find('option:selected').val();
-        if (gr_id) {
-            jGroupSelect.prop('disabled', false);
-            $.post(URLdir + 'handler/Transfer/getGroups',
-                {'gradeID': jGrades.find('option:selected').val()},
-                function (data) {
-                    jGroupSelect.html(data);
-                });
-        } else {
-            jGroupSelect.prop('disabled', true);
-        }
 
-        // clear list
-        jList.html('');
+    let groupSelect = getGroupLoader(jGroupSelect,
+        () => ({FacultyID: settings.facultyID, 'GradeID': +jGrades.val()})
+    ).setOnChange(OptionLoader.stubFoo);
+
+    jGrades.change(() => {
+        let gradeID = jGrades.val();
+        if (gradeID)
+            groupSelect.reload();
+        else
+            groupSelect.turnOff();
     });
 
     var jButtonSelect = $('#SelectAll' + type);
@@ -57,7 +55,9 @@ function GroupFunction(type) {
             $(this).removeClass('selected') : $(this).addClass('selected');
     });
 }
+
 $(function () {
+    settings = getSettings();
 
     GroupFunction('Left');
     GroupFunction('Right');
diff --git a/~dev_rating/application/classes/Controller/Handler/GetData.php b/~dev_rating/application/classes/Controller/Handler/GetData.php
index 5dbecc52d2bf13bdb3da4308f787c6e34fd22146..573ff4e96ec8de71bb3557d5a1a9cd83d4448438 100644
--- a/~dev_rating/application/classes/Controller/Handler/GetData.php
+++ b/~dev_rating/application/classes/Controller/Handler/GetData.php
@@ -9,13 +9,6 @@ class Controller_Handler_GetData extends Controller_Handler
         $this->user->checkAccess(User::RIGHTS_AUTHORIZED);  // todo: is it?
     }
 
-    public function action_GetGroups() {
-        $res['data'] = $this->user->Faculty->getGroups($this->post['GradeID']);
-
-        $res['success'] = true;
-        $this->response->body(json_encode($res));
-    }
-
     public function action_GetDisciplinesForGroup() {
         $response['data'] = Model_Group::with($_POST['groupID'])
             ->getDisciplines($lazy = false, $this->post['semesterID']);
diff --git a/~dev_rating/application/classes/Controller/Handler/Students.php b/~dev_rating/application/classes/Controller/Handler/Students.php
index fc4b08b40ce24aa516169a06e45ad43c26e0eb4b..6901f440125a92737ca35f933bdc9dd3c376452d 100644
--- a/~dev_rating/application/classes/Controller/Handler/Students.php
+++ b/~dev_rating/application/classes/Controller/Handler/Students.php
@@ -44,25 +44,6 @@ class Controller_Handler_Students extends Controller_Handler
         $this->response->body(json_encode(Model_Students::ofGroup($groupID, $semesterID)));
     }
 
-    public function action_getGroups() {
-        $facultyID = $this->post['facultyID'];
-        $gradeID = $this->post['gradeNum'];
-
-        $groupsHandled = [];
-        if (($facultyID && $gradeID) != 0) {
-            $groups = Model_Faculty::with($facultyID)->getGroups($gradeID);
-
-            foreach ($groups as $row)
-                $groupsHandled[] = [
-                    'ID' => $row['ID'],
-                    'Num' => $row['GroupNum'],
-                    'SpecName' => is_null($row['SpecName']) ? 'Без специализации' : $row['SpecName'],
-                    'SpecAbbr' => is_null($row['SpecAbbr']) ? '' : $row['SpecAbbr'],
-                ];
-        }
-        $this->response->body(json_encode($groupsHandled));
-    }
-
     private function groupByID($array)
     {
         $result = [];
diff --git a/~dev_rating/application/views/controls/transfer.twig b/~dev_rating/application/views/controls/transfer.twig
index 94e2107644ca2ee4b700a78c7853e0168af6add8..966fac00ecbc65b0aa64ba019c09ad70c12e8c1a 100644
--- a/~dev_rating/application/views/controls/transfer.twig
+++ b/~dev_rating/application/views/controls/transfer.twig
@@ -5,6 +5,7 @@
     {{ HTML.script('static/js/transfer/controller.js')|raw }}
     {{ HTML.script('static/js/transfer.js')|raw }}
     {{ HTML.style('static/css/controls/transfer.css')|raw }}
+    {{ HTML.script('static/js/optionLoader.js')|raw }}
 {% endmacro %}
 
 {% macro TransferList(Type, SemestersList, GradesList, CurrentSemester) %}
diff --git a/~dev_rating/application/views/office/sheets/index.twig b/~dev_rating/application/views/office/sheets/index.twig
index fe0dfdd3c8c0334701c2262d1aa7719e3cbad8e2..577eb1c45dd75ddb31775dd52551b9ed6b66969b 100644
--- a/~dev_rating/application/views/office/sheets/index.twig
+++ b/~dev_rating/application/views/office/sheets/index.twig
@@ -7,6 +7,7 @@
     {{ HTML.script('static/js/libs/jquery.fileDownload.js')|raw }}
     {{ HTML.style('static/css/discipline.css')|raw }}
     {{ HTML.style('static/css/common/forms.css')|raw }}
+    {{ HTML.script('static/js/optionLoader.js')|raw }}
     {{ HTML.script('static/js/dean/dean.js')|raw }}
 {% endblock %}
 
@@ -98,5 +99,6 @@
             </div>
         </div>
     </div>
+    <div id="hidden_div" style="display: none">{ "facultyID" : {{ User.FacultyID }} }</div>
 
 {% endblock %}
diff --git a/~dev_rating/application/views/office/students/add.twig b/~dev_rating/application/views/office/students/add.twig
index f2457e19234b5c4ab878c8348924245f94e375ce..180148046c78be2380e92a54bfcfe5174083f64d 100644
--- a/~dev_rating/application/views/office/students/add.twig
+++ b/~dev_rating/application/views/office/students/add.twig
@@ -2,6 +2,7 @@
 
 {% block office_media %}
     {{ HTML.style('static/css/admin/inputGroup.css')|raw }}
+    {{ HTML.script('static/js/optionLoader.js')|raw }}
     {{ HTML.script('static/js/admin/students/add.js')|raw }}
 {% endblock %}
 
diff --git a/~dev_rating/application/views/office/students/profile.twig b/~dev_rating/application/views/office/students/profile.twig
index 0e489d023f91783f02cfe8d65650917470858da0..17c8d188d6a47139024b4cdb5c83b7e3685cca70 100644
--- a/~dev_rating/application/views/office/students/profile.twig
+++ b/~dev_rating/application/views/office/students/profile.twig
@@ -4,6 +4,7 @@
 
 {% block office_media %}
     {{ HTML.style('static/css/admin/profilePage.css')|raw }}
+    {{ HTML.script('static/js/optionLoader.js')|raw }}
     {{ HTML.script('static/js/admin/students/profile.js')|raw }}
     <script>
         var facultyID = {{ Profile.FacultyID }};
diff --git a/~dev_rating/application/views/office/students/transfer.twig b/~dev_rating/application/views/office/students/transfer.twig
index f0390448f12a673f566922b827e7e99d1cd1b386..3d6535a1de44be823a7775c0c75bba1b3e1637e6 100644
--- a/~dev_rating/application/views/office/students/transfer.twig
+++ b/~dev_rating/application/views/office/students/transfer.twig
@@ -10,4 +10,5 @@
 {% block office_content %}
     <h2 class="defaultForm marginBetween">Перевод студентов</h2>
     <div class="defaultForm marginBetween">{{ transfer.control(SemestersList, GradesList, CurrentSemester) }}</div>
+    <div id="hidden_div" style="display: none">{ "facultyID" : {{ User.FacultyID }} }</div>
 {% endblock %}