Jump to content

Python code to generate Earth-to-Glorantha correspondence chart


PhilHibbs

Recommended Posts

if you are on the Facebooks then you might have seen this recently. Thanks to Ellie for starting it, and @Nick Brooke for improving it.

You will need Python 3, and run pip install svgwrite

Creates a file called YearWheel.svg in the current directory.

The SVG file is a bit of a mess in that it contains construction lines for splitting the circles into seasons and months, which I did in Inkscape by merging the circles into rings, replicating, and then intersecting with the parallelogram cutting shapes. I ran this code several times with sections commented out so that I could group up and composite the various elements with each other.

Quote

import math
import svgwrite

dwg = svgwrite.Drawing('YearWheel.svg')

tau = math.pi * 2

# Draw a centre marker
x_length = 360
x_start_angle = -(tau/4) #  Start at the top
x_lines = 4
for i in range(0,x_lines):
    angle = (tau / x_lines) * i
    endx   = math.sin(angle) * x_length
    endy   = math.cos(angle) * x_length
    dwg.add( dwg.line( (0,0), (endx,endy), stroke='black', stroke_width=0.5, stroke_dasharray=4 ) )

season_radius_inner = 250
season_radius_width = 60
season_radius_inset = 10
season_radius_outset = 80
season_radius_outer = season_radius_inner + season_radius_width
season_week_line_start = 30
season_day_line_start = 36
season_line_end = 10
season_day_font_size = 10
season_name_font_size = 14
season_name_radius = season_radius_outer + 5

year_seasons = 5
season_weeks = 8
sacred_weeks = 2
week_days = 7

gdays = ((year_seasons*season_weeks)+sacred_weeks)*week_days

eq_lines = [(0,"Spring Equinox"),(1,"Summer Solstice"),(2,"Autumn Equinox"),(3,"Winter Solstice")]
eq_offset_days = -6
eq_offset_text = 50
eq_length = 360
for i in eq_lines:
    angle = (tau / gdays) * ((gdays / len(eq_lines) * i[0]) + eq_offset_days)
    #print("angle={}".format(angle))
    endx   =  math.sin(angle) * eq_length
    endy   = -math.cos(angle) * eq_length
    dwg.add( dwg.line( (0,0), (endx,endy), stroke='black', stroke_width=0.5, stroke_dasharray=4 ) )
    textx =  math.sin(angle) * eq_offset_text
    texty = -math.cos(angle) * eq_offset_text
    rot = 'rotate({},{}, {})'.format(math.degrees(angle)-90,textx,texty)
    dwg.add( dwg.text
        ( i[1]
        , insert=(textx,texty)
        , transform=rot
        , style="font-family:Arial;baseline-shift:-33%"
        , font_size="{}px".format(season_name_font_size)
        ) )

# Draw the Gloranthan Seasons inner and outer circles
dwg.add( dwg.circle( (0,0), season_radius_inner, stroke='black', stroke_width=0.5, fill='none' ) )
dwg.add( dwg.circle( (0,0), season_radius_outer, stroke='black', stroke_width=0.5, fill='none' ) )
# These will be merged using the Cut operation, then duplicated once per season and intersected with the cutting shapes

seasons=[("Sea Season",8),("Fire Season",8),("Earth Season",8),("Dark Season",8),("Storm Season",8),("Sacred Time",2)]

# Draw the Gloranthan Seasons cutting shapes
week_count = 0
for s in seasons:
    angle1 = (tau / gdays) * week_days * week_count
    angle2 = (tau / gdays) * week_days * (week_count + s[1])

    a1startx =  math.sin(angle1) * (season_radius_inner - season_radius_inset)
    a1endx   =  math.sin(angle1) * (season_radius_outer + season_radius_outset)
    a1starty = -math.cos(angle1) * (season_radius_inner - season_radius_inset)
    a1endy   = -math.cos(angle1) * (season_radius_outer + season_radius_outset)
    a2startx =  math.sin(angle2) * (season_radius_inner - season_radius_inset)
    a2endx   =  math.sin(angle2) * (season_radius_outer + season_radius_outset)
    a2starty = -math.cos(angle2) * (season_radius_inner - season_radius_inset)
    a2endy   = -math.cos(angle2) * (season_radius_outer + season_radius_outset)

    dwg.add( dwg.polygon( [(a1startx,a1starty), (a1endx,a1endy), (a2endx,a2endy), (a2startx,a2starty)], stroke='black', stroke_width=0.5, fill='none' ) )

    angle_season_name = ( angle1 + angle2 ) / 2
    startx = math.sin(angle_season_name) * season_name_radius
    starty = -math.cos(angle_season_name) * season_name_radius
    rot = 'rotate({},{}, {})'.format(math.degrees(angle_season_name),startx,starty)
    dwg.add( dwg.text
        ( "{}".format(s[0])
        , insert=(startx,starty)
        , transform=rot
        , style="font-family:Arial;text-anchor:middle"
        , font_size="{}px".format(season_name_font_size)
        ) )

    week_count = week_count + s[1]

