diff --git a/backend/Dockerfile b/backend/Dockerfile index 5074e7d..8635046 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -6,4 +6,4 @@ RUN yarn install COPY src src/ COPY data data/ -CMD ["node", "src/index.js"] +CMD ["npm", "run", "app"] diff --git a/backend/data/timeline.js b/backend/data/timeline.js deleted file mode 100644 index 99857a2..0000000 --- a/backend/data/timeline.js +++ /dev/null @@ -1,2725 +0,0 @@ -module.exports = [ - { - "timestamp": 0, - "events": [ - { - "type": "talk", - "text": [ - "Zet je schrap!", - "We gaan zo beginnen" - ] - } - ] - }, - { - "timestamp": 42, - "events": [ - { - "type": "talk", - "text": [ - "Daar gaan we!", - "Dit was het startsein, je hoeft nog niet te drinken" - ] - }, - { - "type": "song", - "text": [ - "Nena", - "99 Luftballons" - ] - } - ] - }, - { - "timestamp": 108, - "events": [ - { - "type": "shot", - "text": [ - "De eerste!", - "Nog 99 shotjes" - ], - "shotCount": 1 - } - ] - }, - { - "timestamp": 148, - "events": [ - { - "type": "song", - "text": [ - "Hermes House Band", - "Country Roads" - ] - } - ] - }, - { - "timestamp": 167, - "events": [ - { - "type": "shot", - "text": [ - "Nummertje twee!", - "Nog 98 shotjes" - ], - "shotCount": 2 - } - ] - }, - { - "timestamp": 185, - "events": [ - { - "type": "song", - "text": [ - "Vinzzent", - "Dromendans" - ] - } - ] - }, - { - "timestamp": 223, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 97 shotjes" - ], - "shotCount": 3 - }, - { - "type": "song", - "text": [ - "Linda, Roos & Jessica", - "Ademnood" - ] - } - ] - }, - { - "timestamp": 283, - "events": [ - { - "type": "shot", - "text": [ - "Lustrum!", - "Nog 96 shotjes" - ], - "shotCount": 4 - }, - { - "type": "song", - "text": [ - "Peter de Koning", - "Het is altijd lente in de ogen van de tandarts-assistente" - ] - } - ] - }, - { - "timestamp": 340, - "events": [ - { - "type": "shot", - "text": [ - "Niet gooien!", - "Nog 95 shotjes" - ], - "shotCount": 5 - }, - { - "type": "song", - "text": [ - "Liquido", - "Narcotic" - ] - } - ] - }, - { - "timestamp": 412, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 94 shotjes" - ], - "shotCount": 6 - }, - { - "type": "song", - "text": [ - "Snoop Dogg feat. Pharrell", - "Drop It Like It's Hot" - ] - } - ] - }, - { - "timestamp": 449, - "events": [ - { - "type": "song", - "text": [ - "M.O.P.", - "Ante Up" - ] - } - ] - }, - { - "timestamp": 459, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 93 shotjes" - ], - "shotCount": 7 - } - ] - }, - { - "timestamp": 514, - "events": [ - { - "type": "shot", - "text": [ - "Trek een ad!", - "Nog 92 shotjes" - ], - "shotCount": 8 - }, - { - "type": "song", - "text": [ - "Los Del Rio", - "Macarena" - ] - } - ] - }, - { - "timestamp": 560, - "events": [ - { - "type": "song", - "text": [ - "Spice Girls", - "Wannabe" - ] - } - ] - }, - { - "timestamp": 574, - "events": [ - { - "type": "shot", - "text": [ - "We zijn er nog lang niet!", - "Nog 91 shotjes" - ], - "shotCount": 9 - } - ] - }, - { - "timestamp": 617, - "events": [ - { - "type": "song", - "text": [ - "Major Lazer feat. Busy Signal, The Flexican & FS Green", - "Watch Out For This (Bumaye)" - ] - } - ] - }, - { - "timestamp": 635, - "events": [ - { - "type": "shot", - "text": [ - "Nummer tien!", - "Nog 90 shotjes" - ], - "shotCount": 10 - } - ] - }, - { - "timestamp": 647, - "events": [ - { - "type": "time", - "text": [ - "Nog 90 minuten!", - "Geef alles, behalve op" - ] - } - ] - }, - { - "timestamp": 684, - "events": [ - { - "type": "song", - "text": [ - "Kabouter Plop", - "Kabouterdans" - ] - } - ] - }, - { - "timestamp": 699, - "events": [ - { - "type": "shot", - "text": [ - "Met vriendelijke toet!", - "Nog 89 shotjes" - ], - "shotCount": 11 - } - ] - }, - { - "timestamp": 725, - "events": [ - { - "type": "song", - "text": [ - "K3", - "Alle kleuren" - ] - } - ] - }, - { - "timestamp": 756, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 88 shotjes" - ], - "shotCount": 12 - } - ] - }, - { - "timestamp": 757, - "events": [ - { - "type": "song", - "text": [ - "Kinderen voor Kinderen", - "Tietenlied" - ] - } - ] - }, - { - "timestamp": 812, - "events": [ - { - "type": "shot", - "text": [ - "Ongeluksshotje 13!", - "Nog 87 shotjes" - ], - "shotCount": 13 - } - ] - }, - { - "timestamp": 814, - "events": [ - { - "type": "song", - "text": [ - "Guus Meeuwis", - "Het dondert en het bliksemt" - ] - } - ] - }, - { - "timestamp": 820, - "events": [ - { - "type": "talk", - "text": [ - "Carnaval is prachtig!", - "Schrijf je snel in op svia.nl/carnaval" - ] - } - ] - }, - { - "timestamp": 874, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 86 shotjes" - ], - "shotCount": 14 - } - ] - }, - { - "timestamp": 876, - "events": [ - { - "type": "song", - "text": [ - "Harry Vermeegen", - "1-2-3-4 Dennis bier" - ] - } - ] - }, - { - "timestamp": 906, - "events": [ - { - "type": "song", - "text": [ - "Puhdys", - "Hey, wir woll’n die Eisbär'n sehn!" - ] - } - ] - }, - { - "timestamp": 935, - "events": [ - { - "type": "shot", - "text": [ - "Fünfzehn!", - "Nog 85 shotjes" - ], - "shotCount": 15 - } - ] - }, - { - "timestamp": 966, - "events": [ - { - "type": "song", - "text": [ - "DJ Ötzi", - "Burger Dance" - ] - } - ] - }, - { - "timestamp": 995, - "events": [ - { - "type": "shot", - "text": [ - "Toet!", - "Nog 84 shotjes" - ], - "shotCount": 16 - } - ] - }, - { - "timestamp": 996, - "events": [ - { - "type": "song", - "text": [ - "Mickie Krause", - "Hütte auf der Alm" - ] - } - ] - }, - { - "timestamp": 1030, - "events": [ - { - "type": "song", - "text": [ - "Ali B & Yes-R & The Partysquad", - "Rampeneren" - ] - } - ] - }, - { - "timestamp": 1046, - "events": [ - { - "type": "shot", - "text": [ - "Zuipen!", - "Nog 83 shotjes" - ], - "shotCount": 17 - } - ] - }, - { - "timestamp": 1107, - "events": [ - { - "type": "shot", - "text": [ - "Met dank aan bestuur 18; super 'vo", - "Nog 82 shotjes" - ], - "shotCount": 18 - }, - { - "type": "song", - "text": [ - "Martin Solveig", - "Intoxicated" - ] - } - ] - }, - { - "timestamp": 1137, - "events": [ - { - "type": "song", - "text": [ - "Nicki Minaj", - "Starships" - ] - } - ] - }, - { - "timestamp": 1173, - "events": [ - { - "type": "shot", - "text": [ - "Laatste shotje als tiener!", - "Nog 81 shotjes" - ], - "shotCount": 19 - } - ] - }, - { - "timestamp": 1222, - "events": [ - { - "type": "song", - "text": [ - "2Unlimited", - "Get Ready For This" - ] - } - ] - }, - { - "timestamp": 1233, - "events": [ - { - "type": "time", - "text": [ - "Nog 80 minuten!", - "Al 19 shotjes achter de rug" - ] - } - ] - }, - { - "timestamp": 1235, - "events": [ - { - "type": "shot", - "text": [ - "Adje!", - "Nog 80 shotjes" - ], - "shotCount": 20 - } - ] - }, - { - "timestamp": 1275, - "events": [ - { - "type": "song", - "text": [ - "The Village People", - "YMCA" - ] - } - ] - }, - { - "timestamp": 1288, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 79 shotjes" - ], - "shotCount": 21 - } - ] - }, - { - "timestamp": 1348, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 78 shotjes" - ], - "shotCount": 22 - } - ] - }, - { - "timestamp": 1350, - "events": [ - { - "type": "song", - "text": [ - "Carly Rae Jepsen ft Owl City", - "It's Always A Good Time" - ] - } - ] - }, - { - "timestamp": 1395, - "events": [ - { - "type": "song", - "text": [ - "Avicii", - "Levels" - ] - } - ] - }, - { - "timestamp": 1411, - "events": [ - { - "type": "shot", - "text": [ - "Claxon!", - "Nog 77 shotjes" - ], - "shotCount": 23 - } - ] - }, - { - "timestamp": 1456, - "events": [ - { - "type": "song", - "text": [ - "Flo-Rida feat. T-Pain", - "Low" - ] - } - ] - }, - { - "timestamp": 1471, - "events": [ - { - "type": "shot", - "text": [ - "En nu even op standje maximaal!", - "Nog 76 shotjes" - ], - "shotCount": 24 - } - ] - }, - { - "timestamp": 1486, - "events": [ - { - "type": "song", - "text": [ - "Taio Cruz", - "Hangover" - ] - } - ] - }, - { - "timestamp": 1522, - "events": [ - { - "type": "talk", - "text": [ - "Dit is nog het rustige stukje!", - "Zet hem maar op de bonk-bonk" - ] - } - ] - }, - { - "timestamp": 1530, - "events": [ - { - "type": "shot", - "text": [ - "Halve Abraham!", - "Nog 75 shotjes" - ], - "shotCount": 25 - } - ] - }, - { - "timestamp": 1545, - "events": [ - { - "type": "song", - "text": [ - "LMFAO", - "Party Rock Anthem" - ] - } - ] - }, - { - "timestamp": 1594, - "events": [ - { - "type": "shot", - "text": [ - "Hoch die Hände!", - "Nog 74 shotjes" - ], - "shotCount": 26 - }, - { - "type": "song", - "text": [ - "Hans Entertainment vs. Finger & Kadel", - "Hoch die Hände" - ] - } - ] - }, - { - "timestamp": 1623, - "events": [ - { - "type": "song", - "text": [ - "Galantis", - "No Money" - ] - } - ] - }, - { - "timestamp": 1653, - "events": [ - { - "type": "shot", - "text": [ - "Voel je 'm al?", - "Nog 73 shotjes" - ], - "shotCount": 27 - } - ] - }, - { - "timestamp": 1683, - "events": [ - { - "type": "song", - "text": [ - "Kid Cudi", - "Pursuit of Happiness (Steve Aoki remix)" - ] - } - ] - }, - { - "timestamp": 1712, - "events": [ - { - "type": "shot", - "text": [ - "Project X!", - "Nog 72 shotjes" - ], - "shotCount": 28 - } - ] - }, - { - "timestamp": 1741, - "events": [ - { - "type": "song", - "text": [ - "Yeah Yeah Yeahs", - "Heads Will Roll (A-Trak remix)" - ] - } - ] - }, - { - "timestamp": 1769, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 71 shotjes" - ], - "shotCount": 29 - } - ] - }, - { - "timestamp": 1814, - "events": [ - { - "type": "song", - "text": [ - "Michael Calfan", - "Resurrection" - ] - } - ] - }, - { - "timestamp": 1825, - "events": [ - { - "type": "time", - "text": [ - "Nog 70 minuten!", - "Half uurtje zit erop" - ] - } - ] - }, - { - "timestamp": 1829, - "events": [ - { - "type": "shot", - "text": [ - "Toet!", - "Nog 70 shotjes" - ], - "shotCount": 30 - } - ] - }, - { - "timestamp": 1858, - "events": [ - { - "type": "song", - "text": [ - "Basto!", - "Again and Again" - ] - } - ] - }, - { - "timestamp": 1887, - "events": [ - { - "type": "shot", - "text": [ - "Over de dertig!", - "Nog 69 (hehe) shotjes" - ], - "shotCount": 31 - } - ] - }, - { - "timestamp": 1916, - "events": [ - { - "type": "song", - "text": [ - "David Guetaa feat. Sia", - "Titanium" - ] - } - ] - }, - { - "timestamp": 1945, - "events": [ - { - "type": "shot", - "text": [ - "Trek een ad!", - "Nog 68 shotjes" - ], - "shotCount": 32 - } - ] - }, - { - "timestamp": 1959, - "events": [ - { - "type": "song", - "text": [ - "Gala", - "Freed From Desire" - ] - } - ] - }, - { - "timestamp": 2004, - "events": [ - { - "type": "shot", - "text": [ - "Nummertje 33!", - "Nog 67 shotjes!" - ], - "shotCount": 33 - } - ] - }, - { - "timestamp": 2034, - "events": [ - { - "type": "song", - "text": [ - "Wolter Kroes", - "Viva Hollandia" - ] - } - ] - }, - { - "timestamp": 2064, - "events": [ - { - "type": "shot", - "text": [ - "Voor het vaderland!", - "Nog 66 shotjes" - ], - "shotCount": 34 - } - ] - }, - { - "timestamp": 2125, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 65 shotjes" - ], - "shotCount": 35 - } - ] - }, - { - "timestamp": 2128, - "events": [ - { - "type": "song", - "text": [ - "Westlife", - "Uptown Girl" - ] - } - ] - }, - { - "timestamp": 2179, - "events": [ - { - "type": "song", - "text": [ - "Aqua", - "Barbie Girl" - ] - } - ] - }, - { - "timestamp": 2194, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 64 shotjes" - ], - "shotCount": 36 - } - ] - }, - { - "timestamp": 2225, - "events": [ - { - "type": "song", - "text": [ - "Guillerma & Tropical Danny", - "Toppertje" - ] - } - ] - }, - { - "timestamp": 2245, - "events": [ - { - "type": "shot", - "text": [ - "In dat keelgaatje!", - "Nog 63 shotjes" - ], - "shotCount": 37 - } - ] - }, - { - "timestamp": 2305, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 62 shotjes" - ], - "shotCount": 38 - }, - { - "type": "song", - "text": [ - "The Bloody Beetroots feat. Steve Aoki", - "Warp 1.9" - ] - } - ] - }, - { - "timestamp": 2374, - "events": [ - { - "type": "shot", - "text": [ - "Toet!", - "Nog 61 shotjes" - ], - "shotCount": 39 - }, - { - "type": "song", - "text": [ - "David Guetta & Showtek feat. Vassy", - "Bad" - ] - } - ] - }, - { - "timestamp": 2431, - "events": [ - { - "type": "shot", - "text": [ - "40 alweer!", - "Nog 60 shotjes" - ], - "shotCount": 40 - }, - { - "type": "song", - "text": [ - "Showtek & Justin Prime", - "Cannonball" - ] - } - ] - }, - { - "timestamp": 2444, - "events": [ - { - "type": "time", - "text": [ - "Nog 60 minuten!", - "Een klein uurtje" - ] - } - ] - }, - { - "timestamp": 2460, - "events": [ - { - "type": "song", - "text": [ - "Die Atzen", - "Disco Pogo" - ] - } - ] - }, - { - "timestamp": 2489, - "events": [ - { - "type": "shot", - "text": [ - "Zuipen!", - "Nog 59 shotjes" - ], - "shotCount": 41 - } - ] - }, - { - "timestamp": 2534, - "events": [ - { - "type": "song", - "text": [ - "Lorenz Büffel", - "Johnny Däpp" - ] - } - ] - }, - { - "timestamp": 2555, - "events": [ - { - "type": "shot", - "text": [ - "Dab dat glas naar je mond!", - "Nog 58 shotjes" - ], - "shotCount": 42 - } - ] - }, - { - "timestamp": 2587, - "events": [ - { - "type": "song", - "text": [ - "Zware Jongens", - "Jodeljump" - ] - } - ] - }, - { - "timestamp": 2606, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 57 shotjes" - ], - "shotCount": 43 - } - ] - }, - { - "timestamp": 2635, - "events": [ - { - "type": "song", - "text": [ - "Parla & Pardoux", - "Liberté" - ] - } - ] - }, - { - "timestamp": 2664, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 56 shotjes" - ], - "shotCount": 44 - } - ] - }, - { - "timestamp": 2695, - "events": [ - { - "type": "song", - "text": [ - "Markus Becker", - "Das rote Pferd" - ] - } - ] - }, - { - "timestamp": 2729, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 55 shotjes" - ], - "shotCount": 45 - } - ] - }, - { - "timestamp": 2743, - "events": [ - { - "type": "song", - "text": [ - "Olaf Henning", - "Cowboy und Indianer" - ] - } - ] - }, - { - "timestamp": 2784, - "events": [ - { - "type": "shot", - "text": [ - "Adje!", - "Nog 54 shotjes" - ], - "shotCount": 46 - } - ] - }, - { - "timestamp": 2785, - "events": [ - { - "type": "song", - "text": [ - "Ch!pz", - "Cowboy" - ] - } - ] - }, - { - "timestamp": 2824, - "events": [ - { - "type": "song", - "text": [ - "Toy-Box", - "Tarzan & Jane" - ] - } - ] - }, - { - "timestamp": 2850, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 53 shotjes" - ], - "shotCount": 47 - } - ] - }, - { - "timestamp": 2879, - "events": [ - { - "type": "song", - "text": [ - "Toy-Box", - "Sailor Song" - ] - } - ] - }, - { - "timestamp": 2919, - "events": [ - { - "type": "shot", - "text": [ - "Bijna op de helft!", - "Nog 52 shotjes" - ], - "shotCount": 48 - } - ] - }, - { - "timestamp": 2921, - "events": [ - { - "type": "song", - "text": [ - "Vengaboys", - "Boom, Boom, Boom, Boom!!" - ] - } - ] - }, - { - "timestamp": 2975, - "events": [ - { - "type": "shot", - "text": [ - "Bam!", - "Nog 51 shotjes" - ], - "shotCount": 49 - } - ] - }, - { - "timestamp": 2998, - "events": [ - { - "type": "song", - "text": [ - "Vengaboys", - "To Brazil!" - ] - } - ] - }, - { - "timestamp": 3024, - "events": [ - { - "type": "time", - "text": [ - "Nog 50 minuten!", - "We zijn op de helft!" - ] - } - ] - }, - { - "timestamp": 3039, - "events": [ - { - "type": "shot", - "text": [ - "Abraham!", - "Nog 50 shotjes" - ], - "shotCount": 50 - } - ] - }, - { - "timestamp": 3070, - "events": [ - { - "type": "song", - "text": [ - "Snollebollekes", - "Bam bam (bam)" - ] - } - ] - }, - { - "timestamp": 3104, - "events": [ - { - "type": "shot", - "text": [ - "Tweede helft!", - "Nog 49 shotjes" - ], - "shotCount": 51 - } - ] - }, - { - "timestamp": 3120, - "events": [ - { - "type": "song", - "text": [ - "Def Rhymz", - "Schudden" - ] - } - ] - }, - { - "timestamp": 3160, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 48 shotjes" - ], - "shotCount": 52 - } - ] - }, - { - "timestamp": 3190, - "events": [ - { - "type": "song", - "text": [ - "Cooldown Café", - "Hey baby" - ] - } - ] - }, - { - "timestamp": 3215, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 47 shotjes" - ], - "shotCount": 53 - } - ] - }, - { - "timestamp": 3232, - "events": [ - { - "type": "song", - "text": [ - "Gebroeders Ko", - "Schatje, mag ik je foto" - ] - } - ] - }, - { - "timestamp": 3279, - "events": [ - { - "type": "shot", - "text": [ - "Zuipen!", - "Nog 46 shotjes" - ], - "shotCount": 54 - }, - { - "type": "song", - "text": [ - "Guus Meeuwis", - "Het is een nacht" - ] - } - ] - }, - { - "timestamp": 3341, - "events": [ - { - "type": "shot", - "text": [ - "Adje!", - "Nog 45 shotjes" - ], - "shotCount": 55 - } - ] - }, - { - "timestamp": 3356, - "events": [ - { - "type": "song", - "text": [ - "Tom Waes", - "Dos cervezas" - ] - } - ] - }, - { - "timestamp": 3398, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 44 shotjes" - ], - "shotCount": 56 - } - ] - }, - { - "timestamp": 3412, - "events": [ - { - "type": "song", - "text": [ - "Peter Wackel", - "Vollgas" - ] - } - ] - }, - { - "timestamp": 3439, - "events": [ - { - "type": "song", - "text": [ - "Peter Wackel", - "Scheiß drauf!" - ] - } - ] - }, - { - "timestamp": 3465, - "events": [ - { - "type": "shot", - "text": [ - "Hard gaan!", - "Nog 43 shotjes" - ], - "shotCount": 57 - } - ] - }, - { - "timestamp": 3467, - "events": [ - { - "type": "song", - "text": [ - "Ikke Hüftgold", - "Dicke titten, kartoffelsalat" - ] - } - ] - }, - { - "timestamp": 3520, - "events": [ - { - "type": "shot", - "text": [ - "Hap, slok, weg!", - "Nog 42 shotjes" - ], - "shotCount": 58 - } - ] - }, - { - "timestamp": 3521, - "events": [ - { - "type": "song", - "text": [ - "Tim Toupet", - "Fliegerlied (So ein schöner Tag)" - ] - } - ] - }, - { - "timestamp": 3564, - "events": [ - { - "type": "song", - "text": [ - "Cooldown Café", - "Met z'n allen" - ] - } - ] - }, - { - "timestamp": 3577, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 41 shotjes" - ], - "shotCount": 59 - } - ] - }, - { - "timestamp": 3636, - "events": [ - { - "type": "time", - "text": [ - "Nog 40 minuten!", - "Uurtje achter de rug" - ] - } - ] - }, - { - "timestamp": 3643, - "events": [ - { - "type": "shot", - "text": [ - "Glas 60!", - "Nog 40 shotjes" - ], - "shotCount": 60 - } - ] - }, - { - "timestamp": 3659, - "events": [ - { - "type": "song", - "text": [ - "The Partysquad feat. Jayh, Sjaak & Reverse", - "Helemaal naar de klote" - ] - } - ] - }, - { - "timestamp": 3687, - "events": [ - { - "type": "song", - "text": [ - "K-Liber", - "Viben" - ] - } - ] - }, - { - "timestamp": 3700, - "events": [ - { - "type": "shot", - "text": [ - "Adje!", - "Nog 39 shotjes" - ], - "shotCount": 61 - } - ] - }, - { - "timestamp": 3753, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 38 shotjes" - ], - "shotCount": 62 - } - ] - }, - { - "timestamp": 3755, - "events": [ - { - "type": "song", - "text": [ - "FeestDJRuud & Dirtcaps feat. Sjaak & Kraantje Pappie", - "Weekend" - ] - } - ] - }, - { - "timestamp": 3808, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 37 shotjes" - ], - "shotCount": 63 - }, - { - "type": "song", - "text": [ - "Lawineboys", - "Joost" - ] - } - ] - }, - { - "timestamp": 3860, - "events": [ - { - "type": "song", - "text": [ - "Gebroeders Ko", - "Ik heb een toeter op mijn waterscooter" - ] - } - ] - }, - { - "timestamp": 3874, - "events": [ - { - "type": "shot", - "text": [ - "Toe-toe-toeter!", - "Nog 36 shotjes" - ], - "shotCount": 64 - } - ] - }, - { - "timestamp": 3904, - "events": [ - { - "type": "song", - "text": [ - "Gebroeders Ko", - "Tringeling" - ] - } - ] - }, - { - "timestamp": 3931, - "events": [ - { - "type": "shot", - "text": [ - "Tringeling!", - "Nog 35 shotjes" - ], - "shotCount": 65 - } - ] - }, - { - "timestamp": 3975, - "events": [ - { - "type": "song", - "text": [ - "Basshunter", - "Boten Anna" - ] - } - ] - }, - { - "timestamp": 3988, - "events": [ - { - "type": "shot", - "text": [ - "Zuipen!", - "Nog 34 shotjes" - ], - "shotCount": 66 - } - ] - }, - { - "timestamp": 4029, - "events": [ - { - "type": "song", - "text": [ - "Lawineboys", - "Wat zullen we drinken" - ] - } - ] - }, - { - "timestamp": 4050, - "events": [ - { - "type": "shot", - "text": [ - "Dorst!", - "Nog 33 shotjes" - ], - "shotCount": 67 - } - ] - }, - { - "timestamp": 4081, - "events": [ - { - "type": "song", - "text": [ - "Lamme Frans", - "Wakker met een biertje!" - ] - } - ] - }, - { - "timestamp": 4113, - "events": [ - { - "type": "shot", - "text": [ - "Biertje in de hand...", - "Nog 32 shotjes" - ], - "shotCount": 68 - } - ] - }, - { - "timestamp": 4124, - "events": [ - { - "type": "song", - "text": [ - "Lawineboys feat. DJ Jerome", - "Seks met die kale" - ] - } - ] - }, - { - "timestamp": 4175, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 31 shotjes" - ], - "shotCount": 69 - } - ] - }, - { - "timestamp": 4177, - "events": [ - { - "type": "song", - "text": [ - "Zombie Nation", - "Kernkraft 400" - ] - } - ] - }, - { - "timestamp": 4214, - "events": [ - { - "type": "time", - "text": [ - "Nog 30 minuten!", - "Half uurtje nog maar" - ] - } - ] - }, - { - "timestamp": 4228, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 30 shotjes" - ], - "shotCount": 70 - } - ] - }, - { - "timestamp": 4230, - "events": [ - { - "type": "song", - "text": [ - "DJ Boozywoozy", - "Party Affair" - ] - } - ] - }, - { - "timestamp": 4280, - "events": [ - { - "type": "shot", - "text": [ - "Tik maar achterover!", - "Nog 29 shotjes" - ], - "shotCount": 71 - } - ] - }, - { - "timestamp": 4289, - "events": [ - { - "type": "song", - "text": [ - "2Unlimited", - "No Limit" - ] - } - ] - }, - { - "timestamp": 4341, - "events": [ - { - "type": "shot", - "text": [ - "Alcoholic party!", - "Nog 28 shotjes" - ], - "shotCount": 72 - } - ] - }, - { - "timestamp": 4343, - "events": [ - { - "type": "song", - "text": [ - "DJ Kicken vs. MC-Q", - "Ain't No Party" - ] - } - ] - }, - { - "timestamp": 4408, - "events": [ - { - "type": "shot", - "text": [ - "Toet!", - "Nog 27 shotjes" - ], - "shotCount": 73 - } - ] - }, - { - "timestamp": 4411, - "events": [ - { - "type": "song", - "text": [ - "Jan Wayne", - "Becuase the Night" - ] - } - ] - }, - { - "timestamp": 4455, - "events": [ - { - "type": "song", - "text": [ - "Cascada", - "Everytime We Touch" - ] - } - ] - }, - { - "timestamp": 4467, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 26 shotjes" - ], - "shotCount": 74 - } - ] - }, - { - "timestamp": 4510, - "events": [ - { - "type": "song", - "text": [ - "Gigi D'Agostino", - "L'amour toujours" - ] - } - ] - }, - { - "timestamp": 4521, - "events": [ - { - "type": "shot", - "text": [ - "Shotje 75!", - "Nog 25 shotjes" - ], - "shotCount": 75 - } - ] - }, - { - "timestamp": 4573, - "events": [ - { - "type": "song", - "text": [ - "Jason Paige", - "Gotta Catch 'M All" - ] - } - ] - }, - { - "timestamp": 4578, - "events": [ - { - "type": "shot", - "text": [ - "Trek een ad!", - "Nog 24 shotjes" - ], - "shotCount": 76 - } - ] - }, - { - "timestamp": 4636, - "events": [ - { - "type": "song", - "text": [ - "Scooter", - "How Much Is The Fish" - ] - } - ] - }, - { - "timestamp": 4645, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 23 shotjes" - ], - "shotCount": 77 - } - ] - }, - { - "timestamp": 4675, - "events": [ - { - "type": "song", - "text": [ - "Scooter", - "Weekend" - ] - } - ] - }, - { - "timestamp": 4701, - "events": [ - { - "type": "shot", - "text": [ - "scToeter!", - "Nog 22 shotjes" - ], - "shotCount": 78 - } - ] - }, - { - "timestamp": 4714, - "events": [ - { - "type": "song", - "text": [ - "Scooter", - "One (Always Hardcore)" - ] - } - ] - }, - { - "timestamp": 4764, - "events": [ - { - "type": "shot", - "text": [ - "En door!", - "Nog 21 shotjes" - ], - "shotCount": 79 - } - ] - }, - { - "timestamp": 4766, - "events": [ - { - "type": "song", - "text": [ - "Scooter", - "Maria (I Like It Loud)" - ] - } - ] - }, - { - "timestamp": 4815, - "events": [ - { - "type": "time", - "text": [ - "Nog 20 minuten!", - "Geef alles, behalve over" - ] - } - ] - }, - { - "timestamp": 4818, - "events": [ - { - "type": "song", - "text": [ - "Scooter", - "J'adore Hardcore" - ] - } - ] - }, - { - "timestamp": 4829, - "events": [ - { - "type": "shot", - "text": [ - "Al 80 in de mik!", - "Nog 20 shotjes" - ], - "shotCount": 80 - } - ] - }, - { - "timestamp": 4860, - "events": [ - { - "type": "song", - "text": [ - "Wildstylez feat. Niels Geusebroek", - "Year of Summer" - ] - } - ] - }, - { - "timestamp": 4888, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 19 shotjes" - ], - "shotCount": 81 - } - ] - }, - { - "timestamp": 4929, - "events": [ - { - "type": "song", - "text": [ - "Brennan Heart & Wildstylez", - "Lose My Mind" - ] - } - ] - }, - { - "timestamp": 4953, - "events": [ - { - "type": "shot", - "text": [ - "Bakken vouwen!", - "Nog 18 shotjes" - ], - "shotCount": 82 - } - ] - }, - { - "timestamp": 5004, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 17 shotjes" - ], - "shotCount": 83 - } - ] - }, - { - "timestamp": 5006, - "events": [ - { - "type": "song", - "text": [ - "Starkoo", - "Ik wil je" - ] - } - ] - }, - { - "timestamp": 5059, - "events": [ - { - "type": "song", - "text": [ - "Feestteam", - "Let It Be" - ] - } - ] - }, - { - "timestamp": 5071, - "events": [ - { - "type": "shot", - "text": [ - "Let it bier!", - "Nog 16 shotjes" - ], - "shotCount": 84 - } - ] - }, - { - "timestamp": 5125, - "events": [ - { - "type": "shot", - "text": [ - "Adje numero 85!", - "Nog 15 shotjes" - ], - "shotCount": 85 - } - ] - }, - { - "timestamp": 5179, - "events": [ - { - "type": "song", - "text": [ - "DJ Nikolai & DJ Mike van Dijk", - "Piano Man" - ] - } - ] - }, - { - "timestamp": 5188, - "events": [ - { - "type": "shot", - "text": [ - "Toet!", - "Nog 14 shotjes" - ], - "shotCount": 86 - } - ] - }, - { - "timestamp": 5190, - "events": [ - { - "type": "talk", - "text": [ - "Gewoon doorgaan!", - "Deze Piano Man telt niet" - ] - } - ] - }, - { - "timestamp": 5237, - "events": [ - { - "type": "song", - "text": [ - "Robbie Williams", - "Angels" - ] - } - ] - }, - { - "timestamp": 5243, - "events": [ - { - "type": "shot", - "text": [ - "Drinken!", - "Nog 13 shotjes" - ], - "shotCount": 87 - } - ] - }, - { - "timestamp": 5278, - "events": [ - { - "type": "song", - "text": [ - "Enrique Iglesias", - "Hero" - ] - } - ] - }, - { - "timestamp": 5308, - "events": [ - { - "type": "shot", - "text": [ - "I can't be your biero!", - "Nog 12 shotjes" - ], - "shotCount": 88 - } - ] - }, - { - "timestamp": 5331, - "events": [ - { - "type": "song", - "text": [ - "Whitney Houston", - "I Will Always Love You" - ] - } - ] - }, - { - "timestamp": 5374, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 11 shotjes" - ], - "shotCount": 89 - } - ] - }, - { - "timestamp": 5380, - "events": [ - { - "type": "song", - "text": [ - "Mariah Carey", - "All I Want For Christmas" - ] - } - ] - }, - { - "timestamp": 5431, - "events": [ - { - "type": "shot", - "text": [ - "90 in de keel, hierna niet veel!", - "Nog 10 shotjes" - ], - "shotCount": 90 - } - ] - }, - { - "timestamp": 5441, - "events": [ - { - "type": "time", - "text": [ - "Nog 10 minuten!", - "De laatste loodjes" - ] - } - ] - }, - { - "timestamp": 5444, - "events": [ - { - "type": "song", - "text": [ - "Kraantje Pappie", - "Feesttent (FeestDJRuud remix)" - ] - } - ] - }, - { - "timestamp": 5488, - "events": [ - { - "type": "shot", - "text": [ - "Zuip je uit de dubbele cijfers!", - "Nog 9 shotjes" - ], - "shotCount": 91 - } - ] - }, - { - "timestamp": 5490, - "events": [ - { - "type": "song", - "text": [ - "New Kids feat. DJ Paul Elstak", - "Turbo" - ] - } - ] - }, - { - "timestamp": 5556, - "events": [ - { - "type": "shot", - "text": [ - "Zuipen!", - "Nog 8 shotjes" - ], - "shotCount": 92 - } - ] - }, - { - "timestamp": 5558, - "events": [ - { - "type": "song", - "text": [ - "Lipstick", - "I'm a Raver" - ] - } - ] - }, - { - "timestamp": 5591, - "events": [ - { - "type": "song", - "text": [ - "Nakatomi", - "Children of the Night" - ] - } - ] - }, - { - "timestamp": 5612, - "events": [ - { - "type": "shot", - "text": [ - "Pweeeep!", - "Nog 7 shotjes" - ], - "shotCount": 93 - } - ] - }, - { - "timestamp": 5614, - "events": [ - { - "type": "song", - "text": [ - "Charly Lownoise & Mental Theo", - "Wonderful Days" - ] - } - ] - }, - { - "timestamp": 5659, - "events": [ - { - "type": "song", - "text": [ - "DJ Paul Elstak", - "Luv You More" - ] - } - ] - }, - { - "timestamp": 5667, - "events": [ - { - "type": "shot", - "text": [ - "Bijna daar!", - "Nog 6 shotjes" - ], - "shotCount": 94 - } - ] - }, - { - "timestamp": 5704, - "events": [ - { - "type": "song", - "text": [ - "DJ Paul Elstak", - "Rainbow In The Sky" - ] - } - ] - }, - { - "timestamp": 5716, - "events": [ - { - "type": "time", - "text": [ - "Nog 5 minuten!", - "Zet de shotjes maar klaar" - ] - } - ] - }, - { - "timestamp": 5731, - "events": [ - { - "type": "shot", - "text": [ - "Toeter!", - "Nog 5 shotjes" - ], - "shotCount": 95 - } - ] - }, - { - "timestamp": 5733, - "events": [ - { - "type": "song", - "text": [ - "Evil Activities", - "Nobody Said It Was Easy" - ] - } - ] - }, - { - "timestamp": 5783, - "events": [ - { - "type": "shot", - "text": [ - "Slok 96!", - "Nog 4 shotjes" - ], - "shotCount": 96 - } - ] - }, - { - "timestamp": 5827, - "events": [ - { - "type": "song", - "text": [ - "Melrose", - "O" - ] - } - ] - }, - { - "timestamp": 5846, - "events": [ - { - "type": "shot", - "text": [ - "Voor de 97e keer!", - "Nog 3 shotjes" - ], - "shotCount": 97 - } - ] - }, - { - "timestamp": 5855, - "events": [ - { - "type": "song", - "text": [ - "Backstreet Boys", - "I Want It That Way" - ] - } - ] - }, - { - "timestamp": 5902, - "events": [ - { - "type": "shot", - "text": [ - "Nummer 98!", - "Nog 2 shotjes" - ], - "shotCount": 98 - } - ] - }, - { - "timestamp": 5933, - "events": [ - { - "type": "song", - "text": [ - "R. Kelly", - "The World's Greatest" - ] - } - ] - }, - { - "timestamp": 5970, - "events": [ - { - "type": "shot", - "text": [ - "Nummer 99!", - "Nog 1 shotje" - ], - "shotCount": 99 - } - ] - }, - { - "timestamp": 6020, - "events": [ - { - "type": "shot", - "text": [ - "CENTURION!", - "Geen shots meer" - ], - "shotCount": 100 - } - ] - } -] diff --git a/backend/data/timelines.js b/backend/data/timelines.js new file mode 100644 index 0000000..801091b --- /dev/null +++ b/backend/data/timelines.js @@ -0,0 +1,2733 @@ +module.exports = { + 'timelines': [ + { + 'name': 'Centurion', + 'feed': [ + + { + "timestamp": 0, + "events": [ + { + "type": "talk", + "text": [ + "Zet je schrap!", + "We gaan zo beginnen" + ] + } + ] + }, + { + "timestamp": 42, + "events": [ + { + "type": "talk", + "text": [ + "Daar gaan we!", + "Dit was het startsein, je hoeft nog niet te drinken" + ] + }, + { + "type": "song", + "text": [ + "Nena", + "99 Luftballons" + ] + } + ] + }, + { + "timestamp": 108, + "events": [ + { + "type": "shot", + "text": [ + "De eerste!", + "Nog 99 shotjes" + ], + "shotCount": 1 + } + ] + }, + { + "timestamp": 148, + "events": [ + { + "type": "song", + "text": [ + "Hermes House Band", + "Country Roads" + ] + } + ] + }, + { + "timestamp": 167, + "events": [ + { + "type": "shot", + "text": [ + "Nummertje twee!", + "Nog 98 shotjes" + ], + "shotCount": 2 + } + ] + }, + { + "timestamp": 185, + "events": [ + { + "type": "song", + "text": [ + "Vinzzent", + "Dromendans" + ] + } + ] + }, + { + "timestamp": 223, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 97 shotjes" + ], + "shotCount": 3 + }, + { + "type": "song", + "text": [ + "Linda, Roos & Jessica", + "Ademnood" + ] + } + ] + }, + { + "timestamp": 283, + "events": [ + { + "type": "shot", + "text": [ + "Lustrum!", + "Nog 96 shotjes" + ], + "shotCount": 4 + }, + { + "type": "song", + "text": [ + "Peter de Koning", + "Het is altijd lente in de ogen van de tandarts-assistente" + ] + } + ] + }, + { + "timestamp": 340, + "events": [ + { + "type": "shot", + "text": [ + "Niet gooien!", + "Nog 95 shotjes" + ], + "shotCount": 5 + }, + { + "type": "song", + "text": [ + "Liquido", + "Narcotic" + ] + } + ] + }, + { + "timestamp": 412, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 94 shotjes" + ], + "shotCount": 6 + }, + { + "type": "song", + "text": [ + "Snoop Dogg feat. Pharrell", + "Drop It Like It's Hot" + ] + } + ] + }, + { + "timestamp": 449, + "events": [ + { + "type": "song", + "text": [ + "M.O.P.", + "Ante Up" + ] + } + ] + }, + { + "timestamp": 459, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 93 shotjes" + ], + "shotCount": 7 + } + ] + }, + { + "timestamp": 514, + "events": [ + { + "type": "shot", + "text": [ + "Trek een ad!", + "Nog 92 shotjes" + ], + "shotCount": 8 + }, + { + "type": "song", + "text": [ + "Los Del Rio", + "Macarena" + ] + } + ] + }, + { + "timestamp": 560, + "events": [ + { + "type": "song", + "text": [ + "Spice Girls", + "Wannabe" + ] + } + ] + }, + { + "timestamp": 574, + "events": [ + { + "type": "shot", + "text": [ + "We zijn er nog lang niet!", + "Nog 91 shotjes" + ], + "shotCount": 9 + } + ] + }, + { + "timestamp": 617, + "events": [ + { + "type": "song", + "text": [ + "Major Lazer feat. Busy Signal, The Flexican & FS Green", + "Watch Out For This (Bumaye)" + ] + } + ] + }, + { + "timestamp": 635, + "events": [ + { + "type": "shot", + "text": [ + "Nummer tien!", + "Nog 90 shotjes" + ], + "shotCount": 10 + } + ] + }, + { + "timestamp": 647, + "events": [ + { + "type": "time", + "text": [ + "Nog 90 minuten!", + "Geef alles, behalve op" + ] + } + ] + }, + { + "timestamp": 684, + "events": [ + { + "type": "song", + "text": [ + "Kabouter Plop", + "Kabouterdans" + ] + } + ] + }, + { + "timestamp": 699, + "events": [ + { + "type": "shot", + "text": [ + "Met vriendelijke toet!", + "Nog 89 shotjes" + ], + "shotCount": 11 + } + ] + }, + { + "timestamp": 725, + "events": [ + { + "type": "song", + "text": [ + "K3", + "Alle kleuren" + ] + } + ] + }, + { + "timestamp": 756, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 88 shotjes" + ], + "shotCount": 12 + } + ] + }, + { + "timestamp": 757, + "events": [ + { + "type": "song", + "text": [ + "Kinderen voor Kinderen", + "Tietenlied" + ] + } + ] + }, + { + "timestamp": 812, + "events": [ + { + "type": "shot", + "text": [ + "Ongeluksshotje 13!", + "Nog 87 shotjes" + ], + "shotCount": 13 + } + ] + }, + { + "timestamp": 814, + "events": [ + { + "type": "song", + "text": [ + "Guus Meeuwis", + "Het dondert en het bliksemt" + ] + } + ] + }, + { + "timestamp": 820, + "events": [ + { + "type": "talk", + "text": [ + "Carnaval is prachtig!", + "Leve de vervoerie" + ] + } + ] + }, + { + "timestamp": 874, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 86 shotjes" + ], + "shotCount": 14 + } + ] + }, + { + "timestamp": 876, + "events": [ + { + "type": "song", + "text": [ + "Harry Vermeegen", + "1-2-3-4 Dennis bier" + ] + } + ] + }, + { + "timestamp": 906, + "events": [ + { + "type": "song", + "text": [ + "Puhdys", + "Hey, wir woll’n die Eisbär'n sehn!" + ] + } + ] + }, + { + "timestamp": 935, + "events": [ + { + "type": "shot", + "text": [ + "Fünfzehn!", + "Nog 85 shotjes" + ], + "shotCount": 15 + } + ] + }, + { + "timestamp": 966, + "events": [ + { + "type": "song", + "text": [ + "DJ Ötzi", + "Burger Dance" + ] + } + ] + }, + { + "timestamp": 995, + "events": [ + { + "type": "shot", + "text": [ + "Toet!", + "Nog 84 shotjes" + ], + "shotCount": 16 + } + ] + }, + { + "timestamp": 996, + "events": [ + { + "type": "song", + "text": [ + "Mickie Krause", + "Hütte auf der Alm" + ] + } + ] + }, + { + "timestamp": 1030, + "events": [ + { + "type": "song", + "text": [ + "Ali B & Yes-R & The Partysquad", + "Rampeneren" + ] + } + ] + }, + { + "timestamp": 1046, + "events": [ + { + "type": "shot", + "text": [ + "Zuipen!", + "Nog 83 shotjes" + ], + "shotCount": 17 + } + ] + }, + { + "timestamp": 1107, + "events": [ + { + "type": "shot", + "text": [ + "Met dank aan bestuur 19; super 'vo", + "Nog 82 shotjes" + ], + "shotCount": 18 + }, + { + "type": "song", + "text": [ + "Martin Solveig", + "Intoxicated" + ] + } + ] + }, + { + "timestamp": 1137, + "events": [ + { + "type": "song", + "text": [ + "Nicki Minaj", + "Starships" + ] + } + ] + }, + { + "timestamp": 1173, + "events": [ + { + "type": "shot", + "text": [ + "Laatste shotje als tiener!", + "Nog 81 shotjes" + ], + "shotCount": 19 + } + ] + }, + { + "timestamp": 1222, + "events": [ + { + "type": "song", + "text": [ + "2Unlimited", + "Get Ready For This" + ] + } + ] + }, + { + "timestamp": 1233, + "events": [ + { + "type": "time", + "text": [ + "Nog 80 minuten!", + "Al 19 shotjes achter de rug" + ] + } + ] + }, + { + "timestamp": 1235, + "events": [ + { + "type": "shot", + "text": [ + "Adje!", + "Nog 80 shotjes" + ], + "shotCount": 20 + } + ] + }, + { + "timestamp": 1275, + "events": [ + { + "type": "song", + "text": [ + "The Village People", + "YMCA" + ] + } + ] + }, + { + "timestamp": 1288, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 79 shotjes" + ], + "shotCount": 21 + } + ] + }, + { + "timestamp": 1348, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 78 shotjes" + ], + "shotCount": 22 + } + ] + }, + { + "timestamp": 1350, + "events": [ + { + "type": "song", + "text": [ + "Carly Rae Jepsen ft Owl City", + "It's Always A Good Time" + ] + } + ] + }, + { + "timestamp": 1395, + "events": [ + { + "type": "song", + "text": [ + "Avicii", + "Levels" + ] + } + ] + }, + { + "timestamp": 1411, + "events": [ + { + "type": "shot", + "text": [ + "Claxon!", + "Nog 77 shotjes" + ], + "shotCount": 23 + } + ] + }, + { + "timestamp": 1456, + "events": [ + { + "type": "song", + "text": [ + "Flo-Rida feat. T-Pain", + "Low" + ] + } + ] + }, + { + "timestamp": 1471, + "events": [ + { + "type": "shot", + "text": [ + "En nu even op standje maximaal!", + "Nog 76 shotjes" + ], + "shotCount": 24 + } + ] + }, + { + "timestamp": 1486, + "events": [ + { + "type": "song", + "text": [ + "Taio Cruz", + "Hangover" + ] + } + ] + }, + { + "timestamp": 1522, + "events": [ + { + "type": "talk", + "text": [ + "Dit is nog het rustige stukje!", + "Zet hem maar op de bonk-bonk" + ] + } + ] + }, + { + "timestamp": 1530, + "events": [ + { + "type": "shot", + "text": [ + "Halve Abraham!", + "Nog 75 shotjes" + ], + "shotCount": 25 + } + ] + }, + { + "timestamp": 1545, + "events": [ + { + "type": "song", + "text": [ + "LMFAO", + "Party Rock Anthem" + ] + } + ] + }, + { + "timestamp": 1594, + "events": [ + { + "type": "shot", + "text": [ + "Hoch die Hände!", + "Nog 74 shotjes" + ], + "shotCount": 26 + }, + { + "type": "song", + "text": [ + "Hans Entertainment vs. Finger & Kadel", + "Hoch die Hände" + ] + } + ] + }, + { + "timestamp": 1623, + "events": [ + { + "type": "song", + "text": [ + "Galantis", + "No Money" + ] + } + ] + }, + { + "timestamp": 1653, + "events": [ + { + "type": "shot", + "text": [ + "Voel je 'm al?", + "Nog 73 shotjes" + ], + "shotCount": 27 + } + ] + }, + { + "timestamp": 1683, + "events": [ + { + "type": "song", + "text": [ + "Kid Cudi", + "Pursuit of Happiness (Steve Aoki remix)" + ] + } + ] + }, + { + "timestamp": 1712, + "events": [ + { + "type": "shot", + "text": [ + "Project X!", + "Nog 72 shotjes" + ], + "shotCount": 28 + } + ] + }, + { + "timestamp": 1741, + "events": [ + { + "type": "song", + "text": [ + "Yeah Yeah Yeahs", + "Heads Will Roll (A-Trak remix)" + ] + } + ] + }, + { + "timestamp": 1769, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 71 shotjes" + ], + "shotCount": 29 + } + ] + }, + { + "timestamp": 1814, + "events": [ + { + "type": "song", + "text": [ + "Michael Calfan", + "Resurrection" + ] + } + ] + }, + { + "timestamp": 1825, + "events": [ + { + "type": "time", + "text": [ + "Nog 70 minuten!", + "Half uurtje zit erop" + ] + } + ] + }, + { + "timestamp": 1829, + "events": [ + { + "type": "shot", + "text": [ + "Toet!", + "Nog 70 shotjes" + ], + "shotCount": 30 + } + ] + }, + { + "timestamp": 1858, + "events": [ + { + "type": "song", + "text": [ + "Basto!", + "Again and Again" + ] + } + ] + }, + { + "timestamp": 1887, + "events": [ + { + "type": "shot", + "text": [ + "Over de dertig!", + "Nog 69 (hehe) shotjes" + ], + "shotCount": 31 + } + ] + }, + { + "timestamp": 1916, + "events": [ + { + "type": "song", + "text": [ + "David Guetaa feat. Sia", + "Titanium" + ] + } + ] + }, + { + "timestamp": 1945, + "events": [ + { + "type": "shot", + "text": [ + "Trek een ad!", + "Nog 68 shotjes" + ], + "shotCount": 32 + } + ] + }, + { + "timestamp": 1959, + "events": [ + { + "type": "song", + "text": [ + "Gala", + "Freed From Desire" + ] + } + ] + }, + { + "timestamp": 2004, + "events": [ + { + "type": "shot", + "text": [ + "Nummertje 33!", + "Nog 67 shotjes!" + ], + "shotCount": 33 + } + ] + }, + { + "timestamp": 2034, + "events": [ + { + "type": "song", + "text": [ + "Wolter Kroes", + "Viva Hollandia" + ] + } + ] + }, + { + "timestamp": 2064, + "events": [ + { + "type": "shot", + "text": [ + "Voor het vaderland!", + "Nog 66 shotjes" + ], + "shotCount": 34 + } + ] + }, + { + "timestamp": 2125, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 65 shotjes" + ], + "shotCount": 35 + } + ] + }, + { + "timestamp": 2128, + "events": [ + { + "type": "song", + "text": [ + "Westlife", + "Uptown Girl" + ] + } + ] + }, + { + "timestamp": 2179, + "events": [ + { + "type": "song", + "text": [ + "Aqua", + "Barbie Girl" + ] + } + ] + }, + { + "timestamp": 2194, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 64 shotjes" + ], + "shotCount": 36 + } + ] + }, + { + "timestamp": 2225, + "events": [ + { + "type": "song", + "text": [ + "Guillerma & Tropical Danny", + "Toppertje" + ] + } + ] + }, + { + "timestamp": 2245, + "events": [ + { + "type": "shot", + "text": [ + "In dat keelgaatje!", + "Nog 63 shotjes" + ], + "shotCount": 37 + } + ] + }, + { + "timestamp": 2305, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 62 shotjes" + ], + "shotCount": 38 + }, + { + "type": "song", + "text": [ + "The Bloody Beetroots feat. Steve Aoki", + "Warp 1.9" + ] + } + ] + }, + { + "timestamp": 2374, + "events": [ + { + "type": "shot", + "text": [ + "Toet!", + "Nog 61 shotjes" + ], + "shotCount": 39 + }, + { + "type": "song", + "text": [ + "David Guetta & Showtek feat. Vassy", + "Bad" + ] + } + ] + }, + { + "timestamp": 2431, + "events": [ + { + "type": "shot", + "text": [ + "40 alweer!", + "Nog 60 shotjes" + ], + "shotCount": 40 + }, + { + "type": "song", + "text": [ + "Showtek & Justin Prime", + "Cannonball" + ] + } + ] + }, + { + "timestamp": 2444, + "events": [ + { + "type": "time", + "text": [ + "Nog 60 minuten!", + "Een klein uurtje" + ] + } + ] + }, + { + "timestamp": 2460, + "events": [ + { + "type": "song", + "text": [ + "Die Atzen", + "Disco Pogo" + ] + } + ] + }, + { + "timestamp": 2489, + "events": [ + { + "type": "shot", + "text": [ + "Zuipen!", + "Nog 59 shotjes" + ], + "shotCount": 41 + } + ] + }, + { + "timestamp": 2534, + "events": [ + { + "type": "song", + "text": [ + "Lorenz Büffel", + "Johnny Däpp" + ] + } + ] + }, + { + "timestamp": 2555, + "events": [ + { + "type": "shot", + "text": [ + "Dab dat glas naar je mond!", + "Nog 58 shotjes" + ], + "shotCount": 42 + } + ] + }, + { + "timestamp": 2587, + "events": [ + { + "type": "song", + "text": [ + "Zware Jongens", + "Jodeljump" + ] + } + ] + }, + { + "timestamp": 2606, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 57 shotjes" + ], + "shotCount": 43 + } + ] + }, + { + "timestamp": 2635, + "events": [ + { + "type": "song", + "text": [ + "Parla & Pardoux", + "Liberté" + ] + } + ] + }, + { + "timestamp": 2664, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 56 shotjes" + ], + "shotCount": 44 + } + ] + }, + { + "timestamp": 2695, + "events": [ + { + "type": "song", + "text": [ + "Markus Becker", + "Das rote Pferd" + ] + } + ] + }, + { + "timestamp": 2729, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 55 shotjes" + ], + "shotCount": 45 + } + ] + }, + { + "timestamp": 2743, + "events": [ + { + "type": "song", + "text": [ + "Olaf Henning", + "Cowboy und Indianer" + ] + } + ] + }, + { + "timestamp": 2784, + "events": [ + { + "type": "shot", + "text": [ + "Adje!", + "Nog 54 shotjes" + ], + "shotCount": 46 + } + ] + }, + { + "timestamp": 2785, + "events": [ + { + "type": "song", + "text": [ + "Ch!pz", + "Cowboy" + ] + } + ] + }, + { + "timestamp": 2824, + "events": [ + { + "type": "song", + "text": [ + "Toy-Box", + "Tarzan & Jane" + ] + } + ] + }, + { + "timestamp": 2850, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 53 shotjes" + ], + "shotCount": 47 + } + ] + }, + { + "timestamp": 2879, + "events": [ + { + "type": "song", + "text": [ + "Toy-Box", + "Sailor Song" + ] + } + ] + }, + { + "timestamp": 2919, + "events": [ + { + "type": "shot", + "text": [ + "Bijna op de helft!", + "Nog 52 shotjes" + ], + "shotCount": 48 + } + ] + }, + { + "timestamp": 2921, + "events": [ + { + "type": "song", + "text": [ + "Vengaboys", + "Boom, Boom, Boom, Boom!!" + ] + } + ] + }, + { + "timestamp": 2975, + "events": [ + { + "type": "shot", + "text": [ + "Bam!", + "Nog 51 shotjes" + ], + "shotCount": 49 + } + ] + }, + { + "timestamp": 2998, + "events": [ + { + "type": "song", + "text": [ + "Vengaboys", + "To Brazil!" + ] + } + ] + }, + { + "timestamp": 3024, + "events": [ + { + "type": "time", + "text": [ + "Nog 50 minuten!", + "We zijn op de helft!" + ] + } + ] + }, + { + "timestamp": 3039, + "events": [ + { + "type": "shot", + "text": [ + "Abraham!", + "Nog 50 shotjes" + ], + "shotCount": 50 + } + ] + }, + { + "timestamp": 3070, + "events": [ + { + "type": "song", + "text": [ + "Snollebollekes", + "Bam bam (bam)" + ] + } + ] + }, + { + "timestamp": 3104, + "events": [ + { + "type": "shot", + "text": [ + "Tweede helft!", + "Nog 49 shotjes" + ], + "shotCount": 51 + } + ] + }, + { + "timestamp": 3120, + "events": [ + { + "type": "song", + "text": [ + "Def Rhymz", + "Schudden" + ] + } + ] + }, + { + "timestamp": 3160, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 48 shotjes" + ], + "shotCount": 52 + } + ] + }, + { + "timestamp": 3190, + "events": [ + { + "type": "song", + "text": [ + "Cooldown Café", + "Hey baby" + ] + } + ] + }, + { + "timestamp": 3215, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 47 shotjes" + ], + "shotCount": 53 + } + ] + }, + { + "timestamp": 3232, + "events": [ + { + "type": "song", + "text": [ + "Gebroeders Ko", + "Schatje, mag ik je foto" + ] + } + ] + }, + { + "timestamp": 3279, + "events": [ + { + "type": "shot", + "text": [ + "Zuipen!", + "Nog 46 shotjes" + ], + "shotCount": 54 + }, + { + "type": "song", + "text": [ + "Guus Meeuwis", + "Het is een nacht" + ] + } + ] + }, + { + "timestamp": 3341, + "events": [ + { + "type": "shot", + "text": [ + "Adje!", + "Nog 45 shotjes" + ], + "shotCount": 55 + } + ] + }, + { + "timestamp": 3356, + "events": [ + { + "type": "song", + "text": [ + "Tom Waes", + "Dos cervezas" + ] + } + ] + }, + { + "timestamp": 3398, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 44 shotjes" + ], + "shotCount": 56 + } + ] + }, + { + "timestamp": 3412, + "events": [ + { + "type": "song", + "text": [ + "Peter Wackel", + "Vollgas" + ] + } + ] + }, + { + "timestamp": 3439, + "events": [ + { + "type": "song", + "text": [ + "Peter Wackel", + "Scheiß drauf!" + ] + } + ] + }, + { + "timestamp": 3465, + "events": [ + { + "type": "shot", + "text": [ + "Hard gaan!", + "Nog 43 shotjes" + ], + "shotCount": 57 + } + ] + }, + { + "timestamp": 3467, + "events": [ + { + "type": "song", + "text": [ + "Ikke Hüftgold", + "Dicke titten, kartoffelsalat" + ] + } + ] + }, + { + "timestamp": 3520, + "events": [ + { + "type": "shot", + "text": [ + "Hap, slok, weg!", + "Nog 42 shotjes" + ], + "shotCount": 58 + } + ] + }, + { + "timestamp": 3521, + "events": [ + { + "type": "song", + "text": [ + "Tim Toupet", + "Fliegerlied (So ein schöner Tag)" + ] + } + ] + }, + { + "timestamp": 3564, + "events": [ + { + "type": "song", + "text": [ + "Cooldown Café", + "Met z'n allen" + ] + } + ] + }, + { + "timestamp": 3577, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 41 shotjes" + ], + "shotCount": 59 + } + ] + }, + { + "timestamp": 3636, + "events": [ + { + "type": "time", + "text": [ + "Nog 40 minuten!", + "Uurtje achter de rug" + ] + } + ] + }, + { + "timestamp": 3643, + "events": [ + { + "type": "shot", + "text": [ + "Glas 60!", + "Nog 40 shotjes" + ], + "shotCount": 60 + } + ] + }, + { + "timestamp": 3659, + "events": [ + { + "type": "song", + "text": [ + "The Partysquad feat. Jayh, Sjaak & Reverse", + "Helemaal naar de klote" + ] + } + ] + }, + { + "timestamp": 3687, + "events": [ + { + "type": "song", + "text": [ + "K-Liber", + "Viben" + ] + } + ] + }, + { + "timestamp": 3700, + "events": [ + { + "type": "shot", + "text": [ + "Adje!", + "Nog 39 shotjes" + ], + "shotCount": 61 + } + ] + }, + { + "timestamp": 3753, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 38 shotjes" + ], + "shotCount": 62 + } + ] + }, + { + "timestamp": 3755, + "events": [ + { + "type": "song", + "text": [ + "FeestDJRuud & Dirtcaps feat. Sjaak & Kraantje Pappie", + "Weekend" + ] + } + ] + }, + { + "timestamp": 3808, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 37 shotjes" + ], + "shotCount": 63 + }, + { + "type": "song", + "text": [ + "Lawineboys", + "Joost" + ] + } + ] + }, + { + "timestamp": 3860, + "events": [ + { + "type": "song", + "text": [ + "Gebroeders Ko", + "Ik heb een toeter op mijn waterscooter" + ] + } + ] + }, + { + "timestamp": 3874, + "events": [ + { + "type": "shot", + "text": [ + "Toe-toe-toeter!", + "Nog 36 shotjes" + ], + "shotCount": 64 + } + ] + }, + { + "timestamp": 3904, + "events": [ + { + "type": "song", + "text": [ + "Gebroeders Ko", + "Tringeling" + ] + } + ] + }, + { + "timestamp": 3931, + "events": [ + { + "type": "shot", + "text": [ + "Tringeling!", + "Nog 35 shotjes" + ], + "shotCount": 65 + } + ] + }, + { + "timestamp": 3975, + "events": [ + { + "type": "song", + "text": [ + "Basshunter", + "Boten Anna" + ] + } + ] + }, + { + "timestamp": 3988, + "events": [ + { + "type": "shot", + "text": [ + "Zuipen!", + "Nog 34 shotjes" + ], + "shotCount": 66 + } + ] + }, + { + "timestamp": 4029, + "events": [ + { + "type": "song", + "text": [ + "Lawineboys", + "Wat zullen we drinken" + ] + } + ] + }, + { + "timestamp": 4050, + "events": [ + { + "type": "shot", + "text": [ + "Dorst!", + "Nog 33 shotjes" + ], + "shotCount": 67 + } + ] + }, + { + "timestamp": 4081, + "events": [ + { + "type": "song", + "text": [ + "Lamme Frans", + "Wakker met een biertje!" + ] + } + ] + }, + { + "timestamp": 4113, + "events": [ + { + "type": "shot", + "text": [ + "Biertje in de hand...", + "Nog 32 shotjes" + ], + "shotCount": 68 + } + ] + }, + { + "timestamp": 4124, + "events": [ + { + "type": "song", + "text": [ + "Lawineboys feat. DJ Jerome", + "Seks met die kale" + ] + } + ] + }, + { + "timestamp": 4175, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 31 shotjes" + ], + "shotCount": 69 + } + ] + }, + { + "timestamp": 4177, + "events": [ + { + "type": "song", + "text": [ + "Zombie Nation", + "Kernkraft 400" + ] + } + ] + }, + { + "timestamp": 4214, + "events": [ + { + "type": "time", + "text": [ + "Nog 30 minuten!", + "Half uurtje nog maar" + ] + } + ] + }, + { + "timestamp": 4228, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 30 shotjes" + ], + "shotCount": 70 + } + ] + }, + { + "timestamp": 4230, + "events": [ + { + "type": "song", + "text": [ + "DJ Boozywoozy", + "Party Affair" + ] + } + ] + }, + { + "timestamp": 4280, + "events": [ + { + "type": "shot", + "text": [ + "Tik maar achterover!", + "Nog 29 shotjes" + ], + "shotCount": 71 + } + ] + }, + { + "timestamp": 4289, + "events": [ + { + "type": "song", + "text": [ + "2Unlimited", + "No Limit" + ] + } + ] + }, + { + "timestamp": 4341, + "events": [ + { + "type": "shot", + "text": [ + "Alcoholic party!", + "Nog 28 shotjes" + ], + "shotCount": 72 + } + ] + }, + { + "timestamp": 4343, + "events": [ + { + "type": "song", + "text": [ + "DJ Kicken vs. MC-Q", + "Ain't No Party" + ] + } + ] + }, + { + "timestamp": 4408, + "events": [ + { + "type": "shot", + "text": [ + "Toet!", + "Nog 27 shotjes" + ], + "shotCount": 73 + } + ] + }, + { + "timestamp": 4411, + "events": [ + { + "type": "song", + "text": [ + "Jan Wayne", + "Becuase the Night" + ] + } + ] + }, + { + "timestamp": 4455, + "events": [ + { + "type": "song", + "text": [ + "Cascada", + "Everytime We Touch" + ] + } + ] + }, + { + "timestamp": 4467, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 26 shotjes" + ], + "shotCount": 74 + } + ] + }, + { + "timestamp": 4510, + "events": [ + { + "type": "song", + "text": [ + "Gigi D'Agostino", + "L'amour toujours" + ] + } + ] + }, + { + "timestamp": 4521, + "events": [ + { + "type": "shot", + "text": [ + "Shotje 75!", + "Nog 25 shotjes" + ], + "shotCount": 75 + } + ] + }, + { + "timestamp": 4573, + "events": [ + { + "type": "song", + "text": [ + "Jason Paige", + "Gotta Catch 'M All" + ] + } + ] + }, + { + "timestamp": 4578, + "events": [ + { + "type": "shot", + "text": [ + "Trek een ad!", + "Nog 24 shotjes" + ], + "shotCount": 76 + } + ] + }, + { + "timestamp": 4636, + "events": [ + { + "type": "song", + "text": [ + "Scooter", + "How Much Is The Fish" + ] + } + ] + }, + { + "timestamp": 4645, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 23 shotjes" + ], + "shotCount": 77 + } + ] + }, + { + "timestamp": 4675, + "events": [ + { + "type": "song", + "text": [ + "Scooter", + "Weekend" + ] + } + ] + }, + { + "timestamp": 4701, + "events": [ + { + "type": "shot", + "text": [ + "scToeter!", + "Nog 22 shotjes" + ], + "shotCount": 78 + } + ] + }, + { + "timestamp": 4714, + "events": [ + { + "type": "song", + "text": [ + "Scooter", + "One (Always Hardcore)" + ] + } + ] + }, + { + "timestamp": 4764, + "events": [ + { + "type": "shot", + "text": [ + "En door!", + "Nog 21 shotjes" + ], + "shotCount": 79 + } + ] + }, + { + "timestamp": 4766, + "events": [ + { + "type": "song", + "text": [ + "Scooter", + "Maria (I Like It Loud)" + ] + } + ] + }, + { + "timestamp": 4815, + "events": [ + { + "type": "time", + "text": [ + "Nog 20 minuten!", + "Geef alles, behalve over" + ] + } + ] + }, + { + "timestamp": 4818, + "events": [ + { + "type": "song", + "text": [ + "Scooter", + "J'adore Hardcore" + ] + } + ] + }, + { + "timestamp": 4829, + "events": [ + { + "type": "shot", + "text": [ + "Al 80 in de mik!", + "Nog 20 shotjes" + ], + "shotCount": 80 + } + ] + }, + { + "timestamp": 4860, + "events": [ + { + "type": "song", + "text": [ + "Wildstylez feat. Niels Geusebroek", + "Year of Summer" + ] + } + ] + }, + { + "timestamp": 4888, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 19 shotjes" + ], + "shotCount": 81 + } + ] + }, + { + "timestamp": 4929, + "events": [ + { + "type": "song", + "text": [ + "Brennan Heart & Wildstylez", + "Lose My Mind" + ] + } + ] + }, + { + "timestamp": 4953, + "events": [ + { + "type": "shot", + "text": [ + "Bakken vouwen!", + "Nog 18 shotjes" + ], + "shotCount": 82 + } + ] + }, + { + "timestamp": 5004, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 17 shotjes" + ], + "shotCount": 83 + } + ] + }, + { + "timestamp": 5006, + "events": [ + { + "type": "song", + "text": [ + "Starkoo", + "Ik wil je" + ] + } + ] + }, + { + "timestamp": 5059, + "events": [ + { + "type": "song", + "text": [ + "Feestteam", + "Let It Be" + ] + } + ] + }, + { + "timestamp": 5071, + "events": [ + { + "type": "shot", + "text": [ + "Let it bier!", + "Nog 16 shotjes" + ], + "shotCount": 84 + } + ] + }, + { + "timestamp": 5125, + "events": [ + { + "type": "shot", + "text": [ + "Adje numero 85!", + "Nog 15 shotjes" + ], + "shotCount": 85 + } + ] + }, + { + "timestamp": 5179, + "events": [ + { + "type": "song", + "text": [ + "DJ Nikolai & DJ Mike van Dijk", + "Piano Man" + ] + } + ] + }, + { + "timestamp": 5188, + "events": [ + { + "type": "shot", + "text": [ + "Toet!", + "Nog 14 shotjes" + ], + "shotCount": 86 + } + ] + }, + { + "timestamp": 5190, + "events": [ + { + "type": "talk", + "text": [ + "Gewoon doorgaan!", + "Deze Piano Man telt niet" + ] + } + ] + }, + { + "timestamp": 5237, + "events": [ + { + "type": "song", + "text": [ + "Robbie Williams", + "Angels" + ] + } + ] + }, + { + "timestamp": 5243, + "events": [ + { + "type": "shot", + "text": [ + "Drinken!", + "Nog 13 shotjes" + ], + "shotCount": 87 + } + ] + }, + { + "timestamp": 5278, + "events": [ + { + "type": "song", + "text": [ + "Enrique Iglesias", + "Hero" + ] + } + ] + }, + { + "timestamp": 5308, + "events": [ + { + "type": "shot", + "text": [ + "I can't be your biero!", + "Nog 12 shotjes" + ], + "shotCount": 88 + } + ] + }, + { + "timestamp": 5331, + "events": [ + { + "type": "song", + "text": [ + "Whitney Houston", + "I Will Always Love You" + ] + } + ] + }, + { + "timestamp": 5374, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 11 shotjes" + ], + "shotCount": 89 + } + ] + }, + { + "timestamp": 5380, + "events": [ + { + "type": "song", + "text": [ + "Mariah Carey", + "All I Want For Christmas" + ] + } + ] + }, + { + "timestamp": 5431, + "events": [ + { + "type": "shot", + "text": [ + "90 in de keel, hierna niet veel!", + "Nog 10 shotjes" + ], + "shotCount": 90 + } + ] + }, + { + "timestamp": 5441, + "events": [ + { + "type": "time", + "text": [ + "Nog 10 minuten!", + "De laatste loodjes" + ] + } + ] + }, + { + "timestamp": 5444, + "events": [ + { + "type": "song", + "text": [ + "Kraantje Pappie", + "Feesttent (FeestDJRuud remix)" + ] + } + ] + }, + { + "timestamp": 5488, + "events": [ + { + "type": "shot", + "text": [ + "Zuip je uit de dubbele cijfers!", + "Nog 9 shotjes" + ], + "shotCount": 91 + } + ] + }, + { + "timestamp": 5490, + "events": [ + { + "type": "song", + "text": [ + "New Kids feat. DJ Paul Elstak", + "Turbo" + ] + } + ] + }, + { + "timestamp": 5556, + "events": [ + { + "type": "shot", + "text": [ + "Zuipen!", + "Nog 8 shotjes" + ], + "shotCount": 92 + } + ] + }, + { + "timestamp": 5558, + "events": [ + { + "type": "song", + "text": [ + "Lipstick", + "I'm a Raver" + ] + } + ] + }, + { + "timestamp": 5591, + "events": [ + { + "type": "song", + "text": [ + "Nakatomi", + "Children of the Night" + ] + } + ] + }, + { + "timestamp": 5612, + "events": [ + { + "type": "shot", + "text": [ + "Pweeeep!", + "Nog 7 shotjes" + ], + "shotCount": 93 + } + ] + }, + { + "timestamp": 5614, + "events": [ + { + "type": "song", + "text": [ + "Charly Lownoise & Mental Theo", + "Wonderful Days" + ] + } + ] + }, + { + "timestamp": 5659, + "events": [ + { + "type": "song", + "text": [ + "DJ Paul Elstak", + "Luv You More" + ] + } + ] + }, + { + "timestamp": 5667, + "events": [ + { + "type": "shot", + "text": [ + "Bijna daar!", + "Nog 6 shotjes" + ], + "shotCount": 94 + } + ] + }, + { + "timestamp": 5704, + "events": [ + { + "type": "song", + "text": [ + "DJ Paul Elstak", + "Rainbow In The Sky" + ] + } + ] + }, + { + "timestamp": 5716, + "events": [ + { + "type": "time", + "text": [ + "Nog 5 minuten!", + "Zet de shotjes maar klaar" + ] + } + ] + }, + { + "timestamp": 5731, + "events": [ + { + "type": "shot", + "text": [ + "Toeter!", + "Nog 5 shotjes" + ], + "shotCount": 95 + } + ] + }, + { + "timestamp": 5733, + "events": [ + { + "type": "song", + "text": [ + "Evil Activities", + "Nobody Said It Was Easy" + ] + } + ] + }, + { + "timestamp": 5783, + "events": [ + { + "type": "shot", + "text": [ + "Slok 96!", + "Nog 4 shotjes" + ], + "shotCount": 96 + } + ] + }, + { + "timestamp": 5827, + "events": [ + { + "type": "song", + "text": [ + "Melrose", + "O" + ] + } + ] + }, + { + "timestamp": 5846, + "events": [ + { + "type": "shot", + "text": [ + "Voor de 97e keer!", + "Nog 3 shotjes" + ], + "shotCount": 97 + } + ] + }, + { + "timestamp": 5855, + "events": [ + { + "type": "song", + "text": [ + "Backstreet Boys", + "I Want It That Way" + ] + } + ] + }, + { + "timestamp": 5902, + "events": [ + { + "type": "shot", + "text": [ + "Nummer 98!", + "Nog 2 shotjes" + ], + "shotCount": 98 + } + ] + }, + { + "timestamp": 5933, + "events": [ + { + "type": "song", + "text": [ + "R. Kelly", + "The World's Greatest" + ] + } + ] + }, + { + "timestamp": 5970, + "events": [ + { + "type": "shot", + "text": [ + "Nummer 99!", + "Nog 1 shotje" + ], + "shotCount": 99 + } + ] + }, + { + "timestamp": 6020, + "events": [ + { + "type": "shot", + "text": [ + "CENTURION!", + "Geen shots meer" + ], + "shotCount": 100 + } + ] + } + ] + } + ] +} diff --git a/backend/package-lock.json b/backend/package-lock.json index b21d805..da37201 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -4,12 +4,81 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.6.tgz", + "integrity": "sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.4.tgz", + "integrity": "sha512-dPs6CaRWxsfHbYDVU51VjEJaUJEcli4UI0fFMT4oWmgCvHj+j7oIxz5MLHVL0Rv++N004c21ylJNdWQvPkkb5w==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/range-parser": "*" + } + }, + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==", + "dev": true + }, "@types/node": { "version": "13.11.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.0.tgz", "integrity": "sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ==", "dev": true }, + "@types/qs": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.1.tgz", + "integrity": "sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", + "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, "@types/socket.io": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.4.tgz", @@ -33,6 +102,12 @@ "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -93,6 +168,12 @@ "type-is": "~1.6.17" } }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -159,6 +240,12 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -379,6 +466,12 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -663,6 +756,22 @@ } } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -678,6 +787,19 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "ts-node": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.8.2.tgz", + "integrity": "sha512-duVj6BpSpUpD/oM4MfhO98ozgkp3Gt9qIp3jGxwU2DFvl/3IRaEAvbLa8G60uS7C77457e/m5TMowjedeRxI1Q==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "3.1.1" + } + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -687,6 +809,12 @@ "mime-types": "~2.1.24" } }, + "typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -716,6 +844,12 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/backend/package.json b/backend/package.json index 11de22f..4f83c0d 100644 --- a/backend/package.json +++ b/backend/package.json @@ -4,8 +4,8 @@ "description": "", "main": "./src/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "app": "node src/index.js" + "build": "tsc", + "app": "ts-node src/index.ts" }, "author": "", "license": "ISC", @@ -14,6 +14,9 @@ "socket.io": "^2.3.0" }, "devDependencies": { - "@types/socket.io": "^2.1.4" + "@types/express": "^4.17.6", + "@types/socket.io": "^2.1.4", + "ts-node": "^8.8.2", + "typescript": "^3.8.3" } } diff --git a/backend/src/Lobby.js b/backend/src/Lobby.js deleted file mode 100644 index 536207b..0000000 --- a/backend/src/Lobby.js +++ /dev/null @@ -1,160 +0,0 @@ -const User = require("./User.js"); -const timeline = require("./timeline.js"); - -module.exports = class Lobby { - /** - * @type {User[]} - */ - users = []; - /** - * @type {string|undefined} - */ - leaderId = undefined; - - running = false; - startTime = 0; - currentSeconds = 0; - timelineIndex = 0; - - // For debugging purposes - speedFactor = 1; - - constructor(name) { - this.name = name; - } - - run(io) { - this.running = true; - this.startTime = Date.now(); - - const doTick = () => { - if (this.users.length === 0) { - // this lobby is over. - return; - } - - const timestamp = timeline.getIndex(this.timelineIndex); - const nextShot = timeline.getNextShot(this.timelineIndex); - - if (!timestamp) { - // We are done. - io.to(this.name + "").emit('tick_event', { - current: this.currentSeconds - }); - console.log("Done"); - this.running = false; - return; - } - - console.log("ticking", this.currentSeconds); - - io.to(this.name + "").emit('tick_event', { - current: this.currentSeconds, - next: timestamp, - nextShot: nextShot - }); - - if (this.currentSeconds >= timestamp.timestamp) { - this.timelineIndex += 1; - } - - this.currentSeconds += 1; - // We spend some time processing, wait a bit less than 1000ms - const nextTickTime = this.startTime + (1000 * this.currentSeconds / this.speedFactor); - const waitTime = nextTickTime - Date.now(); - console.log("waiting", waitTime); - setTimeout(doTick, Math.floor(waitTime / this.speedFactor)); - }; - - doTick(); - } - - /** - * - * @param io - * @param {number} time - */ - seek(io, time) { - this.currentSeconds = time; - this.startTime = Date.now() - time * 1000; - this.timelineIndex = timeline.indexForTime(this.currentSeconds); - io.to(this.name + "").emit('seek', time); - } - - /** - * - * @returns {boolean} - */ - hasUsers() { - return this.users.length !== 0; - } - - - setRandomLeader() { - if (this.hasUsers()) { - this.leaderId = this.users[0].id; - } - } - - /** - * - * @param {User} user - */ - addUser(user) { - this.users.push(user); - } - - /** - * - * @param id - * @returns {User|undefined} - */ - getUser(id) { - return this.users.find(u => u.id === id); - } - - /** - * - * @param {string} id - */ - removeUser(id) { - this.users = this.users.filter(u => u.id !== id); - } - - /** - * - * @returns {boolean} - */ - hasLeader() { - return !!this.leaderId; - } - - /** - * - * @param {string} id - * @returns {boolean} - */ - isLeader(id) { - return this.leaderId === id; - } - - /** - * - * @param {string} id - */ - setLeader(id) { - if (!this.getUser(id)) { - throw new Error('user_not_in_lobby'); - } - - this.leaderId = id; - } - - /** - * - * @returns {User|undefined} - */ - getLeader() { - return this.users.find(u => u.id === this.leaderId) - } -}; diff --git a/backend/src/Room.ts b/backend/src/Room.ts new file mode 100644 index 0000000..d9aa685 --- /dev/null +++ b/backend/src/Room.ts @@ -0,0 +1,186 @@ +import {Socket} from "socket.io"; + +import User from "./User"; +import {getIndex, getNextShot, getTimeline, indexForTime} from "./timeline"; +import {getCurrentTime} from "./util"; + +export default class Room { + id: number = 0; + users: User[] = []; + leader: User | null = null; + + running = false; + startTime = 0; + currentSeconds = 0; + timelineIndex: number = 0; + + timelineName: string = 'Centurion'; + + // For debugging purposes + speedFactor = 1; + + constructor(name: number) { + this.id = name; + } + + serialize(user: User) { + return { + 'id': this.id, + 'userCount': this.users.length, + 'isLeader': this.leader == user, + 'running': this.running, + 'startTime': this.startTime, + 'timelineName': this.timelineName, + } + } + + serializeTimeline(user: User) { + return getTimeline(this.timelineName); + } + + sync() { + this.users.forEach(u => u.sync()); + } + + join(user: User) { + this.users.push(user); + user.setRoom(this); + + if (!this.hasLeader()) { + this.setLeader(user); + } + + this.sync(); + } + + leave(user: User) { + this.users.splice(this.users.indexOf(user), 1); + user.setRoom(null); + + if (this.leader == user) { + this.setRandomLeader(); + } + + this.sync(); + } + + onBeforeDelete() { + } + + start() { + this.running = true; + this.startTime = getCurrentTime() - 1400 * 1000 + + this.sync(); + } + + run(io: Socket) { + this.running = true; + this.startTime = Date.now(); + + // io.to(this.id.toString()).emit('timeline', { + // 'timeline': { + // } + // }); + + const doTick = () => { + if (this.users.length === 0) { + // this room is over. + return; + } + + const timestamp = getIndex(this.timelineIndex); + const nextShot = getNextShot(this.timelineIndex); + + if (!timestamp) { + // We are done. + io.to(this.id.toString()).emit('tick_event', { + tick: { + current: this.currentSeconds + } + }); + console.log("Done"); + this.running = false; + return; + } + + console.log("ticking", this.currentSeconds); + + io.to(this.id.toString()).emit('tick_event', { + tick: { + current: this.currentSeconds, + next: timestamp, + nextShot: nextShot + } + }); + + if (this.currentSeconds >= timestamp.timestamp) { + this.timelineIndex += 1; + } + + this.currentSeconds += 1; + // We spend some time processing, wait a bit less than 1000ms + const nextTickTime = this.startTime + (1000 * this.currentSeconds / this.speedFactor); + const waitTime = nextTickTime - Date.now(); + console.log("waiting", waitTime); + setTimeout(doTick, Math.floor(waitTime / this.speedFactor)); + }; + + doTick(); + } + + /** + * + * @param io + * @param {number} time + */ + seek(io: Socket, time: number) { + this.currentSeconds = time; + this.startTime = Date.now() - time * 1000; + this.timelineIndex = indexForTime(this.currentSeconds); + io.to(this.id.toString()).emit('seek', time); + } + + /** + * + * @returns {boolean} + */ + hasUsers() { + return this.users.length !== 0; + } + + setRandomLeader() { + if (this.hasUsers()) { + this.leader = this.users[0]; + } + } + + /** + * + * @param id + * @returns {User|undefined} + */ + getUser(id: string) { + return this.users.find(u => u.id === id); + } + + /** + * + * @param {string} id + */ + removeUser(id: string) { + this.users = this.users.filter(u => u.id !== id); + } + + hasLeader(): boolean { + return this.leader != null; + } + + setLeader(user: User) { + this.leader = user; + } + + getLeader(): User | null { + return this.leader; + } +}; diff --git a/backend/src/Service.ts b/backend/src/Service.ts new file mode 100644 index 0000000..b3e3c41 --- /dev/null +++ b/backend/src/Service.ts @@ -0,0 +1,120 @@ +import {Socket} from "socket.io"; + +import User from './User' +import Room from './Room' +import {getCurrentTime, randomInt} from "./util"; + +export default class Service { + private roomIdToRooms = new Map(); + private socketsToUsers = new Map(); + + onSocketConnect(socket: Socket) { + let user = new User(socket); + this.socketsToUsers.set(socket.id, user); + } + + onSocketDisconnect(socket: Socket) { + let user = this.getUser(socket); + + if (user.room != null) { + user.room.leave(user); + } + + this.deleteEmptyRooms(); + + user.onDisconnect(); + } + + onTimeSync(socket: Socket, requestId: number, clientTime: number) { + let user = this.getUser(socket); + + let now = getCurrentTime(); + user.emit('time_sync', { + 'requestId': requestId, + 'clientDiff': now - clientTime, + 'serverTime': now + }) + } + + onRequestStart(socket: Socket) { + let user = this.getUser(socket); + + if (user.room?.getLeader() == user) { + user.room!!.start(); + } + } + + onRequestJoin(socket: Socket, roomId: number): boolean { + let user = this.getUser(socket); + if (!this.roomIdToRooms.has(roomId)) return false; + if (user.room && user.room.id == roomId) return false; + + if (user.room) { + user.room.leave(user); + this.deleteEmptyRooms(); + } + + let room = this.roomIdToRooms.get(roomId)!!; + room.join(user); + return true; + } + + onRequestJoinRandom(socket: Socket) { + let user = this.getUser(socket); + + if (user.room) { + user.room.leave(user); + this.deleteEmptyRooms(); + } + + const room = this.createRandomRoom(); + if (!room) throw Error('Too many rooms active'); + room.join(user); + } + + hasRoomId(roomId: number): boolean { + return this.roomIdToRooms.has(roomId); + } + + private getUser(socket: Socket): User { + let user = this.socketsToUsers.get(socket.id); + if (!user) { + throw new Error('User not found'); + } + return user; + } + + private deleteEmptyRooms() { + for (let room of this.roomIdToRooms.values()) { + if (room.users.length == 0) { + this.deleteRoom(room); + } + } + } + + private createRandomRoom(): Room | null { + let tries = 0; + while (tries++ < 1000) { + const randomId = randomInt(100, Math.max(1000, this.roomIdToRooms.size * 2)); + if (this.roomIdToRooms.has(randomId)) continue; + + return this.createRoomWithId(randomId); + } + return null; + } + + private createRoomWithId(roomId: number): Room { + if (this.roomIdToRooms.has(roomId)) { + throw new Error('A room with the given id already exists'); + } + + let room = new Room(roomId); + this.roomIdToRooms.set(roomId, room); + return room; + } + + private deleteRoom(room: Room) { + this.roomIdToRooms.get(room.id)!!.onBeforeDelete(); + this.roomIdToRooms.delete(room.id) + } +} diff --git a/backend/src/State.js b/backend/src/State.js deleted file mode 100644 index b078181..0000000 --- a/backend/src/State.js +++ /dev/null @@ -1,59 +0,0 @@ -const Lobby = require("./Lobby.js"); -const {getRandomInt} = require("./util.js"); - -class State { - /** - * @type {Object.} - */ - lobbies = {}; - - constructor() { - } - - /** - * @returns {Lobby} - */ - createRandomLobby() { - let lobby = undefined; - - while (!lobby) { - const lobbyCount = Object.keys(this.lobbies).length; - const id = getRandomInt(100, Math.max(1000, lobbyCount * 2)); - lobby = this.createLobby(id); - } - - return lobby; - } - - /** - * - * @param lobbyId - * @returns {Lobby|undefined} - */ - getLobby(lobbyId) { - if (!lobbyId || !this.lobbies.hasOwnProperty(lobbyId)) { - return undefined; - } - - return this.lobbies[lobbyId]; - } - - /** - * Returns undefined when the lobby already exists. - * @param {number} lobbyId - * @returns {Lobby|undefined} - */ - createLobby(lobbyId) { - if (this.lobbies.hasOwnProperty(lobbyId)) { - return undefined; - } - - return new Lobby(lobbyId); - } - - removeLobby(lobbyId) { - delete this.lobbies[lobbyId]; - } -} - -module.exports = new State(); diff --git a/backend/src/User.js b/backend/src/User.js deleted file mode 100644 index b071f72..0000000 --- a/backend/src/User.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = class User { - constructor(id) { - this.id = id; - } -}; \ No newline at end of file diff --git a/backend/src/User.ts b/backend/src/User.ts new file mode 100644 index 0000000..290ddc6 --- /dev/null +++ b/backend/src/User.ts @@ -0,0 +1,77 @@ +import {Socket} from "socket.io"; + +import Room from "./Room"; + +export default class User { + socket: Socket; + id: string; + + room: Room | null = null; + + constructor(socket: Socket) { + this.socket = socket; + this.id = socket.id; + } + + onDisconnect() { + if (this.room != null) { + + } + } + + setRoom(room: Room | null) { + if (this.room === room) return; + + if (this.room != null) { + this.socket.leave(this.room.id.toString()); + } + + this.room = room; + + if (this.room != null) { + this.socket.join(this.room.id.toString()); + } + + this.sync(); + } + + sentRoom: any = null; + sentTimelineName: string | null = null; + + sync() { + if (!this.shallowEquals(this.sentRoom, this.room?.serialize(this))) { + this.sentRoom = this.room?.serialize(this); + this.emit('room', { + 'room': this.sentRoom + }) + } + + if (!this.shallowEquals(this.sentTimelineName, this.room?.timelineName)) { + this.sentTimelineName = this.room?.timelineName || null; + this.emit('timeline', { + 'timeline': this.sentTimelineName == null ? null : this.room!!.serializeTimeline(this) + }) + } + } + + emit(eventName: string, obj: any) { + this.socket.emit(eventName, obj); + } + + shallowEquals(obj1: any, obj2: any) { + if (obj1 === null && obj2 === null) + return true; + + if ((obj1 === null && obj2 !== null) || (obj1 !== null && obj2 === null)) + return false; + + if (typeof (obj1) != typeof (obj2)) + return false; + + if (Object.keys(obj1).length !== Object.keys(obj2).length) return false + + return Object.keys(obj1).every(key => + obj2.hasOwnProperty(key) && obj1[key] === obj2[key] + ); + } +} diff --git a/backend/src/app.js b/backend/src/app.js deleted file mode 100644 index fbbe8b1..0000000 --- a/backend/src/app.js +++ /dev/null @@ -1,22 +0,0 @@ -const express = require("express"); -const socketIO = require("socket.io"); -const state = require("./State.js"); -const path = require("path"); - -const HOST = '0.0.0.0'; -const PORT = 3001; - -const app = express(); -const server = app.listen(PORT, HOST,() => console.log(`Centurion listening on port ${PORT}!`)); -app.use(express.static(path.join(__dirname, '../public'))); - -const io = socketIO(server); - -app.get('/state', (req, res) => res.send('
' + JSON.stringify(state) + '
')); - -process.on('SIGINT', () => process.exit()); -process.on('SIGTERM', () => process.exit()); - -module.exports = { - app, server, io -}; diff --git a/backend/src/index.js b/backend/src/index.js deleted file mode 100644 index 27d757c..0000000 --- a/backend/src/index.js +++ /dev/null @@ -1,80 +0,0 @@ -const service = require("./service.js"); -const state = require("./State.js"); - -const {io} = require('./app.js'); - -io.on('connection', socket => { - const socketId = socket.id; - - console.log('a user connected', socketId); - - const lobby = state.createRandomLobby(); - service.joinLobby(socketId, lobby.name); - socket.join(lobby.name); - socket.emit('welcome', {lobby: lobby}); - - socket.on('disconnect', (reason) => { - console.log('Disconnected:', socketId); - service.leaveLobby(socketId); - }); - - socket.on('join_lobby', (lobbyId, callback) => { - if (!callback || typeof callback !== 'function') { - console.error("Join: Callback not a function."); - return - } - - if (!lobbyId) { - return callback('no_lobby_id_given'); - } - - if (!Number.isSafeInteger(+lobbyId)) { - return callback('lobby_id_not_integer'); - } - - console.log(`${socketId} wants to join '${lobbyId}'.`); - - // Leave current lobby first - service.leaveLobby(socketId); - const lobby = service.joinLobby(socketId, lobbyId); - - socket.join(lobby.name); - - callback(null, { - status: 'ok', - lobby: lobby - }); - }); - - socket.on('lobby_info', callback => { - if (!callback || typeof callback !== 'function') { - console.error("Lobby info: Callback not a function."); - return - } - - const lobby = service.getUserLobby(socketId); - - callback(null, { - status: 'ok', - lobby: lobby - }); - }); - - socket.on('request_start', (time = null) => { - console.log('request start', socket.rooms); - - const lobby = service.getUserLobby(socketId); - if (!lobby.isLeader(socketId)) { - console.warn("Non leader tried to start."); - return; - } - - io.to(lobby.name + "").emit('started'); - lobby.run(io); - - if (typeof time === 'number' && time) { - console.log("Starting at", time); - lobby.seek(io, time); - } - }); -}); diff --git a/backend/src/index.ts b/backend/src/index.ts new file mode 100644 index 0000000..a6cb73f --- /dev/null +++ b/backend/src/index.ts @@ -0,0 +1,175 @@ +import express from "express"; +import SocketIO, {Socket} from "socket.io"; +import path from "path"; + +import Service from './Service' + +// process.on('SIGINT', () => process.exit()); +// process.on('SIGTERM', () => process.exit()); + +const HOST = '0.0.0.0'; +const PORT = 3001; + +const app = express(); +const server = app.listen(PORT, HOST, () => console.log(`Centurion listening on port ${PORT}!`)); +app.use(express.static(path.join(__dirname, '../public'))); + +const io = SocketIO(server); + +const service = new Service(); + +io.on('connection', socket => { + socket.on('disconnect', (reason) => { + service.onSocketDisconnect(socket); + }); + + socket.on('ping', () => { + socket.emit('pong'); + }) + + socket.on('time_sync', (requestId: number, clientTime: number) => { + if (!Number.isSafeInteger(requestId)) return; + if (!Number.isSafeInteger(clientTime)) return; + + service.onTimeSync(socket, requestId, clientTime); + }) + + socket.on('request_start', () => { + service.onRequestStart(socket); + }); + + socket.on('request_join', (roomId: number) => { + if (!Number.isSafeInteger(roomId)) return; + + service.onRequestJoin(socket, roomId); + }); + + socket.on('request_join_random', () => { + service.onRequestJoinRandom(socket); + }) + + socket.on('call', (id: number, name: string, params: any) => { + if (!Number.isSafeInteger(id)) return; + // noinspection SuspiciousTypeOfGuard + if (!name || typeof (name) !== 'string') return; + // if (!params) return; + + let call = new Call(socket, id, name, params); + + if (name == 'room_exists') { + let roomId = params && params['roomId']; + if (!Number.isSafeInteger(roomId)) { + call.error('Invalid room id'); + return; + } + + call.respond(service.hasRoomId(roomId)); + return; + } + + if (name == 'request_join') { + let roomId = params && params['roomId']; + if (!Number.isSafeInteger(roomId)) { + call.error('Invalid room id'); + return; + } + if (!service.hasRoomId(roomId)) { + call.respond(false); + return; + } + if (service.onRequestJoin(socket, roomId)) { + call.respond(true); + } else { + call.respond(false); + } + } + }) + + service.onSocketConnect(socket); + + /*socket.on('join_room', (roomId, callback) => { + if (!callback || typeof callback !== 'function') { + console.error("Join: Callback not a function."); + return + } + + if (!roomId) { + return callback('no_room_id_given'); + } + + if (!Number.isSafeInteger(+roomId)) { + return callback('room_id_not_integer'); + } + + console.log(`${socketId} wants to join '${roomId}'.`); + + // Leave current room first + + let currentRoom = service.getUserRoom(socketId); + if (currentRoom) { + socket.leave(currentRoom.name); + service.leaveRoom(socketId); + } + + const room = service.joinRoom(socketId, roomId); + + socket.join(room.name); + sendRoom(socket, room); + }); + + socket.on('room_info', callback => { + if (!callback || typeof callback !== 'function') { + console.error("Room info: Callback not a function."); + return + } + + const room = service.getUserRoom(socketId); + sendRoom(socket, room); + }); + + socket.on('request_start', (time = null) => { + console.log('request start', socket.rooms); + + const room = service.getUserRoom(socketId); + if (!room.isLeader(socketId)) { + console.warn("Non leader tried to start."); + return; + } + + room.run(io); + sendRoom(io.to(room.name.toString()), room); + + if (typeof time === 'number' && time) { + console.log("Starting at", time); + room.seek(io, time); + } + });*/ +}); + +class Call { + private socket: Socket; + private id: number; + private name: string; + private params: any; + + constructor(socket: Socket, id: number, name: string, params: any) { + this.socket = socket; + this.id = id; + this.name = name; + this.params = params; + } + + error(reason: string) { + this.socket.emit('call_response', { + 'id': this.id, + 'error': reason + }) + } + + respond(data: any) { + this.socket.emit('call_response', { + 'id': this.id, + 'response': data + }); + } +} diff --git a/backend/src/service.js b/backend/src/service.js deleted file mode 100644 index a9431fe..0000000 --- a/backend/src/service.js +++ /dev/null @@ -1,68 +0,0 @@ -const User = require("./User.js"); -const state = require("./State.js"); - -/** - * - * @param {string} socketId - * @param {number} lobbyId - * @returns {Lobby} - */ -function joinLobby(socketId, lobbyId) { - let lobby = state.getLobby(lobbyId); - if (!lobby) { - lobby = state.createLobby(lobbyId); - } - - lobby.addUser(new User(socketId)); - - if (!lobby.hasLeader()) { - lobby.setLeader(socketId); - } - - state.lobbies[lobby.name] = lobby; - return lobby; -} - -function leaveLobby(socketId) { - Object.keys(state.lobbies).forEach(lobbyId => { - const lobby = state.getLobby(lobbyId); - - if (!lobby) { - return; - } - - lobby.removeUser(socketId); - - if (!lobby.hasUsers()) { - state.removeLobby(lobbyId); - return; - } - - if (lobby.getLeader() === socketId) { - lobby.setRandomLeader(); - } - }); -} - -/** - * - * @param socketId - * @returns {Lobby|undefined} - */ -function getUserLobby(socketId) { - for (let lobbyId of Object.keys(state.lobbies)) { - const lobby = state.getLobby(lobbyId); - - if (!lobby) { - continue; - } - - if (lobby.getUser(socketId)) { - return lobby; - } - } - - return undefined; -} - -module.exports = {joinLobby, leaveLobby, getUserLobby}; diff --git a/backend/src/timeline.js b/backend/src/timeline.ts similarity index 64% rename from backend/src/timeline.js rename to backend/src/timeline.ts index ab9a30f..8c75510 100644 --- a/backend/src/timeline.js +++ b/backend/src/timeline.ts @@ -1,11 +1,19 @@ -const timeline = require('../data/timeline.js'); +// @ts-ignore +import timeline from '../data/timelines.js'; + + +export function getTimeline(name: string) { + let t = timeline.timelines.find((i: any) => i.name == name); + if (!t) return null; + return t; +} /** * * @param i * @returns {*} */ -function getIndex(i) { +export function getIndex(i: number): any { if (i >= timeline.length) { return; } @@ -17,7 +25,7 @@ function getIndex(i) { * @param {number} i - the index. * @returns {{count: number, timestamp: number}|undefined} */ -function getNextShot(i) { +export function getNextShot(i: number) { for (; i < timeline.length; i++) { const time = getIndex(i); @@ -34,9 +42,9 @@ function getNextShot(i) { return undefined; } -function indexForTime(seconds) { +export function indexForTime(seconds: number): number { let lastIndex = 0; - for(let i = 0; i < timeline.length; i++) { + for (let i = 0; i < timeline.length; i++) { const time = timeline[i]; if (time.timestamp >= seconds) { @@ -45,8 +53,6 @@ function indexForTime(seconds) { lastIndex = i; } -} -module.exports = { - getIndex, getNextShot, indexForTime -}; \ No newline at end of file + return -1; +} diff --git a/backend/src/util.js b/backend/src/util.js deleted file mode 100644 index 85c0c89..0000000 --- a/backend/src/util.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Generates random int - * @param {number} min, inclusive - * @param {number} max, exclusive - * @returns {number} - */ -function getRandomInt(min, max) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min)) + min; -} - -module.exports = { - getRandomInt -}; \ No newline at end of file diff --git a/backend/src/util.ts b/backend/src/util.ts new file mode 100644 index 0000000..157e5bd --- /dev/null +++ b/backend/src/util.ts @@ -0,0 +1,20 @@ +/** + * Generates random int + * @param {number} min, inclusive + * @param {number} max, exclusive + * @returns {number} + */ +export function randomInt(min: number, max: number): number { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min)) + min; +} + +let _randomTimeOffsetForDebug = randomInt(-10000, 10000); +_randomTimeOffsetForDebug = 0; + +console.log('random time offset', _randomTimeOffsetForDebug); + +export function getCurrentTime() { + return Date.now() + _randomTimeOffsetForDebug; +} diff --git a/backend/tsconfig.json b/backend/tsconfig.json new file mode 100644 index 0000000..8bb50b5 --- /dev/null +++ b/backend/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "strict": true, + "esModuleInterop": true + } +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4403353..21de874 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,27 +12,32 @@ "tinycolor2": "^1.4.1" } }, - "@ant-design/create-react-context": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@ant-design/create-react-context/-/create-react-context-0.2.5.tgz", - "integrity": "sha512-1rMAa4qgP2lfl/QBH9i78+Gjxtj9FTMpMyDGZsEBW5Kih72EuUo9958mV8PgpRkh4uwPSQ7vVZWXeyNZXVAFDg==", + "@ant-design/icons": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.0.6.tgz", + "integrity": "sha512-Hvly7PhImdZo5+UnpRPSpqcYFttTEE9ELCgir6R9cPe99IHciLv97EZTshYTFp4T6i2q0x9nuSLpG11UFeu4Dg==", "requires": { - "gud": "^1.0.0", - "warning": "^4.0.3" + "@ant-design/colors": "^3.1.0", + "@ant-design/icons-svg": "^4.0.0", + "classnames": "^2.2.6", + "insert-css": "^2.0.0", + "rc-util": "^4.9.0" } }, - "@ant-design/icons": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz", - "integrity": "sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w==" + "@ant-design/icons-svg": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.0.0.tgz", + "integrity": "sha512-Nai+cd3XUrv/z50gSk1FI08j6rENZ1e93rhKeLTBGwa5WrmHvhn2vowa5+voZW2qkXJn1btS6tdvTEDB90M0Pw==" }, - "@ant-design/icons-react": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@ant-design/icons-react/-/icons-react-2.0.1.tgz", - "integrity": "sha512-r1QfoltMuruJZqdiKcbPim3d8LNsVPB733U0gZEUSxBLuqilwsW28K2rCTWSMTjmFX7Mfpf+v/wdiFe/XCqThw==", + "@ant-design/react-slick": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.25.5.tgz", + "integrity": "sha512-fusHR9LkarCARvYTN6cG3yz2/Ogf+HTaJ2XEihIjsjgm6uE1aSXycRFEVDpOFP1Aib51Z2Iz3tgg/gL+WbK8rQ==", "requires": { - "@ant-design/colors": "^3.1.0", - "babel-runtime": "^6.26.0" + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "lodash": "^4.17.15", + "resize-observer-polyfill": "^1.5.0" } }, "@babel/code-frame": { @@ -1624,6 +1629,15 @@ "@types/node": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", @@ -1701,10 +1715,10 @@ "@types/react": "*" } }, - "@types/react-slick": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.4.tgz", - "integrity": "sha512-vXoIy4GUfB7/YgqubR4H7RALo+pRdMYCeLgWwV3MPwl5pggTlEkFBTF19R7u+LJc85uMqC7RfsbkqPLMQ4ab+A==", + "@types/react-lifecycles-compat": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/react-lifecycles-compat/-/react-lifecycles-compat-3.0.1.tgz", + "integrity": "sha512-4KiU5s1Go4xRbf7t6VxUUpBeN5PGjpjpBv9VvET4uiPHC500VNYBclU13f8ehHkHoZL39b2cfwHu6RzbV3b44A==", "requires": { "@types/react": "*" } @@ -1717,6 +1731,11 @@ "@types/react": "*" } }, + "@types/shallowequal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/shallowequal/-/shallowequal-1.1.1.tgz", + "integrity": "sha512-Lhni3aX80zbpdxRuWhnuYPm8j8UQaa571lHP/xI4W+7BAFhSIhRReXnqjEgT/XzPoXZTJkCqstFMJ8CZTK6IlQ==" + }, "@types/socket.io-client": { "version": "1.4.32", "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.32.tgz", @@ -2251,63 +2270,53 @@ } }, "antd": { - "version": "3.26.15", - "resolved": "https://registry.npmjs.org/antd/-/antd-3.26.15.tgz", - "integrity": "sha512-OAcfz9D1Qt+4Fme4E0DfCKuWm/1RIVrJZzaTYVCGOnVAHJjoxEtKCoCrcj/8wwCS9LbXHVci/s2u/gY+QmtCSw==", - "requires": { - "@ant-design/create-react-context": "^0.2.4", - "@ant-design/icons": "~2.1.1", - "@ant-design/icons-react": "~2.0.1", - "@types/react-slick": "^0.23.4", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/antd/-/antd-4.1.4.tgz", + "integrity": "sha512-YRF/nrAq4R+olKRJxEDqeO4xkTvx+U6ovIQjGew1JDiEHMMhSftpvpYg2Iu5hRdFL66uxQk6VYngMttBpuYm9Q==", + "requires": { + "@ant-design/icons": "^4.0.0", + "@ant-design/react-slick": "~0.25.5", "array-tree-filter": "^2.1.0", - "babel-runtime": "6.x", "classnames": "~2.2.6", "copy-to-clipboard": "^3.2.0", "css-animation": "^1.5.0", - "dom-closest": "^0.2.0", - "enquire.js": "^2.1.6", - "is-mobile": "^2.1.0", "lodash": "^4.17.13", "moment": "^2.24.0", "omit.js": "^1.0.2", "prop-types": "^15.7.2", "raf": "^3.4.1", - "rc-animate": "^2.10.2", - "rc-calendar": "~9.15.7", - "rc-cascader": "~0.17.4", - "rc-checkbox": "~2.1.6", + "rc-animate": "~2.10.2", + "rc-cascader": "~1.0.0", + "rc-checkbox": "~2.2.0", "rc-collapse": "~1.11.3", "rc-dialog": "~7.6.0", "rc-drawer": "~3.1.1", - "rc-dropdown": "~2.4.1", - "rc-editor-mention": "^1.1.13", - "rc-form": "^2.4.10", - "rc-input-number": "~4.5.0", - "rc-mentions": "~0.4.0", - "rc-menu": "~7.5.1", - "rc-notification": "~3.3.1", - "rc-pagination": "~1.20.11", + "rc-dropdown": "~3.0.0", + "rc-field-form": "~1.1.0", + "rc-input-number": "~4.5.4", + "rc-mentions": "~1.1.0", + "rc-menu": "~8.0.1", + "rc-notification": "~4.0.0", + "rc-pagination": "~2.2.0", + "rc-picker": "~1.4.0", "rc-progress": "~2.5.0", - "rc-rate": "~2.5.0", - "rc-resize-observer": "^0.1.0", - "rc-select": "~9.2.0", - "rc-slider": "~8.7.1", + "rc-rate": "~2.5.1", + "rc-resize-observer": "^0.2.0", + "rc-select": "~10.2.0", + "rc-slider": "~9.2.3", "rc-steps": "~3.5.0", "rc-switch": "~1.9.0", - "rc-table": "~6.10.5", - "rc-tabs": "~9.7.0", - "rc-time-picker": "~3.7.1", - "rc-tooltip": "~3.7.3", - "rc-tree": "~2.1.0", - "rc-tree-select": "~2.9.1", - "rc-trigger": "^2.6.2", - "rc-upload": "~2.9.1", - "rc-util": "^4.16.1", - "react-lazy-load": "^3.0.13", - "react-lifecycles-compat": "^3.0.4", - "react-slick": "~0.25.2", + "rc-table": "~7.4.2", + "rc-tabs": "~10.1.1", + "rc-tooltip": "~4.0.2", + "rc-tree": "~3.1.0", + "rc-tree-select": "~3.1.0", + "rc-trigger": "~4.0.0", + "rc-upload": "~3.0.0", + "rc-util": "^4.20.0", + "rc-virtual-list": "^1.1.0", "resize-observer-polyfill": "^1.5.1", - "shallowequal": "^1.1.0", + "scroll-into-view-if-needed": "^2.2.20", "warning": "~4.0.3" } }, @@ -2513,9 +2522,9 @@ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "async-validator": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.11.5.tgz", - "integrity": "sha512-XNtCsMAeAH1pdLMEg1z8/Bb3a8cdCbui9QbJATRFHHHW5kT6+NPI3zSVQUXgikTFITzsg+kYY5NTWhM2Orwt9w==" + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.2.4.tgz", + "integrity": "sha512-mTgzMJixkrh+5t2gbYoua8MLy11GHkQqFE6tbhY5Aqc4jEDGsR4BWP+sVQiYDHtzTMB8WIwI/ypObTVPcTZInw==" }, "asynckit": { "version": "0.4.0", @@ -3719,6 +3728,11 @@ } } }, + "compute-scroll-into-view": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.13.tgz", + "integrity": "sha512-o+w9w7A98aAFi/GjK8cxSV+CdASuPa2rR5UWs3+yHkJzWqaKoBEufFNWYaXInCSmUfDCVhesG+v9MTWqOjsxFg==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3909,16 +3923,6 @@ "sha.js": "^2.4.8" } }, - "create-react-class": { - "version": "15.6.3", - "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.3.tgz", - "integrity": "sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg==", - "requires": { - "fbjs": "^0.8.9", - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" - } - }, "cross-spawn": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", @@ -4559,14 +4563,6 @@ "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.11.1.tgz", "integrity": "sha512-hN42DmUgtweBx0iBjDLO4WtKOMcK8yBmPx/fgdsgQadLuzPu/8co3oLdK5yMmeM/vnUd3yDyV6qV8/NzxBexQg==" }, - "dom-closest": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-closest/-/dom-closest-0.2.0.tgz", - "integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=", - "requires": { - "dom-matches": ">=1.0.1" - } - }, "dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -4584,16 +4580,6 @@ "csstype": "^2.6.7" } }, - "dom-matches": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz", - "integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw=" - }, - "dom-scroll-into-view": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-1.2.1.tgz", - "integrity": "sha1-6PNnMt0ImwIBqI14Fdw/iObWbH4=" - }, "dom-serializer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", @@ -4672,16 +4658,6 @@ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, - "draft-js": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.10.5.tgz", - "integrity": "sha512-LE6jSCV9nkPhfVX2ggcRLA4FKs6zWq9ceuO/88BpXdNCS7mjRTgs0NsV6piUCJX9YxMsB9An33wnkMmU2sD2Zg==", - "requires": { - "fbjs": "^0.8.15", - "immutable": "~3.7.4", - "object-assign": "^4.1.0" - } - }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -4746,14 +4722,6 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "requires": { - "iconv-lite": "~0.4.13" - } - }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -4828,11 +4796,6 @@ } } }, - "enquire.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz", - "integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ=" - }, "entities": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", @@ -5384,11 +5347,6 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" }, - "eventlistener": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/eventlistener/-/eventlistener-0.0.1.tgz", - "integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg=" - }, "events": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", @@ -5752,27 +5710,6 @@ "bser": "2.1.1" } }, - "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - } - } - }, "figgy-pudding": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", @@ -6236,11 +6173,6 @@ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" }, - "gud": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", - "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" - }, "gzip-size": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", @@ -6652,11 +6584,6 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==" }, - "immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" - }, "import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", @@ -6834,6 +6761,11 @@ } } }, + "insert-css": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/insert-css/-/insert-css-2.0.0.tgz", + "integrity": "sha1-610Ql7dUL0x56jBg067gfQU4gPQ=" + }, "internal-ip": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", @@ -7019,11 +6951,6 @@ "is-extglob": "^2.1.1" } }, - "is-mobile": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-2.2.1.tgz", - "integrity": "sha512-6zELsfVFr326eq2CI53yvqq6YBanOxKBybwDT+MbMS2laBnK6Ez8m5XHSuTQQbnKRfpDzCod1CMWW5q3wZYMvA==" - }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -7160,15 +7087,6 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" - } - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -8867,11 +8785,6 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, "lodash.flow": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", @@ -8905,11 +8818,6 @@ "lodash._reinterpolate": "^3.0.0" } }, - "lodash.throttle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" - }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -9215,21 +9123,18 @@ } }, "mini-store": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mini-store/-/mini-store-2.0.0.tgz", - "integrity": "sha512-EG0CuwpQmX+XL4QVS0kxNwHW5ftSbhygu1qxQH0pipugjnPkbvkalCdQbEihMwtQY6d3MTN+MS0q+aurs+RfLQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mini-store/-/mini-store-3.0.2.tgz", + "integrity": "sha512-TM7IQBu+mVssLQReprx7JGftXk0EyaiIWw7yAx6E4SIZRHwgQ8XcG4dINFAaBCBihbYPJyhf7kbz7e5qk1FkuQ==", "requires": { - "hoist-non-react-statics": "^2.3.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/react-lifecycles-compat": "^3.0.1", + "@types/shallowequal": "^1.1.1", + "hoist-non-react-statics": "^3.3.2", "prop-types": "^15.6.0", "react-lifecycles-compat": "^3.0.4", - "shallowequal": "^1.0.2" - }, - "dependencies": { - "hoist-non-react-statics": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", - "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" - } + "shallowequal": "^1.0.2", + "typescript": "^3.8.3" } }, "minimalistic-assert": { @@ -9391,11 +9296,6 @@ "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, - "mutationobserver-shim": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mutationobserver-shim/-/mutationobserver-shim-0.3.5.tgz", - "integrity": "sha512-YAMuSp4Oi19SYQF04dGnRajyFp4Wyam+jKKWzm5roPcNh1Rip8dnHPxls5F/xBgY0H2gV+3IzWuIvYQPDAvmBQ==" - }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -9465,15 +9365,6 @@ "tslib": "^1.10.0" } }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, "node-forge": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", @@ -9671,6 +9562,17 @@ "prepend-http": "^1.0.0", "query-string": "^4.1.0", "sort-keys": "^1.0.0" + }, + "dependencies": { + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + } } }, "npm-run-path": { @@ -11322,14 +11224,6 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "requires": { - "asap": "~2.0.3" - } - }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -11437,12 +11331,20 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.12.1.tgz", + "integrity": "sha512-OHj+zzfRMyj3rmo/6G8a5Ifvw3AleL/EbcHMD27YA31Q+cO5lfmQxECkImuNVjcskLcvBRVHNAB3w6udMs1eAA==", "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" + "decode-uri-component": "^0.2.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "dependencies": { + "strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" + } } }, "querystring": { @@ -11509,14 +11411,14 @@ } }, "rc-align": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-2.4.5.tgz", - "integrity": "sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw==", + "version": "3.0.0-rc.1", + "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-3.0.0-rc.1.tgz", + "integrity": "sha512-GbofumhCUb7SxP410j/fbtR2M9Zml+eoZSdaliZh6R3NhfEj5zP4jcO3HG3S9C9KIcXQQtd/cwVHkb9Y0KU7Hg==", "requires": { - "babel-runtime": "^6.26.0", + "classnames": "2.x", "dom-align": "^1.7.0", - "prop-types": "^15.5.8", - "rc-util": "^4.0.4" + "rc-util": "^4.12.0", + "resize-observer-polyfill": "^1.5.1" } }, "rc-animate": { @@ -11533,43 +11435,24 @@ "react-lifecycles-compat": "^3.0.4" } }, - "rc-calendar": { - "version": "9.15.10", - "resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.15.10.tgz", - "integrity": "sha512-xh1A3rYejKskAvkjnd9BcHXFbBnAYsHMGHBdtoAkbwp43B6yEieNL0g0Tzz8s1gApDZV2j5vF1jJ9IIpPYFNLw==", - "requires": { - "babel-runtime": "6.x", - "classnames": "2.x", - "moment": "2.x", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.0", - "rc-util": "^4.1.1", - "react-lifecycles-compat": "^3.0.4" - } - }, "rc-cascader": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-0.17.5.tgz", - "integrity": "sha512-WYMVcxU0+Lj+xLr4YYH0+yXODumvNXDcVEs5i7L1mtpWwYkubPV/zbQpn+jGKFCIW/hOhjkU4J1db8/P/UKE7A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-1.0.1.tgz", + "integrity": "sha512-3mk33+YKJBP1XSrTYbdVLuCC73rUDq5STNALhvua5i8vyIgIxtb5fSl96JdWWq1Oj8tIBoHnCgoEoOYnIXkthQ==", "requires": { "array-tree-filter": "^2.1.0", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.0", + "rc-trigger": "^4.0.0", "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.4", - "shallow-equal": "^1.0.0", "warning": "^4.0.1" } }, "rc-checkbox": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.1.8.tgz", - "integrity": "sha512-6qOgh0/by0nVNASx6LZnhRTy17Etcgav+IrI7kL9V9kcDZ/g7K14JFlqrtJ3NjDq/Kyn+BPI1st1XvbkhfaJeg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.2.0.tgz", + "integrity": "sha512-Wjh/nutLA8iIPTT1P9I9KOqlUblVe+CWa3SxMibFySnLyYbMxKNtPhwNcbADPOqzNU0AsCntTduNeJg1n0B5fg==", "requires": { "babel-runtime": "^6.23.0", - "classnames": "2.x", - "prop-types": "15.x", - "react-lifecycles-compat": "^3.0.4" + "classnames": "2.x" } }, "rc-collapse": { @@ -11607,58 +11490,23 @@ } }, "rc-dropdown": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-2.4.1.tgz", - "integrity": "sha512-p0XYn0wrOpAZ2fUGE6YJ6U8JBNc5ASijznZ6dkojdaEfQJAeZtV9KMEewhxkVlxGSbbdXe10ptjBlTEW9vEwEg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-3.0.2.tgz", + "integrity": "sha512-T3XP4qL6xmkxn8z52YF2SEPoMHPpBiLf0Kty3mjNdRSyKnlu+0F+3bhDHf6gO1msmqrjURaz8sMNAFDcoFHHnw==", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.6", - "prop-types": "^15.5.8", - "rc-trigger": "^2.5.1", - "react-lifecycles-compat": "^3.0.2" + "rc-trigger": "^4.0.0" } }, - "rc-editor-core": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/rc-editor-core/-/rc-editor-core-0.8.10.tgz", - "integrity": "sha512-T3aHpeMCIYA1sdAI7ynHHjXy5fqp83uPlD68ovZ0oClTSc3tbHmyCxXlA+Ti4YgmcpCYv7avF6a+TIbAka53kw==", - "requires": { - "babel-runtime": "^6.26.0", - "classnames": "^2.2.5", - "draft-js": "^0.10.0", - "immutable": "^3.7.4", - "lodash": "^4.16.5", - "prop-types": "^15.5.8", - "setimmediate": "^1.0.5" - } - }, - "rc-editor-mention": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/rc-editor-mention/-/rc-editor-mention-1.1.13.tgz", - "integrity": "sha512-3AOmGir91Fi2ogfRRaXLtqlNuIwQpvla7oUnGHS1+3eo7b+fUp5IlKcagqtwUBB5oDNofoySXkLBxzWvSYNp/Q==", - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "^2.2.5", - "dom-scroll-into-view": "^1.2.0", - "draft-js": "~0.10.0", - "immutable": "~3.7.4", - "prop-types": "^15.5.8", - "rc-animate": "^2.3.0", - "rc-editor-core": "~0.8.3" - } - }, - "rc-form": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/rc-form/-/rc-form-2.4.11.tgz", - "integrity": "sha512-8BL+FNlFLTOY/A5X6tU35GQJLSIpsmqpwn/tFAYQTczXc4dMJ33ggtH248Cum8+LS0jLTsJKG2L4Qp+1CkY+sA==", + "rc-field-form": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.1.3.tgz", + "integrity": "sha512-m7SUNNaum4pHrUj5MGnymEk3SRitMUZBhnMS0wqWrcL6XqvdTAG5Yz5HjukA6BryaS6nyQOgUVBXMxxNN/XsTQ==", "requires": { - "async-validator": "~1.11.3", - "babel-runtime": "6.x", - "create-react-class": "^15.5.3", - "dom-scroll-into-view": "1.x", - "hoist-non-react-statics": "^3.3.0", - "lodash": "^4.17.4", - "rc-util": "^4.15.3", + "@babel/runtime": "^7.8.4", + "async-validator": "^3.0.3", + "rc-util": "^4.17.0", "warning": "^4.0.3" } }, @@ -11685,55 +11533,59 @@ } }, "rc-mentions": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-0.4.2.tgz", - "integrity": "sha512-DTZurQzacLXOfVuiHydGzqkq7cFMHXF18l2jZ9PhWUn2cqvOSY3W4osN0Pq29AOMOBpcxdZCzgc7Lb0r/bgkDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.1.0.tgz", + "integrity": "sha512-uOVMiQ5Jxfo3mbpOZsZt20Alid0268lX9eBR2I/chly0qhNbmSB71iLOHGkbL7zuHd50GF/eSr9fXJJQKUYG1Q==", "requires": { - "@ant-design/create-react-context": "^0.2.4", "classnames": "^2.2.6", - "rc-menu": "^7.4.22", - "rc-trigger": "^2.6.2", - "rc-util": "^4.6.0", - "react-lifecycles-compat": "^3.0.4" + "rc-menu": "^8.0.1", + "rc-trigger": "^4.0.0", + "rc-util": "^4.6.0" } }, "rc-menu": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-7.5.5.tgz", - "integrity": "sha512-4YJXJgrpUGEA1rMftXN7bDhrV5rPB8oBJoHqT+GVXtIWCanfQxEnM3fmhHQhatL59JoAFMZhJaNzhJIk4FUWCQ==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-8.0.3.tgz", + "integrity": "sha512-a37l9MfzjXt8/q5en6ukjD2PoVsHCzWeRPdFK9eWi6hF5/9M3mfxgUt1LruQvaJKMQUxDyN5+4M8FsYULXJALw==", "requires": { "classnames": "2.x", - "dom-scroll-into-view": "1.x", - "mini-store": "^2.0.0", - "mutationobserver-shim": "^0.3.2", + "mini-store": "^3.0.1", "rc-animate": "^2.10.1", - "rc-trigger": "^2.3.0", + "rc-trigger": "^4.0.0", "rc-util": "^4.13.0", "resize-observer-polyfill": "^1.5.0", + "scroll-into-view-if-needed": "^2.2.20", "shallowequal": "^1.1.0" } }, "rc-notification": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-3.3.1.tgz", - "integrity": "sha512-U5+f4BmBVfMSf3OHSLyRagsJ74yKwlrQAtbbL5ijoA0F2C60BufwnOcHG18tVprd7iaIjzZt1TKMmQSYSvgrig==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.0.0.tgz", + "integrity": "sha512-In9FimkJY+JSIq3/eopPfBpQQr2Zugq5i9Aw9vdiNCGCsAsSO9bGq2dPsn8bamOydNrhc3djljGfmxUUMbcZnA==", "requires": { - "babel-runtime": "6.x", "classnames": "2.x", - "prop-types": "^15.5.8", "rc-animate": "2.x", "rc-util": "^4.0.4" } }, "rc-pagination": { - "version": "1.20.14", - "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.20.14.tgz", - "integrity": "sha512-sNKwbFrxiqATqcIIShfrFs8BT03n4UUwTAMYae+JhHTmILQmXdvimEnZbVuWcno6G02DAJcLrFpmkn1h2tmEJw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-2.2.0.tgz", + "integrity": "sha512-fXempMD/kvHu8tsiW70uPjn1pI4mdD62xFG9drcBh17gj5CbCjazrjpWS615RSauk3b2BBgIcAJzREAMvlAkFQ==", "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.6", - "prop-types": "^15.5.7", - "react-lifecycles-compat": "^3.0.4" + "classnames": "^2.2.1" + } + }, + "rc-picker": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-1.4.9.tgz", + "integrity": "sha512-Lg/+06ozXEsivYit+fNET6IKSY8xnWEDsuQiRjJttsELg1kE3JyCZflaX98nCxkg+2IQqMPVXLuKIiaYGr43Uw==", + "requires": { + "classnames": "^2.2.1", + "moment": "^2.24.0", + "rc-trigger": "^4.0.0", + "rc-util": "^4.17.0", + "shallowequal": "^1.1.0" } }, "rc-progress": { @@ -11757,45 +11609,37 @@ } }, "rc-resize-observer": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-0.1.3.tgz", - "integrity": "sha512-uzOQEwx83xdQSFOkOAM7x7GHIQKYnrDV4dWxtCxyG1BS1pkfJ4EvDeMfsvAJHSYkQXVBu+sgRHGbRtLG3qiuUg==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-0.2.1.tgz", + "integrity": "sha512-GENTRkL3lq05ilrjTxPpHUPrKTC9D7XqUGesSXgi/GyO4j/jKIjLPn7zuZOcJ5QmN5QGRe24IaVWPZHQPE6vLw==", "requires": { "classnames": "^2.2.1", - "rc-util": "^4.13.0", + "rc-util": "^4.14.0", "resize-observer-polyfill": "^1.5.1" } }, "rc-select": { - "version": "9.2.3", - "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-9.2.3.tgz", - "integrity": "sha512-WhswxOMWiNnkXRbxyrj0kiIvyCfo/BaRPaYbsDetSIAU2yEDwKHF798blCP5u86KLOBKBvtxWLFCkSsQw1so5w==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-10.2.4.tgz", + "integrity": "sha512-PtfAHQRXof5gX1qEYQc8GIgroajtzU3mcMGbqM1aE1jqaZ4r+p0GJy3rabXoNANsKH7jUV5+zYJb5VhTxj2vmQ==", "requires": { - "babel-runtime": "^6.23.0", "classnames": "2.x", - "component-classes": "1.x", - "dom-scroll-into-view": "1.x", - "prop-types": "^15.5.8", - "raf": "^3.4.0", - "rc-animate": "2.x", - "rc-menu": "^7.3.0", - "rc-trigger": "^2.5.4", - "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.2", - "warning": "^4.0.2" + "rc-animate": "^2.10.0", + "rc-trigger": "^4.0.0", + "rc-util": "^4.20.0", + "rc-virtual-list": "^1.1.2", + "warning": "^4.0.3" } }, "rc-slider": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-8.7.1.tgz", - "integrity": "sha512-WMT5mRFUEcrLWwTxsyS8jYmlaMsTVCZIGENLikHsNv+tE8ThU2lCoPfi/xFNUfJFNFSBFP3MwPez9ZsJmNp13g==", + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-9.2.4.tgz", + "integrity": "sha512-wSr7vz+WtzzGqsGU2rTQ4mmLz9fkuIDMPYMYm8ygYFvxQ2Rh4uRhOWHYI0R8krNK5k1bGycckYxmQqUIvLAh3w==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", - "prop-types": "^15.5.4", - "rc-tooltip": "^3.7.0", + "rc-tooltip": "^4.0.0", "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.4", "shallowequal": "^1.1.0", "warning": "^4.0.3" } @@ -11822,149 +11666,85 @@ } }, "rc-table": { - "version": "6.10.14", - "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-6.10.14.tgz", - "integrity": "sha512-yn47IqxXA4bzPAs1Aai7WwNzOBpuH1mm+GYrIIOUuGySaxz20Wr3udbRF+gLzEbG14CWUxomvcUaXyWPWdH08w==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.4.5.tgz", + "integrity": "sha512-lQS9izhGmgyCVK05imUrl32lBS9g2f3hB8LOKOof19JWCULKuYL5D3lLpaZSpCTecRYfONYNpgR7mZs7FOnYSQ==", "requires": { "classnames": "^2.2.5", "component-classes": "^1.2.6", "lodash": "^4.17.5", - "mini-store": "^2.0.0", "prop-types": "^15.5.8", - "rc-util": "^4.13.0", + "raf": "^3.4.1", + "rc-resize-observer": "^0.2.0", + "rc-util": "^4.20.1", "react-lifecycles-compat": "^3.0.2", - "shallowequal": "^1.0.2" + "shallowequal": "^1.1.0" } }, "rc-tabs": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-9.7.0.tgz", - "integrity": "sha512-kvmgp8/MfLzFZ06hWHignqomFQ5nF7BqKr5O1FfhE4VKsGrep52YSF/1MvS5oe0NPcI9XGNS2p751C5v6cYDpQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-10.1.1.tgz", + "integrity": "sha512-dOFeaYil3d6zV3ZtGZWfRf7zwyqUQ48cl67/Y/03SsBWEdYgfZzlgjfHqmUT+V7L7CvhQ5lIQyYpj4EthkgKCg==", "requires": { - "@ant-design/create-react-context": "^0.2.4", - "babel-runtime": "6.x", "classnames": "2.x", "lodash": "^4.17.5", - "prop-types": "15.x", - "raf": "^3.4.1", "rc-hammerjs": "~0.6.0", - "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.4", "resize-observer-polyfill": "^1.5.1", "warning": "^4.0.3" } }, - "rc-time-picker": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.7.3.tgz", - "integrity": "sha512-Lv1Mvzp9fRXhXEnRLO4nW6GLNxUkfAZ3RsiIBsWjGjXXvMNjdr4BX/ayElHAFK0DoJqOhm7c5tjmIYpEOwcUXg==", - "requires": { - "classnames": "2.x", - "moment": "2.x", - "prop-types": "^15.5.8", - "raf": "^3.4.1", - "rc-trigger": "^2.2.0", - "react-lifecycles-compat": "^3.0.4" - } - }, "rc-tooltip": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-3.7.3.tgz", - "integrity": "sha512-dE2ibukxxkrde7wH9W8ozHKUO4aQnPZ6qBHtrTH9LoO836PjDdiaWO73fgPB05VfJs9FbZdmGPVEbXCeOP99Ww==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-4.0.3.tgz", + "integrity": "sha512-HNyBh9/fPdds0DXja8JQX0XTIHmZapB3lLzbdn74aNSxXG1KUkt+GK4X1aOTRY5X9mqm4uUKdeFrn7j273H8gw==", "requires": { - "babel-runtime": "6.x", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.2" + "rc-trigger": "^4.0.0" } }, "rc-tree": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.1.3.tgz", - "integrity": "sha512-COvV65spQ6omrHBUhHRKqKNL5+ddXjlS+qWZchaL9FFuQNvjM5pjp9RnmMWK4fJJ5kBhhpLneh6wh9Vh3kSMXQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-3.1.5.tgz", + "integrity": "sha512-LOUfsJg5XxtA4FKgGkuVwnbBlnh3VVtySF7LMp4ko0n8oIUBYnn2vs6WG41kuH0V4tLTlQhvCFup/6JEKL01sg==", "requires": { - "@ant-design/create-react-context": "^0.2.4", "classnames": "2.x", "prop-types": "^15.5.8", - "rc-animate": "^2.6.0", - "rc-util": "^4.5.1", - "react-lifecycles-compat": "^3.0.4", - "warning": "^4.0.3" + "rc-animate": "^2.9.2", + "rc-util": "^4.11.0", + "rc-virtual-list": "^1.1.0", + "react-lifecycles-compat": "^3.0.4" } }, "rc-tree-select": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-2.9.4.tgz", - "integrity": "sha512-0HQkXAN4XbfBW20CZYh3G+V+VMrjX42XRtDCpyv6PDUm5vikC0Ob682ZBCVS97Ww2a5Hf6Ajmu0ahWEdIEpwhg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-3.1.3.tgz", + "integrity": "sha512-VQDr+qLCCJ9V/4ewnp3crMT2N7iJV58V0uWVA3nGJxVuxhSj8TPHFZLnyMh6vaNrQsrY6eBp/x1y6nEJBjnVQg==", "requires": { - "classnames": "^2.2.1", - "dom-scroll-into-view": "^1.2.1", - "prop-types": "^15.5.8", - "raf": "^3.4.0", - "rc-animate": "^2.8.2", - "rc-tree": "~2.1.0", - "rc-trigger": "^3.0.0", - "rc-util": "^4.5.0", - "react-lifecycles-compat": "^3.0.4", - "shallowequal": "^1.0.2", - "warning": "^4.0.1" - }, - "dependencies": { - "rc-trigger": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-3.0.0.tgz", - "integrity": "sha512-hQxbbJpo23E2QnYczfq3Ec5J5tVl2mUDhkqxrEsQAqk16HfADQg+iKNWzEYXyERSncdxfnzYuaBgy764mNRzTA==", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.6", - "prop-types": "15.x", - "raf": "^3.4.0", - "rc-align": "^2.4.1", - "rc-animate": "^3.0.0-rc.1", - "rc-util": "^4.15.7" - }, - "dependencies": { - "rc-animate": { - "version": "3.0.0-rc.6", - "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.0.0-rc.6.tgz", - "integrity": "sha512-oBLPpiT6Q4t6YvD/pkLcmofBP1p01TX0Otse8Q4+Mxt8J+VSDflLZGIgf62EwkvRwsQUkLPjZVFBsldnPKLzjg==", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "component-classes": "^1.2.6", - "fbjs": "^0.8.16", - "prop-types": "15.x", - "raf": "^3.4.0", - "rc-util": "^4.5.0", - "react-lifecycles-compat": "^3.0.4" - } - } - } - } + "classnames": "2.x", + "rc-select": "^10.1.0", + "rc-tree": "^3.1.0", + "rc-util": "^4.17.0" } }, "rc-trigger": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.6.5.tgz", - "integrity": "sha512-m6Cts9hLeZWsTvWnuMm7oElhf+03GOjOLfTuU0QmdB9ZrW7jR2IpI5rpNM7i9MvAAlMAmTx5Zr7g3uu/aMvZAw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-4.0.2.tgz", + "integrity": "sha512-to5S1NhK10rWHIgQpoQdwIhuDc2Ok4R4/dh5NLrDt6C+gqkohsdBCYiPk97Z+NwGhRU8N+dbf251bivX8DkzQg==", "requires": { - "babel-runtime": "6.x", "classnames": "^2.2.6", "prop-types": "15.x", - "rc-align": "^2.4.0", - "rc-animate": "2.x", - "rc-util": "^4.4.0", - "react-lifecycles-compat": "^3.0.4" + "raf": "^3.4.1", + "rc-align": "^3.0.0-rc.0", + "rc-animate": "^2.10.2", + "rc-util": "^4.20.0" } }, "rc-upload": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-2.9.4.tgz", - "integrity": "sha512-WXt0HGxXyzLrPV6iec/96Rbl/6dyrAW8pKuY6wwD7yFYwfU5bjgKjv7vC8KNMJ6wzitFrZjnoiogNL3dF9dj3Q==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-3.0.4.tgz", + "integrity": "sha512-dTCvj1iHxjHG0qo5UyN2ZmtueG9GG3xrOhOwnjsehaoOvl0TOjLbHkUIPPqLZk+wHb57Ue4KB7c3+IMgkDoBvw==", "requires": { "babel-runtime": "6.x", - "classnames": "^2.2.5", - "prop-types": "^15.5.7", - "warning": "4.x" + "classnames": "^2.2.5" } }, "rc-util": { @@ -11979,6 +11759,16 @@ "shallowequal": "^1.1.0" } }, + "rc-virtual-list": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-1.1.2.tgz", + "integrity": "sha512-+WwxrtmBta7vcPCty7MtgilBmbxSGwN28Y8o+MG3GkHZccV0tXT+PLnAB+5WOjhhH10iFq+pzviRcXgcZ1x4OA==", + "requires": { + "classnames": "^2.2.6", + "raf": "^3.4.1", + "rc-util": "^4.8.0" + } + }, "react": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", @@ -12303,17 +12093,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, - "react-lazy-load": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/react-lazy-load/-/react-lazy-load-3.0.13.tgz", - "integrity": "sha1-OwqS0zbUPT8Nc8vm81sXBQsIuCQ=", - "requires": { - "eventlistener": "0.0.1", - "lodash.debounce": "^4.0.0", - "lodash.throttle": "^4.0.0", - "prop-types": "^15.5.8" - } - }, "react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", @@ -12404,18 +12183,6 @@ } } }, - "react-slick": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.25.2.tgz", - "integrity": "sha512-8MNH/NFX/R7zF6W/w+FS5VXNyDusF+XDW1OU0SzODEU7wqYB+ZTGAiNJ++zVNAVqCAHdyCybScaUB+FCZOmBBw==", - "requires": { - "classnames": "^2.2.5", - "enquire.js": "^2.1.6", - "json2mq": "^0.2.0", - "lodash.debounce": "^4.0.8", - "resize-observer-polyfill": "^1.5.0" - } - }, "react-transition-group": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.3.0.tgz", @@ -13032,6 +12799,14 @@ "ajv-keywords": "^3.4.1" } }, + "scroll-into-view-if-needed": { + "version": "2.2.24", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.24.tgz", + "integrity": "sha512-vsC6SzyIZUyJG8o4nbUDCiIwsPdH6W/FVmjT2avR2hp/yzS53JjGmg/bKD20TkoNajbu5dAQN4xR7yes4qhwtQ==", + "requires": { + "compute-scroll-into-view": "^1.0.13" + } + }, "scss-tokenizer": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", @@ -13273,11 +13048,6 @@ } } }, - "shallow-equal": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", - "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" - }, "shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -13684,6 +13454,11 @@ } } }, + "split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -14574,11 +14349,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==" }, - "ua-parser-js": { - "version": "0.7.21", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz", - "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==" - }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 7c84d05..282025b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,8 +11,9 @@ "@types/react": "^16.9.19", "@types/react-dom": "^16.9.5", "@types/react-transition-group": "^4.2.3", - "antd": "^3.26.9", + "antd": "^4.1.4", "node-sass": "^4.13.1", + "query-string": "^6.12.1", "react": "^16.12.0", "react-dom": "^16.12.0", "react-scripts": "^3.4.0", diff --git a/frontend/src/components/App.tsx b/frontend/src/components/App.tsx index 57212bc..e15f5b5 100644 --- a/frontend/src/components/App.tsx +++ b/frontend/src/components/App.tsx @@ -1,13 +1,10 @@ import React from 'react'; -import {SocketIOProvider} from "use-socketio/lib"; import Centurion from "./Centurion"; const App = () => { return ( - - - + ); }; diff --git a/frontend/src/components/Centurion.tsx b/frontend/src/components/Centurion.tsx index 39f5588..8460ce9 100644 --- a/frontend/src/components/Centurion.tsx +++ b/frontend/src/components/Centurion.tsx @@ -1,76 +1,38 @@ -import React, {useEffect, useRef, useState} from "react"; +import React, {useRef, useState} from "react"; import {Row} from "antd"; -import {useSocket} from "use-socketio"; import {NumberParam, useQueryParam} from "use-query-params"; -import {Tick} from "../types/types"; - +import {roomTime, useRoom, useRoomRunningChanged, useTick} from "../lib/Connection"; import NextShot from "./NextShot"; import Feed from "./Feed"; import ShotsTaken from "./ShotsTaken"; import Lobby from "./Lobby"; import logo from "../img/via-logo.svg"; +import Player from "./Player"; const Centurion = () => { - const [started, setStarted] = useState(false); - const [wantsToStart, setWantsToStart] = useState(false); - const player = useRef(new Audio("centurion.m4a")); - const [noSound] = useQueryParam('noSound', NumberParam); - - function goStart() { - console.log("Starting from wrapper.."); - setWantsToStart(true); - } - - - useSocket("started", async (obj: any) => { - console.log("got started"); - setStarted(true); - - if (typeof noSound === 'undefined') { - await player.current.play(); - } - }); - - useEffect(() => { - if (noSound === 1) { - // Won't play sound so we don't get DOM Interaction errors. - setWantsToStart(true); - } - }, [noSound]); - - useSocket("tick_event", async (tick: Tick) => { - if (!started && wantsToStart) { - if (player.current.paused) { - if (typeof noSound === 'undefined') { - await player.current.play(); - } - } - - setStarted(true); - player.current.currentTime = tick.current; - } - }); + let roomRunning = useRoomRunningChanged()?.running || false; const feedContent = ( - - - - - + + + + + + + + ); const lobbyContent = ( - + ); - const content = started ? feedContent : lobbyContent; - return ( <>
- {content} + {roomRunning ? feedContent : lobbyContent}