Просмотр исходного кода

Merge branch 'main' into practices

main^2
Simon Bowie 2 дней назад
Родитель
Сommit
2fca4f3c8d
Аккаунт пользователя с таким Email не найден
28 измененных файлов: 208 добавлений и 35 удалений
  1. +1
    -1
      README.md
  2. +1
    -1
      docker-compose.prod.yml
  3. +1
    -1
      docker-compose.yml
  4. +2
    -2
      web/app/book.py
  5. +19
    -5
      web/app/main.py
  6. +2
    -0
      web/app/models.py
  7. +1
    -1
      web/app/practice.py
  8. +3
    -3
      web/app/relationships.py
  9. +29
    -3
      web/app/resources.py
  10. +2
    -2
      web/app/schemas.py
  11. Двоичные данные
      web/app/static/images/OBF_WP6_logo.png
  12. Двоичные данные
      web/app/static/images/cpc_logo_white_bg.png
  13. Двоичные данные
      web/app/static/images/funder_logos.png
  14. Двоичные данные
      web/app/static/images/seminar_logos.png
  15. +18
    -8
      web/app/static/package-lock.json
  16. +1
    -1
      web/app/static/package.json
  17. +0
    -1
      web/app/static/src/main.css
  18. +22
    -0
      web/app/static/styles/main.css
  19. +7
    -2
      web/app/templates/about.html
  20. +2
    -0
      web/app/templates/base.html
  21. +6
    -0
      web/app/templates/book.html
  22. +9
    -0
      web/app/templates/resource.html
  23. +2
    -2
      web/app/tool.py
  24. +2
    -2
      web/content/colophon.md
  25. +2
    -0
      web/content/home.md
  26. +44
    -0
      web/content/seminar.md
  27. +31
    -0
      web/content/seminar_details.md
  28. +1
    -0
      web/requirements.txt

+ 1
- 1
README.md Просмотреть файл

@@ -83,7 +83,7 @@ To build the database tables run:

## credits