# Draw the Gloranthan Days and Weeks lines
for i in range(0,gdays):
    angle = (tau / gdays) * i
    #print("angle={}".format(angle))
    if i % 7 == 0:
        startr = season_week_line_start
    else:
        startr = season_day_line_start
    startx = math.sin(angle) * (season_radius_inner + startr)
    endx   = math.sin(angle) * (season_radius_outer - season_line_end)
    starty = -math.cos(angle) * (season_radius_inner + startr)
    endy   = -math.cos(angle) * (season_radius_outer - season_line_end)
    dwg.add( dwg.line( (startx,starty), (endx,endy), stroke='black', stroke_width=1 ) )
    if i % 7 == 0:
        rot = 'rotate({},{}, {})'.format(math.degrees(angle)-90,startx,starty)
        dwg.add( dwg.text( "{}".format(i)
                         , insert=(startx,starty)
                         , transform=rot
                         , style="font-family:Arial;text-anchor:end;baseline-shift:-33%"
                         , font_size="{}px".format(season_day_font_size)
                         ) )

month_tups = [ ("January",31)
             , ("February",28)
             , ("March",31)
             , ("April",30)
             , ("May",31)
             , ("June",30)
             , ("July",31)
             , ("August",31)
             , ("September",30)
             , ("October",31)
             , ("November",30)
             , ("December",31)]
year_days = sum([b for a,b in month_tups])

month_radius_inner = 180
month_radius_width = 60
month_radius_inset = 20
month_radius_outset = 40
month_radius_outer = month_radius_inner + month_radius_width
month_group_line_start = 30
month_half_group_line_start = 32
month_day_line_start = 36
month_line_end = 10
month_day_font_size = 12
month_start_angle = (tau / 360) * -80.64
month_day_group = 10
month_day_half_group = 5
month_name_font_size = 14
month_name_radius = month_radius_inner - 15

month_dash_start_outset = -10
month_dash_start_inset = -35
month_dash_frequency = 1

# Draw the Terrestrial Seasons inner and outer circles
dwg.add( dwg.circle( (0,0), month_radius_inner, stroke='black', stroke_width=0.5, fill='none' ) )
dwg.add( dwg.circle( (0,0), month_radius_outer, stroke='black', stroke_width=0.5, fill='none' ) )
# These will be merged using the Cut operation, then duplicated once per season and intersected with the cutting shapes

if month_radius_outer < season_radius_inner:
    dash_inner = month_radius_outer
    dash_outer = season_radius_inner
else:
    dash_inner = season_radius_outer
    dash_outer = month_radius_inner

