Автоматизація реєстрації користувачів

 

МІНІСТЕРСТВО ОСВІТИ І НАУКИ, МОЛОДІ ТА СПОРТУ УКРАЇНИ

НАЦІОНАЛЬНИЙ ТЕХНІЧНИЙ УНІВЕРСИТЕТ УКРАЇНИ «КПІ»

Кафедра автоматизованих систем обробки інформації та управління











Пояснювальна записка до курсової роботи

з дисципліни "Об'єктно-орієнтоване програмування"

на тему: "Автоматизація реєстрації користувачів"





Керівник : доц. Ковалюк Т. В.

Виконав: Саган Б. Г.

студент гр. ІС-11, ФІОТ, 2 курс

№IC-1122





Київ 2013


Зміст


1. Загальні положення

.1 Опис предметного середовища

.2 Огляд наявних аналогів

.3 Постановка задачі

Висновки до розділу

. Інформаційне забезпечення

.1 Вхідні дані

.2 Вихідні дані

Висновки до розділу

. Постановка задачі

.1 Організаційно-інформаційна сутність задачі

. Програмне та технічне забезпечення

.1 Засоби розробки

.2 Загальні вимоги до технічного забезпечення

Висновки до розділу

. Технологічний розділ

.1 Керівництво користувача

.2 Керівництво системного програміста

.3 Керівництво програміста

.4 Випробування програмного продукту

Загальні висновки

Перелік посилань



1.Загальні положення


.1 Опис предметного середовища


Active Directory - LDAP <#"justify">Опис процесу діяльності

Система призначена для полегшення процесу реєстрації користувачів в базі даних Active Directory. Система працює з урахування специфіки та політики безпеки Windows Server 2008R2 і Windows Active Directory.

Опис функціональної моделі

Для автоматизації та оптимізації роботи системних адміністраторів кафедри АСОІУ система підтримує реалізацію таких функцій, що допомагають полегшити процес реєстрації користувачів в базі даних Active Directory:

·створення облікового запису в базі даних Active Directory;

·заповнення анкети персональних даних користувача;

·розповсюдження на обліковий запис, певних групових політик(GPO);

·відправка на електронну пошту користувача листа з «Правилами поведінки в аудиторіях кафедри» та «Правилами користування обладнанням кафедри».

Користувач має можливість: ознайомитись з правилами кафедри, заповнити свої персональні дані, переглянути контактну інформацію з технічної підтримкою кафедри.

Адміністратор має можливість: змінити GPO, що розповсюджуються на обліковий запис користувача, змінити параметри облікового запису, вміст листа що відправляється на пошту користувача.


.2 Огляд наявних аналогів


На момент розробки даної системи не було знайдено подібних систем.


.3 Постановка задачі


Призначення розробки

Система «Автоматизація реєстрації користувачів» розробляється для полегшення процесу створення облікових записів користувачів в базі даних Active Directory.

Цілі створення

Цілями створення даної системи є:

·оптимізація роботи системних адміністраторів;

·автоматизація створення облікових записів користувачів.

Для реалізації поставлених цілей система повинна рішити наступні задачі:

·створення зручного, легкого та зрозумілого у користуванні зовнішнього інтерфейсу;

·розробка програми, що буде створювати облікові записи користувачів та наділяти їх відповідними правами.


Висновки до розділу


У даному розділі були розглянуті проаналізовані та поставлені основні цілі для створення системи. Проведена постановка задачі для системи. Проведений опис діяльності та описані функціональні можливості системи для автоматизації користувачів Active Directory.

При аналізі існуючих рішень було виявлено та проаналізовано декілька розробок. Жодна з них повністю не задовольнили вимоги до системи, що і спонукало до створення даної розробки.



2.Інформаційне забезпечення


.1 Вхідні дані


Дані вводяться в систему користувачем, через веб-сторінку.

Дані, що надходять від користувача:

·імя;

·прізвище;

·номер залікової книжки;

·пароль;

·адреса електронної пошти.

Це дозволяє створити обліковий запис в базі даних Active Directory та заповнити інформацію про користувача.


.2 Вихідні дані


Вихідною інформацією є повідомлення про успішну реєстрацію користувача в базі даних Active Directory та створений обліковий запис користувача.


Висновки до розділу


У даному розділі був приведений структурний опис первісних даних системи, запропоновані макети виглядів вигляду веб-сторінки в якості вихідних даних.



