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";

const REMOTE_ADDR = "http://45.33.13.215:4502";

const axios = require('axios');
const moment = require('moment');

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"/>
	</svg>
	)
}
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"/>
	</svg>
	)
}
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"/>
	</svg>
	)
}
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"/>
	</svg>
	)
}
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"/>
	</svg>
	)
}
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"/>
	</svg>
	)
}
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"/>
	</svg>
	)
}
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"/>
	</svg>
	)
}
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>
	</svg>
	)
}
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>
	</svg>
	)
}

var RATING_cool=new Image();
RATING_cool.src="data:image/png;base64, "
var RATING_fine=new Image();
RATING_fine.src="data:image/png;base64, "
var RATING_safe=new Image();
RATING_safe.src="data:image/png;base64, "
var RATING_sad=new Image();
RATING_sad.src="data:image/png;base64, "
var RATING_worst=new Image();
RATING_worst.src="data:image/png;base64, "

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, "
	notes[1].src="data:image/png;base64, "
	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, "
	var shadownotes=[new Image(),new Image(),new Image(),new Image()]
	shadownotes[0].src="data:image/png;base64, "
	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, "
	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}
				</div>
				<div className="data col-6 col-md-12 text-center">
					{p.data}
				</div>
			</div>
		</div>
	);
}

function StatisticsPanel(p) {
	return (
		<>
			<div className="row">
				<div className="col-md-1"></div>
				<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"></div>
			</div>
		</>
	)
}

function HitCountsPanel(p) {
	return (
		<>
			<div className="row text-center">
				<div className="col-md-1">
				</div>
				<div className="col-md-2 border">
					<div className="row">
						<div className="col-6 col-md-12">
							<img src={RATING_cool.src} height="16"/>
						</div>
						<div className="col-6 col-md-12">
							{p.user.cool}
						</div>
					</div>
				</div>
				<div className="col-md-2 border">
					<div className="row">
						<div className="col-6 col-md-12">
							<img src={RATING_fine.src} height="16"/>
						</div>
						<div className="col-6 col-md-12">
							{p.user.fine}
						</div>
					</div>
				</div>
				<div className="col-md-2 border">
					<div className="row">
						<div className="col-6 col-md-12">
							<img src={RATING_safe.src} height="16"/>
						</div>
						<div className="col-6 col-md-12">
							{p.user.safe}
						</div>
					</div>
				</div>
				<div className="col-md-2 border">
					<div className="row">
						<div className="col-6 col-md-12">
							<img src={RATING_sad.src} height="16"/>
						</div>
						<div className="col-6 col-md-12">
							{p.user.sad}
						</div>
					</div>
				</div>
				<div className="col-md-2 border">
					<div className="row">
						<div className="col-6 col-md-12">
							<img src={RATING_worst.src} height="16"/>
						</div>
						<div className="col-6 col-md-12">
							{p.user.worst}
						</div>
					</div>
				</div>
				<div className="col-md-1">
				</div>
			</div>
		</>
	)
}

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.play.difficulty}</span>
	</>
	);
}

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}%`}
			</Modal.Title>
		  </Modal.Header>
		  <Modal.Body>
			<img src={p.play.src} width={(zoom)?"auto":"100%"} className={(zoom)?"zoomout":"zoomin"} onClick={()=>{setZoom(!zoom)}}/>
		  </Modal.Body></>:<></>}
		</Modal>
	)
}

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</span>:(p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge fc">★FC</span>:<></>)} <Difficulty play={p.play} song={p.song}/> {Math.floor(p.play.score)} pts</div>
						<div className="col-md-3 order-3 order-md-2 text-center border-right align-middle text-nowrap overflow-hidden">{GetDateDisplay()}</div>
						<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}
								</div>
								<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}/>
									:<></>
									}
								</div>
								<div className="col-6 order-2 order-md-3 col-md-3 text-right text-md-left">
									<b>{p.play.percent}%</b>
								</div>
								<div className="col-6 order-2 order-md-3 col-md-2 text-right text-md-left">
								{(p.play.src)?<IMAGE_CAMERA/>:<></>}
								</div>
							</div>
						</div>
					</div>
				</div>
			</div>
			<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</span>:(p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge fc">★FC</span>:<></>)}<Difficulty play={p.play} song={p.song}/></div></div>}
					<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}
						</div>
						<div className="col-4 text-center">
							<b>{p.play.percent}%</b> {(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}/>:<></>}
							<span className="pl-2"/>
							{(p.play.src)?<IMAGE_CAMERA/>:<></>}
							<br/>
							{GetDateDisplay(true)}
						</div>
					</div>
				</div>
			</div>
		</>
		);
	} 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}</span>{((p.play.fine==0&&p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge pfc">✪PFC</span>:(p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge fc">★FC</span>:<></>)}</div>:<></>}
				<div className="col-md-3 text-center border-right align-middle text-nowrap overflow-hidden"><SongName song={p.song}/><span className="tinytime">{GetDateDiff()}</span></div>
				<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}/></div>
				<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"/>
								</div>
								<div className="col-4 col-md-7">
									{p.play.cool}
								</div>
							</div>
						</div>
						<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"/>
								</div>
								<div className="col-4 col-md-7">
									{p.play.safe}
								</div>
							</div></div>
						<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"/>
								</div>
								<div className="col-4 col-md-7">
									{p.play.worst}
								</div>
							</div></div>
						<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"/>
								</div>
								<div className="col-4 col-md-7">
									{p.play.fine}
								</div>
							</div></div>
						<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"/>
								</div>
								<div className="col-4 col-md-7">
									{p.play.sad}
								</div>
							</div></div>
						<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></div>
					</div>
				</div>
			</div>
		</>
		);
	}
}

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></h6>:<div className="spinner-grow text-primary" role="status"><span className="sr-only">Loading...</span></div>
			}
			</div>
		</div>
			</li>
		)
	} 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></h6>:<div className="spinner-grow text-primary" role="status"><span className="sr-only">Loading...</span></div>
			}
			</div>
		</div>
	)
}

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]}/>
				</li>})}
			<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}/>
			</ul>
		</div>
	
	return (
	<>
	<div className="row ml-3 mr-3">
		{content}
	</div>
	</>
	);
}

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>:<></>}
		</span>
	)
}

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>}
		</td>
		<td>
		{(p.song.report.rank>0)?<>{p.song.report.score}</>:""}
		</td>
		<td>
		{(p.song.report.rank>0)?<>{p.song.report.percent}%</>:""}
		</td>
		<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":"")}</>:<></>}</>);setStyle("easy");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.epfccount>0?"✪":p.song.report.efccount>0?"★":""}{p.song.report.ecount}</span>:<></>}
			{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":"")}</>:<></>}</>);setStyle("normal");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.npfccount>0?"✪":p.song.report.nfccount>0?"★":""}{p.song.report.ncount}</span>:<></>}
			{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":"")}</>:<></>}</>);setStyle("hard");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.hpfccount>0?"✪":p.song.report.hfccount>0?"★":""}{p.song.report.hcount}</span>:<></>}
			{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":"")}</>:<></>}</>);setStyle("ex");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.expfccount>0?"✪":p.song.report.exfccount>0?"★":""}{p.song.report.excount}</span>:<></>}
			{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":"")}</>:<></>}</>);setStyle("exex");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.exexpfccount>0?"✪":p.song.report.exexfccount>0?"★":""}{p.song.report.exexcount}</span>:<></>}
			{(visibility)?<span style={{position:"absolute"}} className={"display-tooltip alert alert-dark "+style+"-background"}>{tooltip}</span>:<></>}
		</td>
		<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}/>
			:<></>
			}
		</td>
		</>
	);
}

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}</h5>
			<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}/>
			</div>
		</div>
	</>
	)
}
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}/></td>
					</tr>)
					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}</>:<></>}</>}</span>
				</td>
				<PlayDetail song={p.song}/>
			</tr>
			{expand}
		</>
	)
}

function HasSong(song,user) {
	//console.log(JSON.stringify(song)+"/"+JSON.stringify(user))
	return (song.mega39s&&user.megamix)||
		(song.futuretone&&user.futuretone)
}

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)
	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}/>
		<table className="table table-sm">
			<thead>
				<tr id="headerbar">
					<th scope="col" className={(style)?"scrollingHeader":""}>
						Song Name
					</th>
					<th className={(style)?"scrollingHeader":""}>
						Ranking
					</th>
					<th className={(style)?"scrollingHeader":""}>
						Score
					</th>
					<th className={(style)?"scrollingHeader":""}>
						%
					</th>
					<th className={(style)?"scrollingHeader":""}>
						Play Count
					</th>
					<th className={(style)?"scrollingHeader":""}>
						Mods
					</th>
				</tr>
			</thead>
			<tbody>
				{report.filter((report)=>Object.keys(filter).length==0||report.id in filter).map((song,i)=>{return (HasSong(song,p.user))?<HoverSongName profileUpdate={p.profileUpdate} setModalSrc={p.setModalSrc} setModalVisible={p.setModalVisible} to={song.name} song={song} key={song.id} username={p.username}/>:<></>
				})}
			</tbody>
			<tfoot>
			<tr><td colSpan="8" id="footer" className={(style)?"scrollingFooter":""}>
				<span className="badge badge-primary">Easy</span> <span className="badge badge-info">Normal</span> <span className="badge badge-success">Hard</span> <span className="badge badge-warning">Extreme</span> <span className="badge badge-danger">Extra Extreme</span> <span className="badge badge-light">★ = FC</span>  <span className="badge badge-light">✪ = Perfect FCs</span>
			</td></tr>
			</tfoot>
		</table>
	</>
	);
}

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}</span>
	</>
	)
}


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"/>}
		</div>
	)
}

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}></ImageDisplayer>
			<GamesPanel name="Games" user={user}/>
			<h2>{username+"'s Profile"}</h2>
				{(render)?<>
					{user.playstyle&&user.playstyle.length>0&&
					<div className="row">
						<div className="col-md-4"></div>
						<FavoritePlaystyle playstyle={user.playstyle}/>
						<div className="col-md-4"></div>
					</div>}
					<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"}}/></Link>
					</>
					:<></>
				}
		</>
	);
}

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%"}}/>
				</colgroup>
				<thead>
					<tr>
						<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} label="Username" order="username"/></th>
						<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} setUpdateUsers={setUpdateUsers} label="Rating" order="rating"/></th>
						<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} label="Last Played" order="last_played"/></th>
						<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} label="Play Count" order="playcount"/></th>
						<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} label="FC Count" order="fccount"/></th>
					</tr>
				</thead>
			{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}</Link></td>
						<td className={(isLoading)?"loading":""} className={(isLoading)?"loading":""}>{user.rating}</td>
						<td className={(isLoading)?"loading":""} className={(isLoading)?"loading":""} className={(isLoading)?"loading":""}>{moment(user.last_played).format("ddd, MMM Do h:mm a")}</td>
						<td className={(isLoading)?"loading":""}>{user.playcount}</td>
						<td className={(isLoading)?"loading":""}>{user.fccount}</td>
					</tr>
				</tbody>)}
			</table>
		</>
	);
}

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</h3>
					<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</div>
					</div>
					{(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"></div>
						  <div style={{position:"relative"}}>{fileProgress+"%"}</div>
						</div>
					</>:<>Upload</>}</button> 
				  </div>
				</form>);
		}
	}
}

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")}/>
			</div>
			<div className="p-8">
			<h4>{p.songs[key].name}</h4>{(p.songs[key].romanized_name)?p.songs[key].romanized_name:p.songs[key].english_name}
			</div>
			</div>
			</div>})}</div>:<></>}
			
			More stuff goes here.
		</>
	)
}

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 %</span>
					</label>
					<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.
					</small>
				</div>
			</div>
			</>:<></>)}
		</>
	)
}

function Submit(p) {
	return (
		<div className="row">
			<div className="col-12 col-md-10">
				<Switch>
					<Route path="/submitplay/simple">
						<SimpleUpload songs={p.songs}/>
					</Route>
					<Route path="/submitplay/detail">
						Detailed
					</Route>
					<Route path="/submitplay/switch">
						<h2>Playstation/Nintendo Switch/Twitter Upload</h2>
						Want to upload your scores to the website conveniently? Go to <Link to="/usersettings">Edit Profile Settings</Link> and enter your Twitter username, then follow the steps below!
						<hr/>
						<div className="row mb-4">
							<div className="col-4 m-6">
							<h4>Step 1</h4>
							From your Nintendo Switch Album or Playstation Gallery, select up to 4 results screenshots that you want the DivaRBot to parse.
							</div>
							<div className="col-8 m-6">
							<img width="100%" className="border rounded shadow" src="http://projectdivar.com/files/switch1.png"/>
							</div>
						</div>
						<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"/>
							</div>
							<div className="col-4 m-6">
							<h4>Step 2</h4>
							Make sure to include <b>#divarbot</b> so the bot can find your plays! Then submit and the bot will process them in just a few minutes! Check your scores out after they have been processed.
							</div>
						</div>
					</Route>
					<Route path="/submitplay/image">
						<ImageUpload/>
					</Route>
					<Route path="/submitplay">
						<h2>Select a submission method</h2>
						{false&&<><div className="card">
							<Link smooth to="/submitplay/simple#content" className="nostyle">
								<div className="card-body">
									<h5 className="card-title">Manual Submit</h5>
									<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.</small></p>
								</div>
							</Link>
						</div>
						<br/></>}
						<div className="card">
							<Link smooth to="/submitplay/image#content" className="nostyle">
								<div className="card-body">
									<h5 className="card-title">Image Upload</h5>
									<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.</small></p>
								</div>
							</Link>
						</div>
						<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</h5>
									<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.</small></p>
								</div>
							</Link>
						</div>
						<br/>
						<div className="card">
							<Link smooth to="/streampanel#content" className="nostyle">
								<div className="card-body">
									<h5 className="card-title">Stream Monitoring</h5>
									<p className="card-text">Stream <b>Project Diva Future Tone</b> through your Playstation 4 to submit records!</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.</small></p>
								</div>
							</Link>
						</div>
						<br/>
						<div className="card">
							<Link smooth to="/divabot#content" className="nostyle">
								<div className="card-body">
									<h5 className="card-title">DivaBot</h5>
									<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> that automatically records your results as you play.</small></p>
								</div>
							</Link>
						</div>
					</Route>
				</Switch>
			</div>
		</div>
	)
}

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}></ImageDisplayer>
		{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</Link>
	</>}
	</>
	)
}

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}</h3>}
			{authCodeVisible&&<><h3>We have sent you an email containing your login code!</h3>
			<br/>
			Please submit it to finish the login process.
			</>}
			<Form.Group controlId="formUsername">
				<Form.Label>Username</Form.Label>
				<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.
				</Form.Text>
			</Form.Group>
				{authCodeVisible&&<>
				<div className="row">
				<div className="col-4">
				<Form.Group controlId="formCode">
					<Form.Label>Authentication Code</Form.Label>
					<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.
					</Form.Text>
				</Form.Group>
				</div>
				</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"}
			</Button>
		</Form>
	</>
	)
}

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}</h3>}
			{authCodeVisible&&<><h3>We have sent you an email containing your registration code!</h3>
			<br/>
			Please submit it to finish the registration process.
			</>}
			<Form.Group controlId="formUsername">
				<Form.Label>Username</Form.Label>
				<Form.Control disabled={authCodeVisible} isInvalid={username.length<1||username.includes("/")||username.includes("\\")} onChange={(e)=>{setUsername(e.currentTarget.value)}} placeholder="MikuMiku" value={username} />
			</Form.Group>
			<Form.Group controlId="formEmail">
				<Form.Label>Email Address</Form.Label>
				<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.
				</Form.Text>
			</Form.Group>
				{authCodeVisible&&<>
				<div className="row">
				<div className="col-4">
				<Form.Group controlId="formAuthCode">
					<Form.Label>Authentication Code</Form.Label>
					<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.
					</Form.Text>
				</Form.Group>
				</div>
				</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"}
			</Button>
		</Form>
	</>
	)
}

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</Form.Label> - <b>{playStyle}</b>
		<br/>
		<Button onClick={()=>{setPlayStyle("PS4 Controller")}} onMouseOver={()=>{setPlayStyleHover("PS4 Controller")}} variant={playStyle==="PS4 Controller"?"info":"outline-info"}><IMAGE_CONTROLLER width={36} height={36}/></Button>
		<Button onClick={()=>{setPlayStyle("Joycons")}} onMouseOver={()=>{setPlayStyleHover("Joycons")}} variant={playStyle==="Joycons"?"primary":"outline-primary"}><IMAGE_JOYCONS width={36} height={36}/></Button>
		<Button onClick={()=>{setPlayStyle("Mix Mode")}} onMouseOver={()=>{setPlayStyleHover("Mix Mode")}} variant={playStyle==="Mix Mode"?"secondary":"outline-secondary"}><IMAGE_MIXMODE width={36} height={36}/></Button>
		<Button onClick={()=>{setPlayStyle("Arcade Controller")}} onMouseOver={()=>{setPlayStyleHover("Arcade Controller")}} variant={playStyle==="Arcade Controller"?"success":"outline-success"}><IMAGE_ARCADE width={36} height={36}/></Button>
		<Button onClick={()=>{setPlayStyle("Touch Screen")}} onMouseOver={()=>{setPlayStyleHover("Touch Screen")}} variant={playStyle==="Touch Screen"?"warning":"outline-warning"}><IMAGE_TABLET width={36} height={36}/></Button>
		<Form.Text className="text-muted">
		{playStyleHover?<>Change playstyle to <b>{playStyleHover}</b></>:<>Your playstyle will be included in your submitted plays.</>}
		</Form.Text>
	</Form.Group>
	<hr/>
	<Form.Group controlId="twitter">
		<Form.Label>Twitter Username:</Form.Label>
		<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> (with "#divarbot" in the message) and your plays will auto-submit from Twitter at any time.
		</Form.Text>
	</Form.Group>
	<Form.Group controlId="twitch">
		<Form.Label className="pt-4">Twitch Username:</Form.Label>
		<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</Link>.
		</Form.Text>
	</Form.Group>
	<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</Button>
	{message&&<h3 style={{color:"green"}}>{message}</h3>}
	{error&&<h3 style={{color:"red"}}>{error}</h3>}
	<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> is used for verifying your identity when using apps such as <b>DivaBot</b>. By clicking the <b>{"<Reveal Code>"}</b> button, you understand that you should not share this code or show it to anyone!
	<br/><br/>
	{showAuthCode?
		<input readOnly value={authToken}></input>
		:<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>"}
		</button>
	}
	</>)
}

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]}
		</li>
		)}
		</ul>
	</>
	)
}

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</Badge> <Badge variant="success" pill>BUGGED</Badge> <b>DO NOT USE!</b></>],
	["01A","http://projectdivar.com/files/releases/DivaBot01A.zip","13 Sep 2020",<><IMAGE_BUG/> <Badge variant="warning" pill>Incompatible</Badge> <Badge variant="success" pill>BUGGED</Badge> <b>DO NOT USE!</b> <i>Speed Improvements</i></>],
	["01","http://projectdivar.com/files/releases/DivaBot01.zip","13 Sep 2020",<><IMAGE_BUG/> <Badge variant="warning" pill>Incompatible</Badge> <Badge variant="success" pill>BUGGED</Badge> <b>DO NOT USE!</b> <i>Initial Release</i></>]
	]
	
	return (
	<>
		<b>DivaBot</b> was created by <b>sigonasr2</b> in order to allow Project Diva streamers to personalize their stream setups with their personal scores and achievements into their game.
		
		<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> and <b>Future Tone</b>. Other games will be supported in the future.
		<hr/>
		<h3>Setup Instructions</h3>
		{<iframe width="100%" height="480" src="https://www.youtube.com/embed/IAPpbp5EFto" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>}
		<hr/>
		<h3>Downloads</h3>
		<ReleaseList releases={releases}/>
		<hr/>
		<h3>Repository - Open Source Software</h3>
		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> server (<b>@sigonasr2</b>).
		<hr/>
		<h3>Incompatible Downloads</h3>
		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> stream of <b>Project Diva Future Tone</b>. Read the instructions below before using this tool for the first time to properly set it up.
				<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>}</h3>
				{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</Button>
				:monitor==="LOADING"?<Button disabled><Spinner animation="border" size="sm"/> Checking Status...</Button>
				:
				<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</Button>
					</div>
					<div className="col-4">
						{image}
					</div>
					<div className="col-6">
						<RecentPlays username={p.userSettings.username} songs={p.songs}/>
					</div>
				</div>
				}
				</Card>
				<h4 className="pt-4">Prerequisite</h4>
				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</h2>
				<div className="row">
					<div className="col-md-6">
						While on the game's <b>Main Menu</b>, select the <b>SHARE</b> button on your PS4.
					</div>
				</div>
				<h2 className="pt-4">Step 2</h2>
				<div className="row">
					<div className="col-md-6">
					Setup your broadcasting settings and make sure you select <b>720p - High (60fps)</b> for best results. (Selecting a lower resolution will likely not work)
					</div>
					<div className="col-md-6">
						<img style={{height:"320px"}} src="http://projectdivar.com/files/ps4startstream.png"/>
					</div>
				</div>
				<h2 className="pt-4">Step 3</h2>
				<div className="row">
					<div className="col-md-6">
						Once you are broadcasting on PS4, click the <b>Start Stream Monitor</b> button and let it calibrate your screen.
					</div>
				</div>
				<h2 className="pt-4">Step 4</h2>
				<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)
					</div>
				</div>
				<hr/>
				<h2 className="pt-4">Video</h2>
				<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></iframe>}
					</div>
				</div>
			</>
		)
	} else {
		return (
			<>
				You will need to go to your <Link to="/usersettings">Profile Settings</Link> and update your Twitch username before using this feature.
			</>
		)
	}
}

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 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</h3>
					<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>
			</div>
			<div className="col-md-10 pt-3 pb-3">
				<div id="content"/>
				<Switch>
					<Route path="/rankings/:sort/:sortOrder">
						<Rankings/>
					</Route>
					<Route path="/user/:username">
						{(songs)?
						<Profile songs={songs}/>:<></>
						}
					</Route>
					<Route path="/usersettings">
						{
							<UserSettings setUserSettings={setUserSettings} userSettings={userSettings} username={username}/>
						}
					</Route>
					<Route path="/submitplay">
						<Submit songs={songs}/>
					</Route>
					<Route path="/divabot">
						<h1 className="title">DivaBot</h1>
						<DivaBot/>
					</Route>
					<Route path="/login">
						<h1 className="title">Login to Project DivaR</h1>
						<Login isLoggedIn={username!==undefined} setLoginPanelUpdate={setLoginPanelUpdate}/>
					</Route>
					<Route path="/register">
						<h1 className="title">Register New Account</h1>
						<Register isLoggedIn={username!==undefined} setLoginPanelUpdate={setLoginPanelUpdate}/>
					</Route>
					<Route path="/streampanel">
						<h1 className="title">Stream Panel</h1>
						<StreamPanel songs={songs} setUserSettings={setUserSettings} userSettings={userSettings} isLoggedIn={username!==undefined} setLoginPanelUpdate={setLoginPanelUpdate}/>
					</Route>
					<Route path="/stream">
						<h1 className="title">Stream</h1>
						<StreamData/>
					</Route>
					<Route path="/">
						<h1 className="title">Project DivaR</h1>
						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</h1>
								  <p className="superglow">A home for all your best plays.</p>
								</Carousel.Caption>
							  </Carousel.Item>
							  <Carousel.Item>
								<img
								  className="d-block w-100"
								  src="http://projectdivar.com/files/slide2.png"
								  alt="Third slide"
								/>

								<Carousel.Caption>
								  <h1 className="superglow">Statistics</h1>
								  <p className="superglow">Keep track of your all-time stats.</p>
								</Carousel.Caption>
							  </Carousel.Item>
							  <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</h1>
								  <p className="superglow">Watch as you improve and become greater over time.</p>
								</Carousel.Caption>
							  </Carousel.Item>
							  <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</h1>
								  <p className="superglow">Submit your scores by screenshots, Twitter, DivaBot, or streaming.</p>
								</Carousel.Caption>
							  </Carousel.Item>
							</Carousel>
						</div>
							<hr/>
							<h3>Support</h3>
							<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</h5>
										<div className="row rounded">
											<div className="col-md-3">
												<b>Image Submission: </b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/>
											</div>
											<div className="col-md-3">
												<b>Twitter: </b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/>
											</div>
											<div className="col-md-3">
												<b>DivaBot: </b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/>
											</div>
											<div className="col-md-3">
												<b>Manual: </b> <IMAGE_X style={{color:"maroon"}}/>
											</div>
										</div>
									</div>
								</div>
							</div>
							<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</h5>
										<div className="row rounded">
											<div className="col-md-3">
												<b>Image Submission: </b> <IMAGE_X style={{color:"maroon"}}/>
											</div>
											<div className="col-md-3">
												<b>Twitter: </b> <IMAGE_X style={{color:"maroon"}}/>
											</div>
											<div className="col-md-3">
												<b>DivaBot: </b> <IMAGE_X style={{color:"maroon"}}/>
											</div>
											<div className="col-md-3">
												<b>Manual: </b> <IMAGE_X style={{color:"maroon"}}/>
											</div>
										</div>
									</div>
								</div>
							</div>
							<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</h5>
										<div className="row rounded">
											<div className="col-md-3">
												<b>Image Submission: </b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/>
											</div>
											<div className="col-md-3">
												<b>Twitter: </b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/>
											</div>
											<div className="col-md-3">
												<b>DivaBot: </b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/>
											</div>
											<div className="col-md-3">
												<b>Stream Monitor: </b> <IMAGE_CHECKMARK style={{color:"darkgreen"}}/>
											</div>
											<div className="col-md-3">
												<b>Manual: </b> <IMAGE_X style={{color:"maroon"}}/>
											</div>
										</div>
									</div>
								</div>
							</div>
							</Card>
					</Route>
				</Switch>
			</div>
		</div>
	);
}

/*window.onmousemove = function(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/>
						</Link>
					</div>
				</div>
			</div>
			<Website/>
		</div>
	</Router>
	)
}

export default App;
