joeni

Add buses link to adm-index

Author
Maarten Vangeneugden
Date
Aug. 24, 2018, 12:22 a.m.
Hash
75a3cedc225b0d39f080c4fa7dca9051b974788a
Parent
30d7e2a1ac283b2789d938f219e1ff66905fcdb9
Modified files
administration/templates/administration/buses.djhtml
administration/urls.py
administration/views.py
docs/thesis/aandachtspunten.org
docs/thesis/client-side-scripting.org
docs/thesis/toekomst.org

administration/templates/administration/buses.djhtml

2 additions and 1 deletion.

View changes Hide changes
1
1
{% load i18n %}
2
2
{% load humanize %}
3
3
{% load joeni_org %}
4
4
5
5
{% block title %}
6
6
    {% trans "Buses" %} | {{ block.super }}
7
7
{% endblock %}
8
8
9
9
{% block main %}
10
10
    <h1>{% trans "Bus departures" %}</h1>
11
11
    <h2 id="diepenbeek">Campus Diepenbeek</h2>
12
12
    <div class="flex-container">
13
13
    {% for bus in departures_diepenbeek %}
14
14
    <div class="flex-items timetable" style="border-color: {{ bus.color }};">
15
15
        <span class="number" style="background-color: {{ bus.color }};">
16
16
            {{ bus.number }}</span>
17
17
        {{ bus.time|time }}
18
18
        <span style="color: {{ bus.color }}; font-weight:bold;">🡺</span>
19
19
        {{ bus.destination }}
20
20
        <div class="timetable-under">
21
21
        <time>{{ bus.time|naturaltime|capfirst }}</time>
22
22
        {% if bus.via %}
23
23
            <span class="undernote">| Gaat via {{ bus.via }}</span>
24
-
        {% endif %}
+
24
            <span class="undernote"> Gaat via {{ bus.via }}</span>
+
25
        {% endif %}
25
26
        </div>
26
27
    </div>
27
28
    {% empty %}
28
29
    {% trans "There are currently no buses that stop here." %}
29
30
    {% endfor %}
30
31
    </div>
31
32
32
33
    <h2 id="hasselt">Campus Hasselt (Dusartplein)</h2>
33
34
    <div class="flex-container">
34
35
    {% for bus in departures_dusart %}
35
36
    <div class="flex-items timetable" style="border-color: {{ bus.color }};">
36
37
        <span class="number" style="background-color: {{ bus.color }};">
37
38
            {{ bus.number }}</span>
38
39
        {{ bus.time|time }}
39
40
        <span style="color: {{ bus.color }}; font-weight:bold;">🡺</span>
40
41
        {{ bus.destination }}
41
42
        <div class="timetable-under">
42
43
        <time>{{ bus.time|naturaltime|capfirst }}</time>
43
44
        {% if bus.via %}
44
45
            <span style="color: {{ bus.color }}; font-weight:bold;">|</span>
45
46
            <span class="undernote"> Gaat via {{ bus.via }}</span>
46
47
        {% endif %}
47
48
        </div>
48
49
    </div>
49
50
    {% empty %}
50
51
    {% trans "There are currently no buses that stop here." %}
51
52
    {% endfor %}
52
53
    </div>
53
54
54
55
55
56
{% endblock main %}
56
57

administration/urls.py

0 additions and 4 deletions.

View changes Hide changes
1
1
from django.contrib.auth import views as auth_views
2
2
from . import views
3
3
from django.utils.translation import gettext_lazy as _
4
4
5
5
urlpatterns = ([
6
6
    path('', views.index, name='administration-index'),
7
7
    path(_('pre-registration'), views.pre_registration, name='administration-pre-registration'),  # HOLD
8
8
    path(_('settings'), views.settings, name='administration-settings'),
9
9
    path(_('curriculum'), views.curriculum, name='administration-curriculum'),  # TODO
10
10
    # Commented because they might very well be merged with curriculum
11
-
    #path(_('results'), views.results, name='administration-results'),
12
-
    #path(_('results/<slug:course>'), views.result, name='administration-results'),
13
-
    #path(_('results/<int:student_id>'), views.result, name='administration-results'),
14
-
    path(_('forms'), views.forms, name='administration-forms'),  # In Dutch: "Attesten"  # HOLD
15
11
    path(_('forms/<str:form>'), views.forms, name='administration-forms'),  # HOLD
16
12
    path(_('rooms'), views.rooms, name='administration-rooms'),  # TODO
17
13
    path(_('rooms/<str:room>'), views.room_detail, name='administration-room-detail'),  # TODO
18
14
    #path(_('rooms/reservate'), views.room_reservate, name='administration-room-reservate'),
19
15
    path(_('roster'), views.roster, name='administration-roster'),  # TODO
20
16
    re_path(_('roster/(?P<begin>[0-9]{2}-[0-9]{2}-[0-9]{4})/(?P<end>[0-9]{2}-[0-9]{2}-[0-9]{4})'), views.roster, name='administration-roster'),  # TODO
21
17
    path(_('jobs'), views.jobs, name='administration-jobs'),  # HOLD
22
18
    path(_('bulletin-board'), views.bulletin_board, name='administration-bulletin-board'),  # TODO
23
19
    path(_('user/<slug:slug_name>'), views.user, name='administration-user'),  # TODO
24
20
    path(_('buses'), views.buses, name='administration-buses'),
25
21
    path(_('roster/<slug:user_slug>.ics'), views.roster_ics, name='administration-roster-ics'),  # TODO
26
22
27
23
    path('login', views.login, name='administration-login'),  # FIXME
28
24
    ])
29
25

administration/views.py

4 additions and 0 deletions.

View changes Hide changes
1
1
from . import bus
2
2
from collections import OrderedDict
3
3
from django.http import HttpResponseRedirect
4
4
import datetime
5
5
from django.urls import reverse # Why?
6
6
from django.utils.translation import gettext as _
7
7
from .models import *
8
8
from .forms import UserDataForm
9
9
from .new_roster import create_roster_rows
10
10
import administration
11
11
from django.contrib.auth.decorators import login_required
12
12
from django.contrib.auth import authenticate
13
13
from django.contrib.auth import login as login_auth
14
14
15
15
@login_required
16
16
def roster(request, begin=None, end=None):
17
17
    """Collects and renders the data that has to be displayed in the roster.
18
18
19
19
    The begin and end date can be specified. Only roster points in that range
20
20
    will be included in the response. If no begin and end are specified, it will
21
21
    take the current week as begin and end point. If it's
22
22
    weekend, it will take next week."""
23
23
24
24
    # TODO Handle given begin and end