3.Постановка задачі


.1 Організаційно-інформаційна сутність задачі


Спочатку кожного навчального року, першокурсники повинні пройти процес реєстрації особистих облікових записів в базі даних Active Directory, які в подальшому їхньому навчанні будуть використовуватись для роботи в компютерних аудиторія кафедри. Дана програма створена для того, щоб знизити затрати часу на цей процес та підвищити ефективність роботи системних адміністраторів.

Об'єкти представляють собою окремі сутності (користувача, комп'ютер, принтер, програму або спільну мережеву папку) і їх атрибути. Об'єкти також можуть бути контейнерами для інших об'єктів. Об'єкт унікально ідентифікується своїм ім'ям і має набір атрибутів:

·характеристик;

·даних, які об'єкт може містити.



4.Програмне та технічне забезпечення


.1 Засоби розробки


При створенні даного програмного продукту були використані такі засоби програмування як Microsoft Visual Studio 2010 (ASP.NET) та Script Editor.

Для створення програми, що працює даними Active Directory використовувалась мова програмування C#. Головною перевагою C# в створенні даної системи - її пристосованість до роботи з Microsoft AD, а саме легке управління обєктами бази даних AD.

Для створення графічної оболонки (веб-сторінки) використовувалась мова розмітки HTML/CSS та JavaScript - для динамічної зміні змісту сторінки.


.2 Загальні вимоги до технічного забезпечення


Даний програмний продукт являє собою систему, що створює облікові записи користувачів в базі даних AD.

Для правильної роботи програми до складу технічних засобів повинні входити:

a) ПК під управлінням однієї з перелічених операційних систем: Windows XP/Vista/7/8, Linux, MacOS;) Технічні параметри ПК повинні задовольняти перелічені нижче:

·Процесор з тактовою частотою не нижче 1.6 ГГц;

·Достатній обєм оперативної памяті (не менше 512 МБ);

·Широкий канал підключення до мережі Інтернет;

·Браузер (Google Chrome, Opera, Mozilla Firefox);

c) Технічні параметри сервера:

·Процесор з тактовою частотою не нижче 1.6 ГГц;

·Достатній обєм оперативної памяті (не менше 512 МБ);

·Широкий канал підключення до мережі Інтернет;

·Встановлений IIS Web;


Висновки до розділу


Розглянуто основні особливості розробки програм для роботи з AD за допомогою мови програмування C#.

До системи, що розробляється були поставлені мінімальні технічні вимоги для функціонування системи.



5.Технологічний розділ


.1 Керівництво користувача

автоматизація реєстрація користувач програміст

Для запуску даної системи потрібно відкрити браузер та перейти за вказаним інтернет-адресом. При відкриті веб-сторінки, користувачу буде відображено форму з «Правилами кафедри АСОЇУ». Вигляд даної форми наведено на рисунку 5.1.


Рисунок 5.1 - Блок ознайомлення з «Правилами кафедри»


Перехід до блоку заповнення персональної інформації користувача здійснюється після натиснення кнопки «Далі», що знаходиться на правій стороні форми. Після натиснення перед вами зявиться анкета зображена на рисунку 5.2.

Правила вводу персональних даних:

·Імя та Прізвище повинні бути введені латиницею, перші букви мають бути великими;

·Номер залікової книжки повинен бути введений в такому форматі: isXXXX/ipXXXX, де is/ip - напрямок навчання, XXXX-номер заліковки;

·Пароль повинен містити мінімум 8 символів, серед яких мають бути великі та маленькі літери та цифри;


Рисунок 5.2 - Блок заповнення персональних даних


При наступному натисненні кнопки «Далі» користувач перейде до блоку, де він має засвідчитись, що всі введені ним дані є коректними. Приклад показаний на рисунку 5.3.

Також користувач має право проходити процедуру реєстрації на англійській мові.



Рисунок 5.3 - Блок перевірки даних


Наступне натискання кнопки «Далі» відправить запит на сервер і якщо дані є вірними створить користувача. Також на електронну адресу користувача буде надіслано повідомлення з його персональними даними та «Правилами кафедри АСОІУ».


5.2 Керівництво системного програміста


Для коректної роботи системи потрібно:

Технічні параметри сервера:

·Процесор з тактовою частотою не нижче 1.6 ГГц;

