Skip to content

Commit 38ddbdf

Browse files
committed
Conform new structure
1 parent 5c6f8aa commit 38ddbdf

11 files changed

Lines changed: 311 additions & 47 deletions

_layouts/conference.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ <h1>
8686
</div>
8787
<div id="page-content">
8888
<div id="conf-deadline-timer" class="row">
89-
<div id="cfp-timer" class="col-12 conf-timer">{% if page.cfp == "TBA" %}TBA{%endif%}
89+
<div id="cfp-timer" class="col-12 conf-timer">{% if page.cfp == "TBA" %}TBA{% elsif cfp == "Cancelled" %}Cancelled{%endif%}
9090
</div>
9191
</div>
9292
<div id="conf-key-facts" class="row">
@@ -204,6 +204,10 @@ <h1>
204204
$('#cfp-timer').html("TBA");
205205
$('.deadline-time').html("TBA");
206206
$('.deadline-local-time').html("TBA");
207+
{% elsif cfp == "Cancelled" %}
208+
$('#cfp-timer').html("Cancelled");
209+
$('.deadline-time').html("Cancelled");
210+
$('.deadline-local-time').html("Cancelled");
207211
{% else %}
208212

209213
// Use specified timezone for deadlines if available else use AoE timezone

_layouts/summary.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ <h1>
277277
$('#{{conf.conference | slugify}}-{{conf.year}} .timer').html("TBA");
278278
$('#{{conf.conference | slugify}}-{{conf.year}} .deadline-time').html("TBA");
279279
$('#{{conf.conference | slugify}}-{{conf.year}}').attr("cfpDiff", Infinity);
280+
{% elsif cfp == "Cancelled" %}
281+
$('#{{conf.conference | slugify}}-{{conf.year}} .timer').html("Cancelled");
282+
$('#{{conf.conference | slugify}}-{{conf.year}} .deadline-time').html("Cancelled");
283+
$('#{{conf.conference | slugify}}-{{conf.year}}').attr("cfpDiff", Infinity);
280284
{% else %}
281285

282286
// Use specified timezone for deadlines if available else use AoE timezone

_pages/archive.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ <h1 id="past-events-title">Past Events</h1>
191191
$('#{{conf.conference | slugify}}-{{conf.year}} .timer').html("TBA");
192192
$('#{{conf.conference | slugify}}-{{conf.year}} .deadline-time').html("TBA");
193193
$('#{{conf.conference | slugify}}-{{conf.year}}').attr("cfpDiff", Infinity);
194+
{% if cfp == "Cancelled" %}
195+
$('#{{conf.conference | slugify}}-{{conf.year}} .timer').html("Cancelled");
196+
$('#{{conf.conference | slugify}}-{{conf.year}} .deadline-time').html("Cancelled");
197+
$('#{{conf.conference | slugify}}-{{conf.year}}').attr("cfpDiff", Infinity);
194198
{% else %}
195199

196200
// Use specified timezone for deadlines if available else use AoE timezone

index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ <h1 id="archive-link">Visit the <a href="/archive/">Archive</a></h1>
203203
$('#{{conf.conference | slugify}}-{{conf.year}} .timer').html("TBA");
204204
$('#{{conf.conference | slugify}}-{{conf.year}} .deadline-time').html("TBA");
205205
$('#{{conf.conference | slugify}}-{{conf.year}}').attr("cfpDiff", Infinity);
206+
{% elsif cfp == "Cancelled" %}
207+
$('#{{conf.conference | slugify}}-{{conf.year}} .timer').html("Cancelled");
208+
$('#{{conf.conference | slugify}}-{{conf.year}} .deadline-time').html("Cancelled");
209+
$('#{{conf.conference | slugify}}-{{conf.year}}').attr("cfpDiff", Infinity);
206210
{% else %}
207211

208212
// Use specified timezone for deadlines if available else use AoE timezone

utils/date_magic.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33

44

55
dateformat = "%Y-%m-%d %H:%M:%S"
6-
tba_words = ["tba", "tbd"]
6+
tba_words = ["tba", "tbd", "cancelled"]
77

88

99
def clean_dates(data):
10-
10+
1111
# Clean Up Dates
1212
for dates in ["start", "end"]:
1313
if isinstance(data[dates], str):
1414
data[dates] = datetime.datetime.strptime(data[dates], dateformat.split(" ")[0]).date()
15-
16-
# Make deadlines
15+
16+
# Make deadlines
1717
for datetimes in ["cfp", "workshop_deadline", "tutorial_deadline"]:
1818
if datetimes in data and data[datetimes].lower() not in tba_words:
1919
try:
@@ -33,17 +33,17 @@ def suffix(d):
3333
def create_nice_date(data):
3434
if "date" in data and data["date"]:
3535
return data
36-
36+
3737
try:
3838
start = datetime.datetime.strptime(data["start"], dateformat.split(" ")[0])
3939
end = datetime.datetime.strptime(data["end"], dateformat.split(" ")[0])
4040
except TypeError:
4141
start = data["start"]
4242
end = data["end"]
43-
43+
4444
if start == end:
4545
tmp_date = start.strftime("%B %d, %Y")
46-
46+
4747
data["date"] = tmp_date[:-6] + suffix(start.day) + tmp_date[-6:]
4848
elif start.month == end.month:
4949
tmp_date = start.strftime("%B %d, %Y")

utils/import_python_official.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import pandas as pd
2+
from icalendar import Calendar, Event
3+
from datetime import datetime
4+
import pytz
5+
from urllib import request
6+
import re
7+
import yaml
8+
9+
10+
def ics_to_dataframe():
11+
# Open the .ics file and parse it into a Calendar object
12+
with request.urlopen(
13+
"https://www.google.com/calendar/ical/j7gov1cmnqr9tvg14k621j7t5c@group.calendar.google.com/public/basic.ics"
14+
) as file:
15+
calendar = Calendar.from_ical(file.read())
16+
17+
link_desc = re.compile(r".*<a .*?href=\"? ?((?:https|http):\/\/[\w0-9\.\/\-\?= ]+)\"?.*?>(.*?)[#0-9 ]*<\/?a>.*")
18+
19+
# Initialize a list to hold event data
20+
event_data = []
21+
22+
# Iterate over each event in the Calendar
23+
for component in calendar.walk():
24+
if component.name == "VEVENT":
25+
# Extract event details
26+
conference = str(component.get("summary"))
27+
start = component.get("dtstart").dt
28+
end = component.get("dtend").dt
29+
# If the event is all day, the date might be of type 'date' (instead of 'datetime')
30+
# Adjust format accordingly
31+
start = start.strftime("%Y-%m-%d")
32+
end = end.strftime("%Y-%m-%d")
33+
year = start[:4]
34+
35+
description = re.sub(
36+
r"(?:\\s|&nbsp;|\\|\'|<br />|<br>|</[^a][^>]*>|<[^a/][^>]*>)+",
37+
" ",
38+
"<a "
39+
+ "<a ".join(
40+
str(component.get("description"))
41+
.replace("\n", "")
42+
.replace("”", '"')
43+
.replace("“", '"')
44+
.replace("&amp;", "&")
45+
.replace("&quot;", '"')
46+
.replace("&apos;", "'")
47+
.replace("&lt;", "<")
48+
.replace("&gt;", ">")
49+
.split("<a ")[1:]
50+
),
51+
)
52+
53+
try:
54+
m = re.match(link_desc, description)
55+
link = m.group(1).strip()
56+
conference2 = m.group(2).strip()
57+
except AttributeError:
58+
print(m)
59+
print("." + description + " | " + re.escape(str(component.get("description"))) + ".")
60+
continue
61+
62+
if conference2 != "":
63+
conference = conference2
64+
location = str(component.get("location"))
65+
66+
# Append this event's details to the list
67+
event_data.append([conference, year, "TBA", start, end, link, location])
68+
69+
# Convert the list into a pandas DataFrame
70+
df = pd.DataFrame(event_data, columns=["conference", "year", "cfp", "start", "end", "link", "place"])
71+
72+
return df
73+
74+
75+
# Use the function to parse your .ics file
76+
df = ics_to_dataframe()
77+
78+
with open("df.yml", "w") as file:
79+
yaml.dump({"result": df.to_dict(orient="records")}, file, default_flow_style=False)
80+
81+
# Display the DataFrame
82+
print(df)

utils/import_python_organizers.py

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ def load_yml():
3636
return pd.concat(
3737
[schema, pd.DataFrame.from_dict(data), pd.DataFrame.from_dict(archive)],
3838
ignore_index=True,
39-
).set_index("title", drop=False)
39+
).set_index("conference", drop=False)
4040

4141

