Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Swad Timeline
1. SWAD, an Open
Learning Management System
Including timeline implementation
Antonio Cañas
University of Granada (UGR)
@acanasvargas acanas@ugr.es acanas@openswad.org
https://openswad.org/ @openswad
SWAD, an Open
Learning Management System
Including timeline implementation
Antonio Cañas
University of Granada (UGR)
@acanasvargas acanas@ugr.es acanas@openswad.org
https://openswad.org/ @openswad
1
1
Antonio Cañas et al.
November 22, 2021, Granada, Spain
November 22, 2021, Granada, Spain
2. Contents
●
History and summary of features
●
Implementation
●
Free software release
●
swad.ugr.es figures
●
openswad.org
●
Timeline
●
Future objectives and tasks
●
Conclusions
3. History and
summary of features
“The dream of yesterday is the hope of today and the
reality of tomorrow”
.
Robert H. Goddard
History and
summary of features
“The dream of yesterday is the hope of today and the
reality of tomorrow”
.
Robert H. Goddard
4. LMS in 2021: a very broad offer
●
Today: hundreds of LMS
●
proprietary / free software
●
expensive / free of charge
●
installable on the client's servers / accessible in the cloud
7. ...but in 1999 there were not so many available, and we started to develop our
own system:
Sistema Web de Apoyo a la Docencia
(Web System for Teaching Support)
⬇
Social Workspace At a Distance
https://swad.ugr.es/
https://openswad.org/
A web platform to manage courses, students and teachers,
with functions to support teaching and learning.
What is SWAD?
8. What is SWAD?
This is how it looks,
although some parts of its appearance,
such as colors or icons, are customizable
9. Features
Free software · 9 languages · Responsive design · Android app
Face-to-face or blended learning
Hierarchical organization: System · Countries · Institutions
(universities, companies) · Centers (faculties, schools) ·
Degrees · Courses · Group types · Groups
10 available roles: Unknown · Guest · User · Student · Non-
editing teacher · Teacher · Degree admin · Center admin ·
Institution admin · System admin
10. Functionality
Social network · Calendar · Notifications · Course
information · Syllabus · Documents · Shared files ·
Portfolio · Grades · Assignments · Projects · Exam
announcements · Quizzes · Exams · Games · Surveys ·
Groups · Lists of students and teachers · Attendance
control using QR codes · Forums · Notices · Messaging
system · Statistics · Agenda · Preferences
All features in https://github.com/acanas/swad-core/wiki/UserGuide.en
11. Dpt.ATC: 1999-2003
1º TIP: 2003-2004
2º TIP: 2005-2006
3º TIP: 2006-2008
V.L.Center:2008-2016
Free Software: 2010...
UNA.py: 2012-2014
OpenSWAD: 2012…
Dpt.ATC: 2016...
21 years of use and development
openswad.org
2012...
ugr.es CEVUG
2008-2016
ugr.es TIPs
2003-2008
ugr.es ATC
1999-2003
una.py
2012-2015
ugr.es ATC
2016...
12. Free software release
“You're frozen
When your heart's not open”
Frozen, Madonna
Free software release
“You're frozen
When your heart's not open”
Frozen, Madonna
13. First release as free software
January 21, 2010
Free software office of the University of Granada
14. Steps to release the core
1. Code (names, comments) in English (100%)
2. Code independent from the UGR (100%)
3. Translation to 9 languages (90%)
4. Add AGPL headers to files (100%)
5. Publish the source code (100%) https://openswad.org/source/
6. Publish the installation procedure (100%) https://openswad.org/install/
7. Use git version control system (100%)
8. Upload to GitHub (100%) https://github.com/acanas/swad-core
9. Desirable: automate installation (20%)
15. Why do we create free software?
●
Because it facilitates collaborative development
Fourth Hackathon of free software projects of the UGR, 2012. Photo: A. Cañas
16. Why do we create free software?
●
Because it encourages better programming
@psicobyte_ explains the benefits of free software. Photo: A. Cañas
17. Why do we create free software?
●
Because it improves the code quality
Hackathon of SWADroid and SWAD, 2013. Photo: A. Cañas
18. Why do we create free software?
●
Because it provides freedom and security to users
https://www.gnu.org/philosophy/
19. How much work is behind?
swad-core SWADroid
Affero GPL v3 license
https://github.com/acanas/swad-core
GPL v3 license
https://github.com/Amab/SWADroid
361,650
C code lines
144
MySQL tables
60,744
Java code lines
17K
downloads
94 person-years
estimated effort*
14 person-years
estimated effort*
$5,196,470
estimated cost*
$794,070
estimated cost*
Other modules and more info: https://openswad.org/source
* According to the COCOMO model in Open Hub
20. swad.ugr.es figures
“What goes up,
must come down”
What goes up, The Alan Parsons Project
swad.ugr.es figures
“What goes up,
must come down”
What goes up, The Alan Parsons Project
21. 482 million
clicks (page views)
386
million
(80%)
students
26
million
(5%)
teachers
69
million
(14%)
others
1
million
(<1%)
admin.
SWAD-UGR - Jan 2005 Nov
→ 2021
22. 198,402
users have used the platform
173,814
(88%)
as students
3913
(2%)
as teachers
35,677
(18%)
as guests
133
(<1%)
as admin.
SWAD-UGR - Jan 2005 Nov
→ 2021
35. Keys to success at the UGR
●
#3: User support: thousands of queries answered
Thank you for your help and efficiency...
and for having designed a computer invention that really works,
which reconciles me with the new technologies...
36. ●
#4: Developed according to the users’ requests
Keys to success at the UGR
A user wants the platform
to congratulate him
on his birthday...
Days later a new feature
congratulates users
for their birthdays.
37. Keys to success at the UGR
●
#5: Strengths of the tool
●
Functionality and usability
●
Simplicity
●
It has what most teachers asked
●
Reliability and safety
●
It consumes few resources
●
It works 24 hours, fast and almost without failures
38. openswad.org
“A planet is the cradle of mind, but one cannot live in
a cradle forever.”
Konstantin Tsiolkovski (russian physicist)
openswad.org
“A planet is the cradle of mind, but one cannot live in
a cradle forever.”
Konstantin Tsiolkovski (russian physicist)
39. SWAD outside the UGR after release
●
Little diffusion
●
Difficult to reach the target audience (need for advertising)
●
Absence of simple installation
●
Many competitors
●
Many LMS, some of them very widespread
●
Released as free software too late (2010)
●
A lot of work, small team
●
Conclusion
●
Very few (two or three) installations
40. The OpenSWAD.org project
●
OpenSWAD.org is an installation in the cloud of the SWAD educational
platform, offered free of charge for any country by the OpenSWAD
Association (non-profit organization, independent of the UGR)
●
OpenSWAD.org is available since 2012, but it did not start growing until
2015, when we decided to carry out advertising campaigns
41. Why “Open”?
●
Free software (so open source)
●
Open and free for everyone
●
Open design and interaction
●
You can access many features (hierarchy, courses, teachers, statistics) even if you are not logged in
●
Open content allowed
●
Upload, mark as public and choose license
●
Anyone could access, even without log in
42. Steps for internationalization
1. Code independent from the institution (100%)
2. Translation to 9 languages (90%)
3. ISO 8601 format for date-times (100%)
4. Dates-hours independent of location (100%)
5. Calendars independent of location (100%)
6. Weeks starting on Monday or Sunday (100%)
7. Floating point / comma format (10%)
43. Advertising: conversion funnel
2,600,000 ad impressions on Twitter and Facebook
2,600,000 ad impressions on Twitter and Facebook
2600 filled in their data (50%)
2600 filled in their data (50%)
260 created center, degree, course (10%)
260 created center, degree, course (10%)
130,000 clicked link (5%)
130,000 clicked link (5%)
5200 created account (
5200 created account (4%
4%)
)
130 enrolled in course (50%)
130 enrolled in course (50%)
65 created course content (50%)
65 created course content (50%)
13 used with students (20%, 5 per million)
13 used with students (20%, 5 per million)
Example: Feb. 2015 March 2016
→
44. Cost of advertising (2015 2017)
→
Cost Dates Days Cost/day Impressions Clicks Cost/click
Twitter 4650.29€ Feb 12, 2015
Sep 25, 2017
956 4.86 € 14,042,284 50,119 €0.108
Facebook 2400.84€ Sep 26, 2015
Sep 25, 2017
730 3.29 € 12,858,591 192,833 €0.012
AdWords 1255.93€ Feb 16, 2017
Sep 25, 2017
221 5.68 € 392,298 15,046 €0.083
Total 8307.06€ Feb 12, 2015
Sep 25, 2017
956 8.69 € 27,293,173 257,998 €0.032
Courses Teachers Students Total users
Courses or users with real use 528 385 1657 18 411
Cost per course or user €15,73 €21,58 €5,01 €0,45
45. Conversion comparison (2017)
Cost Dates Days Impresiones Clicks Page views Users New
accounts
New
courses
Twitter €66.20 Sep 6 -
Sep 24,
2017
7
€9.46 /
day
271,072
€0.00024 /
impression
734
€0.09 /
click
14 632
€0.0045 /
page view
342
€0.19 /
user
186
€0.36 / new
account
10
€6.62 / new
course
Facebook €109.66 Sep 7 -
Sep 25,
2017
7
€15.66 /
day
148,206
€0.00074 /
impression
3780
€0.03 /
click
33 087
€0.0033 /
page view
274
€0.40 /
user
114
€0.96 / new
account
12
€9.14 / new
course
AdWords €65.83 Sep 5 -
Sep 23,
2017
7
€9.40 /
day
13,210
€0.00498 /
impression
808
€0.08 /
click
11 169
€0.0060 /
page view
243
€0.27 /
user
94
€0.70 / new
account
7
€9.40 / new
course
Total €241.69 Sep 5 -
Sep 25,
2017
21
€11.51 /
day
432,488
€0.00056 /
impression
5322
€0.05 /
click
58 888
€0.0041 /
page view
859
€0.28 /
user
394
€0.61 / new
account
29
€8.33 / new
course
49. Users / country (OpenSWAD)
First countries in OpenSWAD according to number of users
First countries in OpenSWAD according to number of users
34,440 users
from 152 countries
50. Users / country (OpenSWAD)
●
Even a report about OpenSWAD has been broadcast on a Latin American TV
channel
OpenSWAD in Atomun, Telesur TV (Venezuela), July 2017
55. Implementation
“Every step that you take
Could be your biggest mistake
It could bend or it could break
That's the risk that you take”
What If, Coldplay
Implementation
“Every step that you take
Could be your biggest mistake
It could bend or it could break
That's the risk that you take”
What If, Coldplay
56. The core
●
Written from scratch in C
(compiled, not interpreted)
✔Advantages:
●
+ speed
●
- memory
●
Functional even in a Raspberry Pi
●
+ stability of source code over time
✘Disadvantages:
●
absence of specialized library functions for the web
57. 2nd: 2004-2006
Pentium 4 HT
RAM 2 GiB
2 HD 160 GB
Fedora 3
3rd: 2007-2008
Core 2 Duo
RAM 4 GiB
2 HD 500 GB
Fedora 6
4th: 2009-2010
Core 2 Quad
RAM 4 GiB
2 HD 146 GB
2 HD 1 TB
Fedora 10
5th: 2011-2016
2 Xeon Quad
RAM 24 GiB
4 HD 146 GB
4 HD 500 GB
CentOS 5.7
1st: 1999-2003
Shared server
Former servers at the UGR
58. Current server at the UGR (6th: 2016...)
●
HP Proliant DL160 G9, 2 Xeon with 6 cores, RAM 32 GiB
4 HD 146 GB
SAS 15000 rpm
RAID 1+0 (292 GB)
SO CentOS 7.2
MySQL database
4 HD 1 TB
SAS 7200 rpm
RAID 5 (3 TB)
Web files
( /var/www )
59. Plugins
●
It is possible to develop add-ons (plugins) that run on:
●
other servers
●
mobile devices. Example: SWADroid
●
The plugins interact with the swad core through an API:
https://openswad.org/api/
60. Photographs of users
●
Our own automatic system for detecting faces and
improving the quality of photos, trained with 90K photos
61. Up to 400K times per day
Up to 2000 times / minute (30 times / second)
Log
“click”
logged access
HTML5
server
database
swad-core
63. Log table
●
It allows analyzing a lot of information:
●
By role
●
By user
●
By action performed
●
By qualification
●
By subject
●
By dates
●
...
UGR: 482 million registered hits since 2005
64. Log table
Pages per minute
(averaged during an academic year)
teachers
students
65. Log table
Matches of the Soccer World Cup 2010
You can even see the rest in the match
67. Log table
●
What if we convert every click into a sound?
●
At 1 am:
http://swad.ugr.es/stat/clicks/clicks_1am.wav
●
At 1 pm:
http://swad.ugr.es/stat/clicks/clicks_1pm.wav
●
Peak (students choosing groups):
http://swad.ugr.es/stat/clicks/clicks_grupos.wav
68. Who has developed it?
●
Recent programmers:
●
Antonio Cañas Vargas (swad-core, servers, management, courses)
●
Daniel J. Calandria Hernández (photo processing, chat)
●
Juan Miguel Boyero Corral (SWADroid)
●
Bate Ye (iSWAD)
●
Javier Bueno López (SWADroid)
●
Adrián Lara Roldán (iSWAD)
●
Jesús Mesa González (photo processing)
●
Sergio Díaz Rueda (SWADroid)
(green = free software)
69. Who has developed it?
●
Former programmers (I):
●
Jesús Álvarez Martín (photo processing)
●
Alberto E. Rodrigo Gámiz (photo processing)
●
Ana Belén Cara Carmona (chat & whiteboard)
●
Carlos Moreno Muñoz (chat & whiteboard)
70. Who has developed it?
●
Former programmers (II):
●
Antonio Manuel Aguilera Malagón (SWADroid)
●
Helena Rodríguez Gijón (SWADroid)
●
José Antonio Guerrero Avilés (SWADroid)
●
Alejandro Alcalde Barros (SWADroid)
●
Rubén Martín Hidalgo (SWADroid)
●
Miguel Ángel Cerrailo Valle (Triswados, app Android)
●
Raúl Álvarez Hinojosa (iSWAD)
71. Who has developed it?
●
Programmers of modules that were not used:
●
Andrés Ramón Masegosa Aredondo (photo processing)
●
Raúl Jiménez Benítez (chat)
●
María Beatriz Medina Yáñez (whiteboard)
●
Raquel Cazalilla Sáez (chat & whiteboard)
●
Emiliano Luis Rincón Vallejos (rich text editor)
●
Diego Montesinos Hervás (iSWAD)
●
Lucas Ortiz Velasco (SWADMyPage)
●
David Medina Godoy (SWADE, rich text editor)
●
Marta Muñoz López (SWAD2Moodle)
72. Who has developed it?
●
Translators:
●
Antonio Cañas Vargas (CA,DE,EN,ES,FR,GN,IT,PL,PT)
●
Joan Lluís Díaz Rodríguez (CA)
●
Rafael Barranco Droege (DE)
●
Giuseppe Antonio Pagin, Antonella Grande, Francisco Manuel Herrero Pérez, Nicola
Comunale Rizzo (IT)
●
Wojtek Kieca, Tomasz Olechowski, Mateusz Stanko (PL)
73. Who has developed it?
●
Contributors (I):
●
Javier Fernández Baldomero (forums, papers)
●
Antonio F. Díaz García (servers)
●
Eva Martínez Ortigosa (administration, papers)
●
Francisco Illeras García (servers)
●
Alberto Prieto Espinosa (papers)
●
Beatriz Prieto Campos (papers)
●
Begoña del Pino Prieto (papers)
●
Mancia Anguita López (papers)
●
Eduardo Ros Vidal (papers)
74. Who has developed it?
●
Contributors (II):
●
Francisco A. Ocaña Lara (FAQ, papers)
●
Adrián Gómez Anaya (WikiSwad)
●
Paloma Marín Arraiza (video tutorials)
●
technicians and scholars from the Virtual Learning Center
●
~120 degree administrators
●
...and many more
75. Timeline
“You think you know when you learn, are more sure
when you can write, even more when you can teach,
but certain when you can program.”
Alan Perlis
Timeline
“You think you know when you learn, are more sure
when you can write, even more when you can teach,
but certain when you can program.”
Alan Perlis
76. Timeline, notes, publications
●
Timeline: set of publications
●
from a user
●
global
●
Only me
●
Followed users
●
All users
typedef enum
{
Tml_Usr_TIMELINE_USR,
Tml_Usr_TIMELINE_GBL,
} Tml_Usr_UsrOrGbl_t;
typedef enum
{
Usr_WHO_UNKNOWN,
Usr_WHO_ME,
Usr_WHO_SELECTED, // Not applicable to timeline
Usr_WHO_FOLLOWED,
Usr_WHO_ALL,
} Usr_Who_t;
77. Timeline, notes, publications
●
Publication: · original note (24805, 78% of 31845)
· shared note ( 1282, 4% of 31845)
· comment to a note ( 5758, 18% of 31845)
typedef enum
{
Tml_Pub_UNKNOWN = 0,
Tml_Pub_ORIGINAL_NOTE = 1,
Tml_Pub_SHARED_NOTE = 2,
Tml_Pub_COMMENT_TO_NOTE = 3,
} Tml_Pub_Type_t;
struct Tml_Pub_Publication
{
long PubCod; // Publication code
long NotCod; // Note code
long PublisherCod; // Sharer or writer of the publication
Tml_Pub_Type_t Type; // Original note, shared note, comment
struct Tml_Pub_Publication *Next; // Used for chained list
}; *swad.ugr.es, nov 2021
78. Timeline, notes, publications
●
Note: timeline post ( 4163, 17% of 24805)
public file ( 66, <1% of 24805)
call for exam ( 2727, 11% of 24805)
notice (17567, 71% of 24805)
forum post ( 282, 1% of 24805)
*swad.ugr.es, nov 2021
79. Timeline, notes, publications
struct Tml_Not_Note
{
long NotCod; // Unique code/identifier for each note
Tml_Not_Type_t Type; // Timeline post, public file,
// call for exam, notice, forum post...
long UsrCod; // Publisher
long HieCod; // Hierarchy code
// (institution/center/degree/course)
long Cod; // Code of file, forum post,
// notice, timeline post...
bool Unavailable; // File, forum post, notice,...
// unavailable (removed)
time_t DateTimeUTC; // Date-time of publication in UTC time
unsigned NumShared; // Number of times (users)
// this note has been shared
unsigned NumFavs; // Number of times (users)
// this note has been favourited
};
80. Timeline, notes, publications
__________________
|@author |
| Note |
|__________________|
|@author |
| Comment 1 |
|______________|
|@author |
| Comment 2 |
|______________|
| |
| ... |
|______________|
|@author |
| Comment n |
|______________|
●
A note can have comments attached to it:
84. Database: publications
mysql> DESCRIBE tml_pubs;
+--------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+----------+------+-----+---------+----------------+
| PubCod | bigint | NO | PRI | NULL | auto_increment |
| NotCod | bigint | NO | MUL | NULL | |
| PublisherCod | int | NO | MUL | NULL | |
| PubType | tinyint | NO | MUL | NULL | |
| TimePublish | datetime | NO | MUL | NULL | |
+--------------+----------+------+-----+---------+----------------+
85. Database: notes
mysql> DESCRIBE tml_notes;
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| NotCod | bigint | NO | PRI | NULL | auto_increment |
| NoteType | tinyint | NO | MUL | NULL | |
| Cod | int | NO | | -1 | |
| UsrCod | int | NO | MUL | NULL | |
| HieCod | int | NO | | -1 | |
| Unavailable | enum('N','Y') | NO | | N | |
| TimeNote | datetime | NO | MUL | NULL | |
+-------------+---------------+------+-----+---------+----------------+
mysql> DESCRIBE tml_notes_fav;
+---------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+----------------+
| FavCod | bigint | NO | PRI | NULL | auto_increment |
| NotCod | bigint | NO | MUL | NULL | |
| UsrCod | int | NO | MUL | NULL | |
| TimeFav | datetime | NO | | NULL | |
+---------+----------+------+-----+---------+----------------+
86. Database: comments
mysql> DESCRIBE tml_comments;
+--------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+----------+------+-----+---------+-------+
| PubCod | bigint | NO | PRI | NULL | |
| Txt | longtext | NO | MUL | NULL | |
| MedCod | int | NO | MUL | -1 | |
+--------+----------+------+-----+---------+-------+
mysql> DESCRIBE tml_comments_fav;
+---------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+----------------+
| FavCod | bigint | NO | PRI | NULL | auto_increment |
| PubCod | bigint | NO | MUL | NULL | |
| UsrCod | int | NO | MUL | NULL | |
| TimeFav | datetime | NO | | NULL | |
+---------+----------+------+-----+---------+----------------+
87. Database: posts
mysql> DESCRIBE tml_posts;
+--------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+----------+------+-----+---------+----------------+
| PstCod | int | NO | PRI | NULL | auto_increment |
| Txt | longtext | NO | MUL | NULL | |
| MedCod | int | NO | MUL | -1 | |
+--------+----------+------+-----+---------+----------------+
mysql> DESCRIBE cfe_exams;
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| ExaCod | int | NO | PRI | NULL | auto_increment |
| ... | ... | ... | ... | ... | ... |
mysql> DESCRIBE brw_files;
+-----------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+----------------+
| FilCod | int | NO | PRI | NULL | auto_increment |
| ... | ... | ... | ... | ... | ... |
mysql> DESCRIBE not_notices;
+-----------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+----------------+
| NotCod | int | NO | PRI | NULL | auto_increment |
| ... | ... | ... | ... | ... | ... |
mysql> DESCRIBE for_posts;
+-----------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+----------------+
| PstCod | int | NO | PRI | NULL | auto_increment |
| ... | ... | ... | ... | ... | ... |
88. Database: timelines
mysql> DESCRIBE tml_timelines;
+-----------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+-------+
| SessionId | char(43) | NO | PRI | NULL | |
| NotCod | bigint | NO | PRI | NULL | |
+-----------+----------+------+-----+---------+-------+
mysql> DESCRIBE tml_tmp_timeline;
+--------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------+------+-----+---------+-------+
| NotCod | bigint | NO | PRI | NULL | NULL |
+--------+--------+------+-----+---------+-------+
89. Timeline: getting list of publications
●
Our algorithm:
●
Select publications one by one in a loop
●
In each iteration:
●
Get the most recent publication (original, shared or comment) checking that its note is not already
retrieved
●
After getting a publication, save its note code to not get it again.
SELECT PubCod
FROM tml_pubs
WHERE NotCod NOT IN
(SELECT NotCod
FROM tml_tmp_timeline)
ORDER BY PubCod DESC
LIMIT 1;
90. Timeline: getting list of publications
●
Slower alternative (may need seconds for large tables):
●
Get the maximum PubCod, i.e more recent publication (original, shared or commment),
of every set of publications corresponding to the same note:
SELECT MAX(PubCod) AS NewestPubCod
FROM tml_pubs
GROUP BY NotCod
ORDER BY NewestPubCod DESC
LIMIT 10;
91. Timeline: getting list of publications
●
Restricting publications to mine and those I follow:
CREATE TEMPORARY TABLE fol_tmp_me_and_followed
(UsrCod INT NOT NULL,
UNIQUE INDEX(UsrCod)) ENGINE=MEMORY
SELECT my_usr_cod AS UsrCod
UNION
SELECT FollowedCod AS UsrCod
FROM usr_follow
WHERE FollowerCod=my_usr_cod;
----------------------------------------------
SELECT tml_pubs.PubCod,
tml_pubs.NotCod,
tml_pubs.PublisherCod,
tml_pubs.PubType
FROM tml_pubs,
fol_tmp_me_and_followed
WHERE tml_pubs.PublisherCod=fol_tmp_me_and_followed.UsrCod
AND tml_pubs.NotCod NOT IN
(SELECT NotCod
FROM tml_tmp_timeline)
ORDER BY PubCod DESC
LIMIT 1;
92. Timeline: getting list of publications
●
Three types of timeline updates
_ ______________________
/ |______________________| Tml_GET_NEW_PUBS
New < |______________________| automatically from time to time
_|______________________| (AJAX)
_|_See_new_activity_(3)_|
/ |______________________| Tml_GET_REC_PUBS
| |______________________| user clicks on action menu
Recent < |______________________| or after editing timeline
| |______________________|
_|______________________|
_|_______See_more_______|
/ |______________________| Tml_GET_OLD_PUBS
| |______________________| user clicks on bottom link
Old < |______________________| (AJAX)
| |______________________|
_|______________________|
93. Timeline: getting list of publications
tml_pubs
_____
|_____|11
|_____|10
_|_____| 9 <-- RangePubsToGet.Top
Get / |_____| 8
pubs | |_____| 7
from < |_____| 6
this | |_____| 5
range _|_____| 4
|_____| 3 <-- RangePubsToGet.Bottom
|_____| 2
|_____| 1
0
94. Timeline: getting list of publications
case Tml_GET_REC_PUBS: // Get some limited recent publications
/* First query to get initial timeline shown
==> no notes yet in current timeline table */
RangePubsToGet->Top = 0;
/* _ _____ 0 <-- RangePubsToGet.Top = +infinite
/ |_____| 8
Get | |_____| 7
pubs < |_____| 6
from | |_____| 5
all | |_____| 4
range . |_____| 3
. |_____| 2
. |_____| 1
0 <-- RangePubsToGet.Bottom = -infinite */
RangePubsToGet->Bottom = 0;
95. Timeline: getting list of publications
case Tml_GET_NEW_PUBS: // Get the publications (without limit)
// newer than last pub. code
/* Via AJAX automatically from time to time */
RangePubsToGet->Top = 0;
/* _ _____ 0 <-- RangePubsToGet.Top = +infinite
Get / |_____|11
these < |_____|10
pubs _|_____| 9
/ |_____| 8 <-- RangePubsToGet.Bottom = last pub. code
Pubs | |_____| 7
already < |_____| 6
shown | |_____| 5
| |_____| 4
. |_____| .
. |_____| .
. |_____| .
*/
RangePubsToGet->Bottom = Tml_DB_GetPubCodFromSession (Tml_Pub_LAST);
96. Timeline: getting list of publications
case Tml_GET_OLD_PUBS: // Get some limited publications
// older than first pub. code
/* Via AJAX when I click in link to get old publications */
RangePubsToGet->Top = Tml_DB_GetPubCodFromSession (Tml_Pub_FIRST);
/* _____
. |_____| .
. |_____| .
. |_____| .
Pubs | |_____| 8
already < |_____| 7
shown | |_____| 6
| |_____| 5
Get _|_____| 4 <-- RangePubsToGet.Top = first pub. code
pubs / |_____| 3
from < |_____| 2
this _|_____| 1
rage 0 <-- RangePubsToGet.Bottom = -infinite */
RangePubsToGet->Bottom = 0;
97. Timeline: getting list of publications
●
Restricting publications to range:
SELECT tml_pubs.PubCod,
tml_pubs.NotCod,
tml_pubs.PublisherCod,
tml_pubs.PubType
FROM tml_pubs,
fol_tmp_me_and_followed
WHERE tml_pubs.PublisherCod=fol_tmp_me_and_followed.UsrCod
AND tml_pubs.PubCod>bottom // if type == Tml_GET_REC_PUBS
AND tml_pubs.PubCod<top // updated every iteration
// to last pub. code got
AND tml_pubs.NotCod NOT IN
(SELECT NotCod
FROM tml_tmp_timeline)
ORDER BY PubCod DESC
LIMIT 1;
98. Timeline: getting list of publications
Timeline->Pubs.Top Pub #0
______ ______ Pub #1
|______|------>|______| ______ Pub #2
|______| -> |______| ______ Pub #3
|______| / |______| ->|______| ______
|______| / |______| / |______| ->|______|
|_Next_|-- |______| / |______| // |______|
more recent |_Next_|-- |______| // |______|
______ |_Next_|--/ |______|
|______|---------------------------------------------- |_NULL_|
older
Timeline->Pubs.Bottom
●
After getting the publications, the result is a chained list:
99. Timeline: showing publications
_____
/ |_____| just_now_timeline_list (Posts retrieved automatically
| |_____| via AJAX from time to time.
| |_____| They are transferred inmediately
| | to new_timeline_list.)
Hidden < __v__
| |_____| new_timeline_list (Posts retrieved but hidden.
| |_____| When user clicks to view them,
| |_____| the most recent of each note is
|_____| is transferred
| to visible timeline_list.)
See new activity (0)
__v__
/ |_____| timeline_list (Posts visible on page)
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
|_____|
^
See more
__|__
/ |_____| old_timeline_list (Posts just retrieved via AJAX
| |_____| when user clicks "see more".
| |_____| They are transferred inmediately
Hidden < |_____| to timeline_list.)
| |_____|
| |_____|
|_____|
<ul id="just_now_timeline_list" ...>
</ul>
<ul id="new_timeline_list" ...>
</ul>
<div id="view_new_container" ...
style="display:none;">
<a href="" ...
onclick="moveNewTimelineToTimeline();
return false;">
See new activity
(<span id="view_new_count">
0
</span>)
</a>
</div>
<ul id="timeline_list" ...>
visible timeline
</ul>
<div id="view_old_container" ...>
<a href="" ...
onclick="...
refreshOldTimeline();
return false;">
...
See more
</a>
</div>
<ul id="old_timeline_list" ...>
</ul>
100. Timeline: showing publications
<head>
...
<script type="text/javascript" ...>
var delayNewTml = Cfg_TIME_TO_REFRESH_TIMELINE; // 2000 ms
function init() {
ActionAJAX = "SWAD_URL";
...
setTimeout('refreshNewTml()',delayNewTL);
...
}
</script>
<script type="text/javascript" ...>
var refreshParamIdSes = "ses=...";
var refreshParamNxtActNewPub = "act=...";
var refreshParamWho = "Who=...";
</script>
...
</head>
<body onload="init();">
...
</body>
●
Automatic refresh via AJAX every 2 s → 3 s → 4 s...
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
|_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
|_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
|_____|
102. Timeline: showing publications
function readNewTimelineData () {
if (objXMLHttpReqNewTml.readyState == 4) // Check if data have been received
if (objXMLHttpReqNewTml.status == 200) {
// Access to UL for just now timeline
var justNowTimeline = document.getElementById('just_now_timeline_list');
if (justNowTimeline) {
// Update list of publications in just now timeline
justNowTimeline.innerHTML = objXMLHttpReqNewTml.responseText;
var numNotesJustGot = justNowTimeline.childNodes.length;
if (numNotesJustGot) {// New notes received
// Scripts in timeline got via AJAX not executed ==> execute them
evalScriptsInElem (justNowTimeline);
// Process maths
MathJax.typeset();
...
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
|_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
|_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
|_____|
103. Timeline: showing publications
...
// Move all the LI elements (notes) in UL 'just_now_timeline_list'
// ...to the top of UL 'new_timeline_list'
var newTimeline = document.getElementById('new_timeline_list');
for (var i=0; i<numNotesJustGot; i++) {
// Move node from just now timeline to new timeline
newTimeline.insertBefore(justNowTimeline.lastChild,
newTimeline.firstChild);
newTimeline.firstChild.className += " Tml_NEW_PUB";
}
// Update number of notes in new timeline
var viewNewCount = document.getElementById('view_new_count');
viewNewCount.innerHTML = newTimeline.childNodes.length;
// Unhide message with number of notes if hidden
var viewNewContainer = document.getElementById('view_new_container');
viewNewContainer.style.display = '';
}
}
// Global delay variable is set initially in swad-core
delayNewTml += 1000; // Increase one second on each call
setTimeout('refreshNewTml()',delayNewTml);
}
}
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
|_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
|_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
|_____|
104. _____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
|_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
|_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
|_____|
Timeline: showing publications
function moveNewTimelineToTimeline () {
// Move the LI elements (notes) in UL 'new_timeline_list'...
// ...to the top of UL 'timeline_list', only if not repeated before
var newTimeline = document.getElementById('new_timeline_list');
var numNewNotes = newTimeline.childNodes.length;
if (numNewNotes) {
var timeline = document.getElementById("timeline_list");
for (var i=1; i<=numNewNotes; i++) {
// Check if the last child (the oldest) in the new timeline...
// ...is the last ocurrence of the note
var mostRecentOcurrenceOfNote = true;
var lastChildIndex = numNewNotes - i;
var noteCode = newTimeline.lastChild.dataset.noteCode;
for (var j=0; j<lastChildIndex; j++)
if (newTimeline.childNodes[j].dataset.noteCode == noteCode) {
mostRecentOcurrenceOfNote = false;
break;
}
...
●
User clicks "See new activity" → View new pubs.
105. Timeline: showing publications
...
// Move or remove node from new timeline
if (mostRecentOcurrenceOfNote) {
// Move node from new timeline to timeline
timeline.insertBefore(newTimeline.lastChild,timeline.firstChild);
timeline.firstChild.className += " Tml_NEW_PUB";
}
else
// Remove last child (because is repeated in more recent pubs)
newTimeline.removeChild(newTimeline.lastChild);
}
}
// Reset number of new publications after moving
var viewNewCount = document.getElementById('view_new_count');
viewNewCount.innerHTML = 0;
// Hide link to view new publications after moving
var viewNewContainer = document.getElementById('view_new_container');
viewNewContainer.style.display = 'none';
}
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
|_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
|_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
|_____|
106. _____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
|_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
|_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
|_____|
Timeline: showing publications
var objXMLHttpReqOldTml = false;
function refreshOldTimeline () {
objXMLHttpReqOldTml = AJAXCreateObject (); // new XMLHttpRequest()
if (objXMLHttpReqOldTml) {
var refreshParams = refreshParamNxtActOldPub + '&' +
refreshParamIdSes;
if (typeof refreshParamUsr !== 'undefined') {
if (refreshParamUsr.length)
refreshParams += '&' + refreshParamUsr;
}
if (typeof refreshParamWho !== 'undefined') {
if (refreshParamWho.length)
refreshParams += '&' + refreshParamWho;
}
objXMLHttpReqOldTml.onreadystatechange = readOldTimelineData;
objXMLHttpReqOldTml.open('POST',actionAJAX,true);
objXMLHttpReqOldTml.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
objXMLHttpReqOldTml.send(refreshParams);
}
}
●
User clicks "See more..." → View old pubs.
107. Timeline: showing publications
function readOldTimelineData () {
if (objXMLHttpReqOldTml.readyState == 4) // Check if data have been received
if (objXMLHttpReqOldTml.status == 200) {
// Access to UL with the old timeline
var oldTimeline = document.getElementById('old_timeline_list');
if (oldTimeline) {
// Fill list of publications in old timeline
oldTimeline.innerHTML = objXMLHttpReqOldTml.responseText;
var countOldTimeline = oldTimeline.childNodes.length;
if (countOldTimeline) {
// Scripts in timeline got via AJAX not executed ==> execute them
evalScriptsInElem (oldTimeline);
// Process maths
MathJax.typeset();
// Move all the LI elements in UL 'old_timeline_list'
// to the bottom of UL 'timeline_list'
var timeline = document.getElementById("timeline_list");
for (var i=0; i<countOldTimeline; i++)
timeline.appendChild(oldTimeline.firstChild);
...
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
|_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
|_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
|_____|
108. Timeline: showing publications
...
// There may be more publications
// Unhide icon to be hidden on click
document.getElementById('get_old_timeline').style.display = '';
// Hide icon to be shown on click
document.getElementById('getting_old_timeline').style.display = 'none';
}
else // No old publications retrieved, so we have reached the oldest pub.
// Hide container with link to get old publications
document.getElementById("view_old_pubs_container").style.display = 'none';
}
}
}
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
|_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
|_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
|_____|
113. Layout: favs & shared
___________________________________________________________________________
| div which content will be updated (parent of parent of form) |
| _____________________ _______ _____________________________________ |
| | div (parent of form)| | div | | div for users | |
| | _________________ | | for | | ______ ______ ______ ______ | |
| | | this form | | | num. | | | | | | | | | form | | |
| | | _____________ | | | of | | | user | | user | | user | | to | | |
| | | | fav icon | | | | users | | | 1 | | 2 | | 3 | | show | | |
| | | |_____________| | | | | | | | | | | | | all | | |
| | |_________________| | | | | |______| |______| |______| |______| | |
| |_____________________| |_______| |_____________________________________| |
|___________________________________________________________________________|
typedef enum
{
Tml_Usr_SHOW_FEW_USRS, // Show a few first favers/sharers
Tml_Usr_SHOW_ALL_USRS, // Show all favers/sharers
} Tml_Usr_HowManyUsrs_t;
114. Future objectives and
tasks
“When they ask me when a program will be ready, I
answer: it depends on how much you work on it.”
Richard Stallman
Future objectives and
tasks
“When they ask me when a program will be ready, I
answer: it depends on how much you work on it.”
Richard Stallman
115. Future objectives and tasks
●
Objective 1: Incorporate new functionalities in the platform and improve some
of the existing ones for its integration with gamification, geolocation and EDM
Objective 1 tasks
T1.1 Instructional design + planning T1.5 Improved test exams
T1.2 Monitoring + activity reports T1.6 Scanning homework with the mobile
T1.3 Collaborative edition (wiki) T1.7 Integrated grades
T1.4 Improved schedule + calendar T1.8 Enhanced forums + chat + messages
116. Future objectives and tasks
●
Objective 2: Integration of gamification based on typical game elements in the
functionalities of the web platform and the mobile app
Objective 2 tasks
T2.1 ARS integrated (interactive games with remote control)
T2.2 Scores + badges in global and course functionalities
T2.3 Karma in timeline, forums and files
T2.4 Progress bars in user profiles and courses
117. Future objectives and tasks
●
Objective 3: Integration of indoor geolocation to improve the location of users
in institutional dependencies and attendance control
Objective 3 tasks
T3.1 Database + location prototype T3.5 Possible improvements
•
Alerts about friends that are close
•
Display location on map
•
QR to check-in
•
Store history for activity reports and
recommendations
T3.2 SWAD API functions
T3.3 Integration in SWADroid
T3.4 Add gamification
118. Future objectives and tasks
●
Objective 4: Integrate Educational Data Mining techniques to improve student
assessment, identify study tips, and offer alerts to students and teachers
Objective 4 tasks
T4.1 Study state of the art of EDM (lines of research, articles)
T4.2 Study algorithms + software tools
T4.3 Off-platform experiments (predict + recommend + alert)
T4.4 Select algorithms and integrate them into the platform
119. Future objectives and tasks
●
Objective 5: Analyze educational changes in motivation and
participation, results, and degree of use and satisfaction
after the improvements
Objective 5 tasks
T5.1 Interviews with users prior to the improvement
T5.2 Acquire reference data prior to improvement
T5.3 Measure indicators after improvement: performance, use, motivation ...
T5.4 Disseminate partial and final results
120. Conclusions
“We are free, we can be wide open"
Analyse, The Cranberries
Conclusions
“We are free, we can be wide open"
Analyse, The Cranberries
121. Conclusions
●
We have developed and used an educational platform for 21 years at UGR
(Spain)
●
It’s a fast tool that consumes very few computing resources, making it
suitable for low-cost installations
122. Conclusions
●
It had a great growth between 2005 and 2015
●
In 2015 it was almost used by the entire UGR (≈60K students)
●
In total, it has been used by 195,000 users at UGR
123. Conclusions
●
Since 2010 it’s free software, so anyone can install it (and improve it)
●
Since 2012 it is freely available in the cloud for everyone, in the portal
OpenSWAD.org
●
Of course, you can try it at https://openswad.org/
124. Conclusions
●
Since 2016 its use at UGR has decreased due to institutional support to
another official platform
●
However, we have continued working on the improvement of the platform
●
We will continue its upgrade with gamification, geolocation and data
mining, among other features
125. Thank you!
Antonio Cañas
University of Granada (UGR)
@acanasvargas acanas@ugr.es acanas@openswad.org
https://openswad.org/ @openswad
Thank you!
Antonio Cañas
University of Granada (UGR)
@acanasvargas acanas@ugr.es acanas@openswad.org
https://openswad.org/ @openswad
125
125
Antonio Cañas Vargas