Commit 9c5d21f9 authored by gijs's avatar gijs

Set up of pelican

parent ac792834
- Add language indications to the code blocks.
- Use markdown syntax for the images
- Use real markdown headers (normalize headers and subheaders)
- Keep saving the images and resources within the chapter folder
- We added title and page_order metadata for pelican.
\ No newline at end of file
DEBUG ?= 0
ifeq ($(DEBUG), 1)
ifeq ($(RELATIVE), 1)
PELICANOPTS += --relative-urls
@echo 'Makefile for a pelican Web site '
@echo ' '
@echo 'Usage: '
@echo ' make html (re)generate the web site '
@echo ' make clean remove the generated files '
@echo ' make regenerate regenerate files upon modification '
@echo ' make publish generate using production settings '
@echo ' make serve [PORT=8000] serve site at http://localhost:8000'
@echo ' make serve-global [SERVER=] serve (as root) to $(SERVER):80 '
@echo ' make devserver [PORT=8000] serve and regenerate together '
@echo ' make ssh_upload upload the web site via SSH '
@echo ' make rsync_upload upload the web site via rsync+ssh '
@echo ' '
@echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html '
@echo 'Set the RELATIVE variable to 1 to enable relative urls '
@echo ' '
[ ! -d $(OUTPUTDIR) ] || rm -rf $(OUTPUTDIR)
ifdef PORT
ifdef SERVER
ifdef PORT
.PHONY: html help clean regenerate serve serve-global devserver publish
\ No newline at end of file
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf-8 -*- #
from __future__ import unicode_literals
AUTHOR = '.'
SITENAME = 'Aesthetic Programming'
PATH = 'content'
TIMEZONE = 'Europe/Paris'
# Feed generation is usually not desired when developing
# Blogroll
LINKS = (('Pelican', ''),
('', ''),
('Jinja2', ''),
('You can modify those links in your config file', '#'),)
# Social widget
SOCIAL = (('You can add links in your config file', '#'),
('Another social link', '#'),)
# Uncomment following line if you want document-relative URLs when developing
#PAGE_PATHS = ['../source']
STATIC_PATHS = ['content']
THEME = 'theme/aesthetic-programming'
PLUGIN_PATHS = ['plugins']
PLUGINS = ['page_order']
\ No newline at end of file
Page Order
*Author: Ahmad Khayyat (<>)*
A [Pelican][1] plugin that adds a `page_order` attribute to all pages
if one is not defined. Allows your templates to sort pages as follows:
{% for p in PAGES|sort(attribute='page_order') %}
Without this plugin, to be able to use the line above in your
templates, you would have to define the `page_order` attribute in all
pages. This plugin sets the value of this attribute to a default value
of 100, unless a `DEFAULT_PAGE_ORDER` setting is defined.
The `page_order` attribute is cast to an `int`, so only use numeric
values. This is to have a value of `11` be greater than `2`.
Page Order
Adds a `page_order` attribute to all pages if one is not defined.
from pelican import signals
def set_page_order(generator):
for page in generator.pages:
page.page_order = int(page.page_order)
if 'DEFAULT_PAGE_ORDER' in generator.settings:
page.page_order = int(generator.settings['DEFAULT_PAGE_ORDER'])
page.page_order = 100
generator.pages.sort(key=lambda p: p.page_order)
def register():
#!/usr/bin/env python
# -*- coding: utf-8 -*- #
from __future__ import unicode_literals
# This file is only used if you use `make publish` or
# explicitly specify it as your config file.
import os
import sys
from pelicanconf import *
# If your site is available via HTTPS, make sure SITEURL begins with https://
FEED_ALL_ATOM = 'feeds/all.atom.xml'
CATEGORY_FEED_ATOM = 'feeds/{slug}.atom.xml'
# Following items are often useful when publishing
\ No newline at end of file
# -*- coding: utf-8 -*-
import os
import shutil
import sys
import datetime
from invoke import task
from invoke.util import cd
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
from pelican.settings import DEFAULT_CONFIG, get_settings_from_file
LOCAL_SETTINGS = get_settings_from_file(SETTINGS_FILE_BASE)
'settings_base': SETTINGS_FILE_BASE,
'settings_publish': '',
# Output path. Can be absolute or relative to Default: 'output'
'deploy_path': SETTINGS['OUTPUT_PATH'],
# Port for `serve`
'port': 8000,
def clean(c):
"""Remove generated files"""
if os.path.isdir(CONFIG['deploy_path']):
def build(c):
"""Build local version of site"""'pelican -s {settings_base}'.format(**CONFIG))
def rebuild(c):
"""`build` with the delete switch"""'pelican -d -s {settings_base}'.format(**CONFIG))
def regenerate(c):
"""Automatically regenerate site upon file modification"""'pelican -r -s {settings_base}'.format(**CONFIG))
def serve(c):
"""Serve site at http://localhost:$PORT/ (default port is 8000)"""
class AddressReuseTCPServer(RootedHTTPServer):
allow_reuse_address = True
server = AddressReuseTCPServer(
('', CONFIG['port']),
sys.stderr.write('Serving on port {port} ...\n'.format(**CONFIG))
def reserve(c):
"""`build`, then `serve`"""
def preview(c):
"""Build production version of site"""'pelican -s {settings_publish}'.format(**CONFIG))
def livereload(c):
"""Automatically reload browser tab upon file modification."""
from livereload import Server
server = Server()
# Watch the base settings file['settings_base'], lambda: build(c))
# Watch content source files
content_file_extensions = ['.md', '.rst']
for extension in content_file_extensions:
content_blob = '{0}/**/*{1}'.format(SETTINGS['PATH'], extension), lambda: build(c))
# Watch the theme's templates and static assets
theme_path = SETTINGS['THEME']'{}/templates/*.html'.format(theme_path), lambda: build(c))
static_file_extensions = ['.css', '.js']
for extension in static_file_extensions:
static_file = '{0}/static/**/*{1}'.format(theme_path, extension), lambda: build(c))
# Serve output path on configured port
server.serve(port=CONFIG['port'], root=CONFIG['deploy_path'])
def publish(c):
"""Publish to production via rsync"""'pelican -s {settings_publish}'.format(**CONFIG))
'rsync --delete --exclude ".DS_Store" -pthrvz -c '
'-e "ssh -p {ssh_port}" '
'{} {ssh_user}@{ssh_host}:{ssh_path}'.format(
CONFIG['deploy_path'].rstrip('/') + '/',
/* CSS for Paged.js interface */
/* Change the look */
:root {
--color-background: whitesmoke;
--color-pageBox: #666;
--color-paper: white;
--color-marginBox: transparent;
/* To define how the book look on the screen: */
@media screen {
body {
background-color: var(--color-background);
.pagedjs_pages {
display: flex;
width: calc(var(--pagedjs-width) * 2);
flex: 0;
flex-wrap: wrap;
margin: 0 auto;
.pagedjs_page {
background-color: var(--color-paper);
box-shadow: 0 0 0 1px var(--color-pageBox);
margin: 0;
flex-shrink: 0;
flex-grow: 0;
margin-top: 10mm;
.pagedjs_first_page {
margin-left: var(--pagedjs-width);
.pagedjs_page:last-of-type {
margin-bottom: 10mm;
/* show the margin-box */
.pagedjs_margin-left-bottom {
box-shadow: 0 0 0 1px inset var(--color-marginBox);
/* uncomment this part for recto/verso book : ------------------------------------ */
.pagedjs_pages {
flex-direction: column;
width: 100%;
.pagedjs_first_page {
margin-left: 0;
.pagedjs_page {
margin: 0 auto;
margin-top: 10mm;
/* uncomment this par to see the baseline : -------------------------------------------*/
.pagedjs_pagebox {
--pagedjs-baseline: 11px;
--pagedjs-baseline-position: -4px;
--pagedjs-baseline-color: cyan;
background: linear-gradient(var(--color-paper) 0%, var(--color-paper) calc(var(--pagedjs-baseline) - 1px), var(--pagedjs-baseline-color) calc(var(--pagedjs-baseline) - 1px), var(--pagedjs-baseline-color) var(--pagedjs-baseline)), transparent;
background-size: 100% var(--pagedjs-baseline);
background-repeat: repeat-y;
background-position-y: var(--pagedjs-baseline-position);
@page {
size: 140mm 200mm;
.debug .pagedjs_page {
.pagedjs_page {
counter-increment: page;
.pagedjs_margin-bottom:before {
/*content: var(--pagedjs-page-count);*/
content: counter(page);
@font-face {
font-family: Code;
src: url("../fonts/CutiveMono-Regular.ttf");
@font-face {
font-family: Text;
src: url("../fonts/cmunui.ttf");
body {
font-family: Text;
code {
font-family: Code;
img {
max-width: 100%;
max-height: 100%;
\ No newline at end of file
/home/svilayphiou/fonts/Computer Modern/Upright Italic/cmunui.ttf
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{{ SITENAME }}</title>
<link rel="stylesheet" href="{{ SITEURL }}/{{ THEME_STATIC_DIR }}/css/styles.css" type="text/css" media="all" charset="utf-8">
<link rel="stylesheet" href="{{ SITEURL }}/{{ THEME_STATIC_DIR }}/css/interface-0.1.css" type="text/css" media="all" charset="utf-8">
<script type="text/javascript" charset="utf-8" src="{{ SITEURL }}/{{ THEME_STATIC_DIR }}/js/paged.polyfill.js"></script>
{% for page in pages %}
{{ page.content }}
{% endfor %}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{{ SITENAME }}</title>
<link rel="stylesheet" href="{{ SITEURL }}/{{ THEME_STATIC_DIR }}/css/styles.css" type="text/css" media="all" charset="utf-8">
{% for page in pages: %}
<a href="{{ page.url }}">{{ page.title }}</a>
{% endfor %}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{{ SITENAME }}</title>
<link rel="stylesheet" href="{{ SITEURL }}/{{ THEME_STATIC_DIR }}/css/styles.css" type="text/css" media="all" charset="utf-8">
<link rel="stylesheet" href="{{ SITEURL }}/{{ THEME_STATIC_DIR }}/css/interface-0.1.css" type="text/css" media="all" charset="utf-8">
<script type="text/javascript" charset="utf-8" src="{{ SITEURL }}/{{ THEME_STATIC_DIR }}/js/paged.polyfill.js">
{{ page.content }}
\ No newline at end of file
To replace html images with markdown images:
Search: <img src="([^"]+)" width="(\d+)">
Replace: <!-- $0 -->\n![]({attach}$1)
\ No newline at end of file
Title: 0. *Aesthetic Programming: A Handbook of Software Studies*
page_order: 0
*Aesthetic Programming: A Handbook of Software Studies*
Title: 1. Getting Started
page_order: 1
## 1. Getting Started
## 1.1 Begin()
......@@ -13,7 +16,8 @@ In 2016, Nick Montfort, who is a poet and professor of digital media at MIT, pub
As the first chapter of this book, we think that it is important to reflecting on why do we need to learn programming, which is also a way to set the scene and sustain our motivation to learn persistently. Knowing the fact that not all new learners would like to be a creative coder or professional programmer, we would then also address on code as means to work computationally, to think conceptually on wider cultural issues as well as to raise questions critically. As such, engaging with programming provides a way to creating changes in techno-cultural systems (which we have also discussed in the Preface). By understanding from many others especially our students who begin with our course without any programming experience, learning to code is a deep learning process with enjoyment and achivement but also comes with frustration in most of the times, specially there are new perspectives, syntaxes and structure to explore and experiment at the first place. It may not come naturally but takes time to familiar with computational thinking through structured logics and precise procedures.
### 1.1.1 Start()
<img src="ch1_1.png" width="450">
<!-- <img src="ch1_1.png" width="450"> -->
*Figure 1.1: p5.js web interface*
......@@ -47,7 +51,8 @@ Additionally Gitlab will be the main platform for code and text respository, at
ATOM will be used as a key code editor in this book. Apart from its free and open source nature, ATOM supports cross-platform editing which can be run on Mac OS, Windows and Linux.
1. Download the software ATOM from the homepage:
2. Drag the 'p5' folder that you have just unzipped onto ATOM. You should able to see the left-hand pane with your project. Then you try to navigate to the 'index.html' file under the 'empty-example' folder, double click that file and the source code should display on the right-hand pane. See below:
<br><img src="ch1_4.png" width="450"><br>
<br><!-- <img src="ch1_4.png" width="450"> -->
*Figure 1.4: The file structure of ATOM*
The 'index.html' is the default page, among other pages and files, that a web browser will first pick up and display. You can customize a page title and other styling, but the focus for this chapter will be navigating the libaries and run our first program. Since p5.js is a library, here on line 8-11 which indicates how to incorporate javascript files and libraries by using the tags `<script>` and `</script>. `
......@@ -56,7 +61,8 @@ Right now the script is using relative paths, which is a useful concept when we
Next you will need to install a package called 'atom-live-server'<sup>[19](#myfootnote19)</sup>, and this is useful for setting up a web server and you can update your code and see the result immediately on a browser without the need to refresh it. You can first check under 'Packages' on your menu bar and see if the package is there. If not, then go to Edit > Preferences > +Install, then type 'atom-live-server'. Hit the blue install button and you should able to find it again under the Packages menu.
<img src="ch1_5.png" width="500"> <br>
<!-- <img src="ch1_5.png" width="500"> -->
![]({attach}ch1_5.png) <br>
*Figure 1.5: Installing atom-live-server*
If you want to customize the theme like the background color of the panes, simply go to Preferences > Themes.
......@@ -82,7 +88,8 @@ function draw() {
* To run the code, you just need to go to Packages > atom-live-server (or you can use the shortcut Crtl + Alt + L). Then there will be a popup window, click on the 'empty-example' folder and it should display something like below:
<br><img src="ch1_6.png" width="500"> <br>
<br><!-- <img src="ch1_6.png" width="500"> -->
![]({attach}ch1_6.png) <br>
*Figure 1.6: My first program*
## Exercise in class
......@@ -94,7 +101,8 @@ function draw() {
6. Change the title in the HTML file (line 6)
7. Can you run the program so that you can see almost the same screen as Figure 6 on a web browser?
<br><img src="ch1_7.png" width="500"> <br>
<br><!-- <img src="ch1_7.png" width="500"> -->
![]({attach}ch1_7.png) <br>
*Figure 1.7: My first program 1.1*
This exerise is to get you to familar with the path and local directory so as to know that running a sketch on a web browser requires to loading the right path of the JavaScript libraries. As the book progress, you are also free to create your own folder name and rename the file like sketch.js as you wish.
......@@ -106,12 +114,14 @@ As you might aware, this book is not following the convention of most programmin
In the sample code above, line 4 with the print() function that writes the text 'hello world'. To see the text, you need to open the web console area which is differently located according to browsers and you can try to search through navigating the menu bar. In Firefox browser, it is located under Tools > Web Developer > Web Console (Ctrl+Shift+K).
<br><img src="ch1_8.png" width="400"> <br>
<br><!-- <img src="ch1_8.png" width="400"> -->
![]({attach}ch1_8.png) <br>
*Figure 1.8: The console area*
At the bottom of the Figure 8, the web console area shows the text 'hello world'. What you know from this is that the sketch is running properly and it is able to read the print's function line. When you progress with this book, you will find that the web console area is very important, because you can also see error messages when, for example, the syntax is wrong and the browser will give you some good hints to bug fix your own code. Figure 1.9 shows that the web console area is able to specify which file (sketch.js) and which line of code (line 8) with problems (the syntax background was spelled wrong intentionally - see Figure 2.9).
<br><img src="ch1_9.png" width="500"> <br>
<br><!-- <img src="ch1_9.png" width="500"> -->
![]({attach}ch1_9.png) <br>
*Figure 1.9: Example of syntax error*
Indeed, Hello World program has a long history in computing, especially introducing to novice programmers with a programming language and making sure things are running. Wendy Hui Kyong Chun and Andrew Lison argue the first Hello World program we learn is enjoyable and seductive <sup>[21](#myfootnote21)</sup>. On the one hand we rougly understand the line `print("hello world")` literally as it is considered as human language: to 'print' the text 'hello world', which is understandable and straight forward; On the other hand, the computer is executing what exactly you want it to perform as printing a text through an 'instruction', giving you the immediate result which is rewarding. Such feedback "produce a feeling of power" that you start mastering technologies, transitioning from "immature students into programmers".
......@@ -127,7 +137,8 @@ There are some kinds of structure here which is hard to remember as a new langua
For p5.js, functions are documented in the page called [References](<sup>[24](#myfootnote24)</sup> and they are structured in a similar fashion. Once you get used to their presentation, it will be easier and quicker to learn and write that syntax.
<img src="ch1_10.png" height="500"> <br>
<!-- <img src="ch1_10.png" height="500"> -->
![]({attach}ch1_10.png) <br>
*Figure 1.10: The reference guide example - ellipse()*
Let's read together for the reference in Figure 2.9 - [`ellipse()`](<sup>[25](#myfootnote25)</sup>. It usually starts with an example and an illustration, and you can click the 'edit' button to modify the code, especially changing the parameters on the fly and display the result immediately on a screen.
......@@ -136,7 +147,8 @@ The description part of the reference page explains how the function syntax work