diff --git a/db/StoredFunctions.sql b/db/StoredFunctions.sql
index 4bd995c0cfc24ff93a843675f6ad679044f70a82..374e08fb0f43c10b982dc4863ae1723af821a4fc 100644
--- a/db/StoredFunctions.sql
+++ b/db/StoredFunctions.sql
@@ -34,6 +34,10 @@ DROP FUNCTION IF EXISTS AddDiscipline//
 
 DROP FUNCTION IF EXISTS GetMaxRateForDisc//
 
+DROP FUNCTION IF EXISTS BindTeacher//
+
+DROP FUNCTION IF EXISTS GetDisciplineSemesterID//
+
 
 
 # -------------------------------------------------------------------------------------------
@@ -248,25 +252,47 @@ END //
 # Label: semesters
 # -------------------------------------------------------------------------------------------
 
+DROP FUNCTION IF EXISTS GetDisciplineProperty//
+CREATE FUNCTION `GetDisciplineProperty` (
+    `pDisciplineID` INT,
+    `pType` enum('grade', 'subject', 'author', 'semester', 'milestone')
+) RETURNS int(11)
+    NO SQL
+BEGIN
+    DECLARE vRes INT DEFAULT -1;
+
+    SELECT CASE pType
+            WHEN 'grade' THEN disciplines.GradeID
+            WHEN 'subject' THEN disciplines.SubjectID
+            WHEN 'author' THEN disciplines.AuthorID
+            WHEN 'semester' THEN disciplines.SemesterID
+            WHEN 'milestone' THEN disciplines.Milestone
+        END INTO vRes
+        FROM `disciplines`
+        WHERE disciplines.ID = pDisciplineID
+        LIMIT 1;
+
+    RETURN vRes;
+END //
+
 
 
 # -------------------------------------------------------------------------------------------
 # Label: faculties
 # -------------------------------------------------------------------------------------------
 
-# TODO: return faculty id
 DROP FUNCTION IF EXISTS CreateFaculty //
 CREATE FUNCTION CreateFaculty (
         `pFacultyName` TEXT CHARSET utf8,
         `pFacultyAbbr` TEXT CHARSET utf8
-    ) RETURNS INT(11) # 0 - success
+    ) RETURNS INT(11) # -1 or id
     NO SQL
 BEGIN
     DECLARE EXIT HANDLER FOR SQLEXCEPTION RETURN -1;
 
     INSERT INTO faculties
         (Name, Abbr) VALUES(pFacultyName, pFacultyAbbr);
-    RETURN 0;
+    RETURN LAST_INSERT_ID();
 END//
 
 # -------------------------------------------------------------------------------------------
@@ -369,6 +395,25 @@ BEGIN
 END //
 
 
+DROP FUNCTION IF EXISTS GetStudentGroup//
+CREATE FUNCTION `GetStudentGroup` (
+    `pStudentID` INT,
+    `pSemesterID` INT
+) RETURNS int(11) # groupID or -1 if failed
+    NO SQL
+BEGIN
+    DECLARE vGroupID INT DEFAULT -1;
+
+    SELECT students_groups.GroupID INTO vGroupID
+        FROM `students_groups`
+        WHERE   students_groups.StudentID = pStudentID AND
+                students_groups.SemesterID = pSemesterID
+        LIMIT 1;
+
+    RETURN vGroupID;
+END //
+
+
 
 
 # -------------------------------------------------------------------------------------------
@@ -663,6 +708,7 @@ BEGIN
         INNER JOIN `accounts` ON teachers.AccountID=accounts.ID
         WHERE teachers.ID = pTeacherID
         LIMIT 1;
+    # TODO: magic constants
     IF vUserRole = 4 THEN # 4 - сотрудник деканата
         RETURN 0;
     END IF;
@@ -677,7 +723,6 @@ END //
 # -------------------------------------------------------------------------------------------
 
 # TODO: magic constants (UserRoleID)