·Достатній обєм оперативної памяті (не менше 512 МБ);

·Широкий канал підключення до мережі Інтернет;

На сервері повинна бути встановлена операційна система Windows Server 2008R2 і піднятий сервіс IISWeb.

IIS (Internet Information Services, до версії 5.1 - Internet Information Server) - це набір серверів <#"justify">5.3 Керівництво програміста


Для створення даної системи використовувались Microsoft Visual Studio 2010 Professionalі Sublime 2.

Код мовою C#, що виконує реєстрацію користувачів на сервері:


//e-mail

//========================================mail = newMailMessage();SmtpServer = newSmtpClient("smtp.gmail.com");.From = newMailAddress("[email protected]");.To.Add(email.Text);.Subject = "Test Mail";.Body = " Name: " + studname.Text + "\n Surname: " + studsurname.Text + "\n login: " + recordbook.Text

+ "\n Password: " + pass.Text;.Port = 587;.Credentials =System.Net.NetworkCredential("[email protected]", "fiot_asoiu");.EnableSsl = true;.Send(mail);

//AD

//========================================connectionPrefix = "LDAP://10.18.16.13";dirEntry = newDirectoryEntry(connectionPrefix);newUser = dirEntry.Children.Add("CN=" + studname.Text + " " + studsurname.Text, "user");

//=======.Properties["samAccountName"].Value = recordbook.Text;.Invoke("Put", newobject[] { "Description", recordbook.Text });.Properties["displayName"].Value = studname.Text + " " + studsurname.Text;.Properties["givenName"].Value = studname.Text;.Properties["sn"].Value = studsurname.Text;.Properties["mail"].Value = email.Text;

//=======.CommitChanges();

//=======.Invoke("SetPassword", newobject[] { pass.Text });.Invoke("Put", newobject[] { "userPrincipalName", recordbook.Text + "@asoiu.ntu-kpi.kiev.ua" });

//=======.CommitChanges();

//=======ctx = newPrincipalContext(ContextType.Domain, "10.18.16.13");principal = UserPrincipal.FindByIdentity(ctx, recordbook.Text);.UserCannotChangePassword = true;.Save();

//=======.Properties["userAccountControl"].Value = 0x10002;.CommitChanges();.Close();.Close();.Show("Registration was complete");


Додаткові значення userAccountControl:

_TEMP_DUPLICATE_ACCOUNT = 0x0100,_NORMAL_ACCOUNT = 0x0200,_INTERDOMAIN_TRUST_ACCOUNT = 0x0800,_WORKSTATION_TRUST_ACCOUNT = 0x1000,_SERVER_TRUST_ACCOUNT = 0x2000,_DONT_EXPIRE_PASSWD = 0x10000,_SCRIPT = 0x0001,_ACCOUNTDISABLE = 0x0002,_HOMEDIR_REQUIRED = 0x0008,_LOCKOUT = 0x0010,_PASSWD_NOTREQD = 0x0020,_PASSWD_CANT_CHANGE = 0x0040,_ACCOUNT_LOCKOUT = 0X0010,_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0X0080,


Код форми реєстрації:

$(str) { return document.querySelector(str) }hasClass(el, name) {RegExp('(\\s|^)'+name+'(\\s|$)').test(el.className);

}addClass(el, name)

{(!hasClass(el, name)) { el.className += (el.className ? ' ' : '') +name; }

}removeClass(el, name)

