Skip to content

Instantly share code, notes, and snippets.

@splintor
Last active May 8, 2022 08:38
Show Gist options
  • Save splintor/adccd10959dd83f76741ee7536396a96 to your computer and use it in GitHub Desktop.
Save splintor/adccd10959dd83f76741ee7536396a96 to your computer and use it in GitHub Desktop.
GitHub - Continue in SSO
// ==UserScript==
// @name JIRA Meetinator
// @namespace http://shmulikf.wix.com/
// @version 0.15
// @description Improve team meeting experience in Jira: Enable randomly selecting a team member, set time limit for each team member, celebrate completion.
// @author Shmulik Flint
// @match https://jira.wixpress.com/secure/RapidBoard.jspa*
// @icon https://jira.wixpress.com/s/-8bjowq/813009/g345zt/_/images/fav-jsw.png
// @downloadURL https://gist.githubusercontent.com/splintor/f10c20926335324c6ff8e007439ed64c/raw/JIRA-Meetinator.user.js
// @updateURL https://gist.githubusercontent.com/splintor/f10c20926335324c6ff8e007439ed64c/raw/JIRA-Meetinator.user.js
// @require https://cdn.jsdelivr.net/npm/canvas-confetti@1.5.1/dist/confetti.browser.min.js
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addStyle
// ==/UserScript==
/* globals confetti */
// TODO: Add sounds: When time is about to end. When time ends, when all members finished
(function() {
'use strict'
const memberHeadingSelector = '.ghx-heading'
const closeMemberSelector = '.ghx-swimlane.ghx-closed'
const openMemberSelector = '.ghx-swimlane:not(.ghx-closed)'
const getMemberHeadings = () => document.querySelectorAll(memberHeadingSelector)
const getMembersProgress = () => document.querySelectorAll(memberHeadingSelector + ' progress')
const getOpenMember = () => document.querySelector(openMemberSelector)
const getContainer = () => document.querySelector('#ghx-pool')
const getMeetinator = () => document.querySelector('#Meetinator')
const markMemberAsVisited = (memberHeading) => memberHeading.classList.add('visitedMember')
const markMemberAsNotVisited = (memberHeading) => memberHeading.classList.remove('visitedMember')
const getMemberName = (memberHeading) => memberHeading.querySelector('.js-expander + span').innerText
function getClickedMembers() {
const clickedMembersJSON = GM_getValue('clicked_members', '{}')
try {
return JSON.parse(clickedMembersJSON)
} catch (e) {
return {}
}
}
let clickedMembers = getClickedMembers()
function updateClickedMembers(updates) {
clickedMembers = { ...clickedMembers, ...updates }
console.log('clickedMembers', clickedMembers)
GM_setValue('clicked_members', JSON.stringify(clickedMembers))
}
function resetClickedMembers() {
GM_setValue('clicked_members', '{}')
clickedMembers = {}
}
const wasConfettiDisplayed = () => GM_getValue('confetti_displayed', '') === 'true'
const setConfettiDisplayed = (value) => GM_setValue('confetti_displayed', String(value))
let timerTime = Number(GM_getValue('timer_time', '300'))
function getMembers() {
const members = [...getMemberHeadings()]
const relevantMembers = members.filter(m => !clickedMembers[getMemberName(m)])
return { members, relevantMembers }
}
function onClick(e) {
if (e.target.type === 'submit') {
const { relevantMembers } = getMembers()
const memberToClick = relevantMembers[Math.floor(Math.random() * relevantMembers.length)]
updateClickedMembers({ [getMemberName(memberToClick)]: new Date().toISOString() })
markMemberAsVisited(memberToClick)
updateButtons()
memberToClick.click()
} else if (e.target.type === 'reset') {
resetClickedMembers()
setConfettiDisplayed(false)
const { members } = getMembers()
members.forEach(markMemberAsNotVisited)
updateButtons()
}
}
function buildUI() {
const ui = document.createElement('div')
ui.id = 'Meetinator'
ui.innerHTML =
'<div class="logo" tooltip="abc">' +
'<img width="50px" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7N15nBxlnT/wz/ep6mPOnJPJTDI5ZzKTBJBLREUJAuGQQ8DhRhDwgMVVVzk8UHQ9V9ldj/WnriuKXILrxYIXKqKuLIICArkgCZBjcsxk7p4+qr6/P0JiIDOZ7pnufqqqP+/Xy9eLzPRUfWKmqz5d9dTzAEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREkSK2AxBR6a1bty5RV1fX5vt+uzFmDoBqVZ0qIllVHRSRbgAbcrncmrlz526ynZeISo8FgCiitm3b9lpVfTOAFap6FIBYnj+6A8CDqvobY8wPZ8+evb10KYnIFhYAogh5/vnnpyUSiXer6mUAlhRhkzkAPxeRbzQ2Nt4nIlqEbRJRALAAEEXAiy++ON113esBXAWgrhT7UNUnAHyyubn5h6XYPhGVFwsAUYipqnR1dV0C4AsAZpVptw8C+IempqZnyrQ/IioBFgCikNqyZctMEfkOgDdb2P2IiNwwe/bsL1nYNxEVAQsAUQht3br1KAD/DWCuzRyqeqfneVe0tLSkbOYgosKxABCFTFdX1/Gq+iOU6F7/BDzsed5pc+fO7bYdhIjyZ2wHIKL8dXV1na6q9yM4J38AONp13Qc2bNgw1XYQIsofrwAQhURXV9fRqvoAgBrbWcbwsKoe39zcPGw7CBGNj1cAiEJg69atC1765B/Ukz8AHG2M+abtEESUHxYAooBT1Ziq3g5gmu0s41HVi7q6uq60nYOIxscCQBRwXV1dN4rI62znyJeqfnnbtm2LbOcgogNjASAKsO3bt7cBuNZ2jgJV+b7/NdshiOjAWACIAszzvH8DkLSdYwJO2rp1q40JiogoTywARAG1efPmwwCcajvHJHzMdgAiGhsLAFFAGWM+gnA/qnvUtm3bTrAdgohGxwJAFEDbt2+fDeAM2zkmy/f9d9rOQESjYwEgCqDu7u6vqmrMdo7JGhoaesuqVasW2M5BRPtjASAKoGw2u3J4OPwT6g0NDcVE5DrbOYhofywARAGzevXq5lwuVzc4OAhVtR1nwlKpFDzPQy6XW2k7CxHtjwWAKHjeDgC+7yOsVwFUFYODgwAAz/PmW45DRKNgASAKGN/3j93z34ODg/A8z2acCRkeHkYulwMAeJ7nPvnkk5wZkChgWACIAkZVF+75b9/30d/fbzNOwXK5HAYGBl72tXg8fuwYLyciS1gAiALG9/2Gff88MjISmlsBqoq+vr79xi6IyOGWIhHRGFgAiAJGVROv/Fp/fz8ymYyNOAUZK6fv+zMtxCGiA2ABIAoY3/fdV35NVdHb27v3vnoQDQ0NjXmlQkTqyxyHiMbBAkAUMCKjz/7reR56enoCOShweHj4gGMVojCpEVHUsAAQBYyIjHmG9zwP3d3dgboSMDQ0hL6+vvFe1luOLESUPxYAooARkeyBvr+nBIyMjJQr0qj23JbI5ykFERm3IRBRebEAEAWMiIz7adn3fezatQv9/f1WZgvM5XLo7u5GKpXK6/WqurrEkYioQPsNNiIiu4wxGwHMzee1Q0NDSKfTqK+vRyKx38MDRef7PoaGhjA0NFRQ8XBd97cljEVEE8ACQBQwIvIEgGPyfX0ul0NPTw/i8Thqa2tLUgR830cqlcLg4CB83y/oZ40x2tra+njRQxHRpPAWAFHAxGKxWybyc5lMBj09Pdi5cyeGhoYKPlGPJpvNor+/H9u3b0d/f/+Etum67jYRmXwYIioqXgEgCpjW1tbHnnjiiazneRN6dC6bzSKbzWJgYACxWAyJRAKxWAyxWAzGjN35VRWe5yGbzSKTySCdThflkUNjzMOT3ggRFR0LAFEAxWKxJz3PO2Iy21BVZDKZl83MJyJwHAciAmMMVBWqCt/34ft+SQYUxuPxLxd9o0Q0abwFQBRAxpjPlWK7qopcLodsNot0Oo1MJoNsNgvP80py8nddd6C1tZUDAIkCiAWAKIA6Ojp+4LpuOFYAOoB4PP5j2xmIaHQsAEQBFY/Hv2U7w2Q4juN7nvc+2zmIaHQsAEQB5XnetY7jBH8JwDHEYrF7ly9f3mM7BxGNjgWAKKCWL1+eSSQS/2w7x0Q4jpNNp9OX2c5BRGNjASAKsI6Ojk/FYrEu2zkKlUwmP33YYYdxASCiAGMBIAo413VPM8aEZiKdRCKxpr29/RO2cxDRgbEAEAXc0qVLH0smkx+3nSMfruuOuK6b9zTGRGSP2A5ARPlZvXr1/cPDw6fYzjEWY4xfVVW1sr29/de2sxDR+HgFgCgkOjo6Tk0mk4/ZzjEaEdFkMnkpT/5E4cECQBQiS5cuPSqRSDxiO8e+REQTicQ1HR0dt9nOQkT54y0AohB65pln7hsZGTnVdg5jTK66uvotS5Ysuc92FiIqDAsAUUitW7fu/UNDQ1/0fd/Klbx4PL4tkUi8vq2t7Tkb+yeiyWEBIAqxtWvXHppOp+/NZrNzy7XPl+7339XR0XGxiITm8UQiejkWAKIIWLNmzYcymczHstlsspT7SSQSa+Px+FltbW3PlHI/RFR6LABEEaGqZu3atZ9Kp9PX5HK5umJtV0Q0Ho+visViVy1ZsuShYm2XiOxiASCKoMEbPvG5dF3t+d2HHzx7sHFmotCfd7M5nfrcxt6Zf3x0R9Xzm3pw5JLXy0038XI/UYSwABBFjJ5yUT38zLMAGgBARXZlmhp3jiyYJ6mmmXUj06ZW+zXVTs51XON5vpPJes5QKlfVtX0guXnbcPULm2JO/0ALAHefrV4qv/jBrXb+RkRUCiwARBGjJ73104B8uLgbxWYkRpbIvfcOF3W7RGQNJwIiihA98fxmQN5X9A0L5iCb/Ieib5eIrGEBIIoS8T4JoLok21Z8WI8/a0ZJtk1EZccCQBQRuvKcDgguLeEupsKNfaiE2yeiMmIBIIoKMV/AywbulYK+R084Z1Fp90FE5cACQBQBuvLcNwI4rQy7isMxN5VhP0RUYiwARCGngED0c2Xc5UV60nmHl3F/RFQCLABEYXfyW98K4LVl3KOB+J8t4/6IqAQ4DwBRiOmKFS4SDU8DWFL+vcub5Bd3/7b8+yWiYuAVAKIwSzZcCisnfwDQT9nZLxEVA68AEIWUdnbG0Y/VABZajHGa/OKe+yzun4gmiFcAiMJqQN4Nuyd/QPFZvekmHkeIQohvXKIQ0s7OKqhebzsHBAfj4afOsR2DiArHAkAURn14L4Bm2zEAACqf0hUrSjwBEREVGwsAUcjoCZ1TILjWdo59LEGy4WLbIYioMCwARGHj6AcATLcd42UUN+kppyRsxyCi/LEAEIWInn7BTEDeazvHKObDr7vSdggiyh8LAFGYZLwbANTbjjE6/YiefnppliImoqJjASAKCT3p7CZAr7Kd4wCakE3+g+0QRJQfFgCi0HBuBBDsT9iK6/WUiwJ6hYKI9sUCQBQCuvL8FgBX2M6Rhxnws9fYDkFE42MBIAoDyX0YQNx2jPzoP+kZZ9TZTkFEB8YCQBRwesrZcwF5u+0cBZiBkQTHAhAFHAsAUdD55gYA4XrGXvBBXgUgCjYWAKIA05POboLK5bZzTMAMZBLvth2CiMbGAkAUZOJ+CIIq2zEmRHGdruistR2DiEbHAkAUUHpq52z4GubZ9WYioe+yHYKIRscCQBRUnlwf2k//e8m1nB2QKJhYAIgCSI+/oBHQd9rOUQSNSFfxKgBRALEAEAWRm7sOQZ/1L1+i12lnZ8ivZBBFDwsAUcDsXvEPUfj0v8dsDMg7bIcgopdjASAKmmz2egDRGj2vegOvAhAFCwsAUYDo8WfNgEoUn59vQn8o1jIgqhgsAERB4jrXImqf/v/ueu3sDMl6BkTRxwJAFBC7l9GN5Kf/PeZiAJfYDkFEu7EAEAXF7mV0p9iOUVKKa/Wmm3jcIQoAvhGJAkBXXJYE9BrbOcqgHX965izbIYiIBYAoGJKDlwNosh2jPPR62wmICBDbAYgqnXZ2OujHagCttrOUjegJ8vMf/Np2DKJKxisARLYNyLmopJM/AKjwKgCRZSwARLapftB2BAtO1BPPOdJ2CKJKxgJAZJGufOspAA63ncMK41xnOwJRJWMBILKqki+F6zl66nlLbKcgqlQsAESW6EmdR0FwrO0cFhl4XiXe/iAKBBYAIns+bDuAffI2PfH8ZtspiCoRCwCRBbrynA4Ap9vOEQAJiPc+2yGIKhELAJENYq4H33+7Cd6tb75wmu0YRJWGByCiMtNTzp4L4ELbOQKkDl7mH2yHIKo0LABE5ea7HwDAZXH3pfI+XXlJje0YRJWEBYCojHZf6tYrbecIoBmQNJcKJiojFgCicsrl3gmg1naMYNL3c6lgovLhm42oTHTFChfQq23nCLAlePiZk22HIKoULABE5RKf+VYA82zHCDRVPhJIVCYsAETlIsKT2/hO1JPPOcR2CKJKwAJAVAZ6cudrAbzGdo5Q8M0/2o5AVAlYAIjKQeX9tiOEhuBiPf6CRtsxiKKOBYCoxPSEznmAnmU7R4gk4HrvtB2CKOpYAIhKzdX3AHBtxwgXvUZXXJa0nYIoylgAiEpIV15SA5XLbecIoVmID59nOwRRlLEAEJVU6nIA022nCCf9gAJiOwVRVLEAEJWIAgIRLnIzUYKDcfJbj7UdgyiqWACISuXkztMBtNuOEWp8eoKoZFgAiEpFwYl/Ju90PbmTJYqoBFgAiEpAT+08GMAK2zkiQADeRiEqBRYAolLw9QPgALbiUL1cT+rkQEqiImMBICoyXXnWLKjwEbbi4aOURCXAAkBUbCZ2NQBOYlNMotdoZ6djOwZRlLAAEBWRrljhwtcrbeeIoPno01NshyCKEhYAomJKzDoTgjm2Y0STXGU7AVGUsAAQFZXyJFUqgpN1ZedC2zGIooIFgKhI9KTOVgBvsp0jwgxE32U7BFFUsAAQFYvo1eCjfyUmV3CVQKLiYAEgKgLt7KyCyqW2c1SAmUgMnW07BFEUsAAQFcMAzgNX/SsXjrMgKgIWAKJiUJ6UyuiYl6ZaJqJJYAEgmiQ9sfNQAEfZzlFRcvJu2xGIwo4FgGiyjF5tO0LFEb1ET7mo3nYMojBjASCaBD3jjDpAzredowLVQdMX2A5BFGYsAESTkU5cCqDOdoyKpMIrL0STwAJANDmcmMaeQ/TkztfaDkEUViwARBOkK899I4CDbOeoaHz6gmjCWACIJo4nH/vO1VM6G2yHIAojFgCiCdBTOhsgepbtHIQEPM7ASDQRLABEE6F6JYCE7RgEQPTdetNNPJYRFYhvGqIC6U03Gai8w3YO2msx/vjUCbZDEIUNCwBRoR5+5mQAXJc+SIzwaQyiArEAEBVK9QrbEWg/Z+ipnbNthyAKExYAogLo6RfMBPBm2zloPy48vch2CKIwYQEgKkQmeyk4+C+g5B0KiO0URGHBAkBUELncdgIaUztO7jzadgiisGABIMqTrnzr6wAss52DDsAHx2cQ5YkFgChfwpNL4AnO271CIxGNhwWAKA+6orMWkE7bOWhctUjH32o7BFEYsAAQ5SOJ88Blf8NBhFdqiPLAAkCUD+Xl/9BQvF5POG+p7RhEQccCQDQOXXlOBwCuOx8mjl5mOwJR0LEAEI3HGK42Fzp6sXZ2OrZTEAUZCwDRAexe+AecYS58mjEgXCCI6ABYAIgO5E/PvAlAi+0YNAGqb7MdgSjIWACIDognkdBSnKUr3jLVdgyioGIBIBqDrrykBsBZtnPQBAmqkIydYzsGUVCxABCNxYx0Aqi1HYMmQcEBnERjYAEgGouCl//D7xg95bzFtkMQBRELANEo9NSz5wM41nYOmjSB6iW2QxAFEQsA0Wh8cwn4/ogG1UsVENsxiIKGBzii0ajwU2N0LMDKc99gOwRR0LAAEL2CnnzeqwEssZ2DiupC2wGIgoYFgOiVVHmyiBrRc7WzM247BlGQsAAQ7WP31L/aaTsHFd009MlJtkMQBQkLANG+fvvYeRDMsR2DiiznQfv7brIdgyhIODKWaB/eEW9aC89rk6lTIQleMY4CHRyE398PKOAkapvlsV9stZ2JKAh4BYDoJfqaU+o1k2nVbBb+zp3wd/UCvm87Fk2QZrLwt++A39sH+Aqownf0Rtu5iILCtR2AymfBLTrVS6K6ykcyBzgC1O/7fQ/w4kA/AGQBzwP6X7hIdtlJW36+5j4M3999VUwVOjQEbyQFM3UqpKrKcjrKm/rw+wehAwP7fy+bPgfA1WXPZIk+f+E0xFAPBw4AIIt6mJf+ew/P9CHu+0j7I/CSw7LwO702slL58RZAyC2+VWdpDPMgmAcf82AwHz4aIGgA0AhgJoCpAGomsZs+AL0A+qDYLoKtvqJLgC1i0OUBG12D5549V3YU4a9kjXfEcS/oSHrUpX+lqgpm6hTAcUb7NgWEpkbg9/burq+jEcCZOrVd/nD/2vImKx7tumQWcv4iiL8QYhqhOgeKRgiaATQAmArBFCimTGI3g4D2AdgJSBeAnVDdASMbAbwI+C/AxF6Q2d/bXoS/ElnCAhASrXdrg+ZwsG+wTICDoFgOYDmAabaz7aUYgGA9gOdEsQoGT2kOT1fFsebpcyVjO96B6PFnNHrburugOvaLjIGZMgVSU12+YJQf34ff2wcdHh73pVJTfbvzyAMXlyHVhOnTnXHUux0wsgyKgwF0QHQxIIsA1NnOt49dgD4FNc9A9CkonoaTfUqa7gn1h4FKwQIQQAvv0EYBjoHBMfDxKggOwu5mH1ZZKNZB8BdRPOIZ/BkpPL7x7TJiO9ge3tErv6YDg1fl81pJJmCmTQccDqEJAk2n4ffsGvtT/ytIPN7r/PXBwBRn3XBZErH0YTDyavjyagiOALQN4b5FuwPA36D6JIz8Hsb5A68WBA8LQAAsuV0XeYI3qOANUBwDQbvtTGWQheBJVfxRFA8ZFw/ZvIXgHX7cNk2nZ+X9A8bATOPYAKtU4ff1QwcHC/5RZ9q0I+UP9z1WglTj0q2dDVD3jVBzLKCvh+BgKGI2spTZGgB/gOIhxPAHabxjve1AlY4FwIIFt+hUpwonq+J0AVYo0Gw7UwAogGcg+B18/AYuHlh/rvSVZccnnD7P6+p5/oCX/8cg1VUw06YBwrdSOWk6A793F5DNTejnTW31D83/PXBOkWONSp/rnIJE/EQIjgN0BYCl4LEXgG4G5EFA7kUm9gsOPiw//hKWyYI7dYEjWKmK0wGsBMCHzA/Mg+BxKP5HfNz73IX4C0QKP0Pns6PXrPwvHRy8fMIbcByY6dM5b0A5qMLvHxh9hH8BJBEbcP7yu/rxXzkxuu3CRfBwOhSnAXgj+H4fjwfgYQD3AubHMue2NbYDVQIWgBJqvVMP84FOAKcDOMh2npDbBMV/i+Du587Hn4pZBrzDj9uh6fTMSW1EBFJbCzOlZOcUyuXg9+yCZoozntSZMv118r//86dibEsVgi3nvxZqzoXgHABzi7HdiiX4G3zcC5i7Ze5tT9iOE1UsAEU2/3va5MRwLhRvA3C47TwRtUmBH4rinvUX4I+TKQN6zJsXeb29z03k8v9oJJGAmc4BgsWmIyO7B/oVcWImU13zU/PnX505mW3o1guWw5dOCC6GYnGxstHLPAPgVsSy35VZ93TZDhMlLABFsOAWTTpJnKmCt0FxEgA+LF4+zwO4Sxx867lz5dlCf9g7auV3dWjwbUVNZMzuWwLJRFE3W6n8/n7owCCKVdL2kFh80Hn8wYIfqdMXL2yD0SsBOQ/A/KKGogPJQeQX8P1bkU38VBZ+JzBPEYUVC8AkzL9LlzqK90BwARRTbeepcArgAQi+Pq8RP33wOMlrdJh32HHdmklPL0Ugqa+DqavjAMGJ8n34PT3QkXTJduHUT1khf/rZ78Z7nT76zhiaB86AyrsBHA8eO23rBXA7YL7C8QITx1/iQqnKortxPHy8F8Cbwf8Pg6gLwHd94OsbL5CNY71I33ham9eza22xP1nuS5JJmOnTAMNbAoXQdAZ+T0/ez/ZPlKmpvt888sCbx8zxwvnNcMwl2D198LyShqGJ+iOgn0fznf8jgtK9mSOIJ688Lb9ba4c9XCrAPwJYYjsP5cWD4h4FPrvhQnlyv28edcLtOjR8YclTOA7MjOmQOAeC50P7B3av3lcGEnOHnccf2m+abN108asg+mFAzwFv6YXFaii+DNe5VWZ/b8h2mDBgARjHkjt0Zg74AARXAZOaW5vsUQHu9X18esNF8sieL3qHrejRTKY8M8IJYKZNg1RzGuExqb97lH+qvLd2ndqak+T/fvVLANBNFx29+8SP08DjY1j1QvE1wP1XmXtrt+0wQcZf8DF0fFdnZOJ4D4D3gSf+KPmjKj6//v+d+pzX0/d0uXe+91FBjgt4Oc+Dv7Mbms2WfdemuupX8pNZn4TK9dh94qdoGATwbcSyn+XTA6PjUegVWu/WBt/HB6G4GkCt7TxUGtNTvX+95a4PLl26eVWy3PuWqqrd4wJYAgAAmknD39lT1Ef88iUdVWlz48wX0OC0lX3nVC6DgHwV4t8szXfutB0mSHgEesmCW3SqSeIGANdgckvnUnj4r3/+L6u/8NNPLpnZt6OsC69IPAYzY2bFzxegwyn4u3YV/RG/8UhD3DPXzlyPQ+OLAVT2P0Ll2F0ERjKfk8X3lGWa8aCr+AKw4rfqvrgNl6vinwHkvxgMRYZAhy9+/Cdd1/7iKwuT2ZHyvSdcF87MGYAb5kXfJk4HBncP9ivnyT8hcK5sWIczqmdDArWsLpVPD4B/QW/232T5PYFeprzUKroALLxTzxDFv1TI6ns0jngu1/XFn30mdvITv5hRtp0as/sJgURlTRrk9/XtntynjMyJU/rkvdPSiLPoEwBgNaDXyZw777UdxJaKLACtd+nhnuJmAVbYzkLB86quNau+8f3rlkwf2Fmex79Eds8cWFX24Qjlp/rSSP9U2XYpDXHP3NSwAW2x1rLtlMLkN1B8QObe8bjtIOVWUQWg8VatqYnhRgAfBJ/tpQMwqn03/O7rw5f94bamsu1zesQfE1SF391d0pn9Xsm8edomec+UahiUZLZHigwfim+hSq6VGbeXZxKKAChZAVBVZ/v27QtyudxsEakRkSkiMgJgSER2qupzs2fPLttkDQvv0NNF8B8AWsq1Twq/RT0vrPnOXf/UOrtna1kKo5k6BVIbwYdP1N/9mF+6TLdcZ8Z859ON67DQ5e09yp9gK3zcIHPvuLVcu9y+fXutqi5S1ZkAalQ1qap9qjrkuu7WWbNmPS8iJZkSs2gFYNOmTTNc1z1BVVcAeD12z5Y33o3NFwH8VUR+A+DXs2fPfqpYefZYcrfOyXn4MoCzi71tqgxGdeCL930md9rj95dl0iAzpR5SF6HxaZ4Pv3snNFOeZ/zNm6b0yHXTXBhwbWaaGJH7IN410nTXxmJvuqur62Df948XkeMAHIbxP5SmAawB8L8AfpvL5R5oaWnpKUaWSRUAVXW2bt16OoDLROQUAJOd6/QpALeKyHdnz569fVJbuknNoiX4Rwg+DSDC11WpTPTNax5a9YUffmyZ65X+RGbqp0DqI3AlwPfh79hZngl+XANzY+MqeW2iAxV2e5NKYgiCj6BpyVdEbprUJBVdXV2zVPXtAN4GYNkkc2VE5H4A32lsbLxXRCacbUJvElWNbdu27RJVvR6lmRd/WFX/0/O8L7S0tGwu9IcX3KkLjOLbEBxXgmxUwaan+tbf/Z13zpvXvankz+6F/kqAKvztO8py8pemRM58qXEjphoO9KMik/+FL5dKy20FLze+efPmFmPMtQCuBFBV/GxYA+Bzs2fPvk0kvxVQ91VwAdiyZcsxIvI1AAcX+rMTMAzgC4ODg59ta2sbf+SQqiz+Pt6hPr7IZ3ypVIyvvV/66cf1pKd+XfJbAqG9EqC6+5N/pvT3/OVN9f3m+ukK4ZTdVDIDEP0nNN35X/msOPjSh+SrVfVTKM+Msk/6vn/1nDlz/ljID+VdADZs2JBMJpM3A7iqkJ8rkr8BOL+pqemZsV7Qcqc2u8B/CXByGXNR5fLf9chdz3/gl19ZWOodmalTIbUhmpyyjCd/c3XDBnlLzQLwkj+Vg+B+ZMyVsuC2rWO9pKur6yBV/T4mf6m/UArgq4ODg9fm9YEZeb5ptm/f3ur7/j2qeuik4k3OEICrm5qa9huduehOPR7AbQBmlz0VVbSjX3z86W/f9r7lpR4XYKZNg9SEYCiLKvzuHuhIiVf0cwHnn5ufwRHxch9kiXbAx2XScsf9r/zG1q1b3w7gP1Cay/35+osxprOxsXH9eC8ctwBs2bLliJcGHARl9qzPNzU13QDsnsb3hS58FMCN4HzeZMnc/q7VP/7Pty+pT/WX8HdQYGbOgCQDPGNguSb5qXfV+Vrzs5hluIAP2aIAvoLe7LV7phPeunXr9QA+ZzfWXttU9dTm5ua/HOhFBywAL93vvx8I1v10Vf3yG37X9EUF7sTuRw6JrKrJpLb86NtXNC7Y+Xzp5gsQgZk5E5KY7MM2peH39kIHSzy1R0si53y1aQuqMK+0OyLKg+LPiOH8Lv/m92P3QnJB0u/7/qkHGhcwZgF46T7GQwDK8uxzof55Vf0DP99WfYLtHER7xPzcjp98+/IprV3Ple4MbQycWQ2BW0BIBwbg95V2AjXTWpWRLzcOwEX51mogGseIOerXvTjveNs5xtDned6KzC7AdAAAIABJREFUuXPnjjrN8agFYMeOHU25XO4xAGWbBrVQCuCyR2f+77OD7utsZyHaw1G/+4ffeUf10s2rS3cP0HV3lwATjLtemhqB39NT0lX9pKN6xPz7rGFO6UtBktXZf+52PvjqII9BFZHNInJEY2Pjtld+b78jiKqabDZ7KwJ88gd2/9/9rSO6D086WGs7C9EenpgZZ132rcwT8181XLKd5HLwu0t7ws2XZjKlP/kvqx4yX5qV4smfgkQ19lyP8/6DgnzyBwBVneP7/l2qut/tyf0KwNatWz8kIqG4tB4TTX7t0J0OgBIPOSbKny8y5byLv5r7y4LDSlYCNJ2G39dXqs3nx/Pgd3eX9uS/vGbY/OusLCSYtyKpYqV3Of9gFK7N0f6FWLFt27ZrX/nFlxWAbdu2LRaRj5Yv0+S11+UWv6Eh/SfbOYj25Yupv/CiL/tPtBxSsnKqg0OlH3Q39t7hd+8CvEnNkHpAclB12tzc4MNgasl2QjQBI3LInzJoKfkcIMWkqh/r6up6WeaXFQDf9/8dQOgWJf/E0t7XONAttnMQ7csXU3ve2/4j9dzsxSWbEcfv6y3PPPuv3O+uPmimhMv6tiSy5gsNQzBlmUWNKG8K09UnFxxtO8cEVAH4132/sLcAbNmy5XAAby53omJIGK0+v2WYYwEocHwx0858+7d3bpvSWPA83XlR7B4P4Jfuk/h+uxwehg6V8MpDYzznfH12NxzhPX8KnCE5bq0iHroPygCgqm/ZsmXLkXv+vLcAGGNuRNBHMxzAOxYNHm0E+41yJLIt47jNp7z7ts29NVNLc7M8lyv5QLw9NJuFv6u3dDuoddT5RtMLiAln9aQAMjuGZOVrbKeYDBG5Yc9/GwB48cUX56jq6fYiTV5MNPnGmSNjrhVAZNNgrHr+mVfcsn4kVpqZ/HQkDR0aLMm2/74TQHt2la5oJB2Yb8x5HtWyqDQ7IJqcETnkaYUb4Ok483LWpk2b5gIvFYBUKvV5AKWbwaxMLmnaeZDtDERj2Vo/a/Glb/vqWpXSXGjz+/pLOh7A7+sr3fYFMF+YvV4azILS7IBo0rQ7vSIKa0+YoaGhTwMvFYCRkZGzM2VYuavUZni7Gupdf4PtHERj+WvTsiU3n3jNuIt0TMjeT+gl2HQ6DR0s3RUG5+pZ66U9xk/+FFie1m7oGUgGZU2cCUun00in028FALN69epDcrlc1WAJ39zlkEqlkMvl8Nr60k5HSjRZ3zzq/AUPLHtTTym2rdks/P4izw/g+/B7dhV3m/uQY+p34czq+SXbAVERDOQ6JJfLYaTUK12W2NDQEHK5XPXTTz+9zBhj3g7sbgVhvQqgqthTYI6q6+M84RR05pqzPulsbFhQkuvpOjgETRfvvez39gGeV7Ttvcy8RNZ8dJqDCNyCpGjrHVk0AwAGBgagAZiFcyIymQzS6d2P7zqO83aTy+WO2fPN/v7+UP7FhoeHkcvtfsqqNd4fqJULiUbji0w55+3/uWU4UVX8N5wq/F3FuRWg6Qx0uEQTGtY46ny5aRuM1JdmB0TFM5huqgOAXC6H4VK9J0pIVdG3z+yhnue9wfi+37LnC9lsNnR/Mc/zsO/tixqTE0dQksurRMU0EK+e/+7zby7N/BW5HHRwYHLb2FMkSsR8evY6VGNuyXZAVCSqZmfWi+0dvTswMAC/jHNvFMO+H5QBQFXnG9/3XzbN5sDAwMteFHS9vb37/UNMjXmlO2oRFdHDLa9q/+ERZ24vxbb9/n5gEu9lv39gUj9/IOYt07pkWWxJSTZOVGQ+6l42+YWqore3hPNhFFk2m0V//8vHx3meN834vh/b94uqil27doXiVsDAwMCo4xbqnVyJblgSFd+HTr42uWn6nOKfaRUTn7QnlyvdqP+5iZxcNaWmNBsnKr6cVu33cT+dTmNgYJJX2cpgzzl9lK/HjKrutyJgLpdDT0+wr6KnUimM9eRCjRv88kK0h4rUn3/p/1vvSfHHwWk6DU0VPmrZ7+0rzYQ/DuDc3LgRAo7VodDwdfS5fwYHBwP/VMCuXbvgjTKIV1XNfif/PTKZTGCvBIyMjLxsMMMrxcALABQu22tmLPmXk99bkjkstMDHAjWdhpbooOZc07AB00xrSTZOVCI+3DG/19vbu3dkfZCoKnp6eg6YzYjImGf4kZER9Pb2BqoEDA8Pj5tp2DOhXdOAKtctR5zT8sycZUU/kmg2V9DiPdpb5HkEXiLLqtN4c03L+K8kChZHRsY8p+w50aZSqXJGOqA9YxQOdPIXETUADjiUcWRkBD09PdZHPO55hKGvr2/cQjLkOywAFEbuFed9YbMnY16YmzC/fyCvS/o6PFya6X4NYD45cwtwgI9SRAElOjLum7K3t3fM29Ll5Hkeuru787k14RtjzLifODKZDHbs2GHtMofnedi1a1fejygeVDdyHwQ/BlCajzJEJdJdPXXR/1tx5QtF37Dn7b6vfyC+D7+vNDNpmssbNqLeLCzJxolKpxfAj1P+/PvzefHAwAB6enpGvedeDul0Gjt37kQ2jxLvOM6IPPXUUxszmUze03BWVVWhvr4eZuzhA0WVSqXy+tS/r7q6ulltbW07cLc6C3y8WhSnCnAWAC4WRMGnOvTg189NNHdvKfqnZVNfD6kfZfyd58Hv7oGWYjbQOfGs8+3mLATVxd84UZEJ/gaVH0HxM8zJ/FnkHq+rq2vWli1b8l5uXkRQX1+P6ury/Mr7vo/+/v6CbkMkEokNsmrVqt+kUqnjCtmZiKC2thbV1dUlKwIjIyMYHBzMq8nsy3Gc3Kte9arYaN9bdLu2weBsCC6C4uCiBCUqgSU7Nq75n29c1F6KbUssBqmuBmIu4Cs089JsfyW6zef819y1aHH5zD8F2ZOA3A5ffigttz072gsef/zxnO/7BT2q47ou6uvrkUiUaBlwVQwNDWFwcLDgsXrJZPLXruM4PwNQUAFQVQwMDGBwcBDV1dWoqqpCLDbqObcgqopUKrVnsYIJbcN13U1jfW/9RbIOwOcBfH7B7XqocXApFBcBaJhYYqLSWNuwoP1/Dj2l97THfzZ1/FcXRrNZ6AGeoikmOWnKLp78KaC2QXAHfPNdmXvbE+O9OBaLbU6n0/MK2cGeR+pjsdjec6UUYTnwbDaLVCqF4eHhCQ/Sj8Vi98mqVatmpFKpnZMNFIvFkEgkEI/HEYvF8royoKrI5XJ7FygoxhiDqqqq7y5duvSyfF+//G6ND/s4UxTvBfD6SQcgKpJkLr31zzef0pTIBu8Ro7zEDZwftmxDXBptRyHax2MQfBNe9nvSck/e18xXrVp1WyqVumgyOxaRvefJeDwO13XzKgSqikwms/dcWeiV8dFyOI4zXQDgb3/7285sNlvUVfRc14XjODDGwBgDEYGqQlXh+z5yuRw8zyv6I4aJROI1y5cvf2QiP7vgLj1aFDcIcAYAPklA1r37z3dt+KdffCWUg+ecq2eux1tqF9nOQYTdT7v9FL7/OWm56/8msoHVq1e/fnh4+A/FDPXSiRiu6+49T+45V/q+D9/34Xle0afnj8ViOw4++OBZAgCrVq36eiqVeldR92BBLBbbdfDBB0+f7HYW3aYHw8GHAJwHoDyjHYlGIar9f/rSmbXTB7vD9Xs4I+Y7d8wZ4ox/ZJkH4C4Y/aw03fn0ZDf25JNP9uZyuSlFyGVVTU3NV9vb299jACAWi33sQBMChUU8Hv/vYmxn/cXyt/UXyIXGwcEC3FOMbRJNhIrUf+y0656znaNQ5gMNz/HkT5Y9ADVHyJw7Li7GyR8AYrHYD4uxHZuMMQrgE8BLn25bW1u3x+PxR62mmiTHcfx0On1dMbf57LnyzHMXyLmiOB7Ak8XcNlG+ftl6zMJnmxaX4Pm80pDWqqwcGeelf7LlcfjmOJlzx4n5DO4rxNDQ0PuNMaGeaz4Wi/1fe3v7TmCfy9uJROLyYoxOtCUWi/30kEMOKckywM9dKL+ZNxtHQPF+AKWZKYVobO51p33kedsh8mWum7kRQPFXNiI6EEEfBO9Fc/ZIabntwVLs4sgjj+xLJBI/L8W2y0FEEI/Hr9jz570FoLW19al4PP4nO7EmxxiTU9Urxn/lxD14nOTWXyj/ngWWKvCTUu6L6JWeamxvXTWnIziTjY/BLKtOYYHDxX6ozPRHcLMd0nzHl0XuKekndGPMZY7jFH/57jJIJBK/b2tre2bPn185sOg0Y0zo/mLJZPKzy5cvL8v6xS9eIFs2XCBvUcG5CnSXY59EAOSjp14f+KsA8v7pL4BP0FC57P7U/y6Zc+fZMuuernLssr29fWc8Hv9iOfZVTI7j5OLx+Fv3/drLCsDy5ct7EonEx8sba3ISicTzHR0dHyv3fjecL/c4Hg6F4qFy75sq098al7Svbu4I7OLjsrRqBPM56Q+VieJ38Nzl0nzHN8u966VLl34oFouNOelcEFVXV3+0tbV1+75f2+/RoqVLl34mmUw+XL5YE+c4TjYejx9ja//PXiyb1rt4E3aPqLS7XCJVAvnoqdcVf6GgIpH3zeCnfyoHBfBldNWeKC23brYVoqqq6nWu65Zg6cziq6qq+mNbW9vnX/n1UZ8trqqqOi4Wi5XlkvpEGWO0urr6ora2Nrst7Fzx1l8gN4ngNHD1QSqxJ2e3t65tag/c1IDSXp2WhW6b7RwUebsgcrLMueO9cuQ3rZ58W1tbX0wmk5cG/RH6WCzWnUwmTxjte6MWgIULF47E4/H2WCw2UNpoE1dVVfWRtra2wDyj/9z58jP4eDWA1bazUKSZT534j4EbC2CumsZP/1Rq6yDe66X59l/aDrLHkiVL7qytrf2A7RxjicViQzU1NcsXLlw46q3DMWcXe2mgw1Gu6w6XLl7hRAQ1NTWfaW9v/6ztLK+0/iJZl/PxOo4LoFJ6eN6hC3ZMmRWYZ5GlMe5heWyB7RwUYYLfIhM/Spq/v8p2lFdqa2v7t6qqqs8F7TF613WH4/H4kYsWLRpzGeMDTi/a3t6+2nXd1ng8HojbASKiiUTimvb29o/YzjKWFy6SXWYqVgL4ge0sFFnxrx57xUbbIfaQS6dthGLyy4ESje7HSMdPlYXf6bUdZCxLly79UE1NzXtfmmXPulgs1u26bmt7e/sBr0jnVVk2bNiQTKVSPx8ZGTm2OPEK57rucCKROKO9vf3XtjIU5G51Fnn4JoDLbUeh6DHq73r8X06cmsyO2P3YUWXU+dH8Phgt+rLFRFD5Bua0XS1yUygGWa9du/bEVCr1E8/zqmxlSCQST0ybNu11zc3N4169z2uBkYULF44sW7ZsRU1NzSfKPQ2iiCCZTD5aVVXVFJqTP7B7cOD5uBKCr9mOQtHji5l251Fv3WI7h5w1bQtP/lQa+p+Yc/tVYTn5A8CSJUt+5ft+czKZ/Gu5bwk4jpOrrq6+cfny5Yfmc/IHJjBoZ/369Y2pVOredDr96sIjFiYWi/XFYrErOzo6wns5XVUW3oWvC/BO21EoWmrTwy8+9sWVLVLkJbXzJoDz43mbUWXm2AlA0SVfQ/Pt14ggEJfUJ2LNmjXnpdPp/8zlciVfFCuZTD4cj8fPfOVz/uMpeInRRYsWbVu+fPlRNTU1RyUSiSdK0XJc1+2trq6+/uCDD54a6pM/AIjohjW4CoKirFRItMdgorrlz4tfPWRr/+aoukGe/KnoBPegue09YT75A0B7e/v3DznkkPqampoPx2Kxoj8i/tLV8b9WVVUduWzZstcWevIHivDYzrPPPtuSzWY/lcvlzsjlclN1gp9GjDG5WCz2aDwe/0xbW9u9k80VNHPv1qq4h18BeL3tLBQdR7/wxJpbb7263ca+nS/NXYulnPmPikl/j0xipSz8TmBnvJyo1atXn+n7/g3ZbPZIz/PciWxDROA4Tm88Hv+R67ofb21tfXEymYr68X3NmjVzfN9/p6qu9H1/vud5M3zfj6nq3v2ICETEcxyn33GcrcaYx1zXvaW1tfW3xcwSRB3f1RmZGP4IgZUDNkVS6s83n5qYkuor+GrepNS5vvPfc9MArA12osh5Fib7Omm6Z4ftIKW2Zs2a4z3PuwzA4blcrtn3/TpVdfb9AC0i6jhO1hjTbYx5XkR+qapfX7Zs2dZi5SjbKIX169c3Lly4sFtEQrfYUDHNv1sXOh7+BKDRdhaKhg/+/lsvvvN3t7SUc5/m0pkvykW1Zd0nRdoO+OZ10nLbs7aD2KSq7oYNG2Yc6Nn9YgrWzAUVYuHtepQY/A5A0nYWCr+pI/0bH/niKQvKuU/nh/M2otaUdZ8UWSkI3iDNdzxmO0ilKe9lQwIAbLhIHoEisNNHUrj0JusXPNVyUNnWB5CDakZ48qeiEbyPJ387WAAsWX+hfA2Ku2znoGi45TXnlW1VNNNZZ20FNooY0R/YWM6XdmMBsMhP4yoAG2znoPD7WfuxdZ6U4e1sDPCaRH3pd0QV4AV4uXfZDlHJWAAs2vh26VUf5wPI2M5C4ZYTp+GR1qP6S70fObqmD0YaSr0firwcVM+XlnsCsc5MpWIBsGzDRfIIBB+3nYPC77tHdXaVeh9yRl3J90GVQD4ic+/8k+0UlY4FIADWG3wBwF9s56Bwe3DBUQ05p4SL8rkGcliCj6/SZD2K5szNtkMQC0AwnCsegHcBCMwa7xQ+vphpD7W/vmS3AcwxNb0QLvxDk+JBzLtE7uGxLgBYAAJi/QXyqHLlQJqkO444u2QTiMjp9QXPNU70MqpfkebbeLUzIFgAAsTJ4aMA+IgVTdgf5x023S/F0wAGwPIYB//RxAm2Ip27yXYM+jsWgAB59mLpV8H7beeg8PLEzHhiwaFFXyFQDq0dhMG0Ym+XKoleLYvvKfqqeDRxLAABs+F8uUeBB23noPD60SGnFH2kvqys5eh/moxfSfOdP7Ydgl6OBSCIfFwPhHstbLLn/vZjJ7TU6IHIaxOJYm+TKojv32g7Au2PBSCANlwkjwC4z3YOCqf+eM38F2bMLd6qm3MTWVQJV/6jCdIfSctd/2c7Be2PBSCgVPBRAL7tHBROPztoZdFG7JsT6suyNClFkg/H/ZjtEDQ6FoCA2nC+PAHF3bZzUDjd33Fc0QYCyhuqUsXaFlUYxe0y+3tP2Y5Bo2MBCDKDj4OTA9EErJ65cLZnijAUIGaAuWbO5DdEFSgH3/uE7RA0NhaAAFt/vqwF8CPbOSh8VKTu8YWvGpzsdsxh1QMQVBcjE1UauUfmff852ylobCwAQaf4ku0IFE4/71gx+XEAx9TsKEIUqkS+x2NXwLEABNz6C+UPAB6xnYPC54HWYyZ/++goPv1HEyH/y5H/wccCEAaCL9uOQOGzuW7W/OF4cuIbqDGQGYaP/1HhVP/ddgQaHwtACEzrw93gGgFUuPijC4+c8Ah+c1jNEBQlXF+YIuoFzNnCsUshwAIQAo+9S7ICfN12Dgqf3y96Tc+Ef/jIZG8Ro1Dl+JrIg8WbiIpKhgUgJBwHt4CPBFKB/rDgyOxEf1YOr+JBnArlw3dvsx2C8sMCEBJrz5XNAH5nOweFy/ppLbM84xT+g44AjTKr+Iko2uSX0nIrb1eGBAtAiIjiVtsZKFzUSPWa2UsKvgogHVUZiFSVIhNFmOB7tiNQ/lgAQmQwhx8AmPTkLlRZ/th61K5Cf0aOrJr42AGqVIMw5ie2Q1D+WABCZNvbZEg4MyAV6KHFRxdcGuXIqqKtJUAV4x6Z/T3+3oQIC0DI+AIOsKGCPDlrSeFT+S50aksQhaJM5XbbEagwLAAhM70Pv4WAj2dR3lKxZGNvzVTN+wemuj7i0ljCSBQ9veiqech2CCoMC0DIPPYuyYril7ZzUKjIM3OW5X0bwCyv5jgTKtR9cuQ3J/zIKdnBAhBCvuJe2xkoXP48/1X9eb/4oET+ryUCANWf2o5AhWMBCKGsi/sBcJIWytuf575qJO8XL49nShiFokaQRTbBq5IhxAIQQpvOlR4F/mA7B4XHqobFeQ8ElAUxDgCk/Cl+Kwu/w3FJIcQCEF732Q5A4TEQr24cTORxXq8zQBINpU9EkSE8FoUVC0BIGR+/tZ2BQsWsa2ob99K+aa9KA5Ay5KGoMM5vbEegiWEBCKnnYnicjwNSIZ6a3T4w7ovaOACQCtKNxsXP2A5BE8MCEFbnigfg97ZjUHg82bJs3JO7tCf5CCDlT/GgyE2+7Rg0MSwAIaY+Vwek/D0xq3385aQXuzyYU/5EeQwKMRaAEDOKB21noPDYNKWpftwXNZhpZYhCUeGbB21HoIljAQix52J4HECf7RwUDjnjzOqrnjL2lMDTYz4MppcxEoVbD+a2PW07BE0cC0CY7R4H8JjtGBQe6xoXp8f6nlmUzH+yICLgUd7/DzcWgJBTZQGg/K1rXDz2IL9FMS7lSvlTPGo7Ak0OC0DIGWEBoPytaVg8PNb3ZGE8Vc4sFHKGx56wYwEIORG2cMrfmoaFY68hMT/G9SWoAC6PPSHHAhByz56H9QB6bOegcNg4ZY475jdnS7yMUSjcdkrzrS/YDkGTwwIQdiIK4HHbMSgcdlVPHX2UvwCokRnlTUMh9hfbAWjyWAAiQAV8FIfy4ovUdtfM2P9RwIaYQqTKQiQKIx5zIoEFIALEx2rbGSg8Ns6av9+jgKYlzkcAKX++rrEdgSaPBSACBCwAlL+NM+ft/yTAvDgfAaT8OTzmRAELQARkhG9Gyt/66fP2nwtgrstFgCh/hsecKGABiIAXL5AtXBqY8rVhesv+l/vnuBkLUSiceqXxzm22Q9DksQBEhYL35Cgvz09rlv2+OMvd/2tEo+On/4hgAYgIBTbazkDhsKN6enK/L06XagtRKJzW2w5AxcECEBEieN52BgqH/kTdfkv+SpLLAFO+hBMARQQLQEQo8KLtDBQOvkjtQLLu71+odwEDXgGg/KiyAEQEC0BUKPimpLx1TWn09v5hlss1ACh/yquNUcECEBHqswBQ/nbUz9o7GZBpiO83MRDRmFxlAYgIFoCI8MFWTvnbWt/w95N+g8NZACl/ccPbjRHBAhARL1wkuwDwkxzlZeuUxtTePzSyAFDehmXG7f22Q1BxsABEy07bASgctkxt/PtJf5bL4kj52m47ABUPC0CUCHbYjkDhsKl29t6Bf9LocBAg5Ud5jIkSFoAoUbZzys+2upl/n/lvuuFxgPJjhMeYCOEbP0rYzilPvVX18b1/qDEJi1EoVHzeZowQFoBo4ZuT8jLkVlXt/UOC0wBT3niMiRAWgGjpsx2AwiHruH+fCtBF3QFeSvR3vnDV0QhhAYgQMeCa7pQXFakacZNArQGA+HivJwIAGAzYjkDFwwIQIap8c1L++mum+jI15o3/SqKXqPAYEyEsAFEiLACUv57qKR7qHRYAyp8qjzERwgIQIbwCQIXorZ2WlSlu1nYOChHDAhAlru0AVDxGMagy/uuIAKC7elpGpxjwV4YKwHFGEcICECEKZGxnoPAYSNZmpM6o7RwUIp7wGBMhLAARooqM8OMc5ak/WZdGDQsAFUD4ISNKWAAiRIEMz/+Ur4FkbQa1/I2hAjjKMSMRwgIQIa4g69sOQaHRF6/xUMNxwFSAHG8BRAkLQIT4igxHdFG+BpO1PgsAFcT1eQUgQvjujxDjgBcAKG99iWpFFTgGgKhCsQBESM5HzHYGCo/heI1KtWM7BoVJzuVV4whhAYgQx/CWDuWvP14tqDa8aUT5czweYyKEBSBCPI8FgPI3EqsyiPMYQAUwvAIQJfzHjBDDKwBUgBE34SApLACUvxyvAEQJ3/wRYpRjACh/qVjChcvfGSqAI/x9iRC2uQjxBC5v6FK+so6bgCscBUj583yeMyKE/5gRYgxc5YOAlKescZNwwAJA+TMOzxkRwn/MCPEVMV4BoHz5YpJw4HImAMqb7/EWQISwAESIARwey6kAVaoCYQOgfBnDc0aEcBBghPgcBEgF8pWHACoArwBECt/9EWIEU21noHDxuXgEFcI4U2xHoOJhAYgSH3xzUkFyvAJAhVCfHzIihO/+KOEVACoQbwFQQUR4jIkQvvujRHgFgAqTUz4FSAVQ5TEmQlgAIkSVVwCoMLwCQAVRXgGIEr77o4XtnArCKwBUEF5ljBQWgCjhFQAqEJ8CoALxGBMhLABRwkGAVCCPtwCoEBwEGCl890dLve0AFC455cRuVABVFoAI4bs/Qrb0+YuUs7pSAZ7b8TzmTX3QdgwKDbPYdgIqHhaAiKi7Q2cO9HCpTirMcM4DvB7bMSg8XF3VMUOWru62HYQmj7cAIsIM4TDbGSh8hFeMqFBJHGw7AhUHC0BEqIOltjNQ+KjwKQAqUM5fZjsCFQcLQFR4/hLbESh8HHi2I1Do+G22E1BxsABEhKcy33YGCp+YydqOQKGTW2A7ARUHC0BEKNBkOwOFjys52xEobDTHY01EsABEhCpm2s5A4eOCBYAKpNlZtiNQcbAARISnOt12BgqfhEnbjkChk+GxJiJYACLC81BjOwOFjysZ2xEobPxUre0IVBwsABFQe6vO8pT/llS4uHAQIBXIH3F0VccM2zFo8njSiAAnizfYzkDhxCsANCEJvM52BJo8FoAoUP8I2xEonHgFgCYk573adgSaPBaACPBUODMXTYjDxwBpIkz2INsRaPJYACLAU7TbzkDhlDAjtiNQGHmZDtsRaPJYACLA83WO7QwUTpwJkCZEUzzmRAALQNipSs4DH8uhCYlzECBNhD9YpwquJBVyLAAhN+O/8Gqfb0SaoBgHAdJEaFawuuNw2zFoclzbAahwqiqbN2+eIyI1lz6SOeX321zeyKUJcZ1aANW2Y1AIZZKHnLZ5868HVXVozpw5m0VEbWeiwvCTYwj09PRMSafTJwE4TkSOVtUl4FGbiIJjWETWqurDAH6bSCR+MX369D7boejAWAACbMuWLW8UkasBnAkgaTsPEVGeUgB+oqpfa27L+15XAAAGS0lEQVRu/r3tMDQ6FoAA2rZt2+t83/88gGNsZyEimqSHROT62bNnP2w7CL0cC0CAdHd316fT6ZtF5Arw34aIosMXkW85jvPBhoaGAdthaDeeZAJiy5Yth4vI9wG02s5CRFQia40x5zY2Nj5hOwixAARCV1fX8ar6IwB1trMQEZXYEIDOpqamn9kOUuk4D4BlW7ZsOUtVfwae/ImoMtQA+HFXV9eZtoNUOl4BsGjr1q0rAPwMHOFPRJVnRFVPam5ufsh2kErFAmDJpk2b5jqO81cAM21nISKyZEculzuspaVls+0glYi3ACxQVeM4zp3gyZ+IKluD67p3qCrPRRbw/3QLurq63g0+409EBABv3Lp16xW2Q1Qi3gIosxdffHG667rPAphmOwsRUUD0jIyMLF64cGGv7SCVhFcAysx13feCJ38ion1NTyaT77EdotLwCkAZrVu3rt73/W319fUc9U9EtI++vr4Rx3Ea29ra+m1nqRS8AlBG2Wz2k0NDQ8lMJmM7ChFRYGSzWQwPDyc9z7vRdpZKwgJQRqraCQADA5wKm4hoj/7+3R/6Pc+7wHKUisICUCbr1q1LZLPZJgDIZDIYHBy0HYmIyLrBwUHsuSqayWSa161bl7AcqWKwAJSJ7/vn+b6/d8zFvr/0RESV6JUfhlRVPM/rtBiporAAlImqHvuKP6O3txe5XM5WJCIia3K5HHp7e6Gqr/zWsaO9noqPBaBMfN9f/sqveZ6H7u5ulgAiqii5XA7d3d3wPG+/7/m+f5CFSBWJBaBMVHXGaF/3fR89PT0sAURUEfac/H3fH+sl08uZp5KxAJRP1Vjf8DwPO3fuxNDQUDnzEBGVVSqVws6dOw908ofv+9VljFTRXNsBKoXv+86Bvq+q6O/vRzabRV1dHRzngC8nIgoNz/PQ39+PkZGRfF7Og1+ZsACUieM4qWw2O+7rUqkURkZGUFNTg9raWohwskYiCidVxeDgIIaGhkYb7DcqEUmVOBa9hAWgfPKe/WffN00ymUR1dTXi8XgpsxERFU06ncbw8DDS6XTeJ/59cKa0MmEBKBMReRbAIYX8jKoilUohlUrBGIN4PI5YLIZYLAZjzN7/ERHZ4Pv+3v9ls1lks1lkMpkD3uMfjzFmbREj0gGwAJSJMeZRAGdP9Od938fIyEi+99CIiEJJRB61naFS8ONjmXie9x3ezyciGpuIQERut52jUrAAlMmyZcu2uq7LBQCIiMbgOM5Ae3v7Zts5KgULQBm5rvs72xmIiILKdd3f2M5QSVgAyqiqqupG3gYgItqfiMAY8zHbOSoJC0AZLViw4K+xWOwF2zmIiIImHo9v6OjoeNJ2jkrCAlBm8Xj8/bYzEBEFTTwef6/tDJWG16MteOqpp1ZlMpkO2zmIiIIgkUg8vXz5cq4CWGa8AmCBMeYMY8zEZ8ogIooIx3F8x3FOt52jErEAWLBs2bJ1iUTiOg4IJKJKl0wmP9rR0bHBdo5KxDOQRatWrfpNKpU6znYOIiIbqqqqfrV06dKVtnNUKhYAy55++unH0+n/394do0gNxQEczsuESSbFFhZWFtMMM5OAK2phowewWC9hJ3gG8RpeQrHwABZWsrAwTpPOVgStxjDJs1CwEDvZN7vzfSf4QQj5P15478dp6g6Ay1SW5ae2bdvUHcfMFkBiTdPcrarqY+oOgMtSVdVF0zQWPokZABILIYxN09yv6/qdfwKA6yyEkM1ms7dN05yGEPape46dAeBArFarx1VVPZ9MJl4K4NrJ83xfluWz9Xp9lrqFXyw5D0zXdTf7vn+z2+0epG4B+B/KsvxQFMXZcrn8krqFPwwAB2q73d6LMb7q+/7OOI6eE3Cl5Hkep9PpeV3XT+fz+XnqHv7mw3LgNpvNjTzPXwzD8GS/398ax9G2DXCQfh/q87koitfDMLxs2/Zr6ib+zQBwhcQY867rHg7D8CjLstsxxpMY40nqLuA4hRC+Z1n2LYRwMZlM3i8WC1eeAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJDKT+3mjGdue+fZAAAAAElFTkSuQmCC"/>' +
'<span>Meetinator™</span>' +
'<div class="logoTooltip">' +
'<span>Created by <a href="https://wix.slack.com/team/UD5USBS5R">Shmulik Flint</a> ' +
'<a href="https://gist.github.com/splintor/f10c20926335324c6ff8e007439ed64c" rel="noreferrer"><img width="14px" src="https://github.githubassets.com/favicon.ico"/></a>' +
'<div class="logoAttribution"><a href="https://www.flaticon.com/free-icons/joker">Joker logo source</a></div>' +
'</span>' +
'</div>' +
'</div><div class="buttons">' +
'<button type="submit"></button>' +
'<button type="reset" style="margin-left: 10px">Reset</button>' +
'</div>'
getContainer().appendChild(ui)
ui.addEventListener('click', onClick)
GM_addStyle('#Meetinator { position: absolute; top: 0; margin-top: 90px; margin-left: 400px; z-index: 1000; }')
GM_addStyle('.logo { display: flex; align-items: center; justify-content: center; margin-bottom: 5px; cursor: default; }')
GM_addStyle('.logo > span { margin-inline-start: 8px; font-size: 22px; text-shadow: 2px 2px 5px lightseagreen; }')
GM_addStyle('.logo img { margin-block-start: -4px; }')
GM_addStyle('.buttons { display: flex; }')
GM_addStyle('.logoTooltip { display: none; }')
GM_addStyle('.logo:hover .logoTooltip { display: block; position: absolute; top: 40px; left: 110px; background: lightyellow; border: 1px solid gray; padding: 7px; min-width: 181px; }')
GM_addStyle('.logoAttribution { font-size: 11px; margin-block-start: 4px; }')
GM_addStyle('.memberStatus { display: none; }')
GM_addStyle(openMemberSelector + ' ~ #Meetinator { display: none !important; }')
GM_addStyle(memberHeadingSelector + ':not(.visitedMember) > .js-expander + span { font-weight: bold; }')
GM_addStyle(openMemberSelector + ' .visitedMember > .js-expander + span { background-color: gold; }')
GM_addStyle(openMemberSelector + ' .visitedMember .memberStatus { display: inline; }')
GM_addStyle('.unopenLink { display: none; }')
GM_addStyle('.unopenLink a { margin-inline-start: 7px; font-size: 12px; color: darkviolet; opacity: .4; }')
GM_addStyle(closeMemberSelector + ':hover .visitedMember .unopenLink { display: inline; }')
GM_addStyle('.ghx-swimlane .ghx-heading .memberStatus.editMode { display: none; }')
GM_addStyle('.ghx-swimlane .ghx-heading .memberStatus:not(.editMode) ~ .timerSettings { display: none; }')
GM_addStyle('#Meetinator button { border-radius: 6px; padding: 10px 18px; outline: 0; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0 2px 4px; }')
GM_addStyle('#Meetinator button :hover { box-shadow: rgba(253, 76, 0, 0.5) 0 3px 8px; }');
GM_addStyle('progress { vertical-align: middle; border: none; -webkit-appearance: none; -moz-appearance: none; appearance: none; }')
GM_addStyle('progress[data-expired="true"]::-webkit-progress-value { background-color: red; }')
GM_addStyle('progress[data-expired="true"]::-moz-progress-bar { background-color: red; }')
GM_addStyle('.timeCounter { min-width: 40px; display: inline-block; font-weight: bold; }')
GM_addStyle('.timeTracker { cursor: pointer; }')
GM_addStyle('.timerSettings { background-color: cornsilk; padding: 5px; }')
GM_addStyle('.timerSettings input { width: 70px; text-align: end; }')
GM_addStyle('.timerSettings button { margin-inline: 5px; }')
GM_addStyle('.timerSettings a { color: black; }')
const { members, relevantMembers } = getMembers()
members.forEach(markMemberAsVisited)
relevantMembers.forEach(markMemberAsNotVisited)
updateButtons()
addMembersStatus()
}
function updateButtons() {
const ui = document.querySelector('#Meetinator')
const submitButton = ui.querySelector('button[type="submit"]')
const resetButton = submitButton.nextSibling
const { members, relevantMembers } = getMembers()
if (relevantMembers.length === members.length) {
submitButton.innerText = 'Open a random member'
resetButton.style.display = 'none'
} else {
submitButton.innerText = 'Open next random member (' + relevantMembers.length + ' left)'
resetButton.style.display = 'block'
}
submitButton.disabled = relevantMembers.length === 0
}
function addMembersStatus() {
getMemberHeadings().forEach(member => {
const memberName = getMemberName(member)
member.insertAdjacentHTML('beforeend',
'<span>' +
'<span class="memberStatus">' +
'<span class="timeTracker">' +
'<span>Time left: <span class="timeCounter" id="' + memberName + 'Timer"></span></span>' +
'<progress id="' + memberName+ 'Progress" max="' + timerTime + '" value="0"></progress>' +
'</span>' +
'</span>' +
'<span class="unopenLink">' +
'<a href="#">Mark as not opened</a>' +
'</span>' +
'<span class="timerSettings"><form>' +
'Timer duration in seconds: <input type="number">' +
'<button type="submit">Save</button>' +
'<a href="#">X</a>' +
'</form></span>' +
'</span>')
member.querySelector('.unopenLink a').addEventListener('click', e => {
e.preventDefault()
e.stopPropagation()
updateClickedMembers({ [getMemberName(member)]: undefined })
markMemberAsNotVisited(member)
updateButtons()
setConfettiDisplayed(false)
})
const memberStatus = member.querySelector('.memberStatus')
const timeInput = member.querySelector('input')
const button = member.querySelector('.timerSettings button')
member.querySelector('.timeTracker').addEventListener('click', e => {
e.preventDefault()
memberStatus.classList.add('editMode')
timeInput.value = timerTime
})
timeInput.addEventListener('input', e => {
button.disabled = !timeInput.value
})
button.addEventListener('click', e => {
e.preventDefault()
timerTime = Number(timeInput.value)
GM_setValue('timer_time', timeInput.value)
getMembersProgress().forEach(progress => { progress.max = timerTime })
memberStatus.classList.remove('editMode')
})
member.querySelector('.timerSettings a').addEventListener('click', e => {
e.preventDefault()
memberStatus.classList.remove('editMode')
})
})
}
function getTimerString(seconds) {
if (seconds <= 0) {
return '0:00'
}
const m = Math.floor(seconds / 60)
const s = seconds % 60
return m + ':' + String(s).padStart(2, '0')
}
function updateMembersStatus() {
const { members } = getMembers()
members.forEach(member => {
const memberName = getMemberName(member)
const memberStartTime = clickedMembers[memberName]
if (!memberStartTime) {
return
}
const elapsedSeconds = Math.floor((new Date() - new Date(memberStartTime)) / 1000)
const progress = document.getElementById(memberName + 'Progress')
progress.value = elapsedSeconds
progress.setAttribute('data-expired', elapsedSeconds > timerTime)
document.getElementById(memberName + 'Timer').innerText = getTimerString(timerTime - elapsedSeconds)
})
}
function showConfetti() {
const confettiParticleXount = 400
const fireConfetti = (particleRatio, opts) => confetti({
origin: { y: 0.7 },
particleCount: Math.floor(confettiParticleXount * particleRatio),
...opts
})
fireConfetti(0.25, {
spread: 26,
startVelocity: 55,
})
fireConfetti(0.2, {
spread: 60,
})
fireConfetti(0.35, {
spread: 100,
decay: 0.91,
scalar: 0.8
})
fireConfetti(0.1, {
spread: 120,
startVelocity: 25,
decay: 0.92,
scalar: 1.2
})
fireConfetti(0.1, {
spread: 120,
startVelocity: 45,
})
}
function showConfettiOnCompletion() {
if (wasConfettiDisplayed() || getOpenMember() || getMembers().relevantMembers.length > 0) {
return
}
setConfettiDisplayed(true)
showConfetti()
}
function renderMeetinator() {
if (getContainer()) {
if (!getMeetinator()) {
buildUI()
}
updateMembersStatus()
showConfettiOnCompletion()
}
}
setInterval(renderMeetinator, 500)
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment