diff --git a/judge/boring_avatars/__init__.py b/judge/boring_avatars/__init__.py new file mode 100644 index 000000000..5bfcd6736 --- /dev/null +++ b/judge/boring_avatars/__init__.py @@ -0,0 +1,8 @@ +from judge.boring_avatars.avatar import Avatar +from judge.boring_avatars.avatar_bauhaus import AvatarBauhaus +from judge.boring_avatars.avatar_beam import AvatarBeam +from judge.boring_avatars.avatar_marble import AvatarMarble +from judge.boring_avatars.avatar_pixel import AvatarPixel +from judge.boring_avatars.avatar_ring import AvatarRing +from judge.boring_avatars.avatar_sunset import AvatarSunset +from judge.boring_avatars.utilities import AvatarProperties diff --git a/judge/boring_avatars/avatar.py b/judge/boring_avatars/avatar.py new file mode 100644 index 000000000..10d4f1a5b --- /dev/null +++ b/judge/boring_avatars/avatar.py @@ -0,0 +1,23 @@ +from judge.boring_avatars.avatar_bauhaus import AvatarBauhaus +from judge.boring_avatars.avatar_beam import AvatarBeam +from judge.boring_avatars.avatar_marble import AvatarMarble +from judge.boring_avatars.avatar_pixel import AvatarPixel +from judge.boring_avatars.avatar_ring import AvatarRing +from judge.boring_avatars.avatar_sunset import AvatarSunset + +DEFAULT_GENRE = 'beam' +MATCH_GENRE_FROM_STRING = { + 'bauhaus': AvatarBauhaus, + 'beam': AvatarBeam, + 'marble': AvatarMarble, + 'pixel': AvatarPixel, + 'ring': AvatarRing, + 'sunset': AvatarSunset, +} + + +def Avatar(props): + if props.genre not in MATCH_GENRE_FROM_STRING: + props.genre = DEFAULT_GENRE + avatar = MATCH_GENRE_FROM_STRING[props.genre] + return avatar(props) diff --git a/judge/boring_avatars/avatar_bauhaus.py b/judge/boring_avatars/avatar_bauhaus.py new file mode 100644 index 000000000..cf78a167f --- /dev/null +++ b/judge/boring_avatars/avatar_bauhaus.py @@ -0,0 +1,100 @@ +import random + +from judge.boring_avatars.utilities import getBoolean, getRandomColor, getUnit, hashCode + +ELEMENTS = 4 +SIZE = 80 + + +def generateColors(name, colors): + numFromName = hashCode(name) + colorRange = len(colors) if colors else None + + elementsProperties = [ + { + 'color': getRandomColor(numFromName + i, colors, colorRange), + 'translateX': getUnit(numFromName * (i + 1), SIZE / 2 - (i + 17), 1), + 'translateY': getUnit(numFromName * (i + 1), SIZE / 2 - (i + 17), 2), + 'rotate': getUnit(numFromName * (i + 1), 360), + 'isSquare': getBoolean(numFromName, 2), + } + for i in range(ELEMENTS) + ] + + return elementsProperties + + +def AvatarBauhaus(props): + properties = generateColors(props.name, props.colors) + maskID = random.randrange(10**9, 10**10 - 1) + + svg = f""" + + """ + + return svg diff --git a/judge/boring_avatars/avatar_beam.py b/judge/boring_avatars/avatar_beam.py new file mode 100644 index 000000000..59c166315 --- /dev/null +++ b/judge/boring_avatars/avatar_beam.py @@ -0,0 +1,108 @@ +import random +from types import SimpleNamespace + +from judge.boring_avatars.utilities import getBoolean, getContrast, getRandomColor, getUnit, hashCode + +SIZE = 36 + + +def generateData(name, colors): + numFromName = hashCode(name) + colorRange = len(colors) if colors else None + wrapperColor = getRandomColor(numFromName, colors, colorRange) + preTranslateX = getUnit(numFromName, 10, 1) + wrapperTranslateX = preTranslateX + SIZE / 9 if preTranslateX < 5 else preTranslateX + preTranslateY = getUnit(numFromName, 10, 2) + wrapperTranslateY = preTranslateY + SIZE / 9 if preTranslateY < 5 else preTranslateY + + data = SimpleNamespace( + wrapperColor=wrapperColor, + faceColor=getContrast(wrapperColor), + backgroundColor=getRandomColor(numFromName + 13, colors, colorRange), + wrapperTranslateX=wrapperTranslateX, + wrapperTranslateY=wrapperTranslateY, + wrapperRotate=getUnit(numFromName, 360), + wrapperScale=1 + getUnit(numFromName, SIZE // 12) / 10, + isMouthOpen=getBoolean(numFromName, 2), + isCircle=getBoolean(numFromName, 1), + eyeSpread=getUnit(numFromName, 5), + mouthSpread=getUnit(numFromName, 3), + faceRotate=getUnit(numFromName, 10, 3), + faceTranslateX=wrapperTranslateX / 2 if wrapperTranslateX > SIZE / 6 else getUnit(numFromName, 8, 1), + faceTranslateY=wrapperTranslateY / 2 if wrapperTranslateY > SIZE / 6 else getUnit(numFromName, 7, 2), + ) + + return data + + +def AvatarBeam(props): + data = generateData(props.name, props.colors) + maskID = random.randrange(10**9, 10**10 - 1) + + svg = f""" + + """ + + return svg diff --git a/judge/boring_avatars/avatar_marble.py b/judge/boring_avatars/avatar_marble.py new file mode 100644 index 000000000..18c6c8ec7 --- /dev/null +++ b/judge/boring_avatars/avatar_marble.py @@ -0,0 +1,78 @@ +import random +from types import SimpleNamespace + +from judge.boring_avatars.utilities import getRandomColor, getUnit, hashCode + +ELEMENTS = 3 +SIZE = 80 + + +def GenerateColors(name, colors): + numFromName = hashCode(name) + colorRange = len(colors) if colors else 0 + + properties = [ + SimpleNamespace( + color=getRandomColor(numFromName + i, colors, colorRange), + translateX=getUnit(numFromName * (i + 1), SIZE // 10, 1), + translateY=getUnit(numFromName * (i + 1), SIZE // 10, 2), + scale=1.2 + getUnit(numFromName * (i + 1), SIZE // 20) / 10, + rotate=getUnit(numFromName * (i + 1), 360, 1), + ) + for i in range(ELEMENTS) + ] + + return properties + + +def AvatarMarble(props): + properties = GenerateColors(props.name, props.colors) + maskID = random.randrange(10**9, 10**10 - 1) + + svg = f""" + + """ + + return svg diff --git a/judge/boring_avatars/avatar_pixel.py b/judge/boring_avatars/avatar_pixel.py new file mode 100644 index 000000000..061792012 --- /dev/null +++ b/judge/boring_avatars/avatar_pixel.py @@ -0,0 +1,115 @@ +import random + +from judge.boring_avatars.utilities import getRandomColor, hashCode + +ELEMENTS = 64 +SIZE = 80 + + +def GenerateColors(name, colors): + numFromName = hashCode(name) + colorRange = len(colors) if colors else 0 + + colorsList = [ + getRandomColor(numFromName % (i + 1), colors, colorRange) + for i in range(ELEMENTS) + ] + + return colorsList + + +def AvatarPixel(props): + pixelColors = GenerateColors(props.name, props.colors) + maskID = random.randrange(10**9, 10**10 - 1) + + svg = f""" + + """ + return svg diff --git a/judge/boring_avatars/avatar_ring.py b/judge/boring_avatars/avatar_ring.py new file mode 100644 index 000000000..91b0d421d --- /dev/null +++ b/judge/boring_avatars/avatar_ring.py @@ -0,0 +1,61 @@ +import random + +from judge.boring_avatars.utilities import getRandomColor, hashCode + +SIZE = 90 +COLORS = 5 + + +def generateColors(colors, name): + numFromName = hashCode(name) + range_len = len(colors) if colors else 0 + colorsShuffle = [getRandomColor(numFromName + i, colors, range_len) for i in range(COLORS)] + + colorsList = [ + colorsShuffle[0], + colorsShuffle[1], + colorsShuffle[1], + colorsShuffle[2], + colorsShuffle[2], + colorsShuffle[3], + colorsShuffle[3], + colorsShuffle[0], + colorsShuffle[4], + ] + + return colorsList + + +def AvatarRing(props): + ringColors = generateColors(props.colors, props.name) + maskID = random.randrange(10**9, 10**10 - 1) + + svg = f""" + + """ + + return svg diff --git a/judge/boring_avatars/avatar_sunset.py b/judge/boring_avatars/avatar_sunset.py new file mode 100644 index 000000000..74b0f980a --- /dev/null +++ b/judge/boring_avatars/avatar_sunset.py @@ -0,0 +1,68 @@ +import random +import re + +from judge.boring_avatars.utilities import getRandomColor, hashCode + +ELEMENTS = 4 +SIZE = 80 + + +def generateColors(name, colors): + numFromName = hashCode(name) + range_len = len(colors) if colors else 0 + + colorsList = [getRandomColor(numFromName + i, colors, range_len) for i in range(ELEMENTS)] + return colorsList + + +def AvatarSunset(props): + sunsetColors = generateColors(props.name, props.colors) + name = re.sub(r'\s+', '', props.name) # Removes spaces from name + maskID = random.randrange(10**9, 10**10 - 1) + + svg = f""" + + """ + + return svg diff --git a/judge/boring_avatars/utilities.py b/judge/boring_avatars/utilities.py new file mode 100644 index 000000000..3785c0898 --- /dev/null +++ b/judge/boring_avatars/utilities.py @@ -0,0 +1,61 @@ +import math + + +def hashCode(name): + hash = 0 + for character in name: + hash = (hash << 5) - hash + ord(character) + hash = hash & 0xFFFFFFFF # Ensure it's a 32-bit integer + return abs(hash) + + +def getDigit(number, postion): + return (number // (10 ** postion)) % 10 + + +def getBoolean(number, postion): + return (getDigit(number, postion) % 2) == 0 + + +def getAngle(x, y): + return math.degrees(math.atan2(y, x)) + + +def getUnit(number, range, index=None): + value = number % range + + if index and getBoolean(number, index): + return -value + + return value + + +def getRandomColor(number, colors, range): + return colors[number % range] + + +def getContrast(hexcolor): + if hexcolor.startswith('#'): + hexcolor = hexcolor[1:] + + r = int(hexcolor[0:2], 16) + g = int(hexcolor[2:4], 16) + b = int(hexcolor[4:6], 16) + + yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000 + + return '#000000' if yiq >= 128 else '#FFFFFF' + + +class AvatarProperties: + genre = 'beam' + colors = ['#0A0310', '#49007E', '#FF005B', '#FF7D10', '#FFB238'] + name = 'Sample Name' + title = False + size = 40 + square = False + style = '' + + def __init__(self, **kwargs): + for key, value in kwargs.items(): + setattr(self, key, value) diff --git a/judge/jinja2/__init__.py b/judge/jinja2/__init__.py index ab63aaf9e..2d532f6e5 100644 --- a/judge/jinja2/__init__.py +++ b/judge/jinja2/__init__.py @@ -8,8 +8,8 @@ from judge.highlight_code import highlight_code from judge.user_translations import gettext -from . import (camo, datetime, filesize, format, gravatar, language, markdown, rating, reference, render, social, - spaceless, submission, timedelta) +from . import (boring_avatars, camo, datetime, filesize, format, gravatar, language, markdown, rating, reference, + render, social, spaceless, submission, timedelta) from . import registry registry.function('str', str) diff --git a/judge/jinja2/boring_avatars.py b/judge/jinja2/boring_avatars.py new file mode 100644 index 000000000..bb2f82b3f --- /dev/null +++ b/judge/jinja2/boring_avatars.py @@ -0,0 +1,9 @@ +from django.utils.safestring import mark_safe + +from judge.boring_avatars import Avatar, AvatarProperties +from . import registry + + +@registry.function +def boring_avatars(**kwargs): + return mark_safe('