Skip to content

Instantly share code, notes, and snippets.

@ryan-williams
Created March 14, 2020 04:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryan-williams/65c6143d3a027cd2532785565d740ca8 to your computer and use it in GitHub Desktop.
Save ryan-williams/65c6143d3a027cd2532785565d740ca8 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Parse submissions, generate proposed-talks.html\n",
"Load submissions from [papercall scraper](./scrape-papercall.ipynb):"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"from numpy import datetime64, nan\n",
"from pandas import concat, DataFrame as DF, Series\n",
"from pathlib import Path\n",
"\n",
"path = Path('submissions.json')\n",
"with path.open('r') as f:\n",
" submissions = json.load(f)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Insert late submission (cf. [gist](https://gist.github.com/rlmark/3e6b8db1696c7746bcc57a185c2fe77c)):"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"submissions.append({\n",
" 'meta': {\n",
" 'title': 'Comonads and the Game of Life',\n",
" 'tags': [],\n",
" 'author': 'Rebecca Mark',\n",
" 'href': nan,\n",
" 'submitted': '2020-02-12T05:00:00Z',\n",
" 'modified': '2020-02-12T05:00:00Z',\n",
" 'location': nan,\n",
" },\n",
" 'details': {\n",
" 'Elevator Pitch': '''<p>Have you heard of Conway’s Game of Life? How about comonads?</p><p>Let’s put these two things in conversation and implement the Game of Life in Scala!</p>''',\n",
" 'Description': '''<p>In this talk, we’ll shine the spotlight on the lesser-known dual of the Monad: the Comonad. If you’ve ever wondered where comonads are useful, or simply what they are, this talk is for you! First, we’ll introduce the concept of a comonad with commonplace data structures. We’ll also demonstrate how comonads can be encoded in Scala, and finally we’ll show how the Game of Life is an example of a domain in which the properties of comonadic computation are elegant and powerful.</p>''',\n",
" 'Notes': '''<p>This talk will be an evolution of a blogpost on comonads and the Game of Life which can be found here for the committee's reference.</p>''',\n",
" 'format': 'Medium Talk (30 minutes)',\n",
" 'level': 'Intermediate',\n",
" 'author': {\n",
" 'name': 'Rebecca Mark',\n",
" 'links': [],\n",
" 'blurb': '''<p>Rebecca is a humble practitioner of functional programming. She works as a senior software engineer at 47 Degrees.</p>'''\n",
" },\n",
" },\n",
"})\n",
" \n",
"submissions = DF(submissions); submissions"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"meta = submissions.meta.apply(Series)\n",
"meta.submitted = meta.submitted.astype(datetime64)\n",
"meta.modified = meta.modified.astype(datetime64)\n",
"meta"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"details = submissions.details.apply(Series)\n",
"author = details.author.apply(Series)\n",
"details = details.drop(columns=['author'])\n",
"details"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"details.format.value_counts()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"details.level.value_counts()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"author"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"all = concat([ meta, details, author ], axis=1)\n",
"all"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"anonymized = concat([ meta[['title','tags']], details[['Elevator Pitch','Description','format','level']]], axis=1)\n",
"\n",
"# Filtering two talks out for lack of relevance\n",
"title_waitlist_terms = [\n",
" 'Does Stress Exist',\n",
" 'Team Dynamics & Communication Skills',\n",
"]\n",
"typelevel_accepted_terms = [\n",
" 'Sleeping well',\n",
" 'Sequent Calculus',\n",
" 'Functional Error Handling'\n",
"]\n",
"for title_waitlist_term in (title_waitlist_terms + typelevel_accepted_terms):\n",
" anonymized = anonymized[~anonymized.title.str.contains(title_waitlist_term)]\n",
"\n",
"anonymized"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"len(anonymized)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"long_talks = anonymized[anonymized.format.str.contains('Long')]; long_talks"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"medium_talks = anonymized[anonymized.format.str.contains('Medium')]; medium_talks"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"lightning_talks = anonymized[anonymized.format.str.contains('Lightning')]; lightning_talks"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"[ len(talks) for talks in [long_talks, medium_talks, lightning_talks] ]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from functools import partial\n",
"from yattag import Doc, indent\n",
"doc, _, txt, e = Doc().ttl()\n",
"\n",
"div = partial(_, 'div')\n",
"img = partial(doc.stag, 'img')\n",
"br = partial(doc.stag, 'br')\n",
"\n",
"idx = 0\n",
"\n",
"def render_talk(r):\n",
" global idx\n",
" with _('div', klass='talk'):\n",
" e('div', r.title, klass='talk-title')\n",
" e('div', f'Audience Level: {r.level}', klass='talk-level')\n",
"\n",
" with _('div', klass='talk-abstract'):\n",
" doc.asis(r['Elevator Pitch'])\n",
"\n",
" with _('div', klass=\"full-descr-button\"):\n",
" e('button', 'Toggle Full Description', id=f'f{idx}', klass=\"btn descr-button\")\n",
"\n",
" with _('div', id=f'f{idx}-description', klass=\"talk-descr\", style=\"display: none\"):\n",
" doc.asis(r.Description)\n",
" \n",
" idx += 1\n",
"\n",
"\n",
"talk_sections = [\n",
" { 'title': 'Long Talks', 'id': 'long', 'length': 45, 'talks': long_talks },\n",
" { 'title': 'Medium Talks', 'id': 'medium', 'length': 30, 'talks': medium_talks },\n",
" { 'title': 'Lightning Talks', 'id': 'lightning', 'length': 15, 'talks': lightning_talks },\n",
"]\n",
"\n",
"def render_talks(title, id, length, talks): \n",
" with _('div', klass='talks-block'):\n",
" e('h3', f'{title} ({length} minutes)', id=id)\n",
" with _('div', klass='talks'):\n",
" talks.apply(render_talk, axis=1)\n",
"\n",
"def all_talks():\n",
" [ \n",
" render_talks(**section) \n",
" for section in talk_sections \n",
" ]\n",
"\n",
"\n",
"doc.asis('<!DOCTYPE HTML>')\n",
"with _('html', lang='en'):\n",
" doc.asis('''<head>\n",
" <title>NEScala 2020: Proposed Talks</title>\n",
" <meta charset=\"utf-8\"/>\n",
" <meta name=\"viewport\"\n",
" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>\n",
" <meta name=\"twitter:card\" content=\"summary\">\n",
" <meta name=\"twitter:site\" content=\"@nescalas\">\n",
" <meta name=\"twitter:title\" content=\"nescala 2020\">\n",
" <meta name=\"twitter:description\"\n",
" content=\"Your friendly neighborhood Scala conference, chugging through the Northeast since 2011.\">\n",
" <meta name=\"twitter:image\" content=\"/images/nescalas-logo.png\">\n",
" <link rel=\"stylesheet\" href=\"assets/css/main.css\"/>\n",
" <link rel=\"stylesheet\" href=\"assets/css/custom.css\"/>\n",
" <link rel=\"shortcut icon\" type=\"image/png\" href=\"/images/favicon.png\" />\n",
"</head>''')\n",
" with _('body', klass='is-preload'):\n",
" doc.asis('''<section id=\"header\">\n",
" <header>\n",
" <span class=\"image avatar\"><img src=\"images/nescalas-logo.png\" alt=\"\"/></span>\n",
" </header>\n",
" <nav id=\"nav\">\n",
" <ul>\n",
" <li><a href=\"index.html\">Home</a></li>\n",
" <li><a href=\"#long\">Long Talks</a></li>\n",
" <li><a href=\"#medium\">Medium Talks</a></li>\n",
" <li><a href=\"#lightning\">Lightning Talks</a></li>\n",
" </ul>\n",
" </nav>\n",
" <footer>\n",
" <ul class=\"icons\">\n",
" <li>\n",
" <a target=\"_blank\" href=\"https://twitter.com/nescalas\" class=\"icon fa-twitter\"><span class=\"label\">Twitter</span></a>\n",
" </li>\n",
" </ul>\n",
" </footer>\n",
"</section>''')\n",
" \n",
" with div(id='wrapper'):\n",
" with div(id='main'):\n",
" with _('section', id='proposed-talks'):\n",
" with div(('data-position', 'center'), klass='image main'):\n",
" img(src='images/bk-bridge-skyline.jpg', alt='')\n",
" with div(klass='container'):\n",
" with _('header', klass='major'):\n",
" e('span', '', id='logo')\n",
" with _('h2'):\n",
" txt('Northeast Scala Symposium ')\n",
" e('span', '2020', style='color: #777')\n",
" br()\n",
" txt('Proposed Talks')\n",
" \n",
" with _('a', href='https://bit.ly/nescala-2020-vote'):\n",
" img(klass='inline padded', src='images/nescalas-logo-r.png')\n",
" txt('Vote for your favorite talks here!')\n",
"\n",
" with _('span'):\n",
" txt(\" (also \")\n",
" e('a', \"don't forget to get your ticket\", href='https://www.eventbrite.com/e/northeast-scala-symposium-typelevel-summit-2020-tickets-92788556069')\n",
" txt(\", for your vote to be eligible\")\n",
" img(klass='inline padded', src='images/nescalas-logo-l.png')\n",
"\n",
" all_talks()\n",
" \n",
" with _('section', id=\"footer\"):\n",
" with div(klass=\"container align-center\"):\n",
" with _('p'):\n",
" txt('Made possible with ')\n",
" e('i', '', klass=\"fa fa-heart\")\n",
" txt('from the')\n",
" e('a', 'Philadelphia', target=\"_blank\", href=\"https://scala-phase.org\")\n",
" txt(', ')\n",
" e('a', 'New York', target=\"_blank\", href=\"https://www.meetup.com/ny-scala/\")\n",
" txt(', and')\n",
" e('a', 'Boston', target=\"_blank\", href=\"https://www.meetup.com/boston-scala/\")\n",
" txt('Scala Enthusiasts.')\n",
" with _('ul', klass='copyright'):\n",
" for year in range(2019, 2011, -1):\n",
" with _('li'):\n",
" e('a', year, href=f'{year}/')\n",
" with _('ul', klass='copyright'):\n",
" with _('li'):\n",
" txt('Design: ')\n",
" e('a', 'HTML5 UP', href=\"http://html5up.net\", target=\"_blank\")\n",
"\n",
" scripts = [\n",
" \"assets/js/jquery.min.js\",\n",
" \"assets/js/jquery.scrollex.min.js\",\n",
" \"assets/js/jquery.scrolly.min.js\",\n",
" \"assets/js/browser.min.js\",\n",
" \"assets/js/breakpoints.min.js\",\n",
" \"assets/js/util.js\",\n",
" \"assets/js/main.js\",\n",
" ]\n",
" for script in scripts:\n",
" e('script', '', src=script)\n",
" \n",
" doc.asis(\n",
" '''\n",
" <script type=\"text/javascript\">\n",
" $(document).ready(function() {\n",
" function shuffle(array) {\n",
" for (let i = array.length - 1; i > 0; i--) {\n",
" let j = Math.floor(Math.random() * (i + 1)); // random index from 0 to i\n",
"\n",
" // swap elements array[i] and array[j]\n",
" // we use \"destructuring assignment\" syntax to achieve that\n",
" // you'll find more details about that syntax in later chapters\n",
" // same can be written as:\n",
" // let t = array[i]; array[i] = array[j]; array[j] = t\n",
" [array[i], array[j]] = [array[j], array[i]];\n",
" }\n",
" }\n",
" $.fn.shuffleChildren = function() {\n",
" $.each(this.get(), function(index, el) {\n",
" var $el = $(el);\n",
" var $find = $el.children();\n",
"\n",
" shuffle($find);\n",
"\n",
" $el.empty();\n",
" $find.appendTo($el);\n",
" });\n",
" };\n",
"\n",
" $('.talks').shuffleChildren();\n",
"\n",
" $(\".descr-button\").click(function(e) {\n",
" var buttonID = $(this).attr(\"id\");\n",
" $(\"#\" + buttonID + \"-description\").toggle()\n",
" });\n",
"\n",
" });\n",
" </script>\n",
" ''')\n",
"\n",
"\n",
"out_path = Path('/Users/ryan/c/nescalas.github.io/proposed-talks.html')\n",
"with out_path.open('w') as f:\n",
" f.write(indent(doc.getvalue()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Titles, for easy pasting into Google Forms"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print('\\n'.join(long_talks.title))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print('\\n'.join(medium_talks.title))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"print('\\n'.join(lightning_talks.title))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "nescala-2020-planning-3.8.1",
"language": "python",
"name": "nescala-2020-planning-3.8.1"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment