diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..3d210c1
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "dz-2-basics"]
+ path = dz-2-basics
+ url = git@github.com:turboDi/dz-2-basics.git
diff --git a/dz-2-basics b/dz-2-basics
new file mode 160000
index 0000000..178377c
--- /dev/null
+++ b/dz-2-basics
@@ -0,0 +1 @@
+Subproject commit 178377c62bd267c824c2cac260ab0041134b67b0
diff --git a/event-collection.html b/event-collection.html
new file mode 100644
index 0000000..d5bff20
--- /dev/null
+++ b/event-collection.html
@@ -0,0 +1,23 @@
+
+
+
+
+ EVents test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/event-collection.js b/event-collection.js
new file mode 100644
index 0000000..cb75e93
--- /dev/null
+++ b/event-collection.js
@@ -0,0 +1,231 @@
+/**
+ * Добавляет к дате кол-во лет, месяцев, дней и т.д определенных в параметре
+ * Параметр добавления даты должен иметь формат + dd.MM.YY hh:mm
+ * @param {Number|Date} date Дата
+ * @param {String} dateTimeStr Строка в формате '+ dd.MM.YY hh:mm'
+ *
+ * @return {Date}
+ */
+function addDateTime(date, dateTimeStr) {
+ 'use strict';
+ var result, splitted, sign, addDate, dd, mm, yy, addTime, hh, min;
+ splitted = checkAddTime(dateTimeStr);
+ result = new Date(date.getTime());
+ if (splitted) {
+ if (splitted[1] === '-') {
+ sign = -1;
+ } else {
+ sign = 1;
+ }
+ addDate = splitted[2].split('.');
+ addTime = splitted[3].split(':');
+ result.setDate(result.getDate() + sign * addDate[0]);
+ result.setMonth(result.getMonth() + sign * addDate[1]);
+ result.setYear(result.getYear() + sign * addDate[2]);
+ result.setHours(result.getHours() + sign * addTime[0]);
+ result.setMinutes(result.getMinutes() + sign * addTime[1]);
+ } else {
+ console.log("Add time in 'addDateTime' function must have format '+ dd.MM.YY hh:mm'");
+ }
+ return result;
+}
+
+/**
+ * Вычисляет когда в следующий раз случится периодическое событие
+ *
+ * @param {Event} event Событие
+ *
+ * @return {Date}
+ */
+function getNextHappenDate(event) {
+ 'use strict';
+ var nhd, today;
+ if (!event.nextHappenDate) {
+ today = new Date();
+ nhd = event.startDate;
+ while (nhd < today) {
+ nhd = addDateTime(nhd, event.repeat.value);
+ }
+ event.nextHappenDate = nhd;
+ }
+ return event.nextHappenDate;
+}
+
+/**
+ * Вычисляет следующее время напоминания для периодических событий
+ *
+ * @param {Event} event Событие
+ *
+ * @return {Date}
+ */
+function getNextAlarmTime(event) {
+ 'use strict';
+ var nhd = getNextHappenDate(event);
+ return addDateTime(nhd, event.alert.value);
+}
+
+/**
+ * Функция проверяет, нужно ли напомнить о событии
+ *
+ * @param {Event} event Событие
+ *
+ * @return {Boolean}
+ */
+function isAlertTime(event) {
+ 'use strict';
+ var today, diff;
+ today = new Date();
+ diff = today - getNextAlarmTime(event);
+ return diff > -500 && diff < 500;
+}
+
+/**
+ * Вычисляет дату начала недели
+ *
+ * @param {Date} [date="new Date()"] Дата
+ *
+ * @return {Date}
+ */
+function getWeekStartDate(date) {
+ 'use strict';
+ var startOfWeek;
+ date = date || new Date();
+ startOfWeek = new Date(date.getTime());
+ startOfWeek.setDate(date.getDate() - date.getDay() + 1);
+ startOfWeek.setHours(0);
+ startOfWeek.setMinutes(0);
+ return startOfWeek;
+}
+
+/**
+ * Вычисляет дату конца недели
+ *
+ * @param {Date} [date="new Date()"] Дата
+ *
+ * @return {Date}
+ */
+function getWeekEndDate(date) {
+ 'use strict';
+ var startOfWeek, endOfWeek;
+ startOfWeek = getWeekStartDate(date);
+ endOfWeek = new Date(startOfWeek.getTime());
+ endOfWeek.setDate(startOfWeek.getDate() + 7);
+ return endOfWeek;
+}
+
+/**
+ * Фабрика фильтрации массива
+ *
+ * @param {function} selector Функция фильтрации
+ *
+ * @return {Array}
+ */
+function filterFactory(selector) {
+ 'use strict';
+ return function (array) {
+ return array.filter(selector);
+ };
+}
+
+/**
+ * Фабрика сортировки массива
+ *
+ * @param {function} selector Функция сортировки
+ *
+ * @return {Array}
+ */
+function sortFactory(selector) {
+ 'use strict';
+ return function (array) {
+ return array.sort(selector);
+ };
+}
+
+/**
+ * Функция получения коллекции случайных событий
+ *
+ * @param {Number} size Размер массива
+ *
+ * @return {Array}
+ */
+function getEventsCollection(size) {
+ 'use strict';
+ var i, events;
+ events = [];
+ for (i = 0; i < size; i++) {
+ events.push(getRandomEvent());
+ }
+ return events;
+}
+
+var events = getEventsCollection(20);
+
+var pastEvents = filterFactory(function (event) {
+ 'use strict';
+ return event.endDate < new Date();
+});
+
+var futureEvents = filterFactory(function (event) {
+ 'use strict';
+ return event.startDate > new Date();
+});
+
+var thisWeekEvents = filterFactory(function (event) {
+ 'use strict';
+ return event.startDate > getWeekStartDate() && event.startDate < getWeekEndDate();
+});
+
+var partyEvents = filterFactory(function (event) {
+ 'use strict';
+ return event.title === 'Drunken feast';
+});
+
+var nightAlarms = filterFactory(function (event) {
+ 'use strict';
+ var alarm = getNextAlarmTime(event);
+ return alarm.getHours() > 0 && alarm.getHours() < 8;
+});
+
+var sortByStartDateInt = sortFactory(function (a, b) {
+ 'use strict';
+ return b.startDate - a.startDate;
+});
+
+var sortByNextHappenDateInt = sortFactory(function (a, b) {
+ 'use strict';
+ return getNextHappenDate(b) - getNextHappenDate(a);
+});
+
+/**
+ * Функция сортировки массива событий по дате начала
+ *
+ * @param {Array} events Массив событий
+ * @param {Boolean} [asc = null] Сортировка по возрастанию/убыванию
+ *
+ * @return {Array}
+ */
+function sortByStartDate(events, asc) {
+ 'use strict';
+ var sorted = sortByStartDateInt(events);
+ if (!asc) {
+ sorted.reverse();
+ }
+ return sorted;
+}
+
+/**
+ * Функция сортировки массива событий по дате их следующего раза
+ *
+ * @param {Array} events Массив событий
+ * @param {Boolean} [asc = null] Сортировка по возрастанию/убыванию
+ *
+ * @return {Array}
+ */
+function sortByNextHappenDate(events, asc) {
+ 'use strict';
+ var sorted = sortByNextHappenDateInt(events);
+ if (!asc) {
+ sorted.reverse();
+ }
+ return sorted;
+}
\ No newline at end of file
diff --git a/event-random.js b/event-random.js
new file mode 100644
index 0000000..58787a6
--- /dev/null
+++ b/event-random.js
@@ -0,0 +1,113 @@
+/*jslint plusplus: true*/
+var activities = ["Studying", "Drunken feast", "Karaoke singing", "Hanging around"];
+var locations = ["My home", "My work", "My friend's house", "1905 Sq.", "UrFU", "Unknown"];
+
+/**
+ * Возвращает случайное число в интервале [min, max]
+ *
+ * @param {Number} min нижний предел
+ * @param {Number} max верхний предел
+ *
+ * @return {Number}
+ */
+function getRandomInt(min, max) {
+ 'use strict';
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+/**
+ * Возвращает случайный элемент массива
+ *
+ * @param {Array} arr массив
+ *
+ * @return {Object}
+ */
+function getRandomElement(arr) {
+ 'use strict';
+ return arr[getRandomInt(0, arr.length - 1)];
+}
+
+/**
+ * Возвращает сгенерированную строку из случайных символов
+ *
+ * @return {String}
+ */
+function getRandomString() {
+ 'use strict';
+ var chars, length, str, i;
+ chars = "01234 56789 ABCDE FGHIJ KLMNO PQRST UVWXT Zabcd efghi klmno pqrst uvwxy z";
+ chars = chars.split('');
+ length = getRandomInt(4, chars.length);
+ str = '';
+ for (i = 0; i < length; i++) {
+ str += getRandomElement(chars);
+ }
+ return str;
+}
+
+/**
+ * Возвращает случайное собственное свойство объекта
+ *
+ * @param {Object} obj объект
+ *
+ * @return {Object}
+ */
+function getRandomPropertyVal(obj) {
+ 'use strict';
+ var keys, prop;
+ keys = [];
+ for (prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ keys.push(prop);
+ }
+ }
+ return obj[getRandomElement(keys)];
+}
+
+/**
+ * Возвращает сгенерированную дату начала события
+ * Вычисляется как текущая дата начала события + случайное число дней от -28 до 28
+ *
+ * @return {Date}
+ */
+function getRandomStartDate() {
+ 'use strict';
+ var startDate = new Date();
+ startDate.setDate(startDate.getDate() + getRandomInt(-28, 28));
+ startDate.setHours(getRandomInt(0, 23));
+ startDate.setMinutes(getRandomInt(0, 59));
+ return startDate;
+}
+
+/**
+ * Возвращает сгенерированную дату окончания события
+ * Вычисляется как дата начала события + случайное число часов от 1 до 23
+ * @param {Number|Date} startDate Начало события
+ *
+ * @return {Date}
+ */
+function getRandomEndDate(startDate) {
+ 'use strict';
+ var endDate = new Date(startDate.getTime());
+ endDate.setHours(startDate.getHours() + getRandomInt(1, 23));
+ endDate.setMinutes(getRandomInt(0, 59));
+ return endDate;
+}
+
+/**
+ * Возвращает сгенерированный случайным образом объект Event
+ *
+ * @return {Object}
+ */
+function getRandomEvent() {
+ 'use strict';
+ var title, location, starts, ends, repeat, alert, notes;
+ title = getRandomElement(activities);
+ location = getRandomElement(locations);
+ starts = getRandomStartDate();
+ ends = getRandomEndDate(starts);
+ repeat = getRandomPropertyVal(REPEAT);
+ alert = getRandomPropertyVal(ALERT);
+ notes = getRandomString();
+ return Event(title, location, starts, ends, repeat, alert, notes);
+}
\ No newline at end of file