4242
def map_columns(df, reverse=False):
4343
cols = {
44-
"Subject": "title",
44+
"Subject": "conference",
4545
"Start Date": "start",
4646
"End Date": "end",
4747
"Tutorial Deadline": "tutorial_deadline",
@@ -61,28 +61,30 @@ def map_columns(df, reverse=False):
6161

6262
def fuzzy_match(df_yml, df_remote):
6363
# Make Title the index
64-
df_remote = df_remote.set_index("title", drop=False)
64+
df_remote = df_remote.set_index("conference", drop=False)
6565
df_remote.index.rename("title_match", inplace=True)
6666
known_mappings = {"SciPy US": "SciPy"}
6767

6868
df = df_yml.copy()
6969

7070
# Get closest match for titles
71-
df["title_match"] = df["title"].apply(lambda x: process.extract(x, df_remote["title"], limit=1))
71+
df["title_match"] = df["conference"].apply(lambda x: process.extract(x, df_remote["conference"], limit=1))
7272

7373
for key, value in known_mappings.items():
74-
if key in df["title"].values:
75-
df.loc[df["title"] == key, "title_match"] = value
74+
if key in df["conference"].values:
75+
df.loc[df["conference"] == key, "title_match"] = value
7676

7777
# Get first match if it's over 90
7878
for i, row in df.copy().iterrows():
7979
if isinstance(row["title_match"], str):
8080
continue
81+
if len(row["title_match"]) == 0:
82+
continue
8183
title, prob, _ = row["title_match"][0]
8284
if prob == 100:
8385
title = title
8486
elif prob >= 70:
85-
if not query_yes_no(f"Do '{row['title']}' and '{title}' match? (y/n): "):
87+
if not query_yes_no(f"Do '{row['conference']}' and '{title}' match? (y/n): "):
8688
# Code for non-matching case
8789
title = i
8890
else:
@@ -106,11 +108,11 @@ def interactive_merge(df_yml, df_remote):
106108
columns = df_new.columns.tolist()
107109

108110
try:
109-
df_yml = df_yml.drop(["title"], axis=1)
111+
df_yml = df_yml.drop(["conference"], axis=1)
110112
except:
111113
pass
112114
try:
113-
df_remote = df_remote.drop(["title"], axis=1)
115+
df_remote = df_remote.drop(["conference"], axis=1)
114116
except:
115117
pass
116118

@@ -124,7 +126,7 @@ def interactive_merge(df_yml, df_remote):
124126

125127
df_merge = pd.merge(left=df_yml, right=df_remote, how="outer", on="title_match", validate="one_to_one")
126128
for i, row in df_merge.iterrows():
127-
df_new.loc[i, "title"] = i
129+
df_new.loc[i, "conference"] = i
128130
for column in columns:
129131
cx, cy = column + "_x", column + "_y"
130132
# print(i,cx,cy,cx in df_merge.columns and cy in df_merge.columns,column in df_merge.columns,)
@@ -197,7 +199,16 @@ def interactive_merge(df_yml, df_remote):
197199
):
198200
df_new.loc[i, column] = rx + cfp_time_x
199201
else:
200-
df_new.loc[i, column] = ry + cfp_time_y
202+
if query_yes_no(f"Is this an extension?"):
203+
rrx, rry = int(rx.replace("-", "").split(" ")[0]), int(ry.replace("-", "").split(" ")[0])
204+
if rrx < rry:
205+
df_new.loc[i, "cfp"] = rx + cfp_time_x
206+
df_new.loc[i, "cfp_ext"] = ry + cfp_time_y
207+
else:
208+
df_new.loc[i, "cfp"] = ry + cfp_time_y
209+
df_new.loc[i, "cfp_ext"] = rx + cfp_time_x
210+
else:
211+
df_new.loc[i, column] = ry + cfp_time_y
201212
else:
202213
# For everything else give a choice
203214
if query_yes_no(f"For {i} in column '{column}' would you prefer '{rx}' or keep '{ry}'?"):
@@ -213,7 +224,7 @@ def interactive_merge(df_yml, df_remote):
213224

214225
def fill_missing_required(df):
215226
required = [
216-
"title",
227+
"conference",
217228
"year",
218229
"link",
219230
"cfp",
@@ -228,7 +239,7 @@ def fill_missing_required(df):
228239
for keyword in required:
229240
if pd.isna(row[keyword]):
230241
user_input = input(
231-
f"What's the value of '{keyword}' for conference '{row['title']}' check {row['link']} ?: "
242+
f"What's the value of '{keyword}' for conference '{row['conference']}' check {row['link']} ?: "
232243
)
233244
if user_input != "":
234245
df.loc[i, keyword] = user_input
@@ -251,7 +262,7 @@ def write_yaml(df, out_url):
251262
default_flow_style=False,
252263
explicit_start=True,
253264
).splitlines():
254-
outfile.write(line.replace("- title:", "\n- title:"))
265+
outfile.write(line.replace("- conference:", "\n- conference:"))
255266
outfile.write("\n")
256267