month_start=0
for mt in month_tups:
    month_end = month_start + mt[1]
    #print("mt[1]={}".format(mt[1]))
    #print("month_start={}".format(month_start))
    angle_month1 = (tau / year_days) * month_start
    angle_month1 = angle_month1 + month_start_angle
    angle_month2 = (tau / year_days) * month_end
    angle_month2 = angle_month2 + month_start_angle
    for i in range(month_start,month_end):
        angle_day = (tau / year_days) * i
        angle_day = angle_day + month_start_angle
        if i % month_day_group == 0:
            startr = month_group_line_start
        elif i % month_day_half_group == 0:
            startr = month_half_group_line_start
        else:
            startr = month_day_line_start
        startx = math.sin(angle_day) * (month_radius_inner + startr)
        endx   = math.sin(angle_day) * (month_radius_outer - month_line_end)
        starty = -math.cos(angle_day) * (month_radius_inner + startr)
        endy   = -math.cos(angle_day) * (month_radius_outer - month_line_end)
        dwg.add( dwg.line( (startx,starty), (endx,endy), stroke='black', stroke_width=1 ) )
        if i % month_day_group == 0:
            rot = 'rotate({},{}, {})'.format(math.degrees(angle_day)-90,startx,starty)
            dwg.add( dwg.text(
                  "{}".format(i)
                , insert=(startx,starty)
                , transform=rot
                , style="font-family:Arial;text-anchor:end;baseline-shift:-33%"
                , font_size="{}px".format(month_day_font_size)
                ) )
        # Draw dotted lines between the two calendars based on terrestrial days
        if month_dash_frequency > 0 and (i-month_start) % month_dash_frequency == 0:
            angle_day = (tau / year_days) * (i + 0.5)
            angle_day = angle_day + month_start_angle
            startx = math.sin(angle_day) * (dash_inner + month_dash_start_outset)
            endx   = math.sin(angle_day) * (dash_outer - month_dash_start_inset)
            starty = -math.cos(angle_day) * (dash_inner + month_dash_start_outset)
            endy   = -math.cos(angle_day) * (dash_outer - month_dash_start_inset)
            dwg.add( dwg.line( (startx,starty), (endx,endy), stroke='black', stroke_width=0.5, stroke_dasharray=1 ) )
            
        
    a1startx = math.sin(angle_month1) * (month_radius_inner - month_radius_inset)
    a1endx   = math.sin(angle_month1) * (month_radius_outer + month_radius_outset)
    a1starty = -math.cos(angle_month1) * (month_radius_inner - month_radius_inset)
    a1endy   = -math.cos(angle_month1) * (month_radius_outer + month_radius_outset)
    a2startx = math.sin(angle_month2) * (month_radius_inner - month_radius_inset)
    a2endx   = math.sin(angle_month2) * (month_radius_outer + month_radius_outset)
    a2starty = -math.cos(angle_month2) * (month_radius_inner - month_radius_inset)
    a2endy   = -math.cos(angle_month2) * (month_radius_outer + month_radius_outset)

    dwg.add( dwg.polygon( [(a1startx,a1starty), (a1endx,a1endy), (a2endx,a2endy), (a2startx,a2starty ) ], stroke='black', stroke_width=0.5, fill='none' ) )
    
    angle_month_name = ( angle_month1 + angle_month2 ) / 2
    startx = math.sin(angle_month_name) * month_name_radius
    starty = -math.cos(angle_month_name) * month_name_radius
    rot = 'rotate({},{}, {})'.format(math.degrees(angle_month_name),startx,starty)
    dwg.add( dwg.text
        ( "{}".format(mt[0])
        , insert=(startx,starty)
        , transform=rot
        , style="font-family:Arial;text-anchor:middle"
        , font_size="{}px".format(month_name_font_size)
        ) )

    month_start = month_end

dwg.save()
 

Final SVG is on the wiki:

https://runequest-glorantha.fandom.com/wiki/File:Calendar_correspondence.svg

Year_Wheel_2.thumb.jpg.f3b493fad00899829555e1f4d436c5f0.jpg

Edited by PhilHibbs
  • Like 3
  • Thanks 1
Link to comment
Share on other sites

Cool; I was going to make the tiny change to the code so that it was appropriate for the southern hemisphere, but the original code quoted there does not on my system produce SVG that renders as yours does - I get a white square. The SVG itself is presumably the same.

Edit: Turns out, the SVG produced from the code above is very different from the SVG that can be downloaded.

Edited by jenh
Link to comment
Share on other sites

I can try testing it tomorrow to see if I goofed on pasting the code, but yes the downloadable SVG is different, it has been finished off in Inkscape. The output from this code contains the construction lines, the "cookie cutters" that assist in creating the final image.

 

And there is no screen output, just the file.

Edited by PhilHibbs
Link to comment
Share on other sites

20 hours ago, jenh said:

Edit: Turns out, the SVG produced from the code above is very different from the SVG that can be downloaded.

That's what I meant by "a bit of a mess". If you want to rotate the Earth calendar in the finished SVG, it should be selectable and rotatable as a single object in Inkscape (which is free).

Link to comment
Share on other sites

