Add timetable to Wulkanowy (#38)

* Add timetable entities, synchronization and UI
* Add better code hub config
* Update SDK tools
* Change activity to ui

* [API] fix lesson room, when division into groups
* [API] Rewrite lesson parser
* [API] Add support for new lesson type
* [API] Fix for substitutions in the timetable
This commit is contained in:
Rafał Borcz
2017-12-11 19:45:28 +01:00
committed by Mikołaj Pich
parent 647ed08460
commit c111e43f18
77 changed files with 3125 additions and 471 deletions

View File

@ -4,8 +4,9 @@ apply plugin: 'jacoco'
apply plugin: 'com.jfrog.bintray'
apply plugin: 'com.github.dcendents.android-maven'
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
compileJava.options.encoding = "UTF-8"
compileTestJava.options.encoding = "UTF-8"
ext {
PUBLISH_GROUP_ID = GROUP_ID

View File

@ -9,6 +9,8 @@ public class Day {
private String date = "";
private String dayName = "";
private boolean isFreeDay = false;
private String freeDayName = "";
@ -35,6 +37,15 @@ public class Day {
return this;
}
public String getDayName() {
return dayName;
}
public Day setDayName(String dayName) {
this.dayName = dayName;
return this;
}
public boolean isFreeDay() {
return isFreeDay;
}

View File

@ -10,6 +10,8 @@ public class Lesson {
public static final String CLASS_NEW_MOVED_IN_OR_CHANGED = "x-treelabel-zas";
private String number = "";
private String subject = "";
private String teacher = "";
@ -24,6 +26,8 @@ public class Lesson {
private String endTime = "";
private String date = "";
private boolean isEmpty = false;
private boolean isDivisionIntoGroups = false;
@ -36,6 +40,15 @@ public class Lesson {
private boolean isNewMovedInOrChanged = false;
public String getNumber() {
return number;
}
public Lesson setNumber(String number) {
this.number = number;
return this;
}
public String getSubject() {
return subject;
}
@ -99,6 +112,15 @@ public class Lesson {
return this;
}
public String getDate() {
return date;
}
public Lesson setDate(String date) {
this.date = date;
return this;
}
public boolean isEmpty() {
return isEmpty;
}

View File

@ -5,8 +5,12 @@ import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import io.github.wulkanowy.api.StudentAndParent;
@ -20,125 +24,178 @@ public class Timetable {
this.snp = snp;
}
public Week getWeekTable() throws IOException {
public Week getWeekTable() throws IOException, ParseException {
return getWeekTable("");
}
public Week getWeekTable(String tick) throws IOException {
public Week getWeekTable(final String tick) throws IOException, ParseException {
Element table = snp.getSnPPageDocument(TIMETABLE_PAGE_URL + tick)
.select(".mainContainer .presentData").first();
Elements tableHeaderCells = table.select("thead th");
List<Day> days = getDays(table.select("thead th"));
setLessonToDays(table, days);
return new Week()
.setStartDayDate(days.get(0).getDate())
.setDays(days);
}
private List<Day> getDays(Elements tableHeaderCells) throws ParseException {
List<Day> days = new ArrayList<>();
for (int i = 2; i < 7; i++) {
String[] dayHeaderCell = tableHeaderCells.get(i).html().split("<br>");
boolean isFreeDay = tableHeaderCells.get(i).hasClass("free-day");
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT);
Date d = sdf.parse(dayHeaderCell[1].trim());
sdf.applyPattern("yyyy-MM-dd");
Day day = new Day();
day.setDate(dayHeaderCell[1]);
day.setDayName(dayHeaderCell[0]);
day.setDate(sdf.format(d));
if (isFreeDay) {
day.setFreeDay(isFreeDay);
if (tableHeaderCells.get(i).hasClass("free-day")) {
day.setFreeDay(true);
day.setFreeDayName(dayHeaderCell[2]);
}
days.add(day);
}
Elements hoursInDays = table.select("tbody tr");
return days;
}
// fill days in week with lessons
for (Element row : hoursInDays) {
private void setLessonToDays(Element table, List<Day> days) {
for (Element row : table.select("tbody tr")) {
Elements hours = row.select("td");
// fill hours in day
for (int i = 2; i < hours.size(); i++) {
Lesson lesson = new Lesson();
Elements e = hours.get(i).select("div");
switch (e.size()) {
case 1:
lesson = getLessonFromElement(e.first());
break;
case 3:
lesson = getLessonFromElement(e.get(1));
break;
default:
lesson.setEmpty(true);
break;
}
String[] startEndEnd = hours.get(1).text().split(" ");
lesson.setStartTime(startEndEnd[0]);
lesson.setEndTime(startEndEnd[1]);
lesson.setDate(days.get(i - 2).getDate());
lesson.setNumber(hours.get(0).text());
addLessonDetails(lesson, hours.get(i).select("div"));
days.get(i - 2).setLesson(lesson);
}
}
Element startDayCellHeader = tableHeaderCells.get(2);
String[] dayDescription = startDayCellHeader.html().split("<br>");
return new Week()
.setStartDayDate(dayDescription[1])
.setDays(days);
}
private Lesson getLessonFromElement(Element e) {
Lesson lesson = new Lesson();
private void addLessonDetails(Lesson lesson, Elements e) {
switch (e.size()) {
case 1:
addLessonInfoFromElement(lesson, e.first());
break;
case 2:
addLessonInfoFromElement(lesson, e.last());
break;
case 3:
addLessonInfoFromElement(lesson, e.get(1));
break;
default:
lesson.setEmpty(true);
break;
}
}
private void addLessonInfoFromElement(Lesson lesson, Element e) {
Elements spans = e.select("span");
lesson.setSubject(spans.get(0).text());
lesson.setTeacher(spans.get(1).text());
lesson.setRoom(spans.get(2).text());
// okienko dla uczniów
if (5 == spans.size()) {
lesson.setTeacher(spans.get(2).text());
lesson.setRoom(spans.get(3).text());
}
addGroupDivisionInfo(lesson, spans);
adTypeInfo(lesson, spans);
addDescriptionInfo(lesson, spans);
return lesson;
addTypeInfo(lesson, spans);
addNormalLessonInfo(lesson, spans);
addChangesInfo(lesson, spans);
addGroupLessonInfo(lesson, spans);
}
private void addGroupDivisionInfo(Lesson lesson, Elements e) {
if ((4 == e.size() && (e.first().attr("class").equals("")) ||
(5 == e.size() && e.first().hasClass(Lesson.CLASS_NEW_MOVED_IN_OR_CHANGED)))) {
lesson.setDivisionIntoGroups(true);
String[] subjectNameArray = lesson.getSubject().split(" ");
String groupName = subjectNameArray[subjectNameArray.length - 1];
lesson.setSubject(lesson.getSubject().replace(" " + groupName, ""));
lesson.setGroupName(StringUtils.substringBetween(groupName, "[", "]"));
lesson.setTeacher(e.get(2).text());
lesson.setRoom(e.get(3).text());
}
}
private void adTypeInfo(Lesson lesson, Elements e) {
if (e.first().hasClass(Lesson.CLASS_MOVED_OR_CANCELED)) {
lesson.setMovedOrCanceled(true);
} else if (e.first().hasClass(Lesson.CLASS_NEW_MOVED_IN_OR_CHANGED)) {
lesson.setNewMovedInOrChanged(true);
} else if (e.first().hasClass(Lesson.CLASS_PLANNING)) {
private void addTypeInfo(Lesson lesson, Elements spans) {
if (spans.first().hasClass(Lesson.CLASS_PLANNING)) {
lesson.setPlanning(true);
}
if (e.last().hasClass(Lesson.CLASS_REALIZED)
|| e.first().attr("class").equals("")) {
if (spans.first().hasClass(Lesson.CLASS_MOVED_OR_CANCELED)) {
lesson.setMovedOrCanceled(true);
}
if (spans.first().hasClass(Lesson.CLASS_NEW_MOVED_IN_OR_CHANGED)) {
lesson.setNewMovedInOrChanged(true);
}
if (spans.last().hasClass(Lesson.CLASS_REALIZED) || "".equals(spans.first().attr("class"))) {
lesson.setRealized(true);
}
}
private void addDescriptionInfo(Lesson lesson, Elements e) {
if ((4 == e.size() || 5 == e.size())
&& (e.first().hasClass(Lesson.CLASS_MOVED_OR_CANCELED)
|| e.first().hasClass(Lesson.CLASS_NEW_MOVED_IN_OR_CHANGED))) {
lesson.setDescription(StringUtils.substringBetween(e.last().text(), "(", ")"));
private void addNormalLessonInfo(Lesson lesson, Elements spans) {
if (3 == spans.size()) {
lesson.setSubject(spans.get(0).text());
lesson.setTeacher(spans.get(1).text());
lesson.setRoom(spans.get(2).text());
}
}
private void addChangesInfo(Lesson lesson, Elements spans) {
if (!spans.last().hasClass(Lesson.CLASS_REALIZED)) {
return;
}
if (7 == spans.size()) {
lesson.setSubject(spans.get(3).text());
lesson.setTeacher(spans.get(4).text());
lesson.setRoom(spans.get(5).text());
lesson.setMovedOrCanceled(false);
lesson.setNewMovedInOrChanged(true);
lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")")
+ " (poprzednio: " + spans.get(0).text() + ")");
} else if (9 == spans.size()) {
String[] subjectAndGroupInfo = getLessonAndGroupInfoFromSpan(spans.get(4));
lesson.setSubject(subjectAndGroupInfo[0]);
lesson.setGroupName(subjectAndGroupInfo[1]);
lesson.setTeacher(spans.get(6).text());
lesson.setRoom(spans.get(7).text());
lesson.setMovedOrCanceled(false);
lesson.setNewMovedInOrChanged(true);
lesson.setDivisionIntoGroups(true);
lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")")
+ " (poprzednio: " + getLessonAndGroupInfoFromSpan(spans.get(0))[0] + ")");
} else if (4 <= spans.size()) {
lesson.setSubject(spans.get(0).text());
lesson.setTeacher(spans.get(1).text());
lesson.setRoom(spans.get(2).text());
lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")"));
}
}
private void addGroupLessonInfo(Lesson lesson, Elements spans) {
if (4 == spans.size() && !spans.last().hasClass(Lesson.CLASS_REALIZED)) {
lesson.setRoom(spans.last().text());
}
if ((4 == spans.size() && !spans.last().hasClass(Lesson.CLASS_REALIZED) || 5 == spans.size())) {
String[] subjectAndGroupInfo = getLessonAndGroupInfoFromSpan(spans.get(0));
lesson.setSubject(subjectAndGroupInfo[0]);
lesson.setGroupName(subjectAndGroupInfo[1]);
lesson.setTeacher(spans.get(2).text());
lesson.setDivisionIntoGroups(true);
}
if (5 == spans.size()) {
lesson.setRoom(spans.get(3).text());
}
}
private String[] getLessonAndGroupInfoFromSpan(Element span) {
String[] subjectNameArray = span.text().split(" ");
String groupName = subjectNameArray[subjectNameArray.length - 1];
return new String[]{
span.text().replace(" " + groupName, ""),
StringUtils.substringBetween(groupName, "[", "]")
};
}
}

View File

@ -32,20 +32,29 @@ public class TimetableTest extends StudentAndParentTestCase {
@Test
public void getStartDayDateTest() throws Exception {
Assert.assertEquals("19.06.2017", std.getWeekTable().getStartDayDate());
Assert.assertEquals("19.06.2017", full.getWeekTable().getStartDayDate());
Assert.assertEquals("31.07.2017", holidays.getWeekTable().getStartDayDate());
Assert.assertEquals("2017-06-19", std.getWeekTable().getStartDayDate());
Assert.assertEquals("2017-06-19", full.getWeekTable().getStartDayDate());
Assert.assertEquals("2017-07-31", holidays.getWeekTable().getStartDayDate());
}
// Day
@Test
public void getDayNameTest() throws Exception {
Assert.assertEquals("poniedziałek", std.getWeekTable().getDay(0).getDayName());
Assert.assertEquals("piątek", std.getWeekTable().getDay(4).getDayName());
Assert.assertEquals("wtorek", full.getWeekTable().getDay(1).getDayName());
Assert.assertEquals("czwartek", full.getWeekTable().getDay(3).getDayName());
Assert.assertEquals("środa", holidays.getWeekTable().getDay(2).getDayName());
}
@Test
public void getDayDateTest() throws Exception {
Assert.assertEquals("19.06.2017", std.getWeekTable().getDay(0).getDate());
Assert.assertEquals("23.06.2017", std.getWeekTable().getDay(4).getDate());
Assert.assertEquals("20.06.2017", full.getWeekTable().getDay(1).getDate());
Assert.assertEquals("22.06.2017", full.getWeekTable().getDay(3).getDate());
Assert.assertEquals("02.08.2017", holidays.getWeekTable().getDay(2).getDate());
Assert.assertEquals("2017-06-19", std.getWeekTable().getDay(0).getDate());
Assert.assertEquals("2017-06-23", std.getWeekTable().getDay(4).getDate());
Assert.assertEquals("2017-06-20", full.getWeekTable().getDay(1).getDate());
Assert.assertEquals("2017-06-22", full.getWeekTable().getDay(3).getDate());
Assert.assertEquals("2017-08-02", holidays.getWeekTable().getDay(2).getDate());
}
@Test
@ -72,12 +81,26 @@ public class TimetableTest extends StudentAndParentTestCase {
// Lesson
@Test
public void getLessonNumberTest() throws Exception {
Assert.assertEquals("2", std.getWeekTable().getDay(0).getLesson(1).getNumber());
Assert.assertEquals("5", std.getWeekTable().getDay(2).getLesson(4).getNumber());
Assert.assertEquals("0", full.getWeekTable().getDay(0).getLesson(0).getNumber());
Assert.assertEquals("13", full.getWeekTable().getDay(4).getLesson(13).getNumber());
Assert.assertEquals("3", holidays.getWeekTable().getDay(3).getLesson(3).getNumber());
}
@Test
public void getLessonSubjectTest() throws Exception {
Assert.assertEquals("Historia", std.getWeekTable().getDay(0).getLesson(1).getSubject());
Assert.assertEquals("Zajęcia techniczne", std.getWeekTable().getDay(2).getLesson(4).getSubject());
Assert.assertEquals("Wychowanie fizyczne", std.getWeekTable().getDay(1).getLesson(1).getSubject());
Assert.assertEquals("Język angielski", full.getWeekTable().getDay(0).getLesson(1).getSubject());
Assert.assertEquals("Wychowanie do życia w rodzinie", full.getWeekTable().getDay(2).getLesson(0).getSubject());
Assert.assertEquals("Wychowanie fizyczne", full.getWeekTable().getDay(3).getLesson(1).getSubject());
Assert.assertEquals("Uroczyste zakończenie roku szkolnego", full.getWeekTable().getDay(4).getLesson(0).getSubject());
Assert.assertEquals("Fizyka", full.getWeekTable().getDay(0).getLesson(0).getSubject());
Assert.assertEquals("Metodologia programowania", full.getWeekTable().getDay(1).getLesson(0).getSubject());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getSubject());
}
@ -87,6 +110,8 @@ public class TimetableTest extends StudentAndParentTestCase {
Assert.assertEquals("Chlebowski Stanisław", std.getWeekTable().getDay(2).getLesson(4).getTeacher());
Assert.assertEquals("Kobczyk Iwona", full.getWeekTable().getDay(0).getLesson(1).getTeacher());
Assert.assertEquals("Bączek Grzegorz", full.getWeekTable().getDay(0).getLesson(7).getTeacher());
Assert.assertEquals("Nowak Jadwiga", full.getWeekTable().getDay(2).getLesson(0).getTeacher());
Assert.assertEquals("Nowicka Irena", full.getWeekTable().getDay(3).getLesson(1).getTeacher());
Assert.assertEquals("Baran Małgorzata", full.getWeekTable().getDay(4).getLesson(0).getTeacher());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getTeacher());
}
@ -95,7 +120,11 @@ public class TimetableTest extends StudentAndParentTestCase {
public void getLessonRoomTest() throws Exception {
Assert.assertEquals("", std.getWeekTable().getDay(3).getLesson(3).getRoom());
Assert.assertEquals("33", full.getWeekTable().getDay(0).getLesson(7).getRoom());
Assert.assertEquals("19", full.getWeekTable().getDay(0).getLesson(0).getRoom());
Assert.assertEquals("32", full.getWeekTable().getDay(1).getLesson(0).getRoom());
Assert.assertEquals("32", full.getWeekTable().getDay(1).getLesson(8).getRoom());
Assert.assertEquals("32", full.getWeekTable().getDay(2).getLesson(8).getRoom());
Assert.assertEquals("G4", full.getWeekTable().getDay(3).getLesson(1).getRoom());
Assert.assertEquals("37", full.getWeekTable().getDay(4).getLesson(0).getRoom());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getRoom());
}
@ -103,9 +132,12 @@ public class TimetableTest extends StudentAndParentTestCase {
@Test
public void getLessonDescriptionTest() throws Exception {
Assert.assertEquals("", std.getWeekTable().getDay(3).getLesson(3).getDescription());
Assert.assertEquals("przeniesiona z lekcji 7, 01.12.2017", full.getWeekTable().getDay(1).getLesson(1).getDescription());
Assert.assertEquals("okienko dla uczniów", full.getWeekTable().getDay(0).getLesson(7).getDescription());
Assert.assertEquals("przeniesiona z lekcji 7, 20.06.2017", full.getWeekTable().getDay(1).getLesson(2).getDescription());
Assert.assertEquals("przeniesiona z lekcji 4, 20.06.2017", full.getWeekTable().getDay(1).getLesson(3).getDescription());
Assert.assertEquals("zastępstwo (poprzednio: Religia)", full.getWeekTable().getDay(2).getLesson(0).getDescription());
Assert.assertEquals("zastępstwo (poprzednio: Wychowanie fizyczne)", full.getWeekTable().getDay(3).getLesson(1).getDescription());
Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(0).getDescription());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getDescription());
}
@ -115,7 +147,9 @@ public class TimetableTest extends StudentAndParentTestCase {
Assert.assertEquals("CH", std.getWeekTable().getDay(0).getLesson(2).getGroupName());
Assert.assertEquals("JNPW", std.getWeekTable().getDay(4).getLesson(0).getGroupName());
Assert.assertEquals("", full.getWeekTable().getDay(0).getLesson(7).getGroupName());
Assert.assertEquals("zaw2", full.getWeekTable().getDay(1).getLesson(0).getGroupName());
Assert.assertEquals("wf2", full.getWeekTable().getDay(1).getLesson(3).getGroupName());
Assert.assertEquals("zaw1", full.getWeekTable().getDay(3).getLesson(1).getGroupName());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getGroupName());
}
@ -141,6 +175,7 @@ public class TimetableTest extends StudentAndParentTestCase {
public void getLessonIsEmptyTest() throws Exception {
Assert.assertFalse(std.getWeekTable().getDay(1).getLesson(4).isEmpty());
Assert.assertTrue(std.getWeekTable().getDay(3).getLesson(7).isEmpty());
Assert.assertFalse(full.getWeekTable().getDay(1).getLesson(1).isEmpty());
Assert.assertFalse(full.getWeekTable().getDay(1).getLesson(2).isEmpty());
Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(7).isEmpty());
Assert.assertTrue(full.getWeekTable().getDay(2).getLesson(9).isEmpty());
@ -154,6 +189,7 @@ public class TimetableTest extends StudentAndParentTestCase {
Assert.assertTrue(std.getWeekTable().getDay(4).getLesson(0).isDivisionIntoGroups());
Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(7).isDivisionIntoGroups());
Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(3).isDivisionIntoGroups());
Assert.assertTrue(full.getWeekTable().getDay(3).getLesson(1).isDivisionIntoGroups());
Assert.assertFalse(holidays.getWeekTable().getDay(3).getLesson(3).isDivisionIntoGroups());
}
@ -161,7 +197,7 @@ public class TimetableTest extends StudentAndParentTestCase {
public void getLessonIsPlanningTest() throws Exception {
Assert.assertFalse(std.getWeekTable().getDay(4).getLesson(4).isPlanning());
Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(1).isPlanning());
Assert.assertFalse(full.getWeekTable().getDay(1).getLesson(3).isPlanning());
Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(3).isPlanning());
Assert.assertTrue(full.getWeekTable().getDay(4).getLesson(0).isPlanning());
Assert.assertFalse(holidays.getWeekTable().getDay(3).getLesson(3).isPlanning());
}
@ -190,6 +226,7 @@ public class TimetableTest extends StudentAndParentTestCase {
Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(1).isNewMovedInOrChanged());
Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(2).isNewMovedInOrChanged());
Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(3).isNewMovedInOrChanged());
Assert.assertTrue(full.getWeekTable().getDay(3).getLesson(1).isNewMovedInOrChanged());
Assert.assertFalse(holidays.getWeekTable().getDay(3).getLesson(3).isNewMovedInOrChanged());
}
}