25
25
    context = dict()
26
26
    #context = {'money' : update_balance(None)}
27
27
    template = "administration/roster.djhtml"
28
28
29
29
    if begin is None or end is None:
30
30
        today = datetime.date.today()
31
31
        if today.isoweekday() in {6,7}:  # Weekend
32
32
            begin = today + datetime.timedelta(days=8-today.isoweekday())
33
33
            end = today + datetime.timedelta(days=13-today.isoweekday())
34
34
        else:  # Same week
35
35
            begin = today - datetime.timedelta(days=today.weekday())
36
36
            end = today + datetime.timedelta(days=5-today.isoweekday())
37
37
    else:  # Changing regexes to date objects
38
38
        b = begin.split("-")
39
39
        e = end.split("-")
40
40
        begin = datetime.datetime(int(b[2]),int(b[1]),int(b[0]))
41
41
        end = datetime.datetime(int(e[2]),int(e[1]),int(e[0]))
42
42
43
43
    context['begin'] = begin
44
44
    context['end'] = end
45
45
46
46
    context['prev_begin'] = (begin - datetime.timedelta(days=7)).strftime("%d-%m-%Y")
47
47
    context['prev_end'] = (begin - datetime.timedelta(days=2)).strftime("%d-%m-%Y")
48
48
    context['next_begin'] = (end + datetime.timedelta(days=2)).strftime("%d-%m-%Y")
49
49
    context['next_end'] = (end + datetime.timedelta(days=7)).strftime("%d-%m-%Y")
50
50
51
51
    days = [begin]
52
52
    while (end-days[-1]).days != 0:
53
53
        # Human translation: Keep adding days until the last day in the array of
54
54
        # days is the same day as the last day the user wants to see the roster for.
55
55
        days.append(days[-1] + datetime.timedelta(days=1))
56
56
    context['days'] = days
57
57
58
58
    # Collecting events
59
59
    course_events = CourseEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end).order_by("begin_time")
60
60
    #university_events = UniversityEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end)
61
61
    #study_events = StudyEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end)
62
62
    #events = Event.objects.filter(begin_time__gte=begin).filter(end_time__lte=end)
63
63
    conflicts, table_code = create_roster_rows(course_events)
64
64
65
65
    context['time_blocks'] = table_code
66
66
    context['conflicts'] = conflicts
67
67
    #print(time_blocks)
68
68
    return render(request, template, context)
69
69
    # TODO Finish!
70
70
71
71
def roster_ics(request, user_slug):
72
72
    template = "administration/roster.ics"
73
73
    context = dict()
74
74
    context['events'] = CourseEvent.objects.all()  # FIXME: Filter to personal calendar items!
75
75
    return render(request, template, context)
76
76
77
77
def index(request):
78
78
    template = "administration/index.djhtml"
79
79
    #context = {'money': update_balance(None)}
80
80
    context = dict()
81
81
    context['links'] = [
82
82
        ("administration-settings",
83
83
         _("Personal settings"),
84
84
         _("Edit your personal information, billing address, home address, and so on.")),
85
85
        ("administration-curriculum",
86
86
         _("Curricula"),
87
87
         _("View all information related to your curricula, including exam results.<br />"
88
88
           "You can also change your current curriculum here, or request a change.")),
89
89
        ("administration-forms",
+
90
         _("Bus departures"),
+
91
         _("If you're leaving Hasselt University, you can check the bus departures from "
+
92
           "your campus here.")),
+
93
        ("administration-forms",
90
94
         _("Forms"),
91
95
         _("All forms for special services can be found on this page.")),
92
96
        ("administration-rooms",
93
97
         _("Rooms"),
94
98
         _("Room occupancy, free rooms, properties, ... <br />"
95
99
           "All this and much more is available on this page.")),
96
100
        ("administration-roster",
97
101
         _("Personal roster"),
98
102
         _("Everything about your roster and events at Hasselt University is available here.")),
99
103
        ("administration-bulletin-board",
100
104
         _("Bulletin board"),
101
105
         _("From time to time, UHasselt publishes announcements regarding changes, events, ..."
102
106
           "<br />All publications are neatly organized here for easy reference.")),
103
107
        ]
104
108
105
109
    return render(request, template, context)
106
110
107
111
    pass
108
112
109
113
def pre_registration(request):
110
114
    user_data_form = UserDataForm()
111
115
    template = "administration/pre_registration.djhtml"
112
116
    context = dict()
113
117
114
118
    if request.method == 'POST':
115
119
        user_data_form = UserDataForm(request.POST)
116
120
        context['user_data_form'] = user_data_form
117
121
        if user_data_form.is_valid():
118
122
            user_data_form.save()
119
123
            context['messsage'] = _("Your registration has been completed. You will receive an e-mail shortly.")
120
124
        else:
121
125
            context['messsage'] = _("The data you supplied had errors. Please review your submission.")
122
126
    else:
123
127
        context['user_data_form'] = UserDataForm(instance = user_data_form)
124
128
125
129
    return render(request, template, context)
126
130
    pass
127
131
128
132
@login_required
129
133
def settings(request):
130
134
    user_data = UserData.objects.get(user=request.user)
131
135
    user_data_form = UserDataForm(instance = user_data)
132
136
    template = "administration/settings.djhtml"
133
137
    context = dict()
134
138
    #context = {'money' : update_balance(None)}
135
139
136
140
    if request.method == 'POST':
137
141
        user_data_form = UserDataForm(request.POST, instance = user_data)
138
142
        context['user_data_form'] = user_data_form
139
143
        if user_data_form.is_valid():
140
144
            user_data_form.save()
141
145
            context['messsage'] = _("Your settings were successfully updated.")
142
146
        else:
143
147
            context['messsage'] = _("The data you supplied had errors. Please review your submission.")
144
148
    else:
145
149
        context['user_data_form'] = UserDataForm(instance = user_data)
146
150
147
151
    return render(request, template, context)
148
152
149
153
@login_required
150
154
def bulletin_board(request):
151
155
    context = dict()
152
156
    #context = {'money' : update_balance(None)}
153
157
    context['exam_commission_decisions'] = ExamCommissionDecision.objects.filter(user=request.user)
154
158
    context['education_department_messages'] = EducationDepartmentMessages.objects.all()
155
159
    for item in context['education_department_messages']:
156
160
        print(item.text)
157
161
    template = "administration/bulletin_board.djhtml"
158
162
    return render(request, template, context)
159
163
160
164
def jobs(request):
161
165
    context = dict()
162
166
    #context = {'money' : update_balance(None)}