{(hasClass(el, name)) {.className=el.className.replace(new RegExp('(\\s|^)'+name+'(\\s|$)'),' ').replace(/^\s+|\s+$/g, '');

}

}getXmlHttp() {xmlhttp;{= new ActiveXObject("Msxml2.XMLHTTP");

} catch (e) {{= new ActiveXObject("Microsoft.XMLHTTP");

} catch (E) {= false;

}

}(!xmlhttp &&typeof XMLHttpRequest!='undefined') {= new XMLHttpRequest();

}xmlhttp;

}Scroller = {: 0,: 0,: null,: 0,: 0,:0,:0,: function(){(this) {.style.left=-posX*w+'px';.style.top=-posY*h+'px';

}

},: function(){(this) {-= 1;= (posX<0) ? 0 : posX;()

}

},: function(){(this) {+= 1;= (posX>sizeX-1) ? sizeX-1 : posX;()

}

},: function(){(this) {-= 1;= (posY<0) ? 0 : posY;()

}

},: function(){(this) {+= 1;= (posY>sizeY-1) ? sizeY-1 : posY;()

}

},: function(x,y) {(this) {= y= (posY<0) ? 0 : posY= (posY>sizeY-1) ? sizeY-1 : posY= x= (posX<0) ? 0 : posX= (posX>sizeX-1) ? sizeX-1 : posX()

}

},: function(x,y,sx,sy,width,height,contentSelector){(this) {= x;= y;= sx;= sy;= document.querySelector(contentSelector);.style.position='relative'=width=height

};

}

}scroll = null;Registration() {scriptAddres = '#"justify">'rules' : '#rules',

'form' : '#regBlock',

'formData' : '#regFormData',

'langPanel' : '#langPanel',

'confirm' : '#confirm',

'nextBtn' : '#nextBtn',

'canselBtn' : '#CancelBtn',

'wait' : '#wait',

'supportBtn' : '#support',

'supportBlock' : '#supportBlock',

'stepBar' : '#stepBar',

'procWaiter' : '#waiter',

'procError' : '#error',

'procSuccess' : '#success',

'support' : '#supportBlock',

'backBtn' : '#backBtn'

},= {

'name' : '#Name',

'surname' : '#SurName',

'group' : '#Group',

'pass' : '#Pass',

'pass2' : '#CPass',

'mail' : '#EMail'

},= {},= {

'name' : '',

'surname' : '',

'group' : '',

'pass' : '',

'mail' : ''

},= {

'ua' : {

'name' : 'Ім\'я',

'surname' : 'Прізвище',

'group' : 'Номер залікової книжки',

'pass' : 'Пароль',

'pass2' : 'Підтвердження паролю',

'mail' : 'Електронна пошта',

'emptyName' : 'Пусте поле ім\'я',

'emptySurName' : 'Пусте поле прізвища',

'emptyGroup' : 'Пусте поле номера залікової книжки',

'badGroup' : 'Некоректний номер залікової книжки',

'emptyPass' : 'Пусте поле паролю',

'badPass' : 'Некоректний пароль',

'difPass' : 'Паролі не збігаються',

'emptyMail' : 'Пусте поле електронної пошти',

'badMail' : 'Некоректна електронна пошта',

'wait' : 'Будь ласка зачекайте',

'step1' : 'Правила',

'step2' : 'Заповнення даних',

'step3' : 'Перевірка даних',

'step4' : 'Обробка',

'rules' : 'ua rules',

'support' : 'ua support'

},

'eng' : {

'name' : 'Name',

'surname' : 'Last name',

'group' : 'Number of academic records',

'pass' : 'Pass',

'pass2' : 'Confirm Password',

'mail' : 'Email Address',

'emptyName' : 'Empty name',

'emptySurName' : 'Empty last name',

'emptyGroup' : 'Empty number of academic records',

'badGroup' : 'Invalid academic record',

'emptyPass' : 'Empty pass',

'badPass' : 'bad pass',

'difPass' : 'Different pass',

'emptyMail' : 'Empty email',

'badMail' : 'bad mail',

'wait' : 'Please wait',

'step1' : 'Rules',

'step2' : 'Fill data',

'step3' : 'Check data',

'step4' : 'Processing',

'rules' : 'eng rules',

'support' : 'eng support'

}

},= 'ua',= 'rules',= 0,= 0;hide(el){.style.display="none";

}show(el){.style.display="block";

}isBadStr() {(var key in arguments)(arguments[key]) returnfalse;

}warningCodeGet(value,flagVal,flag){(flag === undefined)(value) ? '' : flagVal{(value)(flag) ? '' : flagVal[0]flagVal[1]

}

}checkEmail(){mail = fields.mail.valuereg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;.mail = warningCodeGet(mail,[languageData[language] ['badMail'],[language]['emptyMail']],reg.test(mail))isBadStr(warningCodes.mail)

}checkNames(){.name = warningCodeGet(fields.name.value,languageData [language]['emptyName']).surname = warningCodeGet(fields.surname.value,language Data[language]['emptySurName'])isBadStr(warningCodes.name,warningCodes.surname)

}checkPass() {(fields.pass.value==fields.pass2.value) {reg = /[^A-Za-z0-9!@#\$%\^&\*()_\+-=]/flag = !reg.test() && (fields.pass.value.length >= 8).pass = warningCodeGet(fields.pass.value,[languageData[language]['badPass'],languageData[language]['emptyPass']],flag)

}warningCodes.pass = languageData[language]['difPass']isBadStr(warningCodes.pass)

}checkGroup() {group = $(fieldSelectors.group).value.toLowerCase()= group.replace('с','s')= group.replace('п','p')= group.replace('і','i')(group!=fields.group.value).group.value=group.group = warningCodeGet(group,[languageData[language] ['badGroup'],[language]['emptyGroup']],

(group[0]=='i'&& (group[1]=='p' || group[1]=='s') && group.length==6))isBadStr(warningCodes.group)

}check(){r = checkNames() + checkGroup() + checkPass() + checkEmail()(r<4) ? false : true

}removeToolTip(el){(el.parentNode.parentNode.querySelector('.tool-tip'),'tool-tip-show')(el.parentNode,'input-correct')

}addToolTip(el,str){(el.parentNode,'input-correct')(el.parentNode.parentNode.querySelector('.tool-tip'),'tool-tip-show').parentNode.parentNode.querySelector('.tool-tip').innerHTML = str;

}applyLanguage(e){(typeof e != "string") {= e.target.getAttribute('data-lang')

}language1 = e= language1(!language) return;(var key in fields)[key].parentNode.parentNode.querySelector('span').innerHTML = languageData[language][key]().rules.innerHTML = languageData[language]['rules'].support.innerHTML = languageData[language]['support'](var key in warningCodes)[key].parentNode.parentNode.querySelector('.tool-tip').innerHTML = warningCodes[key].stepBar.innerHTML = languageData[language]['step'+(scroll.posX+ 1)].wait.innerHTML = languageData[language]['wait']+' '+time(mode=='confirm')

{.confirm.innerHTML = languageData[language]['name'] + ' : ' + fields.name.value + '<br>' +[language]['surname'] + ' : ' + fields.surname.value + '<br>' +[language]['group'] + ' : ' + fields.group.value + '<br>' +[language]['mail'] + ' : ' + fields.mail.value + '<br>'

}

}fieldChecker(e){()(var key in warningCodes) {(e.target == fields[key] || (key=='pass'&& e.target == fields['pass2']))(warningCodes[key]) {(fields[key], warningCodes[key])(key=='pass') removeClass(fields['pass2'].parentNode,'input-correct')

} else {(fields[key]);(key=='pass') removeToolTip(fields['pass2']);

}

}

}waiterLoop(){(time == 0) {.wait.style.display='none'.nextBtn.disabled = false(timerId)

} else {.wait.innerHTML = languageData[language]['wait'] + ' ' + time;-;

}

}init() {= 'rules'(var key in selectors)[key] = $(selectors[key])(var key in fieldSelectors)[key] = $(fieldSelectors[key]).nextBtn.addEventListener('click',nextBtnClick).supportBtn.addEventListener('click',supportBtnClick).formData.addEventListener('keyup',fieldChecker).backBtn.addEventListener('click',backBtnClick)(language)().langPanel.addEventListener('click',applyLanguage)= setInterval(waiterLoop, 1000);

}supportBtnClick() {(scroll.posY==1) scroll.moveto(scroll.posX,0){.supportBlock.style.left = (scroll.posX*blocks.supportBlock. offsetWidth)+'px';.moveto(scroll.posX,1);

}

}send() {{="proc".nextBtn.disabled = true.backBtn.disabled = truexmlhttp = getXmlHttp() // Создаём объект XMLHTTP.open('POST', scriptAddres, true) // Открываем асинхронное соединение.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') // Отправляем кодировку

//encodeURIComponentdata = ''dataAdd(key,val) {(data) data += '&'+= encodeURIComponent(key) + '=' + encodeURIComponent(val)

}(key in fields) {(key!='pass2')(key,fields[key].value)

}(blocks.procError).procError.style.opacity = 0(blocks.procSuccess).procSuccess.style.opacity = 0

//xmlhttp.onreadystatechange.onreadystatechange = function() { // Ждём ответа от сервера(xmlhttp.readyState == 4) { // Ответ пришёл(xmlhttp.status == 200) { // Сервер вернул код 200 (что хорошо)(blocks.procWaiter)

///////////////////////////////////////////////////////////

//check correct answer

///////////////////////////////////////////////////////////

//xmlhttp.responseText - то что вернул сервер

//к примеру если нам пришло число 30, то считаем что ответ некоректный(xmlhttp.responseText!=30)

{.procSuccess.innerHTML = xmlhttp.responseText(blocks.procSuccess).procSuccess.style.opacity = 1

} else {.procError.innerHTML = "Incorrect answer"(blocks.procError).procError.style.opacity = 1.backBtn.disabled = false;

}

}

}(xmlhttp.status == 0) {(blocks.procWaiter).procError.innerHTML = "Server don`t response"(blocks.procError).procError.style.opacity = 1.backBtn.disabled = false;

}

}.send(data) // Отправляем POST-запрос

}(e) {(blocks.procWaiter).procError.style.opacity = 0.procSuccess.style.opacity = 0(blocks.procSuccess).procError.innerHTML = "Error : " + e.message(blocks.procError).procError.style.opacity = 1.backBtn.disabled = false;

}

}nextBtnClick() {(scroll.posY==1) scroll.moveto(scroll.posX,0)(mode=='rules') {

//check time='fillData'.moveto(1,0)

} elseif (mode=='fillData') {(check())

{(var key in warningCodes)(fields[key])='confirm'.confirm.innerHTML = languageData[language]['name'] + ' : ' + fields.name.value + '<br>' +[language]['surname'] + ' : ' + fields.surname.value + '<br>' +[language]['group'] + ' : ' + fields.group.value + '<br>' +[language]['mail'] + ' : ' + fields.mail.value + '<br>'.moveto(2,0)

} else {(var key in warningCodes)(warningCodes[key]) addToolTip(fields[key], warningCodes[key])removeToolTip(fields[key])

}

} elseif (mode=='confirm') {(blocks.procError)(blocks.procSuccess)(blocks.procWaiter).moveto(3,0);()

}.stepBar.innerHTML = languageData[language]['step'+(scroll.posX +1)]

}backBtnClick() {(scroll.posY==1) scroll.moveto(scroll.posX,0)(mode) {'rules' :'fillData' :='rules'.moveto(0,0)'confirm' :='fillData'.moveto(1,0)'proc' :='confirm'.moveto(2,0).nextBtn.disabled = false;;

}.stepBar.innerHTML = languageData[language]['step'+(scroll.posX+ 1)];

}();

}.onload = function(){= Scroller.init(0,0,4,2,410,416,"#scrollerContent")

//document.querySelector('#leftBtn').addEventListener('click',function(){ scroll.left() })();

//document.querySelector('#botBtn').addEventListener('click',function(){ scroll.down() })

//document.querySelector('#topBtn').addEventListener('click',function(){ scroll.up() })

}