1 hour ago, d(sqrt(-1)) said:

What's it for? It looks to be stretching a Gloranthan year to a terrestrial year - but why?

It shows the seasonal correspondence, maybe what kind of weather you can expect. And you can figure out where your birthday would fall in the Gloranthan calendar. Also it's prrrdy.

Edited by PhilHibbs
Link to comment
Share on other sites

23 hours ago, PhilHibbs said:

I could fake the orbital eccentricity by just coding in the four cardinal dates and doing a linear squash

Indeed, normally a linear squash would leave notable transition between the 4 sections, but an error of 2 days is only about 2%, so I don't think anyone will see. 

And I've convinced myself that this is indeed all to do with the Earth's elliptical orbit.

Link to comment
Share on other sites

Ok I've done some research* and here's the fixed version.

Quote

import svgwrite
from math import pi, sin, cos, radians, degrees
from datetime import timedelta, date

def xy(angle,dist):
    return((sin(angle) * dist,-cos(angle) * dist))

draw_year=1966
base_day = date(year=draw_year, month=1, day=1)
leap_year=(draw_year%4==0)

"""
 Approx Sun ecliptic latitude

 Prints daily positions for a year.
 For dates between 1950 and 2050,
 it should be accurate to within
 0.01 degrees. For details, see
 https://en.wikipedia.org/wiki/Position_of_the_Sun#Ecliptic_coordinates

 Written by PM 2Ring 2020.12.6
 https://astronomy.stackexchange.com/a/40243/37174
"""

# Approximate solar ecliptic longitude
# Uses day zero = Noon UTC, 1 Jan 2000
# so we subtract half a day
def eclat_approx(n):
    n -= 0.5
    L = 280.46 + 0.9856474 * n
    g = 357.528 + 0.9856003 * n
    gr = radians(g)
    el = L + 1.915 * sin(gr) + 0.020 * sin(2 * gr)
    return el % 360

day_zero = date(year=2000, month=1, day=1)

draw_eqlines = True
draw_eqnames = True
draw_seasoncircle = True
draw_seasoncutters = True
draw_seasonnames = True
draw_gdaylines = True
draw_gdaynumbers = True
draw_monthcircles = True
draw_tdaylines = True
draw_tdaynumbers = True
draw_dottedlines = True
draw_monthcutters = True
draw_monthnames = True

dwg = svgwrite.Drawing('YearWheel0.svg')

tau = pi * 2

season_radius_inner = 250
season_radius_width = 60
season_radius_inset = 10
season_radius_outset = 80
season_radius_outer = season_radius_inner + season_radius_width
season_week_line_start = 30
season_day_line_start = 36
season_line_end = 10
season_day_font_size = 10
season_name_font_size = 14
season_name_radius = season_radius_outer + 5

year_seasons = 5
season_weeks = 8
sacred_weeks = 2
week_days = 7

gdays = ((year_seasons*season_weeks)+sacred_weeks)*week_days

eq_lines = [(0,"Spring Equinox"),(1,"Summer Solstice"),(2,"Autumn Equinox"),(3,"Winter Solstice")]
eq_offset_days = -6
eq_offset_text = 50
eq_length = 320
eq_offset_angle = (tau / gdays) * eq_offset_days

for i in eq_lines:
    angle = (tau / gdays) * ((gdays / len(eq_lines) * i[0])) + eq_offset_angle
    #print("angle={}".format(angle))
    (endx,endy)=xy(angle,eq_length)
    if draw_eqlines:
        dwg.add( dwg.line( (0,0), (endx,endy), stroke='black', stroke_width=0.5, stroke_dasharray=4 ) )
    if draw_eqnames:
        textx,texty = xy(angle,eq_offset_text)
        rot = 'rotate({},{}, {})'.format(degrees(angle)-90,textx,texty)
        dwg.add( dwg.text
            ( i[1]
            , insert=(textx,texty)
            , transform=rot
            , style="font-family:Arial;baseline-shift:-33%"
            , font_size="{}px".format(season_name_font_size)
            ) )

# Draw the Gloranthan Seasons inner and outer circles
if draw_seasoncircle:
    dwg.add( dwg.circle( (0,0), season_radius_inner, stroke='black', stroke_width=0.5, fill='none' ) )
    dwg.add( dwg.circle( (0,0), season_radius_outer, stroke='black', stroke_width=0.5, fill='none' ) )