163
167
    template = "administration/jobs.djhtml"
164
168
    #@context['decisions'] = ExamCommissionDecision.objects.filter(user=request.user)
165
169
    return render(request, template, context)
166
170
167
171
168
172
@login_required
169
173
def curriculum(request):
170
174
    context = dict()
171
175
    #context = {'money' : update_balance(None)}
172
176
    template = "administration/curriculum.djhtml"
173
177
    context['curricula'] = Curriculum.objects.filter(student=request.user)
174
178
    for item in context['curricula']:
175
179
        for co in item.course_programmes_results():
176
180
            print(co)
177
181
    return render(request, template, context)
178
182
179
183
def result(request):
180
184
    return render(request, template, context)
181
185
182
186
@login_required
183
187
def results(request):
184
188
    results = CourseResult.objects.filter(student=request.user)
185
189
    template = "administration/results.djhtml"
186
190
    # TODO
187
191
    return render(request, template, context)
188
192
189
193
def forms(request):
190
194
    context = dict()
191
195
    #context = {'money' : update_balance(None)}
192
196
    template = "administration/forms.djhtml"
193
197
    return render(request, template, context)
194
198
195
199
def user(request, slug_name):
196
200
    pass
197
201
198
202
def rooms(request):
199
203
    context = dict()
200
204
    #context = {'money' : update_balance(None)}
201
205
    context['rooms'] = Room.objects.all()
202
206
    context['room_reservations'] = RoomReservation.objects.all()
203
207
    context['course_events'] = CourseEvent.objects.all()
204
208
    context['blocks'] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
205
209
206
210
    # Collecting all rooms that are free for at least one two hours from now
207
211
    now = datetime.datetime.now(datetime.timezone.utc)
208
212
    end = now + datetime.timedelta(hours=2)
209
213
    free_rooms = dict()
210
214
    for room in context['rooms']:
211
215
        if room.reservation_possible(now, end):
212
216
            event = room.next_event(end)
213
217
            reservation = room.next_reservation(end)
214
218
            if event is None and reservation is None:
215
219
                free_rooms[room] = None
216
220
            elif reservation is not None:
217
221
                free_rooms[room] = event.begin_time
218
222
            elif event is not None:
219
223
                free_rooms[room] = reservation.begin_time
220
224
            elif event.begin_time < reservation.begin_time:
221
225
                free_rooms[room] = event.begin_time
222
226
            else:
223
227
                free_rooms[room] = reservation.begin_time
224
228
    context['free_rooms'] = free_rooms
225
229
226
230
    template = "administration/rooms.djhtml"
227
231
    return render(request, template, context)
228
232
229
233
def room_detail(request, room):
230
234
    template = "administration/room_detail.djhtml"
231
235
    context = dict()
232
236
    #context = {'money' : update_balance(None)}
233
237
    room = Room.objects.get(name=room)
234
238
    context['room'] = room
235
239
    context['reservations'] = RoomReservation.objects.filter(room=room).filter(begin_time__gte=datetime.datetime.now())
236
240
    context['course_events'] = CourseEvent.objects.filter(room=room).filter(begin_time__gte=datetime.datetime.now())
237
241
    # Building the room occupancy of today:
238
242
    today = datetime.date.today()
239
243
    if today.isoweekday() in {6,7}:  # Weekend
240
244
        today = today + datetime.timedelta(days=8-today.isoweekday())
241
245
242
246
    context['days'] = [today]
243
247
244
248
    # Collecting events
245
249
    course_events = CourseEvent.objects.filter(room=room).filter(begin_time__date=today)
246
250
    print(course_events)
247
251
    #university_events = UniversityEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end)
248
252
    #study_events = StudyEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end)
249
253
    #events = Event.objects.filter(begin_time__gte=begin).filter(end_time__lte=end)
250
254
251
255
    conflicts, table_code = create_roster_rows(course_events)
252
256
    context['time_blocks'] = table_code
253
257
    context['conflicts'] = conflicts
254
258
    print(context['time_blocks'])
255
259
    return render(request, template, context)
256
260
257
261
def buses(request):
258
262
    context = dict()
259
263
    context["departures_diepenbeek"] = bus.arrivals(["401474","401475"])
260
264
    #for testing: context["departures_diepenbeek"] = bus.arrivals(["205919","205916","205915"])
261
265
    context["departures_dusart"] = bus.arrivals(["403041","403040"])
262
266
    template = 'administration/buses.djhtml'
263
267
    return render(request, template, context)
264
268
265
269
266
270
267
271
268
272
def login(request):
269
273
    context = dict()
270
274
    #context = {'money' : update_balance(None)}
271
275
    if request.method == "POST":
272
276
        name = request.POST['name']
273
277
        passphrase = request.POST['pass']
274
278
        user = authenticate(username=name, password=passphrase)
275
279
        if user is not None: # The user was successfully authenticated
276
280
            print("YA")
277
281
            login_auth(request, user)
278
282
            return HttpResponseRedirect(request.POST['next'])
279
283
        else: # User credentials were wrong
280
284
            context['next'] = request.POST['next']
281
285
            context['message'] = _("The given credentials were not correct.")
282
286
    else:
283
287
        context['next'] = request.GET.get('next', None)
284
288
        if context['next'] is None:
285
289
            context['next'] = reverse('administration-index')
286
290
287
291
    template = 'administration/login.djhtml'
288
292
289
293
    return render(request, template, context)
290
294

docs/thesis/aandachtspunten.org

15 additions and 20 deletions.

View changes Hide changes
1
-
Fundamenteel is deze bachelorproef nog altijd een werk dat moet bijdragen aan
2
-
het ALIPA-project van de UHasselt.\\
3
-
Voor het stroomlijnen van de ICT-infrastructuur is het ook nodig om kleine
4
-
problemen en mankementen op te lossen als ze gevonden worden. Een afgewerkt
5
-
geheel voedt het gevoel dat alles goed en orderlijk samenwerkt met elkaar, een
6
-
belangrijke doelstelling om vertrouwen te creëren in de gebruikers.
7
-
+
1
 Fundamenteel is deze bachelorproef nog altijd een werk dat moet bijdragen aan
+
2
 het ALIPA-project van de UHasselt.\\
+
3
 Voor het stroomlijnen van de ICT-infrastructuur is het ook nodig om kleine
+
4
 problemen en mankementen op te lossen als ze gevonden worden. Een afgewerkt
+
5
 geheel voedt het gevoel dat alles goed en orderlijk samenwerkt met elkaar, een
+
6
 belangrijke doelstelling om vertrouwen te creëren in de gebruikers.