5.4 Випробування програмного продукту


У ході розробки програмного застосування було проведено ряд тестів на віртуальному сервері на якому було встановлене необхідне програмне забезпечення. Після набуття стабільності систему було перенесено на реальних сервер.

Загальні висновки


Даний проект присвячений опису етапів створення системи «Автоматизація реєстрації користувачів». Були розглянуті структурний опис первісних даних системи, запропоновані веб-сторінки в якості вихідних даних.

Під час створення даного проекту було досягнуто всіх цілей поставлених перед початком розробки.



Перелік посилань


1.ASP.NET MVC Framework с примерами на C# Стивен Сандерсон.

2.Pro ASP.NET 3.5 in C# 2008 Matthew MacDonald and Mario Szpuszta

3.Learning JavaScript Shelley Powers

4.Pro JavaScript Techniques John Resig

.Пости / ASP.NET / Хабрахабр [Електронний ресурс] / Режим доступу: http://habrahabr.ru/hub/aspnet/posts/


МІНІСТЕРСТВО ОСВІТИ І НАУКИ, МОЛОДІ ТА СПОРТУ УКРАЇНИ НАЦІОНАЛЬНИЙ ТЕХНІЧНИЙ УНІВЕРСИТЕТ УКРАЇНИ «КПІ» Кафедра автоматизованих систем обробки ін

Больше работ по теме:

КОНТАКТНЫЙ EMAIL: [email protected]

Скачать реферат © 2017 | Пользовательское соглашение

Скачать      Реферат

ПРОФЕССИОНАЛЬНАЯ ПОМОЩЬ СТУДЕНТАМ