# These will be merged using the Cut operation, then duplicated once per season and intersected with the cutting shapes

seasons=[("Sea Season",8),("Fire Season",8),("Earth Season",8),("Dark Season",8),("Storm Season",8),("Sacred Time",2)]

# Draw the Gloranthan Seasons cutting shapes
week_count = 0
for s in seasons:
    angle1 = (tau / gdays) * week_days * week_count
    angle2 = (tau / gdays) * week_days * (week_count + s[1])

    (a1startx,a1starty) = xy(angle1,season_radius_inner - season_radius_inset)
    (a1endx,a1endy)     = xy(angle1,season_radius_outer + season_radius_outset)
    (a2startx,a2starty) = xy(angle2,season_radius_inner - season_radius_inset)
    (a2endx,a2endy)     = xy(angle2,season_radius_outer + season_radius_outset)
    
    if draw_seasoncutters:
        dwg.add( dwg.polygon( [(a1startx,a1starty), (a1endx,a1endy), (a2endx,a2endy), (a2startx,a2starty)], stroke='black', stroke_width=0.5, fill='none' ) )

    angle_season_name = ( angle1 + angle2 ) / 2
    (startx,starty) = xy(angle_season_name,season_name_radius)
    rot = 'rotate({},{}, {})'.format(degrees(angle_season_name),startx,starty)
    if draw_seasonnames:
        dwg.add( dwg.text
            ( "{}".format(s[0])
            , insert=(startx,starty)
            , transform=rot
            , style="font-family:Arial;text-anchor:middle"
            , font_size="{}px".format(season_name_font_size)
            ) )

    week_count = week_count + s[1]

# Draw the Gloranthan Days and Weeks lines
for i in range(0,gdays):
    angle = (tau / gdays) * i
    #print("angle={}".format(angle))
    if i % 7 == 0:
        startr = season_week_line_start
    else:
        startr = season_day_line_start
    (startx,starty) = xy(angle,season_radius_inner + startr)
    (endx,endy)     = xy(angle,season_radius_outer - season_line_end)
    if draw_gdaylines:
        dwg.add( dwg.line( (startx,starty), (endx,endy), stroke='black', stroke_width=1 ) )
    if draw_gdaynumbers:
        if i % 7 == 0:
            rot = 'rotate({},{}, {})'.format(degrees(angle)-90,startx,starty)
            dwg.add( dwg.text( "{}".format(i)
                             , insert=(startx,starty)
                             , transform=rot
                             , style="font-family:Arial;text-anchor:end;baseline-shift:-33%"
                             , font_size="{}px".format(season_day_font_size)
                             ) )

month_tups = [ ("January",31)
             , ("February",29 if leap_year else 28)
             , ("March",31)
             , ("April",30)
             , ("May",31)
             , ("June",30)
             , ("July",31)
             , ("August",31)
             , ("September",30)
             , ("October",31)
             , ("November",30)
             , ("December",31)]
year_days = sum([b for a,b in month_tups])

month_radius_inner = 180
month_radius_width = 60
month_radius_inset = 20
month_radius_outset = 40
month_radius_outer = month_radius_inner + month_radius_width
month_group_line_start = 30
month_half_group_line_start = 32
month_day_line_start = 36
month_line_end = 10
month_day_font_size = 12
month_start_angle = -(tau / gdays) * 6 - (tau / 4)
month_day_group = 7
month_day_half_group = 7
month_name_font_size = 14
month_name_radius = month_radius_inner - 15

month_dash_start_outset = -10
month_dash_start_inset = -35
month_dash_frequency = 1

# Draw the Terrestrial Months inner and outer circles
if draw_monthcircles:
    dwg.add( dwg.circle( (0,0), month_radius_inner, stroke='black', stroke_width=0.5, fill='none' ) )
    dwg.add( dwg.circle( (0,0), month_radius_outer, stroke='black', stroke_width=0.5, fill='none' ) )
# These will be merged using the Cut operation, then duplicated once per season and intersected with the cutting shapes

if month_radius_outer < season_radius_inner:
    dash_inner = month_radius_outer
    dash_outer = season_radius_inner