+
7
8
8
Tijdens het maken van dit proefwerk ben ik op enkele kleine punten gestoten die
9
-
niet direct van invloed waren op mijn proef, maar die ik hier toch wens te
10
-
vermelden. Het gaat dan om kleine slordigheden, schoonheidsfoutjes, verouderde
11
-
informatie, ...
12
-
+
9
 niet direct van invloed waren op mijn proef, maar die ik hier toch wens te
+
10
 vermelden. Het gaat dan om kleine slordigheden, schoonheidsfoutjes, verouderde
+
11
 informatie, ...
+
12
13
13
Alle benodigde informatie, alsook een redenering wordt per punt uitgeschreven.
14
-
+
14
15
15
** Verouderde informatie
16
-
*** Campushopper afgeschaft
17
16
Op de pagina https://www.uhasselt.be/Contact-en-ligging onder de rubriek "Campus
18
17
 Hasselt/Gevangenis" wordt verteld dat men de
19
18
Campushopper kan nemen, maar deze werd al in 2017 afgeschaft. Beter is om Boulevardpendel
20
19
te nemen, of elke bus die het Dusartplein aandoet.[fn::Dit zijn de volgende
21
20
 lijnen: 1, 3, 5, 11, 13, 16, 18a, 20a, 22, 23, 35, 36, 45, 46, 48, 51, 52, 180,
22
21
 182, AL, BP, H13, H14, H41, H51. (https://www.delijn.be/nl/haltes/halte/403040/Hasselt_Dusartplein)]
23
22
24
23
** Onnodige informatie
25
-
*** Spartacusplan
26
24
Op https://www.uhasselt.be/Contact-en-ligging staat een link naar een
27
25
PDF-bestand omtrent het Spartacusplan. Dit heeft inderdaad te maken met het
28
26
openbaar vervoer, maar voegt weinig toe aan het eigenlijke doel van deze pagina:
29
27
Bezoekers informeren over hoe ze de UHasselt kunnen bereiken.\\
30
28
Ik stel voor om de vermelding hierover de verwijderen.
31
29
32
30
*** Wachtwoorden plaintext
33
31
*Op het Studentendossier is het eerste wachtwoord dat studenten toegewezen
34
32
krijgen /plain text/ in te kijken.* Dit gaat via de link "Initieel paswoord".
35
33
Het spreekt voor zich dat de implicaties voor veiligheid dicteren dat
36
34
*het onversleuteld opslaan van wachtwoorden per direct moet stoppen.*
37
35
** Slecht te vinden informatie
38
-
*** Plattegronden
39
36
Er is weinig te vinden van plattegronden op de website; waar zijn welke lokalen
40
37
 te vinden, plattegronden van de 1ste verdieping, ...
41
38
42
39
Het kan ook zijn dat dit niet per sé nodig is; indien op de campus zelf adequate
43
40
 wegbewijzering wordt aangebracht, wordt een plattegrond minder belangrijk.
44
41
 Waar vind ik alle plattegronden van de campussen? Het zijn er maar 2...
45
42
 Ik heb er eentje gevonden van de campus Diepenbeek op https://www.uhasselt.be/Contact-en-ligging:
46
43
 https://www.uhasselt.be/images/UHasselt/maps/2015/campus-diepenbeek/campus-diepenbeek-gebouwDE.jpg
47
44
 Maar dat is ook enkel gelijkvloers, en niet up-to-date met nieuwe aanbouw.
48
45
49
46
** Mogelijke versimpelingen
50
-
*** Speciale logo's voor Apple
51
47
In de broncode van de websites binnen de UHasselt zijn in de header links te
52
48
vinden naar speciale logo's voor Apple-browsers.\\
53
49
Binnen Joeni worden er geen 
54
-
** Verbeteringspunten
55
-
*** Video's op YouTube
+
50
browser. Ze voegen sowieso niet veel toe aan de eigenlijke werking van de
+
51
website, en maken het geheel weer een beetje complexer.
+
52
*** Video's op YouTube
56
53
Op https://www.uhasselt.be/Videos zijn er veel filmpjes te vinden over het
57
54
reilen en zeilen in de universiteit. Maar eigenlijk zijn het links naar het
58
55
videoplatform YouTube, onderdeel van Google Inc. Eerder werd in deze thesis
59
56
[[Google-privacy][de integratie met diensten van Google] op de korrel genomen.\\
60
57
Dit is makkelijk op te lossen door de video's simpelweg via de eigen website aan
61
58
te bieden, middels het [[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Video][~
62
59
**** Licensiëring video's
63
60
De aangegeven licentie van de video's is de "Standaard YouTube-licentie", deze
64
61
licentie voldoet niet aan de vereisten voor een "Vrij cultureel werk".
65
62
66
63
De aard van deze video's is duidelijk: Ze dienen om toekomstige studenten te
67
64
informeren over de UHasselt en al haar richtingen, een blik te werpen op
68
65
studentenfaciliteiten (zoals verenigingen), en ook als een advertentie om voor
69
66
UHasselt te kiezen.\\
70
67
De doelstelling bereiken wordt met deze licentiekeuze actief tegengewerkt;
71
68
mensen mogen deze video's niet delen, of aanpassen voor nieuwe werken. Er zijn
72
69
ook voorwaarden op het privégebruik ervan.\\
73
70
Creatieve werken met deze doelstellingen dienen zo vrij mogelijk uitgegeven te
74
71
worden om de zichtbaarheid en verspreidingskansen ervan te maximaliseren. Door de huidige wetgeving
75
72
omtrent kopieerrechten is dit niet automatisch mogelijk, maar er bestaan wel
76
73
licenties die hiervoor een zeer toereikend soelaas bieden.
77
74
78
75
Ik raad aan om de licenties op de video's te vervangen met de
79
76
[[https://creativecommons.org/licenses/by/4.0/deed.nl][CC-BY 4.0]]-licentie, die deze problemen direct oplost. Dit kan ook gedaan worden als beslist
80
77
wordt de video's op YouTube te laten staan.
81
78
82
79
*** Google & privacy
83
-
84
-

docs/thesis/client-side-scripting.org

1 addition and 1 deletion.

View changes Hide changes
1
1
 Ingewijden zijn bekend met het feit dat JavaScript een Turing-complete
2
2
 programmeertaal is; je kunt er dus daadwerkelijk programma's mee schrijven.
3
3
 Een prominent voorbeeld hiervan is Google met haar Google Docs, Sheets,
4
4
 Presentations, GMail, ...
5
5
6
6
 Het valt dan natuurlijk op dat binnen Joeni *geen enkele lijn JavaScript
7
7
 geschreven is*. En dat is ook expres gedaan.
8
8
 Dat klinkt misschien nogal contra-intuïtief; een volledig programma, dat
9
9
 hoofdzakelijk gebruikt zal worden via de browser, dat client-side scripting
10
10
 expres aan zijn neus voorbij laat gaan.
11
11
12
12
 Hier zijn meerdere redenen voor. Eén van de voornaamste redenen (en eentje die
13
13
 Google, Facebook, ... allemaal klaarblijkelijk vergeten zijn) is dat een
14
14
 grondregel van /web development/ is dat je er niet van mag uitgaan dat de
15
15
 gebruiker JavaScript ondersteunt.
16
16
17
17
 *Client-side scripting (Css* (niet te verwarren met Cascading Style Sheets, CSS))
18
18
 *mag enkel een strikt cosmetisch effect hebben op
19
19
 een website.* De functionaliteit gaat namelijk compleet verloren als de
20
20
 gebruiker geen ondersteuning biedt.
21
21
22
22
 Alhoewel het in de praktijk steeds neerkomt op "JavaScript (JS) dient vermeden te
23
23
 worden op het web", ga ik enkel spreken over "Client side scripting" (Css),
24
24
 omdat veel van de problemen die zich met JS zouden voordoen, zich eveneens
25
25
 zouden voordoen bij eender welke andere taal (Python, Clojure, ...),
26
26
 als die voor Css gebruikt zou worden. JS is sinds [[http://es6-features.org/][ES6]] een betere taal geworden,
27
27
 maar de "kwaliteit" van een taal is volledig irrelevant in deze discussie. Het
28
28
 bespreken van de faciliteiten die JS als programmeertaal biedt wordt in dit
29
29
 hoofdstuk dus achterwege gelaten.
30
30
31
31
 Er wordt hier ook enkel gefocust op het gebruik van Css om bepaalde
32
32
 functionaliteit te laten werken. Css die enkel een cosmetisch effect heeft is
33
33
 niet het onderwerp van dit stuk, maar wordt eveneens vermeden om aan te tonen
34
34
 dat een bruikbare web-applicatie ook mooi kan zijn met enkel HTML en CSS.
35
35
36
36
*** Verschillende versies
37
37
 Alles wat netwerkgerelateerd is, moet zich houden aan vooraf opgelegde
38
38
 standaarden om correct te kunnen communiceren, en met het WWW is dat niet
39
39
 anders.
40
40
41
41
 Dit geeft ook een reden om geen Css te gebruiken; op dit moment moet ik
42
42
 rekening houden met
43
43
44
44
 - De standaard van HTML(5) en welke tags ondersteund worden
45
45
 - De standaard van CSS(3) en de ondersteunde /properties/ binnen browsers
46
46
47
47
 Dit op zich is al een hele klus, en vereist *continu onderhoud van de software*.
48
48
49
49
 Stel dat men geen website ontwerpt, en /native software/ ontwikkelt, dan hoeft
50
50
 men enkel rekening te houden met de syntax van de programmeertaal; als het
51
51
 compileert kan het bij wijze van spreken gebruikt worden.[fn::In de praktijk is het niet zo voor de hand liggend, maar om het punt te maken volstaat dit.]
52
52
53
53
 Met Css moet men rekening houden met welke onderdelen van de gebruikte
54
54
 programmeertaal door de browsers wordt ondersteund, en dat is van vitaal belang,
55
55
 want als het script niet ondersteund wordt, wordt het simpelweg niet uitgevoerd,
56
56
 met als gevolg dat de website aan functionaliteit moet inboeten.
57
57
58
58
 Als dit bij HTML of CSS gebeurt (bv. gebruik van [[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/marquee][]]), dan kan de browser
59
59
 nog terugvallen op een standaardwaarde. Dit is ook mogelijk, omdat geen van
60
-
 beide een programmeertaal is; men kán onderdelen vervangen zonder een al te
+
60
 beide een programmeertaal is; men kán onderdelen vervangen zonder een al te
61
61
 groot risico te lopen om de site kapot te maken.
62
62
63
63
 Een goed voorbeeld hiervan is het ~~-element, dat wordt gebruikt om een
64
64
 telefoonnummer aan te duiden op een webpagina. Op mobiele browsers wordt een
65
65
 klik hierop behandeld als een telefoongesprek. Op (oudere) desktopbrowsers wordt
66
66
 dit als gewone tekst weergegeven.
67
67
68
68
*** Turing-compleetheid
69
69
 De aantrekkingskracht van Css schuilt in de [[https://nl.wikipedia.org/wiki/Turingvolledigheid][Turing-compleetheid]]. Dit maakt het tot een
70
70
 programmeertaal waarin elk mogelijk computerprogramma geprogrammeerd kan worden.
71
71
72
72
 De grote máár in deze kracht, is dat dat ook een hoop verantwoordelijkheid met
73
73
 zich meebrengt. Er kunnen fouten in de code sluipen, die de hele website kunnen
74
74
 doen vastlopen.
75
75
76
76
 JavaScript heeft dan ook nog de ongelukkige eigenschap dat het een enorm
77
77
 [[https://en.wikipedia.org/wiki/Strong_and_weak_typing][zwak getypeerde programmeertaal]] is; de taal doet in de achtergrond stille
78
78
 conversies tussen verschillende types, en geeft liever foute resultaten terug
79
79
 dan de programmeur te vertellen dat er een fout in de code zit.
80
80
81
81
 Deze punten gelden natuurlijk ook voor de /server-side/, maar dit is (in
82
82
 tegenstelling tot Css) absoluut onvermijdelijk om een dergelijke website te
83
83
 creëren.
84
84
 Daarnaast zijn er ook een hoop voordelen die men niet heeft bij Css:
85
85
86
86
 - Vrije keuze van programmeertaal (en mogelijkheid om te linken met andere
87
87
   software)
88
88
 - Zekerheid dat, als de software werkt op de ene /client/, die ook voor de
89
89
   andere /client/ werkt (zie [[Verschillende versies][Verschillende versies]]).
90
90
91
91
 HTML en CSS zijn geen "volwaardige programmeertalen". HTML is een opmaaktaal,
92
92
 men beschrijft er dus mee hoe bepaalde onderdelen van de website moeten worden
93
93
 voorgesteld; als een hyperlink, een paragraaf, ...
94
94
 CSS laat toe om de stijl van deze opmaak te definiëren, hoe moet een hyperlink
95
95
 uitzien, ...
96
96
97
97
 Een fout hierin heeft hoogstens een esthetisch vervelend effect tot gevolg; veel
98
98
 browsers negeren fouten, en vervangen deze door /fallbacks/. Dit is niet
99
99
 mogelijk met een programmeertaal; een fout is een fout, en computers zijn niet
100
100
 in staat om een fout programma zelf te repareren.
101
101
102
102
*** Onbeschikbaarheid
103
103
 Er zijn talloze manieren waarop de aangereikte code niet beschikbaar kan zijn
104
104
 voor de gebruiker, waardoor een website die afhangt van Css plots zonder
105
105
 waarschuwing niet meer werkzaam is. Een wilde greep uit de mogelijkheden:
106
106
107
107
 - De gebruiker heeft een zwakke computer
108
108
 - De computer heeft een slechte verbinding
109
109
 - De gebruiker surft via de GSM (een zwakke computer met een slechte verbinding)
110
110
 - De gebruiker heeft [[https://noscript.net][NoScript]], [[https://www.gnu.org/software/librejs/][GNU LibreJS,]] of een andere extensie die Css blokkeert
111
111
 - De verbinding wordt onderbroken tijdens het inladen, en de pagina blokkeert
112
112
   terwijl het tevergeefs wacht op de rest van het script
113
113
 - De browser van de gebruiker ondersteunt simpelweg geen Css
114
114
 - De browser van de gebruiker ondersteunt niet de Css-implementatie die op de
115
115
   website gebruikt wordt (zie [[Verschillende versies]])
116
116
 - De website laadt Css in van een externe website, maar er is een fout in het
117
117
   certificaat, en de browser weigert om de verbinding op te zetten
118
118
 - ...
119
119
120
120
 Er hoeft maar één (en slechts één) van deze mogelijkheden op te treden, en *de
121
121
 volledige website is per direct compleet onbruikbaar*.
122
122
123
123
 Voor elk van deze mogelijkheden zou met Css een controle moeten worden
124
124
 ingebouwd, en dan weer voor elke mogelijkheid een oplossing bedacht (want "Het
125
125
 werkt niet en dat is de schuld van de gebruiker" is geen oplossing).
126
126
127
127
 Daarentegen, wat als er server-side een fout optreedt? \\
128
128
 Veel webframeworks hebben ingebouwde /debugging tools/ die bij fouten direct de
129
129
 programmeur wijzen op de fout. Django is hier een goed voorbeeld van.
130
130
131
131
 Daarnaast biedt de betere webserver ook ingebouwde oplossingen om vaak
132
132
 voorkomende fouten af te handelen (zoals een HTTP 404). In dat geval kan er
133
133
 gemakkelijk een e-mail naar de ontwikkelaar gestuurd worden, of kan een log
134
134
 aangemaakt worden. En dit is vaak allemaal /ingebouwd/.
135
135
136
136
*** Uitgesteld resultaat
137
137
 Bestanden over het WWW worden quasi altijd verzonden via [[https://nl.wikipedia.org/wiki/Hypertext_Transfer_Protocol][HTTP]]([[https://nl.wikipedia.org/wiki/HyperText_Transfer_Protocol_Secure][S]]), en de browser
138
138
 is daarna verantwoordelijk voor het in elkaar steken van alle ontvangen
139
139
 onderdelen.
140
140
141
141
 Het handige hieraan, is dat elke browser zelf kan bepalen hoe, en in welke volgorde dit
142
142
 moet gebeuren, al dan niet in functie van bepaalde instellingen die de gebruiker
143
143
 zelf kan aanpassen (bv. geen afbeeldingen laden via 4G).
144
144
145
145
 Css interfereert op haast elk mogelijk niveau met deze werkwijze. Net omdat het
146
146
 niet op voorhand geweten is wat er zal worden aangepast, of wanneer de code
147
147
 ingeladen moet worden, is een browser verplicht om vanaf het eerste moment dat
148
148
 een script gedetecteerd wordt (bv. via de ~~-tags), direct de
149
149
 code te evalueren en uit te voeren, ongeacht hoe lang het duurt of hoe zwaar het is.
150
150
151
151
 Css breekt ook met het gebruikelijke mantra dat de browser/gebruiker bepaalt hoe
152
152
 en wat wordt ingeladen.
153
153
 Vaak betekent dit ook dat de code geëvalueerd moet worden, op dat exacte moment,
154
154
 vooraleer de rest van de pagina getoond kan worden. \\
155
155
 Dit is minder een probleem als Css gebruikt wordt voor het enige waarvoor het
156
156
 zou gebruikt moeten worden (cosmetische elementen), omdat praktisch alle code dan expres
157
157
 op het einde van het HTML-document kan worden ingeladen. De website is dan al
158
158
 bruikbaar vooraleer de code ingeladen moet worden. \\
159
159
 Een groeiend aantal gebruikers blokkeert ook expres Css tijdens het surfen op
160
160
 het web, omdat de snelheidswinsten en sterk verhoogde privacy een waardige
161
161
 afweging is voor een ietwat minder cosmetisch aangeklede website. Met andere
162
162
 woorden; zij stellen het resultaat uit voor onbepaalde duur.
163
163
164
164
 Dit geeft vanzelfsprekend ook problemen als de code niet geoptimaliseerd is, en
165
165
 daar elke browser de aangereikte Css op een andere manier kan evalueren, is het
166
166
 onbegonnen werk om voor alle mogelijke implementaties handige optimalisaties
167
167
 door te voeren. Men beperkt zich natuurlijk meestal tot de populairste
168
168
 implementaties ([[https://en.wikipedia.org/wiki/WebKit][WebKit]] en [[https://en.wikipedia.org/wiki/Gecko_(software)][Gecko]]).
169
169
170
170
 _Maar je hoeft vanzelfsprekend niet te optimaliseren, als er geen code is om te optimaliseren._
171
171
172
172
 Je zou kunnen zeggen dat deze redenering ook opgaat voor Joeni zelf, wat van
173
173
 Python gebruik maakt. Maar het gebruikte framework ondersteunt het
174
174
 [[https://docs.djangoproject.com/en/2.0/topics/cache/][cachen van pagina's]]. Dus eerder geëvalueerde code zal al op voorhand beschikbaar
175
175
 zijn. Daarbij komt dat de snelheid van een server naar wens kan worden vergroot,
176
176
 terwijl je bij de gebruiker er van moet uitgaan dat zijn/haar toestel traag is.
177
177
 De code van de server hoeft ook slechts voor één platform geoptimaliseerd te
178
178
 worden, dat van de server.
179
179
180
180
 Uiteindelijk is het resultaat van (foutief) Css-gebruik 
181
181
 sowieso: *Een traag werkende website.*
182
182
183
183
*** Verlies van betekenis
184
184
 Een bepaalde /tag/ in HTML draagt een bepaalde betekenis. ~~ betekent dat dit
185
185
 een hyperlink is, ~~ betekent dat wat volgt getoond moet worden als de
186
186
 'inhoud' van de pagina, ~

~ duidt op een paragraaf, ...

187
187
188
188
 Deze betekenis wordt vaak door de browser ten volle benut; Alle links kunnen makkelijk
189
189
 op voorhand verzameld worden (i.e. Alles wat tussen ~~ staat), wat tussen
190
190
 ~~ staat wordt niet getoond, ...
191
191
192
192
 *Betekenis opent deuren voor het impliciet infereren van informatie.* Dit is de
193
193
 reden waarom de tags in HTML (en vooral sinds HTML5) een aanduiding zijn voor
194
194
 wat de ingesloten data /betekent/; ~
~ is een artikel en kan dus los
195
195
 weergegeven worden van de rest van de pagina, ~~ is iets dat niet
196
196
 meer relevant is, maar waarschijnlijk toch wel weergegeven moet worden. ~
    ~
197
197
 is een geordende lijst, dus de volgorde van de data is van belang, in
198
198
 tegenstelling tot ~
    ~. Er zijn ontelbare voorbeelden te vinden.
199
199
200
200
 Deze betekenis gaat volledig verloren als onderdelen van de website met Css
201
201
 worden "nagemaakt". ~
~ zal waarschijnlijk wel
202
202
 doorlinken naar een website, maar waar dat je in bv. FireFox met een
203
203
 middelmuisklik een ~~ in een nieuw tabblad kunt openen, zal dit niet werken
204
204
 met Css.
205
205
206
206
*** Conclusie
207
207
 Het moge duidelijk zijn dat het gebruik van Css om zogenaamde /web apps/ te
208
208
 maken, fundamenteel een slecht idee is, dat meer problemen voortbrengt dan het
209
209
 oplost. Alle problemen die sommige websites proberen op te lossen met Css, zijn
210
210
 makkelijker op te lossen met slechts HTML en CSS (Cascading Style Sheets), en
211
211
 Client side scripting maakt soms de problemen zelfs erger.
212
212
213
213
 En zelfs al zouden alle bovenstaande punten onwaar zijn, dan nog is Joeni
214
214
 het bewijs dat Css geen vereiste is om werkende software te schrijven, die
215
215
 hoofdzakelijk via het WWW beschikbaar wordt gesteld.

docs/thesis/toekomst.org

5 additions and 1 deletion.

View changes Hide changes
1
1
 Joeni is op dit moment een voorbeeld van een kant-en-klare oplossing voor de problemen die
2
2
 BlackBoard en het studentendossier stellen aan de UHasselt.
3
3
4
4
 Maar software is steeds in beweging, en is nooit af. Daarom dat ik hier enkele
5
5
 punten voorzie omtrent de toekomstige uitbreidingen die aan Joeni zouden kunnen
6
6
 worden toegevoegd, of aan eender welk ander programma dat als vervanging zou dienen.[fn:still-joeni]
7
7
8
8
[fn:still-joeni] Voor het schrijfgemak wordt in dit hoofdstuk gewoon "Joeni"
9
9
gebruikt om "een vervangende applicatie" te beschrijven, alhoewel dit eender welk
10
10
ander programma kan zijn. Indien het specifiek om Joeni gaat, zal dit ook
11
11
duidelijk blijken uit de context.
12
12
13
13
*** /Desktop/-applicatie
14
14
 Op dit moment wordt Joeni gebruikt via een webbrowser, maar dit is zeker niet
15
15
 wat het eindpunt zou moeten zijn.
16
16
17
17
 Een website kan onmogelijk gebruik maken van alle mogelijkheden die computers
18
18
 aan hun gebruikers bieden; ze zijn van nature statische tekstbestanden, die
19
19
 enkel informatie kunnen doorsturen, en (gestructureerd) via speciale
20
20
 HTML-formulieren informatie kunnen opvangen. Daar komen dan ook een hoop
21
21
 beveiligingsproblemen bij kijken, die inherent zijn aan websites.
22
22
23
23
 Joeni moet een programma worden dat op de computer zelf draait. Veel features
24
24
 die nu simpelweg niet mogelijk zijn in Joeni, zouden hiermee wel mogelijk
25
25
 worden:
26
26
- Pop-ups die aangeven als er een wijziging is gebeurd in het uurrooster :: Nu
27
27
     moeten studenten zelf naar die webpagina surfen, er wordt geen proactieve
28
28
     melding hiervan gemaakt. Veel agendaprogramma's geven hier ook geen melding
29
29
     van, dus via iCal zal dit ook niet lukken.
30
30
- Live chat :: Dit is meer een feature die naar Agora toe gericht is, maar een
31
31
               live chat is ook technisch niet mogelijk zonder /client-side
32
32
               scripting/ (vereist bv. (D)AJAX-requests).
33
33
               Dit zou een uiterst handige toepassing zijn voor
34
34
               groepswerken, waarvoor studenten nu nog altijd zijn aangewezen op
35
35
               programma's van derden.
36
36
- Offline halen van studiemateriaal :: Het is triviaal, maar Joeni werkt enkel
37
37
     met een internetverbinding, net zoals *elke webapplicatie* (van de UHasselt).
38
38
     Een "echt" programma kan al het studiemateriaal, meldingen, opdrachten, ...
39
39
     downloaden op de computer van de student, zodat dit altijd offline
40
40
     geraadpleegd kan worden. Het indienen van taken kan dan ook offline
41
41
     gebeuren, waarna het programma zelf bij de eerstvolgende netwerkverbinding
42
42
     de taak doorstuurt.
43
43
- Veel betere samenhang/snelheid :: Een webapplicatie impliceert dat alle pagina's
44
44
     telkens opnieuw moeten worden ingeladen, er zit dus altijd een soort van
45
45
     /delay/ tussen een klik van de gebruiker en de uiteindelijke reactie. De
46
46
     browser moet ook alles inladen en /renderen/, dus een supersnelle cache
47
47
     alleen zal nooit het snelheidsprobleem kunnen oplossen. En als de
48
48
     verbinding wegvalt tijdens het inladen, dan is Joeni plots niet meer
49
49
     bereikbaar, redelijk frustrerend. Een programma op de computer zelf heeft
50
50
     al deze problemen niet. Er kan ook gebruik gemaakt worden van een hoop
51
51
     andere /widgets/ (zoals tabs in hetzelfde venster) die de samenhang verder
52
52
     kunnen verhogen.
53
53
- Dynamische/Directe informatie :: Als de gebruiker een fout maakt bij de
54
54
     interactie met de website, dan kan hier pas melding van worden gemaakt als
55
55
     de pagina opnieuw wordt ingeladen. Met een applicatie op de computer kunnen
56
56
     direct meldingen worden gegeven, en kan het indienen onmogelijk worden
57
57
     gemaakt totdat de gebruiker alle problemen heeft opgelost. Het geeft ook
58
58
     zekerheid: Als een knop wordt ingedrukt, dan is er zekerheid dat de
59
59
     verandering correct werd doorgevoerd.
60
-
- Mogelijkheden voor verbeterde authenticatie en beveiliging :: Op dit moment
+
60
     van resultaten: Als een docent een student in tweede kans een geslaagd
+
61
     cijfer wilt geven, maar vergeet de uitslag op "geslaagd" te zetten, dan kan
+
62
     een gewoon programma hierover direct informeren dat er misschien een fout
+
63
     gebeurd is. Dat gaat nu niet in Joeni zonder een hoop scripting.
+
64
- Mogelijkheden voor verbeterde authenticatie en beveiliging :: Op dit moment
61
65
     wordt de eigenaar van een account geverifieerd middels een stamnummer en
62
66
     een wachtwoord. Vergeleken met assymetrische sleutels is dit een redelijk
63
67
     slechte manier van beveiliging. Het WWW is niet voorzien op ergonomisch
64
68
     gebruik van bv. PGP-sleutels, maar een gewoon programma kan hiermee
65
69
     probleemloos overweg.
66
70
67
71
De reden dat er voor Joeni toch gekozen is voor een webapplicatie om te
68
72
beginnen, is omdat het niet zozeer de bedoeling was dat Joeni "het eindpunt" zou
69
73
worden, maar eerder een voorstelling van hoe het eruit zou kunnen zien. Het zou
70
74
Joeni ook complexer maken: Rekening houden met dynamische veranderingen, pop-ups
71
75
inbouwen (waarvan de API's kunnen verschillen per besturingssysteem), ... Het
72
76
maakt het geheel veel moeilijker om te bouwen, maar voegt weinig toe voor deze bachelorproef.
73
77
Daarom dat een website het idee van Joeni veel beter overbrengt, maar dan wel in
74
78
een statische setting.\\
75
79
Daarbij is een groot deel van de code in de achtergrond (voornamelijk de
76
80
databasecode) overdraagbaar, daar een desktopapplicatie sowieso contact zal
77
81
moeten onderhouden met een databank.
78
82
79
83
*** Herschrijven of onderhouden?
80
84
Persoonlijk heb ik bij het zien van bepaalde systemen vaak een indruk van: "Dit
81
85
kan beter, en ik weet hoe." Vermoedelijk bestaat er eenzelfde gevoel bij andere
82
86
informatici, een drang om iets volledig te herschrijven en "het deze keer goed
83
87
te doen".
84
88
85
89
Maar eigenlijk moet voor elk onderdeel apart overwogen worden wat op lange
86
90
termijn het voordeligst is voor de universiteit zelf. Herschrijven is
87
91
aantrekkelijk, maar kan veel tijd kosten en kan onvoorziene fouten met zich
88
92
meebrengen. In het ergste geval staat de software hierna zelfs geen stap verder.
89
93
Daarnaast is het op z'n minst een beetje arrogant om aan te nemen dat we niet zo
90
94
slecht zijn in het programmeren als onze voorganger(s), iedereen maakt immers fouten.
91
95
92
96
Het alternatief is de bestaande software onderhouden. Dit kan voordeliger zijn,
93
97
voor verschillende redenen:
94
98
- Personeel dat de software gebruikt is ermee bekend, en kan gradueel de
95
99
  evolutie ervan meevolgen, alsook direct feedback geven. Bij een /full rewrite/
96
100
  is het altijd wachten tot het klaar is, of totdat er een "MVP"[fn:mvp] bestaat, en dan
97
101
  nog is het veelal giswerk, getuige de leerstof van het vak Software
98
102
  Engineering.
99
103
- Een beetje triviaal, maar toch: De software is al uitvoerig getest, is al
100
104
  grotendeels af, en bestaande problemen zijn goed gekend. Er is geen nood aan
101
105
  het maken van uitvoerige /use cases/, /working drafts/, ... Dat op zich is ook
102
106
  al een enorme hoeveelheid tijd bespaard.
103
107
- Er is een redelijke kans dat deze optie een stuk goedkoper uitvalt dan het
104
108
  volledig opnieuw schrijven.
105
109
106
110
Echter, er zijn enkele voorwaarden aan verbonden:
107
111
- De software moet vrij zijn[fn:private-is-free], anders kan er technisch (en juridisch) gezien geen
108
112
  aanpassing aan gebeuren.
109
113
- De software moet ondersteund worden door de gebruikte systemen. Bijvoorbeeld:
110
114
  Een programma geschreven in Turbo Pascal kan waarschijnlijk niet meer werken
111
115
  op een modern besturingssysteem, terwijl een programma dat op de Java Virtual
112
116
  Machine werkt juist nog een lang leven beschoren kan zijn.
113
117
- Er moeten programmeurs voor te vinden zijn. Hiermee doel ik op het feit dat
114
118
  programmeertalen komen en gaan, en zo ook de interesse van mensen om zich
115
119
  erin te verdiepen: Het is tegenwoordig een stuk moeilijker om een
116
120
  COBOL-programmeur te vinden dan een Javaprogrammeur. Als het vinden van
117
121
  gekwalificeerd personeel te moeilijk is, dan is onderhoud waarschijnlijk
118
122
  gewoon niet meer mogelijk.
119
123
120
124
Een mogelijk voorstel is om een lijst op te stellen van beslissende factoren,
121
125
samen met de juiste personen. Dan kunnen die factoren getoetst worden aan alle
122
126
gebruikte software voor de UHasselt, en dan kan er individueel beslist worden
123
127
welke software vervangen wordt, en dewelke onderhouden wordt.
124
128
125
129
[fn:mvp] /Minimum Viable Product/: Een marketingterm waarmee een prototype van
126
130
een product of werk wordt bedoeld waarmee de klant een eerste indruk kan krijgen
127
131
van het uiteindelijke geheel.
128
132
129
133
[fn:private-is-free] Software die de UHasselt zelf geschreven heeft, is per
130
134
definitie ook vrij.