Content in the Experimental Publishing Compendium is © 2022–2023 [COPIM](https://copim.ac.uk) and licensed under a [Creative Commons Attribution 4.0 International License (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/).
Content in the Experimental Publishing Compendium is © 2022–2025 [COPIM](https://copim.ac.uk) and licensed under a [Creative Commons Attribution 4.0 International License (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/).

Book cover data is from the [Open Library Covers API](https://openlibrary.org/dev/docs/api/covers).


+ 1
- 1
docker-compose.prod.yml Просмотреть файл

@@ -1,8 +1,8 @@
version: "3.9"
services:
web:
build: ./web
container_name: python
restart: unless-stopped
expose:
- 5000
volumes:

+ 1
- 1
docker-compose.yml Просмотреть файл

@@ -1,8 +1,8 @@
version: "3.0"
services:
web:
build: ./web
container_name: python
restart: unless-stopped
ports:
- "5000:5000"
volumes:

+ 2
- 2
web/app/book.py Просмотреть файл

@@ -33,7 +33,7 @@ def get_books():
intro_text = markdown.markdown(intro_text)

# DATABASE QUERY
books_query = Resource.query.filter_by(type=resource_type)
books_query = Resource.query.filter_by(type=resource_type).filter_by(published=True)

# FILTERING
for key in request.args.keys():
@@ -52,7 +52,7 @@ def get_books():
# FILTERS MENU
# get values for filter menu dropdowns
# practices
practices_filter = Resource.query.filter_by(type='practice').with_entities(Resource.id, Resource.name).all()
practices_filter = Resource.query.filter_by(type='practice').filter_by(published=True).with_entities(Resource.id, Resource.name).all()
# year
year_filter = get_filter_values('year', resource_type)
# typology

+ 19
- 5
web/app/main.py Просмотреть файл

@@ -50,10 +50,24 @@ def test():
# route for about page
@main.route('/about')
def about():
# get last updated date
last_updated = get_last_date()
with open('content/about.md', 'r') as f:
about_text = f.read()
about_text = markdown.markdown(about_text)
main_text = f.read()
main_text = markdown.markdown(main_text)
with open('content/colophon.md', 'r') as f:
colophon_text = f.read()
colophon_text = markdown.markdown(colophon_text)
return render_template('about.html', about_text=about_text, colophon_text=colophon_text)
sidebar_text = f.read()
sidebar_text = markdown.markdown(sidebar_text)
return render_template('about.html', main_text=main_text, sidebar_text=sidebar_text, last_updated=last_updated)

# route for events page
@main.route('/practice_seminars')
@main.route('/expub_seminars')
def events():
with open('content/seminar.md', 'r') as f:
main_text = f.read()
main_text = markdown.markdown(main_text)
with open('content/seminar_details.md', 'r') as f:
sidebar_text = f.read()
sidebar_text = markdown.markdown(sidebar_text)
return render_template('about.html', main_text=main_text, sidebar_text=sidebar_text)

+ 2
- 0
web/app/models.py Просмотреть файл

@@ -26,9 +26,11 @@ class Resource(db.Model):
# all resource types
id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
created = db.Column(db.DateTime, default=datetime.utcnow)
published = db.Column(db.Boolean)
type = db.Column(db.Text)
name = db.Column(db.Text)
description = db.Column(db.Text)
videoUrl = db.Column(db.Text)
# tools
developer = db.Column(db.Text)
developerUrl = db.Column(db.Text)

+ 1
- 1
web/app/practice.py Просмотреть файл

@@ -35,7 +35,7 @@ def get_practices():
intro_text = markdown.markdown(intro_text)

# DATABASE QUERY
practices_query = Resource.query.filter_by(type=resource_type)
practices_query = Resource.query.filter_by(type=resource_type).filter_by(published=True)

# temporarily removing incomplete practices from main list
practices_query = practices_query.filter(

+ 3
- 3
web/app/relationships.py Просмотреть файл

@@ -18,12 +18,12 @@ def get_relationships(primary_id):
links = []
for relationship in primary_relationships:
secondary_id = relationship.second_resource_id
links.extend(Resource.query.filter_by(id=secondary_id).all())
links.extend(Resource.query.filter_by(id=secondary_id).filter_by(published=True).all())
secondary_relationships = Relationship.query.filter_by(second_resource_id=primary_id).all()
if secondary_relationships:
for relationship in secondary_relationships:
primary_id = relationship.first_resource_id
links.extend(Resource.query.filter_by(id=primary_id).all())
links.extend(Resource.query.filter_by(id=primary_id).filter_by(published=True).all())
return links
else:
secondary_relationships = Relationship.query.filter_by(second_resource_id=primary_id).all()
@@ -31,7 +31,7 @@ def get_relationships(primary_id):
links = []
for relationship in secondary_relationships:
primary_id = relationship.first_resource_id
links.extend(Resource.query.filter_by(id=primary_id).all())
links.extend(Resource.query.filter_by(id=primary_id).filter_by(published=True).all())
return links

# function to append relationships to a resource object

+ 29
- 3
web/app/resources.py Просмотреть файл

@@ -15,6 +15,7 @@ from .relationships import *
from isbntools.app import *
import requests
import re
import json
from sqlalchemy.sql import func
import markdown

@@ -36,6 +37,11 @@ def get_full_resource(resource_id):
book_data = get_book_data(resource.isbn)
if book_data:
resource.__dict__.update(book_data)
# if there's a GitHub repository link, get last GitHub commit date
if resource.repositoryUrl and "github" in resource.repositoryUrl:
# get commit date
date = get_commit_date(resource.repositoryUrl)
resource.__dict__['commitDate'] = date
return resource

# function to get practice from Markdown file
@@ -76,7 +82,7 @@ def extract_first_paragraph(markdown):

# function to retrieve data about a curated list of resources
def get_curated_resources(resource_ids):
resources = Resource.query.filter(Resource.id.in_(resource_ids)).order_by(func.random()).all()
resources = Resource.query.filter(Resource.id.in_(resource_ids)).filter_by(published=True).order_by(func.random()).all()
# append relationships to each resource
append_relationships_multiple(resources)
return resources
@@ -91,7 +97,7 @@ def delete_resource(resource_id):
# function to get filters for a specific field
def get_filter_values(field, type):
# get field values for filter
field_filter = Resource.query.filter_by(type=type).with_entities(getattr(Resource, field))
field_filter = Resource.query.filter_by(type=type).filter_by(published=True).with_entities(getattr(Resource, field))
# turn SQLAlchemy object into list
field_filter = [i for i, in field_filter]
# split each element on '/' (useful for scriptingLanguage only)
@@ -125,4 +131,24 @@ def get_book_cover(book):
else:
book_cover = {'thumbnail': openl_url}
book.update(book_cover)
return book
return book

# function to retrieve last updated date from the database
def get_last_date():
resource = Resource.query.order_by(Resource.created.desc()).filter_by(published=True).first()
return resource.created.isoformat()

# function to retrieve last commit date from a GitHub repository for a tool
def get_commit_date(repositoryUrl):
# change repository URL to API URL
api_url = repositoryUrl.replace("https://github.com", "https://api.github.com/repos")
# get default branch name
r = requests.get(api_url)
r = json.loads(r.content)
branch = r['default_branch']
# get date of last commit on default branch
api_url = api_url + "/branches/" + branch
r = requests.get(api_url)
r = json.loads(r.content)
date = r['commit']['commit']['author']['date'][0:10]
return date

+ 2
- 2
web/app/schemas.py Просмотреть файл

@@ -18,7 +18,7 @@ class UserSchema(ma.Schema):
# schema for JSON transformation of Resource table via Marshmallow
class ToolSchema(ma.Schema):
class Meta:
fields = ('id', 'name', 'description', 'developer', 'developerUrl', 'projectUrl', 'repositoryUrl', 'license', 'scriptingLanguage', 'expertiseToUse', 'expertiseToHost', 'dependencies', 'ingestFormats', 'outputFormats', 'status')
fields = ('id', 'name', 'description', 'developer', 'developerUrl', 'projectUrl', 'repositoryUrl', 'license', 'scriptingLanguage', 'expertiseToUse', 'expertiseToHost', 'dependencies', 'ingestFormats', 'outputFormats', 'videoUrl', 'status')
ordered = True

class PracticeSchema(ma.Schema):
@@ -28,7 +28,7 @@ class PracticeSchema(ma.Schema):

class BookSchema(ma.Schema):
class Meta:
fields = ('id', 'name', 'description', 'author', 'year', 'bookUrl', 'isbn')
fields = ('id', 'name', 'description', 'author', 'year', 'bookUrl', 'videoUrl', 'isbn')
ordered = True

# subschemas for nested fields

Двоичные данные
web/app/static/images/OBF_WP6_logo.png Просмотреть файл

Before After
Width: 1600  |  Height: 823  |  Size: 81KB

Двоичные данные
web/app/static/images/cpc_logo_white_bg.png Просмотреть файл

Before After
Width: 1102  |  Height: 1090  |  Size: 50KB

Двоичные данные
web/app/static/images/funder_logos.png Просмотреть файл

Before After
Width: 2100  |  Height: 368  |  Size: 91KB

Двоичные данные
web/app/static/images/seminar_logos.png Просмотреть файл

Before After
Width: 1086  |  Height: 456  |  Size: 65KB

+ 18
- 8
web/app/static/package-lock.json Просмотреть файл

@@ -10,7 +10,7 @@
"license": "ISC",
"devDependencies": {
"autoprefixer": "^10.4.2",
"postcss": "^8.4.6",
"postcss": "^8.4.31",
"postcss-cli": "^9.1.0",
"tailwindcss": "^3.0.18"
}
@@ -675,10 +675,16 @@
}
},
"node_modules/nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -762,9 +768,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.21",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"funding": [
{
@@ -774,10 +780,14 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},

+ 1
- 1
web/app/static/package.json Просмотреть файл

@@ -8,7 +8,7 @@
},
"devDependencies": {
"autoprefixer": "^10.4.2",
"postcss": "^8.4.6",
"postcss": "^8.4.31",
"postcss-cli": "^9.1.0",
"tailwindcss": "^3.0.18"
},

+ 0
- 1
web/app/static/src/main.css Просмотреть файл

@@ -191,7 +191,6 @@ a.link:hover {
@apply opacity-100;
}


h2,h3 {
hyphens: auto;
}

+ 22
- 0
web/app/static/styles/main.css Просмотреть файл

@@ -1172,6 +1172,10 @@ a.link:hover {
opacity: 1;
}

h2 {
font-size: 150%;
margin-bottom: 1em;
}

h2,h3 {
-webkit-hyphens: auto;
@@ -1182,6 +1186,10 @@ h1, h2, h3 {
font-family: 'ag-fett';
}

#colophon h2:nth-of-type(n+2) {
padding-top: 40px;
}

h4 {
font-style: italic;
font-weight: 700;
@@ -1743,4 +1751,18 @@ select.form-select {
color: #fff;
background-color: #d9534f;
border-color: #d43f3a;
}

#embedded-video {
margin-top: 1rem;
}

div#embedded-video iframe {
position: relative;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 480px;
width: 100%;
}

+ 7
- 2
web/app/templates/about.html Просмотреть файл

@@ -4,11 +4,16 @@

<div class="grid lg:grid-cols-[2fr,1fr] gap-4 container">
<div class="cell-margin text max-w-[65ch] lg:m-16 text-lg lg:text-xl">
{{ about_text|safe }}
{{ main_text|safe }}
</div>

<div id="colophon" class="cell-margin text lg:my-16">
{{ colophon_text | safe }}
{{ sidebar_text | safe }}

{% if last_updated is defined %}
<hr>
Database last updated: {{ last_updated[0:10] }}
{% endif %}
</div>
</div>


+ 2
- 0
web/app/templates/base.html Просмотреть файл

@@ -332,6 +332,8 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="The Experimental Publishing Compendium is a guide for scholars, publishers, librarians, and artists who want to experiment with the form of scholarly books.">
<meta name=”robots” content="index, follow">

<title>Experimental Publishing Compendium</title>
<script src="{{ url_for('static',filename='js/alpine.min.js') }}" defer></script>

+ 6
- 0
web/app/templates/book.html Просмотреть файл

@@ -128,6 +128,12 @@
</div>
{% endif %}
</div>
{% if resource['videoUrl'] %}
<div id="embedded-video" class="lg:col-span-12">
<h3>Accompanying video</h3>
<iframe src="{{ resource['videoUrl']|safe }}" frameborder="0" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe>
</div>
{% endif %}
</div>
</div>
</div>

+ 9
- 0
web/app/templates/resource.html Просмотреть файл

@@ -90,12 +90,21 @@
<div class="">
<h3>Platform status</h3>
{{ resource['status'] }}
{% if resource['commitDate'] %}
: last <a href="{{ resource['repositoryUrl'] }}">GitHub commit</a> on {{ resource['commitDate']}}
{% endif %}
</div>
{% endif %}
{% elif resource.type == 'practice' %}
{{ practice_markdown | safe }}
{% endif %}
</div>
{% if resource['videoUrl'] %}
<div id="embedded-video" class="lg:col-span-12">
<h3>Accompanying video</h3>
<iframe src="{{ resource['videoUrl']|safe }}" frameborder="0" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe>
</div>
{% endif %}

</div>
</div>

+ 2
- 2
web/app/tool.py Просмотреть файл

@@ -33,7 +33,7 @@ def get_tools():
intro_text = markdown.markdown(intro_text)

# DATABASE QUERY
tools_query = Resource.query.filter_by(type=resource_type)
tools_query = Resource.query.filter_by(type=resource_type).filter_by(published=True)

# FILTERING
for key in request.args.keys():
@@ -55,7 +55,7 @@ def get_tools():
# FILTERS MENU
# get values for filter menu dropdowns
# practices
practices_filter = Resource.query.filter_by(type='practice').with_entities(Resource.id, Resource.name).all()
practices_filter = Resource.query.filter_by(type='practice').filter_by(published=True).with_entities(Resource.id, Resource.name).all()
# license
licenses_filter = get_filter_values('license', resource_type)
# language

+ 2
- 2
web/content/colophon.md Просмотреть файл

@@ -6,10 +6,10 @@ Back-end coding by [Simon Bowie](https://simonxix.com), front-end coding by [Joe

Special thanks to Gary Hall, Rebekka Kiesewetter, Marcell Mars, Toby Steiner, and Samuel Moore, and everyone who has provided feedback on our research or shared suggestions of examples to feature, including the participants of COPIM’s experimental publishing workshop, and Nicolás Arata, Dominique Babini, Maria Fernanda Pampin, Sebastian Nordhoff, Abel Packer, and Armanda Ramalho, and Agatha Morka.

Our appreciation also goes out to the [Next Generation Library Publishing Project](https://educopia.org/next-generation-library-publishing/) for sharing an early catalogue-in-progress version of [SComCat](https://www.scomcat.net/) with us which formed one of the inspirations behind the Compendium.
Our appreciation also goes out to the [Next Generation Library Publishing Project](https://educopia.org/next-generation-library-publishing/) for sharing an early catalogue-in-progress version of SComCat with us which formed one of the inspirations behind the Compendium.
___

Copyright © 2023 [COPIM](https://copim.ac.uk/).
Copyright © 2023–2025 [COPIM](https://copim.ac.uk/).

Design © 2023 [Joel Galvez](https://joelgalvez.com/selected).


+ 2
- 0
web/content/home.md Просмотреть файл

@@ -1 +1,3 @@
The Experimental Publishing Compendium is a guide and reference for scholars, publishers, developers, librarians, and designers who want to challenge, push and redefine the shape, form and rationale of scholarly books. The compendium brings together tools, practices, and books to promote the publication of experimental scholarly works. [Read more](/about)

The Open Book Futures Experimental Publishing Group and the Centre for Postdigital Cultures’ Post-Publishing research strand are presenting **a seminar series for for those interested in experimental scholarly book publishing** throughout 2024 and 2025. [Read more and register](/practice_seminars).

+ 44
- 0
web/content/seminar.md Просмотреть файл

@@ -0,0 +1,44 @@
## Experimental Book Publishing in Practice

The Open Book Futures [Experimental Publishing Group](https://copim.pubpub.org/experimental-publishing-group) and the Centre for Postdigital Cultures’ [Post-Publishing](https://postpublishing.postdigitalcultures.org) research strand are pleased to present a seminar series for for those interested in experimental scholarly book publishing throughout 2024 and 2025. Each seminar will bring together authors and publishers with software and tool providers.

Our next seminar will be Thursday 20th March 2025 at 17:00 CET / 16:00 GMT / 11:00 EST bringing together Stephany RunningHawk Johnson (Local Contexts) & Darcy Cullen (UBC Press) to discuss [Traditional Knowledge Labels](https://compendium.copim.ac.uk/tools/170), labels which allow Indigenous communities to express local and specific conditions for sharing and engaging in future research and relationships in ways that are consistent with already existing community rules, governance and protocols for using, sharing and circulating knowledge and data.

Register via [Eventsforce](https://www.eventsforce.net/cugroup/frontEnd/reg/registerNew.csp?ef_sel_menu=9308&eventID=2039).

Every seminar in this series will take place online using [kMeet](https://www.infomaniak.com/en/kmeet), the open source privacy-focused videoconferencing software from Infomaniak. kMeet is compatible with all modern browsers.


![logos for Open Book Futures Experimental Publishing Group and the Centre for Postdigital Cultures](/static/images/seminar_logos.png)

## Seminar recordings

### Sesson 01: Manifold

<br><div id="embedded-video"><iframe src="https://archive.org/embed/Experimental_Publishing_Seminar_01" frameborder="0" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe></div><br>

View the [whole recording on the Internet Archive](https://archive.org/details/Experimental_Publishing_Seminar_01).

### Sesson 02: Hypothes.is

<br><div id="embedded-video"><iframe src="https://archive.org/embed/Experimental_Publishing_Seminar_02" frameborder="0" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe></div><br>

View the [whole recording on the Internet Archive](https://archive.org/details/Experimental_Publishing_Seminar_02).

<br>

## Concept

Last year saw the release of the [Experimental Publishing Compendium](https://compendium.copim.ac.uk/), a guide and reference for scholars, publishers, developers, librarians, and designers who want to challenge, push and redefine the shape, form and rationale of scholarly books. The Compendium brings together tools, practices, and books to promote the publication of experimental scholarly works.

To complement the Compendium, this series of seminars will showcase a selection of open source tools, platforms, and software that support the publication of experimental, interactive, multimodal, and/or versioned books as well as experimental publishing practices from annotating and open reviewing to forking and rewriting.

Organised by [Copim’s Experimental Publishing Group](https://copim.pubpub.org/experimental-publishing-group) in collaboration with the Centre for Postdigital Cultures’ [Post-Publishing](https://postpublishing.postdigitalcultures.org) research strand, these seminars respond to the previously stated need of both authors and publishers to learn more about experimental book publishing and the tools, practices, and workflows that support this (Adema and Stone, 2017; Adema et al. 2022).

The aim of these seminars is to help authors and publishers get started with a tool or platform, which sometimes can be quite daunting or complicated without dedicated IT support. The seminars will feature short walkthroughs of platforms and tools, as well as talks by and Q&As with the people that have developed, designed or are currently maintaining them and will be complemented by presentations by authors or publishers that have used these tools or platforms to publish an experimental book, who will be sharing their experiences of doing so.

Next to providing dedicated space for audience members to ask questions to the presenters during the seminars, the recordings of these events will be uploaded to the Experimental Publishing Compendium to complement the information on the discussed tools, practices, and books already included in the Compendium.

The Open Book Futures project is funded by the [Research England Development (RED) Fund](https://re.ukri.org/funding/our-funds-overview/research-england-development-red-fund/) and [Arcadia](https://www.arcadiafund.org.uk/), a charitable fund of Lisbet Rausing and Peter Baldwin.

![logos for Research England and Arcadia](/static/images/funder_logos.png)

+ 31
- 0
web/content/seminar_details.md Просмотреть файл

@@ -0,0 +1,31 @@
## Seminar 01: Manifold

Date: Thursday 21st November 2024

Time: 17:00 CET / 16:00 GMT / 11:00 EST

Location: Online using kMeet

Speakers: Terence Smyre (Manifold), Matthew Gold (CUNY), & Whitney Trettien (University of Pennsylvania)

## Seminar 02: Hypothes.is

Date: Thursday 16th January 2025

Time: 17:00 CET / 16:00 GMT / 11:00 EST

Location: Online using kMeet

Speakers: Remi Kalir (Duke University), Sonja Visser (Hypothes.is), & Janneke Adema (Open Humanities Press)

## Seminar 03: TK Labels

Date: Thursday 20th March 2025

Time: 17:00 CET / 16:00 GMT / 11:00 EST

Location: Online using kMeet

Speakers: Stephany RunningHawk Johnson (Local Contexts) & Darcy Cullen (UBC Press)

Register via [Eventsforce](https://www.eventsforce.net/cugroup/frontEnd/reg/registerNew.csp?ef_sel_menu=9308&eventID=2039).

+ 1
- 0
web/requirements.txt Просмотреть файл

@@ -10,4 +10,5 @@ isbntools
requests
marshmallow
flask-marshmallow
marshmallow-sqlalchemy
pandas

Загрузка…
Отмена
Сохранить