-# TODO: transaction
 # TODO: group id instead num and grade
 DROP FUNCTION IF EXISTS CreateStudent//
 CREATE FUNCTION `CreateStudent` (
@@ -796,36 +841,18 @@ END //
 # -------------------------------------------------------------------------------------------
 
 
-
-DROP FUNCTION IF EXISTS GetDisciplineSemesterID//
-CREATE FUNCTION `GetDisciplineSemesterID` (
-    `pDisciplineID` INT
-) RETURNS int(11)
-    NO SQL
-BEGIN
-    DECLARE vSemesterID INT DEFAULT -1;
-
-    SELECT disciplines.SemesterID INTO vSemesterID
-        FROM `disciplines`
-        WHERE disciplines.ID = pDisciplineID
-        LIMIT 1;
-
-    RETURN vSemesterID;
-END //
-
-
 DROP FUNCTION IF EXISTS Discipline_Create//
 CREATE FUNCTION `Discipline_Create` (
     `pTeacherID` INT,
     `pGradeID` INT,
     `pSubjectID` INT,
-    `pExamType` VARCHAR(30) CHARSET utf8,
+    `pExamType` enum('exam', 'credit', 'grading_credit'),
     `pLectureCount` INT,
     `pPracticeCount` INT,
     `pLabCount` INT,
     `pFacultyID` INT,
     `pSemesterID` INT,
-    `pSubtype` VARCHAR(30) CHARSET utf8 # scientific_coursework discipline_coursework
+    `pSubtype` enum('scientific_coursework', 'disciplinary_course')
 ) RETURNS int(11)
     NO SQL
 BEGIN
@@ -924,11 +951,7 @@ BEGIN
         RETURN -1;
     END IF;
 
-    # get current grade
-    SELECT disciplines.GradeID INTO vCurGradeID
-        FROM `disciplines`
-        WHERE disciplines.ID = pDisciplineID
-        LIMIT 1;
+    SET vCurGradeID = GetDisciplineProperty(pDisciplineID, 'grade');
     IF vCurGradeID = pGradeID THEN
         RETURN 0;
     END IF;
@@ -968,10 +991,10 @@ BEGIN
 
     # get exam type and extra module ID
     SELECT disciplines.ExamType, modules.ID INTO vOldExamType, vExtraID
-        FROM `disciplines`
-        INNER JOIN `modules` ON  modules.DisciplineID = pDisciplineID AND
-                                 modules.Type = 'extra'
-        WHERE disciplines.ID = pDisciplineID
+        FROM `modules`
+        INNER JOIN `disciplines` ON disciplines.ID = modules.DisciplineID
+        WHERE   modules.DisciplineID = pDisciplineID AND
+                modules.Type = 'extra'
         LIMIT 1;
     IF vExtraID <= 0 THEN
         RETURN -1;
@@ -1064,8 +1087,10 @@ CREATE FUNCTION `BindGroup` (
     ) RETURNS int(11)
     NO SQL
 BEGIN
-    DECLARE vChecker, vSemesterID INT DEFAULT -1;
+    DECLARE vSemesterID INT DEFAULT -1;
     DECLARE EXIT HANDLER FOR SQLEXCEPTION RETURN -3;
+    SET @isAttached := -1;
+
 
     # 1. check if AccessedTeacher is author
     IF  NOT InternalIsTeacherAuthor(pTeacherID, pDisciplineID) OR
@@ -1074,36 +1099,27 @@ BEGIN
         RETURN -1;
     END IF;
 
-    # 2. check if group is bound to discipline
-    SELECT disciplines_groups.ID INTO vChecker
-        FROM `disciplines_groups`
-        WHERE   disciplines_groups.GroupID = pGroupID AND
-                disciplines_groups.DisciplineID = pDisciplineID
-        LIMIT 1;
-    IF vChecker > 0 THEN
-        RETURN 1;
-    END IF;
-
-    # TODO: add param SemesterID
-    SELECT disciplines.SemesterID INTO vSemesterID
-        FROM `disciplines`
-        WHERE disciplines.ID = pDisciplineID
-        LIMIT 1;
-
-    # 3. delete students of this group which were bound to discipline before
-    DELETE FROM `disciplines_students`
-        WHERE   disciplines_students.DisciplineID = pDisciplineID AND
-                disciplines_students.StudentID IN (
-                    SELECT students_groups.StudentID
-                        FROM `students_groups`
-                        WHERE   students_groups.GroupID = pGroupID AND
-                                students_groups.SemesterID = vSemesterID
-                );
-
-    # 4. bind whole group
+    # 2. bind whole group
     INSERT INTO `disciplines_groups`
         (DisciplineID, GroupID)
-        VALUES (pDisciplineID, pGroupID );
+        VALUES ( pDisciplineID, pGroupID )
+        ON DUPLICATE KEY UPDATE
+            disciplines_groups.ID = ( @isAttached := LAST_INSERT_ID(disciplines_groups.ID) );
+
+    IF @isAttached < 0 THEN # group was attached
+        SET vSemesterID = GetDisciplineProperty(pDisciplineID, 'semester');
+
+        # 3. delete students of this group which were bound to discipline before
+                DELETE FROM `disciplines_students`
+                WHERE   disciplines_students.DisciplineID = pDisciplineID AND
+                        disciplines_students.StudentID IN (
+                            SELECT students_groups.StudentID
+                            FROM `students_groups`
+                            WHERE   students_groups.GroupID = pGroupID AND
+                                    students_groups.SemesterID = vSemesterID
+                        );
+    END IF;
+
     RETURN 0;
 END //
 
@@ -1117,26 +1133,23 @@ CREATE FUNCTION `BindStudent` (
     )   RETURNS int(11)
     NO SQL
 BEGIN
-    DECLARE vChecker, vGroupID, vTemp, vSemesterID INT DEFAULT -1;
+    DECLARE vChecker, vStudentGroupID, vTemp, vSemesterID INT DEFAULT -1;
     DECLARE vInGroup BOOLEAN DEFAULT FALSE;
     DECLARE EXIT HANDLER FOR SQLEXCEPTION RETURN -1;
 
-    SET vSemesterID = GetDisciplineSemesterID(pDisciplineID);
-
     # 1. check if AccessedTeacher is author
     IF NOT InternalIsTeacherAuthor(pTeacherID, pDisciplineID) THEN
         RETURN -1;
     END IF;
 
-    # TODO: extract method - Get Student Group
+    SET vSemesterID = GetDisciplineProperty(pDisciplineID, 'semester');
+    SET vStudentGroupID = GetStudentGroup(pStudentID, vSemesterID);
+
     # 2. check if student's group is bound yet
     SET vInGroup = EXISTS(
-        SELECT disciplines_groups.ID
-            FROM `students_groups`
-            INNER JOIN `disciplines_groups` ON disciplines_groups.DisciplineID = pDisciplineID AND
-                                               disciplines_groups.GroupID = students_groups.GroupID
-            WHERE students_groups.StudentID = pStudentID AND
-                  students_groups.SemesterID = vSemesterID
+        SELECT * FROM `disciplines_groups`
+            WHERE disciplines_groups.DisciplineID = pDisciplineID AND
+                  disciplines_groups.GroupID = vStudentGroupID
             LIMIT 1
     );
 
@@ -1169,7 +1182,7 @@ CREATE FUNCTION `UnbindGroup` (
 BEGIN
     DECLARE vSemesterID INT DEFAULT -1;
 
-    IF NOT InternalIsTeacherAuthor(pTeacherID, pDisciplineID) OR InternalIsMapLocked(pDisciplineID)THEN
+    IF NOT InternalIsTeacherAuthor(pTeacherID, pDisciplineID) OR InternalIsMapLocked(pDisciplineID) THEN
         RETURN -1;
     END IF;
 
@@ -1179,11 +1192,7 @@ BEGIN
                 disciplines_groups.GroupID = pGroupID
         LIMIT 1;
 
-    # TODO: add param SemesterID
-    SELECT disciplines.SemesterID INTO vSemesterID
-        FROM `disciplines`
-        WHERE disciplines.ID = pDisciplineID
-        LIMIT 1;
+    SET vSemesterID = GetDisciplineProperty(pDisciplineID, 'semester');
 
     # delete attached, and detached (doesn't take disc in any case)
     DELETE FROM `disciplines_students`
@@ -1207,26 +1216,23 @@ CREATE FUNCTION `UnbindStudent` (
     ) RETURNS int(11)
     NO SQL
 BEGIN
-    DECLARE vInGroup, vSemesterID INT DEFAULT -1;
+    DECLARE vInGroup, vStudentGroupID, vSemesterID INT DEFAULT -1;
     DECLARE EXIT HANDLER FOR SQLEXCEPTION RETURN -1;
+
     IF  NOT InternalIsTeacherAuthor(pTeacherID, pDisciplineID) THEN
         RETURN -1;
     END IF;
 
-    SET vSemesterID = GetDisciplineSemesterID(pDisciplineID);
+    SET vSemesterID = GetDisciplineProperty(pDisciplineID, 'semester');
+    SET vStudentGroupID = GetStudentGroup(pStudentID, vSemesterID);
 
-    # TODO: extract method - GetDisciplineSemesterID
-    # TODO: join students_groups by discipline SemesterID
-
-    # try to get general group, if student in it.
-    SELECT disciplines_groups.ID INTO vInGroup
-        FROM `students`
-        INNER JOIN `students_groups` ON students_groups.StudentID = students.ID AND
-                                        students_groups.SemesterID = vSemesterID
-        INNER JOIN `disciplines_groups` ON disciplines_groups.DisciplineID = pDisciplineID AND
-                                           disciplines_groups.GroupID = students_groups.GroupID
-        WHERE students.ID = pStudentID
-        LIMIT 1;
+    # 2. check if student's group is bound yet
+    SET vInGroup = EXISTS(
+        SELECT * FROM `disciplines_groups`
+        WHERE disciplines_groups.DisciplineID = pDisciplineID AND
+              disciplines_groups.GroupID = vStudentGroupID
+        LIMIT 1
+    );
 
     IF vInGroup > 0 THEN # student in general group
         INSERT INTO `disciplines_students`
@@ -1234,16 +1240,15 @@ BEGIN
             VALUES (pDisciplineID, pStudentID, 'detach');
     ELSE
         DELETE FROM `disciplines_students`
-        WHERE disciplines_students.DisciplineID = pDisciplineID AND
-            disciplines_students.StudentID = pStudentID
-        LIMIT 1;
+            WHERE   disciplines_students.DisciplineID = pDisciplineID AND
+                    disciplines_students.StudentID = pStudentID
+            LIMIT 1;
     END IF;
     RETURN 0;
 END //
 
 
 
-DROP FUNCTION IF EXISTS BindTeacher//
 DROP FUNCTION IF EXISTS Discipline_BindTeacher//
 CREATE FUNCTION `Discipline_BindTeacher` (
     `pDisciplineID` INT,
@@ -1252,7 +1257,7 @@ CREATE FUNCTION `Discipline_BindTeacher` (
     NO SQL
 BEGIN
     DECLARE EXIT HANDLER FOR SQLEXCEPTION RETURN -1;
-  
+
     # try to insert BindingTeacher in access list
     INSERT INTO `disciplines_teachers`
         (DisciplineID, TeacherID)
@@ -1274,7 +1279,8 @@ CREATE FUNCTION `Discipline_UnbindTeacher` (
 BEGIN
     DELETE FROM `disciplines_teachers`
         WHERE   disciplines_teachers.DisciplineID = pDisciplineID AND
-                disciplines_teachers.TeacherID = pBindingTeacher;
+                disciplines_teachers.TeacherID = pBindingTeacher
+        LIMIT 1;
     RETURN ROW_COUNT()-1;
 END //
 
@@ -1382,13 +1388,10 @@ CREATE FUNCTION `Discipline_CountRatings` (
 BEGIN
     DECLARE vRes INT DEFAULT 0;
 
-    SELECT COUNT(rating_table.StudentID)
-        INTO vRes
-        FROM `rating_table`
-        INNER JOIN `submodules` ON rating_table.SubmoduleID = submodules.ID
-        INNER JOIN `modules` ON submodules.ModuleID = modules.ID
-        WHERE modules.DisciplineID = pDisciplineID
-        LIMIT 1;
+    SELECT COUNT(rating_table.StudentID) INTO vRes
+        FROM `view_roadmap`
+        LEFT JOIN `rating_table` ON rating_table.SubmoduleID = view_roadmap.SubmoduleID
+        WHERE view_roadmap.DisciplineID = pDisciplineID;
 
     RETURN vRes;
 END //
@@ -1424,19 +1427,19 @@ BEGIN
     UPDATE `disciplines`
         SET disciplines.MilestoneDate = CURDATE(),
             disciplines.Milestone = pMilestone
-        WHERE    disciplines.FacultyID= pFacultyID AND
+        WHERE   disciplines.FacultyID= pFacultyID AND
                 disciplines.SemesterID = pSemesterID AND
                 ( disciplines.ExamType = 'credit' OR disciplines.ExamType = 'grading_credit');
     RETURN 0;
 END //
 
+
+
 # -------------------------------------------------------------------------------------------
 # Label: modules
 # Label: roadmap
 # -------------------------------------------------------------------------------------------
 
-
-
 DROP FUNCTION IF EXISTS ChangeModuleName//
 CREATE FUNCTION `ChangeModuleName` (
         `pTeacherID` INT,
@@ -1478,7 +1481,7 @@ BEGIN
         FROM `modules`
         WHERE   modules.DisciplineID = pDisciplineID AND modules.Type = 'regular'
         LIMIT 1;
-    IF vOrderNum IS NULL THEN
+    IF vOrderNum IS NULL THEN # TODO: check unreachable code
         SET vOrderNum = 1;
     END IF;
 
@@ -1497,21 +1500,21 @@ CREATE FUNCTION `AddModuleExam` (
     ) RETURNS int(11)
     NO SQL
 BEGIN
-    DECLARE vChecker, vModule INT DEFAULT -1;
+    DECLARE vModule, vChecker INT DEFAULT -1;
+    DECLARE vIsExamExists BOOLEAN;
     IF  NOT InternalIsTeacherAuthor(pTeacherID, pDisciplineID) OR
         InternalIsMapLocked(pDisciplineID)
     THEN
         RETURN -1;
     END IF;
 
-    # TODO: exists
-    # check exam module existence
-    SELECT modules.ID
-        INTO vChecker
-        FROM `modules`
-        WHERE   modules.DisciplineID = pDisciplineID AND
-                modules.Type = 'exam';
-    IF vChecker > 0 THEN
+    SET vIsExamExists = EXISTS(
+        SELECT * FROM `modules`
+            WHERE   modules.DisciplineID = pDisciplineID AND
+                    modules.Type = 'exam'
+            LIMIT 1
+    );
+    IF vIsExamExists THEN
         RETURN -2;
     END IF;
 
@@ -1558,8 +1561,7 @@ BEGIN
 
 
     # get discipline exam type
-    SELECT  modules.ID, disciplines.ExamType
-        INTO vModule, vType
+    SELECT  modules.ID, disciplines.ExamType INTO vModule, vType
         FROM `modules`
         INNER JOIN `disciplines` ON disciplines.ID = modules.DisciplineID
         WHERE   modules.DisciplineID = pDisciplineID AND
diff --git a/db/StoredProcedures.sql b/db/StoredProcedures.sql
index 6e583d35f35dbfa8ebb312d25281c8772e41d392..4db3ad83dce126ebf68cbf719b33f0d8297ba954 100644
--- a/db/StoredProcedures.sql
+++ b/db/StoredProcedures.sql
@@ -37,8 +37,9 @@ DROP PROCEDURE IF EXISTS GetReports//
 # -------------------------------------------------------------------------------------------
 
 DROP PROCEDURE IF EXISTS GetSettings//
-CREATE PROCEDURE `GetSettings`(IN `pKey` VARCHAR(50) CHARSET utf8)
-    NO SQL
+CREATE PROCEDURE `GetSettings` (
+    IN `pKey` VARCHAR(50) CHARSET utf8
+) NO SQL
 BEGIN
     SELECT general_settings.*
         FROM `general_settings`
@@ -52,8 +53,9 @@ END //
 # -------------------------------------------------------------------------------------------
 
 DROP PROCEDURE IF EXISTS GetSemesterInfo//
-CREATE PROCEDURE `GetSemesterInfo` (IN `pSemesterID` INT)
-    NO SQL
+CREATE PROCEDURE `GetSemesterInfo` (
+    IN `pSemesterID` INT
+) NO SQL
 BEGIN
     SELECT  semesters.Num   As 'Num',
             semesters.Year  As 'Year'
@@ -63,8 +65,8 @@ BEGIN
 END //
 
 DROP PROCEDURE IF EXISTS GetSemesters//
-CREATE PROCEDURE `GetSemesters`  ()
-    NO SQL
+CREATE PROCEDURE `GetSemesters` (
+) NO SQL
 BEGIN
     SELECT  semesters.ID,
             semesters.Year,
@@ -80,8 +82,8 @@ END //
 # -------------------------------------------------------------------------------------------
 
 DROP PROCEDURE IF EXISTS GetFaculties//
-CREATE PROCEDURE `GetFaculties` ( )
-    NO SQL
+CREATE PROCEDURE `GetFaculties` (
+) NO SQL
 BEGIN
     SELECT  faculties.ID,
             faculties.Name,
@@ -95,8 +97,9 @@ END //
 # -------------------------------------------------------------------------------------------
 
 DROP PROCEDURE IF EXISTS GetDepartments//
-CREATE PROCEDURE `GetDepartments` (IN `pFacultyID` INT)
-    NO SQL
+CREATE PROCEDURE `GetDepartments` (
+    IN `pFacultyID` INT
+) NO SQL
 BEGIN
     SELECT  departments.ID,
             departments.Name
@@ -111,8 +114,9 @@ END //
 # -------------------------------------------------------------------------------------------
 
 DROP PROCEDURE IF EXISTS GetSpecializations//
-CREATE PROCEDURE `GetSpecializations` (IN `pFacultyID` INT)
-    NO SQL
+CREATE PROCEDURE `GetSpecializations` (
+    IN `pFacultyID` INT
+) NO SQL
 BEGIN
     SELECT  specializations.ID,
             specializations.Name,
@@ -128,8 +132,8 @@ END //
 # -------------------------------------------------------------------------------------------
 
 DROP PROCEDURE IF EXISTS GetJobPositions//
-CREATE PROCEDURE `GetJobPositions` ( )
-    NO SQL
+CREATE PROCEDURE `GetJobPositions` (
+) NO SQL
 BEGIN
     SELECT  job_positions.ID,
             job_positions.Name
@@ -143,13 +147,13 @@ END //
 # -------------------------------------------------------------------------------------------
 
 DROP PROCEDURE IF EXISTS GetGrades//
-CREATE PROCEDURE `GetGrades` ( )
-    NO SQL
+CREATE PROCEDURE `GetGrades` (
+) NO SQL
 BEGIN
-    SELECT  grades.ID       AS 'ID',
-            grades.Num      AS 'Num',
-            grades.Degree   AS 'Degree'
-        FROM    `grades`
+    SELECT  grades.ID,
+            grades.Num,
+            grades.Degree
+        FROM `grades`
         ORDER BY grades.ID;
 END //
 
@@ -159,9 +163,10 @@ END //
 # -------------------------------------------------------------------------------------------
 
 DROP PROCEDURE IF EXISTS GetGroups//
-CREATE PROCEDURE `GetGroups`
-    (IN `pGradeID` INT, IN `pFacultyID` INT)
-    NO SQL
+CREATE PROCEDURE `GetGroups` (
+    IN `pGradeID` INT,
+    IN `pFacultyID` INT
+) NO SQL
 BEGIN
     SELECT  view_groups.GroupID AS 'ID',
             view_groups.GroupNum,
@@ -177,8 +182,9 @@ END //
 
 # get all general study groups, that takes this course
 DROP PROCEDURE IF EXISTS GetGroupsForDiscipline//
-CREATE PROCEDURE `GetGroupsForDiscipline` (IN `pDisciplineID` INT)
-    NO SQL
+CREATE PROCEDURE `GetGroupsForDiscipline` (
+    IN `pDisciplineID` INT
+) NO SQL
 BEGIN
     SELECT  view_groups.GroupID AS 'ID',
             view_groups.GroupNum,
@@ -201,15 +207,16 @@ END //
 # -------------------------------------------------------------------------------------------
 
 DROP PROCEDURE IF EXISTS GetSubjects//
-CREATE PROCEDURE `GetSubjects` (IN `pFacultyID` INT)
-    NO SQL
+CREATE PROCEDURE `GetSubjects` (
+    IN `pFacultyID` INT
+) NO SQL
 BEGIN
     SELECT  subjects.ID,
             subjects.Name AS 'Title',
             subjects.Abbr
         FROM `subjects_faculties`
         INNER JOIN `subjects` ON subjects_faculties.SubjectID = subjects.ID
-        WHERE   subjects_faculties.FacultyID = pFacultyID
+        WHERE subjects_faculties.FacultyID = pFacultyID
         ORDER BY subjects.Name ASC;
 END //
 
@@ -219,6 +226,7 @@ END //
 # Label: accounts
 # -------------------------------------------------------------------------------------------
 
+# TODO: deprecated
 DROP PROCEDURE IF EXISTS GetAccountInfo//
 CREATE PROCEDURE `GetAccountInfo` ( IN `pUserID` INT )
     NO SQL
@@ -238,13 +246,12 @@ BEGIN
         LIMIT 1;
 END //
 
-
+# TODO: deprecated
 DROP PROCEDURE IF EXISTS GetPersonalInfo//
 CREATE PROCEDURE `GetPersonalInfo` (
-        IN `pUserID` INT,
-        IN `pSemesterID` INT
-    )
-    NO SQL
+    IN `pUserID` INT,
+    IN `pSemesterID` INT
+) NO SQL
 BEGIN
     DECLARE vAccountType INT DEFAULT -1;
     SELECT user_roles.Type INTO vAccountType
@@ -293,6 +300,85 @@ BEGIN
     END IF;
 END //
 
+DROP PROCEDURE IF EXISTS GetFullInfo//
+CREATE PROCEDURE `GetFullInfo` (
+    IN `pUserID` INT,
+    IN `pSemesterID` INT
+) NO SQL
+BEGIN
+    DECLARE vAccountType enum('student', 'teacher') DEFAULT -1;
+
+    SELECT user_roles.Type INTO vAccountType
+        FROM `accounts`
+        INNER JOIN `user_roles` ON accounts.UserRoleID = user_roles.ID
+        WHERE accounts.ID = pUserID
+        LIMIT 1;
+
+# type 1: student
+#      2: teacher
+    IF vAccountType = 'student' THEN
+        SELECT  # student info
+                view_students.LastName,
+                view_students.FirstName,
+                view_students.SecondName,
+                view_students.StudentID,
+                view_students.GradeID,
+                view_students.GradeNum,
+                view_students.GroupID,
+                view_students.GroupNum,
+                view_students.GroupName,
+                view_students.Degree,
+                view_students.SpecID,
+                view_students.SpecName,
+                view_students.SpecAbbr,
+                view_students.FacultyID,
+                view_students.FacultyName,
+                view_students.FacultyAbbr,
+                # account info
+                accounts.ID,
+                accounts.Login,
+                accounts.EMail,
+                user_roles.Type,
+                user_roles.RoleName AS 'Role',
+                user_roles.Mark     AS 'RoleMark',
+                accounts.IsEnabled,
+                accounts.ActivationCode AS 'Code',
+                accounts.UserAgent
+            FROM `view_students`
+            INNER JOIN `accounts` ON accounts.ID = view_students.AccountID
+            INNER JOIN `user_roles` ON user_roles.ID = accounts.UserRoleID
+            WHERE view_students.AccountID = pUserID AND
+                  view_students.SemesterID = pSemesterID
+            LIMIT 1;
+    ELSE
+        SELECT  # teacher info
+                view_teachers.LastName,
+                view_teachers.FirstName,
+                view_teachers.SecondName,
+                view_teachers.TeacherID,
+                view_teachers.DepID,
+                view_teachers.DepName,
+                view_teachers.JobPositionName,
+                view_teachers.FacultyID,
+                view_teachers.FacultyName,
+                view_teachers.FacultyAbbr,
+                # account info
+                accounts.ID,
+                accounts.Login,
+                accounts.EMail,
+                user_roles.Type,
+                user_roles.RoleName AS 'Role',
+                user_roles.Mark     AS 'RoleMark',
+                accounts.IsEnabled,
+                accounts.ActivationCode AS 'Code',
+                accounts.UserAgent
+            FROM `view_teachers`
+            INNER JOIN `accounts` ON accounts.ID = view_teachers.AccountID
+            INNER JOIN `user_roles` ON user_roles.ID = accounts.UserRoleID
+            WHERE view_teachers.AccountID = pUserID
+            LIMIT 1;
+    END IF;
+END //
 
 
 
@@ -300,6 +386,7 @@ END //
 # Label: teachers
 # -------------------------------------------------------------------------------------------
 
+# TODO: used in php
 DROP PROCEDURE IF EXISTS GetTeachersByFaculty//
 # CREATE PROCEDURE `GetTeachersByFaculty` (IN `pFacultyID` INT)
 #     NO SQL
@@ -342,40 +429,48 @@ DROP PROCEDURE IF EXISTS GetTeachersForDiscipline//
 CREATE PROCEDURE `GetTeachersForDiscipline`(IN `pDisciplineID` INT)
     NO SQL
 BEGIN
-    SELECT  view_disciplines_teachers.TeacherID AS 'ID',
-            view_disciplines_teachers.LastName,
-            view_disciplines_teachers.FirstName,
-            view_disciplines_teachers.SecondName,
-            view_disciplines_teachers.JobPositionID,
-            view_disciplines_teachers.JobPositionName,
-            view_disciplines_teachers.DepID,
-            view_disciplines_teachers.DepName,
-            view_disciplines_teachers.FacultyID,
-            view_disciplines_teachers.FacultyAbbr,
-            view_disciplines_teachers.IsAuthor
-        FROM `view_disciplines_teachers`
-        WHERE view_disciplines_teachers.DisciplineID = pDisciplineID
-        ORDER BY view_disciplines_teachers.IsAuthor DESC,
-                view_disciplines_teachers.LastName ASC,
-                view_disciplines_teachers.FirstName ASC;
+    DECLARE vAuthorID INT DEFAULT -1;
+    SET vAuthorID = GetDisciplineProperty(pDisciplineID, 'author');
+
+    SELECT  view_teachers.TeacherID AS 'ID',
+            view_teachers.LastName,
+            view_teachers.FirstName,
+            view_teachers.SecondName,
+            view_teachers.JobPositionID,
+            view_teachers.JobPositionName,
+            view_teachers.DepID,
+            view_teachers.DepName,
+            view_teachers.FacultyID,
+            view_teachers.FacultyAbbr,
+            ( view_teachers.TeacherID = vAuthorID ) AS 'IsAuthor'
+        FROM `disciplines_teachers`
+        INNER JOIN `view_teachers` ON view_teachers.TeacherID = disciplines_teachers.TeacherID
+        WHERE disciplines_teachers.DisciplineID = pDisciplineID
+        ORDER BY    view_teachers.TeacherID = vAuthorID DESC,
+                    view_teachers.LastName ASC,
+                    view_teachers.FirstName ASC;
 END //
 
 
 
 # get teachers, that don't teach course
 DROP PROCEDURE IF EXISTS SearchTeachers//
-CREATE PROCEDURE `SearchTeachers`
-    (   IN `pFacultyID` INT, IN `pDepartmentID` INT,
-        IN `pFullName` VARCHAR(100) CHARSET utf8,
-        # order: LastName + FirstName + SecondName
-        IN `pDisciplineID` INT  )
-    NO SQL
+CREATE PROCEDURE `SearchTeachers` (
+    IN `pFacultyID` INT,
+    IN `pDepartmentID` INT,
+    IN `pFullName` VARCHAR(100) CHARSET utf8,
+    # order: LastName + FirstName + SecondName
+    IN `pDisciplineID` INT
+) NO SQL
 BEGIN
     DECLARE vAuthorID INT DEFAULT -1;
-    SELECT disciplines.AuthorID INTO vAuthorID
-        FROM `disciplines`
-        WHERE disciplines.ID = pDisciplineID
-        LIMIT 1;
+    SET vAuthorID = GetDisciplineProperty(pDisciplineID, 'author');
+
+    CREATE TEMPORARY TABLE IF NOT EXISTS tDiscTeachers AS (
+        SELECT disciplines_teachers.TeacherID
+            FROM disciplines_teachers
+            WHERE disciplines_teachers.DisciplineID = pDisciplineID
+    );
 
     SELECT  view_teachers.TeacherID AS 'ID',
             view_teachers.LastName,
@@ -384,14 +479,21 @@ BEGIN
             view_teachers.JobPositionName,
             view_teachers.DepID,
             view_teachers.DepName,
-            (view_teachers.TeacherID = vAuthorID) AS 'IsAuthor'
+            ( view_teachers.TeacherID = vAuthorID ) AS 'IsAuthor'
         FROM `view_teachers`
-        WHERE NOT InternalIsTeacherBounded(view_teachers.TeacherID, pDisciplineID) AND
-            view_teachers.FacultyID = pFacultyID AND
-            CONCAT( view_teachers.LastName, view_teachers.FirstName, view_teachers.SecondName)
-                LIKE CONCAT('%', pFullName, '%')
-        ORDER BY view_teachers.FacultyID ASC,view_teachers.DepName ASC,
-                view_teachers.LastName ASC, view_teachers.FirstName ASC;
+        WHERE   view_teachers.FacultyID = pFacultyID AND
+                ( pDepartmentID = 0 OR view_teachers.DepID = pDepartmentID ) AND
+                NOT EXISTS (
+                    SELECT * FROM tDiscTeachers
+                    WHERE tDiscTeachers.TeacherID = view_teachers.TeacherID
+                    LIMIT 1
+                ) AND
+                CONCAT( view_teachers.LastName, ' ', view_teachers.FirstName, ' ', view_teachers.SecondName)
+                    LIKE CONCAT('%', pFullName, '%')
+        ORDER BY    view_teachers.FacultyID ASC,
+                    view_teachers.DepName ASC,
+                    view_teachers.LastName ASC,
+                    view_teachers.FirstName ASC;
 END //
 
 
@@ -500,7 +602,7 @@ CREATE PROCEDURE `GetStudentsForDiscipline` (
     NO SQL
 BEGIN
     DECLARE vSemesterID INT DEFAULT -1;
-    SET vSemesterID = GetDisciplineSemesterID(pDisciplineID);
+    SET vSemesterID = GetDisciplineProperty(pDisciplineID, 'semester');
 
     SELECT  view_disciplines_students.StudentID AS 'ID',
             view_disciplines_students.LastName,
@@ -744,7 +846,7 @@ BEGIN
               disciplines_groups.GroupID = pGroupID
         LIMIT 1;
 
-    SET vSemesterID = GetDisciplineSemesterID(pDisciplineID);
+    SET vSemesterID = GetDisciplineProperty(pDisciplineID, 'semester');
 
     IF !vChecker THEN
         SELECT  students.ID,
diff --git a/db/Views.sql b/db/Views.sql
index b13e7570d42b53d2f1ee61252927b1c3c1e238d2..051cad6e7d3cd51c77d8a74c119853e97bfdc4f5 100644
--- a/db/Views.sql
+++ b/db/Views.sql
@@ -1,5 +1,9 @@
 
 
+DROP VIEW IF EXISTS view_disciplines_teachers;
+
+
+
 
 CREATE OR REPLACE VIEW `view_groups` AS 
     SELECT  study_groups.ID         AS 'GroupID',
@@ -79,49 +83,31 @@ CREATE OR REPLACE VIEW `view_disciplines` AS
         INNER JOIN `grades` ON grades.ID = disciplines.GradeID;
 
 
-CREATE OR REPLACE VIEW `view_disciplines_results` AS
-    SELECT  disciplines.ID AS 'DisciplineID',
-            SUM(submodules.MaxRate) AS 'DisciplineRateMax',
-            SUM(submodules.MaxRate*submodules.IsUsed) AS 'DisciplineRateCur'
-        FROM `submodules`
-        INNER JOIN `modules` ON modules.ID = submodules.ModuleID
-        RIGHT JOIN `disciplines` ON disciplines.ID = modules.DisciplineID
-        WHERE (modules.Type = 'regular') OR (modules.Type = 'exam' AND submodules.OrderNum = 1)
-        GROUP BY disciplines.ID;
-
-
-CREATE OR REPLACE VIEW `view_disciplines_teachers` AS 
-    SELECT  view_disciplines.DisciplineID,
-            view_teachers.*,
-            (view_disciplines.AuthorID = view_teachers.TeacherID) AS 'IsAuthor'
-        FROM `view_disciplines`
-        LEFT JOIN `disciplines_teachers` ON disciplines_teachers.DisciplineID = view_disciplines.DisciplineID
-        INNER JOIN `view_teachers` ON view_teachers.TeacherID = disciplines_teachers.TeacherID;
 
 
-CREATE OR REPLACE VIEW `view_disciplines_students` AS 
-    (SELECT disciplines_students.DisciplineID,
+CREATE OR REPLACE VIEW `view_disciplines_students` AS (
+    SELECT disciplines_students.DisciplineID,
             disciplines_students.Type AS 'AttachType',
             view_students.*
         FROM `disciplines`
         LEFT JOIN `disciplines_students` ON disciplines_students.DisciplineID = disciplines.ID
         INNER JOIN `view_students` ON   view_students.StudentID = disciplines_students.StudentID AND
                                         view_students.SemesterID = disciplines.SemesterID
-    ) UNION
-    (SELECT disciplines_groups.DisciplineID,
+) UNION (
+    SELECT disciplines_groups.DisciplineID,
             NULL AS 'AttachType',
             view_students.*
         FROM `disciplines`
         LEFT JOIN `disciplines_groups` ON disciplines_groups.DisciplineID = disciplines.ID
         LEFT JOIN `view_students` ON view_students.GroupID = disciplines_groups.GroupID AND
                                      view_students.SemesterID = disciplines.SemesterID
-        WHERE NOT EXISTS 
-            (SELECT disciplines_students.StudentID
+        WHERE NOT EXISTS (
+            SELECT disciplines_students.StudentID
                 FROM `disciplines_students`
                 WHERE disciplines_students.DisciplineID = disciplines_groups.DisciplineID AND
                     disciplines_students.StudentID = view_students.StudentID
             )
-    );
+);
 
 
 CREATE OR REPLACE VIEW `view_roadmap` AS
@@ -129,19 +115,31 @@ CREATE OR REPLACE VIEW `view_roadmap` AS
             modules.ID AS 'ModuleID',
             modules.Name AS 'ModuleName',
             modules.OrderNum AS 'ModuleOrderNum',
-            modules.Type AS 'ModuleType', 
-            # enum('regular','exam', 'bonus', 'extra')
+            modules.Type AS 'ModuleType', # enum('regular','exam', 'bonus', 'extra')
             submodules.ID AS 'SubmoduleID',
             submodules.Name AS 'SubmoduleName',
             submodules.OrderNum AS 'SubmoduleOrderNum',
             submodules.MaxRate AS 'SubmoduleRate',
-            submodules.Type AS 'SubmoduleType',
-            # enum('CurrentControl','LandmarkControl')
+            submodules.Type AS 'SubmoduleType', # enum('CurrentControl','LandmarkControl')
             submodules.IsUsed AS 'SubmoduleIsUsed'
         FROM `modules`
         LEFT JOIN `submodules` ON submodules.ModuleID = modules.ID;
 
 
+CREATE OR REPLACE VIEW `view_disciplines_results` AS
+    SELECT  disciplines.ID AS 'DisciplineID',
+            SUM(submodules.MaxRate) AS 'DisciplineRateMax',
+            SUM(submodules.MaxRate*submodules.IsUsed) AS 'DisciplineRateCur'
+        FROM `disciplines`
+        LEFT JOIN `modules` ON modules.DisciplineID = disciplines.ID
+        LEFT JOIN `submodules` ON submodules.ModuleID = modules.ID
+        WHERE   modules.Type = 'regular' OR
+                (modules.Type = 'exam' AND submodules.OrderNum = 1)
+        GROUP BY disciplines.ID;
+
+
+
+
 # without students, that haven't any rate
 CREATE OR REPLACE VIEW `view_rating_result` AS
     SELECT  rating_table.StudentID,
diff --git a/~dev_rating/application/classes/Controller/Handler/FileCreator.php b/~dev_rating/application/classes/Controller/Handler/FileCreator.php
index b0b3580d75b256eef2cd0e517db03950b3e1c8b1..809f7c19d1b72edefa6f7a8f17b488673e527193 100644
--- a/~dev_rating/application/classes/Controller/Handler/FileCreator.php
+++ b/~dev_rating/application/classes/Controller/Handler/FileCreator.php
@@ -702,7 +702,9 @@ class Controller_Handler_FileCreator extends Controller_Handler
         if ($examHold != 0)
 		{
 			$examRateStr = $examRateValue;
-			if (($examAdmission < 38) or ($examRateValue < 22)) {
+			if ($examAdmission < 38) {
+                $rateOfFive = 'РЅ/Рґ';
+            } elseif ($examRateValue < 22) {
 				$rateOfFive = 'неуд';
 			} else {
 				$totalRateStr = $totalRateValue;
diff --git a/~dev_rating/application/views/teacher/exam.twig b/~dev_rating/application/views/teacher/exam.twig
index 48931738cc29787dbb8677452564c8d8d461be8f..1bba7a0b1c31edaf0cab5f1a1e3c8add4ec738a3 100644
--- a/~dev_rating/application/views/teacher/exam.twig
+++ b/~dev_rating/application/views/teacher/exam.twig
@@ -145,7 +145,7 @@
 						{% endif %}					
 
 						{% if r.Block == 'True' or (r.ModuleType != 'extra' and student.RateResult < 38) %}
-							<td class="staticCell {{ td_class }}" id="col_{{ col }}_row_{{ row }}"> 
+							<td class="{{ td_class }}" id="col_{{ col }}_row_{{ row }}">
 								<input type="text" value="{{ r.Rate  }}" disabled="disabled">
 							</td>
 						{% else %}
diff --git a/~dev_rating/media/js/rating.js b/~dev_rating/media/js/rating.js
index e6e6488c9ac8fa0c016d096cac7d70507802757d..ad56fe06eeae1040d44cd60546754dcda6a790f4 100644
--- a/~dev_rating/media/js/rating.js
+++ b/~dev_rating/media/js/rating.js
@@ -42,22 +42,24 @@ $(function() {
     }
 
     function controlRowVisualization(jRow) {
-        var jAutoPassCheckBox = jRow.children(".autoPass").children(".autoPassCheck");
-        var jAbsenceCheckBoxes = jRow.children(".absenceCell").children(".absenceCheck");
-        var semesterRate = parseInt(jRow.children(".semesterRateResultCell").text());
-        var autopass = jAutoPassCheckBox[0].checked;
-        var absence = jAbsenceCheckBoxes[0].checked;
-        if ((semesterRate < 60) || (absence))
-            jAutoPassCheckBox.attr("disabled", true);
-        else
-            jAutoPassCheckBox.removeAttr("disabled");
-
-        if ((semesterRate < 38) || (autopass))
-            jAbsenceCheckBoxes.attr("disabled", true);
-        else
-            jAbsenceCheckBoxes.removeAttr("disabled");
-
-        // TODO: disable CommonCell connected with this exam if absence or autopass checked
+        if ($("#pageType").val() === "exam") {
+            var jAutoPassCheckBox = jRow.children(".autoPass").children(".autoPassCheck");
+            var jAbsenceCheckBoxes = jRow.children(".absenceCell").children(".absenceCheck");
+            var semesterRate = parseInt(jRow.children(".semesterRateResultCell").text());
+            var autopass = jAutoPassCheckBox[0].checked;
+            var absence = jAbsenceCheckBoxes[0].checked;
+            if ((semesterRate < 60) || (absence))
+                jAutoPassCheckBox.attr("disabled", true);
+            else
+                jAutoPassCheckBox.removeAttr("disabled");
+
+            if ((semesterRate < 38) || (autopass))
+                jAbsenceCheckBoxes.attr("disabled", true);
+            else
+                jAbsenceCheckBoxes.removeAttr("disabled");
+
+            // TODO: disable CommonCell connected with this exam if absence or autopass checked
+        }
     }
 
     function controlVisualization() {
@@ -222,10 +224,9 @@ $(function() {
             return;
         }
 
-        var newRate = 0;
+        var newRate = -1; // если пустая строка в ячейке, значит ничего не поставлено
         if (jThis.children("input").val() !== "")
             newRate = parseInt(jThis.children("input").val());
-
         if (newRate == oldRate)
             return;
 
@@ -239,8 +240,9 @@ $(function() {
         {
             // страница сессии
             rateResult += parseInt(jThis.siblings(".semesterRateResultCell").text());
+            rateResult += parseInt(jThis.siblings(".bonus").text());
 
-            jThis.siblings(".additionalCell").each(function () {
+                jThis.siblings(".additionalCell").each(function () {
                 if ($(this).children("input").val() !== "")
                     rateResult += parseInt($(this).children("input").val());
             });
@@ -252,16 +254,15 @@ $(function() {
                 if (rate)
                     rateResult += parseInt(rate);
             });
-            var examRateStr = jThis.siblings(".examCell").children("p").text();
-            if (examRateStr)
-                rateResult += parseInt(examRateStr);
+
             var additionalRateStr = jThis.siblings(".staticCell").children("p").text();
             if (additionalRateStr)
                 rateResult += parseInt(additionalRateStr);
         }
 
         if (newRate <= g_submoduleMaxRate) {
-
+            if (newRate == -1)
+                newRate = null; // TODO: начить setRate принимать null на вход
             $.ajax({
                 type: "POST",
                 url: URLdir + "handler/rating/setRate",