View File

@ -24,9 +24,34 @@
<tr>
<td>0</td>
<td>07:10 07:55</td>
<td></td>
<td></td>
<td></td>
<td>
<div>
<span class="x-treelabel-ppl x-treelabel-inv">Fizyka [zaw2]</span>
<span class="x-treelabel-ppl x-treelabel-inv"></span>
<span class="x-treelabel-ppl x-treelabel-inv">Bączek Grzegorz</span>
<span class="x-treelabel-ppl x-treelabel-inv">19</span>
<span class="x-treelabel-rlz">(uczniowie zwolnieni do domu)</span>
</div>
</td>
<td>
<div>
<span class="x-treelabel-ppl">Metodologia programowania [zaw2]</span>
<span class="x-treelabel-ppl"></span>
<span class="x-treelabel-ppl"></span>
<span class="x-treelabel-ppl">32</span>
</div>
</td>
<td>
<div>
<span class="x-treelabel-inv">Religia</span>
<span class="x-treelabel-inv">Cyranka Krystian</span>
<span class="x-treelabel-inv">3</span>
<span class="x-treelabel-ppl x-treelabel-zas">Wychowanie do życia w rodzinie</span>
<span class="x-treelabel-ppl x-treelabel-zas">Nowak Jadwiga</span>
<span class="x-treelabel-ppl x-treelabel-zas">3</span>
<span class="x-treelabel-rlz">(zastępstwo)</span>
</div>
</td>
<td></td>
<td>
<div>
@ -47,7 +72,22 @@
<span></span>
</div>
</td>
<td></td>
<td>
<div>
<span class="x-treelabel-ppl x-treelabel-inv">Metodologia programowania [zaw2]</span>
<span class="x-treelabel-ppl x-treelabel-inv"></span>
<span class="x-treelabel-ppl x-treelabel-inv">Baran Małgorzata</span>
<span class="x-treelabel-ppl x-treelabel-inv">36</span>
<span class="x-treelabel-rlz">(zmiana organizacji zajęć)</span>
</div>
<div>
<span class="x-treelabel-ppl x-treelabel-zas">Wychowanie fizyczne [zaw2]</span>
<span class="x-treelabel-ppl x-treelabel-zas"></span>
<span class="x-treelabel-ppl x-treelabel-zas"></span>
<span class="x-treelabel-ppl x-treelabel-zas">G3</span>
<span class="x-treelabel-rlz">(przeniesiona z lekcji 7, 01.12.2017)</span>
</div>
</td>
<td>
<div>
<span>Użytkowanie urządzeń peryferyjnych komputera [zaw2]</span>
@ -56,7 +96,19 @@
<span></span>
</div>
</td>
<td></td>
<td>
<div>
<span class="x-treelabel-inv">Wychowanie fizyczne [zaw1]</span>
<span class="x-treelabel-inv"></span>
<span class="x-treelabel-inv">Jarocki Krzysztof</span>
<span class="x-treelabel-inv">G4</span>
<span class="x-treelabel-ppl x-treelabel-zas">Wychowanie fizyczne [zaw1]</span>
<span class="x-treelabel-ppl x-treelabel-zas"></span>
<span class="x-treelabel-ppl x-treelabel-zas">Nowicka Irena</span>
<span class="x-treelabel-ppl x-treelabel-zas">G4</span>
<span class="x-treelabel-rlz">(zastępstwo)</span>
</div>
</td>
<td></td>
</tr>
<tr>