else:
    dash_inner = season_radius_outer
    dash_outer = month_radius_inner

month_start = 0
m = 0
for mt in month_tups:
    month_end = month_start + mt[1]
    #print("mt[1]={}".format(mt[1]))
    #print("month_start={}".format(month_start))
    day = date(year=draw_year, month=m+1, day=1)
    d = (day - day_zero).days
    angle_month1 = radians(eclat_approx(d))
    angle_month1 = angle_month1 + eq_offset_angle
    day = date(year=draw_year, month=((m+1)%12)+1, day=1)
    d = (day - day_zero).days
    angle_month2 = radians(eclat_approx(d))
    angle_month2 = angle_month2 + eq_offset_angle
    for i in range(0,mt[1]):
        day = date(year=draw_year, month=m+1, day=i+1)
        d = (day - day_zero).days
        angle_day = eclat_approx(d) # (tau / year_days) * ((i + month_start) + 0.5)
        angle_day = radians(angle_day)
        angle_day = angle_day + eq_offset_angle
        if i % month_day_group == 0:
            startr = month_group_line_start
        elif i % month_day_half_group == 0:
            startr = month_half_group_line_start
        else:
            startr = month_day_line_start
        (startx,starty) = xy(angle_day,month_radius_inner + startr)
        (endx,endy)     = xy(angle_day,month_radius_outer - month_line_end)
        if draw_tdaylines:
            dwg.add( dwg.line( (startx,starty), (endx,endy), stroke='black', stroke_width=1 ) )
        # Print the day number just before the division
        if i % month_day_group == month_day_group-1:
            angle_day = angle_day - (tau/year_days/2)
            rot = 'rotate({},{}, {})'.format(degrees(angle_day)-90,startx,starty)
            if draw_tdaynumbers:
                dwg.add( dwg.text(
                      "{}".format(i+1)
                    , insert=(startx,starty)
                    , transform=rot
                    , style="font-family:Arial;text-anchor:end;baseline-shift:-33%"
                    , font_size="{}px".format(month_day_font_size)
                    ) )
        # Draw dotted lines between the two calendars based on terrestrial days
        if month_dash_frequency > 0 and i % month_dash_frequency == 0:
            day = date(year=draw_year, month=m+1, day=i+1)
            d = (day - day_zero).days
            angle_day = radians(eclat_approx(d)) # (tau / year_days) * ((i + month_start) + 0.5)
            angle_day = angle_day + (tau/year_days/2)
            angle_day = angle_day + eq_offset_angle
            (startx,starty) = xy(angle_day,dash_inner + month_dash_start_outset)
            (endx,endy)     = xy(angle_day,dash_outer - month_dash_start_inset)
            if draw_dottedlines:
                dwg.add( dwg.line( (startx,starty), (endx,endy), stroke='black', stroke_width=0.5, stroke_dasharray=1 ) )
        
    (a1startx,a1starty) = xy(angle_month1,month_radius_inner - month_radius_inset)
    (a1endx,a1endy)     = xy(angle_month1,month_radius_outer + month_radius_outset)
    (a2startx,a2starty) = xy(angle_month2,month_radius_inner - month_radius_inset)
    (a2endx,a2endy)     = xy(angle_month2,month_radius_outer + month_radius_outset)

    if draw_monthcutters:
        dwg.add( dwg.polygon( [(a1startx,a1starty), (a1endx,a1endy), (a2endx,a2endy), (a2startx,a2starty ) ], stroke='black', stroke_width=0.5, fill='none' ) )
    
    angle_month_name = ( angle_month1 + (angle_month2 if angle_month2 > angle_month1 else angle_month2+tau )) / 2
    (startx,starty) = xy(angle_month_name,month_name_radius)
    rot = 'rotate({},{}, {})'.format(degrees(angle_month_name),startx,starty)
    if draw_monthnames:
        dwg.add( dwg.text
            ( "{}".format(mt[0])
            , insert=(startx,starty)
            , transform=rot
            , style="font-family:Arial;text-anchor:middle"
            , font_size="{}px".format(month_name_font_size)
            ) )

    month_start = month_end
    m = m + 1

dwg.save()

 

I will post the images in the other thread.

*  I asked on stackexchange and someone gave me the code

Edited by PhilHibbs
  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...