import { Chart } from 'react-charts'
import React , { useState , useEffect , useRef } from 'react' ;
import logo from './logo.svg' ;
import './App.css' ;
import {
BrowserRouter as Router ,
Switch ,
Route ,
Redirect ,
useRouteMatch ,
useParams ,
useHistory ,
useLocation
} from "react-router-dom" ;
import { HashLink as Link } from 'react-router-hash-link' ;
import {
Modal ,
Button ,
Form ,
Badge ,
Card ,
Spinner ,
Carousel
} from "react-bootstrap" ;
import { Line } from 'react-chartjs-2' ;
const REMOTE _ADDR = "http://45.33.13.215:4502" ;
const axios = require ( 'axios' ) ;
const moment = require ( 'moment' ) ;
var IMAGE _EXCLAMATION = ( p ) => {
return (
< svg { ... p } width = "1em" height = "1em" viewBox = "0 0 16 16" className = "bi bi-exclamation-diamond-fill" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< path fillRule = "evenodd" d = "M9.05.435c-.58-.58-1.52-.58-2.1 0L.436 6.95c-.58.58-.58 1.519 0 2.098l6.516 6.516c.58.58 1.519.58 2.098 0l6.516-6.516c.58-.58.58-1.519 0-2.098L9.05.435zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" / >
< / s v g >
)
}
var IMAGE _CAMERA = ( p ) => {
return (
< svg { ... p } width = "1em" height = "1em" viewBox = "0 0 16 16" className = "bi bi-camera-fill link cursor" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< path d = "M10.5 8.5a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z" / >
< path fillRule = "evenodd" d = "M2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4H2zm.5 2a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1zm9 2.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z" / >
< / s v g >
)
}
var IMAGE _BUG = ( p ) => {
return (
< svg width = "1em" height = "1em" viewBox = "0 0 16 16" className = "bi bi-bug-fill" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< path fillRule = "evenodd" d = "M4.978.855a.5.5 0 1 0-.956.29l.41 1.352A4.985 4.985 0 0 0 3 6h10a4.985 4.985 0 0 0-1.432-3.503l.41-1.352a.5.5 0 1 0-.956-.29l-.291.956A4.978 4.978 0 0 0 8 1a4.979 4.979 0 0 0-2.731.811l-.29-.956zM13 6v1H8.5v8.975A5 5 0 0 0 13 11h.5a.5.5 0 0 1 .5.5v.5a.5.5 0 1 0 1 0v-.5a1.5 1.5 0 0 0-1.5-1.5H13V9h1.5a.5.5 0 0 0 0-1H13V7h.5A1.5 1.5 0 0 0 15 5.5V5a.5.5 0 0 0-1 0v.5a.5.5 0 0 1-.5.5H13zm-5.5 9.975V7H3V6h-.5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 0-1 0v.5A1.5 1.5 0 0 0 2.5 7H3v1H1.5a.5.5 0 0 0 0 1H3v1h-.5A1.5 1.5 0 0 0 1 11.5v.5a.5.5 0 1 0 1 0v-.5a.5.5 0 0 1 .5-.5H3a5 5 0 0 0 4.5 4.975z" / >
< / s v g >
)
}
var IMAGE _CONTROLLER = ( p ) => {
return (
< svg width = "1em" height = "1em" { ... p } viewBox = "0 0 16 16" className = "bi bi-controller" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< path fillRule = "evenodd" d = "M11.119 2.693c.904.19 1.75.495 2.235.98.407.408.779 1.05 1.094 1.772.32.733.599 1.591.805 2.466.206.875.34 1.78.364 2.606.024.815-.059 1.602-.328 2.21a1.42 1.42 0 0 1-1.445.83c-.636-.067-1.115-.394-1.513-.773a11.307 11.307 0 0 1-.739-.809c-.126-.147-.25-.291-.368-.422-.728-.804-1.597-1.527-3.224-1.527-1.627 0-2.496.723-3.224 1.527-.119.131-.242.275-.368.422-.243.283-.494.576-.739.81-.398.378-.877.705-1.513.772a1.42 1.42 0 0 1-1.445-.83c-.27-.608-.352-1.395-.329-2.21.024-.826.16-1.73.365-2.606.206-.875.486-1.733.805-2.466.315-.722.687-1.364 1.094-1.772.486-.485 1.331-.79 2.235-.98.932-.196 2.03-.292 3.119-.292 1.089 0 2.187.096 3.119.292zm-6.032.979c-.877.185-1.469.443-1.733.708-.276.276-.587.783-.885 1.465a13.748 13.748 0 0 0-.748 2.295 12.351 12.351 0 0 0-.339 2.406c-.022.755.062 1.368.243 1.776a.42.42 0 0 0 .426.24c.327-.034.61-.199.929-.502.212-.202.4-.423.615-.674.133-.156.276-.323.44-.505C4.861 9.97 5.978 9.026 8 9.026s3.139.943 3.965 1.855c.164.182.307.35.44.505.214.25.403.472.615.674.318.303.601.468.929.503a.42.42 0 0 0 .426-.241c.18-.408.265-1.02.243-1.776a12.354 12.354 0 0 0-.339-2.406 13.753 13.753 0 0 0-.748-2.295c-.298-.682-.61-1.19-.885-1.465-.264-.265-.856-.523-1.733-.708-.85-.179-1.877-.27-2.913-.27-1.036 0-2.063.091-2.913.27z" / >
< path d = "M11.5 6.026a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm-1 1a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm2 0a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm-1 1a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm-7-2.5h1v3h-1v-3z" / >
< path d = "M3.5 6.526h3v1h-3v-1zM3.051 3.26a.5.5 0 0 1 .354-.613l1.932-.518a.5.5 0 0 1 .258.966l-1.932.518a.5.5 0 0 1-.612-.354zm9.976 0a.5.5 0 0 0-.353-.613l-1.932-.518a.5.5 0 1 0-.259.966l1.932.518a.5.5 0 0 0 .612-.354z" / >
< / s v g >
)
}
var IMAGE _ARCADE = ( p ) => {
return (
< svg width = "1em" height = "1em" { ... p } viewBox = "0 0 16 16" className = "bi bi-joystick" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< path d = "M7.106 15.553L.553 12.276A1 1 0 0 1 0 11.382V9.471a1 1 0 0 1 .606-.89L6 6.269v1.088L1 9.5l5.658 2.83a3 3 0 0 0 2.684 0L15 9.5l-5-2.143V6.27l5.394 2.312a1 1 0 0 1 .606.89v1.911a1 1 0 0 1-.553.894l-6.553 3.277a2 2 0 0 1-1.788 0z" / >
< path fillRule = "evenodd" d = "M7.5 9.5v-6h1v6h-1z" / >
< path d = "M10 9.75c0 .414-.895.75-2 .75s-2-.336-2-.75S6.895 9 8 9s2 .336 2 .75zM10 2a2 2 0 1 1-4 0 2 2 0 0 1 4 0z" / >
< / s v g >
)
}
var IMAGE _TABLET = ( p ) => {
return (
< svg width = "1em" height = "1em" { ... p } viewBox = "0 0 16 16" className = "bi bi-tablet-landscape" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< path fillRule = "evenodd" d = "M1 4v8a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1zm-1 8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2v8z" / >
< path fillRule = "evenodd" d = "M14 8a1 1 0 1 0-2 0 1 1 0 0 0 2 0z" / >
< / s v g >
)
}
var IMAGE _CHECKMARK = ( p ) => {
return ( < svg width = "1em" height = "1em" { ... p } viewBox = "0 0 16 16" className = "bi bi-check-circle-fill" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< path fillRule = "evenodd" d = "M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z" / >
< / s v g >
)
}
var IMAGE _X = ( p ) => {
return (
< svg width = "1em" height = "1em" viewBox = "0 0 16 16" { ... p } className = "bi bi-x-circle-fill" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< path fillRule = "evenodd" d = "M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z" / >
< / s v g >
)
}
var IMAGE _ARROWUP = ( p ) => {
return (
< svg width = "1em" height = "1em" viewBox = "0 0 16 16" { ... p } className = "bi bi-arrow-up-circle-fill" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< path fillRule = "evenodd" d = "M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-7.5 3.5a.5.5 0 0 1-1 0V5.707L5.354 7.854a.5.5 0 1 1-.708-.708l3-3a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V11.5z" / >
< / s v g >
)
}
var IMAGE _MIXMODE = ( p ) => {
return (
< svg width = "1em" height = "1em" { ... p } viewBox = "0 0 16 16" className = "bi" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< g
stroke = "none"
strokeWidth = "1"
fillRule = "evenodd"
id = "g22"
transform = "matrix(0.23504594,0.08739104,-0.08739104,0.23504594,7.4047351,-0.89601877)" >
< g
id = "g20" >
< g
transform = "translate(26,16)"
id = "g10" >
< path
d = "m 6,28 c -2.7614237,0 -5,-2.238576 -5,-5 0,-2.761424 2.2385763,-5 5,-5 2.7614238,0 5,2.238576 5,5 0,2.761424 -2.2385762,5 -5,5 z m 0,-2 c 1.6568543,0 3,-1.343146 3,-3 0,-1.656854 -1.3431457,-3 -3,-3 -1.6568543,0 -3,1.343146 -3,3 0,1.656854 1.3431457,3 3,3 z"
fillRule = "nonzero"
id = "path6" / >
< path
d = "M 6,4 C 4.8954305,4 4,3.1045695 4,2 4,0.8954305 4.8954305,0 6,0 7.1045695,0 8,0.8954305 8,2 8,3.1045695 7.1045695,4 6,4 Z m 0,8 C 4.8954305,12 4,11.10457 4,10 4,8.8954305 4.8954305,8 6,8 7.1045695,8 8,8.8954305 8,10 8,11.10457 7.1045695,12 6,12 Z M 2,8 C 0.8954305,8 0,7.1045695 0,6 0,4.8954305 0.8954305,4 2,4 3.1045695,4 4,4.8954305 4,6 4,7.1045695 3.1045695,8 2,8 Z m 8,0 C 8.8954305,8 8,7.1045695 8,6 8,4.8954305 8.8954305,4 10,4 c 1.10457,0 2,0.8954305 2,2 0,1.1045695 -0.89543,2 -2,2 z"
id = "path8" / >
< / g >
< g
transform = "matrix(-1,0,0,1,41.130435,11)"
fillRule = "nonzero"
id = "g18" >
< path
d = "M 16.26087,41 V 2.7254902 H 9.1304348 C 5.1912482,2.7254902 2,5.9136707 2,9.8463828 V 33.879107 C 2,37.806243 5.1950878,41 9.1304348,41 Z M 0,9.8463828 C 0,4.8090529 4.0867262,0.7254902 9.1304348,0.7254902 h 8.1226402 c 0.556589,0 1.007795,0.4461589 1.007795,1.0032974 V 43 H 9.1304348 C 4.0878349,43 0,38.908131 0,33.879107 Z"
id = "path12" / >
< path
d = "m 17.930435,5.8998424 c 0,0.08424 0.05524,0.1393733 0.130435,0.1393733 h -0.130435 z m 0.130435,5.9040796 c -0.06814,0 -0.130435,0.06182 -0.130435,0.139373 v -0.139373 z m -0.130435,0 h -0.739131 v 1 h 0.869566 c 0.04437,0 0.08793,-0.0032 0.130434,-0.0095 V 5.0490748 c -0.04255,-0.00649 -0.0861,-0.00986 -0.130434,-0.00986 h -0.869566 v 1 h 0.739131 z M 17.191304,5.0392157 h 0.869566 c 0.480247,0 0.869565,0.3957278 0.869565,0.8606267 v 6.0434526 c 0,0.475311 -0.38597,0.860627 -0.869565,0.860627 h -0.869566 z"
id = "path14" / >
< path
d = "m 17.930435,29.19396 c 0,0.08424 0.05524,0.139373 0.130435,0.139373 h -0.130435 z m 0.130435,5.904079 c -0.06814,0 -0.130435,0.06182 -0.130435,0.139373 v -0.139373 z m -0.130435,0 h -0.739131 v 1 h 0.869566 c 0.04437,0 0.08793,-0.0032 0.130434,-0.0095 v -7.745343 c -0.04255,-0.0065 -0.0861,-0.0099 -0.130434,-0.0099 h -0.869566 v 1 h 0.739131 z m -0.739131,-6.764706 h 0.869566 c 0.480247,0 0.869565,0.395728 0.869565,0.860627 v 6.043452 c 0,0.475312 -0.38597,0.860627 -0.869565,0.860627 h -0.869566 z"
id = "path16" / >
< / g >
< / g >
< / g >
< g
id = "g22-6"
fillRule = "evenodd"
strokeWidth = "1"
stroke = "none"
transform = "matrix(0.23714163,-0.08153304,0.08153304,0.23714163,-6.7259967,1.4700063)" >
< g
id = "g20-4" >
< g
id = "g10-4"
transform = "translate(26,16)" >
< path
id = "path6-5"
fillRule = "nonzero"
d = "M 6,10 C 3.2385763,10 1,7.7614237 1,5 1,2.2385763 3.2385763,0 6,0 c 2.7614238,0 5,2.2385763 5,5 0,2.7614237 -2.2385762,5 -5,5 z M 6,8 C 7.6568543,8 9,6.6568543 9,5 9,3.3431458 7.6568543,2 6,2 4.3431457,2 3,3.3431458 3,5 3,6.6568543 4.3431457,8 6,8 Z" / >
< path
id = "path8-1"
d = "m 6,22 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z m 0,8 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z M 2,26 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z m 8,0 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.10457,0 2,0.89543 2,2 0,1.104569 -0.89543,2 -2,2 z" / >
< / g >
< g
id = "g18-1"
fillRule = "nonzero"
transform = "translate(23,11)" >
< path
id = "path12-2"
d = "M 16.117647,41 V 2.7254902 H 9.0588235 C 5.1595194,2.7254902 2,5.8842795 2,9.781461 V 33.944029 C 2,37.841438 5.1598077,41 9.0588235,41 Z M 0,9.781461 C 0,4.7799864 4.0546734,0.7254902 9.0588235,0.7254902 h 8.0589335 c 0.552224,0 0.99989,0.4461589 0.99989,1.0032974 V 43 H 9.0588235 C 4.0557734,43 0,38.946542 0,33.944029 Z" / >
< path
id = "path14-3"
d = "m 17.780392,5.8998424 c 0,0.082482 0.05656,0.1393733 0.137255,0.1393733 h -0.137255 z m 0.137255,5.9040796 c -0.07367,0 -0.137255,0.06359 -0.137255,0.139373 v -0.139373 z m -0.137255,0 h -0.72549 v 1 h 0.862745 c 0.04676,0 0.0926,-0.0037 0.137255,-0.01071 V 5.0503178 c -0.0447,-0.0073 -0.09054,-0.011102 -0.137255,-0.011102 h -0.862745 v 1 h 0.72549 z m -0.72549,-6.7647063 h 0.862745 c 0.476481,0 0.862745,0.3957278 0.862745,0.8606267 v 6.0434526 c 0,0.475311 -0.382942,0.860627 -0.862745,0.860627 h -0.862745 z" / >
< path
id = "path16-0"
d = "m 17.780392,29.19396 c 0,0.08248 0.05656,0.139373 0.137255,0.139373 h -0.137255 z m 0.137255,5.904079 c -0.07367,0 -0.137255,0.06359 -0.137255,0.139373 v -0.139373 z m -0.137255,0 h -0.72549 v 1 h 0.862745 c 0.04676,0 0.0926,-0.0037 0.137255,-0.01071 V 28.34443 c -0.0447,-0.0073 -0.09054,-0.0111 -0.137255,-0.0111 h -0.862745 v 1 h 0.72549 z m -0.72549,-6.764706 h 0.862745 c 0.476481,0 0.862745,0.395728 0.862745,0.860627 v 6.043452 c 0,0.475312 -0.382942,0.860627 -0.862745,0.860627 h -0.862745 z" / >
< / g >
< / g >
< / g >
< / s v g >
)
}
var IMAGE _JOYCONS = ( p ) => {
return (
< svg width = "1em" height = "1em" { ... p } viewBox = "0 0 16 16" className = "bi" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" >
< g
stroke = "none"
strokeWidth = "1"
fillRule = "evenodd"
id = "g22"
transform = "matrix(0.37879869,0,0,0.37879869,0.40087271,-4.4665372)" >
< g
id = "g20" >
< g
transform = "translate(26,16)"
id = "g10" >
< path
d = "m 6,28 c -2.7614237,0 -5,-2.238576 -5,-5 0,-2.761424 2.2385763,-5 5,-5 2.7614238,0 5,2.238576 5,5 0,2.761424 -2.2385762,5 -5,5 z m 0,-2 c 1.6568543,0 3,-1.343146 3,-3 0,-1.656854 -1.3431457,-3 -3,-3 -1.6568543,0 -3,1.343146 -3,3 0,1.656854 1.3431457,3 3,3 z"
fillRule = "nonzero"
id = "path6" / >
< path
d = "M 6,4 C 4.8954305,4 4,3.1045695 4,2 4,0.8954305 4.8954305,0 6,0 7.1045695,0 8,0.8954305 8,2 8,3.1045695 7.1045695,4 6,4 Z m 0,8 C 4.8954305,12 4,11.10457 4,10 4,8.8954305 4.8954305,8 6,8 7.1045695,8 8,8.8954305 8,10 8,11.10457 7.1045695,12 6,12 Z M 2,8 C 0.8954305,8 0,7.1045695 0,6 0,4.8954305 0.8954305,4 2,4 3.1045695,4 4,4.8954305 4,6 4,7.1045695 3.1045695,8 2,8 Z m 8,0 C 8.8954305,8 8,7.1045695 8,6 8,4.8954305 8.8954305,4 10,4 c 1.10457,0 2,0.8954305 2,2 0,1.1045695 -0.89543,2 -2,2 z"
id = "path8" / >
< / g >
< g
transform = "matrix(-1,0,0,1,41.130435,11)"
fillRule = "nonzero"
id = "g18" >
< path
d = "M 16.26087,41 V 2.7254902 H 9.1304348 C 5.1912482,2.7254902 2,5.9136707 2,9.8463828 V 33.879107 C 2,37.806243 5.1950878,41 9.1304348,41 Z M 0,9.8463828 C 0,4.8090529 4.0867262,0.7254902 9.1304348,0.7254902 h 8.1226402 c 0.556589,0 1.007795,0.4461589 1.007795,1.0032974 V 43 H 9.1304348 C 4.0878349,43 0,38.908131 0,33.879107 Z"
id = "path12" / >
< path
d = "m 17.930435,5.8998424 c 0,0.08424 0.05524,0.1393733 0.130435,0.1393733 h -0.130435 z m 0.130435,5.9040796 c -0.06814,0 -0.130435,0.06182 -0.130435,0.139373 v -0.139373 z m -0.130435,0 h -0.739131 v 1 h 0.869566 c 0.04437,0 0.08793,-0.0032 0.130434,-0.0095 V 5.0490748 c -0.04255,-0.00649 -0.0861,-0.00986 -0.130434,-0.00986 h -0.869566 v 1 h 0.739131 z M 17.191304,5.0392157 h 0.869566 c 0.480247,0 0.869565,0.3957278 0.869565,0.8606267 v 6.0434526 c 0,0.475311 -0.38597,0.860627 -0.869565,0.860627 h -0.869566 z"
id = "path14" / >
< path
d = "m 17.930435,29.19396 c 0,0.08424 0.05524,0.139373 0.130435,0.139373 h -0.130435 z m 0.130435,5.904079 c -0.06814,0 -0.130435,0.06182 -0.130435,0.139373 v -0.139373 z m -0.130435,0 h -0.739131 v 1 h 0.869566 c 0.04437,0 0.08793,-0.0032 0.130434,-0.0095 v -7.745343 c -0.04255,-0.0065 -0.0861,-0.0099 -0.130434,-0.0099 h -0.869566 v 1 h 0.739131 z m -0.739131,-6.764706 h 0.869566 c 0.480247,0 0.869565,0.395728 0.869565,0.860627 v 6.043452 c 0,0.475312 -0.38597,0.860627 -0.869565,0.860627 h -0.869566 z"
id = "path16" / >
< / g >
< / g >
< / g >
< g
id = "g22-6"
fillRule = "evenodd"
strokeWidth = "1"
stroke = "none"
transform = "matrix(0.37879869,0,0,0.37879869,-8.7351179,-4.4850005)" >
< g
id = "g20-4" >
< g
id = "g10-4"
transform = "translate(26,16)" >
< path
id = "path6-5"
fillRule = "nonzero"
d = "M 6,10 C 3.2385763,10 1,7.7614237 1,5 1,2.2385763 3.2385763,0 6,0 c 2.7614238,0 5,2.2385763 5,5 0,2.7614237 -2.2385762,5 -5,5 z M 6,8 C 7.6568543,8 9,6.6568543 9,5 9,3.3431458 7.6568543,2 6,2 4.3431457,2 3,3.3431458 3,5 3,6.6568543 4.3431457,8 6,8 Z" / >
< path
id = "path8-1"
d = "m 6,22 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z m 0,8 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z M 2,26 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z m 8,0 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.10457,0 2,0.89543 2,2 0,1.104569 -0.89543,2 -2,2 z" / >
< / g >
< g
id = "g18-1"
fillRule = "nonzero"
transform = "translate(23,11)" >
< path
id = "path12-2"
d = "M 16.117647,41 V 2.7254902 H 9.0588235 C 5.1595194,2.7254902 2,5.8842795 2,9.781461 V 33.944029 C 2,37.841438 5.1598077,41 9.0588235,41 Z M 0,9.781461 C 0,4.7799864 4.0546734,0.7254902 9.0588235,0.7254902 h 8.0589335 c 0.552224,0 0.99989,0.4461589 0.99989,1.0032974 V 43 H 9.0588235 C 4.0557734,43 0,38.946542 0,33.944029 Z" / >
< path
id = "path14-3"
d = "m 17.780392,5.8998424 c 0,0.082482 0.05656,0.1393733 0.137255,0.1393733 h -0.137255 z m 0.137255,5.9040796 c -0.07367,0 -0.137255,0.06359 -0.137255,0.139373 v -0.139373 z m -0.137255,0 h -0.72549 v 1 h 0.862745 c 0.04676,0 0.0926,-0.0037 0.137255,-0.01071 V 5.0503178 c -0.0447,-0.0073 -0.09054,-0.011102 -0.137255,-0.011102 h -0.862745 v 1 h 0.72549 z m -0.72549,-6.7647063 h 0.862745 c 0.476481,0 0.862745,0.3957278 0.862745,0.8606267 v 6.0434526 c 0,0.475311 -0.382942,0.860627 -0.862745,0.860627 h -0.862745 z" / >
< path
id = "path16-0"
d = "m 17.780392,29.19396 c 0,0.08248 0.05656,0.139373 0.137255,0.139373 h -0.137255 z m 0.137255,5.904079 c -0.07367,0 -0.137255,0.06359 -0.137255,0.139373 v -0.139373 z m -0.137255,0 h -0.72549 v 1 h 0.862745 c 0.04676,0 0.0926,-0.0037 0.137255,-0.01071 V 28.34443 c -0.0447,-0.0073 -0.09054,-0.0111 -0.137255,-0.0111 h -0.862745 v 1 h 0.72549 z m -0.72549,-6.764706 h 0.862745 c 0.476481,0 0.862745,0.395728 0.862745,0.860627 v 6.043452 c 0,0.475312 -0.382942,0.860627 -0.862745,0.860627 h -0.862745 z" / >
< / g >
< / g >
< / g >
< / s v g >
)
}
var RATING _cool = new Image ( ) ;
RATING _cool . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAEgAAAAWCAYAAABjadrAAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0VBxxA5lzqAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAADnJJREFUWMN9mNlzHcd1xn + ne + YuAEiAJBaK4CoSoGgGEm2TlETLEi3KshPLKVflKfZLqlJJqvLkvFl / gfWYp + QpqSRVceXBkUtJpLIjS4lNWZZJUdxJcREXUCSI / V7cbZbuPnmYAUjadKYKFwPcnp4 + X5 / vO99p6eYdVAPeOeZm73H6zEmuXrn8ykqz + X0UAjokIg1r7ZxgmiIgSAIQVGs2srNPP / 2 lN44e / Tp9A + tQVe7dvcOJ3 / yK67euv9JNut8KIQxSXmbtea15JKnV + 9 / cu2 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
var RATING _fine = new Image ( ) ;
RATING _fine . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAEIAAAAUCAYAAAA5g + sCAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0VBxU5OuROAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAACuJJREFUWMOFmMtvXMl1xn9V93Y3m6REyZ7RayTqOdSzpZEsaQajcewEExiI4QSIswiCrLIIkKyyNZA / wKtkkUV23imrDPI07PgRB5lBZmzN2BjRI4uiREkUH2Lz3d3svvdW1TlZ1O0m9UoK6CYb93bdOud85 / u + 0 + b3 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
var RATING _safe = new Image ( ) ;
RATING _safe . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAEkAAAAVCAYAAAAKP8NQAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0VBw0qVnwYAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAADRlJREFUWMOFmMmTHNdxh7 / 3 qqrX2UAAM1gIcMFCcAFBcKcsS5RkS6EQL4pwWA75JN909M3 / gW8 ++ mjfHWGGrQgqwlpAiYsECiRBggKxE8Q2wOzT0921vCXTh + rpwYikVB0z0dM99Spfvszfkubc + Q9Z7a9x9tLH / 3 r6wpl / WVi5S + kqQBFh22VM / aMKUP / RsBknjj / D3339NbNz506u3b7Ou2dP6x + vXWBjuIGoICKgitY3AqCYrXUxdFsdHj90jFdf + oY5uOsg75z //X/86p1f/2S5v4IBVBVjLMbY0d31y2JQs/l9vVaj0eKxQ8fYN7u/9/b7b0/38z6K3rcTRVQRM3qPQdUwDknBGMPJo8/zD6/92KSDfMhvP3x3/dSl304PsyHTj06zu7sDk1jU8JWXBTTCvfklTl16h5efeI61sMF/vfm6Xli9yvTsNA/smMUkbEvOl10aheH6gN/d+gPz5ZI+e+DE4ptX3prdaGyw5+QcSWZQYwDDn1/IIDGyurzOzz56A4udbk40OPLkIZqtBpg6DlHFx4iPgaCBKkSc9wSJdayqDAZD3r/5Hq+ufov0/L0Lx0+df3N652O7ee3b32d61yRZM6vT+ZeCioYP3v2A//vfX7LQW/73Cxfe/emSX+ab3/0rjj59iM5EG6zy1dnW8XPyjZKLH1/ivd98wJ33bs9uyDovf+NFvvG3X8O27Ljm/tIVfOTSJ9f47NpV8mHF4ZMn+JsffovudJcQPC44Cl8xcAXDsqQMFVUIlMETNNZ1JXD35l16p1dwVXE8vXTnyrk8KfjOKyc4/MSjeKpxxu2fCUqBJKZ0p9oYC7cWb/303bO/47lXn+XFrz1LayYjaBi1aN0aX75K/aTp6SkmJye5d2+RUz9/G5JAq9Ng6oEJTINtzfLVURlCELpT9eGIiWimlInDBc+gGDKsCgZlThU9QRS1hpgpIYtEBFXBiKFIKqrocN4dT5cHK3R3TTL34C7UBJQ4xgkdv9semKBEhIQENYpI5NqtzygkZ8/Ds2TdhGgCGBk1JugYR7Y2rKPPIYJRulNt9hzcTdJJyAdDxAhiBYtBUMxorfvjURRRIQJBIlVV0i8GNRaqsjRY4+Kda5hugtOAlzoZslngaggSiSooNW7aaHAxgAGPHE2jiSRNQ9KsAdGOAqm8ZzjMcd5jv6QOBGjElN5KD6PQjzkmMzQ7DUhl25kXVUW/N8Dct4ixhk6nTbvVGn2uYJRGp0GrkZGP0qrGjtJb/3bRkfeHOOeIKC54qhBw0TMsS/Ki4MZnNyiDJ1rDkMBaLEkkI8SAGEW9UhYVPnhQiyJEHZGLgBHDYKMkEeg2Gv+dqnxZ0VoWF5Z5/9QZ7t5ZwFqLsdvTZNSCwsrdFXZMzLJ7aie31298YS2Jyq3r85z6nzfrc1dAleZEk6eef5ITzx0nayYko4OwGMwom4oi1FXiCfgQuXf7Hud+8xGLd5cQVXJX4CQQELxGYlTcegXB0swyPEoeKqwPSKzZOa45bl38nMHCes2yWpPLJr8YseT9nAO6l26z+0laVhWkX0xUWRQsLS4xf2eexCQYux0RJAq9tT7FRsnxY0+TJOl4c38KO6srq5w5fWYbprSnOkztmuTJpx8naybjdY01WGsRYFgWzK8s4mxg6ErKsuL29ducvfApi/MLgEFt3TaCokbBWGxlSK0ly+rqKaqSpNFAo4Ix+LxkfbVHf2EZo3XzbsM8MQQXyGb2I0C6qX3+dGd75mb57ve/R5VXJNitb0YVpSGyvLjOhXMXuXHlBuWao6yqbaxoAGsNDz10gL//0Y+2kmiEtJnx4OF9NJoNADyeGBzDsiDGiFdhsbfKpdvXqVLBaQQ1+FbCw888xt6jD9c9v0m0UmOQCAwW1rjx6TV8HmjFNkGE4D0iggI2TZg7eIDdM3MjDQZyX0sZgd7qOuVSQS8f/jhtNloEr/fRh6IoE5MdJh/rgtptm+Y+6D0a4ZFjB/nZ6z/n/NmLBFNuE4gKGGvZs2+OPT/cM74zIpTiKKVioVij6Jc45/BV5NbaEsNYERLY8CUroSDUvFNjVAOyR6ZIBUQEMRGjEKWmnBiFVjPirgrkkVQCpfeYEIka6wAaBt2XYfc2xroI0dHOBRsNslDiNjxpqjfT6c4Ulz+/xNLdZR6YmRiftsFgErONqmsglTGIJ5ll/yN7eeHrJ7l6+TPcMMeoGUsHVSUQcER8JlS+oqwq8uDIXcGwLBi6EhccPkZstKyWfYIGFCWoUHqPIyKb7COKNxExoLZmNqOKbKpoURxuHKeI4IKHYFCR0f9B5D7FbRQxMha9iVrKNNKgpsB0/6597//hAs+/9et3GObr7Ny1k2azOeJZs437jbF0Jtq02k2MMXXWk5S5A7tpdzv08x4+BvJQUkXPsCrIq5KVlRVufn4HFzylc5TBEazQnpmgu2MKzQyKYiUhjw4ZBRtCpPKeioBoRBWCD/jKEaNQF4FgFERq+pYguN4QYt32qooPHvEG1VpIaFC880ioEzN+qQKWJFpcr4SY4n08ms5O7v7HyWTq0kenP+Hzz66zc+eOEU7oGH82r2azwTMvnODxE8dotRv1qRCwDQPWEERY6q1y9e5NBtEx9AVFUXL78i3O/uIDOp0JGo0mpS/JKZk79iAHn2qixiKqJMFQRo+MYM3HQOUd5ajhECjWc3pXFom5I7EZxuiYnTaTxUDYNTGLSysKFBc9Es0IwgxmIzK8s4yul9tV6ub3atC8YjJ5iM7ExBvp3eWFX+Y+Z8eOHdgobCz3Ry23BcCbZdhoZvSPDHEhIqGiDA5XeeZXliirgkod8xsrVOsZlQqBCF4phh5WhL8+9iKP7H+YW3du8ebV3+MHrvZMaX3iSbSETVetSoyBMjgKGxAUG6DqF4QbfR6dOcCRA4dpZK1Ng1DLTVU6zQmCRt45d5or5g5BhaBb0qXhBF13sFh80TIpqBpsjDSnGkw22gvppVuXDk7OTvDtV79JZyLbko2mZoqgtRoNEqnE09rR5c5gGbdRkbsSV3qWl1apxBMNDFxJ05UEU2MKQXEx0rYtnj/y3H++fPzFf/rwj2f/+f358/9WqFB5h88UBNKY4GJAR0wTYqTyDmcFUcFKbTuats1Lx17iB698z0y2purJxNi9Q5JmXJm/xrlr5xWtDa1sJglFugmdh3diZ2c2ZfcWxati1ZL3BgyXcvrD/ly6Vqyx+9FdnHzhOM1OWjtkjVS+oCwd/Sqn8LWPCcGxVg0pllfx6gkxomJYzTdwKqgFJ4EiOqLRWup7xUnAkmJL00tyS1IlCyJKFMEFh/MRIwaJCSGE2vGbun1dDHXlIiTBEmIkxdKxXR5I
var RATING _sad = new Image ( ) ;
RATING _sad . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAD0AAAAUCAYAAAA + wTUXAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0VBwUkjfQqAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAACmBJREFUWMOVmMtzHNd1xn / 3 ds / 0 zAAgIBAAKT4hSgIhSqJF2JRDOynJlstJqlxJeZ3KxlklO / 8 FyZ + QVbKKlY29SlKuSmJvElUSS4wVyBYtmiJFijQFkgBJYIDBANOP + zgni26CZJHM41ZNddW9PXfO4zvf + c6YX1y / yOZ2zvKvrvDLizd0c7CLsS1s0sYYizEGRTHKk6s5U1WyRPj9t5fMq4svsXJrjfeXfz24tbox6cVi0gSrhmctRVFRQgyIePb1Wrx0Yu7dF44f / 94 nlz7V6yvbpGkHay0A8lRbms8jS1QQiUxNdjl9evHNpaXF5enpfZh / + fh9li / c4Cc / + 1 SDmeDkwoscOXqE3tg4asDwdKeNMXsGh + D46T / 9 hKPThi + dfq37y19dLlb7kZOLi8yfmKfVzjDP9rm + RyEGz2a / z6eXrnL39jUOHpjh3r1VXnj5DGff / AppK62dwaCqj3irGNv4raCqiCqu8ty5u86FC58wGm3xh39w7k / eevuNH6QbQ + H8x9c06 + 7 nu9 / 5 XU6cOE47azeR + p8trX9A8NHzwX + 8 z + bugPMfXSs2B57feeu3efOrb9Ad66Ka8L95rQrWKGhk4eSL / PgfhM + ufIarPOe + PsepUyfJOi0UeOiuwZjGSVGc91TOU5WRwgXKKmKyGQrX5sMPz / Pev1 / 6 m2NHZ3 + Qrvd3WLl1n6VzX2JhYQFQJNaQ1We72zitKEpiLMaAc8rm5gaHjp7g1GunyDpdvIvYJMEYoU7Os261RBRrLPPzx1laOsPVq58zyl192sRMohC1DlKIQlkGKu / Ji4qdnZw8L8lLR144XFAkJpjWOPMvnuLq5Y84 / 8 Gyphv97bMuGDq9LmLAqAE1iAjW2r06Mk9kqoaVqhBDQFG8FyoXGJ8YJ01bGNMiSVr1uypYY564R1WbTNV3qrVYC / tnnmOs12NjfYCoUlUVRVlSVJ6qClQukBeOnTyQu0BZ1vsiliBKUIsKxGhRVdqdfRjbY9DfJfXOvQzSGGP2MpEkCYPtTdZWVynyEYo8A5aG4IWtzQH7ej3yoqrJb680tAmOcvM319nc7Df1WJ93OhmzBw4yPT1DYtOmCpqAJwmqhv6g4sqNTUrvyUtHWQlFUbDR75OXDrBIhBgVYxO64 / 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
var RATING _worst = new Image ( ) ;
RATING _worst . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAGMAAAAVCAYAAABSQFBJAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0VBjf1QZTrAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAEh1JREFUaN6dmVmMZNV5x3 / n3Fv33lq6lu7q7ulllp4VMAy2MWNsYLABJ3awFMUPUeJIkZK3JFKezZOVp / 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
function Logo ( ) {
var note _arrow = new Image ( ) ;
note _arrow . src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAABjCAYAAACWsFAzAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht+mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM/VEejEDz/F1Dx/f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg+UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX+SXDK5ymDkWEAVKiTHD/4Hv3trFqYm3aRgDOh+se2PYSCwCzTrtv19bNvNE8D/DFxpbX+1Acx+kl5va5EjoG8buLhua/IecLkDDDzpkiE5kp+WUCgA72f0TTmg/xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta/fsBxMxyyECtw/8AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0TDjpHpB7sAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAfVJREFUWMPtlr9q21AUxr8j7CuERQ0lUzA0gzw0VgzxliV5Bs15kA4tWQN5Db9AwG+gxdiDwe6fJc3gKTWdTDRK/jL0KpVry5KSDi2+P7hwOTrn49xzrg4XKOarXjux8j7UarW3AAjgi17UtmocHb37CIDT6ZSz2YwAqG3lOD5+LwCu6vU6ARxQA+BA2660TzGu22AQBA9JkpDkiuQqSRIGQfDgug2WTYoAHkmec5NzAI/aJx/f71yLCIfD4Zw5jEaj7yJC3+9cbwi0Wi0BcGFZFgFcxnGcp8M4jgngUvte6NjfOI5Dz/Putf+K+axIst1u3zuOs35EEblTSpHkIctzqJSiiNyldbmxbZvj8fjTNm9d2K1Kk8nkg23b9P3OTdqlW93qSkK6XrcAKAAoIvgVo/uf2YtIri3dk4TV7Z6cKqXOMneoyn2DUuqs2z05TaUlPULFjCSNtV6QydbMLPwljJARMkJG6F8RqhU5DAaDUkKybWxm5/PWoPWZvS9d+wZg+YL4pY59Fmo0m803VVV0TGOt/cvlsrBbf74Nsm+Aff1FsjUouvE7M/I8D2EYIgxDeJ73up92sVi8/mi9Xg/9fv95X4Z53oNzF3pazPdlZruuCxGptFzX3eja5yiKflbNIooiAPgBg8FgMBgMBoPBYPjfeQJefdQWdKdLVQAAAABJRU5ErkJggg=="
var note _circle = new Image ( ) ;
var note _circle _shadow = new Image ( ) ;
var notes = [ new Image ( ) , new Image ( ) , new Image ( ) , new Image ( ) ]
notes [ 0 ] . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAEcAAABKCAYAAADpLknBAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0RJDG8md8iAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAGQxJREFUeNrtnHl0VFW2 / z / 33 hpTlVSlMk9AgBCSEEBJIE4ggzIJinY7MAhio0 / tpa3ddqO2rfZ7T / v1pG3rr33dba + nLXYrzjiB2qIgowQMSsKcQOaxUknN997z / qgkJCFAhUnfWr + dtVcqNZw653v32Wfv7943ki7C / H8ZWAzn64sCgQCbN29h69ZtonxPOYcPH6aurg6v14emacTG2klISMDpdJKTM5LCsWNFSckkecyYAhRF + VbAkc6F5aiqSmVlFfv27Sve8PmGbevXf8bOnbsIhUKDHsvlclFSMomp06ZSVDRBys0dRWpq6v89cMLhMOvXf8aql14WpaWl7N9 / gGAwCIAiy4zJyCYvJYuhCSmkOly4bLFYDCYUWcYXCuIJ + PAG / VS7mzncVMee + iMcaqqLTFSSiI + PJydnJJdfPoWly5ZKo0fnfvfBCYVClJdXcM / dPxIbN36BrusYFQMWo5GpueNZdtFMZhcWYzGYBj12rbuF10o38MLmteytryaghtB0HbPZzNKlS / j5ww9JaWlp52TrnTE469d / xvN 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
notes [ 1 ] . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAEoAAABOCAYAAACHQYBnAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfkBw0VOiebBf1wAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAH5FJREFUeNrNnHl0U9e977 / nHA2WLcuyNdnGGFuW5xDwDMZmMPM8uA0tadfr6125r + ncd9O0TWiQk5AwGEKAACWXJC1tUm6akAC9TdukTZsmLzRJQwM2Bo + SbEuyZVmDNZ9z9vvjyBN4BKXr7rV + S14gnbP1Ob / 9 + 333 b + 8 tivdGMNvWa + 3 F79 / 5 IykvKaPmF9 + Du2rULX8zFEADFC28jv4fNavLDg0N4eWXXyYLFy6kKisrcdeN90ZmZQOWPnz7 / 3 yTJMQnkK0bt5DWz27M + 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
notes [ 2 ] . src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEMAAABHCAYAAABcW/plAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht+mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM/VEejEDz/F1Dx/f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg+UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX+SXDK5ymDkWEAVKiTHD/4Hv3trFqYm3aRgDOh+se2PYSCwCzTrtv19bNvNE8D/DFxpbX+1Acx+kl5va5EjoG8buLhua/IecLkDDDzpkiE5kp+WUCgA72f0TTmg/xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta/fsBxMxyyECtw/8AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfkBw0VOy+MxUQDAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAA5tJREFUeNrtnM9rE0EUx79vN7EVAgaDVy9aQfHYa1s8e/FQeiiePXjTU72WgkchIL3rxSoKgkjBHpQg0j+gVkqVYC45VEJN2t3szs7zMNlk06YtbXbrTnYehNn8YNj3me9783ZmCK2svHoKyHEwjwHyEsDjAI+p9qxm7XZbsnYBcgFC2mx2dvaJZVnd9wSAkVHzvDbl8/neEMJY13LhxdT1KSzdW0r1zbLnQv7ZAfkEEgQKAMjT9fF84yVe//p4PIxSoYTpiel0w3CaCC7WQW2C5RMooFPDeF/9dHSm00nGHAgQh6k4/oSsFwzfU+mek0n7Oa0yXAQGYXgg1WoVuVxOTxjs+yAmgCkWZaytrbFt2/qFCQsP8IP+MOGM5gxu7wMSIAlQQmWiNjCk0wLJuFXR35EeOUMGwL4DSFKvuJTBPsCyownSA4Z0W6q4CkOEKWZlBJqECTN4rwUS6IZJUs+/qYfBfhvseoAkkOyU3wkl0KHCpP63jsUPi4lPqew4IIEuCGKljYe37uP25RvpgNHYa2D5y/J/U83dq3eGhJHrBIeirFc5HreRrV6dZBobjPn5eczMJL8EsLHxHeVyOQkyZqVL20d4A8PAMDAMjDRZYnVGsVh8Njc39zjufldXVyfK5fKWUYYJEwNjtHKGDiZZLRYxq3I80zCEIEgmvZQRXcthTqbfVMHgyAVHHGdWclYtwRPU1j5ncMS56DVAhz7jYxQgEzxaEyuM0BEwEEjAE1EHqe97HqTTUZlNhAQ80UtGfkBtT5BWh6SsxLIRQ7vTYrmzxAIHAvBdyFZjVIsuPhD8DOYAkIFyXvjqsIjnASIABxK829S7/LYA21abUhSFIZ19iNr2YTaRjd7uxq8ELAkkN8mdj+VtwLYGKIMCBjlHxz11oVBnIwcgcU4HXakzetR/88mFiSSQRwMTIw1USue0XYwOW6QcDluKQKDOb/L2ecBgqC28gbMEDT5DxSeMJh0e2dCxqMNApI38fmC3dA4wiDHcSEdGNBzB8Qu9kc7UI/y3rxVsb/3oJad8fuHd2zcLcd9wvV5PP4xarYZardb32fr6ul5TLYzFo4ybxWvgBz9HBoZRhoFhYBgYBoaBYWAYGAaGgWFgGBipelD7+PszrryYHHmH94RzMgxP+thxG9lWxuRkvxqazSZc182E83RgQZX4wHZ3pVLB5uZmJv9GwiRQA8PAMDAMjGGLrtAKhQJKpdKjLML4BwfkgOBZ+ypaAAAAAElFTkSuQmCC"
notes [ 3 ] . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAFYAAABRCAYAAABIU1FPAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfkBw0WABl9i4D7AAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAE69JREFUeNrtnHlUVGeWwH / v1cKmlAgBQcUNBHEPCEbjviVtlEQ7Syfp9GhOd4 + np3PSk + 5 Muk96ziTpZPrMnMRoujtRo2lbXMMmGEICJhqNbIoIrQgSIiCr7FtVvar3vvmjFDeIlBHFCfeceyjge99771f33e9 + 994 qSQiN / iw7duxIa29vX7xu3TqJe0ik / gy2pqaG5csfEXV1dRw79rU0cuTIewas3J8vbsuWLaKoqIjKykrefvsdcS9ZbL8FW1BQQHx8Ah0dHQghiI + PJzs7ewDs9xGz2UxMzE5RXFyMJMtIskxtbS3vv / + BaG9vHwB7KyKEIDMzk88 ++ 4 zOzk58wsbiNz0ERVH46quvSEtLWyOEGADrrDQ0NLB / f5IoLCxE7 + ZC1MvP8eAb / 4 rB3ZXy8nJiY + O2lZeX09 / h9iuwmqZx4sQJ38TERBRFYfSSmYxZ9gCjF0US / Oh87HY7Bw8eJDY2VrS1tQ2A7a00Njayc + eu2oqKCtx8hjD1 + WhcvT3RGQ2E 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
var shadownotes = [ new Image ( ) , new Image ( ) , new Image ( ) , new Image ( ) ]
shadownotes [ 0 ] . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAF0AAABcCAYAAAAMLblmAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0RJC2omINtAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAACl9JREFUeNrtnV1zE0cWht8eGyxZWBCbxBhCkluuAkWlQlLFH9jb7N / cX5EUYYtKwV7ldheIE8fmw5Yt21ia3gud4zlzprunZ + QPkPpUNRpZRiM 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
shadownotes [ 1 ] . src = "data:image/png;base64,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"
shadownotes [ 2 ] . src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAABKCAYAAAAG7CL/AAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht+mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM/VEejEDz/F1Dx/f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg+UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX+SXDK5ymDkWEAVKiTHD/4Hv3trFqYm3aRgDOh+se2PYSCwCzTrtv19bNvNE8D/DFxpbX+1Acx+kl5va5EjoG8buLhua/IecLkDDDzpkiE5kp+WUCgA72f0TTmg/xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta/fsBxMxyyECtw/8AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0WAROERVikAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAQ1JREFUeNrt2r0KglAcQPGjFATR2BSt4Ri0NfcE9ZrRG/QGQWvQ7NQLBH3YkESZW2aa54x3uMgPvcP/GkTRPMH2wGi3Wz0WQk3yE0YYYYQR5ge1JADgAhBFc2EyDYHls4cw97rAwjPGw1cYYYQRRhhhhBFGGBNGGGGEEUaYylXGBG8AHIGgoP0SoAPEdYc5AKeC92z/wxsTAjxfmH9SOskPS3loE0YYYYQRRhhhhBFGGGFMGGGEKb4y5jFXeP0jsqg96w7T5zujzdrDxHX8lDxjhBFGGGGEEUYYYYQRRhgTRhhhhBFGmCrXAtaZtTMwBXpNh5nlrG+ASZNh3ib36TXHFhh7xpgwwggjTKndAANPGt4oQR7PAAAAAElFTkSuQmCC"
shadownotes [ 3 ] . src = "data:image/png;base64,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"
var divar = new Image ( ) ;
divar . src = " data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAYAAAABQCAYAAAAQjqIkAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht + mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz + LVQcXZ10dXAVB8AfEydFJ0UVK / C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM / VEejEDz / F1Dx / f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg + UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX + SXDK5ymDkWEAVKiTHD / 4 Hv3trFqYm3aRgDOh + se2PYSCwCzTrtv19bNvNE8D / DFxpbX + 1 Acx + kl5va5EjoG8buLhua / IecLkDDDzpkiE5kp + WUCgA72f0TTmg / xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta / fsBxMxyyECtw / 8 AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0VNSCC + XQcAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAIABJREFUeNrtXXl8U1Xafu7N2qR76Z4UaCllKdQWAbEIiCyuoCJaGSQM3 / AxKqAz6igiWEBksTgfoig4KnF0QEQUZHEACyoFRQXZpLRSaNKmLd237Mn5 / ri55ZJmK03Kdp / f7 / 7 apsnNPeee + 7 zved73vAe4iTBx4gMEPHjw4MHj5sLs2U8RmUzGGwAePHjwjuHNhLxVK4lUKuUNAA8ePNpBJpORp59 + kueGGxH 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
var logo ;
var timer = 0 ;
var startpoint = [ Math . random ( ) * 1000 - 500 , Math . random ( ) * 1000 - 500 ]
var scorepoint = [ Math . random ( ) * 10 - 5 , Math . random ( ) * 10 - 5 ]
var pos = [ ... startpoint ] ;
var hitrating = - 1 ;
var timer2 = 0 ;
var notetype = 0 ;
setTimeout ( ( ) => {
logo = document . getElementById ( "logo" ) ;
var draw = logo . getContext ( "2d" ) ;
draw . font = "64px Open Sans Condensed" ;
var size = draw . measureText ( "Pr ject" )
logo . width = size . width
setInterval ( ( ) => {
if ( hitrating == - 1 ) {
pos [ 0 ] -= startpoint [ 0 ] / 20 ;
pos [ 1 ] -= startpoint [ 1 ] / 20 ;
if ( ( Math . abs ( pos [ 0 ] ) < 32 && Math . abs ( pos [ 1 ] ) < 32 && Math . random ( ) * 10 < 1 )
|| ( Math . abs ( pos [ 0 ] ) < 16 && Math . abs ( pos [ 1 ] ) < 16 && Math . random ( ) * 4 < 1 )
|| ( Math . abs ( pos [ 0 ] ) < 4 && Math . abs ( pos [ 1 ] ) < 4 && Math . random ( ) * 2 < 1 ) ) {
scorepoint = [ Math . random ( ) * 30 - 15 , Math . random ( ) * 30 - 15 ]
var distance = Math . abs ( pos [ 0 ] ) + Math . abs ( pos [ 1 ] )
if ( distance > 32 ) {
hitrating = 4 ;
} else
if ( distance > 16 ) {
hitrating = 3 ;
} else
if ( distance > 4 ) {
hitrating = 2 ;
} else
if ( distance > 2 ) {
hitrating = 1 ;
} else {
hitrating = 0 ;
}
timer2 = Math . random ( ) * 400 + 350 ;
}
if ( timer > 1300 ) {
hitrating = 4 ;
timer2 = 350 ;
}
}
if ( hitrating != - 1 && timer2 <= 0 ) {
hitrating = - 1 ;
notetype = Math . floor ( Math . random ( ) * 4 )
startpoint = [ Math . random ( ) * 1000 - 500 , Math . random ( ) * 1000 - 500 ]
pos = [ ... startpoint ] ;
timer = 0 ;
}
var draw = logo . getContext ( "2d" ) ;
draw . clearRect ( 0 , 0 , logo . width , logo . height ) ;
draw . font = "64px Open Sans Condensed" ;
var size = draw . measureText ( "Pr ject" )
draw . fillStyle = "#000000" ;
draw . fillText ( "Pr ject" , 0 , 48 ) ;
draw . font = "28px Open Sans Condensed" ;
draw . fillStyle = "#FFFFFF" ;
draw . drawImage ( divar , 14 , 45 , 152 , 32 ) ;
if ( hitrating == - 1 ) {
draw . drawImage ( shadownotes [ notetype ] , 70 - 19 , 14 , 36 , 36 ) ;
draw . drawImage ( notes [ notetype ] , 70 - 19 + pos [ 0 ] , 14 + pos [ 1 ] , 36 , 36 ) ;
draw . save ( ) ;
drawImage ( note _arrow , 70 + 22 - 4 - 19 , 14 - 19 + 38 , 0.5 , ( ( timer / 50 ) * 18 ) * ( Math . PI / 180 ) ) ;
draw . restore ( ) ;
} else {
switch ( hitrating ) {
case 0 : {
draw . drawImage ( RATING _cool , 70 - 19 + scorepoint [ 0 ] , 14 + scorepoint [ 1 ] ) ;
} break ;
case 1 : {
draw . drawImage ( RATING _fine , 70 - 19 + scorepoint [ 0 ] , 14 + scorepoint [ 1 ] ) ;
} break ;
case 2 : {
draw . drawImage ( RATING _safe , 70 - 19 + scorepoint [ 0 ] , 14 + scorepoint [ 1 ] ) ;
} break ;
case 3 : {
draw . drawImage ( RATING _sad , 70 - 19 + scorepoint [ 0 ] , 14 + scorepoint [ 1 ] ) ;
} break ;
case 4 : {
draw . drawImage ( RATING _worst , 70 - 19 + scorepoint [ 0 ] , 14 + scorepoint [ 1 ] ) ;
} break ;
}
}
timer += 50 ;
timer2 -= 50 ;
//p.setSiteCounter(p.siteCounter+1);
} , 50 )
} , 300 ) ;
function drawImage ( image , x , y , scale , rotation ) {
var draw = logo . getContext ( "2d" ) ;
draw . setTransform ( scale , 0 , 0 , scale , x , y ) ; // sets scale and origin
draw . rotate ( rotation ) ;
draw . drawImage ( image , - image . width / 2 , - image . height / 2 ) ;
}
return ( < >
< canvas className = "homelink" id = "logo" width = "0" height = "84" / >
< / > ) ;
}
function Sort ( p ) {
let { sort , sortOrder } = useParams ( ) ;
return (
< >
< Link to = { "/rankings/" + p . order + "/" + ( ( p . order === sort ) ? ( sortOrder === "desc" ) ? "asc" : "desc" : "desc" ) } onClick = { ( ) => { p . setIsLoading ( true ) ; p . setUpdateUsers ( ! p . updateUsers ) } } > { p . label } < /Link>{(sort===p.order?<>{(sortOrder==="desc")?<>▼</ > : < > ▲ < />}</ > : < > < / > ) }
< / >
)
}
function ProfileDataContainer ( p ) {
return (
< div className = { "col-md-" + p . width + " border" } onMouseOver = { ( ) => { if ( p . setMouseOver ) { p . setMouseOver ( true ) } } } onMouseOut = { ( ) => { if ( p . setMouseOver ) { p . setMouseOver ( false ) } } } >
< div className = "row" >
< div className = "text-center label col-6 col-md-12" >
{ p . label }
< / d i v >
< div className = "data col-6 col-md-12 text-center" >
{ p . data }
< / d i v >
< / d i v >
< / d i v >
) ;
}
function StatisticsPanel ( p ) {
return (
< >
< div className = "row" >
< div className = "col-md-1" > < / d i v >
< ProfileDataContainer label = "Play Count" data = { p . playcount } width = "2" / >
< ProfileDataContainer label = "FC Count" data = { p . fccount } width = "2" / >
< ProfileDataContainer setMouseOver = { p . setMouseOver } label = "Cleared" data = { p . cleared } width = "4" / >
< ProfileDataContainer label = "Accuracy" data = { p . accuracy } width = "2" / >
< div className = "col-md-1" > < / d i v >
< / d i v >
< / >
)
}
function HitCountsPanel ( p ) {
return (
< >
< div className = "row text-center" >
< div className = "col-md-1" >
< / d i v >
< div className = "col-md-2 border" >
< div className = "row" >
< div className = "col-6 col-md-12" >
< img src = { RATING _cool . src } height = "16" / >
< / d i v >
< div className = "col-6 col-md-12" >
{ p . user . cool }
< / d i v >
< / d i v >
< / d i v >
< div className = "col-md-2 border" >
< div className = "row" >
< div className = "col-6 col-md-12" >
< img src = { RATING _fine . src } height = "16" / >
< / d i v >
< div className = "col-6 col-md-12" >
{ p . user . fine }
< / d i v >
< / d i v >
< / d i v >
< div className = "col-md-2 border" >
< div className = "row" >
< div className = "col-6 col-md-12" >
< img src = { RATING _safe . src } height = "16" / >
< / d i v >
< div className = "col-6 col-md-12" >
{ p . user . safe }
< / d i v >
< / d i v >
< / d i v >
< div className = "col-md-2 border" >
< div className = "row" >
< div className = "col-6 col-md-12" >
< img src = { RATING _sad . src } height = "16" / >
< / d i v >
< div className = "col-6 col-md-12" >
{ p . user . sad }
< / d i v >
< / d i v >
< / d i v >
< div className = "col-md-2 border" >
< div className = "row" >
< div className = "col-6 col-md-12" >
< img src = { RATING _worst . src } height = "16" / >
< / d i v >
< div className = "col-6 col-md-12" >
{ p . user . worst }
< / d i v >
< / d i v >
< / d i v >
< div className = "col-md-1" >
< / d i v >
< / d i v >
< / >
)
}
function SongName ( p ) {
//console.log(p.song)
return (
< >
{ ( p . song ) ? ( p . song . english _name === p . song . name ) ?
< > { p . song . name } < / >
:
< > { p . song . name } < br / > { ( p . song . romanized _name . length > 0 ) ? p . song . romanized _name : p . song . english _name } < / >
: < > < / >
}
< / >
)
}
function CalculateBadge ( difficulty ) {
switch ( difficulty ) {
case "E" : {
return "primary" ;
} break ;
case "N" : {
return "info" ;
} break ;
case "H" : {
return "success" ;
} break ;
case "EX" : {
return "warning" ;
} break ;
case "EXEX" : {
return "danger" ;
} break ;
}
}
function FormatRating ( rating ) {
if ( rating ) {
if ( rating . includes ( ".5" ) ) {
return rating ;
} else {
return Math . floor ( rating )
}
}
}
function Difficulty ( p ) {
return (
< >
< span className = { "badge badge-" + CalculateBadge ( p . play . difficulty ) } > { ( p . song && p . song . rating && p . song . rating [ p . play . difficulty ] ) ? FormatRating ( p . song . rating [ p . play . difficulty ] ) : < > < / > } { p . p l a y . d i f f i c u l t y } < / s p a n >
< / >
) ;
}
function ImageDisplayer ( p ) {
var [ zoom , setZoom ] = useState ( false )
//p.play
return (
< Modal
size = "xl"
aria - labelledby = "contained-modal-title-vcenter"
centered
scrollable
show = { p . modalVisible }
onHide = { ( ) => { p . setModalVisible ( false ) } }
>
{ ( p . play !== undefined && p . songs [ p . play . songid ] ) ? < > < Modal . Header closeButton >
< Modal . Title id = "contained-modal-title-vcenter" >
{ ` ${ p . username } 's ${ p . songs [ p . play . songid ] . name } Play - [ ${ p . play . difficulty } ] ${ p . play . percent } % ` }
< / M o d a l . T i t l e >
< / M o d a l . H e a d e r >
< Modal . Body >
< img src = { p . play . src } width = { ( zoom ) ? "auto" : "100%" } className = { ( zoom ) ? "zoomout" : "zoomin" } onClick = { ( ) => { setZoom ( ! zoom ) } } / >
< /Modal.Body></ > : < > < / > }
< / M o d a l >
)
}
function Play ( p ) {
function GetModifiedDiff ( name ) {
switch ( name ) {
case "E" : {
return "easy" ;
}
case "N" : {
return "normal" ;
}
case "H" : {
return "hard" ;
}
case "EX" : {
return "ex" ;
}
case "EXEX" : {
return "exex" ;
}
}
}
function GetDateDiff ( ) {
var hours = Math . floor ( ( Date . now ( ) - new Date ( p . play . date ) ) / 1000 / 60 / 60 ) ;
var days = Math . floor ( hours / 24 )
if ( hours < 24 ) { return < > { hours } { "hour" + ( ( hours !== 1 ) ? "s" : "" ) } ago < / > }
return < > { days } { "day" + ( ( days !== 1 ) ? "s" : "" ) } ago < / >
}
function GetDateDisplay ( timeStampBelow ) {
var date = new Date ( p . play . date ) ;
var months = [ "Jan" , "Feb" , "Mar" , "Apr" , "May" , "Jun" , "Jul" , "Aug" , "Sep" , "Oct" , "Nov" , "Dec" ]
return < > { months [ date . getMonth ( ) ] + " " + date . getDate ( ) + " " + date . getFullYear ( ) + " " + date . getHours ( ) + ":" + ( ( date . getMinutes ( ) < 10 ) ? "0" + date . getMinutes ( ) : date . getMinutes ( ) ) } < span className = { "tinytime infront " + ( ( timeStampBelow ) ? "moveDown" : "" ) } > { GetDateDiff ( ) } < /span></ >
}
if ( p . mini ) {
return (
< >
< div className = { "d-none d-md-block below border border-bottom " + ( ( p . play . src ) ? "background-songs-click" : "" ) } onClick = { ( p . play . src ) ? ( ) => { p . setModalSrc ( p . play )
p . setModalVisible ( true ) } : null } >
< div className = { ( ( p . play . fine == 0 && p . play . safe == 0 && p . play . sad == 0 && p . play . worst == 0 ) ? "pfchighlight" : ( p . play . safe == 0 && p . play . sad == 0 && p . play . worst == 0 ) ? "fchighlight" : "" ) } >
< div className = { "row align-middle" } >
< div className = "col-md-2 order-1 order-md-1 text-center border-right align-middle text-nowrap overflow-hidden" > { ( p . title && p . song ) ? < > { p . song . name } < br / > < />:<></ > } { ( ( p . play . fine == 0 && p . play . safe == 0 && p . play . sad == 0 && p . play . worst == 0 ) ? < span className = "badge pfc" > ✪ PFC < / s p a n > : ( p . p l a y . s a f e = = 0 & & p . p l a y . s a d = = 0 & & p . p l a y . w o r s t = = 0 ) ? < s p a n c l a s s N a m e = " b a d g e f c " > ★ F C < / s p a n > : < > < / > ) } < D i f f i c u l t y p l a y = { p . p l a y } s o n g = { p . s o n g } / > { M a t h . f l o o r ( p . p l a y . s c o r e ) } p t s < / d i v >
< div className = "col-md-3 order-3 order-md-2 text-center border-right align-middle text-nowrap overflow-hidden" > { GetDateDisplay ( ) } < / d i v >
< div className = "col-md-7 order-2 order-md-3" >
< div className = "row" >
< div className = "col-12 order-1 order-md-1 col-md-5 text-center" >
{ p . play . cool + "/" + p . play . fine + "/" + p . play . safe + "/" + p . play . sad + "/" + p . play . worst }
< / d i v >
< div className = "col-6 order-3 order-md-2 col-md-2 text-left text-md-left" >
{ ( p . play . mod !== null && p . play . mod . length > 0 ) ?
< ModDisplay side = { true } badge = { CalculateBadge ( p . play . difficulty ) } diff = { GetModifiedDiff ( p . play . difficulty ) }
hs = { p . play . mod == "HS" ? 1 : 0 } hd = { p . play . mod == "HD" ? 1 : 0 } sd = { p . play . mod == "SD" ? 1 : 0 } / >
: < > < / >
}
< / d i v >
< div className = "col-6 order-2 order-md-3 col-md-3 text-right text-md-left" >
< b > { p . play . percent } % < / b >
< / d i v >
< div className = "col-6 order-2 order-md-3 col-md-2 text-right text-md-left" >
{ ( p . play . src ) ? < IMAGE _CAMERA / > : < > < / > }
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< div className = { "d-block d-small d-md-none " + ( ( p . play . src ) ? "background-songs-click" : "" ) } onClick = { ( p . play . src ) ? ( ) => { p . setModalSrc ( p . play )
p . setModalVisible ( true ) } : null } >
< div className = { ( ( p . play . fine == 0 && p . play . safe == 0 && p . play . sad == 0 && p . play . worst == 0 ) ? "pfchighlight" : ( p . play . safe == 0 && p . play . sad == 0 && p . play . worst == 0 ) ? "fchighlight" : "" ) } > { ( p . title && p . song ) ? < > { p . song . name } < br / > < />:<></ > }
{ < div className = "row" > < div className = "offset-4 col-4 text-center" > { ( ( p . play . fine == 0 && p . play . safe == 0 && p . play . sad == 0 && p . play . worst == 0 ) ? < span className = "badge pfc" > ✪ PFC < / s p a n > : ( p . p l a y . s a f e = = 0 & & p . p l a y . s a d = = 0 & & p . p l a y . w o r s t = = 0 ) ? < s p a n c l a s s N a m e = " b a d g e f c " > ★ F C < / s p a n > : < > < / > ) } < D i f f i c u l t y p l a y = { p . p l a y } s o n g = { p . s o n g } / > < / d i v > < / d i v > }
< div className = "row" >
< div className = "offset-2 col-4 text-center" >
{ Math . floor ( p . play . score ) } pts
< br / >
{ p . play . cool + "/" + p . play . fine + "/" + p . play . safe + "/" + p . play . sad + "/" + p . play . worst }
< / d i v >
< div className = "col-4 text-center" >
< b > { p . play . percent } % < / b > { ( p . p l a y . m o d ! = = n u l l & & p . p l a y . m o d . l e n g t h > 0 ) ? < M o d D i s p l a y s i d e = { t r u e } b a d g e = { C a l c u l a t e B a d g e ( p . p l a y . d i f f i c u l t y ) } d i f f = { G e t M o d i f i e d D i f f ( p . p l a y . d i f f i c u l t y ) }
hs = { p . play . mod == "HS" ? 1 : 0 } hd = { p . play . mod == "HD" ? 1 : 0 } sd = { p . play . mod == "SD" ? 1 : 0 } / > : < > < / > }
< span className = "pl-2" / >
{ ( p . play . src ) ? < IMAGE _CAMERA / > : < > < / > }
< br / >
{ GetDateDisplay ( true ) }
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / >
) ;
} else {
return (
< >
< div className = { "row align-middle " + ( ( p . play . fine == 0 && p . play . safe == 0 && p . play . sad == 0 && p . play . worst == 0 ) ? "pfchighlight" : ( p . play . safe == 0 && p . play . sad == 0 && p . play . worst == 0 ) ? "fchighlight" : "" ) + ( ( p . play . src ) ? " background-songs-click" : "" ) } onClick = { ( p . play . src ) ? ( ) => { p . setModalSrc ( p . play )
p . setModalVisible ( true ) } : null } >
{ ( p . index !== undefined ) ? < div className = " col-md-1 text-center border-right align-middle text-nowrap overflow-hidden" > < span className = "d-none d-md-block" > { p . index + 1 } < / s p a n > { ( ( p . p l a y . f i n e = = 0 & & p . p l a y . s a f e = = 0 & & p . p l a y . s a d = = 0 & & p . p l a y . w o r s t = = 0 ) ? < s p a n c l a s s N a m e = " b a d g e p f c " > ✪ P F C < / s p a n > : ( p . p l a y . s a f e = = 0 & & p . p l a y . s a d = = 0 & & p . p l a y . w o r s t = = 0 ) ? < s p a n c l a s s N a m e = " b a d g e f c " > ★ F C < / s p a n > : < > < / > ) } < / d i v > : < > < / > }
< div className = "col-md-3 text-center border-right align-middle text-nowrap overflow-hidden" > < SongName song = { p . song } / > < span className = "tinytime" > { GetDateDiff ( ) } < / s p a n > < / d i v >
< div className = "col-md-2 text-center border-right align-middle text-nowrap overflow-hidden" > { Math . floor ( p . play . score ) } pts < br / > < Difficulty play = { p . play } song = { p . song } / > < / d i v >
< div className = "col-md-6" >
< div className = "row" >
< div className = "order-1 order-md-1 col-md-4 numbers text-center" >
< div className = "row justify-content-center" >
< div className = "col-4 col-md-5" >
< img src = { RATING _cool . src } className = "pr-2" height = "16" / >
< / d i v >
< div className = "col-4 col-md-7" >
{ p . play . cool }
< / d i v >
< / d i v >
< / d i v >
< div className = "order-3 order-md-2 col-md-4 numbers text-center" >
< div className = "row justify-content-center" >
< div className = "col-4 col-md-5" >
< img src = { RATING _safe . src } className = "pr-2" height = "16" / >
< / d i v >
< div className = "col-4 col-md-7" >
{ p . play . safe }
< / d i v >
< / d i v > < / d i v >
< div className = "order-5 order-md-3 col-md-4 numbers text-center" >
< div className = "row justify-content-center" >
< div className = "col-4 col-md-5" >
< img src = { RATING _worst . src } className = "pr-2" height = "16" / >
< / d i v >
< div className = "col-4 col-md-7" >
{ p . play . worst }
< / d i v >
< / d i v > < / d i v >
< div className = "order-2 order-md-4 order-sm-2 col-md-4 numbers text-center" >
< div className = "row justify-content-center" >
< div className = "col-4 col-md-5" >
< img src = { RATING _fine . src } className = "pr-2" height = "16" / >
< / d i v >
< div className = "col-4 col-md-7" >
{ p . play . fine }
< / d i v >
< / d i v > < / d i v >
< div className = "order-4 order-md-5 col-md-4 numbers text-center" >
< div className = "row justify-content-center" >
< div className = "col-4 col-md-5" >
< img src = { RATING _sad . src } className = "pr-2" height = "16" / >
< / d i v >
< div className = "col-4 col-md-7" >
{ p . play . sad }
< / d i v >
< / d i v > < / d i v >
< div className = "order-6 order-md-6 col-md-4 numbers text-center" > < b > { p . play . percent } % { ( p . play . src ) ? < span className = "pl-4" > < IMAGE _CAMERA onClick = { ( ) => { p . setModalSrc ( p . play )
p . setModalVisible ( true ) } } / > < /span>:<></ > } < / b > < / d i v >
< / d i v >
< / d i v >
< / d i v >
< / >
) ;
}
}
function LoadMore ( p ) {
var [ offset , setOffset ] = useState ( p . params . limit )
var [ params , setParams ] = useState ( p . params )
var [ loading , setLoading ] = useState ( false )
var [ visible , setVisible ] = useState ( false )
var [ update , setUpdate ] = useState ( false )
var [ reloadLoadMore , setReloadLoadMore ] = useState ( false )
const firstUpdate = useRef ( true ) ;
useEffect ( ( ) => {
axios . get ( p . url + constructParams ( params ) )
. then ( ( data ) => {
if ( data . data . length > 0 ) {
setVisible ( true )
}
} )
} , [ update , p . username , p . profileUpdate , reloadLoadMore ] )
useEffect ( ( ) => {
if ( firstUpdate . current ) {
firstUpdate . current = false ;
return ;
}
var obj = params
obj . offset = p . params . offset
setParams ( obj )
setReloadLoadMore ( ! reloadLoadMore )
} , [ p . profileUpdate , p . username ] )
function constructParams ( params ) {
var st = Object . keys ( params ) . reduce ( ( str , key ) => {
if ( str === "" ) {
return str += "?" + key + "=" + params [ key ]
} else {
return str += "&" + key + "=" + params [ key ]
}
} , "" )
return st
}
if ( ! visible ) {
return ( < > < / > )
}
else
if ( p . listItem ) {
return (
< li className = "list-group-item list-group-item-action homelink" onClick = { ( ) => {
setLoading ( true )
axios . get ( p . url + constructParams ( params ) )
. then ( ( data ) => {
if ( data . data . length > 0 ) {
var newVals = [ ... p . value ]
data . data . forEach ( ( val ) => {
newVals . push ( val )
} )
p . setValue ( newVals )
//console.log(newVals)
var obj = { ... params }
obj . offset += offset
setParams ( obj )
setLoading ( false )
if ( data . data . length < p . params . limit ) {
setVisible ( false )
}
} else {
setVisible ( false )
setLoading ( false )
}
} )
}
} >
< div className = "row text-center" >
< div className = "col-12" >
{ ( ! loading ) ? < h6 className = "link" > < i > - Load More - < / i > < / h 6 > : < d i v c l a s s N a m e = " s p i n n e r - g r o w t e x t - p r i m a r y " r o l e = " s t a t u s " > < s p a n c l a s s N a m e = " s r - o n l y " > L o a d i n g . . . < / s p a n > < / d i v >
}
< / d i v >
< / d i v >
< / l i >
)
} else
return (
< div className = "row text-center homelink" onClick = { ( ) => {
setLoading ( true )
axios . get ( p . url + constructParams ( params ) )
. then ( ( data ) => {
if ( ! data . data ) {
setVisible ( false )
} else
if ( data . data . length > 0 ) {
var newVals = [ ... p . value ]
data . data . forEach ( ( val ) => {
newVals . push ( val )
} )
p . setValue ( newVals )
//console.log(newVals)
var obj = { ... params }
obj . offset += offset
setParams ( obj )
setLoading ( false )
if ( data . data . length < p . params . limit ) {
setVisible ( false )
}
} else {
setVisible ( false )
setLoading ( false )
}
} )
}
} >
< div className = "col-12" >
{ ( ! loading ) ? < h6 className = "link" > < i > - Load More - < / i > < / h 6 > : < d i v c l a s s N a m e = " s p i n n e r - g r o w t e x t - p r i m a r y " r o l e = " s t a t u s " > < s p a n c l a s s N a m e = " s r - o n l y " > L o a d i n g . . . < / s p a n > < / d i v >
}
< / d i v >
< / d i v >
)
}
function BestPlaysPanel ( p ) {
var [ bestPlays , setBestPlays ] = useState ( [ ] )
var [ update , setUpdate ] = useState ( false )
useEffect ( ( ) => {
axios . get ( "http://www.projectdivar.com/bestplays/" + p . username + "?fails=false&limit=5&offset=0" )
. then ( ( data ) => { setBestPlays ( data . data ) ; } )
} , [ p . profileUpdate , update , p . username ] )
var content = < div className = "col-md-12 mt-3 mb-3" >
< ul className = "list-group list-group-flush border border-danger rounded-lg" >
{ bestPlays . map ( ( play , i ) => { return < li key = { i } className = { "list-group-item list-group-item-action " + ( i % 2 == 0 ? "background-list-1" : "background-list-2" ) } >
< Play setModalSrc = { p . setModalSrc } setModalVisible = { p . setModalVisible } index = { i } play = { play } song = { p . songs [ play . songid ] } / >
< / l i > } ) }
< LoadMore username = { p . username } profileUpdate = { p . profileUpdate } listItem = { true } url = { "http://www.projectdivar.com/bestplays/" + p . username } params = { { fails : false , limit : 15 , offset : 5 } } value = { bestPlays } setValue = { setBestPlays } / >
< / u l >
< / d i v >
return (
< >
< div className = "row ml-3 mr-3" >
{ content }
< / d i v >
< / >
) ;
}
function ModDisplay ( p ) {
const [ tooltip , setTooltip ] = useState ( "" )
const [ visibility , setVisibility ] = useState ( false )
return (
< span className = { "border border-" + p . badge + " rounded " + p . diff + "-background" } style = { { fontSize : "18px" } } >
{ ( p . hs > 0 ) ? < span style = { { color : "#b33" } } onMouseOver = { ( ) => { setTooltip ( "High Speed - " + p . diff . toUpperCase ( ) ) ; setVisibility ( true ) } } onMouseOut = { ( ) => { setVisibility ( false ) } } > ⬣ < /span>:<></ > }
{ ( p . hd > 0 ) ? < span onMouseOver = { ( ) => { setTooltip ( "Hidden - " + p . diff . toUpperCase ( ) ) ; setVisibility ( true ) } } onMouseOut = { ( ) => { setVisibility ( false ) } } style = { { color : "#968a0e" } } > ⬣ < /span>:<></ > }
{ ( p . sd > 0 ) ? < span onMouseOver = { ( ) => { setTooltip ( "Sudden - " + p . diff . toUpperCase ( ) ) ; setVisibility ( true ) } } onMouseOut = { ( ) => { setVisibility ( false ) } } style = { { color : "#49b" } } > ⬣ < /span>:<></ > }
{ ( visibility ) ? < span style = { { position : "absolute" } } className = { ( ( p . side ) ? "display-tooltipside" : "display-tooltip" ) + " alert alert-dark " + p . diff + "-background" } > { tooltip } < /span>:<></ > }
< / s p a n >
)
}
function PlayDetail ( p ) {
const [ tooltip , setTooltip ] = useState ( "" )
const [ visibility , setVisibility ] = useState ( false )
const [ style , setStyle ] = useState ( "" )
return (
< >
< td >
{ ( p . song . report . rank > 0 ) ? p . song . report . rank : < i > Not Played < / i > }
< / t d >
< td >
{ ( p . song . report . rank > 0 ) ? < > { p . song . report . score } < / > : " " }
< / t d >
< td >
{ ( p . song . report . rank > 0 ) ? < > { p . song . report . percent } % < / > : " " }
< / t d >
< td >
{ p . song . report . ecount > 0 ? < span className = "badge badge-primary" onMouseOver = { ( ) => { setTooltip ( < > { p . song . report . eclearcount + " / " + p . song . report . ecount + " (" + ( Math . floor ( ( p . song . report . eclearcount / p . song . report . ecount ) * 100 ) ) + "% pass rate)" } { ( p . song . report . efccount > 0 ) ? < > < br / > { "★FC'd " + p . song . report . efccount + " time" + ( p . song . report . efccount != 1 ? "s" : "" ) } < />:<></ > } { ( p . song . report . epfccount > 0 ) ? < > < br / > { "✪Perfected " + p . song . report . epfccount + " time" + ( p . song . report . epfccount != 1 ? "s" : "" ) } < />:<></ > } < / > ) ; s e t S t y l e ( " e a s y " ) ; s e t V i s i b i l i t y ( t r u e ) } } o n M o u s e O u t = { ( ) = > { s e t V i s i b i l i t y ( f a l s e ) } } > { p . s o n g . r e p o r t . e p f c c o u n t > 0 ? " ✪ " : p . s o n g . r e p o r t . e f c c o u n t > 0 ? " ★ " : " " } { p . s o n g . r e p o r t . e c o u n t } < / s p a n > : < > < / > }
{ p . song . report . ncount > 0 ? < span className = "badge badge-info" onMouseOver = { ( ) => { setTooltip ( < > { p . song . report . nclearcount + " / " + p . song . report . ncount + " (" + ( Math . floor ( ( p . song . report . nclearcount / p . song . report . ncount ) * 100 ) ) + "% pass rate)" } { ( p . song . report . nfccount > 0 ) ? < > < br / > { "★FC'd " + p . song . report . nfccount + " time" + ( p . song . report . nfccount != 1 ? "s" : "" ) } < />:<></ > } { ( p . song . report . npfccount > 0 ) ? < > < br / > { "✪Perfected " + p . song . report . npfccount + " time" + ( p . song . report . npfccount != 1 ? "s" : "" ) } < />:<></ > } < / > ) ; s e t S t y l e ( " n o r m a l " ) ; s e t V i s i b i l i t y ( t r u e ) } } o n M o u s e O u t = { ( ) = > { s e t V i s i b i l i t y ( f a l s e ) } } > { p . s o n g . r e p o r t . n p f c c o u n t > 0 ? " ✪ " : p . s o n g . r e p o r t . n f c c o u n t > 0 ? " ★ " : " " } { p . s o n g . r e p o r t . n c o u n t } < / s p a n > : < > < / > }
{ p . song . report . hcount > 0 ? < span className = "badge badge-success" onMouseOver = { ( ) => { setTooltip ( < > { p . song . report . hclearcount + " / " + p . song . report . hcount + " (" + ( Math . floor ( ( p . song . report . hclearcount / p . song . report . hcount ) * 100 ) ) + "% pass rate)" } { ( p . song . report . hfccount > 0 ) ? < > < br / > { "★FC'd " + p . song . report . hfccount + " time" + ( p . song . report . hfccount != 1 ? "s" : "" ) } < />:<></ > } { ( p . song . report . hpfccount > 0 ) ? < > < br / > { "✪Perfected " + p . song . report . hpfccount + " time" + ( p . song . report . hpfccount != 1 ? "s" : "" ) } < />:<></ > } < / > ) ; s e t S t y l e ( " h a r d " ) ; s e t V i s i b i l i t y ( t r u e ) } } o n M o u s e O u t = { ( ) = > { s e t V i s i b i l i t y ( f a l s e ) } } > { p . s o n g . r e p o r t . h p f c c o u n t > 0 ? " ✪ " : p . s o n g . r e p o r t . h f c c o u n t > 0 ? " ★ " : " " } { p . s o n g . r e p o r t . h c o u n t } < / s p a n > : < > < / > }
{ p . song . report . excount > 0 ? < span className = "badge badge-warning" onMouseOver = { ( ) => { setTooltip ( < > { p . song . report . exclearcount + " / " + p . song . report . excount + " (" + ( Math . floor ( ( p . song . report . exclearcount / p . song . report . excount ) * 100 ) ) + "% pass rate)" } { ( p . song . report . exfccount > 0 ) ? < > < br / > { "★FC'd " + p . song . report . exfccount + " time" + ( p . song . report . exfccount != 1 ? "s" : "" ) } < />:<></ > } { ( p . song . report . expfccount > 0 ) ? < > < br / > { "✪Perfected " + p . song . report . expfccount + " time" + ( p . song . report . expfccount != 1 ? "s" : "" ) } < />:<></ > } < / > ) ; s e t S t y l e ( " e x " ) ; s e t V i s i b i l i t y ( t r u e ) } } o n M o u s e O u t = { ( ) = > { s e t V i s i b i l i t y ( f a l s e ) } } > { p . s o n g . r e p o r t . e x p f c c o u n t > 0 ? " ✪ " : p . s o n g . r e p o r t . e x f c c o u n t > 0 ? " ★ " : " " } { p . s o n g . r e p o r t . e x c o u n t } < / s p a n > : < > < / > }
{ p . song . report . exexcount > 0 ? < span className = "badge badge-danger" onMouseOver = { ( ) => { setTooltip ( < > { p . song . report . exexclearcount + " / " + p . song . report . exexcount + " (" + ( Math . floor ( ( p . song . report . exexclearcount / p . song . report . exexcount ) * 100 ) ) + "% pass rate)" } { ( p . song . report . exexfccount > 0 ) ? < > < br / > { "★FC'd " + p . song . report . exexfccount + " time" + ( p . song . report . exexfccount != 1 ? "s" : "" ) } < />:<></ > } { ( p . song . report . exexpfccount > 0 ) ? < > < br / > { "✪Perfected " + p . song . report . exexpfccount + " time" + ( p . song . report . exexpfccount != 1 ? "s" : "" ) } < />:<></ > } < / > ) ; s e t S t y l e ( " e x e x " ) ; s e t V i s i b i l i t y ( t r u e ) } } o n M o u s e O u t = { ( ) = > { s e t V i s i b i l i t y ( f a l s e ) } } > { p . s o n g . r e p o r t . e x e x p f c c o u n t > 0 ? " ✪ " : p . s o n g . r e p o r t . e x e x f c c o u n t > 0 ? " ★ " : " " } { p . s o n g . r e p o r t . e x e x c o u n t } < / s p a n > : < > < / > }
{ ( visibility ) ? < span style = { { position : "absolute" } } className = { "display-tooltip alert alert-dark " + style + "-background" } > { tooltip } < /span>:<></ > }
< / t d >
< td >
{ ( p . song . report . ehscount > 0 || p . song . report . ehdcount > 0 || p . song . report . esdcount > 0 ) ?
< ModDisplay badge = "primary" diff = "easy"
hs = { p . song . report . ehscount } hd = { p . song . report . ehdcount } sd = { p . song . report . esdcount } / >
: < > < / >
}
{ ( p . song . report . nhscount > 0 || p . song . report . nhdcount > 0 || p . song . report . nsdcount > 0 ) ?
< ModDisplay badge = "info" diff = "normal"
hs = { p . song . report . nhscount } hd = { p . song . report . nhdcount } sd = { p . song . report . nsdcount } / >
: < > < / >
}
{ ( p . song . report . hhscount > 0 || p . song . report . hhdcount > 0 || p . song . report . hsdcount > 0 ) ?
< ModDisplay badge = "success" diff = "hard"
hs = { p . song . report . hhscount } hd = { p . song . report . hhdcount } sd = { p . song . report . hsdcount } / >
: < > < / >
}
{ ( p . song . report . exhscount > 0 || p . song . report . exhdcount > 0 || p . song . report . exsdcount > 0 ) ?
< ModDisplay badge = "warning" diff = "ex"
hs = { p . song . report . exhscount } hd = { p . song . report . exhdcount } sd = { p . song . report . exsdcount } / >
: < > < / >
}
{ ( p . song . report . exexhscount > 0 || p . song . report . exexhdcount > 0 || p . song . report . exexsdcount > 0 ) ?
< ModDisplay badge = "danger" diff = "exex"
hs = { p . song . report . exexhscount } hd = { p . song . report . exexhdcount } sd = { p . song . report . exexsdcount } / >
: < > < / >
}
< / t d >
< / >
) ;
}
function PlayData ( p ) {
var [ data , setData ] = useState ( [ ] )
var [ update , setUpdate ] = useState ( false )
useEffect ( ( ) => {
axios . get ( "http://projectdivar.com/plays/" + p . username + "/" + p . song . id )
. then ( ( data ) => { setData ( data . data ) ; } )
} , [ p . profileUpdate , p . username , update ] )
return (
< >
< div className = "text-center background-songs below" >
< h5 > Individual Plays for { p . song . name } from { p . username } < / h 5 >
< div className = "border rounded" >
{ data . map ( ( play , i ) => < Play setModalSrc = { p . setModalSrc } setModalVisible = { p . setModalVisible } key = { i } play = { play } mini = { true } song = { p . song } / > ) }
< LoadMore profileUpdate = { p . profileUpdate } username = { p . username } url = { "http://www.projectdivar.com/plays/" + p . username + "/" + p . song . id } params = { { limit : 15 , offset : 5 } } value = { data } setValue = { setData } / >
< / d i v >
< / d i v >
< / >
)
}
var cumulativeOffset = function ( element ) {
var top = 0 , left = 0 ;
do {
top += element . offsetTop || 0 ;
left += element . offsetLeft || 0 ;
element = element . offsetParent ;
} while ( element ) ;
return {
top : top ,
left : left
} ;
} ;
function HoverSongName ( p ) {
let match = useRouteMatch ( {
path : "/user/" + p . username + "/" + p . to ,
exact : true
} ) ;
var [ name , setName ] = useState ( p . song . name )
var [ expand , setExpand ] = useState ( < > < / > )
var [ toggle , setToggle ] = useState ( match )
let history = useHistory ( ) ;
useEffect ( ( ) => {
if ( ( p . song . report . ecount + p . song . report . ncount + p . song . report . hcount + p . song . report . excount + p . song . report . exexcount > 0 ) ) {
if ( toggle ) {
setExpand ( < tr className = "fadein" >
< td colSpan = "6" > < PlayData profileUpdate = { p . profileUpdate } setModalSrc = { p . setModalSrc } setModalVisible = { p . setModalVisible } song = { p . song } username = { p . username } / > < / t d >
< / t r > )
if ( match !== null ) {
window . scroll ( 0 , cumulativeOffset ( document . getElementById ( "songRow_" + p . song . name ) ) . top - document . getElementById ( "songRow_" + p . song . name ) . getBoundingClientRect ( ) . height ) ;
}
} else {
setExpand ( < > < / > )
}
}
} , [ p . profileUpdate , p . username , toggle ] )
return (
< >
< tr id = { "songRow_" + p . song . name } key = { p . song . id } className = "lighthover cursor" onClick = { ( e ) => {
if ( ( p . song . report . ecount + p . song . report . ncount + p . song . report . hcount + p . song . report . excount + p . song . report . exexcount > 0 ) ) {
if ( ! toggle ) {
setToggle ( true )
history . push ( "/user/" + p . username + "/" + p . to )
} else {
setToggle ( false )
}
}
//console.log(e.target.getBoundingClientRect()+"/"+window.pageYOffset)
}
} >
< td className = "overflow-hidden" >
{ ( p . song . report . ecount + p . song . report . ncount + p . song . report . hcount + p . song . report . excount + p . song . report . exexcount > 0 ) ? ( ( toggle ) ? < > ⯆ < />:<>⯈</ > ) : < > < />} {name} <span className="tinytext">{(p.song.romanized_name.length>0)?<>{(p.song.romanized_name!==p.song.name)?<>{p.song.romanized_name}</ > : < > < />}</ > : < > { ( p . song . english _name !== p . song . name ) ? < > { p . song . english _name } < />:<></ > } < / > } < / s p a n >
< / t d >
< PlayDetail song = { p . song } / >
< / t r >
{ expand }
< / >
)
}
function HasSong ( song , user , filter ) {
//console.log(JSON.stringify(song)+"/"+JSON.stringify(user)+"/"+JSON.stringify(filter))
//console.log(song.report.ehdcount+song.report.nhdcount+song.report.hhdcount+song.report.exhdcount+song.report.exexhdcount+song.report.ehscount+song.report.nhscount+song.report.hhscount+song.report.exhscount+song.report.exexhscount+song.report.esdcount+song.report.nsdcount+song.report.hsdcount+song.report.exsdcount+song.report.exexsdcount)
return ( ( song . mega39s && user . megamix ) ||
( song . futuretone && user . futuretone ) )
&& ( filter === "All Songs" ||
( filter === "Cleared Songs" && ( Number ( song . report . eclearcount ) + Number ( song . report . nclearcount ) + Number ( song . report . hclearcount ) + Number ( song . report . exclearcount ) + Number ( song . report . exexclearcount > 0 ) ) ) ||
( filter === "FCs" && ( Number ( song . report . efccount ) + Number ( song . report . nfccount ) + Number ( song . report . hfccount ) + Number ( song . report . exfccount ) + Number ( song . report . exexfccount > 0 ) ) ) ||
( filter === "Perfect FCs" && ( Number ( song . report . epfccount ) + Number ( song . report . npfccount ) + Number ( song . report . hpfccount ) + Number ( song . report . expfccount ) + Number ( song . report . exexpfccount > 0 ) ) ) ||
( filter === "Modded" && ( Number ( song . report . ehdcount ) + Number ( song . report . nhdcount ) + Number ( song . report . hhdcount ) + Number ( song . report . exhdcount ) + Number ( song . report . exexhdcount ) + Number ( song . report . ehscount ) + Number ( song . report . nhscount ) + Number ( song . report . hhscount ) + Number ( song . report . exhscount ) + Number ( song . report . exexhscount ) + Number ( song . report . esdcount ) + Number ( song . report . nsdcount ) + Number ( song . report . hsdcount ) + Number ( song . report . exsdcount ) + Number ( song . report . exexsdcount > 0 ) ) ) ||
( filter === "In Progress" && ( Number ( song . report . eclearcount ) + Number ( song . report . nclearcount ) + Number ( song . report . hclearcount ) + Number ( song . report . exclearcount ) + Number ( song . report . exexclearcount ) === 0 ) ) ||
( filter === "Not Cleared" && ( ( ( song . report . eclearcount ) ? Number ( song . report . eclearcount ) : 0 ) + ( ( song . report . nclearcount ) ? Number ( song . report . nclearcount ) : 0 ) + ( ( song . report . hclearcount ) ? Number ( song . report . hclearcount ) : 0 ) + ( ( song . report . exclearcount ) ? Number ( song . report . exclearcount ) : 0 ) + ( ( song . report . exexclearcount ) ? Number ( song . report . exexclearcount ) : 0 ) === 0 ) )
)
}
function CompletionPanel ( p ) {
const [ report , setReport ] = useState ( [ ] )
const [ song , setSong ] = useState ( "" )
const [ filter , setFilter ] = useState ( { } )
const [ style , setStyle ] = useState ( true )
const [ update , setUpdate ] = useState ( false )
const [ songFilter , setSongFilter ] = useState ( "All Songs" )
useEffect ( ( ) => {
axios . get ( "http://projectdivar.com/completionreport/" + p . username )
. then ( ( data ) => { setReport ( data . data ) } )
. catch ( ( err ) => { console . log ( err . message ) } )
} , [ update , p . username ] )
useEffect ( ( ) => {
if ( firstUpdate . current ) {
firstUpdate . current = false ;
return ;
}
setUpdate ( ! update )
} , [ p . profileUpdate ] )
const firstUpdate = useRef ( true ) ;
return (
< >
< SongSearch songs = { p . songs } song = { song } setSong = { setSong } setStyle = { setStyle } filteredSongs = { filter } setFilteredSongs = { setFilter } / >
< div className = "mt-3 float-right" >
< Form inline >
< Form . Group controlId = "filterSong" >
< Form . Label className = "pr-3" > Filter < / F o r m . L a b e l >
< Form . Control as = "select" value = { songFilter } onChange = { ( e ) => { setSongFilter ( e . currentTarget . value ) } } >
< option > All Songs < / o p t i o n >
< option > Cleared Songs < / o p t i o n >
< option > In Progress < / o p t i o n >
< option > FCs < / o p t i o n >
< option > Perfect FCs < / o p t i o n >
< option > Modded < / o p t i o n >
< option > Not Cleared < / o p t i o n >
< / F o r m . C o n t r o l >
< / F o r m . G r o u p >
< / F o r m >
< / d i v >
< table className = "table table-sm" >
< thead >
< tr id = "headerbar" >
< th scope = "col" className = { ( style ) ? "scrollingHeader" : "" } >
Song Name
< / t h >
< th className = { ( style ) ? "scrollingHeader" : "" } >
Ranking
< / t h >
< th className = { ( style ) ? "scrollingHeader" : "" } >
Score
< / t h >
< th className = { ( style ) ? "scrollingHeader" : "" } >
%
< / t h >
< th className = { ( style ) ? "scrollingHeader" : "" } >
Play Count
< / t h >
< th className = { ( style ) ? "scrollingHeader" : "" } >
Mods
< / t h >
< / t r >
< / t h e a d >
< tbody >
{ report . filter ( ( report ) => Object . keys ( filter ) . length == 0 || report . id in filter ) . map ( ( song , i ) => { return ( HasSong ( song , p . user , songFilter ) ) ? < HoverSongName profileUpdate = { p . profileUpdate } setModalSrc = { p . setModalSrc } setModalVisible = { p . setModalVisible } to = { song . name } song = { song } key = { song . id } username = { p . username } / > : < > < / >
} ) }
< / t b o d y >
< tfoot >
< tr > < td colSpan = "8" id = "footer" className = { ( style ) ? "scrollingFooter" : "" } >
< span className = "badge badge-primary" > Easy < / s p a n > < s p a n c l a s s N a m e = " b a d g e b a d g e - i n f o " > N o r m a l < / s p a n > < s p a n c l a s s N a m e = " b a d g e b a d g e - s u c c e s s " > H a r d < / s p a n > < s p a n c l a s s N a m e = " b a d g e b a d g e - w a r n i n g " > E x t r e m e < / s p a n > < s p a n c l a s s N a m e = " b a d g e b a d g e - d a n g e r " > E X E x t r e m e < / s p a n > < s p a n c l a s s N a m e = " b a d g e b a d g e - l i g h t " > ★ = F C < / s p a n > < s p a n c l a s s N a m e = " b a d g e b a d g e - l i g h t " > ✪ = P e r f e c t F C s < / s p a n >
< / t d > < / t r >
< / t f o o t >
< / t a b l e >
< / >
) ;
}
function Panel ( ) {
return (
< >
[ Placeholder Panel ]
< / >
) ;
}
const CalculateAccuracy = ( cool , fine , safe , sad , worst ) => {
var noteCount = cool + fine + safe + sad + worst ;
var sum = cool + ( fine * 0.5 ) + ( safe * 0.1 ) + ( sad * 0.05 ) ;
return Math . round ( ( sum / noteCount ) * 10000 ) / 100 + "%" ;
}
function ClearBadge ( p ) {
var [ display , setDisplay ] = useState ( < > < / > )
/*<span className="badge badge-primary">{easy}/ { diffs . E }
{ ( fcdata && fcdata . E > 0 ) ? < > < br / > ★ { fcdata . E } < />:<></ > }
{ ( pfcdata && pfcdata . E > 0 ) ? < > < br / > ✪ { pfcdata . E } < />:<></ > } < /span>*/
function toggle ( state ) {
if ( state ) {
setDisplay ( < > { ( ( p . fcdata && p . fcdata [ p . diff ] > 0 ) ? < > < br / > ★ { p . fcdata [ p . diff ] } < />:<></ > ) }
{ ( ( p . pfcdata && p . pfcdata [ p . diff ] > 0 ) ? < > < br / > ✪ { p . pfcdata [ p . diff ] } < />:<></ > ) } < / > )
} else {
setDisplay ( < > < / > )
}
}
useEffect ( ( ) => {
toggle ( p . mouseOver )
} , [ p . mouseOver ] )
return (
< >
< span className = { "badge badge-" + CalculateBadge ( p . diff ) } onTouchStart = { ( ) => { toggle ( true ) } } > { p . count } / { p . diffs [ p . diff ] } { display } < / s p a n >
< / >
)
}
function FavoritePlaystyle ( p ) {
switch ( p . playstyle ) {
case "PS4 Controller" : {
return < ProfileDataContainer playstyle _icon = { true } label = "Favorite Playstyle" data = { p . playstyle } width = "4" / >
}
case "Joycons" : {
return < ProfileDataContainer playstyle _icon = { true } label = "Favorite Playstyle" data = { p . playstyle } width = "4" / >
}
case "Mix Mode" : {
return < ProfileDataContainer playstyle _icon = { true } label = "Favorite Playstyle" data = { p . playstyle } width = "4" / >
}
case "Arcade Controller" : {
return < ProfileDataContainer playstyle _icon = { true } label = "Favorite Playstyle" data = { p . playstyle } width = "4" / >
}
case "Touch Screen" : {
return < ProfileDataContainer playstyle _icon = { true } label = "Favorite Playstyle" data = { p . playstyle } width = "4" / >
}
default : {
return < > < / >
}
}
}
function GamesPanel ( p ) {
return (
< div className = "d-none d-sm-none d-md-block float-right" >
{ p . user . megamix && < img style = { { position : "absolute" , right : "0px" , top : "-8px" } } className = "pr-2" src = "http://projectdivar.com/files/mega39s.png" / > }
{ p . user . futuretone && < img style = { { position : "absolute" , right : ( p . user . megamix ) ? "112px" : "0px" , top : "-8px" } } className = "pl-2" src = "http://projectdivar.com/files/futuretone.png" / > }
< / d i v >
)
}
function Profile ( p ) {
let { username } = useParams ( ) ;
let match = useRouteMatch ( ) ;
var [ updateProfile , setProfile ] = useState ( false ) ;
var [ playcount , setPlayCount ] = useState ( 0 ) ;
var [ fccount , setFCCount ] = useState ( 0 ) ;
var [ cleared , setClear ] = useState ( "" ) ;
var [ accuracy , setAccuracy ] = useState ( "-%" ) ;
var [ rating , setRating ] = useState ( 0 ) ;
var [ lastPlayed , setLastPlayed ] = useState ( new Date ( ) ) ;
var [ update , setUpdate ] = useState ( false ) ;
var [ diffs , setDiffs ] = useState ( { } ) ;
var [ user , setUserData ] = useState ( { } ) ;
var [ render , setRender ] = useState ( false ) ;
var [ modalsrc , setModalSrc ] = useState ( { } )
var [ modalVisible , setModalVisible ] = useState ( false ) ;
var [ mouseOver , setMouseOver ] = useState ( false ) ;
var [ loadedTime , setLoadedTime ] = useState ( new Date ( ) ) ;
const firstUpdate = useRef ( true ) ;
let history = useHistory ( ) ;
const location = useLocation ( ) ;
function CalculateClear ( easy , normal , hard , ex , exex , fcdata , pfcdata ) {
return < >
< ClearBadge mouseOver = { mouseOver } diff = "E" count = { easy } diffs = { diffs } fcdata = { fcdata } pfcdata = { pfcdata } / >
< ClearBadge mouseOver = { mouseOver } diff = "N" count = { normal } diffs = { diffs } fcdata = { fcdata } pfcdata = { pfcdata } / >
< ClearBadge mouseOver = { mouseOver } diff = "H" count = { hard } diffs = { diffs } fcdata = { fcdata } pfcdata = { pfcdata } / >
< ClearBadge mouseOver = { mouseOver } diff = "EX" count = { ex } diffs = { diffs } fcdata = { fcdata } pfcdata = { pfcdata } / >
< ClearBadge mouseOver = { mouseOver } diff = "EXEX" count = { exex } diffs = { diffs } fcdata = { fcdata } pfcdata = { pfcdata } / >
< / >
}
useEffect ( ( ) => {
if ( firstUpdate . current ) {
firstUpdate . current = false ;
return ;
}
setUpdate ( ! update )
} , [ loadedTime ] )
useEffect ( ( ) => {
axios . get ( "http://projectdivar.com:4501/userdata/" + username )
. then ( ( data ) => { setUserData ( data . data ) ; setPlayCount ( data . data . playcount ) ; setFCCount ( data . data . fccount ) ; setRating ( data . data . rating ) ; setLastPlayed ( data . data . last _played ) ; setAccuracy ( CalculateAccuracy ( data . data . cool , data . data . fine , data . data . safe , data . data . sad , data . data . worst ) ) } ) ;
axios . get ( "http://projectdivar.com:4501/songdiffs" )
. then ( ( data ) => { setDiffs ( data . data ) } )
setModalVisible ( false ) ;
const interval = setInterval ( ( ) => {
axios . get ( "http://projectdivar.com/userdata/" + username )
. then ( ( data ) => {
return axios . get ( "http://projectdivar.com/updates/" + data . data . id )
} )
. then ( ( data ) => {
//Positive number means new update is available for this profile.
//console.log(moment(data.data.date).diff(loadedTime))
if ( moment ( data . data . date ) . diff ( loadedTime ) > 0 ) {
setLoadedTime ( new Date ( ) )
history . push ( "/user/" + username )
}
} )
. catch ( ( err ) => {
//console.log(err.message)
} )
} , 10000 )
return ( ) => clearInterval ( interval )
} , [ update , username ] )
useEffect ( ( ) => {
if ( user != { } ) {
setClear ( CalculateClear ( user . eclear , user . nclear , user . hclear , user . exclear , user . exexclear , user . fcdata , user . pfcdata ) )
}
} , [ diffs , user , mouseOver ] )
useEffect ( ( ) => {
setRender ( user !== undefined && playcount !== undefined && fccount !== undefined && rating !== undefined && lastPlayed !== undefined && accuracy !== undefined && diffs !== undefined && cleared !== undefined )
} , [ user , playcount , fccount , rating , lastPlayed , accuracy , diffs , cleared ] )
return (
< >
< ImageDisplayer username = { username } songs = { p . songs } play = { modalsrc } modalVisible = { modalVisible } setModalVisible = { setModalVisible } > < / I m a g e D i s p l a y e r >
< GamesPanel name = "Games" user = { user } / >
< h2 > { username + "'s Profile" } < / h 2 >
{ ( render ) ? < >
{ user . playstyle && user . playstyle . length > 0 &&
< div className = "row" >
< div className = "col-md-4" > < / d i v >
< FavoritePlaystyle playstyle = { user . playstyle } / >
< div className = "col-md-4" > < / d i v >
< / d i v > }
< StatisticsPanel name = "Statistics" setMouseOver = { setMouseOver } username = { username } playcount = { playcount } fccount = { fccount } cleared = { cleared } accuracy = { accuracy } / >
< HitCountsPanel name = "Hit Counts" username = { username } user = { user } / >
< BestPlaysPanel profileUpdate = { update } name = "Best Plays" setModalVisible = { setModalVisible } setModalSrc = { setModalSrc } username = { username } songs = { p . songs } / >
< CompletionPanel profileUpdate = { update } name = "Progress" user = { user } setModalVisible = { setModalVisible } setModalSrc = { setModalSrc } username = { username } songs = { p . songs } / >
< Panel name = "Activity" username = { username } / >
< Link smooth to = { location . pathname + "#content" } > < IMAGE _ARROWUP style = { { fontSize : "32px" , position : "fixed" , right : "18px" , bottom : "18px" } } / > < / L i n k >
< / >
: < > < / >
}
< / >
) ;
}
function Rankings ( ) {
let { sort , sortOrder } = useParams ( ) ;
let match = useRouteMatch ( ) ;
var [ users , setUsers ] = useState ( [ ] ) ;
var [ updateUsers , setUpdateUsers ] = useState ( false ) ;
var [ isLoading , setIsLoading ] = useState ( true ) ;
useEffect ( ( ) => {
axios . get ( "http://projectdivar.com:4501/users/" + sort + "/" + sortOrder + "?limit=100&offset=0" )
. then ( ( data ) => { setUsers ( data . data )
setIsLoading ( false ) ; } )
//.then(()=>{console.log(users)})
} , [ updateUsers ] )
return (
< >
< table >
< colgroup >
< col span = "1" style = { { width : "20%" } } / >
< col span = "1" style = { { width : "15%" } } / >
< col span = "1" style = { { width : "35%" } } / >
< col span = "1" style = { { width : "20%" } } / >
< col span = "1" style = { { width : "10%" } } / >
< / c o l g r o u p >
< thead >
< tr >
< th className = "header" > < Sort setIsLoading = { setIsLoading } updateUsers = { updateUsers } setUpdateUsers = { setUpdateUsers } label = "Username" order = "username" / > < / t h >
< th className = "header" > < Sort setIsLoading = { setIsLoading } updateUsers = { updateUsers } updateUsers = { updateUsers } setUpdateUsers = { setUpdateUsers } setUpdateUsers = { setUpdateUsers } label = "Rating" order = "rating" / > < / t h >
< th className = "header" > < Sort setIsLoading = { setIsLoading } updateUsers = { updateUsers } setUpdateUsers = { setUpdateUsers } label = "Last Played" order = "last_played" / > < / t h >
< th className = "header" > < Sort setIsLoading = { setIsLoading } updateUsers = { updateUsers } setUpdateUsers = { setUpdateUsers } label = "Play Count" order = "playcount" / > < / t h >
< th className = "header" > < Sort setIsLoading = { setIsLoading } updateUsers = { updateUsers } setUpdateUsers = { setUpdateUsers } label = "FC Count" order = "fccount" / > < / t h >
< / t r >
< / t h e a d >
{ users . map ( ( user , i ) =>
< tbody key = { i } style = { { backgroundColor : ( i % 2 === 0 ) ? "rgba(255,255,255,0)" : "rgba(0,0,0,0.05)" } } >
< tr >
< td className = { ( isLoading ) ? "loading" : "" } > < Link to = { "/user/" + user . username } > { user . username } < / L i n k > < / t d >
< td className = { ( isLoading ) ? "loading" : "" } className = { ( isLoading ) ? "loading" : "" } > { user . rating } < / t d >
< td className = { ( isLoading ) ? "loading" : "" } className = { ( isLoading ) ? "loading" : "" } className = { ( isLoading ) ? "loading" : "" } > { moment ( user . last _played ) . format ( "ddd, MMM Do h:mm a" ) } < / t d >
< td className = { ( isLoading ) ? "loading" : "" } > { user . playcount } < / t d >
< td className = { ( isLoading ) ? "loading" : "" } > { user . fccount } < / t d >
< / t r >
< / t b o d y > ) }
< / t a b l e >
< / >
) ;
}
function ImageUpload ( p ) {
var [ file , setFile ] = useState ( null ) ;
var [ fileProcess , setFileProcess ] = useState ( 0 ) ;
var [ error , setError ] = useState ( null ) ;
var [ success , setSuccess ] = useState ( null ) ;
var [ fileProgress , setFileProgress ] = useState ( 0 ) ;
var [ update , setUpdate ] = useState ( false ) ;
var [ authToken , setAuthToken ] = useState ( false ) ;
useEffect ( ( ) => {
axios . post ( "http://projectdivar.com/authenticate/authToken" , { username : localStorage . getItem ( "username" ) ,
authCode : localStorage . getItem ( "authToken" ) } )
. then ( ( data ) => {
setAuthToken ( data . data . authentication _token )
} )
} , [ update ] )
var prepFile = ( e ) => {
setFile ( e . currentTarget . files [ 0 ] )
setError ( null ) ;
}
var uploadFile = ( e ) => {
setError ( null ) ;
if ( ! file ) { setError ( "No file selected!" ) ; return ; }
if ( file . type !== "application/x-zip-compressed" &&
file . type !== "image/jpeg" && file . type !== "image/png" ) {
setError ( "File type is invalid! Please provide a .zip/.jpg/.png file!" )
setFileProcess ( 0 )
return ;
}
const data = new FormData ( )
data . append ( 'file' , file )
data . append ( "username" , localStorage . getItem ( "username" ) ) ;
data . append ( "authentication_token" , authToken ) ;
if ( ! data . has ( "username" ) || ! data . has ( "authentication_token" ) ) { setError ( "Authentication failed!" ) ; return ; }
if ( file . size > 15 * 1024 * 1024 ) {
setError ( "File size is too large! Max is 15MB! Consider splitting your plays into chunks (Recommended 50 files per zip)." ) ; return ;
}
//console.log(file)
setFileProcess ( 1 ) ;
axios . post ( "http://projectdivar.com/upload" , data , {
onUploadProgress : function ( progressEvent ) {
//console.log(progressEvent)
setFileProgress ( Math . round ( ( progressEvent . loaded * 100 ) / progressEvent . total ) )
} } )
. then ( res => {
setSuccess ( res . data ) ;
setFileProgress ( 100 )
setFileProcess ( 0 )
} )
. catch ( ( err ) => { setError ( err . message ) ; setFileProgress ( 0 ) ; setFileProcess ( 0 ) } )
}
switch ( fileProcess ) {
default : {
return (
< form method = "post" action = "#" id = "#" >
< div className = "files form-group color" >
< h3 > Submit your play < / h 3 >
< i > Plays can be a single image or a bunch of images in a zip file ! < / i >
< hr / >
{ ( success != null ) ? < h4 className = "success" > { success } < /h4>:<></ > }
< div style = { { position : "relative" , top : "0px" } } >
< input type = "file" name = "file" className = "form-control" onChange = { ( e ) => { prepFile ( e ) } } disabled = { fileProcess === 1 } / >
< div className = "uploadicon" / >
< div className = "dragText" > or drag it here < / d i v >
< / d i v >
{ ( error !== null ) ? < div className = "error" > { error } < /div>:<></ > }
< button type = "button" className = "btn btn-primary btn-block" onClick = { ( e ) => { uploadFile ( e ) } } disabled = { fileProcess === 1 } >
{ fileProcess === 1 ? < > Uploading ... < span className = "spinner-border" / >
< div className = "progress" style = { { position : "relative" } } >
< div className = { "progress-bar" } style = { { width : fileProgress + "%" } } role = "progressbar" aria - valuemin = "0" aria - valuemax = "100" > < / d i v >
< div style = { { position : "relative" } } > { fileProgress + "%" } < / d i v >
< / d i v >
< />:<>Upload</ > } < / b u t t o n >
< / d i v >
< / f o r m > ) ;
}
}
}
function SongSearch ( p ) {
//Requires: p.songs / p.song / p.setSong / p.filteredSongs / p.setFilteredSongs
const [ song , setSong ] = useState ( "" )
const [ focused , setFocused ] = useState ( false )
useEffect ( ( ) => {
if ( p . setStyle ) {
if ( focused ) {
p . setStyle ( false )
} else {
p . setStyle ( true )
}
}
} , [ focused ] )
return (
< >
< input className = "form-control form-control-lg" value = { song } placeholder = { "🔍 Search by Song,Artist,Vocaloid" } onKeyDown = { ( e ) => { if ( e . key === "Enter" ) { setFocused ( false ) ; e . target . blur ( ) } } } onFocus = { ( ) => { setFocused ( true ) } } onChange = { ( e ) => {
if ( p . setFilteredSongs ) { p . setFilteredSongs ( { } ) }
setSong ( e . target . value )
}
} onBlur = { ( ) => {
setTimeout ( ( ) => { setFocused ( false ) } , 250 )
}
} / >
{ ( focused ) ?
< div className = "overflow-auto rounded-lg" style = { { background : "#eef" , position : "absolute" , width : "95%" , height : "240px" } } > {
Object . keys ( p . songs ) . filter ( ( key ) =>
{
var s = p . songs [ key ]
return s . name . toLowerCase ( ) . includes ( song . toLowerCase ( ) ) || s . romanized _name . toLowerCase ( ) . includes ( song . toLowerCase ( ) ) || s . english _name . toLowerCase ( ) . includes ( song . toLowerCase ( ) ) || s . artist . toLowerCase ( ) . includes ( song . toLowerCase ( ) ) || s . vocaloid . toLowerCase ( ) . includes ( song . toLowerCase ( ) )
} ) . map ( ( key ) => {
if ( p . setFilteredSongs && p . filteredSongs ) {
var obj = p . filteredSongs ;
obj [ key ] = true
//console.log(obj)
p . setFilteredSongs ( obj )
}
return < div key = { key } className = "pb-1 homelink highest" onClick = { ( ) => { setSong ( p . songs [ key ] . name ) ; p . setSong ( p . songs [ key ] . name ) ; setFocused ( false ) ; if ( p . setFilteredSongs && p . filteredSongs ) { var obj = { } ; obj [ key ] = true ; p . setFilteredSongs ( obj ) } } } >
< div className = "d-flex flex-row" >
< div className = "p-2" >
< img className = "centered" src = { p . songs [ key ] . album _art . replace ( "album_art" , "album_art/small" ) } / >
< / d i v >
< div className = "p-8" >
< h4 > { p . songs [ key ] . name } < / h 4 > { ( p . s o n g s [ k e y ] . r o m a n i z e d _ n a m e ) ? p . s o n g s [ k e y ] . r o m a n i z e d _ n a m e : p . s o n g s [ k e y ] . e n g l i s h _ n a m e }
< / d i v >
< / d i v >
< / d i v > } ) } < / d i v > : < > < / > }
< / >
)
}
function SimpleUpload ( p ) {
const [ song , setSong ] = useState ( "" )
const [ percentage , setPercentage ] = useState ( "" )
return (
< >
< SongSearch song = { song } setSong = { setSong } songs = { p . songs } / >
{ ( song . length > 0 ? < >
< div className = "input-group" >
< div className = "input-group-prepend" >
< label htmlFor = "validationCustomUsername" >
< span className = "input-group-text" id = "inputGroupPrepend" > Song % < / s p a n >
< / l a b e l >
< input type = "text" className = "form-control" id = "validationCustomUsername" value = { percentage } placeholder = "101.46%" aria - describedby = "inputGroupPrepend"
onChange = { ( e ) => {
if ( ! e . target . value . includes ( "%" ) ) {
e . target . value += "%"
e . target . selectionStart = e . target . selectionEnd = e . target . value . length - 1
}
setPercentage ( e . target . value ) } }
required / >
< small className = "text-muted" >
Input the % you got on the results screen .
< / s m a l l >
< / d i v >
< / d i v >
< />:<></ > ) }
< / >
)
}
function Submit ( p ) {
return (
< div className = "row" >
< div className = "col-12 col-md-10" >
< Switch >
< Route path = "/submitplay/simple" >
< SimpleUpload songs = { p . songs } / >
< / R o u t e >
< Route path = "/submitplay/detail" >
Detailed
< / R o u t e >
< Route path = "/submitplay/switch" >
< h2 > Playstation / Nintendo Switch / Twitter Upload < / h 2 >
Want to upload your scores to the website conveniently ? Go to < Link to = "/usersettings" > Edit Profile Settings < / L i n k > a n d e n t e r y o u r T w i t t e r u s e r n a m e , t h e n f o l l o w t h e s t e p s b e l o w !
< hr / >
< div className = "row mb-4" >
< div className = "col-4 m-6" >
< h4 > Step 1 < / h 4 >
From your Nintendo Switch Album or Playstation Gallery , select up to 4 results screenshots that you want the DivaRBot to parse .
< / d i v >
< div className = "col-8 m-6" >
< img width = "100%" className = "border rounded shadow" src = "http://projectdivar.com/files/switch1.png" / >
< / d i v >
< / d i v >
< div className = "row" >
< div className = "col-8 m-6" >
< img width = "100%" className = "border rounded shadow" src = "http://projectdivar.com/files/switch3.png" / >
< br / >
< img width = "100%" className = "border rounded shadow" src = "http://projectdivar.com/files/20200930021246.jpg" / >
< / d i v >
< div className = "col-4 m-6" >
< h4 > Step 2 < / h 4 >
Make sure to include < b > # divarbot < / b > s o t h e b o t c a n f i n d y o u r p l a y s ! T h e n s u b m i t a n d t h e b o t w i l l p r o c e s s t h e m i n j u s t a f e w m i n u t e s ! C h e c k y o u r s c o r e s o u t a f t e r t h e y h a v e b e e n p r o c e s s e d .
< / d i v >
< / d i v >
< / R o u t e >
< Route path = "/submitplay/image" >
< ImageUpload / >
< / R o u t e >
< Route path = "/submitplay" >
< h2 > Select a submission method < / h 2 >
{ false && < > < div className = "card" >
< Link smooth to = "/submitplay/simple#content" className = "nostyle" >
< div className = "card-body" >
< h5 className = "card-title" > Manual Submit < / h 5 >
< p className = "card-text" > Submit your plays by entering the clear % of a song < / p >
< p className = "card-text" > < small className = "text-muted" > The simplest way to submit plays , type in a % , tweak the other values quickly , then submit your play ! Optionally include a screenshot . < / s m a l l > < / p >
< / d i v >
< / L i n k >
< / d i v >
< br / > < / > }
< div className = "card" >
< Link smooth to = "/submitplay/image#content" className = "nostyle" >
< div className = "card-body" >
< h5 className = "card-title" > Image Upload < / h 5 >
< p className = "card-text" > Upload images from your Playstation / Nintendo Switch for automatic processing / scoring ! < / p >
< p className = "card-text" > < small className = "text-muted" > Put up to 50 images in a zip file to mass - upload your screenshotted plays to your profile . You will need to extract them from your microSD card from your Nintendo Switch or using a USB for your Playstation . < / s m a l l > < / p >
< / d i v >
< / L i n k >
< / d i v >
< br / >
< div className = "card" >
< Link smooth to = "/submitplay/switch#content" className = "nostyle" >
< div className = "card-body" >
< h5 className = "card-title" > Playstation / Nintendo Switch / Twitter Upload < / h 5 >
< p className = "card-text" > Setup your account for uploading through Twitter using your Playstation or Nintendo Switch ! < / p >
< p className = "card-text" > < small className = "text-muted" > You can select up to 4 images to post to Twitter at one time . < / s m a l l > < / p >
< / d i v >
< / L i n k >
< / d i v >
< br / >
< div className = "card" >
< Link smooth to = "/streampanel#content" className = "nostyle" >
< div className = "card-body" >
< h5 className = "card-title" > Stream Monitoring < / h 5 >
< p className = "card-text" > Stream < b > Project Diva Future Tone < / b > t h r o u g h y o u r P l a y s t a t i o n 4 t o s u b m i t r e c o r d s ! < / p >
< p className = "card-text" > < small className = "text-muted" > Specify your Twitch account and then start up a stream monitor that will watch your game as you play , recording your results . < / s m a l l > < / p >
< / d i v >
< / L i n k >
< / d i v >
< br / >
< div className = "card" >
< Link smooth to = "/divabot#content" className = "nostyle" >
< div className = "card-body" >
< h5 className = "card-title" > DivaBot < / h 5 >
< p className = "card-text" > Use your capture card / stream setup to monitor your game screen as you play . < / p >
< p className = "card-text" > < small className = "text-muted" > This uses software developed by < b > sigonasr2 < / b > t h a t a u t o m a t i c a l l y r e c o r d s y o u r r e s u l t s a s y o u p l a y . < / s m a l l > < / p >
< / d i v >
< / L i n k >
< / d i v >
< / R o u t e >
< / S w i t c h >
< / d i v >
< / d i v >
)
}
function RecentPlays ( p ) {
const [ update , setUpdate ] = useState ( false )
const [ recentPlayData , setRecentPlayData ] = useState ( [ ] )
var [ modalsrc , setModalSrc ] = useState ( { } )
var [ modalVisible , setModalVisible ] = useState ( false ) ;
useEffect ( ( ) => {
const interval = setInterval ( ( ) => {
axios . get ( "http://projectdivar.com/recentplays/" + p . username )
. then ( ( data ) => {
setRecentPlayData ( data . data ) ;
} )
. catch ( ( err ) => { } )
} , 5000 ) ;
return ( ) => { clearInterval ( interval ) }
} , [ update ] )
return (
< >
< ImageDisplayer username = { p . username } songs = { p . songs } play = { modalsrc } modalVisible = { modalVisible } setModalVisible = { setModalVisible } > < / I m a g e D i s p l a y e r >
{ recentPlayData . map ( ( play , i ) => < Play setModalVisible = { setModalVisible } setModalSrc = { setModalSrc } index = { i } play = { play } song = { p . songs [ play . songid ] } title = { true } mini = { true } / > ) }
< / >
)
}
function LoginInfo ( p ) {
const [ username , setUsername ] = useState ( undefined )
const [ authToken , setAuthToken ] = useState ( undefined )
const [ loggedIn , setLoggedIn ] = useState ( false )
//Load our storage data if exists.
useEffect ( ( ) => {
try {
setUsername ( localStorage . getItem ( "username" ) )
setAuthToken ( localStorage . getItem ( "authToken" ) )
} catch {
console . log ( "Not logged in!" ) ;
}
} , [ p . update ] )
useEffect ( ( ) => {
if ( username !== undefined && authToken !== undefined ) {
axios . post ( "http://projectdivar.com/authenticate/login" , { username : username , authCode : authToken } )
. then ( ( data ) => {
setLoggedIn ( true ) ;
p . setUsername ( username ) ;
p . setUserSettings ( data . data )
} )
. catch ( ( err ) => {
setLoggedIn ( false ) ;
} )
}
} , [ username , authToken ] )
return (
< >
{ loggedIn ? < >
Welcome , < b > { username } < /b>!<br/ >
< Link smooth to = { "/user/" + username + "#content" } > My Profile < /Link><br/ >
< Link smooth to = { "/usersettings#content" } > Edit Profile Settings < /Link><br/ >
< Link smooth to = { "/streampanel#content" } > My Stream Panel < /Link><br/ >
< / > : < >
< Link smooth to = "/login#content" > Login < /Link><br/ >
< Link smooth to = "/register#content" > Register < / L i n k >
< / > }
< / >
)
}
function Login ( p ) {
const [ username , setUsername ] = useState ( "" )
const [ authCode , setAuthCode ] = useState ( "" )
const [ authCodeVisible , setAuthCodeVisible ] = useState ( false )
const [ error , setError ] = useState ( false )
const [ disabled , setDisabled ] = useState ( false )
let history = useHistory ( ) ;
if ( p . isLoggedIn ) {
return ( < Redirect to = "/" / > )
}
return (
< >
< Form >
{ error && < h3 style = { { color : "red" } } > { error } < / h 3 > }
{ authCodeVisible && < > < h3 > We have sent you an email containing your login code ! < / h 3 >
< br / >
Please submit it to finish the login process .
< / > }
< Form . Group controlId = "formUsername" >
< Form . Label > Username < / F o r m . L a b e l >
< Form . Control disabled = { authCodeVisible } isInvalid = { username . length < 1 } onChange = { ( e ) => { setUsername ( e . currentTarget . value ) } } placeholder = "MikuMiku" value = { username } / >
< Form . Text className = "text-muted" >
We will send an email to the registered email of this account .
< / F o r m . T e x t >
< / F o r m . G r o u p >
{ authCodeVisible && < >
< div className = "row" >
< div className = "col-4" >
< Form . Group controlId = "formCode" >
< Form . Label > Authentication Code < / F o r m . L a b e l >
< Form . Control type = "password" isInvalid = { authCode . length != 5 } onChange = { ( e ) => { setAuthCode ( e . currentTarget . value ) } } placeholder = "XXXXX" value = { authCode } / >
< Form . Text className = "text-muted" >
Please enter the code you received in your email here . Then submit again .
< / F o r m . T e x t >
< / F o r m . G r o u p >
< / d i v >
< /div></ >
}
< Button disabled = { disabled } variant = "primary" type = "submit" onClick = { ( e ) => { e . preventDefault ( )
if ( username . length >= 1 ) {
setDisabled ( true )
setError ( false )
if ( authCode . length === 5 ) {
axios . post ( "http://projectdivar.com/authenticate/login" , { username : username , authCode : authCode } )
. then ( ( data ) => {
localStorage . setItem ( "username" , username )
localStorage . setItem ( "authToken" , authCode )
p . setLoginPanelUpdate ( true )
history . push ( "/" )
} )
. catch ( ( err ) => {
if ( err ) {
setError ( "Invalid Authentication Code!" )
setDisabled ( false )
}
} )
} else {
axios . post ( "http://projectdivar.com/sendemail/login" , { username : username } )
. then ( ( data ) => {
setAuthCodeVisible ( true )
setDisabled ( false )
} )
. catch ( ( err ) => {
if ( err ) {
setError ( "Invalid credentials provided!" )
setDisabled ( false )
}
} )
}
}
} } >
{ authCodeVisible ? "Submit Code" : "Login" }
< / B u t t o n >
< / F o r m >
< / >
)
}
function Register ( p ) {
const [ username , setUsername ] = useState ( "" )
const [ email , setEmail ] = useState ( "" )
const [ authCode , setAuthCode ] = useState ( "" )
const [ authCodeVisible , setAuthCodeVisible ] = useState ( false )
const [ error , setError ] = useState ( false )
const [ disabled , setDisabled ] = useState ( false )
let history = useHistory ( ) ;
if ( p . isLoggedIn ) {
history . push ( "/" )
}
return (
< >
< Form >
{ error && < h3 style = { { color : "red" } } > { error } < / h 3 > }
{ authCodeVisible && < > < h3 > We have sent you an email containing your registration code ! < / h 3 >
< br / >
Please submit it to finish the registration process .
< / > }
< Form . Group controlId = "formUsername" >
< Form . Label > Username < / F o r m . L a b e l >
< Form . Control disabled = { authCodeVisible } isInvalid = { username . length < 1 || username . includes ( "/" ) || username . includes ( "\\" ) } onChange = { ( e ) => { setUsername ( e . currentTarget . value ) } } placeholder = "MikuMiku" value = { username } / >
< / F o r m . G r o u p >
< Form . Group controlId = "formEmail" >
< Form . Label > Email Address < / F o r m . L a b e l >
< Form . Control disabled = { authCodeVisible } type = "email" disabled = { authCodeVisible } isInvalid = { email . length < 1 } onChange = { ( e ) => { setEmail ( e . currentTarget . value ) } } placeholder = "MikuMiku@39.net" value = { email } / >
< Form . Text className = "text-muted" >
Please provide a valid email address ! We use your email account as your "password" , so it is a requirement for this site .
< / F o r m . T e x t >
< / F o r m . G r o u p >
{ authCodeVisible && < >
< div className = "row" >
< div className = "col-4" >
< Form . Group controlId = "formAuthCode" >
< Form . Label > Authentication Code < / F o r m . L a b e l >
< Form . Control type = "password" isInvalid = { authCode . length != 5 } onChange = { ( e ) => { setAuthCode ( e . currentTarget . value ) } } placeholder = "XXXXX" value = { authCode } / >
< Form . Text className = "text-muted" >
Please enter the code you received in your email here . Then submit again .
< / F o r m . T e x t >
< / F o r m . G r o u p >
< / d i v >
< /div></ >
}
< Button disabled = { disabled } variant = "primary" type = "submit" onClick = { ( e ) => { e . preventDefault ( )
if ( username . length >= 1 && email . length >= 1
&& ! username . includes ( "/" ) && ! username . includes ( "\\" ) ) {
setDisabled ( true )
setError ( false )
if ( authCode . length === 5 ) {
axios . post ( "http://projectdivar.com/authenticate/login" , { username : username , authCode : authCode } )
. then ( ( data ) => {
localStorage . setItem ( "username" , username )
localStorage . setItem ( "authToken" , authCode )
p . setLoginPanelUpdate ( true )
return axios . patch ( "http://projectdivar.com/updateRegisteredState" , { username : username , authCode : authCode } )
} )
. then ( ( data ) => {
//console.log(data)
history . push ( "/" )
} )
. catch ( ( err ) => {
if ( err ) {
setError ( "Invalid Authentication Code!" )
setDisabled ( false )
}
} )
} else {
axios . post ( "http://projectdivar.com/sendemail/register" , { username : username , email : email } )
. then ( ( data ) => {
setAuthCodeVisible ( true )
setDisabled ( false )
} )
. catch ( ( err ) => {
if ( err ) {
setError ( "Username or Email already in use!" )
setDisabled ( false )
}
} )
}
}
} } >
{ authCodeVisible ? "Submit Code" : "Register" }
< / B u t t o n >
< / F o r m >
< / >
)
}
function UserSettings ( p ) {
let history = useHistory ( ) ;
const [ playStyle , setPlayStyle ] = useState ( p . userSettings . playstyle )
const [ playStyleHover , setPlayStyleHover ] = useState ( undefined )
const [ twitter , setTwitter ] = useState ( p . userSettings . twitter _name )
const [ twitterChange , setTwitterChange ] = useState ( false )
const [ twitch , setTwitch ] = useState ( p . userSettings . twitch _name )
const [ twitchChange , setTwitchChange ] = useState ( false )
const [ message , setMessage ] = useState ( false )
const [ error , setError ] = useState ( false )
if ( p . username === undefined ) {
return ( < Redirect to = "/" / > )
}
return (
< >
< Form . Group controlId = "playstyle" onMouseOut = { ( ) => { setPlayStyleHover ( undefined ) } } >
< Form . Label > Favorite Playstyle < / F o r m . L a b e l > - < b > { p l a y S t y l e } < / b >
< br / >
< Button onClick = { ( ) => { setPlayStyle ( "PS4 Controller" ) } } onMouseOver = { ( ) => { setPlayStyleHover ( "PS4 Controller" ) } } variant = { playStyle === "PS4 Controller" ? "info" : "outline-info" } > < IMAGE _CONTROLLER width = { 36 } height = { 36 } / > < / B u t t o n >
< Button onClick = { ( ) => { setPlayStyle ( "Joycons" ) } } onMouseOver = { ( ) => { setPlayStyleHover ( "Joycons" ) } } variant = { playStyle === "Joycons" ? "primary" : "outline-primary" } > < IMAGE _JOYCONS width = { 36 } height = { 36 } / > < / B u t t o n >
< Button onClick = { ( ) => { setPlayStyle ( "Mix Mode" ) } } onMouseOver = { ( ) => { setPlayStyleHover ( "Mix Mode" ) } } variant = { playStyle === "Mix Mode" ? "secondary" : "outline-secondary" } > < IMAGE _MIXMODE width = { 36 } height = { 36 } / > < / B u t t o n >
< Button onClick = { ( ) => { setPlayStyle ( "Arcade Controller" ) } } onMouseOver = { ( ) => { setPlayStyleHover ( "Arcade Controller" ) } } variant = { playStyle === "Arcade Controller" ? "success" : "outline-success" } > < IMAGE _ARCADE width = { 36 } height = { 36 } / > < / B u t t o n >
< Button onClick = { ( ) => { setPlayStyle ( "Touch Screen" ) } } onMouseOver = { ( ) => { setPlayStyleHover ( "Touch Screen" ) } } variant = { playStyle === "Touch Screen" ? "warning" : "outline-warning" } > < IMAGE _TABLET width = { 36 } height = { 36 } / > < / B u t t o n >
< Form . Text className = "text-muted" >
{ playStyleHover ? < > Change playstyle to < b > { playStyleHover } < /b></ > : < > Your playstyle will be included in your submitted plays . < / > }
< / F o r m . T e x t >
< / F o r m . G r o u p >
< hr / >
< Form . Group controlId = "twitter" >
< Form . Label > Twitter Username : < / F o r m . L a b e l >
< Form . Control onChange = { ( e ) => { setTwitter ( e . currentTarget . value ) ; setTwitterChange ( true ) } } value = { twitter } placeholder = "MikuMiku" / >
< Form . Text className = "text-muted" >
If you input your Twitter username , you can submit screenshots to < b > # divarbot < / b > ( w i t h " # d i v a r b o t " i n t h e m e s s a g e ) a n d y o u r p l a y s w i l l a u t o - s u b m i t f r o m T w i t t e r a t a n y t i m e .
< / F o r m . T e x t >
< / F o r m . G r o u p >
< Form . Group controlId = "twitch" >
< Form . Label className = "pt-4" > Twitch Username : < / F o r m . L a b e l >
< Form . Control onChange = { ( e ) => { setTwitch ( e . currentTarget . value ) ; setTwitchChange ( true ) } } value = { twitch } placeholder = "MikuMikuStreams" / >
< Form . Text className = "text-muted" >
If you input your Twitch username , you can setup your stream using the < Link to = "/streampanel" > stream monitoring tool < / L i n k > .
< / F o r m . T e x t >
< / F o r m . G r o u p >
< Button onClick = { ( ) => {
var obj = { username : localStorage . getItem ( "username" ) ,
authCode : localStorage . getItem ( "authToken" ) ,
playStyle : playStyle }
if ( playStyle === undefined || playStyle === null ) {
setError ( "Please select a play style before saving!" )
return ;
}
if ( twitterChange ) {
obj . twitterName = twitter ;
}
if ( twitchChange ) {
obj . twitchName = twitch ;
}
setError ( false )
setMessage ( false )
axios . post ( "http://projectdivar.com/updateuser" , obj )
. then ( ( data ) => {
setMessage ( data . data )
p . setUserSettings ( { ... p . userSettings , playStyle : playStyle , twitter _name : twitter , twitch _name : twitch } )
setTwitterChange ( false )
setTwitchChange ( false )
} )
. catch ( ( err ) => {
setError ( err . message )
} )
} } > Save Changes < / B u t t o n >
{ message && < h3 style = { { color : "green" } } > { message } < / h 3 > }
{ error && < h3 style = { { color : "red" } } > { error } < / h 3 > }
< hr / >
< UserAuth username = { p . username } isLoggedIn = { p . username !== undefined } / >
< / >
)
}
function UserAuth ( p ) {
const [ showAuthCode , setShowAuthCode ] = useState ( false )
const [ authToken , setAuthToken ] = useState ( "" )
return ( < >
Your < b > App Authentication Code < / b > i s u s e d f o r v e r i f y i n g y o u r i d e n t i t y w h e n u s i n g a p p s s u c h a s < b > D i v a B o t < / b > . B y c l i c k i n g t h e < b > { " < R e v e a l C o d e > " } < / b > b u t t o n , y o u u n d e r s t a n d t h a t y o u s h o u l d n o t s h a r e t h i s c o d e o r s h o w i t t o a n y o n e !
< br / > < br / >
{ showAuthCode ?
< input readOnly value = { authToken } > < / i n p u t >
: < button onClick = { ( ) => {
axios . post ( "http://projectdivar.com/authenticate/authToken" , { username : localStorage . getItem ( "username" ) ,
authCode : localStorage . getItem ( "authToken" ) } )
. then ( ( data ) => {
setAuthToken ( data . data . authentication _token )
setShowAuthCode ( true )
} )
. catch ( ( err ) => {
setAuthToken ( err . message )
} )
}
} >
{ "<Click to reveal App Authentication Code>" }
< / b u t t o n >
}
< / > )
}
function ReleaseList ( p ) {
return (
< >
< ul className = "list-group" >
{ p . releases . map ( ( release , i ) =>
< li key = { i } className = "list-group-item" >
< b > { release [ 0 ] } < /b> - <a href={release[1]}>{release[1].replace("http:/ / projectdivar . com / files / releases / "," " ) } < /a> <i>(Released {release[2]})</i > - { release [ 3 ] }
< / l i >
) }
< / u l >
< / >
)
}
function DivaBot ( ) {
const releases = [
[ "05D" , "http://projectdivar.com/files/releases/DivaBot05D.zip" , "29 Sep 2020" , < > < Badge variant = "info" pill > Recommended < /Badge> <i>Maintenance build. Moved song select detection point for FT. Added "EYE_TRACKING_TOGGLE" config parameter.</i > < / > ] ,
[ "05C" , "http://projectdivar.com/files/releases/DivaBot05C2.zip" , "24 Sep 2020" , < > < i > Fixed bug with Finder not being submitted , and fix 1000 + note counts for FT submissions . Improve difficulty detection . < /i></ > ] ,
]
const incompatiblereleases = [
[ "05B" , "http://projectdivar.com/files/releases/DivaBot05B.zip" , "22 Sep 2020" , < > < IMAGE _BUG / > < i > Improved song select recognition speed . < /i></ > ] ,
[ "05A" , "http://projectdivar.com/files/releases/DivaBot05A.zip" , "21 Sep 2020" , < > < i > Added multi - monitor support . Use calibration to switch monitors . < /i></ > ] ,
[ "05" , "http://projectdivar.com/files/releases/DivaBot05.zip" , "21 Sep 2020" , < > < i > Added Miku FC . Huge optimizations to result screen capture , improve menu detection algorithms . < /i></ > ] ,
[ "04B" , "http://projectdivar.com/files/releases/DivaBot04A2.zip" , "20 Sep 2020" , < > < i > Redo the calibrator and improve Future Tone recognition . < /i></ > ] ,
[ "04A" , "http://projectdivar.com/files/releases/DivaBot04A1.zip" , "19 Sep 2020" , < > < IMAGE _BUG / > < i > Fix issues with Future tone songs with * s in them . < /i></ > ] ,
[ "04" , "http://projectdivar.com/files/releases/DivaBot04.zip" , "19 Sep 2020" , < > < IMAGE _BUG / > < i > Update so everything ' s working ! Future Tone compatibility live ! < /i></ > ] ,
[ "03-beta" , "http://projectdivar.com/files/releases/DivaBot03-beta.zip" , "19 Sep 2020" , < > < IMAGE _BUG / > < Badge variant = "success" pill > BUGGED < /Badge> <i>Added Future Tone compatibility. Works with Megamix or Future Tone.</i > < / > ] ,
[ "03" , "http://projectdivar.com/files/releases/DivaBot03.zip" , "17 Sep 2020" , < > < Badge variant = "warning" pill > Megamix ONLY < /Badge> <i>DLC Update - Compatibility with removed 'bpm' field from database. Fixed bug with ":" in song names.</i > < / > ] ,
[ "02A" , "http://projectdivar.com/files/releases/DivaBot02A.zip" , "14 Sep 2020" , < > < Badge variant = "warning" pill > Incompatible < /Badge> <i>Label Headers and Redo Song Calibration features added</i > < / > ] ,
[ "02" , "http://projectdivar.com/files/releases/DivaBot02.zip" , "14 Sep 2020" , < > < Badge variant = "warning" pill > Incompatible ! < /Badge></ > ] ,
[ "01B" , "http://projectdivar.com/files/releases/DivaBot01B.zip" , "13 Sep 2020" , < > < IMAGE _BUG / > < Badge variant = "warning" pill > Incompatible < / B a d g e > < B a d g e v a r i a n t = " s u c c e s s " p i l l > B U G G E D < / B a d g e > < b > D O N O T U S E ! < / b > < / > ] ,
[ "01A" , "http://projectdivar.com/files/releases/DivaBot01A.zip" , "13 Sep 2020" , < > < IMAGE _BUG / > < Badge variant = "warning" pill > Incompatible < / B a d g e > < B a d g e v a r i a n t = " s u c c e s s " p i l l > B U G G E D < / B a d g e > < b > D O N O T U S E ! < / b > < i > S p e e d I m p r o v e m e n t s < / i > < / > ] ,
[ "01" , "http://projectdivar.com/files/releases/DivaBot01.zip" , "13 Sep 2020" , < > < IMAGE _BUG / > < Badge variant = "warning" pill > Incompatible < / B a d g e > < B a d g e v a r i a n t = " s u c c e s s " p i l l > B U G G E D < / B a d g e > < b > D O N O T U S E ! < / b > < i > I n i t i a l R e l e a s e < / i > < / > ]
]
return (
< >
< b > DivaBot < / b > w a s c r e a t e d b y < b > s i g o n a s r 2 < / b > i n o r d e r t o a l l o w P r o j e c t D i v a s t r e a m e r s t o p e r s o n a l i z e t h e i r s t r e a m s e t u p s w i t h t h e i r p e r s o n a l s c o r e s a n d a c h i e v e m e n t s i n t o t h e i r g a m e .
< br / > < br / >
The app works by monitoring your game ' s capture area as you are streaming in order to identify what song you are playing , and what scores you achieve . It is used with this website to make score
submitting and tracking easier .
< br / >
The app currently supports < b > Megamix < / b > a n d < b > F u t u r e T o n e < / b > . O t h e r g a m e s w i l l b e s u p p o r t e d i n t h e f u t u r e .
< hr / >
< h3 > Setup Instructions < / h 3 >
{ < iframe width = "100%" height = "480" src = "https://www.youtube.com/embed/IAPpbp5EFto" frameBorder = "0" allow = "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen > < / i f r a m e > }
< hr / >
< h3 > Downloads < / h 3 >
< ReleaseList releases = { releases } / >
< hr / >
< h3 > Repository - Open Source Software < / h 3 >
I don 't believe in keeping things secret and you shouldn' t be open to just downloading whatever you find on the Internet .
< br / > < br / > < b > This app and Project DivaR < /b> itself is open source. You can find its source code <a href="https:/ / github . com / sigonasr2 / DivaBot " target=" _blank " > at this link < / a > .
< br / > < br / >
If you need an open discussion about how this program works or have any feedbacks / concerns , please contact me via the < b > Project DivaR Discord < / b > s e r v e r ( < b > @ s i g o n a s r 2 < / b > ) .
< hr / >
< h3 > Incompatible Downloads < / h 3 >
Downloads stored below no longer work due to infrastructure changes or updates that break old apps .
< ReleaseList releases = { incompatiblereleases } / >
< hr / >
< / >
)
}
function StreamPanel ( p ) {
const [ update , setUpdate ] = useState ( false ) ;
const [ monitor , setMonitor ] = useState ( "LOADING" ) ;
const [ image , setImage ] = useState ( < > < / > ) ;
let history = useHistory ( ) ;
useEffect ( ( ) => {
//process.env.REACT_APP_FRONTEND_AUTH
const interval = setInterval ( ( ) => {
if ( monitor === "LOADING" || monitor === "RUNNING" ) {
axios . post ( "/streaminfo/" + p . userSettings . id , { username : p . userSettings . username , authentication _token : localStorage . getItem ( "authToken" ) } )
. then ( ( data ) => {
if ( data . data >= 2 ) {
setMonitor ( "RUNNING" )
setImage ( < img style = { { width : "100%" } } src = { "http://projectdivar.com:8080/divar/cropped/cropped" + p . userSettings . id + ".png?" + Date . now ( ) } / > )
} else {
setMonitor ( "WAITING" )
}
} )
}
} , 5000 )
return ( ) => clearInterval ( interval )
} , [ update , monitor ] )
if ( ! p . isLoggedIn ) {
return ( < Redirect to = "/" / > )
}
if ( p . userSettings . twitch _name !== undefined && p . userSettings . twitch _name !== null && p . userSettings . twitch _name . length > 0 ) {
return (
< >
This panel is used to monitor score submissions as you play and to monitor a < b > Playstation 4 < / b > s t r e a m o f < b > P r o j e c t D i v a F u t u r e T o n e < / b > . R e a d t h e i n s t r u c t i o n s b e l o w b e f o r e u s i n g t h i s t o o l f o r t h e f i r s t t i m e t o p r o p e r l y s e t i t u p .
< Card className = "mt-4" body >
< h3 > Stream Monitor :
{ monitor === "RUNNING" ? < b style = { { color : "green" } } > Online < / b > :
monitor === "LOADING" ? < b > Pending < / b > :
< b style = { { color : "red" } } > Offline < / b > } < / h 3 >
{ monitor === "WAITING" ? < Button onClick = { ( ) => {
setMonitor ( "LOADING" )
axios . post ( "http://projectdivar.com/streamstart/" + p . userSettings . id , { username : p . userSettings . username , authentication _token : localStorage . getItem ( "authToken" ) } )
} } > Start Stream Monitor < / B u t t o n >
: monitor === "LOADING" ? < Button disabled > < Spinner animation = "border" size = "sm" / > Checking Status ... < / B u t t o n >
:
< div className = "row" >
< div className = "col-2" >
< Button variant = "info" onClick = { ( ) => {
setMonitor ( "LOADING" )
axios . post ( "http://projectdivar.com/streamkill/" + p . userSettings . id , { username : p . userSettings . username , authentication _token : localStorage . getItem ( "authToken" ) } )
} } > Stop Stream Monitor < / B u t t o n >
< / d i v >
< div className = "col-4" >
{ image }
< / d i v >
< div className = "col-6" >
< RecentPlays username = { p . userSettings . username } songs = { p . songs } / >
< / d i v >
< / d i v >
}
< / C a r d >
< h4 className = "pt-4" > Prerequisite < / h 4 >
If you haven ' t done so already , < a href = "https://www.playstation.com/en-gb/get-help/help-library/apps---features/playstation-apps---features/how-to-broadcast-using-youtube/" > setup your PS4 for Twitch Streaming < / a > .
< h2 className = "pt-4" > Step 1 < / h 2 >
< div className = "row" >
< div className = "col-md-6" >
While on the game ' s < b > Main Menu < / b > , s e l e c t t h e < b > S H A R E < / b > b u t t o n o n y o u r P S 4 .
< / d i v >
< / d i v >
< h2 className = "pt-4" > Step 2 < / h 2 >
< div className = "row" >
< div className = "col-md-6" >
Setup your broadcasting settings and make sure you select < b > 720 p - High ( 60 fps ) < / b > f o r b e s t r e s u l t s . ( S e l e c t i n g a l o w e r r e s o l u t i o n w i l l l i k e l y n o t w o r k )
< / d i v >
< div className = "col-md-6" >
< img style = { { height : "320px" } } src = "http://projectdivar.com/files/ps4startstream.png" / >
< / d i v >
< / d i v >
< h2 className = "pt-4" > Step 3 < / h 2 >
< div className = "row" >
< div className = "col-md-6" >
Once you are broadcasting on PS4 , click the < b > Start Stream Monitor < / b > b u t t o n a n d l e t i t c a l i b r a t e y o u r s c r e e n .
< / d i v >
< / d i v >
< h2 className = "pt-4" > Step 4 < / h 2 >
< div className = "row" >
< div className = "col-md-6" >
If the calibration looks good , then start playing ! Otherwise stop the stream monitor , make sure you are on the main menu , then try starting it again .
After each song , if you want the score to submit , make sure you are on the Result screen for a second . ( You don ' t have to wait for it to pop up on the scores list unless you really want to make sure )
< / d i v >
< / d i v >
< hr / >
< h2 className = "pt-4" > Video < / h 2 >
< div className = "row" >
< div className = "col-md-12" >
Alternatively , I explain how to use this feature in the below video :
{ < iframe width = "100%" height = "480" src = "https://www.youtube.com/embed/GhS8koB3N6s" frameBorder = "0" allow = "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen > < / i f r a m e > }
< / d i v >
< / d i v >
< / >
)
} else {
return (
< >
You will need to go to your < Link to = "/usersettings" > Profile Settings < / L i n k > a n d u p d a t e y o u r T w i t c h u s e r n a m e b e f o r e u s i n g t h i s f e a t u r e .
< / >
)
}
}
function StreamData ( ) {
const [ imageSet , setImageSet ] = useState ( 0 ) ;
const [ rando1 , setRando1 ] = useState ( Date . now ( ) ) ;
const [ rando2 , setRando2 ] = useState ( Date . now ( ) ) ;
useEffect ( ( ) => {
setTimeout ( ( ) => {
if ( imageSet === 0 ) {
setImageSet ( 50 )
setRando1 ( Date . now ( ) )
} else {
setImageSet ( 0 )
setRando2 ( Date . now ( ) )
}
} , 5000 )
} , [ imageSet ] )
return (
< >
{ ( imageSet === 0 ) ? < > < img style = { { visibility : "visible" } } src = { "http://projectdivar.com:8080/feed/output0.png?" + rando1 } id = { rando1 } / > < img style = { { visibility : "hidden" } } id = { rando2 } src = { "http://projectdivar.com:8080/feed/output2.png?" + rando2 } / > < />:<><img style={{visibility:"visible"}} id={rando2} src={"http:/ / projectdivar . com : 8080 / feed / output2 . png ? "+rando2}/><img id={rando1} style={{visibility:" hidden "}} src={" http : //projectdivar.com:8080/feed/output0.png?"+rando1}/></>}
< / >
)
}
function EventData ( ) {
const [ score , currentScore ] = useState ( 0 ) ;
const [ value , setValue ] = useState ( 0 ) ;
const [ value2 , setValue2 ] = useState ( 0 ) ;
return (
< >
< h3 >
My Points : { score } & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; Target :
< / h 3 >
< br / >
< br / >
< br / >
< br / >
< Form . Group >
< Form . Control onKeyDown = { ( e ) => {
if ( e . key === 'Enter' ) {
currentScore ( score + Number ( value ) ) ;
setValue ( "" )
}
}
}
onChange = { ( val ) => { setValue ( val . currentTarget . value ) } } value = { value } > < / F o r m . C o n t r o l >
< / F o r m . G r o u p >
< Button onClick = { ( input ) => { currentScore ( score + Number ( value ) ) ; setValue ( "" ) } } > + < / B u t t o n >
< Form . Group >
< Form . Control onKeyDown = { ( e ) => {
if ( e . key === 'Enter' ) {
currentScore ( Number ( value2 ) ) ;
setValue2 ( "" )
}
}
}
onChange = { ( val ) => { setValue2 ( val . currentTarget . value ) } } value = { value2 } > < / F o r m . C o n t r o l >
< / F o r m . G r o u p >
< Button onClick = { ( input ) => { currentScore ( Number ( value2 ) ) ; setValue ( "" ) } } > Reset < / B u t t o n >
< / >
)
}
const EVENTSTART = moment ( '2021-01-12 12:00:00+09:00' ) ;
const EVENTEND = moment ( '2021-01-21 20:59:59+09:00' ) ;
function GetChartData ( chartData , rank ) {
//console.log(chartData)
if ( ! chartData || chartData . length === 0 ) {
return [ { x : 0 , y : 0 } ]
}
if ( rank <= 20 ) {
return [ ... chartData [ rank ] . map ( ( data ) => { return { x : data . date , y : data . points } } ) , { x : moment ( ) . isBefore ( EVENTEND ) ? moment ( ) : EVENTEND , y : chartData [ rank ] [ chartData [ rank ] . length - 1 ] . points } ]
} else {
return chartData [ rank ] . map ( ( data ) => { return { x : data . date , y : data . points } } )
}
}
function EventPoint ( p ) {
return < >
< tr >
< th scope = "row" > { p . data . id } < / t h >
< td > { p . data . date } < / t d >
< td > { p . data . name } < / t d >
< td > { p . data . description } < / t d >
< td > { p . data . points } < / t d >
< / t r >
< / >
}
function EventEditor ( ) {
const [ tier , setTier ] = useState ( undefined )
const [ event , setEvent ] = useState ( 7 )
const [ tierData , setTierData ] = useState ( [ ] )
const [ update , setUpdate ] = useState ( undefined )
const [ date , setDate ] = useState ( moment ( ) . format ( "YYYY-MM-DDTHH:mm" ) )
const [ points , setPoints ] = useState ( 0 )
const [ send , setSend ] = useState ( false )
const [ message , setMessage ] = useState ( "" )
const EVENTID = 17 ;
//console.log(moment().format("YYYY-MM-DDTHH:mm"))
const tierList = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 50 , 100 , 500 , 1000 , 2000 , 5000 , 10000 , 20000 , 30000 , 50000 ]
useEffect ( ( ) => {
//console.log(moment(date))
if ( send ) {
axios . post ( "http://projectdivar.com/eventsubmit" , { eventid : EVENTID , date : moment ( date ) , rank : Number ( tier ) , name : "" , description : "" , points : points } )
. then ( ( data ) => {
setMessage ( data . data )
setUpdate ( true )
setSend ( false )
} )
. catch ( ( err ) => {
setMessage ( "Failed to submit" )
setUpdate ( true )
setSend ( false )
} )
}
} , [ send ] )
useEffect ( ( ) => {
//console.log(tier)
if ( update ) {
if ( tier ) {
axios . get ( "http://projectdivar.com/eventdata/t20?tier=" + tier + "&event=" + EVENTID )
. then ( ( data ) => {
setTierData ( data . data )
} )
}
setUpdate ( undefined )
}
} , [ tier , update ] )
return < >
< select onChange = { ( t ) => { setUpdate ( true ) ; setTier ( t . currentTarget . value ) } } className = "form-select" aria - label = "Default select example" >
< option value = { tier } > Select a tier < / o p t i o n >
{ tierList . map ( ( tier , i ) => < option value = { tier } key = { i } > { tier } < / o p t i o n > ) }
< / s e l e c t >
< br / >
< br / >
{ message . length > 0 ? < h2 style = { message === "Submitted." ? { color : "green" } : { color : "red" } } > { message } < /h2>:<></ > }
{ tier ? < >
< h3 > T { tier } Data < / h 3 >
< br / >
< br / >
< h4 > Add New Entry : < / h 4 >
< div className = "row" >
< div className = "col-md-5" >
< label htmlFor = "date" className = "form-label" > Date < / l a b e l >
< input value = { date } onChange = { ( t ) => { setDate ( t . currentTarget . value ) } } type = "datetime-local" id = "date" className = "form-control" placeholder = "Username" aria - label = "Username" aria - describedby = "basic-addon1" / >
< / d i v >
< div className = "col-md-3" >
< label htmlFor = "points" className = "form-label" > Event Points < / l a b e l >
< input value = { points } onChange = { ( t ) => { setPoints ( t . currentTarget . value ) } } type = "number" id = "points" className = "form-control" placeholder = "0000" aria - label = "Event Points" aria - describedby = "basic-addon1" / >
< / d i v >
< / d i v >
< div className = "row" >
< div className = "col-md-3" >
< button type = "submit" disabled = { send } onClick = { ( t ) => { setSend ( true ) } } > Submit < / b u t t o n >
< / d i v >
< div className = "col-md-3" >
< button onClick = { ( t ) => { setDate ( moment ( ) . format ( "YYYY-MM-DDTHH:mm" ) ) } } > Set Time to Now < / b u t t o n >
< / d i v >
< / d i v >
< hr / >
< />:<></ > }
< table className = "table" >
< thead >
< tr >
< th scope = "col" > id < / t h >
< th scope = "col" > date < / t h >
< th scope = "col" > name < / t h >
< th scope = "col" > description < / t h >
< th scope = "col" > points < / t h >
< / t r >
< / t h e a d >
< tbody >
{ tierData . map ( ( point , i ) => < EventPoint setUpdate = { setUpdate } data = { point } key = { i } > < / E v e n t P o i n t > ) }
< / t b o d y >
< / t a b l e >
< / >
}
function CanEditor ( ) {
const [ password , setPassword ] = useState ( "" ) ;
const [ cans , setCans ] = useState ( 0 ) ;
const [ games , setGames ] = useState ( 0 ) ;
const [ update , setUpdate ] = useState ( false )
useEffect ( ( ) => {
refreshCount ( )
const interval = setInterval ( ( ) => {
refreshCount ( )
} , 5000 ) ;
return ( ) => { clearInterval ( interval ) }
} , [ update ] )
useEffect ( ( ) => {
} , [ password ] )
function refreshCount ( ) {
axios . get ( "http://projectdivar.com/cans" )
. then ( ( data ) => {
if ( data . data . cans > cans ) {
setCans ( data . data . cans )
}
if ( data . data . cans + data . data . notcan > games ) {
setGames ( Number ( data . data . cans ) + Number ( data . data . notcan ) )
}
} )
}
function sendRequest ( cans ) {
axios . post ( "http://projectdivar.com/cans" , { cans : cans } )
. then ( ( data ) => {
refreshCount ( )
} )
}
function addCan ( t ) {
setCans ( Number ( cans ) + 1 )
setGames ( Number ( games ) + 1 )
sendRequest ( true )
}
function addGame ( t ) {
setGames ( Number ( games ) + 1 )
sendRequest ( false )
}
return < >
< div className = "container" >
< div className = "row" >
< div className = "col-12 text-center" >
< h3 > Can % < / h 3 >
< h1 > { ( ( cans / games ) * 100 ) . toFixed ( 2 ) + "%" } < / h 1 >
< / d i v >
< / d i v >
< div className = "row" >
< div className = "col-6 text-center" >
< h5 > Cans < / h 5 >
< h1 > { cans } < / h 1 >
< / d i v >
< div className = "col-6 text-center" >
< h5 > Total Games < / h 5 >
< h1 > { games } < / h 1 >
< / d i v >
< / d i v >
< / d i v >
{ / * { p a s s w o r d ! = = " m u n i _ 6 2 " & & < >
< b > Password to Edit : < / b >
< input type = "password" placeholder = "Password" onChange = { ( t ) => {
setPassword ( t . currentTarget . value )
} }
/></ > }
{ password == "muni_62" && < >
< div className = "row" >
< div className = "col-6 text-center" >
< button onClick = { ( t ) => { addGame ( t ) } } > No Can < / b u t t o n >
< / d i v >
< div className = "col-6 text-center" >
< button onClick = { ( t ) => { addCan ( t ) } } > Can < / b u t t o n >
< / d i v >
< / d i v >
< />}*/ }
< / >
}
function Website ( ) {
const [ songs , setSongs ] = useState ( [ ] )
const [ update , setUpdate ] = useState ( false )
const [ tooltip , setTooltip ] = useState ( "" )
const [ loginPanelUpdate , setLoginPanelUpdate ] = useState ( false )
const [ username , setUsername ] = useState ( undefined )
const [ userSettings , setUserSettings ] = useState ( { } )
useEffect ( ( ) => {
axios . get ( "http://www.projectdivar.com/songs" )
. then ( ( data ) => {
setSongs ( data . data )
} )
} , [ update ] )
return (
< div className = "row" >
< div className = "col-md-2 pt-3 pb-3 overflow-hidden text-center" >
< h3 className = "d-none d-md-block" > Menu < / h 3 >
< LoginInfo setUserSettings = { setUserSettings } setUsername = { setUsername } update = { loginPanelUpdate } / >
< br / > < br / >
< Link to = "/rankings/rating/desc#content" > Rankings < /Link><br/ >
< Link to = "/submitplay#content" > Submit Scores < /Link><br/ >
< Link to = "/divabot#content" > DivaBot < /Link><br/ >
< hr / >
< a href = "http://discord.gg/eJ3cMzM" > < img src = "http://projectdivar.com/files/discord_button_small.png" / > < / a >
< / d i v >
< div className = "col-md-10 pt-3 pb-3" >
< div id = "content" / >
< Switch >
< Route path = "/rankings/:sort/:sortOrder" >
< Rankings / >
< / R o u t e >
< Route path = "/user/:username" >
{ ( songs ) ?
< Profile songs = { songs } / > : < > < / >
}
< / R o u t e >
< Route path = "/usersettings" >
{
< UserSettings setUserSettings = { setUserSettings } userSettings = { userSettings } username = { username } / >
}
< / R o u t e >
< Route path = "/submitplay" >
< Submit songs = { songs } / >
< / R o u t e >
< Route path = "/divabot" >
< h1 className = "title" > DivaBot < / h 1 >
< DivaBot / >
< / R o u t e >
< Route path = "/login" >
< h1 className = "title" > Login to Project DivaR < / h 1 >
< Login isLoggedIn = { username !== undefined } setLoginPanelUpdate = { setLoginPanelUpdate } / >
< / R o u t e >
< Route path = "/register" >
< h1 className = "title" > Register New Account < / h 1 >
< Register isLoggedIn = { username !== undefined } setLoginPanelUpdate = { setLoginPanelUpdate } / >
< / R o u t e >
< Route path = "/streampanel" >
< h1 className = "title" > Stream Panel < / h 1 >
< StreamPanel songs = { songs } setUserSettings = { setUserSettings } userSettings = { userSettings } isLoggedIn = { username !== undefined } setLoginPanelUpdate = { setLoginPanelUpdate } / >
< / R o u t e >
< Route path = "/stream" >
< h1 className = "title" > Stream < / h 1 >
< StreamData / >
< / R o u t e >
< Route path = "/event" >
< h1 className = "title" > Event Data < / h 1 >
< EventData / >
< / R o u t e >
< Route path = "/eventedit" >
< h1 className = "title" > Event Editor < / h 1 >
< EventEditor / >
< / R o u t e >
< Route path = "/cancount" >
< h1 className = "title" > Can or no Can ? < / h 1 >
< CanEditor / >
< / R o u t e >
< Route path = "/" >
< h1 className = "title" > Project DivaR < / h 1 >
Welcome ! This website is here to store and track all your Project Diva records for yours and others ' enjoyment !
< div className = "pt-4 d-flex justify-content-center" >
< Carousel
className = "d-block w-75" >
< Carousel . Item >
< img
className = "d-block w-100"
src = "http://projectdivar.com/files/slide1.png"
alt = "First slide"
/ >
< Carousel . Caption >
< h1 className = "superglow" > Project Diva Records < / h 1 >
< p className = "superglow" > A home for all your best plays . < / p >
< / C a r o u s e l . C a p t i o n >
< / C a r o u s e l . I t e m >
< Carousel . Item >
< img
className = "d-block w-100"
src = "http://projectdivar.com/files/slide2.png"
alt = "Third slide"
/ >
< Carousel . Caption >
< h1 className = "superglow" > Statistics < / h 1 >
< p className = "superglow" > Keep track of your all - time stats . < / p >
< / C a r o u s e l . C a p t i o n >
< / C a r o u s e l . I t e m >
< Carousel . Item >
< img
className = "d-block w-100"
src = "http://projectdivar.com/files/slide3.png"
alt = "Third slide"
/ >
< Carousel . Caption >
< h1 className = "superglow" > Progression Tracking < / h 1 >
< p className = "superglow" > Watch as you improve and become greater over time . < / p >
< / C a r o u s e l . C a p t i o n >
< / C a r o u s e l . I t e m >
< Carousel . Item >
< img
className = "d-block w-100"
src = "http://projectdivar.com/files/slide4.png"
alt = "Third slide"
/ >
< Carousel . Caption >
< h1 className = "superglow" > Many Ways to Submit < / h 1 >
< p className = "superglow" > Submit your scores by screenshots , Twitter , DivaBot , or streaming . < / p >
< / C a r o u s e l . C a p t i o n >
< / C a r o u s e l . I t e m >
< / C a r o u s e l >
< / d i v >
< hr / >
< h3 > Support < / h 3 >
< Card className = "mt-4" body >
< div className = "border rounded p-2 mt-4" style = { { backgroundColor : "#eeeeee" } } >
< div className = "row" >
< div className = "col-md-12" >
< img className = "mr-2 rounded" style = { { float : "left" } } src = "http://projectdivar.com/files/mega39s.png" / >
< h5 > Project Diva Megamix < / h 5 >
< div className = "row rounded" >
< div className = "col-md-3" >
< b > Image Submission : < /b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/ >
< / d i v >
< div className = "col-md-3" >
< b > Twitter : < /b> <IMAGE_X style={{color:"maroon"}}/ > < i > Twitter bot is currently suspended < / i >
< / d i v >
< div className = "col-md-3" >
< b > DivaBot : < /b> <IMAGE_EXCLAMATION style={{color:"orange"}}/ > < i > Megamix detection may require adjusting . < / i >
< / d i v >
< div className = "col-md-3" >
< b > Manual : < /b> <IMAGE_X style={{color:"maroon"}}/ >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< div className = "border rounded p-2 mt-4" style = { { backgroundColor : "#eeeeee" } } >
< div className = "row" >
< div className = "col-md-12" >
< img className = "mr-2 rounded" style = { { float : "left" } } src = "http://projectdivar.com/files/mixmode.png" / >
< h5 > Project Diva Megamix Mix Mode < / h 5 >
< div className = "row rounded" >
< div className = "col-md-3" >
< b > Image Submission : < /b> <IMAGE_X style={{color:"maroon"}}/ >
< / d i v >
< div className = "col-md-3" >
< b > Twitter : < /b> <IMAGE_X style={{color:"maroon"}}/ >
< / d i v >
< div className = "col-md-3" >
< b > DivaBot : < /b> <IMAGE_X style={{color:"maroon"}}/ >
< / d i v >
< div className = "col-md-3" >
< b > Manual : < /b> <IMAGE_X style={{color:"maroon"}}/ >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< div className = "border rounded p-2 mt-4" style = { { backgroundColor : "#eeeeee" } } >
< div className = "row" >
< div className = "col-md-12" >
< img className = "mr-2 rounded" style = { { float : "left" } } src = "http://projectdivar.com/files/futuretone.png" / >
< h5 > Project Diva Future Tone < / h 5 >
< div className = "row rounded" >
< div className = "col-md-3" >
< b > Image Submission : < /b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/ >
< / d i v >
< div className = "col-md-3" >
< b > Twitter : < /b> <IMAGE_X style={{color:"maroon"}}/ > < i > Twitter bot is currently suspended < / i >
< / d i v >
< div className = "col-md-3" >
< b > DivaBot : < /b> <IMAGE_EXCLAMATION style={{color:"orange"}}/ > < i > The newest FT DLC is not compatible < / i >
< / d i v >
< div className = "col-md-3" >
< b > Stream Monitor : < /b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/ >
< / d i v >
< div className = "col-md-3" >
< b > Manual : < /b> <IMAGE_X style={{color:"maroon"}}/ >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / C a r d >
< / R o u t e >
< / S w i t c h >
< / d i v >
< / d i v >
) ;
}
/ * w i n d o w . o n m o u s e m o v e = f u n c t i o n ( e ) {
var obj = document . getElementById ( "display-tooltip" )
if ( obj != null ) {
//var offset = obj.parentElement.getBoundingClientRect();
var tipDist = 15 ;
obj . style . top = ( e . clientY + tipDist ) + 'px' ;
obj . style . left = ( e . clientX + tipDist ) + 'px' ;
}
} * /
function App ( ) {
return (
< Router >
< div className = "container-fluid content" >
< div className = "row" >
< div className = "topbar col-md-12 pt-1 overflow-hidden border rounded text-center" >
< div >
< Link to = "/" >
< Logo / >
< / L i n k >
< / d i v >
< / d i v >
< / d i v >
< Website / >
< / d i v >
< / R o u t e r >
)
}
export default App ;