257268

@@ -296,15 +307,18 @@ def main(year=None, base=""):
296307
except urllib.error.HTTPError:
297308
break
298309

299-
df_merged, df_remote = fuzzy_match(df_yml[df_yml["year"] == y], df)
300-
df_merged["year"] = y
301-
df_merged = df_merged.drop(["title"], axis=1)
302-
df_merged = interactive_merge(df_merged, df_remote)
310+
if df_yml[df_yml["year"] == y].empty:
311+
df_csv = pd.concat([df_new, df], ignore_index=True)
312+
else:
313+
df_merged, df_remote = fuzzy_match(df_yml[df_yml["year"] == y], df)
314+
df_merged["year"] = y
315+
df_merged = df_merged.drop(["conference"], axis=1)
316+
df_merged = interactive_merge(df_merged, df_remote)
303317

304-
df_new = pd.concat([df_new, df_merged], ignore_index=True)
318+
df_new = pd.concat([df_new, df_merged], ignore_index=True)
305319

306-
merged, _ = fuzzy_match(df, df_yml[df_yml["year"] == y])
307-
df_csv = pd.concat([df_csv, merged], ignore_index=True)
320+
merged, _ = fuzzy_match(df, df_yml[df_yml["year"] == y])
321+
df_csv = pd.concat([df_csv, merged], ignore_index=True)
308322

309323
df_new = fill_missing_required(df_new)
310324
write_yaml(df_new, target_file)

utils/link_check.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import requests
2+
from urllib.parse import urlparse
3+
4+
5+
def check_link_availability(url, start):
6+
"""
7+
Checks if a URL is available. If not, tries to retrieve an archived version from the Wayback Machine.
8+
"""
9+
if url.startswith("https://web.archive.org") or url.startswith("http://web.archive.org"):
10+
return url
11+
try:
12+
response = requests.get(url, allow_redirects=True)
13+
final_url = response.url
14+
# Check if the final URL is within the same domain as the original URL
15+
if urlparse(url).netloc == urlparse(final_url).netloc and final_url != url:
16+
print(f"URL {url} was redirected within the same domain to: {final_url}")
17+
return final_url # Use the final URL for the rest of the process
18+
elif response.status_code != 200:
19+
print(f"Link is not available (status code: {response.status_code}). Trying to find an archived version...")
20+
else:
21+
return url
22+
except requests.RequestException as e:
23+
print(f"An error occurred: {e}. Trying to find an archived version...")
24+
25+
# Try to get an archived version from the Wayback Machine
26+
archive_url = f"https://archive.org/wayback/available?url={url}&timestamp={start.strftime('%Y%m%d%H%M%S')}"
27+
try:
28+
archive_response = requests.get(archive_url)
29+
if archive_response.status_code == 200:
30+
data = archive_response.json()
31+
if (
32+
data["archived_snapshots"]
33+
and data["archived_snapshots"]["closest"]
34+
and data["archived_snapshots"]["closest"]["available"]
35+
):
36+
archived_url = data["archived_snapshots"]["closest"]["url"]
37+
print(f"Found archived version: {archived_url}")
38+
return archived_url
39+
else:
40+
print("No archived version found.")
41+
return url
42+
else:
43+
print("Failed to retrieve archived version.")
44+
return url
45+
except requests.RequestException as e:
46+
print(f"An error occurred while retrieving the archived version: {e}")
47+
return url

utils/schema.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
- title: BestConf # Title of conference without year
1+
- conference: BestConf # Title of conference without year
22
year: 2022 # Year
33
link: link-to-website.com # URL to conference
4-
cfp_link: link-to-cfp.com # URL to call for proposals (Optional)
4+
cfp_link: link-to-cfp.com # URL to call for proposals (Optional)
55
cfp: 'YYYY-MM-DD HH:mm:ss' # Deadline for Call for Participation / Proposals
6+
cfp_ext: 'YYYY-MM-DD HH:mm:ss' # Extension for Deadline (Optional)
67
workshop_deadline: 'YYYY-MM-DD HH:mm:ss' # Workshop deadline if different from cfp (Optional)
78
tutorial_deadline: 'YYYY-MM-DD HH:mm:ss' # Tutorial deadline if different from cfp (Optional)
89
timezone: Asia/Seoul # Standard IANA Timezones (Omit for AoE)
@@ -18,4 +19,4 @@
1819
note: Important # In case there are extra notes about the conference (Optional)
1920
location: # Geolocation for inclusion in map
2021
latitude: 0.00
21-
longitude: 0.00
22+
longitude: 0.00

0 commit comments

Comments
 (0)