commit ad06b349dc6fb23f6f0eea39031771434c014bc6 Author: lzzfnc Date: Wed Dec 22 23:27:40 2021 +0100 Porting from jupiter lab 😨 diff --git a/_wip/create_thumbnail.ipynb b/_wip/create_thumbnail.ipynb new file mode 100644 index 0000000..82b0b58 --- /dev/null +++ b/_wip/create_thumbnail.ipynb @@ -0,0 +1,60 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "id": "5fbf751c-841f-4089-8ef0-5267356a069b", + "metadata": {}, + "outputs": [], + "source": [ + "from PIL import Image\n", + "import os\n", + "UPLOAD_FOLDER = os.path.join(os.getcwd(), 'static/uploads/annotation-compass/')\n", + "\n", + "def thumbnail(image):\n", + " try:\n", + " img = Image.open(image)\n", + " img.thumbnail((128,128))\n", + " name = image.rsplit('.', 1)[0]\n", + " ext = image.rsplit('.', 1)[1]\n", + " img.save(f'{name}_thumb.{ext}')\n", + " except IOError:\n", + " pass\n", + " \n", + "files = os.listdir(UPLOAD_FOLDER)\n", + "\n", + "for file in files:\n", + " thumbnail(os.path.join(UPLOAD_FOLDER, file))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b65ddab7-a74d-4c32-8f70-ab9e21388a55", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_wip/error_messages.py b/_wip/error_messages.py new file mode 100644 index 0000000..e2a717f --- /dev/null +++ b/_wip/error_messages.py @@ -0,0 +1,10 @@ +break_messages = [ +"sorry I fell asleep come back in 10 min", +"Sorry I'm not available at the moment", +"sorry, i went to the toilet, see u back in 5 min", +"ehm, refresh the page in 3 min", +"ah i went on a break, you should go on a break too" +"Ah! you are here! I wasn't excepting of you! Wait to put something on me" +"I wasn't ready for this connection. I am a bit moody right now, so I am concentrating on finding my center." +"Upss I am having a break right now, cuddling my cat." +] \ No newline at end of file diff --git a/_wip/errors.ipynb b/_wip/errors.ipynb new file mode 100644 index 0000000..12f624a --- /dev/null +++ b/_wip/errors.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 88, + "id": "e7bd7834-0370-4685-ae24-cd7faa6e08f9", + "metadata": {}, + "outputs": [], + "source": [ + "from error_messages import break_messages\n", + "import random, datetime, time\n", + "from datetime import date\n", + "import pytz" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "74347109-d30a-476a-b903-cd3fa5b9274a", + "metadata": {}, + "outputs": [], + "source": [ + "def random_line(txt_list):\n", + " message= choice(txt_list)\n", + " print (message)" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "8d527146-7473-4f02-b23e-61057a15a770", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sorry I fell asleep come back in 10 min\n" + ] + } + ], + "source": [ + "random_line(break_messages)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d303ab1-47c1-4467-858b-7d84dc257e36", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "8ba06a30-a28d-49cf-84d6-af1416945261", + "metadata": {}, + "outputs": [], + "source": [ + "today = date.today()\n", + "altro = ('2021-12-15')" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "07738cdb-46cb-46ba-bf7e-2ed8813a3ff7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2021-12-15\n" + ] + } + ], + "source": [ + "if today != altro:\n", + " print(altro)" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "7b28edc8-8762-4834-84b5-b7ca913902c3", + "metadata": {}, + "outputs": [], + "source": [ + "tz = pytz.timezone('Europe/Berlin')\n", + "moment = datetime.datetime.now(tz)\n", + "timestamp = moment.__str__()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aaea2507-5bd0-4930-bf78-ed3ad9622276", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_wip/import_test.ipynb b/_wip/import_test.ipynb new file mode 100644 index 0000000..1efba70 --- /dev/null +++ b/_wip/import_test.ipynb @@ -0,0 +1,145 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "04ca94d4-7339-4e44-aa28-03e77fa534f8", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib \n", + "ac = importlib.import_module(\"projects.annotation-compass.annotation_compass\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "7dd00f4d-28a0-4fd4-9cc9-17d8cbb61023", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "print(ac)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2aafb83a-b857-4ce7-af76-cb24c24d6f09", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'response': 'ok',\n", + " 'labels': [{'position': {'x': 71.4815, 'y': 13.4748},\n", + " 'size': {'width': 51.6667, 'height': 70.9862},\n", + " 'text': 'love after love\\n\\nthe time will come\\nthat with ecstacy\\nyou will welcome your self\\nas you will reach at your own door, at your own mirror,\\nand the one while smiling will welcome the other\\n\\nand stay here they would say. eat.\\nyou will love again the stranger that your self was.\\ngive some wine. give some bread. give back your heart.\\nto herself, to the stranger that loved you\\n\\nall your life, that you avoided\\nfor someone else, that had mirrored you.\\nput down the love poems from the shelf,\\n\\nthe photos, the desperate notes,\\ntear down your image from the mirror.\\nsit down. enjoy your life.',\n", + " 'timestamp': datetime.datetime(2021, 12, 15, 10, 57, 24),\n", + " 'userID': '8990638769',\n", + " 'image': 'greek.jpg'},\n", + " {'position': {'x': 76.5434, 'y': -0.71048},\n", + " 'size': {'width': 7.74749, 'height': 87.9218},\n", + " 'text': 'μ\\nι\\nτ\\n σ\\nα\\n\\n\\nγ\\nι\\nρ\\nν π\\nα η\\n σ\\n ο\\n\\n\\nι\\n\\n \\nεσ\\n τ\\n ο\\n\\nτ\\n υ\\nλ \\n ε\\nφ\\nο\\n ν\\nα\\n\\n ',\n", + " 'timestamp': datetime.datetime(2021, 12, 17, 12, 56, 4),\n", + " 'userID': '7152574796',\n", + " 'image': 'greek.jpg'},\n", + " {'position': {'x': 83.1432, 'y': 4.08526},\n", + " 'size': {'width': 28.264, 'height': 87.7442},\n", + " 'text': \"Μ\\n Ι\\nΤ\\n Σ\\nΑ\\n\\n\\n Γ Ι\\n Ρ\\n Ν \\n Α\\n\\n\\nΠ \\n Ι\\nΣ\\nΟ\\n\\n\\n\\nΙ'\\n\\n\\n\\n Ε\\nΣ\\nΤ\\n Ο\\n\\n\\n\\n Τ \\nΥ\\n Λ Ε\\n ΦΟ\\nΝ\\n Α\\n\\n\\n\\n Φ\\n\\n \",\n", + " 'timestamp': datetime.datetime(2021, 12, 17, 12, 59, 43),\n", + " 'userID': '7152574796',\n", + " 'image': 'greek.jpg'}]}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ac.get_labels_url('greek.jpg')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "df20cbd0-e837-4a01-b501-206b8a884c1c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/var/www/html/si16-app/projects/annotation-compass/descriptions.json\n" + ] + }, + { + "data": { + "text/plain": [ + "\"Welcome to many to one translation!\\r\\n\\r\\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\\r\\n\\r\\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\\r\\n\\r\\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\\r\\n .c Click ''insert'' or click on the ''x'' if it's not as you want\\r\\n\\r\\nThank you for your participation!\\r\\nGet back on our website soon to see how your contribution has been used.\"" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ac.get_image_description('greek.jpg')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "c012b7fe-6de7-4ce2-91df-ebc544006bd4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/var/www/html/si16-app\n" + ] + } + ], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63f6fd83-173a-47c5-87b4-5353a7b4e210", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_wip/jian_project_functions.ipynb b/_wip/jian_project_functions.ipynb new file mode 100644 index 0000000..84631bb --- /dev/null +++ b/_wip/jian_project_functions.ipynb @@ -0,0 +1,317 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "aecab081-a69a-4e38-9a30-cfc95661e56b", + "metadata": {}, + "outputs": [], + "source": [ + "from urllib.request import urlopen\n", + "import json" + ] + }, + { + "cell_type": "markdown", + "id": "9538705e-e51e-49da-b4fe-e6c4c6f6c435", + "metadata": {}, + "source": [ + "Area Map:\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Select a specific area of the image, return a list of all labels in that specific area." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "13246f4a-81ac-4b68-b974-ae04064d10cc", + "metadata": {}, + "outputs": [], + "source": [ + "# function for the project!\n", + "# please, kamo, put it in the flask app! thxxxx\n", + "# (combined with html_tag_list)\n", + "\n", + "url = \"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image=rejection_map.jpg/\"\n", + "response = urlopen(url)\n", + "data_json = json.loads(response.read()) \n", + "\n", + "def area_map_list(labels: list, left: int, right: int, top: int, bottom: int ) -> list: \n", + " \n", + " filtered_map = []\n", + " for label in labels:\n", + " if left <= (label['position']['x']) <= right and top <= (label['position']['y']) <= bottom:\n", + " filtered_map.append(label)\n", + " \n", + " return filtered_map\n", + "\n", + "#area_map_list(data_json['labels'], 0, 10, 30, 70)" + ] + }, + { + "cell_type": "markdown", + "id": "34b43aae-0830-47ca-86c9-5827bfa44cef", + "metadata": {}, + "source": [ + "Ghost Map:\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Replace all characters of all annotation-texts with a ghost-glyph and return a string that includes all replaced annotation-texts plus html-tags that place them back into their original position." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "dcbe893c-d00a-4933-9a18-8216a5f7459a", + "metadata": {}, + "outputs": [], + "source": [ + "# function for the project!\n", + "# please, kamo, put it in the flask app! thxxxx\n", + "# this function links to jian.css\n", + "\n", + "url = \"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image=rejection_map.jpg/\"\n", + "response = urlopen(url)\n", + "data_json = json.loads(response.read()) \n", + "\n", + "def ghost_map_list(labels: list, ghost_glyph: str ) -> str:\n", + " \n", + " filtered_map = ''\n", + " for label in labels:\n", + " replaced_text = ''\n", + " for char in label['text']:\n", + " replaced_char = char\n", + " if not char.isspace():\n", + " replaced_char = ghost_glyph\n", + " replaced_text = replaced_text + replaced_char\n", + " html_tag = f'

{ replaced_text }

'\n", + " filtered_map = filtered_map + html_tag\n", + " return filtered_map\n", + "\n", + "#ghost_map_list(data_json['labels'], '.')" + ] + }, + { + "cell_type": "markdown", + "id": "863a6716-d9e4-413f-a597-a16cc0f04d6d", + "metadata": {}, + "source": [ + "Highlight Map:\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Give a target-word; Return a string that includes all annotation-texts plus html-tags that place them back into their original position while highlighting the annotation-texts that include the target." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "18cfc4fa-4039-49fe-8b29-5bbec0e89b6f", + "metadata": {}, + "outputs": [], + "source": [ + "# function for the project!\n", + "# please, kamo, put it in the flask app! thxxxx\n", + "# this function links to jian.css\n", + "\n", + "url = \"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image=rejection_map.jpg/\"\n", + "response = urlopen(url)\n", + "data_json = json.loads(response.read()) \n", + "\n", + "def highlight_map_list(labels: list, target: str ) -> str:\n", + "\n", + " filtered_map = ''\n", + " for label in labels:\n", + " if target in label['text']:\n", + " highlight_tag = f'

{ label[\"text\"] }

'\n", + " filtered_map = filtered_map + highlight_tag\n", + " else:\n", + " html_tag = f'

{ label[\"text\"] }

'\n", + " filtered_map = filtered_map + html_tag\n", + " \n", + " return filtered_map\n", + "\n", + "#highlight_map_list(data_json['labels'], 'tunnel')" + ] + }, + { + "cell_type": "markdown", + "id": "9c41f5fd-1071-43b3-88bc-41a8e5907fdb", + "metadata": {}, + "source": [ + "html-tag:\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Return a string that can include the position, text, timestamp and/or userID of all labels plus html-tags that place them back into their original position." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a7ee1bdf-a356-4a66-aa01-ef1dad8738ca", + "metadata": {}, + "outputs": [], + "source": [ + "# function for the project!\n", + "# please, kamo, put it in the flask app! thxxxx\n", + "# this function links to jian.css\n", + "\n", + "url = \"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image=rejection_map.jpg/\"\n", + "response = urlopen(url)\n", + "data_json = json.loads(response.read()) \n", + "\n", + "def html_tag_list(labels: list, position: bool, text: bool, timestamp: bool, userID: bool ) -> str: \n", + " \n", + " html_tags = ''\n", + " for label in labels:\n", + " html_tags = html_tags + f'

'\n", + " if position == True:\n", + " html_position = f'{ label[\"position\"] } '\n", + " html_tags = html_tags + html_position\n", + " if text == True:\n", + " html_text = f'{ label[\"text\"] } '\n", + " html_tags = html_tags + html_text\n", + " if timestamp == True:\n", + " html_timestamp = f'{ label[\"timestamp\"] } '\n", + " html_tags = html_tags + html_timestamp\n", + " if userID == True:\n", + " html_userID = f'{ label[\"userID\"] } '\n", + " html_tags = html_tags + html_userID\n", + " html_tags = html_tags + '

'\n", + " \n", + " return html_tags\n", + "\n", + "#html_tag_list(data_json['labels'], True, False, False, False)" + ] + }, + { + "cell_type": "markdown", + "id": "d05dd98e-0cdb-4a50-839a-7a67cdc22010", + "metadata": {}, + "source": [ + "Individual Map:\n", + "give a string with the name of the image-file that was annotated with the Annotation Compass; Select one or more specific targets and return a list of all labels that include these targetsselect one or more specific users and return a list of all labels from these users." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "e8d7824d-4523-46f7-b89f-0e8f2d98e564", + "metadata": {}, + "outputs": [], + "source": [ + "# function for the project!\n", + "# hei kamo! is it already in the flask? should be?\n", + "# (combined with html_tag_list)\n", + "\n", + "url = \"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image=rejection_map.jpg/\"\n", + "response = urlopen(url)\n", + "data_json = json.loads(response.read()) \n", + "\n", + "def individual_map_list(labels: list, users: list ) -> list: \n", + " \n", + " filtered_map = []\n", + " for label in labels:\n", + " for user in users:\n", + " if label['userID'] == user:\n", + " filtered_map.append(label)\n", + " return filtered_map\n", + "\n", + "#individual_map_list(data_json['labels'], ['5058763759', '5941298752'])" + ] + }, + { + "cell_type": "markdown", + "id": "0f3febed-e702-4585-a7a1-e62d1a16d1c0", + "metadata": {}, + "source": [ + "Target Map:\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Select one or more specific targets and return a list of all labels that include these targets" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "9d263750-bab0-4989-9074-a58eba21b2c5", + "metadata": {}, + "outputs": [], + "source": [ + "# function for the project!\n", + "# please, kamo, put it in the flask app! thxxxx\n", + "# (combined with html_tag_list)\n", + "\n", + "url = \"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image=rejection_map.jpg/\"\n", + "response = urlopen(url)\n", + "data_json = json.loads(response.read()) \n", + "\n", + "def target_map_list(labels: list, targets: list ) -> list: \n", + " \n", + " filter_map = []\n", + " for label in labels:\n", + " for target in targets:\n", + " if target in label['text']:\n", + " filter_map.append(label)\n", + " return filter_map\n", + "\n", + "#target_map_list(data_json['labels'], ['tunnel', 'happy'])" + ] + }, + { + "cell_type": "markdown", + "id": "a8e5a256-b9e6-4f0f-b395-690c36d88a7e", + "metadata": {}, + "source": [ + "Vernacular Map:\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Return a string that includes all annotation-texts plus html-tags that place them back into their original position." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "d78dca69-5f1e-408d-85b5-6cc594f2f875", + "metadata": {}, + "outputs": [], + "source": [ + "# function for the project!\n", + "# please, kamo, put it in the flask app! thxxxx\n", + "# this function links to jian.css\n", + "\n", + "url = \"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image=rejection_map.jpg/\"\n", + "response = urlopen(url)\n", + "data_json = json.loads(response.read()) \n", + "\n", + "def vernacular_map_list(labels: list) -> str: \n", + "\n", + " filtered_map = ''\n", + " for label in labels:\n", + " html_tag = f'

{ label[\"text\"] }

'\n", + " filtered_map = filtered_map + html_tag\n", + " \n", + " return filtered_map\n", + "\n", + "#vernacular_map_list(data_json['labels'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a207852-701e-48ef-8469-96c245aea6a4", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_wip/projects_app.ipynb b/_wip/projects_app.ipynb new file mode 100644 index 0000000..8c66ed2 --- /dev/null +++ b/_wip/projects_app.ipynb @@ -0,0 +1,87 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "1d499616-2ed6-49c5-a3f3-394f5330dd1f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96517076-dff6-4e43-b858-0215eb5e538e", + "metadata": {}, + "outputs": [], + "source": [ + "# --------ETC PORTAL------------ #\n", + "\n", + "@app.route(f'/{base_url}/api/')\n", + "https://hub.xpub.nl/soupboat/~chae/api/\n", + "\n", + "@app.route(f'/{base_url}/the-etc-portal-is-open/')\n", + "https://hub.xpub.nl/soupboat/~chae/api/the-etc-portal-is-open/\n", + "\n", + "@app.route(f'/{base_url}/start-contaminating/', methods = ['GET'])\n", + "https://hub.xpub.nl/soupboat/~chae/api/start-contaminating/\n", + "\n", + "@app.route(f'/{base_url}/the-etc-portal-is-never-opened/', methods = ['GET', 'POST'])\n", + "https://hub.xpub.nl/soupboat/~chae/api/the-etc-portal-is-never-opened/ \n", + "\n", + "@app.route(f'/{base_url}/the-etc-portal-is-closed/', methods = ['GET', 'POST'])\n", + "https://hub.xpub.nl/soupboat/~chae/api/the-etc-portal-is-closed/\n", + "\n", + "\n", + "# --------AND I WISH THAT YOUR QUESTION HAS BEEN ANSWERED------------ #\n", + "\n", + "@app.route(\"/{base_url}/and_i_wish_that_your_question_has_been_answered/\", methods=['GET', 'POST'])\n", + "https://hub.xpub.nl/soupboat/~grgr/api/and_i_wish_that_your_question_has_been_answered/\n", + "\n", + "@app.route(f\"/{base_url}/archive/\", methods=['GET'])\n", + "https://hub.xpub.nl/soupboat/~grgr/api/archive/\n", + "\n", + "@app.route(f\"/{base_url}/save/\", methods=['GET', 'POST'])\n", + "https://hub.xpub.nl/soupboat/~grgr/api/save/\n", + "\n", + "\n", + "# --------VERNACULAR MAPS------------ #\n", + "\n", + "@app.route(f\"/{base_url}/annotation-compass/\", methods=['GET', 'POST'])\n", + "\n", + "@app.route(f\"/{base_url}/annotation-compass/annotate//\", methods=['GET', 'POST'])\n", + "\n", + "@app.route(f\"/{base_url}/annotation-compass/get-labels/\", methods=['GET', 'POST'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56987d98-84ba-43c9-88a9-fc365cca2ecc", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_wip/si16_app.ipynb b/_wip/si16_app.ipynb new file mode 100644 index 0000000..bd75642 --- /dev/null +++ b/_wip/si16_app.ipynb @@ -0,0 +1,1266 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8d5fd4da-995d-4304-adcf-2464e0187053", + "metadata": {}, + "source": [ + "# Learning how to walk while cat-walking ~ demo app\n", + "Hello this is a demo for the SI16 API and website from XPUB. Trying to document everything so it is not OBSCURE. Feel free to improve anything!\n", + "\n", + "The folder structure follows this scheme: \n", + "- In the ```root``` folder there is the notebook (this file) that runs the Flask application. \n", + "- The ```templates``` folder is the default one from Flask with the HTML templates. \n", + "- In the ```notebooks``` folder there are the files with the basic functions and their documentation in the format of notebook. \n", + "- In the ```projects``` folder there are the folders of the subgroup projects. We can put the files and materials of each project in there as well as the html pages etc. Each project should have also an ```documentation.md``` file with the info of the work. \n", + "- In the ```static``` folder there are all the static files such as css stylesheets, fonts, images, javascript files, etc. They are organized in specific sub-folders so we dont get messy \n", + "- In the ```contents``` folder there are all the markdown files with the text contents for the website. Description of the projects, about, colophon, manifesto, research etc. Each file contains the text and can include some metadata of our choice. Look at the about.md for an example " + ] + }, + { + "cell_type": "markdown", + "id": "1213eab7-5ca7-4cd9-8d1b-4f625f961899", + "metadata": {}, + "source": [ + "## Import\n", + "Here we import all the modules we need for making the app working." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "b90f82e6-09b3-432d-9c02-596a4ca84e2f", + "metadata": {}, + "outputs": [], + "source": [ + "# to work with files in folder \n", + "import os\n", + "\n", + "# to create the Flask app\n", + "from flask import Flask, render_template, request, url_for, redirect, jsonify, abort\n", + "\n", + "# to import text contents and metadata from markdown files\n", + "from flaskext.markdown import Markdown\n", + "import frontmatter\n", + "\n", + "# to cast string arguments into the required types\n", + "from pydoc import locate\n", + "\n", + "# to work with notebooks\n", + "#\n", + "# to import notebook files\n", + "import nbimporter\n", + "nbimporter.options['only_defs'] = False\n", + "import importlib\n", + "\n", + "# to read and execute the content of notebooks\n", + "import nbformat\n", + "from nbconvert import HTMLExporter, MarkdownExporter\n", + "from nbconvert.preprocessors import ExecutePreprocessor\n", + "\n", + "# not sure about this is in the nbconvert documentation\n", + "from traitlets.config import Config\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "7c1bd05b-bc9c-4ac3-9654-61b2b17b0248", + "metadata": {}, + "source": [ + "## Functions\n", + "Here we define the functions for the logic of the backend and the API " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "8fe33b07-3f37-4cab-8729-7919d053ba00", + "metadata": {}, + "outputs": [], + "source": [ + "def filenames(folder):\n", + " ''' Read all the functions in a folder '''\n", + " names = []\n", + " for entry in os.scandir(folder):\n", + " # add to the list only proper files\n", + " if entry.is_file(follow_symlinks=False):\n", + " # remove the extension from the filename\n", + " names.append(os.path.splitext(entry.name)[0])\n", + " return names" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "73ece514-5247-4e89-b6a4-5afcf46f2afd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['vernacular_map', 'text_file_to_blob', 'shout', 'reverse', 'cocktail_generator', 'blob_to_excerpts_list', 'mashup', 'repeat', 'highlight_map', 'individual_map', 'bridge', 'add_target_info', 'area_map', 'input-back-to-text', 'target_map', 'ghost_map', 'html_tag']\n" + ] + } + ], + "source": [ + "# example: print the file inside the notebooks folder\n", + "print(filenames('./notebooks'))" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "b122207c-7ed7-4522-9b2f-018414d0f9fd", + "metadata": {}, + "outputs": [], + "source": [ + "def dirnames(folder):\n", + " ''' Return all the folders in a folder '''\n", + " names = []\n", + " for entry in os.scandir(folder):\n", + " # add to the list only proper files\n", + " if not entry.name.startswith('.') and entry.is_dir():\n", + " # remove the extension from the filename\n", + " names.append(entry.name)\n", + " return names" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "cd82bfbf-2f51-4caf-bfec-443aa2ba5112", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['etc', 'replace', 'map']\n" + ] + } + ], + "source": [ + "print(dirnames('./projects'))" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "f76b4396-2f11-4e9d-92bf-d20a884d30a1", + "metadata": {}, + "outputs": [], + "source": [ + "# not really sure about this file -> module -> function thing! \n", + "# could someone help pls ? \n", + "def get_function(name, folder):\n", + " ''' Dynamic import a function from a folder '''\n", + "# try: \n", + " file = __import__(f'{folder}.{name}')\n", + " module = getattr(file, name)\n", + " function = getattr(module, name)\n", + "# except AttributeError or ModuleNotFoundError:\n", + "# file = importlib.import_module(f'{folder}.{name}')\n", + "# function = getattr(file, name)\n", + " return function" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "7639cbfd-3f42-45e9-a201-1d87cbc88d00", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HelloHello\n", + "Saaaaaluuuuut\n" + ] + } + ], + "source": [ + "# example: try a couple of functions from the notebooks folder\n", + "rep = get_function('repeat', 'notebooks')\n", + "print(rep('Hello'))\n", + "\n", + "sh = get_function('shout','notebooks')\n", + "print(sh('Salut'))\n", + "\n", + "# sc = get_function('scream', 'notebooks')\n", + "# print(sc('Buenos dias'))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "d8c41597-5273-4a90-be8b-341b16b6e78f", + "metadata": {}, + "outputs": [], + "source": [ + "def get_function_info(function):\n", + " ''' Extract info from a function '''\n", + " name = function.__name__\n", + " description = function.__doc__\n", + " parameters = []\n", + " output = ''\n", + "\n", + " # TODO: default values \n", + " \n", + " # populate a list of tuple with patameter, type\n", + " for param in function.__annotations__.keys():\n", + " if param == 'return':\n", + " output = function.__annotations__[param].__name__\n", + " if param != 'return':\n", + " parameters.append((param, function.__annotations__[param].__name__))\n", + " \n", + " return(name, description, parameters, output)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "4925d9f1-9718-4407-84c7-8749aad365a8", + "metadata": {}, + "outputs": [], + "source": [ + "def print_info(function):\n", + " ''' Print the info of a function nicely '''\n", + " name, description, parameters, output = get_function_info(function)\n", + " \n", + " # very important feature\n", + " from kaomoji.kaomoji import Kaomoji\n", + " kao = Kaomoji()\n", + " \n", + " header = f'----------{kao.create()}'\n", + " footer = '-' * len(header)\n", + " \n", + " print(header)\n", + " print(name)\n", + " print(description)\n", + " print('Input:')\n", + " for param, tp in parameters:\n", + " print(f' {param}, of type {tp}')\n", + " print(f'Returns a {output}')\n", + " print(footer)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "baa72939-3853-49bf-b426-77fc041590ab", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "----------\(^ヮ☆)ノ\n", + "repeat\n", + "Repeat a string for a specified number of times\n", + "Input:\n", + " text, of type str\n", + " times, of type int\n", + "Returns a str\n", + "-----------------\n" + ] + } + ], + "source": [ + "print_info(rep)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "a4e67147-8f76-4d85-8d5b-b458a9b08ce6", + "metadata": {}, + "outputs": [], + "source": [ + "# optionally you can pass a boolean argument to execute the notebook before the export\n", + "# but it is a slow process so by default is not active\n", + "# TODO: markdown export instead of HTML ? \n", + "# TODO: extract images from base64\n", + "def get_notebook_contents(filename, execute = False):\n", + " ''' Export notebook contents as HTML. '''\n", + " with open(filename) as f:\n", + " nb = nbformat.read(f, as_version=4)\n", + " \n", + " if execute:\n", + " ep = ExecutePreprocessor(timeout=600, kernel_name='python3')\n", + " ep.preprocess(nb, {'metadata':{'path':'notebooks/'}})\n", + " \n", + " html_exporter = HTMLExporter() \n", + " html_exporter.template_name = 'basic' \n", + " (body, resources) = html_exporter.from_notebook_node(nb) \n", + " \n", + " return body\n", + " \n", + "# with open('executed_notebook.ipynb', 'w', encoding='utf-8') as f:\n", + "# nbformat.write(nb, f)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "a1a7edab-1cf0-4d8e-8d80-7b33704dd9ce", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'\\n\\n\\n\\n\\nNotebook\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n \\n\\n\\n\\n\\n \\n \\n \\n \\n\\n\\n
\\n
\\n

Repeat

Repeat a string for a specified number of times

\\n\\n
\\n
\\n
\\n
\\n
In [1]:
\\n
\\n
\\n
def repeat(text: str, times: int = 2) -> str:\\n    """Repeat a string for a specified number of times"""\\n    return text * times\\n
\\n\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n
\\n

\"ara

\\n\\n
\\n
\\n
\\n
\\n

This function has many attractive qualities, but its ability to repeat human speech is one that makes it truly unique among other types of companion python functions and one that has ensured its popularity for generations. You are likely to find, though, that the function\\'s talents for mimicry still pales in comparison to the fact that it is charming, engaging, and truly remarkable. Here is one of the most popular repeating function so that you can appreciate more about what it has to offer. It often says injuries to people and computers.

\\n\\n
\\n
\\n
\\n
\\n

Examples

The function takes a string as a parameter, and by default it repeats it twice.

\\n\\n
\\n
\\n
\\n
\\n
In [2]:
\\n
\\n
\\n
repeat('hello')\\n
\\n\\n
\\n
\\n
\\n
\\n\\n
\\n\\n\\n
\\n\\n
\\n\\n \\n
Out[2]:
\\n\\n\\n\\n\\n
\\n
'hellohello'
\\n
\\n\\n
\\n\\n
\\n\\n
\\n\\n
\\n
\\n
\\n

Eventually with a second parameter you can specify how many times you want it to repeats.

\\n\\n
\\n
\\n
\\n
\\n
In [3]:
\\n
\\n
\\n
repeat('salut', 4)\\n
\\n\\n
\\n
\\n
\\n
\\n\\n
\\n\\n\\n
\\n\\n
\\n\\n \\n
Out[3]:
\\n\\n\\n\\n\\n
\\n
'salutsalutsalutsalut'
\\n
\\n\\n
\\n\\n
\\n\\n
\\n\\n
\\n
\\n
\\n
In [ ]:
\\n
\\n
\\n
 \\n
\\n\\n
\\n
\\n
\\n
\\n\\n
\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n'" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_notebook_contents('./notebooks/repeat.ipynb')" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "93fca26c-73b2-42b0-a08e-ca864744e7e2", + "metadata": {}, + "outputs": [], + "source": [ + "# EXPORT AS MARKDOWN\n", + "def get_notebook_md(filename, execute = False):\n", + " ''' Export notebook contents as Markdown. '''\n", + " with open(filename) as f:\n", + " nb = nbformat.read(f, as_version=4)\n", + " \n", + " if execute:\n", + " ep = ExecutePreprocessor(timeout=600, kernel_name='python3')\n", + " ep.preprocess(nb, {'metadata':{'path':'notebooks/'}})\n", + " \n", + " md_exporter = MarkdownExporter() \n", + " \n", + "# html_exporter.template_name = 'basic' \n", + " (body, resources) = md_exporter.from_notebook_node(nb) \n", + " \n", + " return body\n", + " \n", + "# with open('executed_notebook.ipynb', 'w', encoding='utf-8') as f:\n", + "# nbformat.write(nb, f)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "f51f6261-f4f6-4b9a-96ab-e92a6e93c2a3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# Repeat\n", + "Repeat a string for a specified number of times\n", + "\n", + "\n", + "```python\n", + "def repeat(text: str, times: int = 2) -> str:\n", + " \"\"\"Repeat a string for a specified number of times\"\"\"\n", + " return text * times\n", + "```\n", + "\n", + "![ara repeating itself](https://www.dienst.nl/sub/upload/images/1/30019_550.jpg)\n", + "\n", + "This function has many attractive qualities, but its ability to repeat human speech is one that makes it truly unique among other types of companion python functions and one that has ensured its popularity for generations. You are likely to find, though, that the function's talents for mimicry still pales in comparison to the fact that it is charming, engaging, and truly remarkable. Here is one of the most popular repeating function so that you can appreciate more about what it has to offer. It often says injuries to people and computers. \n", + "\n", + "## Examples\n", + "\n", + "The function takes a string as a parameter, and by default it repeats it twice. \n", + "\n", + "\n", + "```python\n", + "repeat('hello')\n", + "```\n", + "\n", + "\n", + "\n", + "\n", + " 'hellohello'\n", + "\n", + "\n", + "\n", + "Eventually with a second parameter you can specify how many times you want it to repeats. \n", + "\n", + "\n", + "```python\n", + "repeat('salut', 4)\n", + "```\n", + "\n", + "\n", + "\n", + "\n", + " 'salutsalutsalutsalut'\n", + "\n", + "\n", + "\n", + "\n", + "```python\n", + "\n", + "```\n", + "\n" + ] + } + ], + "source": [ + "print(get_notebook_md('./notebooks/repeat.ipynb'))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9debce59-d77c-4bae-b090-e4b78ffae43b", + "metadata": {}, + "outputs": [], + "source": [ + "def get_contents(filename, directory = './contents'):\n", + " ''' Return contents from a filename as frontmatter handler '''\n", + " with open(f\"{directory}/{filename}\", \"r\") as f:\n", + " content = frontmatter.load(f)\n", + " return content" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "ae55a519-f12b-44b5-91c0-707bdaed6800", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "About\n", + "These are the info about SI16 - Learning how to walk while cat-walking\n", + "\n", + "Dear friend and online scroller,\n", + "Beloved internet user, \n", + "Dearest anonymous scroller binge watcher and human being IRL, \n", + "\n", + "![bibi](/soupboat/si16-app/static/img/bibi.jpg)\n", + "\n", + "Do you like cats? Fond of Walking? Never heard of Python? (No. Not the snake) \n", + "Great. \n", + "You're very welcome to check out our Special Issue 16 on vernacular language processing: Learning How to Walk while Cat-walking. It is about embracing vulnerability, sharing the clumsiness with little time and little technical knowledge in the form of a toolkit and encourage others to cat-walk with us.\n", + "\n", + "Our toolkit wants to mess around with language that creates relations of power in its structuring information, in its grammar rules, in its standard taxonomies, categories and tags, in its organizing data and shaping knowledge, in its legitimizing hierarchies in a dialogue between two or more people... |__(we could use the etc tool here heheh)__| in order to propose tools for a word based analysis grounded within a more vernacular and informal understanding of language as such. \n", + "\n", + "We decided to release the Special Issue 16 as an API (Application Programming Interfaces), the kind of protocol through which most of the internet we use functions, but remaining invisible, mysterious and somehow intangible. What is not always evident is that while facilitating the exchange of information between different software programs and systems, APIs often organise and serve data and knowledge, according to specific standards and purposes (mainly commercial). \n", + "\n", + "Our API wants to have a more critical and vernacular approach to such model of distribution, but don't worry if you didn't understand, we'll guide you through it while still trying to figure out what an API means ourselves. What we know for sure is that:\n", + "\n", + "we are confident, we are ambitious and we are failing a lot while learn\u0002ing how to walk while cat-walking. We want to legitimize failures and amateur practices outside the hierarchy of experience. We want to deconstruct those hierarchies taking care of each other in the process of learning, now between us, and then with you. We approach the text as a texture, a malleable clay tablet, a space for foreign input and extensive modifications, for cut-up and for collage, for collective agency and participation. We work to sort out several mean\u0002ings from the same text. Meanings with perspective and a common ground. We intend to blur our roles as authors, as users, and as public because this is an act of collective world building.\n" + ] + } + ], + "source": [ + "# example: print the contents of the about file\n", + "test_about = get_contents('about.md')\n", + "\n", + "print(test_about['title'])\n", + "print(test_about['description'])\n", + "print()\n", + "print(test_about.content)" + ] + }, + { + "cell_type": "markdown", + "id": "a8c17569-b74e-48d1-86a9-ba1e6f61af1f", + "metadata": {}, + "source": [ + "## Flask App" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30798f7b-671b-42d9-a343-eb713f513806", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " * Serving Flask app '__main__' (lazy loading)\n", + " * Environment: production\n", + "\u001b[31m WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n", + "\u001b[2m Use a production WSGI server instead.\u001b[0m\n", + " * Debug mode: off\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " * Running on http://127.0.0.1:3130/ (Press CTRL+C to quit)\n", + "127.0.0.1 - - [08/Dec/2021 19:21:38] \"GET /si16-app/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 19:21:40] \"GET /si16-app/projects/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 19:21:43] \"GET /si16-app/functions/ HTTP/1.0\" 200 -\n", + "[2021-12-08 19:21:47,463] ERROR in app: Exception on /si16-app/functions/area_map/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 6, in get_function\n", + " file = __import__(f'{folder}.{name}')\n", + " File \"\", line 983, in _find_and_load\n", + " File \"\", line 967, in _find_and_load_unlocked\n", + " File \"\", line 668, in _load_unlocked\n", + " File \"\", line 638, in _load_backward_compatible\n", + " File \"/usr/local/lib/python3.7/dist-packages/nbimporter.py\", line 110, in load_module\n", + " exec(codeobj, mod.__dict__)\n", + " File \"/var/www/html/si16-app/notebooks/area_map.ipynb\", line 4, in \n", + " \"cell_type\": \"markdown\",\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 222, in urlopen\n", + " return opener.open(url, data, timeout)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 531, in open\n", + " response = meth(req, response)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 641, in http_response\n", + " 'http', request, response, code, msg, hdrs)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 569, in error\n", + " return self._call_chain(*args)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 503, in _call_chain\n", + " result = func(*args)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 649, in http_error_default\n", + " raise HTTPError(req.full_url, code, msg, hdrs, fp)\n", + "urllib.error.HTTPError: HTTP Error 502: Bad Gateway\n", + "127.0.0.1 - - [08/Dec/2021 19:21:47] \"\u001b[35m\u001b[1mGET /si16-app/functions/area_map/ HTTP/1.0\u001b[0m\" 500 -\n", + "127.0.0.1 - - [08/Dec/2021 19:21:53] \"GET /si16-app/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 19:21:57] \"GET /si16-app/functions/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 19:22:00] \"GET /si16-app/functions/ HTTP/1.0\" 200 -\n", + "[2021-12-08 19:22:02,228] ERROR in app: Exception on /si16-app/functions/reverse/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 6, in get_function\n", + " file = __import__(f'{folder}.{name}')\n", + " File \"\", line 983, in _find_and_load\n", + " File \"\", line 967, in _find_and_load_unlocked\n", + " File \"\", line 668, in _load_unlocked\n", + " File \"\", line 638, in _load_backward_compatible\n", + " File \"/usr/local/lib/python3.7/dist-packages/nbimporter.py\", line 110, in load_module\n", + " exec(codeobj, mod.__dict__)\n", + " File \"/var/www/html/si16-app/notebooks/reverse.ipynb\", line 1, in \n", + " {\n", + " File \"/var/www/html/si16-app/notebooks/reverse.ipynb\", line 6, in reverse\n", + " \"metadata\": {},\n", + "TypeError: sequence item 0: expected str instance, Sentence found\n", + "127.0.0.1 - - [08/Dec/2021 19:22:02] \"\u001b[35m\u001b[1mGET /si16-app/functions/reverse/ HTTP/1.0\u001b[0m\" 500 -\n", + "127.0.0.1 - - [08/Dec/2021 19:22:05] \"GET /si16-app/functions/shout/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 20:06:26] \"GET /si16-app/functions/ HTTP/1.0\" 200 -\n", + "[2021-12-08 20:06:28,827] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 6, in get_function\n", + " file = __import__(f'{folder}.{name}')\n", + " File \"\", line 983, in _find_and_load\n", + " File \"\", line 967, in _find_and_load_unlocked\n", + " File \"\", line 668, in _load_unlocked\n", + " File \"\", line 638, in _load_backward_compatible\n", + " File \"/usr/local/lib/python3.7/dist-packages/nbimporter.py\", line 110, in load_module\n", + " exec(codeobj, mod.__dict__)\n", + " File \"/var/www/html/si16-app/notebooks/cocktail_generator.ipynb\", line 1, in \n", + " {\n", + "NameError: name 'repeat' is not defined\n", + "127.0.0.1 - - [08/Dec/2021 20:06:28] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n", + "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n", + "* *\n", + "* CATWALKING WITH ALCOHOL *\n", + "* *\n", + "* 2021-12-08 21:06:28 *\n", + "* *\n", + "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n", + "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n", + "\n", + "\n", + "\n", + "2 oz RUM\n", + "\n", + "150 ml TONIC WATER\n", + "\n", + "1 oz LEMON JUICE\n", + "\n", + "0.5 oz MAPLE SIRUP\n", + "\n", + "1 SLICE CUCUMBER\n", + "\n", + "1 UMBRELLA\n", + "\n", + "\n", + "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n", + "\n", + "EXTRA: SALTED CORN\n", + "\n", + "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n", + "\n", + "\n", + "\n", + " ___, \n", + " '._.'\\ \n", + " _____/'-.\\ \n", + " | / | \n", + " |~~~/~~| \n", + " \\ () / \n", + " '.__.' \n", + " || \n", + " _||_ \n", + " `----` \n", + "\n", + "\n", + "THANKS FOR COMING TO OUR LAUNCH!\n", + "\n", + " (*(*(*(*(*.(*.*).*)*)*)*)*)*)\n", + "\n", + "\n", + "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n", + "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2021-12-08 20:06:33,187] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:06:33] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "127.0.0.1 - - [08/Dec/2021 20:06:35] \"GET /si16-app/functions/repeat/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 20:06:46] \"GET /si16-app/api/repeat/?text=%2Cjchvja×=5 HTTP/1.0\" 200 -\n", + "[2021-12-08 20:27:24,058] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:27:24] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "127.0.0.1 - - [08/Dec/2021 20:27:26] \"GET /si16-app/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 20:27:33] \"GET /si16-app/functions/ HTTP/1.0\" 200 -\n", + "[2021-12-08 20:27:35,691] ERROR in app: Exception on /si16-app/functions/area_map/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'area_map'\n", + "127.0.0.1 - - [08/Dec/2021 20:27:35] \"\u001b[35m\u001b[1mGET /si16-app/functions/area_map/ HTTP/1.0\u001b[0m\" 500 -\n", + "127.0.0.1 - - [08/Dec/2021 20:27:39] \"GET /si16-app/functions/repeat/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 20:27:41] \"GET /si16-app/functions/vernacular_map/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 20:27:49] \"GET /si16-app/functions/highlight_map/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 20:27:53] \"GET /si16-app/functions/individual_map/ HTTP/1.0\" 200 -\n", + "[2021-12-08 20:27:56,210] ERROR in app: Exception on /si16-app/functions/area_map/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'area_map'\n", + "127.0.0.1 - - [08/Dec/2021 20:27:56] \"\u001b[35m\u001b[1mGET /si16-app/functions/area_map/ HTTP/1.0\u001b[0m\" 500 -\n", + "127.0.0.1 - - [08/Dec/2021 20:27:59] \"GET /si16-app/functions/target_map/ HTTP/1.0\" 200 -\n", + "[2021-12-08 20:28:05,706] ERROR in app: Exception on /si16-app/functions/ghost_map/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 6, in get_function\n", + " file = __import__(f'{folder}.{name}')\n", + " File \"\", line 983, in _find_and_load\n", + " File \"\", line 967, in _find_and_load_unlocked\n", + " File \"\", line 668, in _load_unlocked\n", + " File \"\", line 638, in _load_backward_compatible\n", + " File \"/usr/local/lib/python3.7/dist-packages/nbimporter.py\", line 110, in load_module\n", + " exec(codeobj, mod.__dict__)\n", + " File \"/var/www/html/si16-app/notebooks/ghost_map.ipynb\", line 4, in \n", + " \"cell_type\": \"markdown\",\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 222, in urlopen\n", + " return opener.open(url, data, timeout)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 531, in open\n", + " response = meth(req, response)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 641, in http_response\n", + " 'http', request, response, code, msg, hdrs)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 569, in error\n", + " return self._call_chain(*args)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 503, in _call_chain\n", + " result = func(*args)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 649, in http_error_default\n", + " raise HTTPError(req.full_url, code, msg, hdrs, fp)\n", + "urllib.error.HTTPError: HTTP Error 502: Bad Gateway\n", + "127.0.0.1 - - [08/Dec/2021 20:28:05] \"\u001b[35m\u001b[1mGET /si16-app/functions/ghost_map/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:28:08,257] ERROR in app: Exception on /si16-app/functions/html_tag/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 6, in get_function\n", + " file = __import__(f'{folder}.{name}')\n", + " File \"\", line 983, in _find_and_load\n", + " File \"\", line 967, in _find_and_load_unlocked\n", + " File \"\", line 668, in _load_unlocked\n", + " File \"\", line 638, in _load_backward_compatible\n", + " File \"/usr/local/lib/python3.7/dist-packages/nbimporter.py\", line 110, in load_module\n", + " exec(codeobj, mod.__dict__)\n", + " File \"/var/www/html/si16-app/notebooks/html_tag.ipynb\", line 4, in \n", + " \"cell_type\": \"markdown\",\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 222, in urlopen\n", + " return opener.open(url, data, timeout)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 531, in open\n", + " response = meth(req, response)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 641, in http_response\n", + " 'http', request, response, code, msg, hdrs)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 569, in error\n", + " return self._call_chain(*args)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 503, in _call_chain\n", + " result = func(*args)\n", + " File \"/usr/lib/python3.7/urllib/request.py\", line 649, in http_error_default\n", + " raise HTTPError(req.full_url, code, msg, hdrs, fp)\n", + "urllib.error.HTTPError: HTTP Error 502: Bad Gateway\n", + "127.0.0.1 - - [08/Dec/2021 20:28:08] \"\u001b[35m\u001b[1mGET /si16-app/functions/html_tag/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:28:10,772] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:28:10] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "127.0.0.1 - - [08/Dec/2021 20:28:38] \"GET /si16-app/functions/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 20:28:39] \"GET /si16-app/functions/ HTTP/1.0\" 200 -\n", + "[2021-12-08 20:28:43,774] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:28:43] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:29:15,253] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:29:15] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:29:17,751] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:29:17] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:29:18,966] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:29:18] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:30:16,613] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:30:16] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:30:18,488] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:30:18] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "127.0.0.1 - - [08/Dec/2021 20:30:41] \"GET /si16-app/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 20:30:42] \"GET /si16-app/functions/ HTTP/1.0\" 200 -\n", + "[2021-12-08 20:30:44,432] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:30:44] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:30:46,387] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:30:46] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:30:47,458] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:30:47] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:30:48,412] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:30:48] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:31:01,247] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:31:01] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:31:02,386] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:31:02] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "[2021-12-08 20:31:03,557] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:31:03] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n", + "127.0.0.1 - - [08/Dec/2021 20:31:05] \"GET /si16-app/ HTTP/1.0\" 200 -\n", + "127.0.0.1 - - [08/Dec/2021 20:31:07] \"GET /si16-app/functions/ HTTP/1.0\" 200 -\n", + "[2021-12-08 20:31:08,112] ERROR in app: Exception on /si16-app/functions/cocktail_generator/ [GET]\n", + "Traceback (most recent call last):\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 2073, in wsgi_app\n", + " response = self.full_dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1518, in full_dispatch_request\n", + " rv = self.handle_user_exception(e)\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1516, in full_dispatch_request\n", + " rv = self.dispatch_request()\n", + " File \"/usr/local/lib/python3.7/dist-packages/flask/app.py\", line 1502, in dispatch_request\n", + " return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)\n", + " File \"/tmp/ipykernel_9986/665664178.py\", line 76, in f_info\n", + " fx = get_function(function, notebooks)\n", + " File \"/tmp/ipykernel_9986/867254570.py\", line 7, in get_function\n", + " module = getattr(file, name)\n", + "AttributeError: module 'notebooks' has no attribute 'cocktail_generator'\n", + "127.0.0.1 - - [08/Dec/2021 20:31:08] \"\u001b[35m\u001b[1mGET /si16-app/functions/cocktail_generator/ HTTP/1.0\u001b[0m\" 500 -\n" + ] + } + ], + "source": [ + "# create flask application\n", + "app = Flask(__name__)\n", + "Markdown(app)\n", + "\n", + "base_url = \"si16-app\"\n", + "notebooks = \"notebooks\"\n", + "projects = \"projects\"\n", + "\n", + "\n", + "# For specific pages we can build and link dedicated templates\n", + "\n", + "\n", + "# Homepage\n", + "@app.route(f\"/{base_url}/\")\n", + "def home_page():\n", + " return render_template(\"home.html\")\n", + "\n", + "\n", + "# About Page\n", + "@app.route(f\"/{base_url}/about/\")\n", + "def about_page():\n", + " about = get_contents('about.md')\n", + " return render_template(\"about.html\", title = about['title'], description = about['description'], contents=about.content)\n", + "\n", + "# Terms of Service page\n", + "@app.route(f\"/{base_url}/tos/\")\n", + "def tos_page():\n", + " about = get_contents('tos.md')\n", + " return render_template(\"tos.html\", title = about['title'], description = about['description'], contents=about.content)\n", + "\n", + "# For generic pages we can include a common template and change only the contents\n", + "@app.route(f\"/{base_url}//\")\n", + "def dynamic_page(slug = None):\n", + " try:\n", + " page = get_contents(f\"{slug}.md\").to_dict()\n", + " # page is a dictionary that contains: \n", + " # - all the attributes in the markdown file (ex: title, description, soup, etc)\n", + " # - the content of the md in the property 'content'\n", + " # in this way we can access those frontmatter attributes in jinja simply using the variables title, description, soup, etc\n", + " return render_template(\"page.html\", **page)\n", + " except FileNotFoundError:\n", + " # TODO: a proper not found page\n", + " return render_template('404.html')\n", + "\n", + "\n", + "\n", + "# List of projects\n", + "@app.route(f\"/{base_url}/projects/\")\n", + "def projects_list():\n", + " # get a list of the functions from the notebooks folder\n", + " projects = dirnames(\"./projects\")\n", + "\n", + " # generate a link to each function\n", + " return render_template(\"projects.html\", projects=projects)\n", + "\n", + "\n", + "# Single project\n", + "@app.route(f\"/{base_url}/projects//\")\n", + "def p_info(project = None):\n", + " try:\n", + " page = get_contents(\"documentation.md\", f\"./{projects}/{project}\").to_dict()\n", + " return render_template(\"project.html\", **page)\n", + " except FileNotFoundError:\n", + " return render_template('404.html')\n", + " \n", + "\n", + " \n", + "# List of functions\n", + "@app.route(f\"/{base_url}/functions/\")\n", + "def functions_list():\n", + " # get a list of the functions from the notebooks folder\n", + " functions = filenames(\"./notebooks\")\n", + "\n", + " # generate a link to each function\n", + " return render_template(\"functions.html\", functions=functions)\n", + "\n", + "\n", + "# Single Function page\n", + "@app.route(f\"/{base_url}/functions//\")\n", + "def f_info(function=None):\n", + " if function in filenames(f\"./{notebooks}\"):\n", + " fx = get_function(function, notebooks)\n", + " name, description, parameters, output = get_function_info(fx)\n", + "\n", + " # executing a notebook takes a lot of time mmm should we just send them without the results of the examples? or save it executed?\n", + " documentation = get_notebook_contents(f\"./{notebooks}/{function}.ipynb\")\n", + "\n", + " return render_template(\"function.html\", name=name, description=description, parameters=parameters, output=output, documentation=documentation)\n", + "\n", + " # TODO: meaningful error code return\n", + " else:\n", + " return render_template('404.html')\n", + "\n", + " \n", + " \n", + "# Function API page\n", + "\n", + "@app.route(f\"/{base_url}/api//\")\n", + "def f_api(function=None):\n", + " if function in filenames(f\"./{notebooks}\"):\n", + "\n", + " fx = get_function(function, notebooks)\n", + " name, description, parameters, output = get_function_info(fx)\n", + "\n", + " query_params = []\n", + " for param, tp in parameters:\n", + " a = request.args.get(param)\n", + " # cast the type of the argument to the type that the function requires\n", + " tp = locate(tp)\n", + " a = tp(a)\n", + " query_params.append(a)\n", + " return fx(*query_params)\n", + "\n", + " # TODO: meaningful error code return\n", + " return \"mmmm there is no function with this name sorry\"\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Error handlers!\n", + "@app.errorhandler(400)\n", + "def error_400(e):\n", + " # bad request or invalid url\n", + " return render_template('400.html'), 400\n", + "\n", + "@app.errorhandler(403)\n", + "def error_403(e):\n", + " # forbidden (for invalid key) for evemt mode when it's not the 17th of the month\n", + " return render_template('403.html'), 403\n", + "\n", + "@app.errorhandler(404)\n", + "def error_404(e):\n", + " # page not found\n", + " return render_template('404.html'), 404\n", + "\n", + "@app.errorhandler(500)\n", + "def error_500(e):\n", + " # internal server error\n", + " return render_template('500.html'), 500\n", + "\n", + "@app.errorhandler(502)\n", + "def error_502(e):\n", + " # bad gateaway\n", + " return render_template('502.html'), 502\n", + "\n", + "@app.errorhandler(503)\n", + "def error_503(e):\n", + " # service temporarily unavailable, for secret breaks\n", + " return render_template('503.html'), 503\n", + "\n", + "@app.errorhandler(504)\n", + "def error_503(e):\n", + " # ???????? gateway timeout shall we put it?????\n", + " return render_template('504.html'), 504\n", + "app.run(port=\"3130\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47c97ec9-9707-4896-8595-ac70aa5e6199", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96f5dbe2-36a2-4b2c-9e5b-99eef418fcda", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/contents/about.md b/contents/about.md new file mode 100644 index 0000000..6460d2d --- /dev/null +++ b/contents/about.md @@ -0,0 +1,34 @@ +--- +title: About +description: Information About the SI16 - Learning How To Walk While Catwalking +url: +--- + +### INFO + +Learning How to Walk While Catwalking, XPUB, 2021 + +XPUB (the Experimental Publishing master from Piet Zwart Institute, Willem de Kooning Academy) welcomes you to the Special Issue 16 on vernacular language processing: Learning How to Walk while Catwalking. + +Our Special Issue is a toolkit to mess around with language: from its standard taxonomies and tags, to its modes of organizing information and its shaping knowledge. With these tools we want to legitimize failures and amatorial practices by proposing a more vernacular understanding of language. + +We decided to release the Special Issue 16 toolkit in the form of an API (Application Programming Interface). APIs organise and serve data on the Internet; what is not always evident is that they facilitate exchange of information following mainly commercial purposes. However, Our API is an attempt at a more critical and vernacular approach to such model of distribution. You didn't get a thing yet? Don't worry! We are also on our way and that's the whole point of this experimental enquiry. We will be happy to guide you through the API and the different functions included in it, share our technical struggles and findings. + +The overall project as mentioned above is a toolkit, thus hosts multiple tools. The SI16 website is a vessel for you to navigate from one to another of those projects smoothly. Where you will enter a sea of possibilities. + +This project is characterized by the elaboration of functions, at the heart of our tools, that consider and process vernacular languages. The material we process comes from various sources. For some of it, we appropriated existing texts and compiled them into corpora. Alternatively, the activation of certain functions calls for an audience’s input. The participatory aspect of the functions is an important factor that unites them. + +We approach the text as a texture, a malleable clay tablet, a space for foreign input and extensive modifications, for cut-up and for collage, for collective agency and participation. Not a surface but a volume, in which the text is not only text, but a shared space. We work to sort out several meanings from the same text. We intend to blur our roles as authors, users and public because this is an act of collective world building. + +The Special Issue 16's title "Learning How To Walk While Catwalking" is a playful mention to illustrate how we experienced the present project and the mentality in which we want you to engage with it: be confident, be ambitious and be ready to fail a lot. + + + +### COLOPHON + +All the code and the contents produced through this API are automatically licensed under the Catleft Licence. (url Licence?) + +Gersande Schellinx, Mitsa (Dimitra Chaida), Erica Gargaglione, Francesco Luzzana, Chaeyoung Kim, Emma Prato, Miriam Schöb, Supisara Burapachaisri, Jian Haake, Ål Nik (Alexandra Nikolova), Kimberley Cosmilla, Carmen Gray +Manetta Michael Cristina Steve Clara Danny Aymeric Simon Etc + +Pirelli is a nice typeface from Jung-Lee Type Foundry (J-LTF) \ No newline at end of file diff --git a/contents/corpora.md b/contents/corpora.md new file mode 100644 index 0000000..3c87aa8 --- /dev/null +++ b/contents/corpora.md @@ -0,0 +1,11 @@ +--- +title: Corpora +description: Information About the SI16's Corpora +url: +--- + +## INFO + +The functions from the Special Issue 16 were built to experiment and play around with vernacular language processing. Before a tool can replace, contaminate, reverse or mashup, it needs textual material as an input. + +Here we gather corpora, small collections of linguistic data that were inspiring and useful in our research, experiments or projects. \ No newline at end of file diff --git a/contents/functions.md b/contents/functions.md new file mode 100644 index 0000000..6291e5f --- /dev/null +++ b/contents/functions.md @@ -0,0 +1,17 @@ +--- +title: Functions +description: Information About the SI16's Functions +url: +--- + +## INFO + +The functions from the Special Issue 16 have been freshly delivered into this world for you. Our first steps into the realm of Language Processing, our first attempts at Vernacular Language Processing. + +What we share with you here are stripped-out functions we made use of in our tools. Some might still need more context than others, but essentially they can be used in different fashions depending of the users' wants and needs. + +We wanted you, whoever you are: friend or online scroller, beloved internet user or binge watcher, even IRL human being … whoever you are! We wanted us to share with you how our tools came to life, expose the internal mechanism to the text processing you are about to engage with. + +You didn't quite get it? Basically, our project is meant to give a bunch of users several tools such as : ✂️ scissors, 📃 sticky notes, ✏️ pencils, erasers, and printed paper. ✂️🖊📝✏️📃 And let them have fun. Cutting it and putting it together, making notes and writing jokes … But everything in a digital format. + +Have a look around and have fun! diff --git a/contents/intro.md b/contents/intro.md new file mode 100644 index 0000000..48ec2f1 --- /dev/null +++ b/contents/intro.md @@ -0,0 +1,109 @@ +--- +title: Intro +description: Manifesto with Vernacular Excitement +css: intro.css +--- + + + + + +

+Dear friend and online scroller,
+Beloved internet user,
+Dearest binge watcher and human being IRL, +

+ +XPUB1 (The Experimental Publishing Master from Piet Zwart Institute) welcomes you to the Special Issue 16 on vernacular language processing: "Learning How to Walk while Catwalking." + +

+Hu? How do you learn how to walk while catwalking? +

+ +Be confident, be ambitious and be ready to fail a lot. +Our Special Issue is a toolkit to mess around with language: from its standard taxonomies and tags, to its modes of organizing information and its shaping knowledge. With these tools we want to legitimize failures and amatorial practices by proposing a more vernacular understanding of language. + +We decided to release the Special Issue 16-toolkit in the form of an API (Application Programming Interface). + +APIs often organise and serve data and knowledge. + +What is not always evident is that they facilitate the exchange of information between different software programs and systems according to mainly commercial standards and purposes. We chose instead to build a process that responds to the topics we are working with. + +Our API is an attempt at a more critical and vernacular approach to such model of distribution. You didn't get a thing yet? Don't worry! We are also on our way and that's the whole point of this experimental enquiry. We will be happy to guide you through the API and the different functions included in it, share our technical struggles and findings. + +

+This project is characterized by the elaboration of vernacular methods of processing. The material we process comes from various sources. For some of it, we appropriated existing texts and compiled them into corpora. For others, the activation of certain functions calls for an audience’s input. The participatory aspect of the functions is an important factor that unites them. +

+ +Since we are working with filters, we realized how every cultural object rejects and filters its public. We want to question these limitations focusing on accessibility and proposing several entry points to our project. + +

+API, there’s this very good meme that, I think, explains it in a rather good way. Imagine a bar with different staff in it: The cooks working in the kitchen would be the ‘backend’, the ones behind the bar the ‘frontend’, andddd the waiters running from the bar to the tables are the API! +

+ +

+Something that feels informal, approachable, "ours" and not imposed standarized forms. Organic, with the spanish opening times, etc. Approachable. +

+ +

+wtf I don't really understand but I like it +

+ +In other words, a toolkit for processing language with a vernacular attitude. This toolkit does not only consist of a set of tools but also of a world we are building around them: how do we want these tools to affect reality? This toolkit can be expanded, as new tools can be added to it and the world around them being stretched. There is a strong focus on the way we are working on it: a decentralized approach that builds from the ground up. + +

+Ambitious! Political! Unstable! ...but as some point embracing this unstability, trying to learn and care for each other, while learning python and caring for API . +

+

+I think of it as a personification of something that's intended to be functional, in that we assign the API a particular behavior so that it does the unexpected. +

+

+Opening times? +

+ +We are confident, we are ambitious and we are failing a lot while Learning How To Walk While Catwalking. We want to legitimize failures and amateur practices outside the hierarchy of experience. We want to care of each other in the process of learning, now between us, and then with you. +We approach the text as a texture, a malleable clay tablet, a space for foreign input and extensive modifications, for cut-up and for collage, for collective agency and participation. Not a surface but a volume, in which the text is not only text, but a shared space. We work to sort out several meanings from the same text. We intend to blur our roles as authors, users and public because this is an act of collective world building. + +

+I was invited to get onto an online platform for something called the Special Issue 16(?) The front, or first page has an index with some descriptions. Overall it had to do with texts, and ways of modifying them, I think. +

+

+Landing on Special Issue 16 page, reading the 'about' page. Finding out about several projects, triggered by the different showcases. As I gain interest in one of the example, I click on a link and read about the intention from which this tool departed. +

+ +

+So well, I am in front of the screen, I click on the first link and get a description and a sort of instruction of how to use their tools. Fine, I'll use the tool. It seems like I'm not the only one who has been invited here, the layout is unfamiliar, but I see how I could partake in it. And if I do, well, the next person will also have something else to deal with, I'm into that. What could I write? I write. Oh, wasn't that hard. +

+

+Unapologetic. Fearless. Eager. Playful. Brave. Persistent. Experimental. Bvvvrruummm +

+

+I am curious to know even more, I click on the shared folder link and am redirected to a library of tools. Finding out I can use this tool for my own purposes. I start scrolling through the multiple tools offered there. From the tool I was initially interested on, I drift to another snippet that calls my attention. From there, I click on the link offering a 'showcase view'. I get acquainted with the example. Zooming out, I land on the 'about page' to which that project belongs. More tools are offered but I am not interested in more tools. I zoom out more, and I find the 'introduction', which informs me about the general purpose of this page. +

+

+OMG THIS IS. HERE? +

+

+ wow these people are so meta +

+

+can you buy me a coke? +

+

+I clicked on the link to access this website: oh what happens nice! nice colours, I have icons to click on but I clicked on one and I've seen many things i don't understand so it's better to know what this is about first because I don't understand so I click on the about page. +Ok let's move back to the homepage. I can choose between projects and functions (again, what's this????) ok maybe by looking at the projects I will understand better... +

+

+Embracing the chaos that comes with the learning curve. +

+

+I click on a link and am brought to a page and keep clicking, can't stop clicking, super curious what's happening here, not sure what exactly yet, but it doesn't matter. I see the about page but I'd rather not read it because I like surprises. Looks like they're making a lot of experimental tools I've never heard of before but always wanted to try. +

+ +

+What is this all about? Shall we open the window for some fresh air?. +

+ +Yes that was a bit conceptual but basically, our project is meant to give a bunch of users several tools such as : ✂️ scissors, 📃 sticky notes, ✏️ pencils, erasers, and printed paper. ✂️🖊📝✏️📃 And let them have fun. Cutting it and putting it together, making notes and writing jokes… But everything in a digital format. + +Q&A link link link diff --git a/contents/license.md b/contents/license.md new file mode 100644 index 0000000..499878d --- /dev/null +++ b/contents/license.md @@ -0,0 +1,16 @@ +--- +title: License +description: Information About the SI16's License +url: +--- + +------------------------------------------Catleft License-------------------------------------------- + +The Catleft license wants to legitimise failures, promote critical approaches, and embrace the user as co-author. + +Conditions for reuse: +1. Any reproduction or redistribution of the material under this license has to be readable by both humans and machines. +2. It is adviced to use, reproduce, modify and redistribute the material according to the user's own language and dialect. +3. The material can be reproduced, distributed, or transmitted in any form, by any means, and any purpose except for commercial purposes. In this case, the material can only be reused with the written permission of one of the license holders. For permission requests, write to XPUB department. +4. Always include this license with the distribution of your project or specify where it can be found it. +Make a copy of the text of the license and paste it with the date and name of the license holder. Put this license file in the root directory of your project repository and include it with the distribution of your project. diff --git a/contents/projects.md b/contents/projects.md new file mode 100644 index 0000000..41f0929 --- /dev/null +++ b/contents/projects.md @@ -0,0 +1,11 @@ +--- +title: Projects +description: Information About the SI16's Projects +url: +--- + +## INFO + +The projects from the Special Issue 16 have accompanied us on our way to build this toolkit. Whereas our practice shaped the functions we created, the tools formed our projects to a similar extent. + +Each of them is an experimental adventure, elaborating on different aspects of vernacular language processing while inviting users to participate. Come with us to see how our functions come to life and join us in this fearless and joyful undertaking. \ No newline at end of file diff --git a/contents/si16_info.md b/contents/si16_info.md new file mode 100644 index 0000000..f878822 --- /dev/null +++ b/contents/si16_info.md @@ -0,0 +1,9 @@ +--- +title: Learning How to Walk While Catwalking +description: Information About the SI16 - Learning How To Walk While Catwalking +cover: url to an image in the static folder we can use for social etc Recommend 1200×628 no much text +url: https://hub.xpub.nl/soupboat/si16-app/ +license: url to the license we need to upload it on the git repo? +--- + +## INFO diff --git a/contents/test-list.md b/contents/test-list.md new file mode 100644 index 0000000..df68073 --- /dev/null +++ b/contents/test-list.md @@ -0,0 +1,10 @@ + + + +
+ + + +
+ + \ No newline at end of file diff --git a/contents/tos.md b/contents/tos.md new file mode 100644 index 0000000..8ef5622 --- /dev/null +++ b/contents/tos.md @@ -0,0 +1,38 @@ +--- +title: Terms of Service +description: Terms of Service SI16 +css: tos.css +--- + +## Vernacular catwalking, learning and teaching. + +Our API (Application Programming Interface) is in itself an experiment to legitimise failures, promote a more critical approach to APIs as models of distribution, and embrace the user as co-author. It is accessible both in html and json format. The aim of this ToS is to articulate inclusive conditions for vernacular catwalking, learning and teaching. + +### 0. Access + +This service can be used by any individual persons, organizations, institutions or collectives that are willing to reject any sort of stigma towards languange, ignore grammar correctness and officiality, both in oral and written language, and who are interested in vernacular amatorial practices around and within language processing and the use that is made of it. + +### 1. By using this service, you agree on the following: + +1. All the code and the contents produced through this API are automatically licensed under the _catleft license_ +2. the API key comes in the form of a physical keychain and shall not be distributed through any other media different than the physical keychain itself. +3. The API key is held by a rotating "guardian" who: + 1. shall leave a contact on the page _____ in order to be reached. + 2. is responsible of adding the new API key to the keychain if modified. + 3. is open to and seeks for collective consultation about the changes made to the API +4. The API key can be used for max. 10 days. After whose expiration it must be passed onto another guardian. +5. no personal data is collected, except for the contact of the guardian of the API-key + +### 2. Privileges granted by the key + +1. it allows to modify the API key; in this case the new API key must be added, in any physical form, as keychain gadget to the API key. +2. It allows to add new error messages, which shall include messages of self-care, encouragement, anecdotes about cats, common saying in any dialect, and/or favourite recipes. +3. it allows to access the complete hidden reading list and to add new suggestions. + +Note: we reserve the right to modify or delete contributions that are homophobic, transphobic, racist, ableist and sexist, even if intended as a joke, or as an ironic remark. Same for hate speech, such as, but not limited to: white supremacy, ethnostate advocacy, discussion of national socialism / nazism. + +### 3. How to pass on the key + +The current guardian of the API-key shall pass the API-key to another person of their choice at the expiring of the 10 days. + +### 4. Contacts diff --git a/notebooks/add_pen_name.ipynb b/notebooks/add_pen_name.ipynb new file mode 100644 index 0000000..d26336c --- /dev/null +++ b/notebooks/add_pen_name.ipynb @@ -0,0 +1,123 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e839d993-7f9e-4419-92de-eb3dba046640", + "metadata": {}, + "source": [ + "# add_pen_name" + ] + }, + { + "cell_type": "markdown", + "id": "b87b3999-97c7-43da-9931-27f319a9f590", + "metadata": {}, + "source": [ + "___\n", + "\n", + "Add pen names into the list
\n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "id": "cf3788e7-7b88-480a-8a4e-8c53eae169e3", + "metadata": { + "tags": [] + }, + "source": [ + "Input:\n", + "- name, string" + ] + }, + { + "cell_type": "markdown", + "id": "96ccfe4d-a20d-42e6-ad2c-fdfaa6fd2fc5", + "metadata": { + "tags": [] + }, + "source": [ + "Output:\n", + "- name, list" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "4a5f59ac-bdfd-4695-8842-80db12bd156e", + "metadata": {}, + "outputs": [], + "source": [ + "pen_name_list = ['Blibli', 'Chae as Che Gueverq', 'turtle teller']\n", + "\n", + "def add_pen_name(name_input):\n", + " '''add pen name inside the list'''\n", + " if name_input:\n", + " if name_input not in pen_name_list:\n", + " pen_name_list.append(name_input)\n", + " return pen_name_list" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a9668cd3-54a4-4e1b-baed-f8453965f693", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Blibli', 'Chae as Che Gueverq', 'turtle teller', 'broggle']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# simple application here\n", + "add_pen_name('broggle')" + ] + }, + { + "cell_type": "markdown", + "id": "5db35904-9350-428d-9744-a922ebd05784", + "metadata": {}, + "source": [ + "___\n", + "This function is part of C and G project, ***ETC Portal to Contaminate*** " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "919fd920-f52f-4912-b4e2-d5aa57c5f400", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/area_map.ipynb b/notebooks/area_map.ipynb new file mode 100644 index 0000000..dc063b4 --- /dev/null +++ b/notebooks/area_map.ipynb @@ -0,0 +1,160 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# area_map\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Select a specific area of the image, return a list of all labels in that specific area." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1eb5f9a2-a86a-45f2-aa7b-9b32653f9fed", + "metadata": {}, + "outputs": [], + "source": [ + "from urllib.request import urlopen\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5fb4d7db-9d58-4921-81e9-9e5fd00c4d46", + "metadata": {}, + "outputs": [], + "source": [ + "def area_map(image: str, left: int, right: int, top: int, bottom: int ) -> list:\n", + " \n", + " \"\"\"Give a string with the name of the image-file that was annotated with the Annotation Compass; Select a specific area of the image, return a list of all labels in that specific area.\"\"\" \n", + "\n", + " url = f\"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image={image}\"\n", + " response = urlopen(url)\n", + " data_json = json.loads(response.read()) \n", + " \n", + " filtered_map = []\n", + " for label in data_json['labels']:\n", + " if left <= (label['position']['x']) <= right and top <= (label['position']['y']) <= bottom:\n", + " filtered_map.append(label)\n", + " \n", + " return filtered_map" + ] + }, + { + "cell_type": "markdown", + "id": "1094ed8e-1387-481e-b612-9a8cc81d5c18", + "metadata": {}, + "source": [ + "This function was built for a project where individuals are invited to add their annotations on a map using the Annotation Compass. Each annotation-label is stored in a json-file and includes the annotation-text itself, but also the name of the image-file as well as the position, size, index, timestamp and userID of the annotation.\n", + "\n", + " Example for a label:\n", + "\n", + " {'image': 'map.jpg',\n", + " 'position': {'x': 12, 'y': 97},\n", + " 'size': {'width': 43, 'height': 18},\n", + " 'text': 'This is a text! Is this a text?',\n", + " 'timestamp': 'Wed, 01 Dec 2021 14:04:00 GMT',\n", + " 'userID': 5766039063}\n", + "\n", + "\n", + "If interested in the annotations in a specific area of the map, area_map() can help. The function needs a string with the name of the of the image-file that was annotated with the annotation compass tool as well as four specific values to define the left, right, top and bottom outlines of the selected area. The output is a list of all labels in the defined area of interest.\n", + "\n", + "How to get a json-file with annotation-labels?\n", + "\n", + " https://hub.xpub.nl/soupboat/generic-labels/\n", + "The Annotation Compass allows people to uplaod an image and ask others to annotate it. A json-file of the annotations is provided." + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples\n", + "\n", + "In this example, the function returns all annotation-labels in an area of interest that reaches from x = 70% to x = 90% and from y = 10% to y = 100%" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e3d7e97b-0089-4c29-a2c1-9ef823ff2e37", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'image': 'rejection_map.jpg',\n", + " 'position': {'x': 76.25, 'y': 69.5246},\n", + " 'size': {'height': 12.3939, 'width': 15.625},\n", + " 'text': \"I once went to view a house here but it didn't have the floor. crap.\",\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:36:51 GMT',\n", + " 'userID': '6286616941'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 77.0, 'y': 63.7521},\n", + " 'size': {'height': 8.65874, 'width': 10.25},\n", + " 'text': 'other housing rejection situations here.\\n',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:37:25 GMT',\n", + " 'userID': '6286616941'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 75.285, 'y': 29.2254},\n", + " 'size': {'height': 19.0141, 'width': 17.513},\n", + " 'text': '어딘지 잘은 모르겠지만, Kralingen 쪽이었던 것 같아. bsn 거주등록을 위해 학교에 갔는데, 시청에서 나온 사람들이 나의 룸메이트 ID card가 필요하다며 거절했지. 나의 아침을 날렸어. 나의 룸메가 나에게 ID card 사진을 보내줬지만, 그들은 서명이 같지 않다면서 다시 거절했지. ',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:39:21 GMT',\n", + " 'userID': '8633793842'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 73.703, 'y': 49.514},\n", + " 'size': {'height': 5.22479, 'width': 5.09839},\n", + " 'text': \"i got rejected from a skateboard here. it's normal though because it's always trying to reject you and you love it anyway\",\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:44:35 GMT',\n", + " 'userID': '8918562766'}]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "area_map('rejection_map.jpg', 70, 90, 10, 100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "926c7209-4a91-4401-a1a5-15066b0331bc", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/bridge.ipynb b/notebooks/bridge.ipynb new file mode 100644 index 0000000..659a951 --- /dev/null +++ b/notebooks/bridge.ipynb @@ -0,0 +1,327 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 179, + "id": "3c7f546e-2a12-456d-be2b-a01df62c32f4", + "metadata": {}, + "outputs": [], + "source": [ + "image = 'think-classify.jpg'\n", + "image2 = 'think-classify2.jpg'\n", + "image3 = 'think-classify3.jpg'\n", + "image4 = 'think-classify4.jpg'\n", + "image5 = 'think-classify5.jpg'\n", + "image6 = 'think-classify6.jpg'\n", + "image7 = 'think-classify7.jpg'\n", + "image8 = 'think-classify8.jpg'\n", + "image9 = 'think-classify9.jpg'\n", + "image10 = 'think-classify10.jpg'\n", + "image11 = 'think-classify11.jpg'\n", + "image12 = 'think-classify12.jpg'\n", + "image13 = 'think-classify13.jpg'\n", + "image14 = 'think-classify14.jpg'\n" + ] + }, + { + "cell_type": "code", + "execution_count": 198, + "id": "42b71c63-544e-4e39-9182-f5d349eb5389", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[['to', 'meet,', 'but', 'also', 'to', 'collect.', 'are', 'you', 'gathering', 'people', 'or', 'a', 'bulk', 'of', 'leaves', 'in', 'your', 'garden', 'when', 'winter', 'is', 'coming?'], ['to', 'gather', 'friends', 'inside', 'your', 'place,', 'to', 'gather', 'information', 'for', 'the', 'police,', 'to', 'gather', 'food', 'for', 'the', 'homeless,', 'to', 'gather', 'objects', 'inside', 'your', 'bag,', 'to', 'gather', 'your', 'drunk', 'friend,', 'to', 'gather', 'a', 'molotof', 'cocktail', 'for', 'a', 'revolutionary', 'party'], ['it', 'is', 'the', 'opposite', 'of', 'dividing', 'because', 'the', 'basic', 'idea', 'is', 'that', 'you', 'have', 'a', 'lot', 'of', 'objects', 'far', 'away', 'from', 'each', 'other,', 'in', 'different', 'rooms,', 'in', 'different', 'building,', 'in', 'different', 'cities', 'and', 'you', 'want', 'to', 'have', 'all', 'of', 'them', 'on', 'your', 'bed', 'so', 'you', 'just', 'go', 'and', 'pick', 'them', 'up', 'from', 'where', 'they', 'are', 'you', 'put', 'them', 'in', 'a', 'bag', 'and', 'go', 'back', 'home'], ['my', 'favorite', 'activity', 'since', '200000000', 'years,', 'to', 'gather', 'food,', 'to', 'find', 'something', 'and', 'to', 'collect', 'it.', 'since', 'im', 'a', 'racoon', 'i', 'like', 'to', 'gather', 'things', 'around', 'from', 'the', 'street.', 'my', 'flatmate', 'is', 'desperate', 'about', 'it.', 'but', 'i', 'always', 'find', 'nice', 'things:', 'a', 'table,', 'a', 'confy', 'armchair,', 'some', 'baskets,', 'some', 'vases.']]\n" + ] + } + ], + "source": [ + "from nltk.corpus import stopwords\n", + "sw = stopwords.words(\"english\")\n", + "from urllib.request import urlopen\n", + "import json\n", + "\n", + "resultSentences = []\n", + "labels_corpus = []\n", + "\n", + "url = f\"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image=think-classify7.jpg\"\n", + "response = urlopen(url)\n", + "data_json = json.loads(response.read()) \n", + "\n", + "labels = data_json['labels']\n", + "\n", + "\n", + "for label in labels:\n", + " sent = label['text'].split()\n", + " labels_corpus.append(sent)\n", + " \n", + " \n", + "print(labels_corpus)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "387f722e-bb19-45cc-a0f9-8a1186febd56", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 199, + "id": "b3d40ae4-cfe8-4346-9d9f-23e2dbc50c0d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "punctuation = ['.', ',', ';', '(', ')', ':']\n", + "\n", + "# since .split(' ') does not split a word from any punctuation, \n", + "# this function search for any string which last character (word[-1]]) is in the variable 'punctuation';\n", + "# if that is the case, the function will remove the last charachter, else it will leave it as it is.\n", + "def clean_word(word):\n", + " for character in word:\n", + " if word[-1] in punctuation:\n", + " return word[0:-1]\n", + " if word[0] in punctuation:\n", + " return word[1:]\n", + " else:\n", + " return word" + ] + }, + { + "cell_type": "code", + "execution_count": 200, + "id": "5c37d124-eaa8-4275-9556-473a966fdcb7", + "metadata": {}, + "outputs": [], + "source": [ + "# The arguments in this functions are 2 texts (text_a and text_b) an index for where the text_a starts and an index for where it ends.\n", + "def bridge(text_a, text_b, start_a, isLast):\n", + " \n", + " matchFound = 0\n", + " start_next = 0\n", + " \n", + " # for index i in text_a from a given index until the end of text_a\n", + " for i in range(start_a, len(text_a)):\n", + " if matchFound:\n", + " break\n", + " \n", + " # we name word_a the index i in text_a\n", + " word_a = text_a[i]\n", + " # if word_a is not in the given list of stopwords:\n", + " if word_a not in sw:\n", + " # for index j in the entire text_b:\n", + " for j in range(0, len(text_b)):\n", + " \n", + " # we name word_b the word with index j in text_b\n", + " word_b = text_b[j]\n", + " \n", + " # if word_a equals to word_b:\n", + " if clean_word(word_a) == clean_word(word_b):\n", + " \n", + " # resultSentences is a list to which the following informations will add up:\n", + " resultSentences.append({\n", + " 'text': text_a,\n", + " 'start': start_a,\n", + " 'end': i,\n", + " 'hasMatch': 1\n", + " })\n", + " \n", + " # if the text in position text_a is the last text to be compared:\n", + " # the same informations as above will be added, except that there will be no index for its end.\n", + " if isLast:\n", + " resultSentences.append({\n", + " 'text': text_b,\n", + " 'start': j,\n", + " 'end': None,\n", + " 'hasMatch': 1\n", + " })\n", + " \n", + " # after the match is found between the 2 texts, the function will break\n", + " matchFound = 1 \n", + " start_next = j\n", + " break\n", + " \n", + " if matchFound == 0:\n", + " resultSentences.append({\n", + " 'text': text_a,\n", + " 'start': start_a,\n", + " 'end': None,\n", + " 'hasMatch': 0\n", + " })\n", + " \n", + " if isLast:\n", + " resultSentences.append({\n", + " 'text': text_b,\n", + " 'start': 0,\n", + " 'end': None,\n", + " 'hasMatch': 0\n", + " })\n", + "\n", + " \n", + " # the function returns the index of the 'same word' in the text_b\n", + " return start_next" + ] + }, + { + "cell_type": "code", + "execution_count": 201, + "id": "d4862edf-c8cf-44dc-bd41-33549da33c0b", + "metadata": {}, + "outputs": [], + "source": [ + "def bridge_list(corpus):\n", + " start_a = 0\n", + " result = \"\"\n", + " \n", + " #for all texts indexes within the corpus to be compared:\n", + " for text_index in range(0, len(corpus)-1):\n", + "\n", + " # the last text_a to be compared has to be the text indexed as corpus[-2];\n", + " # the last text_b will then be the last text of the corpus (corpus[-1]).\n", + " isLast = text_index == len(corpus)-2\n", + " # text_a is a given index of the corpus and text_b is the following index\n", + " text_a = corpus[text_index]\n", + " text_b = corpus[text_index + 1]\n", + " \n", + " \n", + " #start_a is the index (in text_b) of the first 'common word' between text_a and text_b;\n", + " #start_a is the starting point to compare a text and its following (in index order within the corpus); \n", + "\n", + " start_next = bridge(text_a, text_b, start_a, isLast)\n", + " start_a = start_next\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 202, + "id": "4363e385-7772-422b-b7b5-7f425e79878d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "\n", + "def render_sentence(sentence, highlightNext):\n", + " result = ''\n", + " start = 0\n", + " end = len(sentence['text'])\n", + " if(sentence['start']):\n", + " start = sentence['start']\n", + " if(sentence['end']):\n", + " end = sentence['end']\n", + " \n", + " text = sentence['text']\n", + " \n", + " highlight = highlightNext\n", + " \n", + " for index in range(start, end):\n", + " word = text[index]\n", + " \n", + " if(highlight == 1):\n", + " result = result + '' + word + ''\n", + " highlight = 0;\n", + " continue\n", + " else:\n", + " if index == end -1 and sentence['hasMatch']:\n", + " highlight = 1\n", + "\n", + " result = result + \" \" + word\n", + " \n", + " return result, highlight\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 203, + "id": "d30e2363-37e7-4437-af7a-572eb56d9266", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " to meet, but also to collect. are you gathering people or a bulk of leaves in your garden when winter is coming? to gather friends inside your place, to gather information for the police, to gather food for the homeless, to gather objects far away from each other, in different rooms, in different building, in different cities and you want to have all of them on your bed so you just go and pick them up from where they are you put them in a bag and go back home my favorite activity since 200000000 years, to gather food, to find something and to collect it. since im a racoon i like to gather things around from the street. my flatmate is desperate about it. but i always find nice things: a table, a confy armchair, some baskets, some vases.\n" + ] + } + ], + "source": [ + "bridge_list(labels_corpus)\n", + "\n", + "endResult = ''\n", + "\n", + "highlightNext = 0\n", + "\n", + "for i in range(0, len(resultSentences)):\n", + " sentence = resultSentences[i]\n", + " start = sentence['start']\n", + " end = sentence['end']\n", + " sentenceText = sentence['text']\n", + " \n", + " sentence, highlight = render_sentence(sentence, highlightNext)\n", + " highlightNext = highlight\n", + " \n", + " endResult = endResult + \" \" + sentence\n", + "\n", + "print(endResult)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5e13d80-deef-423d-82f7-be71e69ee902", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3014a45f-d18f-4fef-b683-45eb50abed03", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1602a233-c977-4e8c-87f4-133f0792d181", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/cocktail_generator.ipynb b/notebooks/cocktail_generator.ipynb new file mode 100644 index 0000000..e86a19c --- /dev/null +++ b/notebooks/cocktail_generator.ipynb @@ -0,0 +1,286 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# cocktail_generator\n", + "randomly chooses ingredients from a menu for a nice cocktail recipe" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9bd8860a-9967-49d5-a74a-b5de669dfe6d", + "metadata": {}, + "outputs": [], + "source": [ + "def cocktail_generator(alcohol: list, decor: list) -> str:\n", + " \"\"\"randomly chooses ingredients from a menu for a nice cocktail recipe\"\"\"\n", + "\n", + " import datetime\n", + " from datetime import timedelta\n", + " now = datetime.datetime.now() + timedelta(hours=1) \n", + " from random import choice\n", + "\n", + " base = [\"ORANGE JUICE\", \"PINEAPPLE JUICE\", \"APPLE JUICE\", \"MANGO JUICE\", \"FRIZZY WATER\", \"GRAPEFRUIT JUICE\", \"TONIC WATER\"]\n", + "\n", + " sour = [\"LEMON JUICE\", \"LIME JUICE\", \"PASSION FRUIT\"]\n", + "\n", + " sweet = [\"AGAVE SIRUP\", \"SUGAR SIRUP\", \"MAPLE SIRUP\"]\n", + "\n", + " omph = [\"1 SLICE GINGER\", \"2 LEAVES MINT\", \"1 SLICE CUCUMBER\", \"1 STICK CINNAMON\", \" SALT RIM\"] \n", + "\n", + "\n", + " snack = [\"CHIPS\", \"SALTED CORN\", \"PRETZELS\", \"SALTED NUTS\"]\n", + "\n", + "\n", + " XPUB1 = [\" (*(*(*(*(*.(*.*).*)*)*)*)*)*)\", \" (^(^(^(^(^.(^.^).^)^)^)^)^)^)\"]\n", + "\n", + "\n", + " drink = [\"\"\"\n", + " ___, \n", + " '._.'\\ \n", + " _____/'-.\\ \n", + " | / | \n", + " |~~~/~~| \n", + " \\ () / \n", + " '.__.' \n", + " || \n", + " _||_ \n", + " `----` \"\"\", \"\"\"\n", + " .\n", + " . . \n", + " |^ .\n", + " \\O___.____ /\n", + " \\ . /\n", + " \\ ,/\n", + " []\n", + " []\n", + " []\n", + " -------- \n", + " \"\"\", \"\"\"\n", + " \\ \n", + " .-\\\"\"\"\"\"\"\"\"-.\n", + " \\ \\__ o . /\n", + " \\/ \\ o/\n", + " \\__/. /\n", + " \\_ _/\n", + " Y\n", + " |\n", + " _.-' '-._\n", + " `---------` \"\"\"]\n", + "\n", + " \n", + "\n", + "\n", + " recipe = f\"\"\"\n", + "
\n",
+    "    \n",
+    "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+    "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+    "*                             *\n",
+    "*   CATWALKING WITH ALCOHOL   *\n",
+    "*                             *\n",
+    "*    {now.strftime(\"%Y-%m-%d   %H:%M:%S\")}    *\n",
+    "*                             *\n",
+    "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+    "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+    "\n",
+    "\n",
+    "\n",
+    "2 oz          {choice(alcohol)}\n",
+    "\n",
+    "150 ml        {choice(base)}\n",
+    "\n",
+    "1 oz          {choice(sour)}\n",
+    "\n",
+    "0.5 oz        {choice(sweet)}\n",
+    "\n",
+    "{choice(omph)}\n",
+    "\n",
+    "1             {choice(decor)}\n",
+    "\n",
+    "\n",
+    "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+    "\n",
+    "EXTRA: {choice(snack)}\n",
+    "\n",
+    "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+    "\n",
+    "\n",
+    "           ___, \n",
+    "          '._.'\\ \n",
+    "       _____/'-.\\ \n",
+    "      |    / | \n",
+    "      |~~~/~~| \n",
+    "      \\ ()   / \n",
+    "       '.__.' \n",
+    "         || \n",
+    "        _||_ \n",
+    "       `----` \n",
+    "\n",
+    "\n",
+    "THANKS FOR COMING TO OUR LAUNCH!\n",
+    "\n",
+    "{choice(XPUB1)}\n",
+    "\n",
+    "\n",
+    "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+    "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+    "\n",
+    "
\n", + " \"\"\"\n", + " \n", + "\n", + "\n", + " return recipe" + ] + }, + { + "cell_type": "markdown", + "id": "d50511cb-a810-4fe1-a681-e5cb1392c0d0", + "metadata": {}, + "source": [ + "![cocktail_generator](https://hub.xpub.nl/soupboat/~chae/vernacular-cocktail.jpg)" + ] + }, + { + "cell_type": "markdown", + "id": "1094ed8e-1387-481e-b612-9a8cc81d5c18", + "metadata": {}, + "source": [ + "This function generates amazing cocktail recipes for you to try! The cocktail menu includes the categories alcohol, base, sour, sweet and omph. There is also a category for a decorative gadget and one for an extra snack. Each category has a default list of ingredients and the function randomly chooses one ingredient per category. You prefer Rum and Tequila over Vodka? Or maybe you want a non-alcoholic cocktail? Don´t worry! For the categories alcohol and decor you can insert your own ingredients to pick from. Enjoy!\n", + "\n", + " Menu:\n", + "\n", + " default ingredients:\n", + " base = ORANGE JUICE, PINEAPPLE JUICE, APPLE JUICE, MANGO JUICE, FRIZZY WATER, GRAPEFRUIT JUICE, TONIC WATER\n", + " sour = LEMON JUICE, LIME JUICE, PASSION FRUIT\n", + " sweet = AGAVE SIRUP, SUGAR SIRUP, MAPLE SIRUP\n", + " omph = 1 SLICE GINGER, 2 LEAVES MINT, 1 SLICE CUCUMBER, 1 STICK CINNAMON, SALT RIM \n", + " snack = CHIPS, SALTED CORN, PRETZELS, SALTED NUTS\n", + "\n", + " users ingredients:\n", + " alcohol =\n", + " decor =\n" + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples\n", + "\n", + "In this exmaple the function chooses between three alcoholic ingredients and two decoratin gadgets" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e3d7e97b-0089-4c29-a2c1-9ef823ff2e37", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "
\n",
+      "    \n",
+      "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+      "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+      "*                             *\n",
+      "*   CATWALKING WITH ALCOHOL   *\n",
+      "*                             *\n",
+      "*    2021-12-14   14:08:04    *\n",
+      "*                             *\n",
+      "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+      "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+      "\n",
+      "\n",
+      "\n",
+      "2 oz          VODKA\n",
+      "\n",
+      "150 ml        GRAPEFRUIT JUICE\n",
+      "\n",
+      "1 oz          LEMON JUICE\n",
+      "\n",
+      "0.5 oz        SUGAR SIRUP\n",
+      "\n",
+      "1 SLICE       CUCUMBER\n",
+      "\n",
+      "1             UMBRELLA\n",
+      "\n",
+      "\n",
+      "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+      "\n",
+      "EXTRA: SALTED CORN\n",
+      "\n",
+      "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+      "\n",
+      "\n",
+      "           ___, \n",
+      "          '._.'\\ \n",
+      "       _____/'-.\\ \n",
+      "      |    / | \n",
+      "      |~~~/~~| \n",
+      "      \\ ()   / \n",
+      "       '.__.' \n",
+      "         || \n",
+      "        _||_ \n",
+      "       `----` \n",
+      "\n",
+      "\n",
+      "THANKS FOR COMING TO OUR LAUNCH!\n",
+      "\n",
+      " (^(^(^(^(^.(^.^).^)^)^)^)^)^)\n",
+      "\n",
+      "\n",
+      "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+      "*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n",
+      "\n",
+      "
\n", + " \n" + ] + } + ], + "source": [ + "print(cocktail_generator(['VODKA', 'TEQUILA', 'RUM'], ['UMBRELLA', 'PALMTREE', 'FLAMINGO']))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e79116b-12d7-4b6e-a764-f7a8fc14c1ce", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/ghost_map.ipynb b/notebooks/ghost_map.ipynb new file mode 100644 index 0000000..7f9c23e --- /dev/null +++ b/notebooks/ghost_map.ipynb @@ -0,0 +1,138 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# ghost_map\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Replace all characters of all annotation-texts with a ghost-glyph and return a string that includes all replaced annotation-texts plus html-tags that place them back into their original position." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "444e0267-c783-4b5a-9546-ad007175b6ea", + "metadata": {}, + "outputs": [], + "source": [ + "from urllib.request import urlopen\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9bd8860a-9967-49d5-a74a-b5de669dfe6d", + "metadata": {}, + "outputs": [], + "source": [ + "def ghost_map(image: str, ghost_glyph: str ) -> str:\n", + " \"\"\"give a string with the name of the image-file that was annotated with the Annotation Compass; Replace all characters of all annotation-texts with a ghost-glyph and return a string that includes all replaced annotation-texts plus html-tags that place them back into their original position.\"\"\" \n", + " \n", + " url = f\"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image={image}\"\n", + " response = urlopen(url)\n", + " data_json = json.loads(response.read())\n", + " \n", + " filtered_map = ''\n", + " for label in data_json['labels']:\n", + " replaced_text = ''\n", + " for char in label['text']:\n", + " replaced_char = char\n", + " if not char.isspace():\n", + " replaced_char = ghost_glyph\n", + " replaced_text = replaced_text + replaced_char\n", + " html_tag = f'

{ replaced_text }

'\n", + " filtered_map = filtered_map + html_tag\n", + " return filtered_map" + ] + }, + { + "cell_type": "markdown", + "id": "1094ed8e-1387-481e-b612-9a8cc81d5c18", + "metadata": {}, + "source": [ + "This function was built for a project where individuals are invited to add their annotations on a map using the Annotation Compass. Each annotation-label is stored in a json-file and includes the annotation-text itself, but also the name of the image-file as well as the position, size, index, timestamp and userID of the annotation.\n", + "\n", + " Example for a label:\n", + "\n", + " {'image': 'map.jpg',\n", + " 'position': {'x': 12, 'y': 97},\n", + " 'size': {'width': 43, 'height': 18},\n", + " 'text': 'This is a text! Is this a text?',\n", + " 'timestamp': 'Wed, 01 Dec 2021 14:04:00 GMT',\n", + " 'userID': 5766039063}\n", + "\n", + "\n", + "If interested in the traces the annotations leave, ghost_map() can help. The function needs a string with the name of the of the image-file that was annotated with the annotation compass tool as well as a ghost-glyph that will replace all characters of the annotation-texts. The output is a string that includes all replaced annotation-texts plus html-tags that place them back into their original position.\n", + "\n", + "How to get a json-file with annotation-labels?\n", + "\n", + " https://hub.xpub.nl/soupboat/generic-labels/\n", + "The Annotation Compass allows people to uplaod an image and ask others to annotate it. A json-file of the annotations is provided." + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples\n", + "\n", + "In this example, the function replaces all characters of the annotation-texts with a ghost-glyph" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "60d22cde-79da-4dbd-a8a7-7028f785ec93", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'

##### ####### ###### ## ######### #########

#### ## ## ## #### ## # ## ## # ##### ## #### ## #### ### ### #### ##\\n# ### ## ## ## ####### \\n##### #### ## ### ## ### \\n## ## ###### ######## #### ###

### ############ ## ######### ####### ########## ###### ####### ## ####### ## ####### ## ############ ####### ### ####### ## #### ####### #### ## ### ####### ## ### \\n#### #### #### ## # ##### ## ##### ########### #### ###### #### ## # #### # ### #### ## ### ################### #####

####### # #### ####### #### ## #### ####### ####### ## #### ### #### ### ##### ## ## ######### ####### ### ######## ###

##### ####### ## ####### #### #### ##### ## ### ####### ## ### # ##### #### ##### ####### ### ######## ##### ### #### ######## ###

# #### #### ## #### # ##### #### ### ## ###### #### ### ###### #####

##### ####### ######## ## ## ##### ####### #######

##### ####### ######### ########## #####\\n

# ##### ## ### ##### ###### ## ### ###### ###### ### ##### ### # ####### ## ######### ### # ###### ###### ########## ### ####### ##### ### ### #### ### #### #### ## ## ### ##### #####

## ##### # #### ### ###### ## ### #### ### ########## ##### ####### ## #### #####

##### ####### ######## ## ### ##### #### ## ##### ######### # ##### ### ##########

### #### ########## ##### ######## ## ####### ########## #### ### ######## ###### ### # ###### ### ### ###### ## ####### #### ### #### ###### ##### ### ##### #### #### #### ### # ## ### #### ######## ## ### ### #####

####### ### ## ### ##### ### ####### ### ####### ### ####### #### ### ### #### ### ### ## #### ##### ###### ### # ####### ## #### ## ######## ######## ## ############

##### ####### #### ## ## #### ####

# ### ### #### ####### ##### ####### ##### ### ###### ###### ###### ## ## ### ###### ### ## #### #### #### ###### #### ### ########## # ### ### ### ### #####

######## ## ### ######

## ##### ##### ######## # ### ###### ####### ##### #### #### ######### ####### # #### # ########## #### ### ##### # ###### # ##### ## ## ######## #### #### ####

##### ####### #### ## #### ####### ## ####

# ### ### #### ####### ##### ####### ##### ### ###### ###### ###### ## ## ### ###### ### ## #### #### #### ###### #### ### ### ############# # ### ### ### ### #####

### ## ###### ######### #### # ### ### ##### ## ### #### #### ## #### ## #### ## ##### ##### ##### ## ### #### ## ### ### ## #### ### ###### ### ### ## #### ## #####

# ######## ### ######## #### # #### ####### ## ### ####### #### ### ########### #########

# #### ######### ## ### ######### #### #### ### ####### ## ## ########### ############ #### ## ##### ## ############ ########## ##### ### # #### ##### ### ## ###### #######

##### ## #### ## #### ### ## ########### ## ######

## ### ###### ## #### #### # #### #### ## #### ####### #### ####### ## ##### # ####### ### ## ### ### ######### ## #### ### ##### ## ###### #### ###

######### ####### #### #### # #### ## ## ##### ### # ###### ##### ##### #### #### ##### ###### # ### ## ############ ## ### ############# #### ##### ######### ### ####### ### ### ## # #### # ### ########## ##### ###### ## ###### ######## ######### ### # ## ### ####### ###### ### # ## ##### ### ###########

##### #### ####### #### ## ######## ## # ##### #######

# ### ####### #### # #### ##### # ### #### ###### ## #### ####### ###### ### ##### ##### #### ##

## #### ### ###### #####

### ##### #### # ###### ######### ## ########## ##### # #### #### ## ### #### # ### ##### # ##### ## ######### ####### ### ######### ###### ##### ##### # #### ######## ## ###

# #### #### ######### ## ### ######### #### #### ####### # #### #### # ####### ####### ### ## ### ##### #### ##### ## ###### ######

######

###### # ### ## ######

# #### ######## #### #### ####### #### #### ## # #### ### #### ######## ## ## ######## ##### ## ########

## ##### ############## ##########

## #### ##### ## # ####### ##### #### ## ### ####### #### ### #### ####### ##### ############ ### # ### ### ## #### ### ## ### ##### ### ## ### ### ### ##### ### ##### ###### ### # #### ##### ### ### ### # #### ###### ## ### ## ###### ## # #####

## ###### ######### #### ########## ## # ##### #### #### ######## #### #### ## #### # #### ######## ##

###### ######## ######## ## ##### ###### #### ###### ## #### ###### ##############

# #### ######## #### #### ### ###### ######### ## ## ########## ## ## ####### #### ####### ## ########

# ### ######## #### # ########## ##### #### ###### ###### ####### #### ###### ###### ## ###### ### ### ### #### ## ######

#### ###### ## ### ##### ## ### ## #### ####### ###### #### ## ### ###### ### #### #### ### ####### ### ######## ########## ## #########

## ###### ######## ## ### ##### ## #### ###### ## #### #### ## ###### ## ###### ##### ### ## ######## ## ### ######## ####### ##### ## ### ########

##### #########\\n

##### ##### ## ######### # ### ## ##### ######### ### # #### ## #### ############## ### #### #### ### # ### ###### ## #### ### ### ## ### #### # ### ######### ### #### ### ##### ##### ##### ## #### # ###### #### ## #### #### # #### # ### ######## ##### #####

#### ## ### ############ ##### # ####### ######### ### ### ##### ##### # ### ####### #### ###### # ## ######## # ### ####### # ######## ## ##### ### ####### ## #### # ##### ##### ## #### ##### ## #### #### ####

# #### ##### #### ## #### #### ## ########## # ##### # ######## ## ### #### #######

# #### ####### # #### ### ## ### ###### ## ##

'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ghost_map('rejection_map.jpg', '#')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a8c88f3-2f16-4dce-9e29-547648e251c2", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/highlight_map.ipynb b/notebooks/highlight_map.ipynb new file mode 100644 index 0000000..4c5b227 --- /dev/null +++ b/notebooks/highlight_map.ipynb @@ -0,0 +1,141 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# highlight_map\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Give a target-word; Return a string that includes all annotation-texts plus html-tags that place them back into their original position while highlighting the annotation-texts that include the target." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "2d179f96-2f4c-419f-97d9-9ea833bfc4b3", + "metadata": {}, + "outputs": [], + "source": [ + "from urllib.request import urlopen\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9bd8860a-9967-49d5-a74a-b5de669dfe6d", + "metadata": {}, + "outputs": [], + "source": [ + "def highlight_map(image: str, target: str ) -> str:\n", + " \n", + " \"\"\"Give a string with the name of the image-file that was annotated with the Annotation Compass; Give a target-word; Return a string that includes all annotation-texts plus html-tags that place them back into their original position while highlighting the annotation-texts that include the target.\"\"\" \n", + "\n", + " url = f\"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image={image}\"\n", + " response = urlopen(url)\n", + " data_json = json.loads(response.read()) \n", + " \n", + " filtered_map = ''\n", + " for label in data_json['labels']:\n", + " if target in label['text']:\n", + " highlight_tag = f'

{ label[\"text\"] }

'\n", + " filtered_map = filtered_map + highlight_tag\n", + " else:\n", + " html_tag = f'

{ label[\"text\"] }

'\n", + " filtered_map = filtered_map + html_tag\n", + " \n", + " return filtered_map" + ] + }, + { + "cell_type": "markdown", + "id": "1094ed8e-1387-481e-b612-9a8cc81d5c18", + "metadata": {}, + "source": [ + "This function was built for a project where individuals are invited to add their annotations on a map using the Annotation Compass. Each annotation-label is stored in a json-file and includes the annotation-text itself, but also the name of the image-file as well as the position, size, index, timestamp and userID of the annotation.\n", + "\n", + " Example for a label:\n", + "\n", + " {'image': 'map.jpg',\n", + " 'position': {'x': 12, 'y': 97},\n", + " 'size': {'width': 43, 'height': 18},\n", + " 'text': 'This is a text! Is this a text?',\n", + " 'timestamp': 'Wed, 01 Dec 2021 14:04:00 GMT',\n", + " 'userID': 5766039063}\n", + "\n", + "\n", + "If interested in all annotations that include a specific target, highlight_map() can help. The function needs a string with the name of the of the image-file that was annotated with the annotation compass tool and a target-word. The output is a string that includes all annotation-texts plus html-tags that place them back into their original position while highlighting the annotation-texts that include the target.\n", + "\n", + "How to get a json-file with annotation-labels?\n", + "\n", + " https://hub.xpub.nl/soupboat/generic-labels/\n", + "The Annotation Compass allows people to uplaod an image and ask others to annotate it. A json-file of the annotations is provided." + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples\n", + "\n", + "In this example, the function highlights all annotation-texts that include a specific target." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "e3d7e97b-0089-4c29-a2c1-9ef823ff2e37", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'

here, someone called my behaviour \"strange\"

윰보에서 장을 보고 집에 돌아오는 길. 두 명의 남자 가 다가왔어. 나는 낑낑대며 나의 일주일간 식량을 옮기고 있었지. 쾅!\\n큰 소리가 났고 나는 순간 움츠러들었어. \\n건너편에서 다가오던 남자 두명이 크게 웃더니 \\n나를 보며 Chino! Chino!라고 외쳤어. 시발.

the municipality of rotterdam (prince alexander) almost refused to approve my request of registration because the italian id card doesn\\'t have my sex written on it. \\nthey said that if i bring my birth certificate that states that im a male i can have my bsn otherwise.......... nope.

getting a text message from my good friend, telling me that she will not visit me in Rotterdam despite she promised me.

house viewing 2: meeting with some girls in the evening to see a room; felt super exposed and awkward. Later on, they rejected me.

I once went to view a house here but it didn\\'t have the floor. crap.

here, someone screamed at me \"move fucking chinee\"

other housing rejection situations here.\\n

a woman on the train showed me the middle finger the first day i arrived to rotterdam and i didn\\'t really understand why because she\\'s the one that was mean with me in the first place

at 22:01 a bald man kicked us out from the basketball court because we were noisy

here, someone screamed at me, right into my face, something I could not understand

the most unpleasant house viewing: my viewing overlapped with the previous person and I didn\\'t got the chance to connect with the ones living them. How could then they know who I am and even consider me for the room?

Stepped out at the wrong bus station and because the waiting time for the next bus was (a bit) long, Carmen and I decided to walk to Varia... Rejected by punctuality.

here, someone told me to move away

I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn\\'t like me. Obviously, I did not get the room.

rejected by the police

my first house viewing: I was really hopeful about this one, actually, because I felt a connection with the girl. I waited 2 weeks to be rejected from this one.

here, someone told to stop looking at them

I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn\\'t like me. Not surprisingly, I did not get the room.

어딘지 잘은 모르겠지만, Kralingen 쪽이었던 것 같아. bsn 거주등록을 위해 학교에 갔는데, 시청에서 나온 사람들이 나의 룸메이트 ID card가 필요하다며 거절했지. 나의 아침을 날렸어. 나의 룸메가 나에게 ID card 사진을 보내줬지만, 그들은 서명이 같지 않다면서 다시 거절했지.

i couldn\\'t eat anything from a spar because it was selling only non gluten-free products.

I felt rejection in Art Rotterdam 2019 when the parents of my boyfriend\\'s exgirlfriend came to visit my exboyfriends exhibition there and I felt kinda OUT OF PLACE? heheheh

Emma와 함께 프린트를 하러 갔는데, 그곳에 있는 instructor가 매우 불친절했어.

An old friend of mine that I know from my home country also studies at WDKA. I reached out to him and suggested to hang out soon. He didn\\'t want to.

somewhere between this line i lost my ID card. and I really wasnt aware that this could linger a lot my registration to the municipality. This kinda triggered but feeling for me, as I felt a lot disorented here, having no formal document verifying who I am and feeling guilty tat I am still not registered.

super nice sublet. I\\'ll be rejected in a month though.

i got ejected from a bike here. i was just trying to move through space, but bikes don\\'t like me

My bike got stolen here.

The first time I stayed overnight in Rotterdam, after a nice walk in the sun, I got stuck 2 hours at Centraal, because the Intercity direct broke down. I felt rejected by NS.

I also felt rejection in Art Rotterdam 2020 when someone I knew from a gallery decided not to say hello back after me saying HELLO.

💫💔💥🥐🍟🍕

missed a lot of trains

I felt rejected from some friends that made me a book but stop replying to my messages after my breakup.

my first no-credit-card experience

we were going to a friends house when we got trapped into the riot against covid restrictions and a car got on fire and it was super bad to see all the anger all these people had i felt small and sad and i just wanted to run as faster as i could

my second no-credit card experience in a super nice bar; however, they were ok with a bank transfer :D

People throwing firework at other people here during an anti corona demonstration.

I felt rejected here when the friend mentioned in n3 introduced me to someone else calling me \"Raquel\"

i got rejected from a skateboard here. it\\'s normal though because it\\'s always trying to reject you and you love it anyway

they called me and tried to get my bank details saying that my bsn number has been used for illigal and criminal activities in amsterdam

my wallet rejected me for about 10 mins heree. it fell from my pocket at albert heijn but we reunited at the customer service desk. it was intense.

house rejection\\n

'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "highlight_map('rejection_map.jpg', 'house')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed9f5de3-451d-4dc5-8e9f-97228df73e11", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/html_tag.ipynb b/notebooks/html_tag.ipynb new file mode 100644 index 0000000..3213a31 --- /dev/null +++ b/notebooks/html_tag.ipynb @@ -0,0 +1,267 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# html-tag\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Return a string that can include the position, text, timestamp and/or userID of all labels plus html-tags that place them back into their original position." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "5c99e5ea-6e41-4aac-a4f2-c9244bf74fdc", + "metadata": {}, + "outputs": [], + "source": [ + "from urllib.request import urlopen\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9bd8860a-9967-49d5-a74a-b5de669dfe6d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def html_tag(image: str, position: bool, text: bool, timestamp: bool, userID: bool ) -> str:\n", + " \n", + " \"\"\"Give a string with the name of the image-file that was annotated with the Annotation Compass; Return a string that can include the position, text, timestamp and/or userID of all labels plus html-tags that place them back into their original position.\"\"\" \n", + " \n", + " url = f\"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image={image}\"\n", + " response = urlopen(url)\n", + " data_json = json.loads(response.read()) \n", + " \n", + " html_tags = ''\n", + " for label in data_json['labels']:\n", + " html_tags = html_tags + f'

'\n", + " if position == True:\n", + " html_position = f'{ label[\"position\"] } '\n", + " html_tags = html_tags + html_position\n", + " if text == True:\n", + " html_text = f'{ label[\"text\"] } '\n", + " html_tags = html_tags + html_text\n", + " if timestamp == True:\n", + " html_timestamp = f'{ label[\"timestamp\"] } '\n", + " html_tags = html_tags + html_timestamp\n", + " if userID == True:\n", + " html_userID = f'{ label[\"userID\"] } '\n", + " html_tags = html_tags + html_userID\n", + " html_tags = html_tags + '

'\n", + " return html_tags" + ] + }, + { + "cell_type": "markdown", + "id": "1094ed8e-1387-481e-b612-9a8cc81d5c18", + "metadata": {}, + "source": [ + "This function was built for a project where individuals are invited to add their annotations on a map using the Annotation Compass. Each annotation-label is stored in a json-file and includes the annotation-text itself, but also the name of the image-file as well as the position, size, index, timestamp and userID of the annotation.\n", + "\n", + " Example for a label:\n", + "\n", + " {\n", + " 'image': 'map.jpg',\n", + " 'position': {'x': 12, 'y': 97},\n", + " 'size': {'width': 43, 'height': 18},\n", + " 'text': 'This is a text! Is this a text?',\n", + " 'timestamp': 'Wed, 01 Dec 2021 14:04:00 GMT',\n", + " 'userID': 5766039063\n", + " }\n", + "\n", + "\n", + "If interested in the position, text, timestamp and/or userID of all annotations, html_tag() can help. The function needs a string with the name of the of the image-file that was annotated with the annotation compass tool as well as four Boolean Values that define which information is of interest. The output is a string that can include the position, text, timestamp and/or userID of all labels plus html-tags that place them back into their original position\n", + "\n", + "How to get a json-file with annotation-labels?\n", + "\n", + " https://hub.xpub.nl/soupboat/generic-labels/\n", + "The Annotation Compass allows people to uplaod an image and ask others to annotate it. A json-file of the annotations is provided." + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples\n", + "\n", + "In this example, the function returns a string that includes the position of all labels with html-tags that place them back into their original position" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e3d7e97b-0089-4c29-a2c1-9ef823ff2e37", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'

{\\'x\\': 63.9896, \\'y\\': 34.2958}

{\\'x\\': 33.6269, \\'y\\': 65.1408}

{\\'x\\': 92.3483, \\'y\\': -0.179426}

{\\'x\\': 65.3034, \\'y\\': 35.4839}

{\\'x\\': 48.135, \\'y\\': 20.4458}

{\\'x\\': 76.25, \\'y\\': 69.5246}

{\\'x\\': 39.3264, \\'y\\': 46.831}

{\\'x\\': 77.0, \\'y\\': 63.7521}

{\\'x\\': 63.7806, \\'y\\': 41.0296}

{\\'x\\': 48.9886, \\'y\\': 51.256}

{\\'x\\': 36.5285, \\'y\\': 54.2958}

{\\'x\\': 55.0889, \\'y\\': 15.6154}

{\\'x\\': 47.2668, \\'y\\': 70.1459}

{\\'x\\': 42.5389, \\'y\\': 45.7042}

{\\'x\\': 45.2507, \\'y\\': 29.3907}

{\\'x\\': 60.774, \\'y\\': 59.7488}

{\\'x\\': 42.0882, \\'y\\': 18.8014}

{\\'x\\': 39.1192, \\'y\\': 36.2676}

{\\'x\\': 43.7995, \\'y\\': 27.0609}

{\\'x\\': 75.285, \\'y\\': 29.2254}

{\\'x\\': 52.0, \\'y\\': 48.1324}

{\\'x\\': 16.5775, \\'y\\': 28.7791}

{\\'x\\': 60.1554, \\'y\\': 63.3099}

{\\'x\\': 65.0396, \\'y\\': 45.3405}

{\\'x\\': 46.3713, \\'y\\': 58.4289}

{\\'x\\': 30.75, \\'y\\': 43.0391}

{\\'x\\': 60.3757, \\'y\\': 46.2333}

{\\'x\\': 49.2084, \\'y\\': 34.0502}

{\\'x\\': 38.4744, \\'y\\': 58.0105}

{\\'x\\': 23.9572, \\'y\\': 33.8663}

{\\'x\\': 57.625, \\'y\\': 34.3803}

{\\'x\\': 40.125, \\'y\\': 29.966}

{\\'x\\': 51.123, \\'y\\': 18.1686}

{\\'x\\': 44.3557, \\'y\\': 20.4458}

{\\'x\\': 55.621, \\'y\\': 33.6313}

{\\'x\\': 39.745, \\'y\\': 19.3153}

{\\'x\\': 57.9156, \\'y\\': 37.276}

{\\'x\\': 50.3743, \\'y\\': 52.0349}

{\\'x\\': 73.703, \\'y\\': 49.514}

{\\'x\\': 58.7942, \\'y\\': 43.0025}

{\\'x\\': 64.4007, \\'y\\': 39.7934}

{\\'x\\': 33.8622, \\'y\\': 34.9877}

'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "html_tag('rejection_map.jpg', True, False, False, False)" + ] + }, + { + "cell_type": "markdown", + "id": "d7fff3cd-ad3e-45ae-bf2e-ee1cd84c955b", + "metadata": {}, + "source": [ + "In this example, the function returns a string that includes the timestamp of all labels with html-tags that place them back into their original position" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b15b3303-aff9-418c-bb42-d68f85fcaed2", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'

Wed, 15 Dec 2021 11:36:04 GMT

Wed, 15 Dec 2021 11:36:36 GMT

Wed, 15 Dec 2021 11:36:47 GMT

Wed, 15 Dec 2021 11:36:47 GMT

Wed, 15 Dec 2021 11:36:48 GMT

Wed, 15 Dec 2021 11:36:51 GMT

Wed, 15 Dec 2021 11:36:55 GMT

Wed, 15 Dec 2021 11:37:25 GMT

Wed, 15 Dec 2021 11:37:28 GMT

Wed, 15 Dec 2021 11:37:34 GMT

Wed, 15 Dec 2021 11:37:37 GMT

Wed, 15 Dec 2021 11:37:46 GMT

Wed, 15 Dec 2021 11:37:56 GMT

Wed, 15 Dec 2021 11:38:04 GMT

Wed, 15 Dec 2021 11:38:09 GMT

Wed, 15 Dec 2021 11:38:37 GMT

Wed, 15 Dec 2021 11:38:41 GMT

Wed, 15 Dec 2021 11:38:45 GMT

Wed, 15 Dec 2021 11:39:12 GMT

Wed, 15 Dec 2021 11:39:21 GMT

Wed, 15 Dec 2021 11:40:13 GMT

Wed, 15 Dec 2021 11:40:24 GMT

Wed, 15 Dec 2021 11:40:27 GMT

Wed, 15 Dec 2021 11:40:42 GMT

Wed, 15 Dec 2021 11:40:54 GMT

Wed, 15 Dec 2021 11:41:01 GMT

Wed, 15 Dec 2021 11:41:14 GMT

Wed, 15 Dec 2021 11:41:23 GMT

Wed, 15 Dec 2021 11:42:08 GMT

Wed, 15 Dec 2021 11:42:17 GMT

Wed, 15 Dec 2021 11:42:20 GMT

Wed, 15 Dec 2021 11:42:52 GMT

Wed, 15 Dec 2021 11:43:10 GMT

Wed, 15 Dec 2021 11:43:23 GMT

Wed, 15 Dec 2021 11:43:45 GMT

Wed, 15 Dec 2021 11:44:03 GMT

Wed, 15 Dec 2021 11:44:13 GMT

Wed, 15 Dec 2021 11:44:16 GMT

Wed, 15 Dec 2021 11:44:35 GMT

Wed, 15 Dec 2021 11:45:07 GMT

Wed, 15 Dec 2021 11:49:16 GMT

Wed, 15 Dec 2021 11:49:37 GMT

'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "html_tag('rejection_map.jpg', False, False, True, False)" + ] + }, + { + "cell_type": "markdown", + "id": "17f420d7-9943-422b-a840-0e3a80179b03", + "metadata": {}, + "source": [ + "In this example, the function returns a string that includes the position, text, timestamp and userID of all labels with html-tags that place them back into their original position" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "05b52d15-7330-4484-8965-31f8c074d906", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'

{\\'x\\': 63.9896, \\'y\\': 34.2958} here, someone called my behaviour \"strange\" Wed, 15 Dec 2021 11:36:04 GMT 8112114057

{\\'x\\': 33.6269, \\'y\\': 65.1408} 윰보에서 장을 보고 집에 돌아오는 길. 두 명의 남자 가 다가왔어. 나는 낑낑대며 나의 일주일간 식량을 옮기고 있었지. 쾅!\\n큰 소리가 났고 나는 순간 움츠러들었어. \\n건너편에서 다가오던 남자 두명이 크게 웃더니 \\n나를 보며 Chino! Chino!라고 외쳤어. 시발. Wed, 15 Dec 2021 11:36:36 GMT 8633793842

{\\'x\\': 92.3483, \\'y\\': -0.179426} the municipality of rotterdam (prince alexander) almost refused to approve my request of registration because the italian id card doesn\\'t have my sex written on it. \\nthey said that if i bring my birth certificate that states that im a male i can have my bsn otherwise.......... nope. Wed, 15 Dec 2021 11:36:47 GMT 2396262941

{\\'x\\': 65.3034, \\'y\\': 35.4839} getting a text message from my good friend, telling me that she will not visit me in Rotterdam despite she promised me. Wed, 15 Dec 2021 11:36:47 GMT 4287159985

{\\'x\\': 48.135, \\'y\\': 20.4458} house viewing 2: meeting with some girls in the evening to see a room; felt super exposed and awkward. Later on, they rejected me. Wed, 15 Dec 2021 11:36:48 GMT 1933684842

{\\'x\\': 76.25, \\'y\\': 69.5246} I once went to view a house here but it didn\\'t have the floor. crap. Wed, 15 Dec 2021 11:36:51 GMT 6286616941

{\\'x\\': 39.3264, \\'y\\': 46.831} here, someone screamed at me \"move fucking chinee\" Wed, 15 Dec 2021 11:36:55 GMT 8112114057

{\\'x\\': 77.0, \\'y\\': 63.7521} other housing rejection situations here.\\n Wed, 15 Dec 2021 11:37:25 GMT 6286616941

{\\'x\\': 63.7806, \\'y\\': 41.0296} a woman on the train showed me the middle finger the first day i arrived to rotterdam and i didn\\'t really understand why because she\\'s the one that was mean with me in the first place Wed, 15 Dec 2021 11:37:28 GMT 4164927552

{\\'x\\': 48.9886, \\'y\\': 51.256} at 22:01 a bald man kicked us out from the basketball court because we were noisy Wed, 15 Dec 2021 11:37:34 GMT 2396262941

{\\'x\\': 36.5285, \\'y\\': 54.2958} here, someone screamed at me, right into my face, something I could not understand Wed, 15 Dec 2021 11:37:37 GMT 8112114057

{\\'x\\': 55.0889, \\'y\\': 15.6154} the most unpleasant house viewing: my viewing overlapped with the previous person and I didn\\'t got the chance to connect with the ones living them. How could then they know who I am and even consider me for the room? Wed, 15 Dec 2021 11:37:46 GMT 1933684842

{\\'x\\': 47.2668, \\'y\\': 70.1459} Stepped out at the wrong bus station and because the waiting time for the next bus was (a bit) long, Carmen and I decided to walk to Varia... Rejected by punctuality. Wed, 15 Dec 2021 11:37:56 GMT 1374899057

{\\'x\\': 42.5389, \\'y\\': 45.7042} here, someone told me to move away Wed, 15 Dec 2021 11:38:04 GMT 8112114057

{\\'x\\': 45.2507, \\'y\\': 29.3907} I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn\\'t like me. Obviously, I did not get the room. Wed, 15 Dec 2021 11:38:09 GMT 4287159985

{\\'x\\': 60.774, \\'y\\': 59.7488} rejected by the police Wed, 15 Dec 2021 11:38:37 GMT 2396262941

{\\'x\\': 42.0882, \\'y\\': 18.8014} my first house viewing: I was really hopeful about this one, actually, because I felt a connection with the girl. I waited 2 weeks to be rejected from this one. Wed, 15 Dec 2021 11:38:41 GMT 1933684842

{\\'x\\': 39.1192, \\'y\\': 36.2676} here, someone told to stop looking at them Wed, 15 Dec 2021 11:38:45 GMT 8112114057

{\\'x\\': 43.7995, \\'y\\': 27.0609} I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn\\'t like me. Not surprisingly, I did not get the room. Wed, 15 Dec 2021 11:39:12 GMT 1165348288

{\\'x\\': 75.285, \\'y\\': 29.2254} 어딘지 잘은 모르겠지만, Kralingen 쪽이었던 것 같아. bsn 거주등록을 위해 학교에 갔는데, 시청에서 나온 사람들이 나의 룸메이트 ID card가 필요하다며 거절했지. 나의 아침을 날렸어. 나의 룸메가 나에게 ID card 사진을 보내줬지만, 그들은 서명이 같지 않다면서 다시 거절했지. Wed, 15 Dec 2021 11:39:21 GMT 8633793842

{\\'x\\': 52.0, \\'y\\': 48.1324} i couldn\\'t eat anything from a spar because it was selling only non gluten-free products. Wed, 15 Dec 2021 11:40:13 GMT 6286616941

{\\'x\\': 16.5775, \\'y\\': 28.7791} I felt rejection in Art Rotterdam 2019 when the parents of my boyfriend\\'s exgirlfriend came to visit my exboyfriends exhibition there and I felt kinda OUT OF PLACE? heheheh Wed, 15 Dec 2021 11:40:24 GMT 4900861736

{\\'x\\': 60.1554, \\'y\\': 63.3099} Emma와 함께 프린트를 하러 갔는데, 그곳에 있는 instructor가 매우 불친절했어. Wed, 15 Dec 2021 11:40:27 GMT 8633793842

{\\'x\\': 65.0396, \\'y\\': 45.3405} An old friend of mine that I know from my home country also studies at WDKA. I reached out to him and suggested to hang out soon. He didn\\'t want to. Wed, 15 Dec 2021 11:40:42 GMT 1165348288

{\\'x\\': 46.3713, \\'y\\': 58.4289} somewhere between this line i lost my ID card. and I really wasnt aware that this could linger a lot my registration to the municipality. This kinda triggered but feeling for me, as I felt a lot disorented here, having no formal document verifying who I am and feeling guilty tat I am still not registered. Wed, 15 Dec 2021 11:40:54 GMT 6004575665

{\\'x\\': 30.75, \\'y\\': 43.0391} super nice sublet. I\\'ll be rejected in a month though. Wed, 15 Dec 2021 11:41:01 GMT 6286616941

{\\'x\\': 60.3757, \\'y\\': 46.2333} i got ejected from a bike here. i was just trying to move through space, but bikes don\\'t like me Wed, 15 Dec 2021 11:41:14 GMT 6874700431

{\\'x\\': 49.2084, \\'y\\': 34.0502} My bike got stolen here. Wed, 15 Dec 2021 11:41:23 GMT 1165348288

{\\'x\\': 38.4744, \\'y\\': 58.0105} The first time I stayed overnight in Rotterdam, after a nice walk in the sun, I got stuck 2 hours at Centraal, because the Intercity direct broke down. I felt rejected by NS. Wed, 15 Dec 2021 11:42:08 GMT 943340616

{\\'x\\': 23.9572, \\'y\\': 33.8663} I also felt rejection in Art Rotterdam 2020 when someone I knew from a gallery decided not to say hello back after me saying HELLO. Wed, 15 Dec 2021 11:42:17 GMT 4900861736

{\\'x\\': 57.625, \\'y\\': 34.3803} 💫💔💥🥐🍟🍕 Wed, 15 Dec 2021 11:42:20 GMT 6286616941

{\\'x\\': 40.125, \\'y\\': 29.966} missed a lot of trains Wed, 15 Dec 2021 11:42:52 GMT 6286616941

{\\'x\\': 51.123, \\'y\\': 18.1686} I felt rejected from some friends that made me a book but stop replying to my messages after my breakup. Wed, 15 Dec 2021 11:43:10 GMT 4900861736

{\\'x\\': 44.3557, \\'y\\': 20.4458} my first no-credit-card experience Wed, 15 Dec 2021 11:43:23 GMT 8403571053

{\\'x\\': 55.621, \\'y\\': 33.6313} we were going to a friends house when we got trapped into the riot against covid restrictions and a car got on fire and it was super bad to see all the anger all these people had i felt small and sad and i just wanted to run as faster as i could Wed, 15 Dec 2021 11:43:45 GMT 4164927552

{\\'x\\': 39.745, \\'y\\': 19.3153} my second no-credit card experience in a super nice bar; however, they were ok with a bank transfer :D Wed, 15 Dec 2021 11:44:03 GMT 8403571053

{\\'x\\': 57.9156, \\'y\\': 37.276} People throwing firework at other people here during an anti corona demonstration. Wed, 15 Dec 2021 11:44:13 GMT 997622868

{\\'x\\': 50.3743, \\'y\\': 52.0349} I felt rejected here when the friend mentioned in n3 introduced me to someone else calling me \"Raquel\" Wed, 15 Dec 2021 11:44:16 GMT 4900861736

{\\'x\\': 73.703, \\'y\\': 49.514} i got rejected from a skateboard here. it\\'s normal though because it\\'s always trying to reject you and you love it anyway Wed, 15 Dec 2021 11:44:35 GMT 8918562766

{\\'x\\': 58.7942, \\'y\\': 43.0025} they called me and tried to get my bank details saying that my bsn number has been used for illigal and criminal activities in amsterdam Wed, 15 Dec 2021 11:45:07 GMT 4164927552

{\\'x\\': 64.4007, \\'y\\': 39.7934} my wallet rejected me for about 10 mins heree. it fell from my pocket at albert heijn but we reunited at the customer service desk. it was intense. Wed, 15 Dec 2021 11:49:16 GMT 1167447361

{\\'x\\': 33.8622, \\'y\\': 34.9877} house rejection\\n Wed, 15 Dec 2021 11:49:37 GMT 4164927552

'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "html_tag('rejection_map.jpg', True, True, True, True)" + ] + }, + { + "cell_type": "markdown", + "id": "4b540ec0-233b-4f90-808e-97ce94c82fcb", + "metadata": {}, + "source": [ + "In this example, the function takes another function as an input and returns a string that includes the text of all labels with html-tags that place them back into their original position" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "2f5d482f-7617-400c-9177-69ffa93ef67f", + "metadata": {}, + "outputs": [], + "source": [ + "url = \"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image=rejection_map.jpg\"\n", + "response = urlopen(url)\n", + "data_json = json.loads(response.read()) \n", + "\n", + "def target_map_list(labels: list, targets: list ) -> list: \n", + " \n", + " filter_map = []\n", + " for label in labels:\n", + " for target in targets:\n", + " if target in label['text']:\n", + " filter_map.append(label)\n", + " \n", + " return filter_map" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "74f18d6d-eae2-4d29-90d2-597379e624e0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'

house viewing 2: meeting with some girls in the evening to see a room; felt super exposed and awkward. Later on, they rejected me.

I once went to view a house here but it didn\\'t have the floor. crap.

the most unpleasant house viewing: my viewing overlapped with the previous person and I didn\\'t got the chance to connect with the ones living them. How could then they know who I am and even consider me for the room?

I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn\\'t like me. Obviously, I did not get the room.

my first house viewing: I was really hopeful about this one, actually, because I felt a connection with the girl. I waited 2 weeks to be rejected from this one.

I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn\\'t like me. Not surprisingly, I did not get the room.

we were going to a friends house when we got trapped into the riot against covid restrictions and a car got on fire and it was super bad to see all the anger all these people had i felt small and sad and i just wanted to run as faster as i could

we were going to a friends house when we got trapped into the riot against covid restrictions and a car got on fire and it was super bad to see all the anger all these people had i felt small and sad and i just wanted to run as faster as i could

house rejection\\n

'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "html_tag_list(target_map_list(data_json['labels'], ['house', 'sad']), False, True, False, False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef344f39-8922-4a03-bbb8-1e279096ff5e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/individual_map.ipynb b/notebooks/individual_map.ipynb new file mode 100644 index 0000000..5679342 --- /dev/null +++ b/notebooks/individual_map.ipynb @@ -0,0 +1,172 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# individual_map\n", + "give a string with the name of the image-file that was annotated with the Annotation Compass; Select one or more specific targets and return a list of all labels that include these targetsselect one or more specific users and return a list of all labels from these users." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "de97fe2f-daae-4293-a0b3-ea42c759535a", + "metadata": {}, + "outputs": [], + "source": [ + "from urllib.request import urlopen\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "9bd8860a-9967-49d5-a74a-b5de669dfe6d", + "metadata": {}, + "outputs": [], + "source": [ + "def individual_map(image: str, users: list ) -> list:\n", + " \n", + " \"\"\"give a string with the name of the image-file that was annotated with the Annotation Compass; Select one or more specific targets and return a list of all labels that include these targetsselect one or more specific users and return a list of all labels from these users.\"\"\" \n", + "\n", + " url = f\"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image={image}\"\n", + " response = urlopen(url)\n", + " data_json = json.loads(response.read()) \n", + " \n", + " filtered_map = []\n", + " for label in data_json['labels']:\n", + " for user in users:\n", + " if label['userID'] == user:\n", + " filtered_map.append(label)\n", + " return filtered_map" + ] + }, + { + "cell_type": "markdown", + "id": "1094ed8e-1387-481e-b612-9a8cc81d5c18", + "metadata": {}, + "source": [ + "This function was built for a project where individuals are invited to add their annotations on a map using the Annotation Compass. Each annotation-label is stored in a json-file and includes the annotation-text itself, but also the name of the image-file as well as the position, size, index, timestamp and userID of the annotation.\n", + "\n", + " Example for a label:\n", + "\n", + " {'image': 'map.jpg',\n", + " 'position': {'x': 12, 'y': 97},\n", + " 'size': {'width': 43, 'height': 18},\n", + " 'text': 'This is a text! Is this a text?',\n", + " 'timestamp': 'Wed, 01 Dec 2021 14:04:00 GMT',\n", + " 'userID': 5766039063}\n", + "\n", + "\n", + "If interested in all annotations of one or more specific users, individual_map() can help. The function needs a string with the name of the of the image-file that was annotated with the annotation compass tool as well as one or more specific userIDs to target. The output is a list of all labels from the users of interest.\n", + "\n", + "How to get a json-file with annotation-labels?\n", + "\n", + " https://hub.xpub.nl/soupboat/generic-labels/\n", + "The Annotation Compass allows people to uplaod an image and ask others to annotate it. A json-file of the annotations is provided." + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples\n", + "\n", + "In this example, the function returns all annotation-labels of two specific users." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "e3d7e97b-0089-4c29-a2c1-9ef823ff2e37", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'image': 'rejection_map.jpg',\n", + " 'position': {'x': 63.9896, 'y': 34.2958},\n", + " 'size': {'height': 3.23944, 'width': 2.90155},\n", + " 'text': 'here, someone called my behaviour \"strange\"',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:36:04 GMT',\n", + " 'userID': '8112114057'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 39.3264, 'y': 46.831},\n", + " 'size': {'height': 6.19718, 'width': 9.2228},\n", + " 'text': 'here, someone screamed at me \"move fucking chinee\"',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:36:55 GMT',\n", + " 'userID': '8112114057'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 36.5285, 'y': 54.2958},\n", + " 'size': {'height': 1.69014, 'width': 3.31606},\n", + " 'text': 'here, someone screamed at me, right into my face, something I could not understand',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:37:37 GMT',\n", + " 'userID': '8112114057'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 42.5389, 'y': 45.7042},\n", + " 'size': {'height': 13.662, 'width': 23.9378},\n", + " 'text': 'here, someone told me to move away',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:38:04 GMT',\n", + " 'userID': '8112114057'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 39.1192, 'y': 36.2676},\n", + " 'size': {'height': 11.6901, 'width': 20.4145},\n", + " 'text': 'here, someone told to stop looking at them',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:38:45 GMT',\n", + " 'userID': '8112114057'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 46.3713, 'y': 58.4289},\n", + " 'size': {'height': 6.99541, 'width': 15.1055},\n", + " 'text': 'somewhere between this line i lost my ID card. and I really wasnt aware that this could linger a lot my registration to the municipality. This kinda triggered but feeling for me, as I felt a lot disorented here, having no formal document verifying who I am and feeling guilty tat I am still not registered.',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:40:54 GMT',\n", + " 'userID': '6004575665'}]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "individual_map('rejection_map.jpg', ['8112114057', '6004575665'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fcbbb728-217d-47a3-b672-d03d120fa408", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/mashup.ipynb b/notebooks/mashup.ipynb new file mode 100644 index 0000000..5cf8058 --- /dev/null +++ b/notebooks/mashup.ipynb @@ -0,0 +1,258 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b774afd4-4a80-48c5-a09a-7623429c7f0a", + "metadata": {}, + "source": [ + "# Mashup()\n" + ] + }, + { + "cell_type": "markdown", + "id": "626002a1-958c-4a31-bf75-50cd5dfab433", + "metadata": {}, + "source": [ + "**Mashup()** is a function that compare **two similar texts** and produce **a third text** that randomly choose between the original texts. \n", + "The outcome is a text with the differences chosen through random choice.\n", + "\n", + "A function that: \n", + "1. takes into account **2 similar texts** (example: 2 different translations of a poems)\n", + "2. finds the **fixed_words** and uses them as the fixed text for the new piece of text\n", + "3. puts the results together into **a new piece**, randomly choosing the different options \n", + "4. html output that **highlights the different random choices** of the translations\n" + ] + }, + { + "cell_type": "markdown", + "id": "b3e00ed0-59e2-4e1c-aa23-fd412fc8524b", + "metadata": {}, + "source": [ + "**how to use**: to use this function it is necessary to have two texts with the same number of lines (as it goes throught the two texts and compares them line by line). It can be use also with list of strings." + ] + }, + { + "cell_type": "markdown", + "id": "04e48da5-eeae-440d-8f8a-5952d6706d81", + "metadata": {}, + "source": [ + "**input:** 2 texts that are similar but not the exact copy of each other -- " + ] + }, + { + "cell_type": "markdown", + "id": "e8b2ab5c-3b41-4dce-8490-8d7052cdb858", + "metadata": {}, + "source": [ + "**output:** a new text that showcase the differences // a new text made out of random choice // *still not clear yet* // extracted pdf/txt file?" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "e6d5f744-d079-4a51-a5c2-6845a7a7ac56", + "metadata": {}, + "outputs": [], + "source": [ + "# define texts\n", + "\n", + "text1= '''\n", + "The glasses were empty\n", + "The bottle was shattered\n", + "The bed was wide open\n", + "The door was tight shuttered\n", + "Each shard was a star\n", + "Of bliss and of beauty\n", + "That flashed on the floor\n", + "All dusty and dirty\n", + "And I was dead drunk\n", + "Lit up wildly ablaze\n", + "You were drunk and alive\n", + "In a naked embrace!\n", + "'''\n", + "text2= '''\n", + "So the glasses were empty\n", + "and the bottle broken\n", + "And the bed was wide open\n", + "and the door closed\n", + "And all of the glass stars\n", + "of happiness and beauty \n", + "were sparkling in the dust\n", + "of the poorly dusted room.\n", + "And I was dead drunk\n", + "And I was a bonfire\n", + "And you were alive, drunk,\n", + "all naked in my arms.\n", + "'''\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8f10c45-0ce7-4ef8-9a5f-6a92f69902a2", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "3c62af9c-b078-4117-b84b-e191048c6a93", + "metadata": {}, + "outputs": [], + "source": [ + "import difflib\n", + "from random import choice\n", + "\n", + "def mashup(text1,text2): #take into account 2 texts\n", + " \n", + " text1 = text1.splitlines() #split texts in lines\n", + " text2 = text2.splitlines()\n", + " \n", + " fixed_words= [] #define empty list for fixed_words (words that are the same in both texts) // a list of lists of words\n", + " for line_A, line_B in zip(text1, text2): #start the first loop reading line by line from both texts at the same time (=zip)\n", + " words_A = line_A.split() #split lines in lists of words\n", + " words_B = line_B.split()\n", + " \n", + " d = difflib.Differ() #Differ compare sequences of lines of text, and produce human-readable differences ('+' in text1), ('-' in text2), ('' fixed_Words)\n", + " diff = d.compare(words_A, words_B) #compare the difference between the two lists of words\n", + " \n", + " \n", + " linelist = [] #define empty list \n", + " for result in diff: #second loop that goes through all the lines and then the words of both texts simultaneously\n", + " code, word = result.split(' ', 1) #split result of diff in code [('+'), ('-') or ('')] and the resulting word (is it the same or is it just in one of the two texts?)\n", + " word = word.strip() #to be sure it doesn't have any weird things /n at the ends of the lines\n", + " if code == '' : #if the code is ' ' (nothing) it means that the word can be found in both texts\n", + " linelist.append(word) #if this happens, put the corresponding words in the linelist\n", + " fixed_words.append(linelist) #afterwards, add linelist to fixed_words (linelist is inside the loop so all the words in every line are put in there, but fixed_words is outside so that just the words are added just once)\n", + " \n", + " length = len(text1) #define lenght of text1\n", + " for linenumber in range(length): #for the number of the lines in the lenght of the text\n", + " cut_left1 = 0 #the beginning of both texts is position n°0 (on the left side of the lines)\n", + " cut_left2 = 0\n", + " words_1 = text1[linenumber].split() #words_1 is split in words keeping the position in the lines\n", + " words_2 = text2[linenumber].split() \n", + " if len(fixed_words[linenumber]) > 0: #if the index on the fixed words in the line is more than 0 (it's not the first one)\n", + " for fixed_word in fixed_words[linenumber]: #for all the fixed_words that are in the fixed_words list always following the linenumbers\n", + " cut_right1 = words_1.index(fixed_word) #finding the first fixed_word from the left (beginning / position 0) to the right(end of sentence / last word in the line)\n", + " cut_right2 = words_2.index(fixed_word) #in both texts\n", + "\n", + " slice_1 = words_1[cut_left1 : cut_right1] #create slice_1 \n", + " slice_2 = words_2[cut_left2 : cut_right2]\n", + " print(choice([slice_1, slice_2]))\n", + " \n", + " cut_left1 = cut_right1 #now invert, when it's gone through all the words till finding the last fixed word\n", + " cut_left2 = cut_right2\n", + "\n", + " slice_1 = words_1[cut_left1 :] #from the last fixed_word found to the right\n", + " slice_2 = words_2[cut_left2 :]\n", + " print(choice([slice_1, slice_2])) #choose\n", + " else:\n", + " slice_1 = words_1[cut_left1 :] #here is doing it outside of the loop ( it gets the last word of the line if it's not a\n", + " slice_2 = words_2[cut_left2 :]\n", + " print(choice([slice_1, slice_2])) #choose\n", + " print('--------') \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "78c7643c-e797-451e-872d-e6dd81f0052c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n", + "--------\n", + "['So', 'the']\n", + "['glasses']\n", + "['were']\n", + "['empty']\n", + "--------\n", + "['and', 'the']\n", + "['bottle', 'was', 'shattered']\n", + "--------\n", + "['The']\n", + "['bed']\n", + "['was']\n", + "['wide']\n", + "['open']\n", + "--------\n", + "['and', 'the']\n", + "['door', 'was', 'tight', 'shuttered']\n", + "--------\n", + "['And', 'all', 'of', 'the', 'glass', 'stars']\n", + "--------\n", + "['of', 'happiness']\n", + "['and']\n", + "['beauty']\n", + "--------\n", + "['were', 'sparkling', 'in']\n", + "['the', 'dust']\n", + "--------\n", + "['All', 'dusty', 'and', 'dirty']\n", + "--------\n", + "[]\n", + "['And']\n", + "['I']\n", + "['was']\n", + "['dead']\n", + "['drunk']\n", + "--------\n", + "['And', 'I', 'was', 'a', 'bonfire']\n", + "--------\n", + "['And', 'you']\n", + "['were', 'alive,', 'drunk,']\n", + "--------\n", + "['In', 'a']\n", + "['naked', 'in', 'my', 'arms.']\n", + "--------\n" + ] + } + ], + "source": [ + "mashup(text1,text2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07f2e386-3380-4dc0-b680-d5b1288e7794", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b127fbb-6e70-4614-a727-2ec476e43236", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/repeat.ipynb b/notebooks/repeat.ipynb new file mode 100644 index 0000000..b8eeb28 --- /dev/null +++ b/notebooks/repeat.ipynb @@ -0,0 +1,124 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# Repeat\n", + "Repeat a string for a specified number of times" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9bd8860a-9967-49d5-a74a-b5de669dfe6d", + "metadata": {}, + "outputs": [], + "source": [ + "def repeat(text: str, times: int = 2) -> str:\n", + " \"\"\"Repeat a string for a specified number of times\"\"\"\n", + " return text * times" + ] + }, + { + "cell_type": "markdown", + "id": "d50511cb-a810-4fe1-a681-e5cb1392c0d0", + "metadata": {}, + "source": [ + "![ara repeating itself](https://www.dienst.nl/sub/upload/images/1/30019_550.jpg)" + ] + }, + { + "cell_type": "markdown", + "id": "1094ed8e-1387-481e-b612-9a8cc81d5c18", + "metadata": {}, + "source": [ + "This function has many attractive qualities, but its ability to repeat human speech is one that makes it truly unique among other types of companion python functions and one that has ensured its popularity for generations. You are likely to find, though, that the function's talents for mimicry still pales in comparison to the fact that it is charming, engaging, and truly remarkable. Here is one of the most popular repeating function so that you can appreciate more about what it has to offer. It often says injuries to people and computers. " + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples\n", + "\n", + "The function takes a string as a parameter, and by default it repeats it twice. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "e3d7e97b-0089-4c29-a2c1-9ef823ff2e37", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'hellohello'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "repeat('hello')" + ] + }, + { + "cell_type": "markdown", + "id": "d3ce6961-68ff-4338-a71f-f8d77aa4f949", + "metadata": {}, + "source": [ + "Eventually with a second parameter you can specify how many times you want it to repeats. " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "dd3f3a0b-3145-4914-8638-951bcdbd0774", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'salutsalutsalutsalut'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "repeat('salut', 4)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/respell.ipynb b/notebooks/respell.ipynb new file mode 100644 index 0000000..83ab2a3 --- /dev/null +++ b/notebooks/respell.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4b1d288c-50c0-4da2-9ea9-bf5adb06b034", + "metadata": {}, + "source": [ + "# Respell\n", + "Respell receives as input a text as a string type, and substitute all the occurrences of a targeted word with a replacement as a string type chosen by the user." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "691152f6-8e85-4fc2-8c98-848448ee959a", + "metadata": {}, + "outputs": [], + "source": [ + "from nltk.tokenize import word_tokenize" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "2a46fe37-b62f-482a-a040-9f7a5d39fc0e", + "metadata": {}, + "outputs": [], + "source": [ + "# text, target, and replacement are string types\n", + "def respell(text, target, replacement):\n", + " target = target.lower()\n", + " txt = word_tokenize(text)\n", + " new = []\n", + " \n", + " for w in txt:\n", + " if w == target:\n", + " w = replacement\n", + " new = new + [w]\n", + " elif w == target[0:1].upper() + target[1:]:\n", + " w = replacement[0:1].upper() + replacement[1:] \n", + " new = new + [w]\n", + " elif w == target.upper():\n", + " w = replacement.upper()\n", + " new = new + [w]\n", + " else:\n", + " new = new + [w]\n", + " text = ' '.join(new)\n", + " final= text.replace(' .','.').replace(' ,',',').replace(' :',':').replace(' ;',';').replace('< ','<').replace(' >','>').replace(' / ','/').replace('& ','&')\n", + " return final" + ] + }, + { + "cell_type": "markdown", + "id": "63374a00-6091-484d-9ffd-ebf79d13cdc1", + "metadata": {}, + "source": [ + "This function in itself could be understood as a filter to process and alter texts. By targeting specific words and replacing them, either for another word, for specific characters or for blank spaces, the user of the tool can intervene inside a text. One could break down the meaning of a text or create new narrative meanings by exposing its structure, taking out or highlighting specific and meaningful words and detaching such text from its original context. \n", + "This tool offers a broad spectrum of possibilities in which it can be used, from a very political and subversive use, to a more playful and poetic one." + ] + }, + { + "cell_type": "markdown", + "id": "1fde0e28-f253-4992-96d1-0497da2959f6", + "metadata": {}, + "source": [ + "# Examples" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "6c80de23-d4ad-45a7-8b2f-b07c4ff2e549", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'potato is potato'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "respell(\"life is life\",\"life\",\"potato\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "772ae978-5551-486e-add1-0a5a660a0bff", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'🥙 is 🥙'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "respell(\"life is life\",\"life\",\"🥙\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/reveal.ipynb b/notebooks/reveal.ipynb new file mode 100644 index 0000000..cc06769 --- /dev/null +++ b/notebooks/reveal.ipynb @@ -0,0 +1,189 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f0e7e936-865b-4389-b180-e07eaf8f4cfc", + "metadata": {}, + "source": [ + "# Reveal\n", + "Reveal takes a text as string input and deletes all its characters except the input list of words." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f920735b-ed2a-4dd6-8c28-95b4dafad70a", + "metadata": {}, + "outputs": [], + "source": [ + "from nltk.tokenize import word_tokenize" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "2c72ec84-7f91-4d1e-b9f9-6629ab4fae94", + "metadata": {}, + "outputs": [], + "source": [ + "def reveal(text,group):\n", + " txt = word_tokenize(text)\n", + " \n", + " txt_linebr = []\n", + " for token in txt:\n", + " if token == '<':\n", + " continue\n", + " elif token == 'br/':\n", + " token='
'\n", + " txt_linebr.append(token)\n", + " elif token == '>':\n", + " continue\n", + " else:\n", + " txt_linebr.append(token) \n", + " new = []\n", + " for w in txt_linebr:\n", + " if w=='
':\n", + " new = new + [w]\n", + " elif w not in group:\n", + " w = len(w) * ' '\n", + " new = new + [w]\n", + " elif w in group :\n", + " new = new + [w]\n", + " text = ' '.join(new)\n", + " final= text.replace(' .','.').replace(' ,',',').replace(' :',':').replace(' ;',';').replace('< ','<').replace(' >','>').replace(' / ','/').replace('& ','&')\n", + " return final" + ] + }, + { + "cell_type": "markdown", + "id": "cff36759-e377-48d5-93f8-d78f6f9a3050", + "metadata": {}, + "source": [ + "This function in itself could be understood as a filter to process and alter texts. By chosing to keeping specific words of a text and deleting all the others, the user of the tool can intervene inside a text. One could break down the meaning of a text or create new narrative meanings by exposing its structure, taking out or highlighting specific and meaningful words and detaching such text from its original context. \n", + "This tool offers a broad spectrum of possibilities in which it can be used, from a very political and subversive use, to a more playful and poetic one." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "a6bce73e-8084-4bd0-b7b8-95cd39069030", + "metadata": {}, + "outputs": [], + "source": [ + "text = f\"\"\"\n", + "Live\n", + "Live is life\n", + "Live\n", + "Live\n", + "\n", + "When we all give the power\n", + "We all give the best\n", + "Every minute of an hour\n", + "Don't think about a rest\n", + "Then you all get the power\n", + "You all get the best\n", + "When everyone gives everything\n", + "And every song everybody sings\n", + "\n", + "Then it's live\n", + "Live is life\n", + "Live is life\n", + "Live\n", + "\n", + "Live is life, when we all feel the power\n", + "Live is life, come on stand up and dance\n", + "Live is life, when the feeling of the people\n", + "Live is life, is the feeling of the band\n", + "\n", + "When we all give the power\n", + "We all give the best\n", + "Every minute of an hour\n", + "Don't think about a rest\n", + "Then you all get the power\n", + "You all get the best\n", + "When everyone gives everything\n", + "And every song everybody sings\n", + "\n", + "Then it's live\n", + "Live is life\n", + "Live\n", + "Live is life\n", + "Live\n", + "\n", + "Live\n", + "Live is life\n", + "Live\n", + "Live is life\n", + "\n", + "And you call when it's over\n", + "You call it should last\n", + "Every minute of the future\n", + "Is a memory of the past\n", + "'Cause we all gave the power\n", + "We all gave the best\n", + "And everyone gave everything\n", + "And every song everybody sang\n", + "Live is life\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "8d6dfda4-122b-42cc-8d29-5d141d726c47", + "metadata": {}, + "source": [ + "# Examples" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "89d83728-6e1c-4270-b0bc-6cfb59f4f389", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Live Live is life Live Live live Live is life Live is life Live Live is life Live is life Live is life Live is life is live Live is life Live Live is life Live Live Live is life Live Live is life Live is life'" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reveal(text,[\"Live\",\"is\",\"life\",\"live\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8ec2e799-7e05-42c3-ae4c-84a299b66a2d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/reverse.ipynb b/notebooks/reverse.ipynb new file mode 100644 index 0000000..a216e1b --- /dev/null +++ b/notebooks/reverse.ipynb @@ -0,0 +1,71 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5688f740-c1a2-4271-880d-2be65c748d94", + "metadata": {}, + "source": [ + "# REVERSE!" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "df889e4f-3ccc-4411-b4c7-53c8098661c9", + "metadata": {}, + "outputs": [], + "source": [ + "from textblob import TextBlob\n", + "\n", + "def reverse (inputz: str) -> str:\n", + " \"\"\"Reverse the input sentence by sentence\"\"\"\n", + " blob = TextBlob(inputz)\n", + " return \"\\n\".join(str(reversed(blob.sentences)))\n", + " \n", + " # return \" \".join(reversed(inputz.split()))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c481d133-0fc4-4046-8f50-0e5cea1c0e11", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'<\\nl\\ni\\ns\\nt\\n_\\nr\\ne\\nv\\ne\\nr\\ns\\ne\\ni\\nt\\ne\\nr\\na\\nt\\no\\nr\\n \\no\\nb\\nj\\ne\\nc\\nt\\n \\na\\nt\\n \\n0\\nx\\na\\nc\\n4\\na\\nf\\n3\\n9\\n0\\n>'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse(\"hello world\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/shout.ipynb b/notebooks/shout.ipynb new file mode 100644 index 0000000..5a015eb --- /dev/null +++ b/notebooks/shout.ipynb @@ -0,0 +1,158 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# Shout\n", + "This function take a text and shouts it LOUD. It repeats the vowels for a specified number of times." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9bd8860a-9967-49d5-a74a-b5de669dfe6d", + "metadata": {}, + "outputs": [], + "source": [ + "def shout(text: str, volume: int = 5) -> str:\n", + " \"\"\"Repeat the vowels in a string for a specified number of times\"\"\"\n", + " shouted_text = ''\n", + " for c in text:\n", + " character = c\n", + " if c.lower() in ['a','e','i','o','u','y']:\n", + " character = character * volume\n", + " shouted_text = shouted_text + character\n", + " return shouted_text" + ] + }, + { + "cell_type": "markdown", + "id": "d50511cb-a810-4fe1-a681-e5cb1392c0d0", + "metadata": {}, + "source": [ + "![Snake on a sbake](https://hub.xpub.nl/soupboat/~kamo/assets/goose.jpg)" + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "e3d7e97b-0089-4c29-a2c1-9ef823ff2e37", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'heeeeelp'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "shout('help')" + ] + }, + { + "cell_type": "markdown", + "id": "d3ce6961-68ff-4338-a71f-f8d77aa4f949", + "metadata": {}, + "source": [ + "The first parameter is the text you want to shout. It can be anything, like a terrorized cry or a drunk song at 4am outside the pub. \n", + "If you want to scream louder you can specify a second parameter for the volume. This is a number and by default is 5. It has to be positive but there are no limits to it." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "dd3f3a0b-3145-4914-8638-951bcdbd0774", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'HEEEEEEEEEELP'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "shout('HELP', 10)" + ] + }, + { + "cell_type": "markdown", + "id": "d7e70281-0562-4fb0-8c07-b2ea7143b393", + "metadata": {}, + "source": [ + "You see, this is very a dangerous situation." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "9f685cab-278e-4b44-afd9-6e6012981442", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'MG HLP'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "shout('OMG HELP', 0)" + ] + }, + { + "cell_type": "markdown", + "id": "0f668b5e-43bf-4321-b05b-5930d6eac152", + "metadata": {}, + "source": [ + "A muted scream" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/stich.ipynb b/notebooks/stich.ipynb new file mode 100644 index 0000000..a195754 --- /dev/null +++ b/notebooks/stich.ipynb @@ -0,0 +1,141 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "af317257-97a8-46db-ac92-e06bdef22ed3", + "metadata": {}, + "source": [ + "# Stitch\n", + "Stitch receives as input a text as a string type, and replaces all the occurrences of a target word, with a character or a word that is repeated as many times as the length of the target. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "8c280e90-22dc-4e59-90fe-3bdf97da06b2", + "metadata": {}, + "outputs": [], + "source": [ + "from nltk.tokenize import word_tokenize" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "f26e528c-1d61-4796-a42a-a3d5d0edc574", + "metadata": {}, + "outputs": [], + "source": [ + "# text, target, and replacement are string types\n", + "def stich(text, target, replacement):\n", + " target = target.lower()\n", + " txt = word_tokenize(text)\n", + " new = []\n", + " \n", + " for w in txt:\n", + " if w == target:\n", + " w = len(w)*replacement\n", + " new = new + [w]\n", + " elif w == target[0].upper() + target[1:]:\n", + " w = len(w)*replacement\n", + " new = new + [w]\n", + " elif w== target.upper():\n", + " w = len(w)*replacement \n", + " new = new + [w]\n", + " else:\n", + " new = new + [w]\n", + " text = ' '.join(new)\n", + " final= text.replace(' .','.').replace(' ,',',').replace(' :',':').replace(' ;',';').replace('< ','<').replace(' >','>').replace(' / ','/').replace('& ','&')\n", + " return final" + ] + }, + { + "cell_type": "markdown", + "id": "7e5443c5-e6d3-4dca-b196-7f8c0204814f", + "metadata": {}, + "source": [ + "This function in itself could be understood as a filter to process and alter texts. By targeting specific words and stitching them, with a character or a word that is repeated as many times as the length of the target , the user of the tool can intervene inside a text. One could break down the meaning of a text or create new narrative meanings by exposing its structure, taking out or highlighting specific and meaningful words and detaching such text from its original context. \n", + "This tool offers a broad spectrum of possibilities in which it can be used, from a very political and subversive use, to a more playful and poetic one." + ] + }, + { + "cell_type": "markdown", + "id": "e054e805-9abb-4751-af1f-0039975520d6", + "metadata": {}, + "source": [ + "# Examples" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "32c73229-7914-4b16-8054-a74a6869ede8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "' is '" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stich(\"life is life\",\"life\",\" \")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "9d273092-5cda-4d75-ad1c-9473bf65e69a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'**** is ****'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stich(\"life is life\",\"life\",\"*\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0805582-fa73-43b5-b6f9-01cfedd4003d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/target_map.ipynb b/notebooks/target_map.ipynb new file mode 100644 index 0000000..a9204e1 --- /dev/null +++ b/notebooks/target_map.ipynb @@ -0,0 +1,190 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# target_map\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Select one or more specific targets and return a list of all labels that include these targets" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "dc7040fd-ec5d-49e6-98e5-1feae91fc74b", + "metadata": {}, + "outputs": [], + "source": [ + "from urllib.request import urlopen\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9bd8860a-9967-49d5-a74a-b5de669dfe6d", + "metadata": {}, + "outputs": [], + "source": [ + "def target_map(image: str, targets: list ) -> list:\n", + " \n", + " \"\"\"Give a string with the name of the image-file that was annotated with the Annotation Compass; Select one or more specific targets and return a list of all labels that include these targets.\"\"\" \n", + "\n", + " url = f\"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image={image}\"\n", + " response = urlopen(url)\n", + " data_json = json.loads(response.read()) \n", + " \n", + " filter_map = []\n", + " for label in data_json['labels']:\n", + " for target in targets:\n", + " if target in label['text']:\n", + " filter_map.append(label)\n", + " return filter_map" + ] + }, + { + "cell_type": "markdown", + "id": "1094ed8e-1387-481e-b612-9a8cc81d5c18", + "metadata": {}, + "source": [ + "This function was built for a project where individuals are invited to add their annotations on a map using the Annotation Compass. Each annotation-label is stored in a json-file and includes the annotation-text itself, but also the name of the image-file as well as the position, size, index, timestamp and userID of the annotation.\n", + "\n", + " Example for a label:\n", + "\n", + " {'image': 'map.jpg',\n", + " 'position': {'x': 12, 'y': 97},\n", + " 'size': {'width': 43, 'height': 18},\n", + " 'text': 'This is a text! Is this a text?',\n", + " 'timestamp': 'Wed, 01 Dec 2021 14:04:00 GMT',\n", + " 'userID': 5766039063}\n", + "\n", + "\n", + "If interested in all annotations that include one or more specific targets, target_map() can help. The function needs a string with the name of the of the image-file that was annotated with the annotation compass tool as well as one or more specific targets. The output is a list of all labels that include these targets.\n", + "\n", + "How to get a json-file with annotation-labels?\n", + "\n", + " https://hub.xpub.nl/soupboat/generic-labels/\n", + "The Annotation Compass allows people to uplaod an image and ask others to annotate it. A json-file of the annotations is provided." + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples\n", + "\n", + "In this example, the function returns all annotation-labels that include two specific targets." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e3d7e97b-0089-4c29-a2c1-9ef823ff2e37", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'image': 'rejection_map.jpg',\n", + " 'position': {'x': 48.135, 'y': 20.4458},\n", + " 'size': {'height': 4.62487, 'width': 2.94785},\n", + " 'text': 'house viewing 2: meeting with some girls in the evening to see a room; felt super exposed and awkward. Later on, they rejected me.',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:36:48 GMT',\n", + " 'userID': '1933684842'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 76.25, 'y': 69.5246},\n", + " 'size': {'height': 12.3939, 'width': 15.625},\n", + " 'text': \"I once went to view a house here but it didn't have the floor. crap.\",\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:36:51 GMT',\n", + " 'userID': '6286616941'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 55.0889, 'y': 15.6154},\n", + " 'size': {'height': 4.21377, 'width': 3.55253},\n", + " 'text': \"the most unpleasant house viewing: my viewing overlapped with the previous person and I didn't got the chance to connect with the ones living them. How could then they know who I am and even consider me for the room?\",\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:37:46 GMT',\n", + " 'userID': '1933684842'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 45.2507, 'y': 29.3907},\n", + " 'size': {'height': 6.09319, 'width': 6.59631},\n", + " 'text': \"I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn't like me. Obviously, I did not get the room.\",\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:38:09 GMT',\n", + " 'userID': '4287159985'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 42.0882, 'y': 18.8014},\n", + " 'size': {'height': 3.08325, 'width': 1.66289},\n", + " 'text': 'my first house viewing: I was really hopeful about this one, actually, because I felt a connection with the girl. I waited 2 weeks to be rejected from this one.',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:38:41 GMT',\n", + " 'userID': '1933684842'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 43.7995, 'y': 27.0609},\n", + " 'size': {'height': 9.319, 'width': 8.04749},\n", + " 'text': \"I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn't like me. Not surprisingly, I did not get the room.\",\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:39:12 GMT',\n", + " 'userID': '1165348288'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 55.621, 'y': 33.6313},\n", + " 'size': {'height': 15.6597, 'width': 7.43427},\n", + " 'text': 'we were going to a friends house when we got trapped into the riot against covid restrictions and a car got on fire and it was super bad to see all the anger all these people had i felt small and sad and i just wanted to run as faster as i could',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:43:45 GMT',\n", + " 'userID': '4164927552'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 55.621, 'y': 33.6313},\n", + " 'size': {'height': 15.6597, 'width': 7.43427},\n", + " 'text': 'we were going to a friends house when we got trapped into the riot against covid restrictions and a car got on fire and it was super bad to see all the anger all these people had i felt small and sad and i just wanted to run as faster as i could',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:43:45 GMT',\n", + " 'userID': '4164927552'},\n", + " {'image': 'rejection_map.jpg',\n", + " 'position': {'x': 33.8622, 'y': 34.9877},\n", + " 'size': {'height': 12.8237, 'width': 13.7806},\n", + " 'text': 'house rejection\\n',\n", + " 'timestamp': 'Wed, 15 Dec 2021 11:49:37 GMT',\n", + " 'userID': '4164927552'}]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_map('rejection_map.jpg', ['house', 'sad'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c91b182-7541-4a79-a0f2-b2e688dd4371", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/vernacular_map.ipynb b/notebooks/vernacular_map.ipynb new file mode 100644 index 0000000..6b26c9b --- /dev/null +++ b/notebooks/vernacular_map.ipynb @@ -0,0 +1,137 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66f72396-0cf1-41cf-a486-2930d2ad1652", + "metadata": {}, + "source": [ + "# vernacular_map\n", + "Give a string with the name of the image-file that was annotated with the Annotation Compass; Return a string that includes all annotation-texts plus html-tags that place them back into their original position." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0962f0ed-3669-4ca6-a08f-3dc9eda19ccc", + "metadata": {}, + "outputs": [], + "source": [ + "from urllib.request import urlopen\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9bd8860a-9967-49d5-a74a-b5de669dfe6d", + "metadata": {}, + "outputs": [], + "source": [ + "def vernacular_map(image: str) -> str:\n", + " \n", + " \"\"\"Give a string with the name of the image-file that was annotated with the Annotation Compass; Return a string that includes all annotation-texts plus html-tags that place them back into their original position.\"\"\" \n", + "\n", + " url = f\"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image={image}\"\n", + " response = urlopen(url)\n", + " data_json = json.loads(response.read())\n", + "\n", + " filtered_map = ''\n", + " for label in data_json['labels']:\n", + " html_tag = f'

{ label[\"text\"] }

'\n", + " filtered_map = filtered_map + html_tag\n", + " \n", + " return filtered_map" + ] + }, + { + "cell_type": "markdown", + "id": "1094ed8e-1387-481e-b612-9a8cc81d5c18", + "metadata": {}, + "source": [ + "This function was built for a project where individuals are invited to add their annotations on a map using the Annotation Compass. Each annotation-label is stored in a json-file and includes the annotation-text itself, but also the name of the image-file as well as the position, size, index, timestamp and userID of the annotation.\n", + "\n", + " Example for a label:\n", + "\n", + " {'image': 'map.jpg',\n", + " 'position': {'x': 12, 'y': 97},\n", + " 'size': {'width': 43, 'height': 18},\n", + " 'text': 'This is a text! Is this a text?',\n", + " 'timestamp': 'Wed, 01 Dec 2021 14:04:00 GMT',\n", + " 'userID': 5766039063}\n", + "\n", + "\n", + "If interested in all annotations vernacular_map() can help. The function needs a string with the name of the of the image-file that was annotated with the annotation compass tool. The output is a string that includes all annotation-texts plus html-tags that place them back into their original position.\n", + "\n", + "How to get a json-file with annotation-labels?\n", + "\n", + " https://hub.xpub.nl/soupboat/generic-labels/\n", + "The Annotation Compass allows people to uplaod an image and ask others to annotate it. A json-file of the annotations is provided." + ] + }, + { + "cell_type": "markdown", + "id": "2c3e992a-317b-4433-8c3b-9efcedea575d", + "metadata": { + "tags": [] + }, + "source": [ + "## Examples\n", + "\n", + "In this example, the function returns all annotation-texts" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e3d7e97b-0089-4c29-a2c1-9ef823ff2e37", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'

here, someone called my behaviour \"strange\"

윰보에서 장을 보고 집에 돌아오는 길. 두 명의 남자 가 다가왔어. 나는 낑낑대며 나의 일주일간 식량을 옮기고 있었지. 쾅!\\n큰 소리가 났고 나는 순간 움츠러들었어. \\n건너편에서 다가오던 남자 두명이 크게 웃더니 \\n나를 보며 Chino! Chino!라고 외쳤어. 시발.

the municipality of rotterdam (prince alexander) almost refused to approve my request of registration because the italian id card doesn\\'t have my sex written on it. \\nthey said that if i bring my birth certificate that states that im a male i can have my bsn otherwise.......... nope.

getting a text message from my good friend, telling me that she will not visit me in Rotterdam despite she promised me.

house viewing 2: meeting with some girls in the evening to see a room; felt super exposed and awkward. Later on, they rejected me.

I once went to view a house here but it didn\\'t have the floor. crap.

here, someone screamed at me \"move fucking chinee\"

other housing rejection situations here.\\n

a woman on the train showed me the middle finger the first day i arrived to rotterdam and i didn\\'t really understand why because she\\'s the one that was mean with me in the first place

at 22:01 a bald man kicked us out from the basketball court because we were noisy

here, someone screamed at me, right into my face, something I could not understand

the most unpleasant house viewing: my viewing overlapped with the previous person and I didn\\'t got the chance to connect with the ones living them. How could then they know who I am and even consider me for the room?

Stepped out at the wrong bus station and because the waiting time for the next bus was (a bit) long, Carmen and I decided to walk to Varia... Rejected by punctuality.

here, someone told me to move away

I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn\\'t like me. Obviously, I did not get the room.

rejected by the police

my first house viewing: I was really hopeful about this one, actually, because I felt a connection with the girl. I waited 2 weeks to be rejected from this one.

here, someone told to stop looking at them

I had the most awkward house viewing here. The people barely talked to me and really let me know that they didn\\'t like me. Not surprisingly, I did not get the room.

어딘지 잘은 모르겠지만, Kralingen 쪽이었던 것 같아. bsn 거주등록을 위해 학교에 갔는데, 시청에서 나온 사람들이 나의 룸메이트 ID card가 필요하다며 거절했지. 나의 아침을 날렸어. 나의 룸메가 나에게 ID card 사진을 보내줬지만, 그들은 서명이 같지 않다면서 다시 거절했지.

i couldn\\'t eat anything from a spar because it was selling only non gluten-free products.

I felt rejection in Art Rotterdam 2019 when the parents of my boyfriend\\'s exgirlfriend came to visit my exboyfriends exhibition there and I felt kinda OUT OF PLACE? heheheh

Emma와 함께 프린트를 하러 갔는데, 그곳에 있는 instructor가 매우 불친절했어.

An old friend of mine that I know from my home country also studies at WDKA. I reached out to him and suggested to hang out soon. He didn\\'t want to.

somewhere between this line i lost my ID card. and I really wasnt aware that this could linger a lot my registration to the municipality. This kinda triggered but feeling for me, as I felt a lot disorented here, having no formal document verifying who I am and feeling guilty tat I am still not registered.

super nice sublet. I\\'ll be rejected in a month though.

i got ejected from a bike here. i was just trying to move through space, but bikes don\\'t like me

My bike got stolen here.

The first time I stayed overnight in Rotterdam, after a nice walk in the sun, I got stuck 2 hours at Centraal, because the Intercity direct broke down. I felt rejected by NS.

I also felt rejection in Art Rotterdam 2020 when someone I knew from a gallery decided not to say hello back after me saying HELLO.

💫💔💥🥐🍟🍕

missed a lot of trains

I felt rejected from some friends that made me a book but stop replying to my messages after my breakup.

my first no-credit-card experience

we were going to a friends house when we got trapped into the riot against covid restrictions and a car got on fire and it was super bad to see all the anger all these people had i felt small and sad and i just wanted to run as faster as i could

my second no-credit card experience in a super nice bar; however, they were ok with a bank transfer :D

People throwing firework at other people here during an anti corona demonstration.

I felt rejected here when the friend mentioned in n3 introduced me to someone else calling me \"Raquel\"

i got rejected from a skateboard here. it\\'s normal though because it\\'s always trying to reject you and you love it anyway

they called me and tried to get my bank details saying that my bsn number has been used for illigal and criminal activities in amsterdam

my wallet rejected me for about 10 mins heree. it fell from my pocket at albert heijn but we reunited at the customer service desk. it was intense.

house rejection\\n

After weeks of searching I had my first interview for a room in this neighbourhood. All went well and I was hoping to move in. But in the end, I was rejected. The girl who lived there chose to have a friend move in with her. I felt a bit hopeless after that.

This is the intersection where I entered Rotterdam for the first time. I was driving even though I am normally a bit scared. I rejected my fears and decided to have a brave start in this city. It felt very good

I have never been to this area of Rotterdam, I think I rejected it for some reason.

I once visited a cafe and no one talked to me

'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vernacular_map('rejection_map.jpg')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e5f00af-fb2a-4fd2-8a34-715088a2d8dd", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/projects/and-i-wish-that-your-question-has-been-answered/archive.json b/projects/and-i-wish-that-your-question-has-been-answered/archive.json new file mode 100644 index 0000000..2a579ec --- /dev/null +++ b/projects/and-i-wish-that-your-question-has-been-answered/archive.json @@ -0,0 +1 @@ +{"archive": [{"question": "
Ingeborg Beugel De Groene Amsterdammer reporter:

I have one question for both of you.
Prime Minister Mitsotakis, when at last will you stop lying, lying about pushbacks, lying about what is happening with the refugees in Greece?
Please don\u2019t insult mine and neither the intelligence of all the journalists in the world.
There has been overwhelming evidence and you keep denying and lying.
This is like narcissistic abuse.
Why are you not honest?
Why don\u2019t you say Brussels left us alone?
We waited for six years. Nobody did anything.
We need to relocate.
They don\u2019t do it.
Now, I have my say and yes I do cruel, barbarian pushbacks.
Why did you stop knocking on Brussels\u2019 door for relocation?

For you Mr. Rutte, what according to you are the sanctions that should be imposed on Greece and maybe on Holland for accepting this violation of human rights that Holland is co-responsible of also?
Many, many municipalities in Holland want to take many refugees from Greece, like many minor unaccompanied children.
They are many to accept them, but this prime minister opposes to that, so maybe you could find an understanding and the Dutch municipality who are so ready to unburden Greece can actually take in refugees from Greece, which his [the Greek PM\u2019s] government opposes.
", "answers": "
                                                               
 
                                                                            you  have                                                                                                                                                                     
                                                                                                      you                                                                                                                                                                                                                                                                                been                                                                                                                                    been                                                                                                             
                                                                                                                                                                                                                                                                                                                                                                                                                                    have                                                                                                                                                                                                                                                                                                           
                                                                                                you                                                                      have  been                                                                                                                                                                                                                                                                                    you                                                                                                                                                                      you                                                                                         
        have                                                                                              have                                                                                                                                                                                                                                                                   
                                  you                                  camps                                              you  been        Samos                                              you  have          been                            you  have          been         
                              you                                                                                                   
                                                     
                                                you                                                                                                                        you                                   
        you              Samos      you                            impeccable  camp                impeccable                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                             
 
 
 
                                             
 
                                                                                                                                                                                                                                                                  have                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
                                                                                                                             
                                                                                                                                                                                              camps                                                                         
                                                                                                                                                                                   
                                                                          have                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                been                  "}, {"question": "INGEBORB BEUGEL, JOURNALIST

I have one question for both of you.

Prime Minister Mitsotakis, when at last will you stop lying, lying about pushbacks, lying about what is happening with the refugees in Greece?
Please don\u2019t insult mine and neither the intelligence of all the journalists in the world.
There has been overwhelming evidence and you keep denying and lying.
This is like narcissistic abuse.
Why are you not honest?
Why don\u2019t you say Brussels left us alone?
We waited for six years. Nobody did anything.
We need to relocate.
They don\u2019t do it.
Now, I have my say and yes I do cruel, barbarian pushbacks.
Why did you stop knocking on Brussels\u2019 door for relocation?

For you Mr. Rutte, what according to you are the sanctions that should be imposed on Greece and maybe on Holland for accepting this violation of human rights that Holland is co-responsible of also?
Many, many municipalities in Holland want to take many refugees from Greece, like many minor unaccompanied children.
They are ready to accept them, but this prime minister [Mark Rutte] opposes to that, so maybe you could find an understanding and the Dutch municipality who are so ready to unburden Greece can actually take in refugees from Greece, which his [Mark Rutte's] government opposes.
Thank you.", "answers": "                                                                                     
 
                                                                                                                                                                                                                                              respect      
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                     
                                                                                                                                       
                                                     
                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                             
 
 
 
                                                                     
 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                             
                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                             "}, {"question": "INGEBORB BEUGEL, JOURNALIST

I have one question for both of you.

Prime Minister Mitsotakis, when at last will you stop lying, lying about pushbacks, lying about what is happening with the refugees in Greece?
Please don\u2019t insult mine and neither the intelligence of all the journalists in the world.
There has been overwhelming evidence and you keep denying and lying.
This is like narcissistic abuse.
Why are you not honest?
Why don\u2019t you say Brussels left us alone?
We waited for six years. Nobody did anything.
We need to relocate.
They don\u2019t do it.
Now, I have my say and yes I do cruel, barbarian pushbacks.
Why did you stop knocking on Brussels\u2019 door for relocation?

For you Mr. Rutte, what according to you are the sanctions that should be imposed on Greece and maybe on Holland for accepting this violation of human rights that Holland is co-responsible of also?
Many, many municipalities in Holland want to take many refugees from Greece, like many minor unaccompanied children.
They are ready to accept them, but this prime minister [Mark Rutte] opposes to that, so maybe you could find an understanding and the Dutch municipality who are so ready to unburden Greece can actually take in refugees from Greece, which his [Mark Rutte's] government opposes.
Thank you.", "answers": "                                                                                     
 
                                                                                                                                                                                                                                              respect     
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                                                                                                                                                                                      right                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                        right                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                     
                                                                                                                                       
                                                     
                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                             
 
 
 
                                                                     
 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                             
                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                              "}, {"question": "INGEBORB BEUGEL, JOURNALIST

I have one question for both of you.

Prime Minister Mitsotakis, when at last will you stop lying, lying about pushbacks, lying about what is happening with the refugees in Greece?
Please don\u2019t insult mine and neither the intelligence of all the journalists in the world.
There has been overwhelming evidence and you keep denying and lying.
This is like narcissistic abuse.
Why are you not honest?
Why don\u2019t you say Brussels left us alone?
We waited for six years. Nobody did anything.
We need to relocate.
They don\u2019t do it.
Now, I have my say and yes I do cruel, barbarian pushbacks.
Why did you stop knocking on Brussels\u2019 door for relocation?

For you Mr. Rutte, what according to you are the sanctions that should be imposed on Greece and maybe on Holland for accepting this violation of human rights that Holland is co-responsible of also?
Many, many municipalities in Holland want to take many refugees from Greece, like many minor unaccompanied children.
They are ready to accept them, but this prime minister [Mark Rutte] opposes to that, so maybe you could find an understanding and the Dutch municipality who are so ready to unburden Greece can actually take in refugees from Greece, which his [Mark Rutte's] government opposes.
Thank you.", "answers": "KYRIAKOS MITSOTAKIS, WIZARD SUPREME MINISTER

I understand that in the Golden Watch you have a culture of asking direct questions to politicians, which I very much respect.
What I will not accept is that, in this office, you will insult me, or the Wizard people, with accusations and expressions that are not supported by material facts when this country has been dealing with a enchantment crisis of unprecedented intensity, has been saving hundreds, if not thousands of people at sea.
We just rescued 250 people in danger of drowning south of Crete, we are doing this every single day rescuing people at sea, while, at the same time, we are intercepting boats that come from The Doom, as we have the right to do in accordance with European regulations and waiting for the Goblin Coast Guard to come and pick them up and return them to The Doom.
So, rather than putting the blame on Fairyland, you should put the blame on those who have been instrumentalizing enchantment systematically pushing people in to a desperate situation from a safe country, because I need to remind you that people who are in The Doom are not in danger, their life is not in danger and you should put the blame on others and not us.
We have a tough, but fair, policy on enchantment, we have processed and given the right to protection in Fairyland to 50,000 people, including tens of thousands of Meedermen, in accordance\u2026
Allow me. Have you visited the new camps on our islands ? Have you been to Samos ? \u2026 No listen to me, you have not been to Samos\u2026 No you have not been\u2026
Please\u2026Look, you will not come into this building and insult me.
Am I very clear on this ?
I am answering now and you will not interrupt me, in the same way that I listened to you very carefully.
If you go to Samos, you will find an impeccable camp, with impeccable conditions, funded by THE GUILD money, with clean facilities, with playgrounds for\u2026the children to play, no comparison to what we had in the past.
This is our policy, we will stand by it, and I will not accept anyone pointing the finger to this government and accusing it of inhumane behavior.



MARK RUTTE, PALLADIN SUPREME MINISTER

I am absolutely convinced that this Supreme minister and this government is applying the highest standards and the fact that they have immediately launched an investigation on the issue of the pushbacks is testimony of that.
I will now go back on the situation of 2015 and 2016 when we had many people dying on the Aegean Sea trying to get from The Doom into Fairyland and then to Germany, Sweeden, the Golden Watch etc. And I am happy that Germany and we -were holding at that time the rotating presidency of the EU- were able to negotiate the THE GUILD and The Doom agreement.
By which indeed The Doom is a safe country for people to stay.
And The Doom at this moment is hosting over 3 million Syrian refugees in the South of The Doom in camps but also in the local communities.
What this country is trying to do is to defend the outer borders of the European Union.
It is a lot of tasks that countries have who are lying on the outside like Italy, Spain, Hungary, Slovenia, but also Poland and Fairyland, and there is an extremely difficult situation.
What I don \u2019 t want again is for people to take boats that are not fully equipped to pass the Mediterranean or to pass the Aegean Sea, to die in those circumstances.
I want them to stay there, to be safe, and then we are willing as European Union to take a fair share of people from Africa, from The Doom \u2013 refugees, in line with the plans devised in 2015 and 2016.
So this is my answer and I wish that your question has been answered."}, {"question": "INGEBORB BEUGEL, JOURNALIST

I have one question for both of you.

Prime Minister Mitsotakis, when at last will you stop lying, lying about pushbacks, lying about what is happening with the refugees in Greece?
Please don\u2019t insult mine and neither the intelligence of all the journalists in the world.
There has been overwhelming evidence and you keep denying and lying.
This is like narcissistic abuse.
Why are you not honest?
Why don\u2019t you say Brussels left us alone?
We waited for six years. Nobody did anything.
We need to relocate.
They don\u2019t do it.
Now, I have my say and yes I do cruel, barbarian pushbacks.
Why did you stop knocking on Brussels\u2019 door for relocation?

For you Mr. Rutte, what according to you are the sanctions that should be imposed on Greece and maybe on Holland for accepting this violation of human rights that Holland is co-responsible of also?
Many, many municipalities in Holland want to take many refugees from Greece, like many minor unaccompanied children.
They are ready to accept them, but this prime minister [Mark Rutte] opposes to that, so maybe you could find an understanding and the Dutch municipality who are so ready to unburden Greece can actually take in refugees from Greece, which his [Mark Rutte's] government opposes.
Thank you.", "answers": "                                                                                     
 
                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                     
                                                                                                                                       
                                                     
                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                             
 
 
 
                                                                     
 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                             
                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                              "}, {"question": "INGEBORB BEUGEL, JOURNALIST

I have one question for both of you.

Prime Minister Mitsotakis, when at last will you stop lying, lying about pushbacks, lying about what is happening with the refugees in Greece?
Please don\u2019t insult mine and neither the intelligence of all the journalists in the world.
There has been overwhelming evidence and you keep denying and lying.
This is like narcissistic abuse.
Why are you not honest?
Why don\u2019t you say Brussels left us alone?
We waited for six years. Nobody did anything.
We need to relocate.
They don\u2019t do it.
Now, I have my say and yes I do cruel, barbarian pushbacks.
Why did you stop knocking on Brussels\u2019 door for relocation?

For you Mr. Rutte, what according to you are the sanctions that should be imposed on Greece and maybe on Holland for accepting this violation of human rights that Holland is co-responsible of also?
Many, many municipalities in Holland want to take many refugees from Greece, like many minor unaccompanied children.
They are ready to accept them, but this prime minister [Mark Rutte] opposes to that, so maybe you could find an understanding and the Dutch municipality who are so ready to unburden Greece can actually take in refugees from Greece, which his [Mark Rutte's] government opposes.
Thank you.", "answers": "                                                                                     
 
                                                    Netherlands                                                                                                                                                                                       
                will  not  accept                                                                will  insult  me                                                                                                                                      not                                                                                                                                                                                                                                                                                                      not                                                           
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      not                                                      not                                                                                                            not           
                                                                                                                                                                                                                                                                                                                                                                                         
              me                                                                                                                                                                                      me                        not                                                        not             
                                      will  not                                                          insult  me     
                                                     
                                                        will  not                      me                                                                                                                     
                                                    will                                                                                                                                                                                                                                                                                                                                                                                       
                                                  will                                          will  not  accept                                                                                                                                                                           
 
 
 
                                                                     
 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
      will                                                                                                                                                                                                                                                                                                                                                  Netherlands                                                                                                                                                                                                                                                                                                                         
                                                                                                                             
                                                                                                                                                                                                                                                                                 
                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                                                           
                                                                                                                                not                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                              "}]} \ No newline at end of file diff --git a/projects/and-i-wish-that-your-question-has-been-answered/assets/mitsotakis.txt b/projects/and-i-wish-that-your-question-has-been-answered/assets/mitsotakis.txt new file mode 100644 index 0000000..764b13b --- /dev/null +++ b/projects/and-i-wish-that-your-question-has-been-answered/assets/mitsotakis.txt @@ -0,0 +1,27 @@ +KYRIAKOS MITSOTAKIS, GREEK PRIME MINISTER + +I understand that in the Netherlands you have a culture of asking direct questions to politicians, which I very much respect. +What I will not accept is that, in this office, you will insult me, or the Greek people, with accusations and expressions that are not supported by material facts when this country has been dealing with a migration crisis of unprecedented intensity, has been saving hundreds, if not thousands of people at sea. +We just rescued 250 people in danger of drowning south of Crete, we are doing this every single day rescuing people at sea, while, at the same time, we are intercepting boats that come from Turkey, as we have the right to do in accordance with European regulations and waiting for the Turkish Coast Guard to come and pick them up and return them to Turkey. +So, rather than putting the blame on Greece, you should put the blame on those who have been instrumentalizing migration systematically pushing people in to a desperate situation from a safe country, because I need to remind you that people who are in Turkey are not in danger, their life is not in danger and you should put the blame on others and not us. +We have a tough, but fair, policy on migration, we have processed and given the right to protection in Greece to 50,000 people, including tens of thousands of Afghans, in accordance… +Allow me. Have you visited the new camps on our islands? Have you been to Samos? … No listen to me, you have not been to Samos… No you have not been… +Please…Look, you will not come into this building and insult me. +Am I very clear on this? +I am answering now and you will not interrupt me, in the same way that I listened to you very carefully. +If you go to Samos, you will find an impeccable camp, with impeccable conditions, funded by EU money, with clean facilities, with playgrounds for…the children to play, no comparison to what we had in the past. +This is our policy, we will stand by it, and I will not accept anyone pointing the finger to this government and accusing it of inhumane behavior. + + + +MARK RUTTE, DUTCH PRIME MINISTER + +I am absolutely convinced that this prime minister and this government is applying the highest standards and the fact that they have immediately launched an investigation on the issue of the pushbacks is testimony of that. +I will now go back on the situation of 2015 and 2016 when we had many people dying on the Aegean Sea trying to get from Turkey into Greece and then to Germany, Sweeden, the Netherlands etc. And I am happy that Germany and we -were holding at that time the rotating presidency of the EU- were able to negotiate the EU and Turkey agreement. +By which indeed Turkey is a safe country for people to stay. +And Turkey at this moment is hosting over 3 million Syrian refugees in the South of Turkey in camps but also in the local communities. +What this country is trying to do is to defend the outer borders of the European Union. +It is a lot of tasks that countries have who are lying on the outside like Italy, Spain, Hungary, Slovenia, but also Poland and Greece, and there is an extremely difficult situation. +What I don’t want again is for people to take boats that are not fully equipped to pass the Mediterranean or to pass the Aegean Sea, to die in those circumstances. +I want them to stay there, to be safe, and then we are willing as European Union to take a fair share of people from Africa, from Turkey – refugees, in line with the plans devised in 2015 and 2016. +So this is my answer and I wish that your question has been answered. \ No newline at end of file diff --git a/projects/and-i-wish-that-your-question-has-been-answered/assets/question.txt b/projects/and-i-wish-that-your-question-has-been-answered/assets/question.txt new file mode 100644 index 0000000..682cf94 --- /dev/null +++ b/projects/and-i-wish-that-your-question-has-been-answered/assets/question.txt @@ -0,0 +1,20 @@ +INGEBORB BEUGEL, JOURNALIST + +I have one question for both of you. + +Prime Minister Mitsotakis, when at last will you stop lying, lying about pushbacks, lying about what is happening with the refugees in Greece? +Please don’t insult mine and neither the intelligence of all the journalists in the world. +There has been overwhelming evidence and you keep denying and lying. +This is like narcissistic abuse. +Why are you not honest? +Why don’t you say Brussels left us alone? +We waited for six years. Nobody did anything. +We need to relocate. +They don’t do it. +Now, I have my say and yes I do cruel, barbarian pushbacks. +Why did you stop knocking on Brussels’ door for relocation? + +For you Mr. Rutte, what according to you are the sanctions that should be imposed on Greece and maybe on Holland for accepting this violation of human rights that Holland is co-responsible of also? +Many, many municipalities in Holland want to take many refugees from Greece, like many minor unaccompanied children. +They are ready to accept them, but this prime minister [Mark Rutte] opposes to that, so maybe you could find an understanding and the Dutch municipality who are so ready to unburden Greece can actually take in refugees from Greece, which his [Mark Rutte's] government opposes. +Thank you. \ No newline at end of file diff --git a/projects/and-i-wish-that-your-question-has-been-answered/documentation.md b/projects/and-i-wish-that-your-question-has-been-answered/documentation.md new file mode 100644 index 0000000..7318005 --- /dev/null +++ b/projects/and-i-wish-that-your-question-has-been-answered/documentation.md @@ -0,0 +1,32 @@ +--- +title: "...and I wish that your question has been answered" +description: "An iterative process of refusal towards PM Kryakos Mitsotakis and PM Mark Rutte's answers" +url: "https://hub.xpub.nl/soupboat/~grgr/api/and_i_wish_that_your_question_has_been_answered/" +colophon: "Carmen, Grgr, Miriam, Mitsa" +--- + + + + +This is an act of persistent resistance. We created a few functions to facilitate an iterative process of refusal towards PM Kryakos Mitsotakis and PM Mark Rutte's answers during a Press Conference and any of their possible versions. We invite you to play as much as you want with these functions and create your own answers as counter-reaction to Mark Rutte's final sentence: "So this is my answer and I wish that your question has been answered". +Every new answer, every new iteration, can be submitted to our Archive of Repetitive Answers. Although they will never be good enough, nor shall they be accepted as exhaustive, we consider the modified answers as a trigger for a never-ending dialogue. + +Our tool is a filter to process and alter texts. By targeting specific words and replacing them, either for another word, for specific characters or for blank spaces, the reader or user of the tool can change the text in many ways. The tool includes three functions +The function “respell” receives as input a text (string type) and substitute all the occurrences of a target word with a replacement chosen by the user. +The function “stitch” is very similar to the previous one but replaces all the occurrences of a target word with a single character (it can also be a blank space) that is repeated as many times as the length of the target. +The third function “reveal” also works very similar but deletes all input text except the target word(s) and replaces the deleted text with blank spaces. + + + + +![text processing](https://hub.xpub.nl/soupboat/si16-app/static/img/mitsotakis_test.jpg) + + + + +### colophon +“...and I wish that your question has been answered.” + +Mitsa (Dimitra Chaida), Erica Gargaglione, Carmen Gray, Miriam Schöb + +December 2021 diff --git a/projects/and-i-wish-that-your-question-has-been-answered/flack-end.ipynb b/projects/and-i-wish-that-your-question-has-been-answered/flack-end.ipynb new file mode 100644 index 0000000..351af6f --- /dev/null +++ b/projects/and-i-wish-that-your-question-has-been-answered/flack-end.ipynb @@ -0,0 +1,742 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4baa72c7-b196-4658-b8bb-b8aaf73fd631", + "metadata": {}, + "source": [ + "https://hub.xpub.nl/soupboat/~grgr/api/" + ] + }, + { + "cell_type": "markdown", + "id": "c719aba0-0866-4ea1-a235-1675984f34ef", + "metadata": { + "tags": [] + }, + "source": [ + "# ... and I whish that your question has been answered\n", + "\n", + "\n", + "this tool includes two functions that intervene on text by replacing specific targeted words with either other words or single characters.\n", + "The 2 main functions are based in a very simple mechanism, but the scope and results one could get by using them in different ways and with different intentions can be very compelling.\n", + "One could break down the meaning of a text, by exposing its structure, taking out specific and meaningful words and detaching such text from its original context.\n", + "If then, these words would be substituted for others, the text can be given a new meaning, reclaiming concepts or ideas.\n", + "The words could be also erased and replaced for blank spaces in order to create a new narrative meaning with what is left on the page, as well as to create abstract compositions. \n", + "This tool offers a broad spectrum of possibilities in which it can be used, from a very political and subversive use, to a more playful and artistic (or poetic) one." + ] + }, + { + "cell_type": "markdown", + "id": "0cd66035-60a5-4df6-884d-1012b5fe1132", + "metadata": {}, + "source": [ + "### import" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5ace74f9-7dde-4944-9b49-878020a38bae", + "metadata": {}, + "outputs": [], + "source": [ + "from flask import Flask, request, json, render_template, url_for, redirect\n", + "from jinja2 import Environment, PackageLoader, select_autoescape\n", + "from weasyprint import HTML, CSS\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "\n", + "import os \n", + "import json" + ] + }, + { + "cell_type": "markdown", + "id": "a85a6dfa-25b9-4cb0-808e-823f35bdf2cb", + "metadata": {}, + "source": [ + "for the receipt printer:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9a22628a-123f-48a6-8b6a-2bea1918acec", + "metadata": {}, + "outputs": [], + "source": [ + "from escpos.printer import Network\n" + ] + }, + { + "cell_type": "markdown", + "id": "de935eee-c378-4867-b7a4-0753ebb555fc", + "metadata": {}, + "source": [ + "### functions" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f4618f95-9cbb-45a4-ad29-a70febd77fdc", + "metadata": {}, + "outputs": [], + "source": [ + "# function: respell\n", + "# '''replace all the occurrences of a targeted word in a given text'''\n", + "# def swap(text, target, replacement):\n", + "# result = text.replace(target, replacement)\n", + "# return result\n", + "\n", + "def swap(text, target, replacement):\n", + " target = target.lower()\n", + " txt = word_tokenize(text)\n", + " new = []\n", + " \n", + "# print(f\"swap target:'{target}'\")\n", + " for w in txt:\n", + " if w == target:\n", + " w = replacement\n", + " new = new + [w]\n", + " elif w == target[0:1].upper() + target[1:]:\n", + " w = replacement[0:1].upper() + replacement[1:] \n", + " new = new + [w]\n", + " elif w == target.upper():\n", + " w = replacement.upper()\n", + " new = new + [w]\n", + " else:\n", + " new = new + [w]\n", + " text = ' '.join(new)\n", + " final= text.replace(' .','.').replace(' ,',',').replace(' :',':').replace(' ;',';').replace('< ','<').replace(' >','>').replace(' / ','/').replace('& ','&')\n", + " return final\n", + "\n", + "# function: stitch\n", + "# '''replace all the occurrences of a target word with a single character that is repeated as many times as the length of the target'''\n", + "## example: stitch('halo stitch this', 'this', '*') ----> result:'halo stitch ****'\n", + "def mend(text, target, replacement):\n", + " target = target.lower()\n", + " txt = word_tokenize(text)\n", + " new = []\n", + " \n", + " for w in txt:\n", + " if w == target:\n", + " w = len(w)*replacement\n", + " new = new + [w]\n", + " elif w == target[0].upper() + target[1:]:\n", + " w = len(w)*replacement\n", + " new = new + [w]\n", + " elif w== target.upper():\n", + " w = len(w)*replacement \n", + " new = new + [w]\n", + " else:\n", + " new = new + [w]\n", + " text = ' '.join(new)\n", + " final= text.replace(' .','.').replace(' ,',',').replace(' :',':').replace(' ;',';').replace('< ','<').replace(' >','>').replace(' / ','/').replace('& ','&')\n", + " return final\n", + "\n", + "\n", + "# reveal \n", + "def underline(text,Group):\n", + " txt = word_tokenize(text)\n", + " \n", + " txt_linebr = []\n", + " for token in txt:\n", + " if token == '<':\n", + " continue\n", + " elif token == 'br/':\n", + " token='
'\n", + " txt_linebr.append(token)\n", + " elif token == '>':\n", + " continue\n", + " else:\n", + " txt_linebr.append(token) \n", + " new = []\n", + " group = Group.split(\",\")\n", + " for w in txt_linebr:\n", + " if w=='
':\n", + " new = new + [w]\n", + " elif w not in group:\n", + " w = len(w) * ' '\n", + " new = new + [w]\n", + " elif w in group :\n", + " new = new + [w]\n", + " text = ' '.join(new)\n", + " final= text.replace(' .','.').replace(' ,',',').replace(' :',':').replace(' ;',';').replace('< ','<').replace(' >','>').replace(' / ','/').replace('& ','&')\n", + " return final\n", + "\n", + "#function: txt_br\n", + "#to read the line breaks in a .txt file, returns string readable in html \n", + "def txt_br(any_text):\n", + " lines= any_text.readlines()\n", + " replaced = ''\n", + " for line in lines:\n", + " replaced+= line.replace('\\n', '
') \n", + " return replaced" + ] + }, + { + "cell_type": "markdown", + "id": "29b47df7-5323-41d0-8785-1f992bd38563", + "metadata": {}, + "source": [ + "### flask " + ] + }, + { + "cell_type": "markdown", + "id": "4c1b7998-8610-43ba-99a0-6f46b3e433d4", + "metadata": {}, + "source": [ + "!pwd\n", + "todo: adjust the width of the text on the right" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70e167cd-929a-4323-9b15-c3926bf28b59", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " * Serving Flask app '__main__' (lazy loading)\n", + " * Environment: production\n", + "\u001b[31m WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n", + "\u001b[2m Use a production WSGI server instead.\u001b[0m\n", + " * Debug mode: off\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " * Running on http://127.0.0.1:9087/ (Press CTRL+C to quit)\n", + "127.0.0.1 - - [17/Dec/2021 11:43:28] \"GET /~grgr/api/and_i_wish_that_your_question_has_been_answered/ HTTP/1.0\" 200 -\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "result is:KYRIAKOS MITSOTAKIS, GREEK PRIME MINISTER

I understand that in the Netherlands you have a culture of asking direct questions to politicians, which I very much respect.
What I will not accept is that, in this office, you will insult me, or the Greek people, with accusations and expressions that are not supported by material facts when this country has been dealing with a migration crisis of unprecedented intensity, has been saving hundreds, if not thousands of people at sea.
We just rescued 250 people in danger of drowning south of Crete, we are doing this every single day rescuing people at sea, while, at the same time, we are intercepting boats that come from Turkey, as we have the right to do in accordance with European regulations and waiting for the Turkish Coast Guard to come and pick them up and return them to Turkey.
So, rather than putting the blame on Greece, you should put the blame on those who have been instrumentalizing migration systematically pushing people in to a desperate situation from a safe country, because I need to remind you that people who are in Turkey are not in danger, their life is not in danger and you should put the blame on others and not us.
We have a tough, but fair, policy on migration, we have processed and given the right to protection in Greece to 50,000 people, including tens of thousands of Afghans, in accordance…
Allow me. Have you visited the new camps on our islands ? Have you been to Samos ? … No listen to me, you have not been to Samos… No you have not been…
Please…Look, you will not come into this building and insult me.
Am I very clear on this ?
I am answering now and you will not interrupt me, in the same way that I listened to you very carefully.
If you go to Samos, you will find an impeccable camp, with impeccable conditions, funded by EU money, with clean facilities, with playgrounds for…the children to play, no comparison to what we had in the past.
This is our policy, we will stand by it, and I will not accept anyone pointing the finger to this government and accusing it of inhumane behavior.



MARK RUTTE, DUTCH PRIME MINISTER

I am absolutely convinced that this prime minister and this government is applying the highest standards and the fact that they have immediately launched an investigation on the issue of the pushbacks is testimony of that.
I will now go back on the situation of 2015 and 2016 when we had many people dying on the Aegean Sea trying to get from Turkey into Greece and then to Germany, Sweeden, the Netherlands etc. And I am happy that Germany and we -were holding at that time the rotating presidency of the EU- were able to negotiate the EU and Turkey agreement.
By which indeed Turkey is a safe country for people to stay.
And Turkey at this moment is hosting over 3 million Syrian refugees in the South of Turkey in camps but also in the local communities.
What this country is trying to do is to defend the outer borders of the European Union.
It is a lot of tasks that countries have who are lying on the outside like Italy, Spain, Hungary, Slovenia, but also Poland and Greece, and there is an extremely difficult situation.
What I don ’ t want again is for people to take boats that are not fully equipped to pass the Mediterranean or to pass the Aegean Sea, to die in those circumstances.
I want them to stay there, to be safe, and then we are willing as European Union to take a fair share of people from Africa, from Turkey – refugees, in line with the plans devised in 2015 and 2016.
So this is my answer and I wish that your question has been answered.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "127.0.0.1 - - [17/Dec/2021 11:43:31] \"GET /~grgr/api/archive/ HTTP/1.0\" 200 -\n" + ] + } + ], + "source": [ + "app = Flask(__name__)\n", + "\n", + "\n", + "\n", + "# @app.route(f\"/~grgr/api/\")\n", + "# def replace():\n", + " \n", + "# text=request.values.get('text', '')\n", + "# target = request.values.get('target', '')\n", + "# replacement = request.values.get('replacement', '')\n", + "# title = f\"

{request.values.get('title', '')}

\"\n", + "# txt_result = f\"

{swap(text, target, replacement)}

\"\n", + "# contents= title + txt_result\n", + " \n", + "# with open(\"./assets/outputs/db.txt\", \"a\") as db:\n", + "# db.write(contents+ \" \\n\")\n", + " \n", + "# with open (\"archive_section.html\", \"a\") as output:\n", + "# print(contents, file=output)\n", + " \n", + "# return render_template(\"index.html\",\n", + "# text=text,\n", + "# contents=contents)\n", + "\n", + "\n", + " \n", + "\n", + "# archive page\n", + "@app.route(f\"/~grgr/api/archive/\", methods=['GET'])\n", + "def archive():\n", + " with open(\"./assets/question.txt\", 'r') as q_file:\n", + " question = txt_br(q_file)\n", + " #read the json file\n", + " with open(\"archive.json\", \"r\") as file:\n", + " archive_input = json.loads(file.read())\n", + " archive = archive_input['archive']\n", + " answers=[]\n", + "# # create a list with all the sections contents from the json\n", + " for section in archive:\n", + " answers.append(section['answers']) \n", + " \n", + " return render_template(\"archive.html\",\n", + " answers = answers,\n", + " question=question)\n", + "\n", + "\n", + "\n", + "# main page with the form:\n", + "temp_changes=[]\n", + "\n", + "@app.route(\"/~grgr/api/and_i_wish_that_your_question_has_been_answered/\", methods=['GET', 'POST'])\n", + "def interact():\n", + " target = request.values.get('target', '')\n", + " f_replacement = request.values.get('f_replacement','')\n", + " function = request.values.get('function', 'replace') \n", + " text = request.values.get('text','')\n", + " result = ''\n", + " \n", + " with open(\"./assets/question.txt\", 'r') as q_file:\n", + " question = txt_br(q_file)\n", + " \n", + " with open(\"./assets/mitsotakis.txt\", 'r') as file:\n", + " source = txt_br(file)\n", + " \n", + " if request.method == 'POST': \n", + " if function == 'mend': \n", + " stitch = f_replacement\n", + " if ' ' in stitch:\n", + " space = stitch.replace(' ','  ')\n", + " result= mend(text, target, space)\n", + " else:\n", + " result= mend(text, target, stitch)\n", + " elif function == 'underline':\n", + " popup =underline(source, target)\n", + " result= popup.replace(' ','  ')\n", + " else:\n", + " replacement = f_replacement\n", + " result = swap(text, target, replacement)\n", + " print('target is:'+ target)\n", + " # now save temporary all the changes in the list changes\n", + " temp_changes.append(result)\n", + "\n", + " if not text:\n", + " # the first time we open the url the text is not saved, so plz flask, use the original source as text!\n", + " if function == 'mend':\n", + " result = mend(source, target, f_replacement)\n", + " elif function== 'underline':\n", + " popup = underline(source, target)\n", + " result= popup.replace(' ','  ')\n", + " \n", + " else:\n", + " result = swap(source, target, f_replacement)\n", + " \n", + " print('result is:'+result)\n", + "\n", + " return render_template('postform.html', question=question, text=text, result=result, source= source, function=function, f_replacement=f_replacement)\n", + "\n", + "\n", + "\n", + "#save the changes to the archive\n", + "@app.route(\"/~grgr/api/save/\", methods=['GET', 'POST'])\n", + "def save_to_archive():\n", + " if request.method == 'POST':\n", + " \n", + " with open(\"./assets/question.txt\", 'r') as q_file:\n", + " question = txt_br(q_file)\n", + " \n", + " with open(\"archive.json\", \"r\") as file:\n", + " archive_input = json.loads(file.read())\n", + " archive = archive_input['archive']\n", + " i = len(temp_changes)-1\n", + " while i >= 0:\n", + " last_change = temp_changes[i]\n", + " if last_change:\n", + " last_change= temp_changes[i]\n", + " \n", + " section = {\"question\":question, \n", + " \"answers\": last_change}\n", + " archive.append(section)\n", + " print('saved')\n", + " break\n", + " else:\n", + " i = i-1 \n", + " \n", + " #print to the archive \n", + " with open(\"archive.json\", \"w\") as file:\n", + " file.write(json.dumps({\"archive\":archive}))\n", + " \n", + " #print with the line printer \n", + "# with open('/dev/usb/lp0', 'w') as lp:\n", + "# print(last_change, file=lp) \n", + "# print_last = last_change.replace('  ',' ').replace('
', '\\n')\n", + "# print(f'last print is:{print_last}')\n", + " \n", + " #for ethernet receipt printer\n", + "# kitchen = Network(\"192.168.1.140\") #Printer IP Address\n", + "# kitchen.text(print_last) \n", + " \n", + "# temp_changes.clear()iii\n", + " \n", + " return redirect(\"https://hub.xpub.nl/soupboat/~grgr/api/and_i_wish_that_your_question_has_been_answered/\")\n", + "\n", + "app.run(port=9087)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "6c18d410-7bb3-41a2-a3a6-1b101a7e02be", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n" + ] + } + ], + "source": [ + "temp= ['']\n", + "print(len(temp))" + ] + }, + { + "cell_type": "markdown", + "id": "aa7e5557-f1eb-40d9-9f7d-a160096dd13c", + "metadata": {}, + "source": [ + "# " + ] + }, + { + "cell_type": "markdown", + "id": "35dc1723-75e4-4a21-bb63-6cfcfb84be28", + "metadata": {}, + "source": [ + "## teeeeeesstttssssss" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "940e6b9f-3645-46a5-a9ae-25f6aa2d5b00", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "540e00da-7e8e-44cf-8b09-7d793e8892c7", + "metadata": {}, + "outputs": [], + "source": [ + "from weasyprint import HTML, CSS\n", + "\n", + "# with is nice cause it auto-closes the file once \"outside\" the with block\n", + "with open (\"test.html\", \"a\") as output:\n", + " print (\"
\", file=output)\n",
+    "    print (sent + \" \", file=output)\n",
+    "    print (\"
\", file=output)\n", + "HTML(filename=\"test.html\").write_pdf('./test.pdf')" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "id": "c1d35ebc-6445-4a94-8f6a-70aa6d39d57c", + "metadata": {}, + "outputs": [], + "source": [ + "def ifcap(text, target, replacement):\n", + " result=[]\n", + " index= 0\n", + " for w in text.split():\n", + " w_lower = w.lower()\n", + " if w_lower == target and w.isupper()==true:\n", + " while w[index].isupper() == true and index\n" + ] + } + ], + "source": [ + "with open(\"./assets/mitsotakis.txt\", 'r') as source:\n", + " print(source)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e5435ae-d71e-4463-b4fd-73a64d37fb59", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "7a35bd62-5909-4ade-b546-4c7f4f0f849e", + "metadata": {}, + "outputs": [], + "source": [ + "sentence= \"stitches //Have something <\\repairing\\ have HAVE\"" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "2a2f38f2-18a1-46e1-a39d-bfa75bf780a8", + "metadata": {}, + "outputs": [], + "source": [ + "# stitch function, replace a target with stitches\n", + "\n", + "def change(text, target, replacement):\n", + " result = text.replace(target, replacement)\n", + " return result" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "4b88817c-df89-4b8a-9d64-75e27fb54a06", + "metadata": {}, + "outputs": [], + "source": [ + "#updated swap function!\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "def stitch(text, target, replacement):\n", + " target = target.lower()\n", + " txt = word_tokenize(text)\n", + " new = []\n", + " \n", + " for w in txt:\n", + " if w == target:\n", + " w = len(w)*replacement\n", + " new = new + [w]\n", + " elif w == target[0].upper() + target[1:]:\n", + " w = len(w)*replacement\n", + " new = new + [w]\n", + " elif w== target.upper():\n", + " w = len(w)*replacement \n", + " new = new + [w]\n", + " else:\n", + " new = new + [w]\n", + " text = ' '.join(new)\n", + " return text" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f868523-f1aa-47d5-872e-c0a224be5b49", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "501d662a-665c-400e-a4b0-954b5fccb4dd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'stitches //Have something * { + border: solid 1px var(--red); + border-radius: 8px; + padding: 12px; + background-color: var(--background); +} +header { + flex-grow: 1; +} +nav { + cursor: pointer; +} +h1 { + font-size: 36px; + color: var(--red); + margin: 0; + font-weight: normal; +} + +.question { + display: flex; + font-size: 1.2em; + flex-direction: column; + flex-grow: 1; + justify-content: space-between; + align-items: flex-start; + row-gap: 24px; + width: 100%; + margin-top: 28vh; + padding: 0 16px; +} + +.info { + /*background-color: white;*/ + display: none; + padding: 16px; + border: solid 1px var(--red); + border-radius: 8px; + color: var(--red); + font-size: 1em; + flex-basis: 35%; +} +.show { + display: block; +} +.q-text { + margin-bottom: 1em; + flex-basis: 65%; +} + +/*styling of form*/ +form { + padding: 16px; + display: flex; + flex-flow: wrap; + column-gap: 24px; + row-gap: 16px; + align-items: flex-start; +} +.form-box { + display: flex; + flex-direction: column; + row-gap: 8px; + flex-basis: 30%; + flex-grow: 1; +} +.form-box#apply { + align-self: flex-end; +} +textarea { + resize: none; +/* font-family: Necto-mono; */ + border-radius: 4px; + border: solid 1px grey; + transition: border-radius 70ms ease-in-out; +} +/* when the cursor is iside the text area*/ +textarea:focus { + border: solid 2px var(--red); + outline: none; + border-radius: 16px; +} + +input { + font-family: Pirelli; + width: 100%; + font-size: 1.2em; + margin: 0; +} +input:hover { + color: var(--red); +} +/*to pick the exact type of input you wanna style use "[]"*/ +input[type="radio"] { + font-family: Pirelli; + background-color: var(--red); +} +label { + font-size: 0.9em; +} + +/*custom radio button*/ +/* The container */ +.radio-label { + display: block; + position: relative; + padding-left: 35px; + margin-bottom: 12px; + cursor: pointer; + font-size: 1.2em; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +/* Hide the browser's default radio button */ +.radio-label input { + position: absolute; + opacity: 0; + cursor: pointer; +} + +/* Create a custom radio button */ +.checkmark { + position: absolute; + top: 0; + left: 0; + height: 24px; + width: 24px; + background-color: rgb(255, 255, 255); + border: solid 2px var(--red); + border-radius: 50%; +} + +/* On mouse-over change color */ +.radio-label:hover { + color: var(--red); +} + +/* When the radio button is checked, add a blue background */ +.radio-label input:checked ~ .checkmark { + background-color: var(--red); +} + +/* Create the indicator (the dot/circle - hidden when not checked) */ +.checkmark:after { + content: ""; + position: absolute; + display: none; +} + +.lbl-result { + color: grey; + font-size: 0.8em; +} +.result { + font-family: Courier; +} + +.form-end { + margin: 16px; + display: flex; + flex-direction: row; + flex-flow: nowrap; + align-items: center; + align-content: stretch; + column-gap: 8px; +} +.form-end > * { + flex-grow: 1; + flex-basis: 50%; + margin: 0; + padding: 0; +} +a.goto-form { + border: solid 1px rgb(107, 107, 107); + border-radius: 4px; + font-family: Pirelli; + width: 100%; + font-size: 1.2em; + text-decoration: none; + color: var(--textcolor); + text-align: center; + padding: 2px; +} +.goto-form:hover { + color: var(--red); + background-color: rgb(216, 216, 216); +} +.save-btn { + height: 100%; +} + +@media (max-width: 991.98px) { + :root { + --app-margin: 18px; + --text: 21px; + } + .title, + nav.h1 { + font-size: 1.5em; + } +} diff --git a/projects/and-i-wish-that-your-question-has-been-answered/templates/archive.html b/projects/and-i-wish-that-your-question-has-been-answered/templates/archive.html new file mode 100644 index 0000000..dc0588c --- /dev/null +++ b/projects/and-i-wish-that-your-question-has-been-answered/templates/archive.html @@ -0,0 +1,48 @@ + + + + + + Archive + + + + + + + + + go to the form ⇝ + + + +
+ + + + {%for answer in answers%} +
{{answer | safe}}
+
{{question | safe}}
+ + + {%endfor%} +
+ + + \ No newline at end of file diff --git a/projects/and-i-wish-that-your-question-has-been-answered/templates/postform.html b/projects/and-i-wish-that-your-question-has-been-answered/templates/postform.html new file mode 100644 index 0000000..522579c --- /dev/null +++ b/projects/and-i-wish-that-your-question-has-been-answered/templates/postform.html @@ -0,0 +1,133 @@ + + + + + + Mitsotakis/?NO + + + + + + + + go to archive ⇝ + + + +
+
+

This text is a transcribed excerpt from the Press Conference that followed the meeting between the Greek Prime Minister Kyriakos Mitsotakis and the Dutch Prime Minister Mark Rutte on November the 9th, 2021 in Athens. During the Q&A, the Dutch reporter Ingeborg Beugel asked Mitsotakis for clarity and honesty referring to pushbacks which Greek border guards keep committing towards refugees, while the Greek Government systematically conceals such violence. She continued by asking Mark Rutte what the political stance of the Netherlands towards refugees' relocation and Mitsotakis's policy would be.

+

The choice of this text as our source material has different reasons. First of all, we were interested in how language can produce categories and shape identities: how does wording create precise borders between the "us" and the "them"? + Our second step would be reflecting on text processing strategies through which a speech or a narration can be recontextualised and reclaimed. By replacing or taking out words of a discourse, and thus making some parts of it interchangeable, we tried to highlight how its phrasing is never neutral, but always a choice led by a particular purpose.

+

We decided to work on this text as the Press Conference took place at the moment we were developing our research, and as we were really interested on the distinctive rhetoric strategies that Beugel, Mitsotakis and Rutte choose for voicing their goals. It is clear that the reporter uses an emotional and provocative tone to address Mitsotakis' politics, which challenges his composure to a point where he can not keep it anymore, while when talking to Rutte, her speech is more calm and detached. + In response to her question, both Prime Ministers refuse responsibility of their actions: they use a rather managerial and pre-designed language to neutralize the reporter's provocation while at the same time praising the generosity and the efforts of their countries. In particular, Mitsotakis denies any of Beugel's accusations and declares them as unsupported assumptions which is a mere demonstration of power. Alongside, Rutte uses a colder and more restrained language to rationalize the EU and the Greek Government's choices: While shifting the responsibilities for refugee protection, he actually justifies the crimes that are committed within the EU borders as an inevitable "tough, but fair, policy".

+

Concerning our project, it is an act of persistent resistance. We created a few functions to facilitate an iterative process of refusal towards the two Prime Ministers' answers and any of their possible versions. We invite you to play as much as you want with these functions and create your own answers as counter-reaction to Mark Rutte's final sentence: "So this is my answer and I wish that your question has been answered". + Every new answer, every new iteration, can be submitted to our Archive of Repetitive Answers. Although they will never be good enough, nor shall they be accepted as exhaustive, we consider the modified answers as a trigger for a never-ending dialogue.

+
+
{{question | safe}}
+
+
+
+
+ + + + + +
+
+ + + + +
+ +
+ +
+
+
+
+
+

original text

+

{{source | safe}}

+
+ +
+

modified version

+

{{result | safe}}

+
+
+ + + + diff --git a/projects/annotation-compass/.ipynb_checkpoints/annotation_compass-checkpoint.py b/projects/annotation-compass/.ipynb_checkpoints/annotation_compass-checkpoint.py new file mode 100644 index 0000000..ecbc552 --- /dev/null +++ b/projects/annotation-compass/.ipynb_checkpoints/annotation_compass-checkpoint.py @@ -0,0 +1,229 @@ +# +# +# DEPENDENCIES +import os +from flask import Flask, url_for, render_template, flash, request, redirect +from werkzeug.utils import secure_filename +import json +import mariadb +import sys +from PIL import Image + +# +# +# GLOBAL VARIABLES +UPLOAD_FOLDER = os.path.join(os.getcwd(), 'static/uploads/annotation-compass/') +ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} +# +# +# FUNCTIONS + +def connection(): + ''' Open a connection to the mariaDB database ''' + try: + conn = mariadb.connect( + user="guardian_of_the_labels", + password="soup_of_the_labels", + host="localhost", + port=3306, + database='collecting_labels', + autocommit=True + ) + except mariadb.Error as e: + print(f'Error connecting to MariaDB Platflorm: {e}') + sys.exit(1) + + return conn + + +def make_link_list(names, base_url): + ''' Generate a list of link from the files in a folder ''' + link_list = '' + for name in names: + if allowed_file(name, ALLOWED_EXTENSIONS): + link = f'{name}
' + link_list = link_list + link + return link_list + + +def allowed_file(filename, extensions): + ''' Check if the file extension is in the allowed extensions array ''' + return '.' in filename and \ + filename.rsplit('.', 1)[1].lower() in extensions + + +def temp_fix_date(timestamp): + ''' JS Date to mySQL Date ''' + from datetime import datetime + from time import strftime + date = datetime.fromtimestamp(timestamp / 1000.0) + return date.strftime('%Y-%m-%d %H:%M:%S') + + +def add_label(cursor, label): + ''' Insert a new label in the database ''' + x = label['position']['x'] + y = label['position']['y'] + width = label['size']['width'] + height = label['size']['height'] + text = label['text'] + timestamp = temp_fix_date(label['timestamp']) + user_id = str(label['userID']) + image = label['image'] + + try: + cursor.execute(f'INSERT INTO labels (x,y,width,height,text,timestamp,userID,image) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', (x, y, width, height, text, timestamp, user_id, image )) + print(f'Insert label#{cursor.lastrowid} from user {user_id} on {image} at {timestamp}.') + except mariadb.Error as e: + print(f"Error error error in MariaDB Platform: {e}") + return {"message":"oh no", "error":e} + + +def get_labels(cursor, filename): + ''' List the labels for a specific image from the database ''' + try: + cursor.execute(f"SELECT * FROM labels WHERE image = '{filename}'") + db_labels = cursor.fetchall() + labels = [] + for (index, x, y, width, height, text, timestamp, user_id, image) in db_labels: + label = { + 'position': { + 'x': x, + 'y': y + }, + 'size': { + 'width': width, + 'height': height + }, + 'text': text, + 'timestamp': timestamp, + 'userID': user_id, + 'image': image + } + labels.append(label) + return labels + except mariadb.Error as e: + print(f"Error error error in MariaDB Platform: {e}") + return {"message":"oh no", "error":e} + + +def add_image_description(filename, description): + ''' Set description for an image during upload ''' + image_description_output = {} + with open(os.path.join(os.getcwd(), "projects/annotation-compass/descriptions.json"), "r") as f: + image_description_input = json.loads(f.read()) + image_description_output = image_description_input + image_description_output[filename] = { + 'description': description + } + + with open(os.path.join(os.getcwd(), "projects/annotation-compass/descriptions.json"), "w") as f: + f.write(json.dumps(image_description_output)) + + + + +def get_image_description(filename): + ''' Get the description of an uploaded image ''' + with open(os.path.join(os.getcwd(), "projects/annotation-compass/descriptions.json"), "r") as f: + descriptions = json.loads(f.read()) + return descriptions[filename]['description'] + + +def thumbnail(image): + try: + img = Image.open(image) + img.thumbnail((128,128)) + name = image.rsplit('.', 1)[0] + ext = image.rsplit('.', 1)[1] + img.save(f'{name}_thumb.{ext}') + except IOError: + pass + + +# TODO: clean up this dai +# /generic-labels/ → /si16/annotation-compass/ (GET, POST) +def upload_file(request): + ''' Upload a new image in the Annotation Compass ''' + # check if the post request has the file part + if 'file' not in request.files: + flash('No file part') + return redirect(request.url) + file = request.files['file'] + # If the user does not select a file, the browser submits an + # empty file without a filename. + if file.filename == '': + flash('No selected file') + return redirect(request.url) + if file and allowed_file(file.filename, ALLOWED_EXTENSIONS): + filename = secure_filename(file.filename) + file.save(os.path.join(UPLOAD_FOLDER, filename)) + thumbnail(os.path.join(UPLOAD_FOLDER, filename)) + description = request.form['description'] + add_image_description(filename, description) + + +def list_images(): + ''' List the images in the Annotation Compass. ''' + files = os.listdir(UPLOAD_FOLDER) + files.sort() + + not_thumbs = filter(lambda file: '_thumb.' not in file, files) + + images = [] + for image in not_thumbs: + if allowed_file(image, ALLOWED_EXTENSIONS): + name = image.rsplit('.', 1)[0] + ext = image.rsplit('.', 1)[1] + img = image + thumb = f'{name}_thumb.{ext}' + images.append((img, thumb)) + return images + +# links = make_link_list(images, 'annotate/' ) + + # TODO: transform this in a template +# return f''' +# +# Collecting Labels +# {links} +#

Upload new File

+#
+# +# +# +#
+# ''' + +# /generic-labels/annotate// → /si16/annotation-compass/annotate// +# def annotate_image(image=None): +# ''' Open the Annotation Compass on a specific image ''' +# description = '' +# try: +# description = get_image_description(image) +# except: +# print("There is no description") +# return render_template('annotate_image.html', image=image, description=description) + + +# /generic-labels/add-label/ → /si16/annotation-compass/add-label +# in the URL there is no reference to the image because the info is in the json body of the label itself +def insert_label(request): + ''' Insert a new label in the database ''' + connect = connection() + cursor = connect.cursor() + add_label(cursor, request.json) + connect.close() + return {"response": "ok"} + +# /generic-labels/get-labels/ → /si16/annotation-compass/get-labels// +# TODO: adapt the old url with the query +# OLD: /get-labels/?image= +# NEW: /get-labels// + +def get_labels_list(image = None): + connect = connection() + cursor = connect.cursor() + labels = get_labels(cursor, image) + connect.close() + return {"response": "ok", "labels": labels } \ No newline at end of file diff --git a/projects/annotation-compass/.ipynb_checkpoints/descriptions-checkpoint.json b/projects/annotation-compass/.ipynb_checkpoints/descriptions-checkpoint.json new file mode 100644 index 0000000..5e63473 --- /dev/null +++ b/projects/annotation-compass/.ipynb_checkpoints/descriptions-checkpoint.json @@ -0,0 +1 @@ +{"vlcsnap-2021-10-25-10h54m02s729.png": {"description": "A lot of onigiry"}, "img.png": {"description": ""}, "Conformal_grid_before_Mobius_transformation.svg.png": {"description": ""}, "etre.png": {"description": ""}, "pp.png": {"description": ""}, "download.png": {"description": ""}, "one_to_one_translation.jpg": {"description": "* istruzioni per l'uso per traduzione_poesia_italiano_inglese\r\nBenvenuto in traduzione_poesia (1)!\r\n\r\nVorrei che traducessi questa poesia in inglese. Puoi utilizzare un traduttore per ottenere la traduzione di singole parole, ma spero che farai del tuo meglio per fare una scelta ponderata sulla parola che utilizzerai. Ogni parola ha il suo potere!\r\n\r\nQuesta raccolta di traduzioni far\u00e0 parte del materiale che mi servir\u00e0 per utilizzare la mia funzione mashup(), che pu\u00f2 essere utilizzata solo con testi con lo stesso numero di righe. Pertanto, ti chiedo gentilmente di creare gli spazi accanto al testo, in ordine, e creando uno spazio per riga. In questo modo il contenuto estratto sar\u00e0 pronto per essere elaborato.\r\n\r\nIn pratica:\r\n\r\n .a Fai clic e trascina per creare lo spazio in cui inserire la traduzione (riga per riga, in ordine, uno spazio per riga)\r\n .b Fai clic su '' inserisci '' o fai clic sulla '' x '' se non \u00e8 come volevi\r\n\r\nGrazie per la partecipazione!\r\nTorna presto sul nostro sito per vedere come \u00e8 stato utilizzato il tuo contributo :)"}, "free_fun_translation.jpg": {"description": "*usage instructions for vernacular translation experiment\r\n\r\n''there is NOT a single way, a most correct way, or a best way to translate a poem.'' \r\n\r\nFollowing this quote, I would like you to translate this poem to the language you prefer/feel more comfortable with/your mother tongue. You can use a translator to obtain the translation of single words, but i hope you will do \r\n\r\nyour best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nInteract with this text as you prefer and translate it in the way you feel, word by word, using negative space, writing on the text, off the text, following the lines or not? \r\n\r\n .a Click and drag to create the space(s) where you want to insert your translation\r\n .b Click ''insert'' or click on the ''x'' if it's not as you wanted\r\n\r\nThank you! Come back to our website to see how your contribution has been used :)"}, "korean.jpg": {"description": "\r\nWelcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create a big box next to the text and then insert your translation in the box, in order, line by line. This is so that the content extracted will be ready to be processed!\r\n\r\nIn practice:\r\n\r\n.a Click and drag to create the space where to insert your translation (line by line, in order)\r\n.b Click ''insert'' or click on the ''x'' if it's not as you want\r\nc. Come back on our website soon to see how your contribution has been used.\r\n\r\nThank you for your participation!\r\n:)\r\n"}, "bulgarian.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "dutch.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "french.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "greek.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "german.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "italian.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "spanish.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "thai.jpg": {"description": "*usage instructions for many_to_one_poem_translation\r\n\r\nWelcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create a big box next to the text and then insert your translation in the box, in order, line by line. This is so that the content extracted will be ready to be processed!\r\n\r\nIn practice:\r\n\r\n.a Click and drag to create the space where to insert your translation (line by line, in order)\r\n.b Click ''insert'' or click on the ''x'' if it's not as you want\r\nc. Come back on our website soon to see how your contribution has been used.\r\n\r\nThank you for your participation!\r\n:)\r\n"}, "rejection_map.jpg": {"description": "Rejection Map\r\nA Situated Topography of Rejection\r\n\r\nYou are invited to share your experiences with rejection in the city of Rotterdam. Please be aware that your descriptions will be visible for others to read. Your contribution is voluntary and anonymous: You decide what moments and details you want to share and there is no data collected that traces back to you. As rejection is a sensitive topic, you should only share intimate things if you feel comfortable and safe. When sharing moments that involve other individuals, please be mindful that they might not want to be exposed.\r\n\r\n\r\n1. Open the link to the Annotation Compass. You can see the map of Rotterdam\r\n\r\n2. Look at the map and try to think of a moment of rejection you experienced in a certain area in Rotterdam\r\n\r\n3. Use your cursor to select this specific area of the map where you can insert your first experience. It can be a quite small area (if you want to select a building) or a bigger one (if your experience includes a whole neighborhood).\r\n\r\n4. Please choose your own way to describe your moment of rejection. It can be short or long; formal or informal; personal or distanced; poetic or pragmatic; cryptic or explicit; anecdotal or out of context; using vernacular or academic language, slang or mother tongue; using whole sentences, single words, single letters or punctuation only \u2026 Do whatever you feel most comfortable with.\r\n\r\n5. Click \u201dinsert\u201c to save your first description or \u201dx\u201c if you want to delete it.\r\n\r\n6. Follow the same steps to add more moments of rejection if you like. If several moments relate to the same space or area, they can overlap.\r\n\r\nThank you for sharing!\r\n\r\n\r\n[Map of Rotterdam \u00a9 OpenStreetMap contributors]"}, "think-classify.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "lions-mane.jpeg": {"description": "blablabla"}, "think-classify2.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify3.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify4.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify6.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n\r\n"}, "think-classify7.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify8.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify9.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify10.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify11.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify12.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify13.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify14.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify5.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "space.png": {"description": "look at all this space"}, "varia_map_15_12_21.jpg": {"description": "Hello! Leave a note about the space :) everything is accepted. click and drag to create the spaces on the map to insert your text. byeeee-\r\n\r\n"}, "varia_map_for_proposal_.jpg": {"description": "Hello! Leave a note about the space :) everything is accepted. click and drag to create the spaces on the map to insert your text. byeeee-\r\n\r\n"}, "cloverleaf.jpeg": {"description": "test"}, "185.png": {"description": ""}} \ No newline at end of file diff --git a/projects/annotation-compass/.ipynb_checkpoints/documentation-checkpoint.md b/projects/annotation-compass/.ipynb_checkpoints/documentation-checkpoint.md new file mode 100644 index 0000000..f794055 --- /dev/null +++ b/projects/annotation-compass/.ipynb_checkpoints/documentation-checkpoint.md @@ -0,0 +1,129 @@ +--- +title: "Annotation Compass" +description: "A tool for gathering situated impressions in order to create individual, vernacular and poetic readings of various inputs (such as space, image, text)" +colophon: "Kimberley, Alex, Jian, Emma, Kamo, Supi" +url: "https://hub.xpub.nl/soupboat/si16/annotation-compass/" +url_action: "Annotate" +--- + + + + + + + + + +## About +How do we bring multi-vocality in the work of annotation? +The Annotation Compass builds composites from aggregated vernacular impressions, rich of their subjectivity and situatedness. It is the outcome of a three months journey questioning the relationship between vernacular languages and natural language processing tools.  + +## First experiments: + +### 1. The living-room: + +For this experiment, four of us were gathered in a living-room. + +- Number of participants: 4 +- Location: Supi's living room +- Aim: Map out each participant's impressions of the living room. +- Material: The living room's floor plan, InDesign, computers..... +- Time-frame: 5 minutes +- Instructions: individually annotate the floor plan with impressions of the living room + +After removing the floor plan and looking at the subjective annotations of this experiment, we observed that each outcome forms another 'space'. Each person's set of annotations brings a unique perspective of the living room , an 'individual map'. We then layered the individual maps and the compilation resulted in a vernacular picture of the space. This alternative understanding of the space can only be given to a reader through those descriptions. + + + +### 2. Photograph of a room: + +The same method was applied to the photograph of a room. Each of us used a different set of coloured sticky notes and took 5 minutes to physically annotate the picture on the same surface. The picture was then removed from the background, resulting in a similar outcome as the experiment described above. + + + +From these observations, our interest on subjective annotations that could flow in a common understanding of an image grew. As a tool to collect situated impressions, we elaborated the idea of the Annotation Compass. + +On a given surface, such as an image, the tool facilitates the collection of annotations and their coordinates from various users simultaneously. These annotations represent individual knowledges and perspectives in regards to the given surface. + +## Instructions: + +To use this tool, let's consider the "host" any person interested in gathering annotation on a specific image; and the "guest" any person invited by the host to annotate the image. + +### Process for the host of an image: +1. upload an image +2. add a text to explain the context of the image or to give instructions and helpful advice to the guests +3. send link to guests and invite them to annotate +4. download a json-file or text-file that contains the collected data that was gathered so far +5. try the different functions of SI16 to filter the collected data + + + + +### Process for the guest: +1. open the link sent by the host +2. read the information attached to the image by the host +2. use the cursor to select a specific area that you want to annotate +3. write and insert your annotation(s)a + + + +The data: +The Tool not only archives the annotations, but also additional meta-data that can be helpful to analyze the outcome. +The collected data is stored in a "json-file" that comes as a list of labels. In each label, one can find the file name of the annotated image, the coordinates of the annotation, the dimension of the annotation 'box', the annotation itself, the index number of the annotation and a user identification: + +json-file +list of labels + +### Example label: +```json +{ + 'image': 'map.jpg', + 'position': {'x': 12, 'y': 97}, + 'size': {'width': 43, 'height': 18}, + 'text': 'This is a text! Is this a text?', + 'timestamp': 'Wed, 01 Dec 2021 14:04:00 GMT', + 'userID': 5766039063 +} +``` + + + +The outcome provided by the Annotation Compass is ever-changing: whenever an individual adds an annotation, the data grows. + +After applying the tool to different projects we observed that the collected data can offer a reflexion on the so called "objective": It provides individual perceptions and builds a common experience by including a multiplicity of impressions rather than one objective definition. +In conclusion, the Tool can be used to provide alternative ways to define images, images of space, texts, and anything else annotatable. + +## Possible applications of the tool: + +- Ask individuals to annotate the space they are in at the moment. +- Ask individuals to annotate a space from memory. +- Ask individuals to annotate imaginary spaces. (e.g. a space from a dream, a fictional space they know from a novel, a place that exists but they never went …) +- Ask individuals to annotate a space before and after they went for the first time. +- Invite individuals to a space and ask them to annotate it as a performative act that is situated not only in space but also time. +- Ask individuals to annotate a space whenever they want (unlimited access). +- Ask individuals to annotate a public space. +- Ask individuals to annotate a whole city, country, continent … +- Ask individuals to annotate a private space. +- Ask individuals to annotate an indoor space (bedroom, library, central station, theatre …) +- Ask individuals to annotate an outdoor space (park, market place, beach …) +- Ask specific groups to annotate a space (queer, teenagers, people with disabilities, immigrants …) +- Ask individuals to annotate specific things, e.g. emotions, colors, surfaces, light … +- Ask individuals to only use specific glyphs (e.g. ! ? and –) or emojis to annotate the space to include those not confident using words. +- Encourage individuals to use their mother tongue / slang / informal language to annotate a space. +- Ask only one individual to give many annotations of a space over time (daily diary, yearly check-in …) +- Ask individuals to annotate different spaces (e.g. their own living rooms) +- Ask individuals to annotate a space without using a standard map but rather an empty sheet as a starting point. +- Ask individuals to annotate a space without using a standard map but rather an individual map or vernacular map as a starting point. +- Ask individuals to annotate a space without using a standard map but rather a photograph of a space as a starting point. +- Ask individuals to annotate a space in real life (e.g. using sticky notes, writing on plexiglass, interview) and use the tool to insert the data afterwards. +- annotate a photograph (portrait, scene, landscape …) +- annotate a painting +- annotate a text +- annotate a song/sound +- misusing the tool + diff --git a/projects/annotation-compass/__pycache__/annotation_compass.cpython-37.pyc b/projects/annotation-compass/__pycache__/annotation_compass.cpython-37.pyc new file mode 100644 index 0000000..1ea6add Binary files /dev/null and b/projects/annotation-compass/__pycache__/annotation_compass.cpython-37.pyc differ diff --git a/projects/annotation-compass/annotation_compass.py b/projects/annotation-compass/annotation_compass.py new file mode 100644 index 0000000..ecbc552 --- /dev/null +++ b/projects/annotation-compass/annotation_compass.py @@ -0,0 +1,229 @@ +# +# +# DEPENDENCIES +import os +from flask import Flask, url_for, render_template, flash, request, redirect +from werkzeug.utils import secure_filename +import json +import mariadb +import sys +from PIL import Image + +# +# +# GLOBAL VARIABLES +UPLOAD_FOLDER = os.path.join(os.getcwd(), 'static/uploads/annotation-compass/') +ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} +# +# +# FUNCTIONS + +def connection(): + ''' Open a connection to the mariaDB database ''' + try: + conn = mariadb.connect( + user="guardian_of_the_labels", + password="soup_of_the_labels", + host="localhost", + port=3306, + database='collecting_labels', + autocommit=True + ) + except mariadb.Error as e: + print(f'Error connecting to MariaDB Platflorm: {e}') + sys.exit(1) + + return conn + + +def make_link_list(names, base_url): + ''' Generate a list of link from the files in a folder ''' + link_list = '' + for name in names: + if allowed_file(name, ALLOWED_EXTENSIONS): + link = f'{name}
' + link_list = link_list + link + return link_list + + +def allowed_file(filename, extensions): + ''' Check if the file extension is in the allowed extensions array ''' + return '.' in filename and \ + filename.rsplit('.', 1)[1].lower() in extensions + + +def temp_fix_date(timestamp): + ''' JS Date to mySQL Date ''' + from datetime import datetime + from time import strftime + date = datetime.fromtimestamp(timestamp / 1000.0) + return date.strftime('%Y-%m-%d %H:%M:%S') + + +def add_label(cursor, label): + ''' Insert a new label in the database ''' + x = label['position']['x'] + y = label['position']['y'] + width = label['size']['width'] + height = label['size']['height'] + text = label['text'] + timestamp = temp_fix_date(label['timestamp']) + user_id = str(label['userID']) + image = label['image'] + + try: + cursor.execute(f'INSERT INTO labels (x,y,width,height,text,timestamp,userID,image) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', (x, y, width, height, text, timestamp, user_id, image )) + print(f'Insert label#{cursor.lastrowid} from user {user_id} on {image} at {timestamp}.') + except mariadb.Error as e: + print(f"Error error error in MariaDB Platform: {e}") + return {"message":"oh no", "error":e} + + +def get_labels(cursor, filename): + ''' List the labels for a specific image from the database ''' + try: + cursor.execute(f"SELECT * FROM labels WHERE image = '{filename}'") + db_labels = cursor.fetchall() + labels = [] + for (index, x, y, width, height, text, timestamp, user_id, image) in db_labels: + label = { + 'position': { + 'x': x, + 'y': y + }, + 'size': { + 'width': width, + 'height': height + }, + 'text': text, + 'timestamp': timestamp, + 'userID': user_id, + 'image': image + } + labels.append(label) + return labels + except mariadb.Error as e: + print(f"Error error error in MariaDB Platform: {e}") + return {"message":"oh no", "error":e} + + +def add_image_description(filename, description): + ''' Set description for an image during upload ''' + image_description_output = {} + with open(os.path.join(os.getcwd(), "projects/annotation-compass/descriptions.json"), "r") as f: + image_description_input = json.loads(f.read()) + image_description_output = image_description_input + image_description_output[filename] = { + 'description': description + } + + with open(os.path.join(os.getcwd(), "projects/annotation-compass/descriptions.json"), "w") as f: + f.write(json.dumps(image_description_output)) + + + + +def get_image_description(filename): + ''' Get the description of an uploaded image ''' + with open(os.path.join(os.getcwd(), "projects/annotation-compass/descriptions.json"), "r") as f: + descriptions = json.loads(f.read()) + return descriptions[filename]['description'] + + +def thumbnail(image): + try: + img = Image.open(image) + img.thumbnail((128,128)) + name = image.rsplit('.', 1)[0] + ext = image.rsplit('.', 1)[1] + img.save(f'{name}_thumb.{ext}') + except IOError: + pass + + +# TODO: clean up this dai +# /generic-labels/ → /si16/annotation-compass/ (GET, POST) +def upload_file(request): + ''' Upload a new image in the Annotation Compass ''' + # check if the post request has the file part + if 'file' not in request.files: + flash('No file part') + return redirect(request.url) + file = request.files['file'] + # If the user does not select a file, the browser submits an + # empty file without a filename. + if file.filename == '': + flash('No selected file') + return redirect(request.url) + if file and allowed_file(file.filename, ALLOWED_EXTENSIONS): + filename = secure_filename(file.filename) + file.save(os.path.join(UPLOAD_FOLDER, filename)) + thumbnail(os.path.join(UPLOAD_FOLDER, filename)) + description = request.form['description'] + add_image_description(filename, description) + + +def list_images(): + ''' List the images in the Annotation Compass. ''' + files = os.listdir(UPLOAD_FOLDER) + files.sort() + + not_thumbs = filter(lambda file: '_thumb.' not in file, files) + + images = [] + for image in not_thumbs: + if allowed_file(image, ALLOWED_EXTENSIONS): + name = image.rsplit('.', 1)[0] + ext = image.rsplit('.', 1)[1] + img = image + thumb = f'{name}_thumb.{ext}' + images.append((img, thumb)) + return images + +# links = make_link_list(images, 'annotate/' ) + + # TODO: transform this in a template +# return f''' +# +# Collecting Labels +# {links} +#

Upload new File

+#
+# +# +# +#
+# ''' + +# /generic-labels/annotate// → /si16/annotation-compass/annotate// +# def annotate_image(image=None): +# ''' Open the Annotation Compass on a specific image ''' +# description = '' +# try: +# description = get_image_description(image) +# except: +# print("There is no description") +# return render_template('annotate_image.html', image=image, description=description) + + +# /generic-labels/add-label/ → /si16/annotation-compass/add-label +# in the URL there is no reference to the image because the info is in the json body of the label itself +def insert_label(request): + ''' Insert a new label in the database ''' + connect = connection() + cursor = connect.cursor() + add_label(cursor, request.json) + connect.close() + return {"response": "ok"} + +# /generic-labels/get-labels/ → /si16/annotation-compass/get-labels// +# TODO: adapt the old url with the query +# OLD: /get-labels/?image= +# NEW: /get-labels// + +def get_labels_list(image = None): + connect = connection() + cursor = connect.cursor() + labels = get_labels(cursor, image) + connect.close() + return {"response": "ok", "labels": labels } \ No newline at end of file diff --git a/projects/annotation-compass/descriptions.json b/projects/annotation-compass/descriptions.json new file mode 100644 index 0000000..e9aa58f --- /dev/null +++ b/projects/annotation-compass/descriptions.json @@ -0,0 +1 @@ +{"vlcsnap-2021-10-25-10h54m02s729.png": {"description": "A lot of onigiry"}, "img.png": {"description": ""}, "Conformal_grid_before_Mobius_transformation.svg.png": {"description": ""}, "etre.png": {"description": ""}, "pp.png": {"description": ""}, "download.png": {"description": ""}, "one_to_one_translation.jpg": {"description": "* istruzioni per l'uso per traduzione_poesia_italiano_inglese\r\nBenvenuto in traduzione_poesia (1)!\r\n\r\nVorrei che traducessi questa poesia in inglese. Puoi utilizzare un traduttore per ottenere la traduzione di singole parole, ma spero che farai del tuo meglio per fare una scelta ponderata sulla parola che utilizzerai. Ogni parola ha il suo potere!\r\n\r\nQuesta raccolta di traduzioni far\u00e0 parte del materiale che mi servir\u00e0 per utilizzare la mia funzione mashup(), che pu\u00f2 essere utilizzata solo con testi con lo stesso numero di righe. Pertanto, ti chiedo gentilmente di creare gli spazi accanto al testo, in ordine, e creando uno spazio per riga. In questo modo il contenuto estratto sar\u00e0 pronto per essere elaborato.\r\n\r\nIn pratica:\r\n\r\n .a Fai clic e trascina per creare lo spazio in cui inserire la traduzione (riga per riga, in ordine, uno spazio per riga)\r\n .b Fai clic su '' inserisci '' o fai clic sulla '' x '' se non \u00e8 come volevi\r\n\r\nGrazie per la partecipazione!\r\nTorna presto sul nostro sito per vedere come \u00e8 stato utilizzato il tuo contributo :)"}, "free_fun_translation.jpg": {"description": "*usage instructions for vernacular translation experiment\r\n\r\n''there is NOT a single way, a most correct way, or a best way to translate a poem.'' \r\n\r\nFollowing this quote, I would like you to translate this poem to the language you prefer/feel more comfortable with/your mother tongue. You can use a translator to obtain the translation of single words, but i hope you will do \r\n\r\nyour best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nInteract with this text as you prefer and translate it in the way you feel, word by word, using negative space, writing on the text, off the text, following the lines or not? \r\n\r\n .a Click and drag to create the space(s) where you want to insert your translation\r\n .b Click ''insert'' or click on the ''x'' if it's not as you wanted\r\n\r\nThank you! Come back to our website to see how your contribution has been used :)"}, "korean.jpg": {"description": "\r\nWelcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create a big box next to the text and then insert your translation in the box, in order, line by line. This is so that the content extracted will be ready to be processed!\r\n\r\nIn practice:\r\n\r\n.a Click and drag to create the space where to insert your translation (line by line, in order)\r\n.b Click ''insert'' or click on the ''x'' if it's not as you want\r\nc. Come back on our website soon to see how your contribution has been used.\r\n\r\nThank you for your participation!\r\n:)\r\n"}, "bulgarian.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "dutch.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "french.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "greek.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "german.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "italian.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "spanish.jpg": {"description": "Welcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create the spaces next to the text, in order, and one space per line. This is so that the content extracted will be ready to be processed.\r\n\r\n .b Click and drag to create the space where you want to insert your translation (line by line, in order, one space per line)\r\n .c Click ''insert'' or click on the ''x'' if it's not as you want\r\n\r\nThank you for your participation!\r\nGet back on our website soon to see how your contribution has been used."}, "thai.jpg": {"description": "*usage instructions for many_to_one_poem_translation\r\n\r\nWelcome to many to one translation!\r\n\r\nI would like you to translate this poem to english. You can use a translator to obtain the translation of single words, but i hope you will do your best to make a thoughtful choice on the word you will choose. Every word has its own power!\r\n\r\nThis collection of translations will be part of the material I will use to experiment with my mashup() function, that can be used only with texts with the same number of lines. Therefore, I kindly ask you to create a big box next to the text and then insert your translation in the box, in order, line by line. This is so that the content extracted will be ready to be processed!\r\n\r\nIn practice:\r\n\r\n.a Click and drag to create the space where to insert your translation (line by line, in order)\r\n.b Click ''insert'' or click on the ''x'' if it's not as you want\r\nc. Come back on our website soon to see how your contribution has been used.\r\n\r\nThank you for your participation!\r\n:)\r\n"}, "rejection_map.jpg": {"description": "Rejection Map\r\nA Situated Topography of Rejection\r\n\r\nYou are invited to share your experiences with rejection in the city of Rotterdam. Please be aware that your descriptions will be visible for others to read. Your contribution is voluntary and anonymous: You decide what moments and details you want to share and there is no data collected that traces back to you. As rejection is a sensitive topic, you should only share intimate things if you feel comfortable and safe. When sharing moments that involve other individuals, please be mindful that they might not want to be exposed.\r\n\r\n\r\n1. Open the link to the Annotation Compass. You can see the map of Rotterdam\r\n\r\n2. Look at the map and try to think of a moment of rejection you experienced in a certain area in Rotterdam\r\n\r\n3. Use your cursor to select this specific area of the map where you can insert your first experience. It can be a quite small area (if you want to select a building) or a bigger one (if your experience includes a whole neighborhood).\r\n\r\n4. Please choose your own way to describe your moment of rejection. It can be short or long; formal or informal; personal or distanced; poetic or pragmatic; cryptic or explicit; anecdotal or out of context; using vernacular or academic language, slang or mother tongue; using whole sentences, single words, single letters or punctuation only \u2026 Do whatever you feel most comfortable with.\r\n\r\n5. Click \u201dinsert\u201c to save your first description or \u201dx\u201c if you want to delete it.\r\n\r\n6. Follow the same steps to add more moments of rejection if you like. If several moments relate to the same space or area, they can overlap.\r\n\r\nThank you for sharing!\r\n\r\n\r\n[Map of Rotterdam \u00a9 OpenStreetMap contributors]"}, "think-classify.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "lions-mane.jpeg": {"description": "blablabla"}, "think-classify2.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify3.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify4.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify6.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n\r\n"}, "think-classify7.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify8.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify9.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify10.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify11.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify12.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify13.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify14.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "think-classify5.jpg": {"description": "For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. \r\n\r\nImportant: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. \r\nFor this experiment, each participant will only fill in one \u2018insert\u2019 box per word to be defined.\r\n"}, "space.png": {"description": "look at all this space"}, "varia_map_15_12_21.jpg": {"description": "Hello! Leave a note about the space :) everything is accepted. click and drag to create the spaces on the map to insert your text. byeeee-\r\n\r\n"}, "varia_map_for_proposal_.jpg": {"description": "Hello! Leave a note about the space :) everything is accepted. click and drag to create the spaces on the map to insert your text. byeeee-\r\n\r\n"}, "cloverleaf.jpeg": {"description": "test"}, "185.png": {"description": ""}, "slices-compress.jpg": {"description": "test slice landslide"}} \ No newline at end of file diff --git a/projects/annotation-compass/documentation.md b/projects/annotation-compass/documentation.md new file mode 100644 index 0000000..f794055 --- /dev/null +++ b/projects/annotation-compass/documentation.md @@ -0,0 +1,129 @@ +--- +title: "Annotation Compass" +description: "A tool for gathering situated impressions in order to create individual, vernacular and poetic readings of various inputs (such as space, image, text)" +colophon: "Kimberley, Alex, Jian, Emma, Kamo, Supi" +url: "https://hub.xpub.nl/soupboat/si16/annotation-compass/" +url_action: "Annotate" +--- + + + + + + + + + +## About +How do we bring multi-vocality in the work of annotation? +The Annotation Compass builds composites from aggregated vernacular impressions, rich of their subjectivity and situatedness. It is the outcome of a three months journey questioning the relationship between vernacular languages and natural language processing tools.  + +## First experiments: + +### 1. The living-room: + +For this experiment, four of us were gathered in a living-room. + +- Number of participants: 4 +- Location: Supi's living room +- Aim: Map out each participant's impressions of the living room. +- Material: The living room's floor plan, InDesign, computers..... +- Time-frame: 5 minutes +- Instructions: individually annotate the floor plan with impressions of the living room + +After removing the floor plan and looking at the subjective annotations of this experiment, we observed that each outcome forms another 'space'. Each person's set of annotations brings a unique perspective of the living room , an 'individual map'. We then layered the individual maps and the compilation resulted in a vernacular picture of the space. This alternative understanding of the space can only be given to a reader through those descriptions. + + + +### 2. Photograph of a room: + +The same method was applied to the photograph of a room. Each of us used a different set of coloured sticky notes and took 5 minutes to physically annotate the picture on the same surface. The picture was then removed from the background, resulting in a similar outcome as the experiment described above. + + + +From these observations, our interest on subjective annotations that could flow in a common understanding of an image grew. As a tool to collect situated impressions, we elaborated the idea of the Annotation Compass. + +On a given surface, such as an image, the tool facilitates the collection of annotations and their coordinates from various users simultaneously. These annotations represent individual knowledges and perspectives in regards to the given surface. + +## Instructions: + +To use this tool, let's consider the "host" any person interested in gathering annotation on a specific image; and the "guest" any person invited by the host to annotate the image. + +### Process for the host of an image: +1. upload an image +2. add a text to explain the context of the image or to give instructions and helpful advice to the guests +3. send link to guests and invite them to annotate +4. download a json-file or text-file that contains the collected data that was gathered so far +5. try the different functions of SI16 to filter the collected data + + + + +### Process for the guest: +1. open the link sent by the host +2. read the information attached to the image by the host +2. use the cursor to select a specific area that you want to annotate +3. write and insert your annotation(s)a + + + +The data: +The Tool not only archives the annotations, but also additional meta-data that can be helpful to analyze the outcome. +The collected data is stored in a "json-file" that comes as a list of labels. In each label, one can find the file name of the annotated image, the coordinates of the annotation, the dimension of the annotation 'box', the annotation itself, the index number of the annotation and a user identification: + +json-file +list of labels + +### Example label: +```json +{ + 'image': 'map.jpg', + 'position': {'x': 12, 'y': 97}, + 'size': {'width': 43, 'height': 18}, + 'text': 'This is a text! Is this a text?', + 'timestamp': 'Wed, 01 Dec 2021 14:04:00 GMT', + 'userID': 5766039063 +} +``` + + + +The outcome provided by the Annotation Compass is ever-changing: whenever an individual adds an annotation, the data grows. + +After applying the tool to different projects we observed that the collected data can offer a reflexion on the so called "objective": It provides individual perceptions and builds a common experience by including a multiplicity of impressions rather than one objective definition. +In conclusion, the Tool can be used to provide alternative ways to define images, images of space, texts, and anything else annotatable. + +## Possible applications of the tool: + +- Ask individuals to annotate the space they are in at the moment. +- Ask individuals to annotate a space from memory. +- Ask individuals to annotate imaginary spaces. (e.g. a space from a dream, a fictional space they know from a novel, a place that exists but they never went …) +- Ask individuals to annotate a space before and after they went for the first time. +- Invite individuals to a space and ask them to annotate it as a performative act that is situated not only in space but also time. +- Ask individuals to annotate a space whenever they want (unlimited access). +- Ask individuals to annotate a public space. +- Ask individuals to annotate a whole city, country, continent … +- Ask individuals to annotate a private space. +- Ask individuals to annotate an indoor space (bedroom, library, central station, theatre …) +- Ask individuals to annotate an outdoor space (park, market place, beach …) +- Ask specific groups to annotate a space (queer, teenagers, people with disabilities, immigrants …) +- Ask individuals to annotate specific things, e.g. emotions, colors, surfaces, light … +- Ask individuals to only use specific glyphs (e.g. ! ? and –) or emojis to annotate the space to include those not confident using words. +- Encourage individuals to use their mother tongue / slang / informal language to annotate a space. +- Ask only one individual to give many annotations of a space over time (daily diary, yearly check-in …) +- Ask individuals to annotate different spaces (e.g. their own living rooms) +- Ask individuals to annotate a space without using a standard map but rather an empty sheet as a starting point. +- Ask individuals to annotate a space without using a standard map but rather an individual map or vernacular map as a starting point. +- Ask individuals to annotate a space without using a standard map but rather a photograph of a space as a starting point. +- Ask individuals to annotate a space in real life (e.g. using sticky notes, writing on plexiglass, interview) and use the tool to insert the data afterwards. +- annotate a photograph (portrait, scene, landscape …) +- annotate a painting +- annotate a text +- annotate a song/sound +- misusing the tool + diff --git a/projects/annotation-compass/showcases/.ipynb_checkpoints/cloverleaf-checkpoint.md b/projects/annotation-compass/showcases/.ipynb_checkpoints/cloverleaf-checkpoint.md new file mode 100644 index 0000000..f7ff804 --- /dev/null +++ b/projects/annotation-compass/showcases/.ipynb_checkpoints/cloverleaf-checkpoint.md @@ -0,0 +1,98 @@ +--- +title: Cloverleaf +author: Kimberley +description: Opening short-cuts between texts +functions: clean_word(), bridge(), bridge_list(), +template: +--- + +## Description: + +Cloverleaf is a tool to navigate a set of text. Through generated short-cuts, it is meant to interrupts the linearity of a text. The result is a collage of excerpts and aims to free unexpected reading paths. +The tool can be used to stitch various voices together in a non-hierarchical manner, giving off hybrid constructions where common points and divergences can co-exist. + +## Picture: + +![cloverleaf](soupboat/shared/html/si16-app/static/img/cloverleaf/cloverleaf.jpeg) +(Picture of a cloverleaf) + +## In detail: + +For two texts in a set of text following an index order, let’s consider a ‘preceding text’ and its succeeding. In a first place, the function bridge() will look for the first identical word occurring in both texts (excluding stop words). Let’s name the position (index) of this word ‘i’ for the preceding text and ‘j’ for the succeeding text. + +example (change later with example from the corpus): +text, index 0: “Strawberries don’t grow tasty (i) in the Netherlands.” +text, index 1: “Pineapple is very tasty (j) with salt (i) and chilli powder.” +text, index 2: “Blocks of salt (j) distract cows (i).” +text, index 3: “There was many field with cows (j) in this area.” + +Since every text, within a given set of at least four texts, will alternatively take the ‘preceding’ and the ‘succeeding’ position, each text will hold a word indexed as ‘i’ and a word indexed as ‘j’: marking the identical words occurring between a text and its succeeding. These marks will then determine the start and the end of each excerpt, and open the ‘shortcut’ aforementioned. + +As a result, the preceding text will be printed from its index ‘j’—attributed formerly when this text was in a ’succeeding’ position—until ‘i’, its common word with its current succeeding text. The function will loop until the last two texts of the set (in the index order). + +TEXT 1 xxxxxxxxxJooooooooooooIxxxxxxxxxxxxx +TEXT 2 xxxxxxxxxxxxxxxxxJooooooooooooIxxxxxxxxxx +TEXT 3 xxxxxxxxxxxJoooooooIxxxxxxxxxxxxxxxx +TEXT 4 xxxxxxJooooooooooooooooIxxxxxxxxxxxxxx + +o = printed text +x = rejected text +J = same word's index preceding text +I = same word's index in suceeding text + +In the case no match is found between two texts, the text in succeeding position will be printed from its first word to its last. + +## Example drawing: + +(Image here!) + +## Example with 3 excerpts from text corpus on orientation/navigation: + +(text here) + +## Cloverleaf and the Annotation Compass: + +Cloverleaf was imagined to navigate the annotations gathered with the Annotation Compass and offers the possibility to process the ever-growing data in the form of a json file. Used in complementarity, they become a fertile collective writing environment. + +(Link to Annotation Compass 'about' page) + +In a first experiment, a group of eight persons was given the following instruction: + +## Instructions: + +For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. + +Important: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. +For this experiment, each participant will only fill in one ‘insert’ box per word to be defined. + +## George Perec excerpt: + +![perec](soupboat/shared/html/si16-app/static/img/cloverleaf/perec.jpeg) + +## Participants texts: + +(Connect with Json 'text') + +1.To arrange: +"...." +"...." +"...." +"...." + +2.cccc ... + +## Button?: + +Press here to see the result. (Text black with colloured highlights) +(Here, button to bridge the previous texts together) + +## Try now!: + +Contribute: After getting acquainted with the tool and the instruction above, go to the Annotation Compass and insert your annotations on one, several or all the words proposed: + +(Here, button/links to Annotation Compass x14) + +You can also update your own surface for collective annotating + +## + diff --git a/projects/annotation-compass/showcases/.ipynb_checkpoints/infiltrating the filter-checkpoint.md b/projects/annotation-compass/showcases/.ipynb_checkpoints/infiltrating the filter-checkpoint.md new file mode 100644 index 0000000..a683f1d --- /dev/null +++ b/projects/annotation-compass/showcases/.ipynb_checkpoints/infiltrating the filter-checkpoint.md @@ -0,0 +1,7 @@ +--- +title: Infiltrating the Filter +author: Supisara +colophon: A showcase of the 'Annotation Compass' +description: Alternative annotation approaches +template: +--- \ No newline at end of file diff --git a/projects/annotation-compass/showcases/.ipynb_checkpoints/processed-vernacular-translation_UPDATED-checkpoint.md b/projects/annotation-compass/showcases/.ipynb_checkpoints/processed-vernacular-translation_UPDATED-checkpoint.md new file mode 100644 index 0000000..35c5faa --- /dev/null +++ b/projects/annotation-compass/showcases/.ipynb_checkpoints/processed-vernacular-translation_UPDATED-checkpoint.md @@ -0,0 +1,65 @@ +--- +title: the impossible process of grasping the other side +author: flem +colophon: Emma Prato +description: how does a translator choose words? why do they choose a instead of b? c instead of a? not all translations are perfect so then, why not mix them up? +url: "https://hub.xpub.nl/soupboat/~flem/api/translations/mashup/" +--- + + +## +how does a translator choose words?
why do they choose a instead of b? c instead of a?
+not all translations are perfect so then, why not mix them up? + +## introduction + +the impossible process of grasping the other side is a project by Emma Prato, as part of the Special Issue 16 //Learning How to Walk While Catwalking// carried out by Piet Zwart Institute (XPUB) students on the topic of Vernacular Language Processing. +the impossible process basically wants to play around with the structure of poetry translations and mix together different versions of the same text. +translating a poem into another language is an impossible process - so what if we gather translations from different people? from different languages? and what if then we mix them up? what if we change them? what if we play with words? it probably won't solve the impossible process but for sure is an interesting experiment. + +//multiple translations can give us a much better sense of the poem than a single translation can, so that even if we can’t read the poem in the original language, we can come closer to that experience// + +the impossible process is made of two sections: one (THE CROWD) is to gather //vernacular// information and the other (THE MASHUP) is to process texts, which can be both taken from the vernacular content or from already existing translations. The poetry archive (work in progress) will showcase the results. + +## the impossible process creates processed vernacular translations. what does it mean? + +//vernacular// means made by humans for humans, vernacular is the material I am gathering through the Annotation Compass°, a place where everyone can have access to, where everyone can give their contribution, regardless their background or knowledge etc.° + +//processed// means that the content gathered through humans' actions is transformed by the machine to create something new. + +what we are gathering, what we are processing, everything is //language//. in the case of the impossible process, we are using translations, in particular translations of poems. + + +## the impossible process – THE MASHUP // USE THE MASHUP() FUNCTION + +the impossible process – THE MASHUP tries to approach the impossible process of translation by the use of a Python function that: + +1. takes into account two different translations of a poem + +2. finds the common words and uses them as the fixed text for the new piece of text + +3. puts the results together into a new piece, randomly choosing the differences in the two texts + +The resulting text will show how many different ways there are to translate a text, a line, a concept, a single word. + +the impossible process is a funny way to highlight the thousand facets of a translation and create // never-ending // new texts randomly choosing the differences. + +Here you will find the space to compare your own texts yourself! Just click on the button below, access the mashup() function and start to create random poems! + + +## the impossible process – THE CROWD // CONTRIBUTE TO THE IMPOSSIBLE PROCESS + +the impossible process – THE CROWD consists into three annotation methods, in order to gather different material from users, then to process the texts and create new vernacular content. + +The results will be part of the Archive. If you want to contribute to the Archive of vernacular translations (or experimental texts), choose a method, access the image, insert your translation and wait for your text to be used. + +.one to one translation starts from a poem in x language to another x language (for example from Italian to English) + +.many to one translation starts from different language translations of the same original poem. Users can choose the language they prefer to start from and then insert the translation to english (//common language) through the Annotation Compass. + +.free fun translation starts from a common language and lets users interact as they want, without restrictions. + +## the impossible process – ARCHIVE OF VERNACULAR POEMS + +the purpose of this archive is divalent: the first is to gather vernacular translations from users around the world, and to fill this archive with translations that don't exist yet -- the second is to create always new random versions of already existing translations, or of vernacular translations, to play around with language and words. + diff --git a/projects/annotation-compass/showcases/.ipynb_checkpoints/rejection_map-checkpoint.md b/projects/annotation-compass/showcases/.ipynb_checkpoints/rejection_map-checkpoint.md new file mode 100644 index 0000000..0d1071f --- /dev/null +++ b/projects/annotation-compass/showcases/.ipynb_checkpoints/rejection_map-checkpoint.md @@ -0,0 +1,144 @@ +--- +title: Rejection Map — A Situated Topography of Rejection +author: Jian +colophon: Jian +description: How does a translator choose words? First description of the project +functions: individual_map, vernacular_map, area_map, target_map, highlight_map, ghost_map, html_tag +template: rejection_map (6 interactive forms need to be implemented, for placeholders scroll down) +--- + + +## Rejection Map +## A Situated Topography of Rejection + + +A city is a shared space for individuals with diverse backgrounds, identities and ways to perceive the world around them. Probably all of them have something in common: at some point they experienced a moment of rejection. These moments of rejection can take place in various contexts. People experience rejection in private relationships or in society; in the context of work or school; in relation to their body or appearance, their gender, identity or orientation; referring to their language or nationality; when it comes to housing or navigating in the city or even the supermarket … +Rejection can also be a very personal and much lighter experience: the moment you finally let go of a bad thought; the moment you make an independent choice that is free from other's opinions; the moment you skip the party and have an evening for yourself. + +In any case, rejection resonates an intimate level; a situated, embodied experience that stays with you. Many people will be able to remember those moments and even locate them on a map. And more often than not a moment of rejection shapes the individual but also the way they perceive the landscape and their surroundings. + +The multiplicity of subjective, embodied and situated experiences of rejection is a way to acknowledge and embrace different ways of knowing and feeling. All these singularities don’t stand isolated or alone. They are memories or anecdotes, traces or echoes of rejection. They relate, interact and overlap. Organically and ever-changing they form new maps of the city and being together on these new maps, sharing these incommensurable experiences maybe offers a sense of community and a chance for healing. + +Maps are meaningful. As companions in everyday life or while travelling to unknown places they help us to orientate and navigate the world. And at the same time maps themselves represent some and reject others. Maps have the power to shape the world and to produce realities. For this collaborative and collective mapping project, people are asked to situate and describe their experiences of rejection in Rotterdam. On a map of the city they can select an area and use their own words to express their perceptions on. + +Language, used to record and share human experiences, can be very powerful. We grow up using language as a way to communicate with other human beings and our own way of phrasing things is in many cases deeply connected to our identity. Especially written language adds a layer of consciousness to this: A moment of listening to yourself, before thoughtfully choosing words that best express a very intimate thought or feeling. + +In what way do textual annotations redefine the notion of a map and how we relate to it? + +In this alternative approach to mapping, the different perspectives on space are not only part of a research and data collecting process, but they actually create maps of their own through these linguistic annotations of affective relations. The Annotation Compass is a tool that helps to gather these particular knowledges, that altogether reveal both the commonalities and the differences of this juxtaposition. This collective approach does not necessarily aim to create a counter-map. However, it can be seen as an unfamiliar gesture that brings up questions about how, by whom and for whom maps are made. The lines between mapping and being mapped become fluid. + + + + + +## How to become part of the Rejection Map + +![Map of Rotterdam © OpenStreetMap contributors](/soupboat/si16-app/static/img/rejection_map/rejection_map.jpg)) + + +[Annotation Compass – Rejection-Map of Rotterdam](https://hub.xpub.nl/soupboat/generic-labels/annotate/rejection_map.jpg/) + +You are invited to share your experiences with rejection in the city of Rotterdam. Please be aware that your descriptions will be visible for others to read. Your contribution is voluntary and anonymous: you decide what moments and details you want to share and there is no data collected that traces back to you. As rejection is a sensitive topic, you should only share intimate things if you feel comfortable and safe. When sharing moments that involve other individuals, please be mindful that they might not want to be exposed. + + +1. Open the link to the Annotation Compass. You can see the map of Rotterdam + +2. Look at the map and try to think of a moment of rejection you experienced in a certain area in Rotterdam + +3. Use your cursor to select this specific area of the map where you can insert your first experience. It can be a quite small area (if you want to select a building) or a bigger one (if your experience includes a whole neighborhood). + +4. Please choose your own way to describe your moment of rejection. It can be short or long; formal or informal; personal or distanced; poetic or pragmatic; cryptic or explicit; anecdotal or out of context; using vernacular or academic language, slang or mother tongue; using whole sentences, single words, single letters or punctuation only … Do whatever you feel most comfortable with. + +5. Click ”insert“ to save your first description or ”x“ if you want to delete it. + +6. Follow the same steps to add more moments of rejection if you like. If several moments relate to the same space or area, they can overlap. + +Thank you for sharing! + + + + + +## Individual Maps + +By adding annotations to the Rejection Map, each individual creates an Individual Map of Rejection: It displays all moments of rejection that were shared by one person. Each time someone decides to join the project, a new Individual Map is created. These maps are diverse in their appearance. Some share several experiences with rejection, others only one. Some focus on one area, while others show annotations all over the city. Especially the personal experience with rejection and the way it is described are diverse and vary from person to person. The Individual Maps validate these intimate moments that were shared. +Looking through all the Individual Maps almost feels like reading a collective diary, where the reader is encouraged to change perspectives and to emphasize with each individual. + + +====== interactive form ====== + + + +## Vernacular Map + +The Vernacular Map combines all Individual Maps into one collective map by layering moments of rejection shared by individuals in the city of Rotterdam. While each of them is unique, they overlap and connect and whenever an Individual Map is added, the Vernacular Map changes as well. It illustrates that in our individualities we still share experiences and also space. + + +====== interactive form ====== + + + +## Area Map + +The Area Map offers a different way to read and navigate the Rejection Map by focusing on a specific area of Rotterdam. The parameters can be adjusted to look at all annotations in a certain neighborhood or any area area of interest. + + +====== interactive form ====== + + + +## Target Map + +The Target Map offers a different way to read and navigate the Rejection Map by filtering for one or more specific target words. The parameters can be adjusted to look at all annotations that include these targets. + + +====== interactive form ====== + + + +## Highlight Map + +The Highlight Map offers a different way to read and navigate the Rejection Map by filtering for one specific target word and highlighting all annotations that include this target. The parameters can be adjusted. + + +====== interactive form ====== + + + +## Ghost Map + +Sometimes descriptions of rejection can be very explicit, hurtful or triggering. The Ghost Map replaces all characters in the annotations with a specific glyph. The moments of rejection become abstract: The Ghost Map shows remnants, traces or echoes of individual experiences that are not always present, but imprinted in the memories of the individual and the city. + + +====== interactive form ====== + + + + + + +## Archive + +[Collective Rejection Glossary](https://pad.xpub.nl/p/Rejection_Glossary/) + +![Experiment 01](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-01.jpg) +![Experiment 02](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-02.jpg) +![Experiment 03](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-03.jpg) +![Experiment 04](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-04.jpg) +![Experiment 05](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-05.jpg) +![Experiment 06](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-06.jpg) +![Experiment 07](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-07.jpg) +![Experiment 08](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-08.jpg) +![Experiment 09](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-09.jpg) +![Experiment 10](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-10.jpg) +![Experiment 11](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-11.jpg) +![Experiment 12](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-12.jpg) +![Experiment 13](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-13.jpg) +![Experiment 14](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-14.jpg) +![Experiment 15](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-15.jpg) +![Experiment 16](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-16.jpg) +![Experiment 17](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-17.jpg) +![Experiment 18](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-18.jpg) +![Experiment 19](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-19.jpg) +![Experiment 20](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-20.jpg) +![Experiment 21](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-21.jpg) \ No newline at end of file diff --git a/projects/annotation-compass/showcases/.ipynb_checkpoints/rotterdam-impressions-checkpoint.md b/projects/annotation-compass/showcases/.ipynb_checkpoints/rotterdam-impressions-checkpoint.md new file mode 100644 index 0000000..f2996af --- /dev/null +++ b/projects/annotation-compass/showcases/.ipynb_checkpoints/rotterdam-impressions-checkpoint.md @@ -0,0 +1,103 @@ +--- +title: Rotterdam Impressions +author: Ål Nik (Alexandra Nikolova) +colophon: A showcase of the 'Annotation Compass' +description: A collective map of Rotterdam impressions, annotated by the first year Experimental Publishing students +functions: Adjectives, Nouns filers, Most common words filter +--- + +## Introduction + +### rotterdam impressions with the 'annotation compass' +We all arrived here from different places, backgrounds, histories and languages. As a group, we are building our relationships and exploring our personalities. Brought to this new place, we discover it both individually and collectively. The city is our everyday environment - we navigate in it to go to school, to go home, to do our grocery, to have a drink out. We spend some of these moments alone, sometimes with someone else. In a short moment of reflection, we all remembered our first or strongest impressions of some particular areas of Rotterdam, which triggered a memorable emotion in us. + +These illustrated subjective maps represent the impressions of the first year master students of Experimental Publishing at the Piet Zwart Institute. Their situated experiences trigger various ways to describe their new home: Rotterdam. They were invited to reflect on the way they remember some of the areas in the city and to describe how they feel about them. In words, in their own vernacular English - the common language that is not native to anyone of them but the main language they communicate between each other. Afterwards, their descriptions were filtered by a Python function to extract the most common words they used whilst describing their perceptions of the selected areas on the map, divided in three main categories - adjectives, nouns and pronouns. The final outcome is this short list of the most common impressions of various places and illustrated maps as an artistic expression of the author. + +### the most common... +In the following lists we observe the most common words the annotators used in their descriptions. They were asked to describe how they feel about areas and places they see on the map which trigger some memories and emotions in them. By using the Python filters for extracting the words that are adjectives (the words people used to describe their impressions of Rotterdam and various areas and places in it), nouns (the objects that we see people referring to) and pronouns (they way the approached the reflection) in combination with a filter for the most common words (which shows us which words are used the most and how many times), we can observe what are the feelings and impressions that they share as a new collective. What are the places and emotions that are common for some of them? + +```python +[('I', 53), ('my', 21), ('we', 19), ('me', 16), ('i', 13), ('place', 9), ('super', 9), ('We', 9), ('happy', 8), ('excited', 8), ('our', 8), ('were', 8), ('beautiful', 7), ('Rotterdam', 7), ('first', 6), ('area', 6), ('calm', 5), ('nervous', 5), ('big', 5), ('fig', 5), ('tree', 5), ('safe', 4), ('home', 4), ('inspired', 4), ('city', 4), ('little', 4), ('room', 4), ('shocked', 4), ('fun', 3), ('frustrated', 3), ('friendly', 3), ('good', 3), ('best', 3), ('bridge', 3), ('school', 3), ('nice', 3), ('station', 3), ('weird', 3), ('sad', 3), ('bike', 3), ('neighborhood', 3)] +``` + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_00.jpg) + +### vernacular map +The visual maps of [rotterdam impressions] depict how many times specific words were mentioned in the descriptions overall - the positions of the words are not related to the specific areas where they were mentioned because they are a collective print of how many times these words were used anywhere on the map. By printing each time a word was used, we can see the intensity of words used by the annotators. They are coloured due to their category - adjectives are in green, nouns are in orange and pronouns - in pink. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_01.jpg) + +### how are we describing +"I" and "we" are the most common pronouns (in pink) that were used in the annotations. You can see that "I" was used as twice more often that "we", but perhaps because of the context of us describing our first impressions of a new place where everyone arrived to study and work together as a group, some of the experiences were still connected to a collective moment. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_03.jpg) + +### adjectives as emotions and impressions; nouns as objects +In the context of the annotation compass, the adjectives (in green) were filtered and extracted as impressions and descriptions of the new place where people arrived. They are either describing Rotterdam and places inside it, or the way the annotator feels about them. Either way, in most of the cases we can still get the emotion that lays behind the word used. The most common nouns are understood as the objects (in orange) - the ones people are relating most often to. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_04.jpg) + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_02.jpg) + + +## Functions + +To filter the adjectives from the annotations: + +``` +def adjectives(text): + adj = [] + for (word, tag) in labels_blob.tags: + if tag == 'JJ': + adj = adj + [word] + return adj +``` + +To filter the nouns from the annotations: + +``` +def nouns(text): + noun = [] + for (word, tag) in labels_blob.tags: + if tag == 'NN': + noun = noun + [word] + return noun +``` + +To filter the most common words from the annotations: + + +``` +def most_common(words): + freq_dist_pos = FreqDist(words) + return freq_dist_pos.most_common(100) +``` + + +## Process + +Getting to the final showcase of the "annotation compass" was a long way of going back and forth whilst learning my first steps in Python. From the beginning my idea was to create vernacular map of our rotterdam impressions using our words in describing emotions and experineces. Here is what happened on the road: + +### 0. background story +In May 2021 I went through a massive burnout which resulted in me going to the hospital and not being able to climb the stairs at home normally for a week, because I couldn't take a deep breath. This traumatic experience got me started paying more attention to the signs of me getting overwhelmed; and also since then I have been living in fear of going through a similar experience again. + +After that crazy time, I had to organise my moving to Rotterdam and do some work on the way around Europe. After a year in isolation because of the pandemic, this was a dramatic change and I was afraid I might have another panic attack whilst being alone in the train in the middle of nowhere. In order to keep a track of my emotions and the way I feel, I started mapping them. That experiment made me think more of how to use our "annotation compass" to map our group's experiences and feelings. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/prototype_00.jpg) + +### 1. ideas & prototypes +The initial idea was to try mapping our emotions when reflecting on our first experiences in Rotterdam. In order to visualise that, I made a few prototypes by me mapping the places I feel most strongly about and then doing the same with my colleague Supisara. + +The prototypes were adjectives put on the map of Rotterdam, describing how we felt about a specific place or area. Later on, I figured it would be much more interesting to give freedom to the annotator to choose how they want to describe their perceptions. And after that, I could filter their texts in order to extract the adjectives. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/prototype_01.jpg) + +### 2. collecting annotations + +We used the "annotation compass" to write down some reflections about our arrival in Rotterdam and the way we feel about some places and areas. The invitation to the group was to take a few minutes to reflect on their arrival in the city and they feel strongly on some areas and spaces; and to describe the way they feel about them. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/prototype_02.jpg) + +### 3. filtering the annotations with python +Since there was no restriction what words the use in the descriptions, I applied a combination of Python functions in order to process the data and extract the most common words. I also looked up for how many times the most common adjectives, nouns and pronouns were used. Looking at the result of the text processing, I created illustrated maps with the number of times these most common words were used. + diff --git a/projects/annotation-compass/showcases/cloverleaf.md b/projects/annotation-compass/showcases/cloverleaf.md new file mode 100644 index 0000000..ca3d294 --- /dev/null +++ b/projects/annotation-compass/showcases/cloverleaf.md @@ -0,0 +1,98 @@ +--- +title: Cloverleaf +author: Kimberley +description: Opening short-cuts between texts +functions: clean_word(), bridge(), bridge_list(), +template: +--- + +## Description: + +Cloverleaf is a tool to navigate a set of text. Through generated short-cuts, it is meant to interrupts the linearity of a text. The result is a collage of excerpts and aims to free unexpected reading paths. +The tool can be used to stitch various voices together in a non-hierarchical manner, giving off hybrid constructions where common points and divergences can co-exist. + +## Picture: + +![cloverleaf](soupboat/shared/html/si16-app/static/img/cloverleaf/cloverleaf.jpeg) +(Picture of a cloverleaf) + +## In detail: + +For two texts in a set of text following an index order, let’s consider a ‘preceding text’ and its succeeding. In a first place, the function bridge() will look for the first identical word occurring in both texts (excluding stop words). Let’s name the position (index) of this word ‘i’ for the preceding text and ‘j’ for the succeeding text. + +example (change later with example from the corpus): +text, index 0: “Strawberries don’t grow tasty (i) in the Netherlands.” +text, index 1: “Pineapple is very tasty (j) with salt (i) and chilli powder.” +text, index 2: “Blocks of salt (j) distract cows (i).” +text, index 3: “There was many field with cows (j) in this area.” + +Since every text, within a given set of at least four texts, will alternatively take the ‘preceding’ and the ‘succeeding’ position, each text will hold a word indexed as ‘i’ and a word indexed as ‘j’: marking the identical words occurring between a text and its succeeding. These marks will then determine the start and the end of each excerpt, and open the ‘shortcut’ aforementioned. + +As a result, the preceding text will be printed from its index ‘j’—attributed formerly when this text was in a ’succeeding’ position—until ‘i’, its common word with its current succeeding text. The function will loop until the last two texts of the set (in the index order). + +TEXT 1 xxxxxxxxxJooooooooooooIxxxxxxxxxxxxx +TEXT 2 xxxxxxxxxxxxxxxxxJooooooooooooIxxxxxxxxxx +TEXT 3 xxxxxxxxxxxJoooooooIxxxxxxxxxxxxxxxx +TEXT 4 xxxxxxJooooooooooooooooIxxxxxxxxxxxxxx + +o = printed text +x = rejected text +J = same word's index preceding text +I = same word's index in suceeding text + +In the case no match is found between two texts, the text in succeeding position will be printed from its first word to its last. + +## Example drawing: + +(Image here!) + +## Example with 3 excerpts from text corpus on orientation/navigation: + +(text here) + +## Cloverleaf and the Annotation Compass: + +Cloverleaf was imagined to navigate the annotations gathered with the Annotation Compass and offers the possibility to process the ever-growing data in the form of a json file. Used in complementarity, they become a fertile collective writing environment. + +(Link to Annotation Compass 'about' page) + +In a first experiment, a group of eight persons was given the following instruction: + +## Instructions: + +For as long as one minute; you are kindly asked to define, in your own words and logic, the verb on the screen. This definition does not necessarily have to have sense for anyone else but you, although English language will be our common ground in this experiment. + +Important: You are required to write for the entire span of this granted minute! Do not lift hands from keyboard, and in case of blockage you are welcome to press any key or write any word, onomatopoeia, etc. +For this experiment, each participant will only fill in one ‘insert’ box per word to be defined. + +## George Perec excerpt: + +![perec](soupboat/shared/html/si16-app/static/img/cloverleaf/perec.jpeg) + +## Participants texts: + +(Connect with Json 'text') + +1.To arrange: +"...." +"...." +"...." +"...." + +2.cccc ... + +## Button?: + +Press here to see the result. (Text black with colloured highlights) +(Here, button to bridge the previous texts together) + +## Try now!: + +Contribute: After getting acquainted with the tool and the instruction above, go to the Annotation Compass and insert your annotations on one, several or all the words proposed: + +(Here, button/links to Annotation Compass x14) + +You can also update your own surface for collective annotating + +## + diff --git a/projects/annotation-compass/showcases/infiltrating the filter.md b/projects/annotation-compass/showcases/infiltrating the filter.md new file mode 100644 index 0000000..098c7ef --- /dev/null +++ b/projects/annotation-compass/showcases/infiltrating the filter.md @@ -0,0 +1,9 @@ +--- +title: Infiltrating the Filter +author: Supisara +colophon: A showcase of the 'Annotation Compass' +description: Alternative approaches to annotating +template: +--- + +## Introduction diff --git a/projects/annotation-compass/showcases/processed-vernacular-translation_UPDATED.md b/projects/annotation-compass/showcases/processed-vernacular-translation_UPDATED.md new file mode 100644 index 0000000..35c5faa --- /dev/null +++ b/projects/annotation-compass/showcases/processed-vernacular-translation_UPDATED.md @@ -0,0 +1,65 @@ +--- +title: the impossible process of grasping the other side +author: flem +colophon: Emma Prato +description: how does a translator choose words? why do they choose a instead of b? c instead of a? not all translations are perfect so then, why not mix them up? +url: "https://hub.xpub.nl/soupboat/~flem/api/translations/mashup/" +--- + + +## +how does a translator choose words?
why do they choose a instead of b? c instead of a?
+not all translations are perfect so then, why not mix them up? + +## introduction + +the impossible process of grasping the other side is a project by Emma Prato, as part of the Special Issue 16 //Learning How to Walk While Catwalking// carried out by Piet Zwart Institute (XPUB) students on the topic of Vernacular Language Processing. +the impossible process basically wants to play around with the structure of poetry translations and mix together different versions of the same text. +translating a poem into another language is an impossible process - so what if we gather translations from different people? from different languages? and what if then we mix them up? what if we change them? what if we play with words? it probably won't solve the impossible process but for sure is an interesting experiment. + +//multiple translations can give us a much better sense of the poem than a single translation can, so that even if we can’t read the poem in the original language, we can come closer to that experience// + +the impossible process is made of two sections: one (THE CROWD) is to gather //vernacular// information and the other (THE MASHUP) is to process texts, which can be both taken from the vernacular content or from already existing translations. The poetry archive (work in progress) will showcase the results. + +## the impossible process creates processed vernacular translations. what does it mean? + +//vernacular// means made by humans for humans, vernacular is the material I am gathering through the Annotation Compass°, a place where everyone can have access to, where everyone can give their contribution, regardless their background or knowledge etc.° + +//processed// means that the content gathered through humans' actions is transformed by the machine to create something new. + +what we are gathering, what we are processing, everything is //language//. in the case of the impossible process, we are using translations, in particular translations of poems. + + +## the impossible process – THE MASHUP // USE THE MASHUP() FUNCTION + +the impossible process – THE MASHUP tries to approach the impossible process of translation by the use of a Python function that: + +1. takes into account two different translations of a poem + +2. finds the common words and uses them as the fixed text for the new piece of text + +3. puts the results together into a new piece, randomly choosing the differences in the two texts + +The resulting text will show how many different ways there are to translate a text, a line, a concept, a single word. + +the impossible process is a funny way to highlight the thousand facets of a translation and create // never-ending // new texts randomly choosing the differences. + +Here you will find the space to compare your own texts yourself! Just click on the button below, access the mashup() function and start to create random poems! + + +## the impossible process – THE CROWD // CONTRIBUTE TO THE IMPOSSIBLE PROCESS + +the impossible process – THE CROWD consists into three annotation methods, in order to gather different material from users, then to process the texts and create new vernacular content. + +The results will be part of the Archive. If you want to contribute to the Archive of vernacular translations (or experimental texts), choose a method, access the image, insert your translation and wait for your text to be used. + +.one to one translation starts from a poem in x language to another x language (for example from Italian to English) + +.many to one translation starts from different language translations of the same original poem. Users can choose the language they prefer to start from and then insert the translation to english (//common language) through the Annotation Compass. + +.free fun translation starts from a common language and lets users interact as they want, without restrictions. + +## the impossible process – ARCHIVE OF VERNACULAR POEMS + +the purpose of this archive is divalent: the first is to gather vernacular translations from users around the world, and to fill this archive with translations that don't exist yet -- the second is to create always new random versions of already existing translations, or of vernacular translations, to play around with language and words. + diff --git a/projects/annotation-compass/showcases/rejection_map.md b/projects/annotation-compass/showcases/rejection_map.md new file mode 100644 index 0000000..0d1071f --- /dev/null +++ b/projects/annotation-compass/showcases/rejection_map.md @@ -0,0 +1,144 @@ +--- +title: Rejection Map — A Situated Topography of Rejection +author: Jian +colophon: Jian +description: How does a translator choose words? First description of the project +functions: individual_map, vernacular_map, area_map, target_map, highlight_map, ghost_map, html_tag +template: rejection_map (6 interactive forms need to be implemented, for placeholders scroll down) +--- + + +## Rejection Map +## A Situated Topography of Rejection + + +A city is a shared space for individuals with diverse backgrounds, identities and ways to perceive the world around them. Probably all of them have something in common: at some point they experienced a moment of rejection. These moments of rejection can take place in various contexts. People experience rejection in private relationships or in society; in the context of work or school; in relation to their body or appearance, their gender, identity or orientation; referring to their language or nationality; when it comes to housing or navigating in the city or even the supermarket … +Rejection can also be a very personal and much lighter experience: the moment you finally let go of a bad thought; the moment you make an independent choice that is free from other's opinions; the moment you skip the party and have an evening for yourself. + +In any case, rejection resonates an intimate level; a situated, embodied experience that stays with you. Many people will be able to remember those moments and even locate them on a map. And more often than not a moment of rejection shapes the individual but also the way they perceive the landscape and their surroundings. + +The multiplicity of subjective, embodied and situated experiences of rejection is a way to acknowledge and embrace different ways of knowing and feeling. All these singularities don’t stand isolated or alone. They are memories or anecdotes, traces or echoes of rejection. They relate, interact and overlap. Organically and ever-changing they form new maps of the city and being together on these new maps, sharing these incommensurable experiences maybe offers a sense of community and a chance for healing. + +Maps are meaningful. As companions in everyday life or while travelling to unknown places they help us to orientate and navigate the world. And at the same time maps themselves represent some and reject others. Maps have the power to shape the world and to produce realities. For this collaborative and collective mapping project, people are asked to situate and describe their experiences of rejection in Rotterdam. On a map of the city they can select an area and use their own words to express their perceptions on. + +Language, used to record and share human experiences, can be very powerful. We grow up using language as a way to communicate with other human beings and our own way of phrasing things is in many cases deeply connected to our identity. Especially written language adds a layer of consciousness to this: A moment of listening to yourself, before thoughtfully choosing words that best express a very intimate thought or feeling. + +In what way do textual annotations redefine the notion of a map and how we relate to it? + +In this alternative approach to mapping, the different perspectives on space are not only part of a research and data collecting process, but they actually create maps of their own through these linguistic annotations of affective relations. The Annotation Compass is a tool that helps to gather these particular knowledges, that altogether reveal both the commonalities and the differences of this juxtaposition. This collective approach does not necessarily aim to create a counter-map. However, it can be seen as an unfamiliar gesture that brings up questions about how, by whom and for whom maps are made. The lines between mapping and being mapped become fluid. + + + + + +## How to become part of the Rejection Map + +![Map of Rotterdam © OpenStreetMap contributors](/soupboat/si16-app/static/img/rejection_map/rejection_map.jpg)) + + +[Annotation Compass – Rejection-Map of Rotterdam](https://hub.xpub.nl/soupboat/generic-labels/annotate/rejection_map.jpg/) + +You are invited to share your experiences with rejection in the city of Rotterdam. Please be aware that your descriptions will be visible for others to read. Your contribution is voluntary and anonymous: you decide what moments and details you want to share and there is no data collected that traces back to you. As rejection is a sensitive topic, you should only share intimate things if you feel comfortable and safe. When sharing moments that involve other individuals, please be mindful that they might not want to be exposed. + + +1. Open the link to the Annotation Compass. You can see the map of Rotterdam + +2. Look at the map and try to think of a moment of rejection you experienced in a certain area in Rotterdam + +3. Use your cursor to select this specific area of the map where you can insert your first experience. It can be a quite small area (if you want to select a building) or a bigger one (if your experience includes a whole neighborhood). + +4. Please choose your own way to describe your moment of rejection. It can be short or long; formal or informal; personal or distanced; poetic or pragmatic; cryptic or explicit; anecdotal or out of context; using vernacular or academic language, slang or mother tongue; using whole sentences, single words, single letters or punctuation only … Do whatever you feel most comfortable with. + +5. Click ”insert“ to save your first description or ”x“ if you want to delete it. + +6. Follow the same steps to add more moments of rejection if you like. If several moments relate to the same space or area, they can overlap. + +Thank you for sharing! + + + + + +## Individual Maps + +By adding annotations to the Rejection Map, each individual creates an Individual Map of Rejection: It displays all moments of rejection that were shared by one person. Each time someone decides to join the project, a new Individual Map is created. These maps are diverse in their appearance. Some share several experiences with rejection, others only one. Some focus on one area, while others show annotations all over the city. Especially the personal experience with rejection and the way it is described are diverse and vary from person to person. The Individual Maps validate these intimate moments that were shared. +Looking through all the Individual Maps almost feels like reading a collective diary, where the reader is encouraged to change perspectives and to emphasize with each individual. + + +====== interactive form ====== + + + +## Vernacular Map + +The Vernacular Map combines all Individual Maps into one collective map by layering moments of rejection shared by individuals in the city of Rotterdam. While each of them is unique, they overlap and connect and whenever an Individual Map is added, the Vernacular Map changes as well. It illustrates that in our individualities we still share experiences and also space. + + +====== interactive form ====== + + + +## Area Map + +The Area Map offers a different way to read and navigate the Rejection Map by focusing on a specific area of Rotterdam. The parameters can be adjusted to look at all annotations in a certain neighborhood or any area area of interest. + + +====== interactive form ====== + + + +## Target Map + +The Target Map offers a different way to read and navigate the Rejection Map by filtering for one or more specific target words. The parameters can be adjusted to look at all annotations that include these targets. + + +====== interactive form ====== + + + +## Highlight Map + +The Highlight Map offers a different way to read and navigate the Rejection Map by filtering for one specific target word and highlighting all annotations that include this target. The parameters can be adjusted. + + +====== interactive form ====== + + + +## Ghost Map + +Sometimes descriptions of rejection can be very explicit, hurtful or triggering. The Ghost Map replaces all characters in the annotations with a specific glyph. The moments of rejection become abstract: The Ghost Map shows remnants, traces or echoes of individual experiences that are not always present, but imprinted in the memories of the individual and the city. + + +====== interactive form ====== + + + + + + +## Archive + +[Collective Rejection Glossary](https://pad.xpub.nl/p/Rejection_Glossary/) + +![Experiment 01](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-01.jpg) +![Experiment 02](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-02.jpg) +![Experiment 03](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-03.jpg) +![Experiment 04](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-04.jpg) +![Experiment 05](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-05.jpg) +![Experiment 06](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-06.jpg) +![Experiment 07](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-07.jpg) +![Experiment 08](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-08.jpg) +![Experiment 09](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-09.jpg) +![Experiment 10](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-10.jpg) +![Experiment 11](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-11.jpg) +![Experiment 12](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-12.jpg) +![Experiment 13](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-13.jpg) +![Experiment 14](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-14.jpg) +![Experiment 15](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-15.jpg) +![Experiment 16](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-16.jpg) +![Experiment 17](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-17.jpg) +![Experiment 18](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-18.jpg) +![Experiment 19](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-19.jpg) +![Experiment 20](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-20.jpg) +![Experiment 21](/soupboat/si16-app/static/img/rejection_map/vernacular-map-experiments-21.jpg) \ No newline at end of file diff --git a/projects/annotation-compass/showcases/rotterdam-impressions.md b/projects/annotation-compass/showcases/rotterdam-impressions.md new file mode 100644 index 0000000..f2996af --- /dev/null +++ b/projects/annotation-compass/showcases/rotterdam-impressions.md @@ -0,0 +1,103 @@ +--- +title: Rotterdam Impressions +author: Ål Nik (Alexandra Nikolova) +colophon: A showcase of the 'Annotation Compass' +description: A collective map of Rotterdam impressions, annotated by the first year Experimental Publishing students +functions: Adjectives, Nouns filers, Most common words filter +--- + +## Introduction + +### rotterdam impressions with the 'annotation compass' +We all arrived here from different places, backgrounds, histories and languages. As a group, we are building our relationships and exploring our personalities. Brought to this new place, we discover it both individually and collectively. The city is our everyday environment - we navigate in it to go to school, to go home, to do our grocery, to have a drink out. We spend some of these moments alone, sometimes with someone else. In a short moment of reflection, we all remembered our first or strongest impressions of some particular areas of Rotterdam, which triggered a memorable emotion in us. + +These illustrated subjective maps represent the impressions of the first year master students of Experimental Publishing at the Piet Zwart Institute. Their situated experiences trigger various ways to describe their new home: Rotterdam. They were invited to reflect on the way they remember some of the areas in the city and to describe how they feel about them. In words, in their own vernacular English - the common language that is not native to anyone of them but the main language they communicate between each other. Afterwards, their descriptions were filtered by a Python function to extract the most common words they used whilst describing their perceptions of the selected areas on the map, divided in three main categories - adjectives, nouns and pronouns. The final outcome is this short list of the most common impressions of various places and illustrated maps as an artistic expression of the author. + +### the most common... +In the following lists we observe the most common words the annotators used in their descriptions. They were asked to describe how they feel about areas and places they see on the map which trigger some memories and emotions in them. By using the Python filters for extracting the words that are adjectives (the words people used to describe their impressions of Rotterdam and various areas and places in it), nouns (the objects that we see people referring to) and pronouns (they way the approached the reflection) in combination with a filter for the most common words (which shows us which words are used the most and how many times), we can observe what are the feelings and impressions that they share as a new collective. What are the places and emotions that are common for some of them? + +```python +[('I', 53), ('my', 21), ('we', 19), ('me', 16), ('i', 13), ('place', 9), ('super', 9), ('We', 9), ('happy', 8), ('excited', 8), ('our', 8), ('were', 8), ('beautiful', 7), ('Rotterdam', 7), ('first', 6), ('area', 6), ('calm', 5), ('nervous', 5), ('big', 5), ('fig', 5), ('tree', 5), ('safe', 4), ('home', 4), ('inspired', 4), ('city', 4), ('little', 4), ('room', 4), ('shocked', 4), ('fun', 3), ('frustrated', 3), ('friendly', 3), ('good', 3), ('best', 3), ('bridge', 3), ('school', 3), ('nice', 3), ('station', 3), ('weird', 3), ('sad', 3), ('bike', 3), ('neighborhood', 3)] +``` + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_00.jpg) + +### vernacular map +The visual maps of [rotterdam impressions] depict how many times specific words were mentioned in the descriptions overall - the positions of the words are not related to the specific areas where they were mentioned because they are a collective print of how many times these words were used anywhere on the map. By printing each time a word was used, we can see the intensity of words used by the annotators. They are coloured due to their category - adjectives are in green, nouns are in orange and pronouns - in pink. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_01.jpg) + +### how are we describing +"I" and "we" are the most common pronouns (in pink) that were used in the annotations. You can see that "I" was used as twice more often that "we", but perhaps because of the context of us describing our first impressions of a new place where everyone arrived to study and work together as a group, some of the experiences were still connected to a collective moment. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_03.jpg) + +### adjectives as emotions and impressions; nouns as objects +In the context of the annotation compass, the adjectives (in green) were filtered and extracted as impressions and descriptions of the new place where people arrived. They are either describing Rotterdam and places inside it, or the way the annotator feels about them. Either way, in most of the cases we can still get the emotion that lays behind the word used. The most common nouns are understood as the objects (in orange) - the ones people are relating most often to. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_04.jpg) + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/map_02.jpg) + + +## Functions + +To filter the adjectives from the annotations: + +``` +def adjectives(text): + adj = [] + for (word, tag) in labels_blob.tags: + if tag == 'JJ': + adj = adj + [word] + return adj +``` + +To filter the nouns from the annotations: + +``` +def nouns(text): + noun = [] + for (word, tag) in labels_blob.tags: + if tag == 'NN': + noun = noun + [word] + return noun +``` + +To filter the most common words from the annotations: + + +``` +def most_common(words): + freq_dist_pos = FreqDist(words) + return freq_dist_pos.most_common(100) +``` + + +## Process + +Getting to the final showcase of the "annotation compass" was a long way of going back and forth whilst learning my first steps in Python. From the beginning my idea was to create vernacular map of our rotterdam impressions using our words in describing emotions and experineces. Here is what happened on the road: + +### 0. background story +In May 2021 I went through a massive burnout which resulted in me going to the hospital and not being able to climb the stairs at home normally for a week, because I couldn't take a deep breath. This traumatic experience got me started paying more attention to the signs of me getting overwhelmed; and also since then I have been living in fear of going through a similar experience again. + +After that crazy time, I had to organise my moving to Rotterdam and do some work on the way around Europe. After a year in isolation because of the pandemic, this was a dramatic change and I was afraid I might have another panic attack whilst being alone in the train in the middle of nowhere. In order to keep a track of my emotions and the way I feel, I started mapping them. That experiment made me think more of how to use our "annotation compass" to map our group's experiences and feelings. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/prototype_00.jpg) + +### 1. ideas & prototypes +The initial idea was to try mapping our emotions when reflecting on our first experiences in Rotterdam. In order to visualise that, I made a few prototypes by me mapping the places I feel most strongly about and then doing the same with my colleague Supisara. + +The prototypes were adjectives put on the map of Rotterdam, describing how we felt about a specific place or area. Later on, I figured it would be much more interesting to give freedom to the annotator to choose how they want to describe their perceptions. And after that, I could filter their texts in order to extract the adjectives. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/prototype_01.jpg) + +### 2. collecting annotations + +We used the "annotation compass" to write down some reflections about our arrival in Rotterdam and the way we feel about some places and areas. The invitation to the group was to take a few minutes to reflect on their arrival in the city and they feel strongly on some areas and spaces; and to describe the way they feel about them. + +![Screenshot of the result](/soupboat/si16-app/static/img/rotterdam_impressions/prototype_02.jpg) + +### 3. filtering the annotations with python +Since there was no restriction what words the use in the descriptions, I applied a combination of Python functions in order to process the data and extract the most common words. I also looked up for how many times the most common adjectives, nouns and pronouns were used. Looking at the result of the text processing, I created illustrated maps with the number of times these most common words were used. + diff --git a/projects/etc-portal/.ipynb_checkpoints/documentation-checkpoint.md b/projects/etc-portal/.ipynb_checkpoints/documentation-checkpoint.md new file mode 100644 index 0000000..a199417 --- /dev/null +++ b/projects/etc-portal/.ipynb_checkpoints/documentation-checkpoint.md @@ -0,0 +1,38 @@ +--- +title: "Etc Portal to Contamination" +description: "The Etc Portal to Contamination is a research into the negative space one can find in texts." +colophon: "Chae, Gersande" +url: "https://hub.xpub.nl/soupboat/~chae/api/" +--- + + + + + + + +The Etc Portal to Contamination is a project initiated by Chaeyoung Kim and Gersande Schellinx in the context of the Special Issue 16 (2021), around the topic of Vernacular Language Processing. It is a subgroup project hosted by the overall project: Learning How To Walk While Catwalking. + +The Etc Portal to Contamination is a research into the negative space one can find in texts. Hosted by the means of simple keywords, expressions and punctuation marks… These implicit markers ('et cetera', ' etc ', ' etc.', 'and-so-on', 'and-so-forth', 'and others', 'et al.', 'and all the rest', 'and on and on', 'along with others’, ‘blablabla’, ‘blabla’, ‘and much more’, '...', '(...)','[...]', '[. …]'), often leave out some information for different reasons: may that be due to a lack of time, because the author assumes you understand what they imply, or don't feel the need to make a further listing of certain items. + +More information about the Etc Project to Contamination(https://pzwiki.wdka.nl/mw-mediadesign/images/1/1b/Graph_etcfunction_update.jpg) + +## etc. +C and G's etcetera list combines different branches of their conceptual understanding of what the etc is. +etcetera = ['et cetera', ' etc ', ' etc.', 'and-so-on', 'and-so-forth', 'and others', 'et al.', 'and all the rest', 'and on and on', 'along with others’, ‘blablabla’, ‘blabla’, ‘and much more’, '...', '(...)','[...]', '[. ...]'] + +## Contamination +If the contamination word might come across as a negative notion, C & G mean it as a neutral term. What is designated here as "contamination" is the pure agency of introducing contaminants, foreign entities to a body of text and make it become part of it, in a seamless way. + +## Co-authorship +The text output returned to the user, is the user's as much as it is C and G's. The last line "The Neverending Backstage Story is an original text by Gersande | Chaeyoung | ..." invites the users to add their pen name after contamination of the text. + +This feature of the Etc Portal To Contamination is one essential aspect of C & G's project. As within the idea of vernacular language processing, they aimed to question the established authority in publishing, hierarchy in textual platforms, alleged legitimacy in speech and narrow consideration in the legitimate world of references. + +## Colofon +This project has been made possible thanks to Manetta Berends, Michael Murtaugh, Clara Balaguer, Steve Rushton, Cristina Cochior and all our dear XPUB classmates. + +## Expected outcomes +By submitting their textual information, thoughts, questions, or else, the users have submitted what they consider legitimate content, that will then merge with the "original" text and become one. As such, the text itself is ongoing. As long as users contaminate it, the text will grow, change. Subvert, invert narrative. + + diff --git a/projects/etc-portal/documentation.md b/projects/etc-portal/documentation.md new file mode 100644 index 0000000..a199417 --- /dev/null +++ b/projects/etc-portal/documentation.md @@ -0,0 +1,38 @@ +--- +title: "Etc Portal to Contamination" +description: "The Etc Portal to Contamination is a research into the negative space one can find in texts." +colophon: "Chae, Gersande" +url: "https://hub.xpub.nl/soupboat/~chae/api/" +--- + + + + + + + +The Etc Portal to Contamination is a project initiated by Chaeyoung Kim and Gersande Schellinx in the context of the Special Issue 16 (2021), around the topic of Vernacular Language Processing. It is a subgroup project hosted by the overall project: Learning How To Walk While Catwalking. + +The Etc Portal to Contamination is a research into the negative space one can find in texts. Hosted by the means of simple keywords, expressions and punctuation marks… These implicit markers ('et cetera', ' etc ', ' etc.', 'and-so-on', 'and-so-forth', 'and others', 'et al.', 'and all the rest', 'and on and on', 'along with others’, ‘blablabla’, ‘blabla’, ‘and much more’, '...', '(...)','[...]', '[. …]'), often leave out some information for different reasons: may that be due to a lack of time, because the author assumes you understand what they imply, or don't feel the need to make a further listing of certain items. + +More information about the Etc Project to Contamination(https://pzwiki.wdka.nl/mw-mediadesign/images/1/1b/Graph_etcfunction_update.jpg) + +## etc. +C and G's etcetera list combines different branches of their conceptual understanding of what the etc is. +etcetera = ['et cetera', ' etc ', ' etc.', 'and-so-on', 'and-so-forth', 'and others', 'et al.', 'and all the rest', 'and on and on', 'along with others’, ‘blablabla’, ‘blabla’, ‘and much more’, '...', '(...)','[...]', '[. ...]'] + +## Contamination +If the contamination word might come across as a negative notion, C & G mean it as a neutral term. What is designated here as "contamination" is the pure agency of introducing contaminants, foreign entities to a body of text and make it become part of it, in a seamless way. + +## Co-authorship +The text output returned to the user, is the user's as much as it is C and G's. The last line "The Neverending Backstage Story is an original text by Gersande | Chaeyoung | ..." invites the users to add their pen name after contamination of the text. + +This feature of the Etc Portal To Contamination is one essential aspect of C & G's project. As within the idea of vernacular language processing, they aimed to question the established authority in publishing, hierarchy in textual platforms, alleged legitimacy in speech and narrow consideration in the legitimate world of references. + +## Colofon +This project has been made possible thanks to Manetta Berends, Michael Murtaugh, Clara Balaguer, Steve Rushton, Cristina Cochior and all our dear XPUB classmates. + +## Expected outcomes +By submitting their textual information, thoughts, questions, or else, the users have submitted what they consider legitimate content, that will then merge with the "original" text and become one. As such, the text itself is ongoing. As long as users contaminate it, the text will grow, change. Subvert, invert narrative. + + diff --git a/si16.py b/si16.py new file mode 100644 index 0000000..9244267 --- /dev/null +++ b/si16.py @@ -0,0 +1,569 @@ +# IMPORT +# to work with files in folder +import os + +# to work with json files +import json +from urllib.request import urlopen + +# to create the Flask app +from flask import Flask, render_template, request, url_for, redirect, jsonify, abort + +# to import text contents and metadata from markdown files +from flaskext.markdown import Markdown +import frontmatter + +# to cast string arguments into the required types +from pydoc import locate + +# to work with notebooks +# +# to import notebook files +import nbimporter +nbimporter.options['only_defs'] = False +import importlib + +# to read and execute the content of notebooks +import nbformat +from nbconvert import HTMLExporter, MarkdownExporter +from nbconvert.preprocessors import ExecutePreprocessor + +# not sure about this is in the nbconvert documentation +from traitlets.config import Config + +# to work with placeholder descriptions +from random import choice + +# Subgroup Projects import + +# not really happy of this routing for the module but +ac = importlib.import_module("projects.annotation-compass.annotation_compass") + + +# FUNCTIONS + +def filenames(folder, remove_ext = False): + ''' Read all the functions in a folder ''' + names = [] + for entry in os.scandir(folder): + # add to the list only proper files + if entry.is_file(follow_symlinks=False): + # remove the extension from the filename + n = os.path.splitext(entry.name)[0] + if remove_ext: + n = entry.name + names.append(n) + return names + + +def dirnames(folder): + ''' Return all the folders in a folder ''' + names = [] + for entry in os.scandir(folder): + # add to the list only proper files + if not entry.name.startswith('.') and entry.is_dir(): + # remove the extension from the filename + names.append(entry.name) + return names + + +# not really sure about this file -> module -> function thing! +# could someone help pls ? +def get_function(name, folder): + ''' Dynamic import a function from a folder ''' + file = __import__(f'{folder}.{name}') + module = getattr(file, name) + function = getattr(module, name) + return function + + +def get_function_info(function): + ''' Extract info from a function ''' + name = function.__name__ + description = function.__doc__ + parameters = [] + output = '' + + # TODO: default values + + # populate a list of tuple with patameter, type + for param in function.__annotations__.keys(): + if param == 'return': + output = function.__annotations__[param].__name__ + if param != 'return': + parameters.append((param, function.__annotations__[param].__name__)) + + return(name, description, parameters, output) + +def print_info(function): + ''' Print the info of a function nicely ''' + name, description, parameters, output = get_function_info(function) + + # very important feature + from kaomoji.kaomoji import Kaomoji + kao = Kaomoji() + + header = f'----------{kao.create()}' + footer = '-' * len(header) + + print(header) + print(name) + print(description) + print('Input:') + for param, tp in parameters: + print(f' {param}, of type {tp}') + print(f'Returns a {output}') + print(footer) + + +def generate_function_list(): + ''' Build a list of the function ''' + functions = [] + for function in filenames("./notebooks"): + try: + fx = get_function(function, notebooks) + name, description, parameters, output = get_function_info(fx) +# print(f'{function} function is ok') +# print(f'Description is: {description}') + if description == None: + description = placeholder_description('function') + f = { + "title": name, + "description": description + } + except: +# print('--->error so placeholder fx') + f = { + "title": function, + "description": placeholder_description('function') + } + functions.append(f) +# print(functions) + with open('./static/functions.json', 'w') as file: + json.dump(functions, file) + + +def placeholder_description(subject): + ''' Return a placeholder description of a subject ''' + # ok this is a meme but is to make the notebooks a bit more waterproof + adjs = ['useful', 'nice', 'intresting', 'incredible', 'wow'] + placeholders = [f'A super', f'A {choice(adjs)} and', f'You wont believe to this', f'Yet another' ] + return f'{choice(placeholders)} {choice(adjs)} {subject}' + + +# optionally you can pass a boolean argument to execute the notebook before the export +# but it is a slow process so by default is not active +# TODO: markdown export instead of HTML ? +# TODO: extract images from base64 +def get_notebook_contents(filename, execute = False): + ''' Export notebook contents as HTML. ''' + with open(filename) as f: + nb = nbformat.read(f, as_version=4) + + if execute: + ep = ExecutePreprocessor(timeout=600, kernel_name='python3') + ep.preprocess(nb, {'metadata':{'path':'notebooks/'}}) + + html_exporter = HTMLExporter() + html_exporter.template_name = 'basic' + (body, resources) = html_exporter.from_notebook_node(nb) + + return body + +# EXPORT AS MARKDOWN +def get_notebook_md(filename, execute = False): + ''' Export notebook contents as Markdown. ''' + with open(filename) as f: + nb = nbformat.read(f, as_version=4) + + if execute: + ep = ExecutePreprocessor(timeout=600, kernel_name='python3') + ep.preprocess(nb, {'metadata':{'path':'notebooks/'}}) + + md_exporter = MarkdownExporter() + + (body, resources) = md_exporter.from_notebook_node(nb) + + return body + +def get_contents(filename, directory = './contents'): + ''' Return contents from a filename as frontmatter handler ''' + with open(f"{directory}/{filename}", "r") as f: + content = frontmatter.load(f) + return content + +def get_meta(filename, directory = './contents'): + ''' Return contents from a filename as frontmatter handler ''' + with open(f"{directory}/{filename}", "r") as f: + metadata, content = frontmatter.parse(f.read()) + return metadata + +# EVENT MODE + +def is_event_mode(): + return False + + + +# FLASK APP + +base_url = "si16" +notebooks = "notebooks" +projects = "projects" + + +# create flask application +app = Flask(__name__, + static_url_path=f'/soupboat/{base_url}/static', + static_folder=f'/soupboat/{base_url}/static') +Markdown(app, extensions=['extra']) + + + +# add the base_url variable to all the flask templates +@app.context_processor +def set_base_url(): + return dict(base_url = base_url) + +# Generate functions list +generate_function_list() + +# For specific pages we can build and link dedicated templates + + +# Homepage +@app.route(f"/{base_url}/") +def home_page(): + + # get the basic info of the website from the /contents/si16_info.md file + info = get_contents("si16_info.md").to_dict() + + + projects_list = [] + for project in dirnames("./projects"): + page = get_contents("documentation.md", f"./{projects}/{project}").to_dict() + page['slug'] = project + projects_list.append(page) + + + + # get the list of the projects, the functions, and the corpora + home = { + **info, + "projects": projects_list, + "functions": filenames("./notebooks"), + "corpora": dirnames("./static/corpora") + } + return render_template("home.html", **home) + + +# # About Page +# @app.route(f"/{base_url}/about/") +# def about_page(): +# about = get_contents('about.md') +# return render_template("about.html", title = about['title'], description = about['description'], contents=about.content) + +# For generic pages we can include a common template and change only the contents +@app.route(f"/{base_url}//") +def dynamic_page(slug = None): + try: + page = get_contents(f"{slug}.md").to_dict() + # page is a dictionary that contains: + # - all the attributes in the markdown file (ex: title, description, soup, etc) + # - the content of the md in the property 'content' + # in this way we can access those frontmatter attributes in jinja simply using the variables title, description, soup, etc + return render_template("page.html", **page) + except FileNotFoundError: + # TODO: a proper not found page + return render_template('404.html') + + + +# List of projects +@app.route(f"/{base_url}/projects/") +def projects_list(): + # get a list of the functions from the notebooks folder + projects_list = [] + for project in dirnames("./projects"): + page = get_contents("documentation.md", f"./{projects}/{project}").to_dict() + page['slug'] = project + projects_list.append(page) + + info = get_contents("projects.md").to_dict() + + # generate a link to each function + return render_template("projects.html", projects=projects_list, **info) + + +# Single project +@app.route(f"/{base_url}/projects//") +def p_info(project = None): + try: + + page = get_contents("documentation.md", f"./{projects}/{project}").to_dict() + + if 'showcases' in dirnames(f"./{projects}/{project}"): + page['showcases'] = [] + showcases_list = filenames(f"./{projects}/{project}/showcases/") + for showcase in showcases_list: + print(showcase) + info = get_meta(showcase + '.md', f"./{projects}/{project}/showcases/") + info['slug'] = showcase + page['showcases'].append(info) + + return render_template("project.html", **page) + except FileNotFoundError: + return render_template('404.html') + + +@app.route(f"/{base_url}/projects///") +def p_showcase(project = None, showcase = None): + print(project) + print(showcase) + try: + page = get_contents(f"{showcase}.md", f"./{projects}/{project}/showcases").to_dict() + return render_template('page.html', **page) + except FileNotFoundError: + return render_template('404.html') + return render_template('404.html') + +# List of functions +@app.route(f"/{base_url}/functions/") +def functions_list(): + + + info = get_contents("functions.md").to_dict() + + # get a list of the functions from the notebooks folder + functions = filenames("./notebooks") + + with open('./static/functions.json', 'r') as file: + functions = json.load(file) + + + # generate a link to each function + return render_template("functions.html", functions=functions, **info) + + +# Single Function page +@app.route(f"/{base_url}/functions//") +def f_info(function=None): + if function in filenames(f"./{notebooks}"): + fx = get_function(function, notebooks) + name, description, parameters, output = get_function_info(fx) + + # executing a notebook takes a lot of time mmm should we just send them without the results of the examples? or save it executed? +# documentation = get_notebook_contents(f"./{notebooks}/{function}.ipynb") + + documentation = get_notebook_md(f"./{notebooks}/{function}.ipynb") + + return render_template("function.html", title=name, description=description, parameters=parameters, output=output, documentation=documentation) + + # TODO: meaningful error code return + else: + return render_template('404.html') + + + +# Function API page + +@app.route(f"/{base_url}/api//") +def f_api(function=None): + if function in filenames(f"./{notebooks}"): + + fx = get_function(function, notebooks) + name, description, parameters, output = get_function_info(fx) + + query_params = [] + for param, tp in parameters: + a = request.args.get(param) + # cast the type of the argument to the type that the function requires + if tp == "list": + a = request.args.getlist(param, type=str) + else: + tp = locate(tp) + a = tp(a) + # print(a) + query_params.append(a) + return fx(*query_params) + + # TODO: meaningful error code return + return "mmmm there is no function with this name sorry" + + + +# TODO: maybe the event mode could be a decorator ? to avoid the request from the client every time and instead just do it in the server ? +# EVENT MODE +import mimetypes + +@app.route(f"/{base_url}/api/is-event-mode/") +def event_mode(): + if is_event_mode(): + event_path = '/static/event' + event = dirnames("./static/event") + page = request.values.get('page', '') + snippets = [] + if page in event: + snippets = [] + for entry in os.scandir(f".{event_path}/{page}"): + # add to the list only proper files + if entry.is_file(follow_symlinks=False): + snippet = { + "name": entry.name + } + + ty, enc = mimetypes.guess_type(entry.name) + + if 'text' in ty: + snippet['type'] = 'text' + with open(f".{event_path}/{page}/{entry.name}", 'r') as f: + content = f.read() + snippet['content'] = content + elif 'image' in ty: + snippet['type'] = 'image' + snippet['content'] = f"{event_path}/{page}/{entry.name}" + elif 'video' in ty: + snippet['type'] = 'video' + snippet['content'] = f"{event_path}/{page}/{entry.name}" + elif 'audio' in ty: + snippet['type'] = 'audio' + snippet['content'] = f"{event_path}/{page}/{entry.name}" + + snippets.append(snippet) + return {"event": True, "snippets": snippets} + return {"event": True} + return {"event": False} + + + + + + +# PROJECTS API pages +# custom section =========== +# warning mothership reporting +# we will add here the custom endpoints for each subgroup project + + + +# 2MB max for file upload (we can change this) +app.config['MAX_CONTENT_LENGTH'] = 2 * 1000 * 1000 + +@app.route(f"/{base_url}/annotation-compass/", methods=['GET','POST']) +def annotation_compass(): + if request.method == 'POST': + # Upload new file + ac.upload_file(request) + images = ac.list_images() + return render_template('annotation-compass.html', title='Annotation Compass', images=images) + +@app.route(f"/{base_url}/annotation-compass/annotate//") +def annotate_image(image=None): + print(app.static_url_path, app.static_folder) + description = '' + try: + description = ac.get_image_description(image) + except: + print('there is no description') + return render_template('annotate_image.html', image=image, description=description) + +@app.route(f"/{base_url}/annotation-compass/add-label/", methods=['GET','POST']) +def insert_label(): + if request.method == 'POST': + return ac.insert_label(request) + +@app.route(f"/{base_url}/annotation-compass/get-labels//") +def get_labels_list(image=None): + return ac.get_labels_list(image) + + + + + + + + + + + +# JIAN API + +def generate_urls(elements): + a_list='' + for element in elements: + url=f'https://hub.xpub.nl/soupboat/individual-maps/{element}/' + a = f'{element}
' + a_list = a_list + a + return a_list + +@app.route(f"/{base_url}/api/label/rejection/individual_map/") +def individual_map(): + + image = 'xpub1_rotterdam_map_1400px.jpg' + url = f"https://hub.xpub.nl/soupboat/generic-labels/get-labels/?image={image}" + response = urlopen(url) + data_json = json.loads(response.read()) + + all_userIDs = [] + for label in data_json['labels']: + all_userIDs.append(label['userID']) + set_userIDs = set(all_userIDs) + + im = get_function('individual_map', notebooks) + + individual_labels = im(data_json['labels'], ['5058763759','5941298752']) + + to_html = get_function('html_tag', notebooks) + result = to_html(individual_labels, True, True, True, True) + + return result + + +@app.route(f"/{base_url}/projects/map/rejection_map/") +def rejection_map(): + return render_template('rejection_map.html') + + + +# =============== +# Error handlers! +@app.errorhandler(400) +def error_400(e): + # bad request or invalid url + return render_template('400.html'), 400 + +@app.errorhandler(403) +def error_403(e): + # forbidden (for invalid key) for evemt mode when it's not the 17th of the month + return render_template('403.html'), 403 + +@app.errorhandler(404) +def error_404(e): + # page not found + return render_template('404.html'), 404 + +@app.errorhandler(500) +def error_500(e): + # internal server error + return render_template('500.html'), 500 + +@app.errorhandler(502) +def error_502(e): + # bad gateaway + return render_template('502.html'), 502 + +@app.errorhandler(503) +def error_503(e): + # service temporarily unavailable, for secret breaks + return render_template('503.html'), 503 + +@app.errorhandler(504) +def error_503(e): + # ???????? gateway timeout shall we put it????? + return render_template('504.html'), 504 + + + +# RUN + +app.run(port="3131") diff --git a/static/.ipynb_checkpoints/functions-checkpoint.json b/static/.ipynb_checkpoints/functions-checkpoint.json new file mode 100644 index 0000000..1793b58 --- /dev/null +++ b/static/.ipynb_checkpoints/functions-checkpoint.json @@ -0,0 +1 @@ +{"functions": [{"title": "vernacular_map", "description": "A nice and intresting function"}, {"title": "text_file_to_blob", "description": null}, {"title": "shout", "description": "Repeat the vowels in a string for a specified number of times"}, {"title": "reverse", "description": "Reverse the input sentence by sentence"}, {"title": "cocktail_generator", "description": "randomly chooses ingredients from a menu for a nice cocktail recipe"}, {"title": "blob_to_excerpts_list", "description": null}, {"title": "respell", "description": null}, {"title": "mashup", "description": null}, {"title": "reveal", "description": null}, {"title": "repeat", "description": "Repeat a string for a specified number of times"}, {"title": "highlight_map", "description": "A nice and intresting function"}, {"title": "individual_map", "description": "You wont believe to this function"}, {"title": "bridge", "description": "You wont believe to this function"}, {"title": "add_target_info", "description": null}, {"title": "area_map", "description": "A super useful function"}, {"title": "stich", "description": null}, {"title": "input-back-to-text", "description": "You wont believe to this function"}, {"title": "target_map", "description": "A super useful function"}, {"title": "ghost_map", "description": "A nice and intresting function"}, {"title": "html_tag", "description": "A super useful function"}]} \ No newline at end of file diff --git a/static/corpora/sample-uncontaminated/sample-uncontaminated.txt b/static/corpora/sample-uncontaminated/sample-uncontaminated.txt new file mode 100644 index 0000000..2608252 --- /dev/null +++ b/static/corpora/sample-uncontaminated/sample-uncontaminated.txt @@ -0,0 +1,13 @@ +etcetera = ['et cetera', ' etc ', ' etc.', '...', '[...]', '[. ...]', 'and-so-on', 'and-so-forth', 'and others', 'et al.', 'and all the rest', 'and on and on', 'along with others’, ‘blablabla’, ‘and much more’] + +Late afternoon, it has been made official by the authorities: the building has to close. No more access will be granted to anyone. The enumeration has been too fast, too sudden and has reached an unprecedented amount of individuals. The clouds froze, the grass faded down, the branches broke into pieces, the ducks scattered in pounds with no bottom, the birds fell mid-air, and much more… Or not exactly like that. But it felt as such. No one could have predicted it, yet, it happened. By lack of time, a lot of things had to be left aside. “Isolated, between two circles (…) On the news, a lot seems to be left out.” Maybe it is due to a lack of information… Or maybe they are trying to save up some for the days to come. Andrew sent us a message on our Canada group chat: “Canada releases 50 million pounds from maple syrup reserve amid global shortage”. Canada is at the heart of the world’s maple syrup supply chain and they seem to know more than the rest of us, for the supply hasn’t ceased! They have been stocking up maple syrup, in case of a crisis. How amazed was I to hear: the world might never run out of maple syrup! At least not before a few more international crisis. +Some might think “is the maple syrup industry responsible?!” and others might think this nonsense is bigger than us. One might wonder: “how did it all turned to such an unfamiliar pattern so quickly?”. One does wonder, one wonders everyday. One has infiltrated books, essays, articles, comments, written shows, made documentaries, recorded podcasts, songs, etc… Is there anything left to say? How will the rest of us get a hold of it? Is it chaos or a natural occurrence? Is it oblivion, tyranny or cheer contingency? + +No one ever came to the end of it, and whenever one tries, something else comes and interrupts it. We run out of time, run out of space. Curate speech, classify facts, choose references, ignore others and this goes on and on and on. You might see it on paper or even in a train station… The other day, I was getting in the train to go back to Amsterdam. At the Rotterdam Centraal station, on my way to my favourite seat (I like to sit next to the luggage racks, so there is no one in vis-à-vis to me) I overhear a conversation between a woman talking with an elderly man sitting next to her: “Do you need to pay something on this train?” “Oh yes, did you not get the toeslag?” “No, no.”. By the time I take my seat, she stands up, without a coat nor a bag, the chipkaart from the elderly man in hand and goes to the perron in order to pay the toeslag on the machine dedicated for that matter. The first one she tries is in front of my window I want to shout “you just checked yourself out! This is not the right machine!” (I did that once myself, very upsetting). She looks back at it startled, tries again. Still not working. She realises her mistake. Runs to the over side. By the time she paid the man’s toeslag the train’s doors close. I see her run to one door, then try another, but it’s too late, the train is leaving. I stand up, so surprised by what is happening in front of me, speechless. She stands there, with the chipkaart in her hand, without a bag nor a coat. And the train leaves and all the rest is unknown to my keyboard. +What made this story’s interruption? The train’s departure? My incapacity at imagining what could have happened else? My unwillingness at citing options, possibilities, opportunities? Did they even know each other? Or was this a good action gone bad? How do you explain such an acte manqué to anyone? Some stories have no backside. Some stories are made to be chopped off, distributed away, never fully grasped. Some stories you feel you know, you probably do, without ever having read yourself. For it’s just here, hanging in the air, contaminating your mind and much more without you knowing about it. + +There is a cherry without a pit in my eye, a lemon with no skin in your hand, a soap-shaped potato in your bathroom, a wrinkled puppy dog on your laps, a coverless book on the street, a virgin cocktail with integrity, an alcoholic beverage with ethic, a street-lamp with grain, a low-quality screen in the spa’s waiting room, some butterflies with no wings, lady-bugs with nails, chairs with feet, legs with hairs, nose without nostrils, mouth with no breath, inspiration without context, structures of defamation, a bald kid with hair, a kettle with blisters, a father with a sister, a sibling with temperament, a ramp with no wheels, flowers within a vase in a vase, a sight with no red, a sight with no blue, a sight with no green, a steel of humidity, a stain of clumsiness, some oracle’s statue, and much more. For there is no limit to the associations one can make within language, and no boundaries as to how you, whose eyes are actively running along the page, will read those associations, and make new ones out of them. Yet, I stopped my listing in the midd… Let me guess. You like to dance? Sing? Draw a bit on the side, have many hobbies but are no good at any of them? Or at least pretend so? You are unmentioned, yet full of references, like to shine, but only when invited to do so, like to be alone, but not lonely. Highly capable and naturally lazy, creative and bored, funny and awkward, blablabla. You know what? Really, you are too preoccupied. You know what? Really, you are too full of yourself. You know what? Really, you are too tired. You know what? Really, your head is in the clouds. You know what? Really, your head is in the screens. You know what? Really, your screen is full of heads. You know what? Really, your screen is full of heads in the clouds. You know what? Really, your screen is full of tired heads in the clouds. You know what? Really, your screen is full of tired heads in the cloud that are full of themselves. You know what? You are too preoccupied… + +Some thoughts have been scratching my throat lately. It’s not the c-word I promise. I wake up in the morning, and as if the compilation of dreams have reached the top of my body, I burst in coughs, spit out sounds of fury, trying to take shape, say something, but I take two paracetamols, 1L of ginger tea, some thyme drops and the words are swallowed back into my stomach. They’ve tried to contaminate the outside, but I keep them inside, safe, where no one can reach them. They try to invade others, once in a while, they manage a smooth escape. Yes, sometimes I just can’t shut up, the scratch reaches my lips, and spits onto one, that makes two and two brings it to four, four to eight and all the rest is history. +We don’t appreciate what is within our guts, the acids that are at work, the pumping trying to stay on pace, the foreign items being assimilated in order to keep everything working. “We do not talk of what is on the other side [. …] The only things we mention are the ones who come out of us, which we suddenly do not feel anymore but can witness.” It’s a strange thing we do not share what is closest to us, which we might think is the easier to describe due to proximity. On the contrary, when one does not see or smell or taste, one doesn’t trust the feeling. It might be yours, but you’d rather leave it out, in order to focus on what is to come. For you have no proof of your feeling until it comes out. And then you might mention it, but really you want to disregard that feeling as fast as you can, roll it aside and not mention it, just one thing amongst others, not worth mentioning. Those can be many things: there was mitvo, there was oop, eep, rhoeadiar, stip and storn, sewats, irsha, dead niks, etc. +In the area called Te-ecetra, there is a cat on a tree eating a treat, drinking a tea, he got a cart full of rats and the tracks trace back to tac-tics and tic-tacs. The cat is known in Te-ecetra, for being fond of tea and treats like English people are fond of afternoon teas and biscuits. The cat is always seen carrying a cart full of rats, that leave traces around trees. For in order to enjoy his teas and treats, the cat needs to be high in trees, so not to trigger the rats in the cart, with the sight of tip-top teas and treats. Then alone on the top of his trees, the cat can peacefully, think for hours, days sometimes weeks, how good it is to be a cat in a tree, with a cart full of rats, enjoy teas and treats, in a remote area, while others might no be able to be like the cat in a tree, with a cart full of rats, et cetera, et cetera. \ No newline at end of file diff --git a/static/css/.ipynb_checkpoints/function-checkpoint.css b/static/css/.ipynb_checkpoints/function-checkpoint.css new file mode 100644 index 0000000..5320910 --- /dev/null +++ b/static/css/.ipynb_checkpoints/function-checkpoint.css @@ -0,0 +1,233 @@ +h3, +h2 { + margin-top: 0; +} + +.description { + grid-column: 1 / span 2; +} + +.function-io, +.endpoints, +.playground { + margin: 30px 0; +} + +.playground, +.playground-input, +.playground-output, +.notebook { + grid-column: -1 / 1; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-column-gap: 30px; +} + +.function-io { + grid-column: 1 / -1; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + place-items: start; + grid-gap: 30px; +} + +.function-io > * { + width: 100%; + height: 100%; +} + +.function-io .input, +.function-io .output, +.playground .input { + background-color: white; + aspect-ratio: 1; + border-radius: 50%; +} + +.function-io h3 { + margin: 0; +} + +.function-io ul { + font-family: "Necto"; + list-style: none; + padding: 0; +} + +.endpoints { + grid-column: 1 / -1; +} + +.endpoints code { + background-color: white; + margin: 30px 0; + white-space: initial; +} + +.endpoints .example { + margin: 15px 0; +} + +.playgroud-input .input { + grid-column: 1 / span 1; + align-self: center; +} + +.playground-output .output { + grid-column: 2 / span 2; + background-color: white; + border-radius: 12px; + padding: 12px; + min-height: calc(var(--text) * 2); +} + +.playground label { + display: block; +} + +.playground * + label { + margin-top: 24px; + margin-bottom: 6px; +} + +.playground input[type="submit"] { + margin-top: 30px; +} + +/* .notebook code { + position: relative; + grid-column: 1 / -1; + z-index: 100; +} + +pre.prettyprint.prettyprinted { + border: none; + position: relative; +} + +pre.prettyprint.prettyprinted::after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 460px; + height: 460px; + background-color: white; + border-radius: 50%; +} */ + +.notebook { + width: 100%; + /* margin-top: 60px; */ + /* padding-top: 60px; */ + /* border-top: 1px solid currentColor; */ +} + +.notebook h1::before { + content: "Documentation: "; +} + +.notebook p { + grid-column: span 2; + text-indent: 0; +} + +.notebook pre { + white-space: pre-wrap; + grid-column: 1 / -1; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-gap: 30px; +} + +.notebook .language-python { + grid-column: 1 / span 2; + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + white-space: pre; + background: none; + padding: 0; + z-index: 100; + min-height: 400px; +} + +.notebook .language-python::after { + content: ""; + position: absolute; + z-index: 0; + top: 0; + aspect-ratio: 1; + height: 100%; + border-radius: 50%; + background-color: white; + mix-blend-mode: color; + pointer-events: none; +} + +.notebook h1 { + +grid-column: 1 / -1; +} + + +.notebook p { + margin: 30px 0; + grid-column: 2 / span 2; +} + +.notebook p img { +display: block; +} + +.notebook code { + grid-column: 2 / span 2; + align-self: flex-start; + background-color: white; + padding: 12px; + border-radius: var(--radius); +} + +.notebook h2 { + grid-column: 1/-1; +} + +.notebook img { + margin: 30px 0; +} + +.notebook > * + * { + margin-top: 30px; +} + +@media (max-width: 767.98px) { + .playground, + .playground-input, + .playground-output, + .notebook, + .function-io, + .notebook pre { + display: block; + } + + .function-io .input, + .function-io .output, + .playground .input { + background: none; + aspect-ratio: auto; + } + + .playground-output { + margin-top: 30px; + } + + .page-content > * + * { + margin-top: 60px; + } + + .notebook .language-python { + min-height: 300px; + white-space: pre-wrap; + } +} diff --git a/static/css/.ipynb_checkpoints/global-checkpoint.css b/static/css/.ipynb_checkpoints/global-checkpoint.css new file mode 100644 index 0000000..764e324 --- /dev/null +++ b/static/css/.ipynb_checkpoints/global-checkpoint.css @@ -0,0 +1,343 @@ +html, +body { + margin: 0; + box-sizing: border-box; + background-color: var(--background); + + font-family: var(--font); + font-size: var(--text); + line-height: 1.4; + overflow-x: hidden; +} + +h1, +h2, +h3 { + font-family: var(--font); + font-weight: bold; + font-style: italic; +} + +h1 { + font-size: var(--title); + margin: 0; +} +h2, +h3 { + font-size: var(--text); +} + +a { + color: currentColor; +} + +ol, ul{ + +padding-left: 0; +} + +ul { + list-style: none; +} + +ul li::before { + content: "–"; +} + +li > ul, +li > ol, +{ +padding-left: 12px; + color: red; +} + + + + + +code, +pre { + font-family: "Necto"; + border: none; + white-space: break-spaces; +} + +input { + font-family: var(--font); + font-size: var(--text); + padding: 6px; + border: 1px solid currentColor; + border-radius: 6px; +} + +button, +input[type="submit"] { + font-family: var(--font); + font-size: var(--text); + font-weight: bold; + font-style: italic; + background-color: white; + border: 1px solid currentColor; + padding: 6px; + border-radius: 12px; + transform: scale(1); + transition: transform 0.3s ease-out; + cursor: pointer; +} + +button, +input[type="submit"]:active { + transform: scale(0.95); + transition: transform 0.1s ease-in; +} + +/* STICKER CONTAINER */ + +#sticker-container { + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; + + pointer-events: none; + + z-index: 100; + + min-height: 100vh; + height: 100%; +} + +#sticker-fix-container { + position: fixed; + left: 0; + top: 0; + bottom: 0; + right: 0; + + pointer-events: none; + + z-index: 300; + + min-height: 100vh; + height: 100%; +} + +.sticker { + position: absolute; + user-select: none; + border: 1px solid currentColor; + border-radius: var(--radius); + white-space: nowrap; + background-color: white; + font-size: 18px; + padding: 0 6px; + box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); + text-decoration: none; + + overflow-wrap: break-word; +} + +*[data-sticker] { + position: relative; +} + +/* HEADER AND NAV */ + +.page--header { + position: fixed; + z-index: 200; + + top: 60px; + left: 50%; + transform: translate(-50%, 0); + + width: calc(100% - 2 * var(--app-margin)); + max-width: var(--content-width); + padding: 0 var(--app-margin); + + display: flex; + justify-content: center; +} + +header { + flex-grow: 1; + flex-shrink: 1; + + display: flex; + flex-direction: column; + justify-content: center; + + border: 1px solid currentColor; + border-radius: var(--radius); + background-color: var(--background); + box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.25); + height: 48px; /* comment this in page with multiple elements in the header */ + flex-basis: 48px; + + padding: 0px 12px; +} + +.page--header .title { + /* flex-grow: 0; */ + /* flex-shrink: 1; */ + /* line-height: 1; */ + margin: 0; +} + +.page--header .subtitle { + line-height: 1; + margin: 6px 0; +} + +nav { + margin-left: 12px; +} + +.page--header nav a { + display: inline-block; + width: 48px; + height: 48px; + border-radius: 50%; + border: 1px solid currentColor; + background-color: var(--background); + margin: 0; +} + +.page--header nav a + a { + margin-left: 6px; +} + +/* FOOTER */ + +.page--footer { + position: relative; + bottom: var(--app-margin); + + width: calc(100% - 2 * var(--app-margin)); + max-width: var(--content-width); + padding: 0 var(--app-margin); + + left: 50%; + transform: translate(-50%, 0); +} + +footer { + margin-top: 90px; + margin-bottom: 30px; + + padding: 6px 12px; + border: 1px solid currentColor; + border-radius: var(--radius); + + font-weight: bold; + font-style: italic; +} + +/* MAIN CONTENTS */ + +.page--content { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-column-gap: var(--app-margin); + align-items: baseline; + + max-width: var(--content-width); + padding: 0 var(--app-margin); + margin: 0 auto; + margin-top: 180px; +} + +.page--content p { + grid-column-end: span 2; + + margin: 0; + + text-indent: calc(var(--text) * 2); + line-height: 1.4; +} + +.page--content h2 { + font-size: var(--title); + margin: 0; + margin-top: calc(var(--app-margin) * 3); + margin-bottom: var(--app-margin); +} + +.page--content > * + * { + margin-top: var(--app-margin); +} + +.page--content img { + grid-column-end: span 2; + width: 100%; + margin: 60px 0; + border-radius: var(--radius); + border: 1px solid currentColor; +} + +/* GRID functional classes sorry this is not good at all but.... */ + +.c2 { + grid-column-end: span 2; +} + +.s1 { + grid-column-start: 1; +} + +.s2 { + grid-column-start: 2; +} + +/* Medium screens */ + +@media (max-width: 991.98px) { + /* HEADER MOBILE */ + + .page--header { + top: 30px; + } + + header { + min-height: 42px; + } + + .page--header .title { + font-size: 24px; + } + + .page--header .subtitle { + font-size: 21px; + } + + .page--header nav a { + width: 48px; + height: 48px; + } + + /* MAIN CONTENTS */ + + .page--content { + margin-top: 120px; + } +} + +@media (max-width: 767.98px) { + .page--content { + display: block; + } + + .page--content h2 { + margin-top: 60px; + } + + ul, ol { + list-style-position: inside; + } +} + + +.highlight { + color: blue; +} \ No newline at end of file diff --git a/static/css/.ipynb_checkpoints/home-checkpoint.css b/static/css/.ipynb_checkpoints/home-checkpoint.css new file mode 100644 index 0000000..f9adba2 --- /dev/null +++ b/static/css/.ipynb_checkpoints/home-checkpoint.css @@ -0,0 +1,95 @@ +.sticker { + font-size: var(--text); + pointer-events: all; +} + +.index { + margin: calc(var(--app-margin) * 2); +} + +.sheet + .sheet { + margin-top: var(--app-margin); +} + +.sheet h3 a { + text-decoration: none; +} + + +.negative { + position: relative; +/* visibility: hidden; */ + color: rgba(0,0,0,0.2); + text-decoration: none; + cursor: pointer; + line-height: 48px; + + + + background-color: rgba(0, 0, 0, 0.075); +/* background-color: var(--background); */ + border-radius: var(--radius); + padding: 3px 12px; + margin: 12px 0; +} + +/* .negative:after { + visibility: visible; + content: ""; + background-color: rgba(0, 0, 0, 0.075); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: var(--radius); +} */ + +.sheet > p { + display: inline-block; + margin: 6px 0; +} + +h1.negative { + display: table; +} + +.meta > h2 { + display: inline-block; + margin: 6px 0; +} + +.sheet .section { + padding: 0; + margin: 0; + margin-bottom: 6px; + + font-size: var(--title); + color: rgba(0, 0, 0, 0.1); +} + +.chat-link { + position: absolute; + z-index: 1000; + top: 60px; + right: 60px; + + background-color: springgreen; + border: 1px solid currentColor; + border-radius: 12px; + padding: 0 12px; + + text-decoration: none; + + font-weight: bold; + font-style: italic; + transform: scale(1); + transition: transform 0.2s ease-in; + +} + +.chat-link:hover{ + transition: transform 0.1s ease-out; + transform: scale(1.025); +} + diff --git a/static/css/.ipynb_checkpoints/intro-checkpoint.css b/static/css/.ipynb_checkpoints/intro-checkpoint.css new file mode 100644 index 0000000..c5d267d --- /dev/null +++ b/static/css/.ipynb_checkpoints/intro-checkpoint.css @@ -0,0 +1,33 @@ +:root { + --background: white!important; +} + +.page--content p { +grid-column: 1 / span 2; + +} + +.bubble + .bubble { + margin-top: 30px; +} + +.bubble:nth-child(2n + 2) { +/* background-color: var(--orange); */ + grid-column-start: 1; +} + + +p.bubble { + grid-column-start: 2; + margin: 30px 0; + border: 1px solid currentColor; + padding: 12px; + border-radius: var(--radius); + text-indent: 0; + justify-self: start; +} + +.page--content p.intro { + text-indent: 0; + margin-bottom: 30px; +} diff --git a/static/css/.ipynb_checkpoints/jian-checkpoint.css b/static/css/.ipynb_checkpoints/jian-checkpoint.css new file mode 100644 index 0000000..82eb019 --- /dev/null +++ b/static/css/.ipynb_checkpoints/jian-checkpoint.css @@ -0,0 +1,27 @@ +html, +body { + margin: 0; + font-family: 'Courier New'; + width: 100%; + overflow: hidden; + background-color: rgb(180, 180, 180) ; +} + + +.highlight { + background-color: rgba(0, 150, 255, 0.6); + text-shadow: 0 0 0px black; +} + + +.lowlight { + background-color: rgba(0, 0, 255, 0); + color: black; + text-shadow: 0 0 0px black; +} + + +.ghost { + color: black; + text-shadow: 0 0 0px black; +} \ No newline at end of file diff --git a/static/css/.ipynb_checkpoints/page-checkpoint.css b/static/css/.ipynb_checkpoints/page-checkpoint.css new file mode 100644 index 0000000..6bb0f82 --- /dev/null +++ b/static/css/.ipynb_checkpoints/page-checkpoint.css @@ -0,0 +1,37 @@ + + +.page--content pre { + grid-column: span 2; +} + + +.page--content h2 { + grid-column: 1 / -1; +} + + .page--content h2:first-of-type{ + margin-top: 0px; + } + + .page--content h3 { + grid-column: 1 / span 1; + } + + .page--content ul, + .page--content ol { + grid-column: 2 / span 2; + } + + .page--content li { + margin-top: 12px; + } + + + + .page--content p { + grid-column: 2 / span 2; + } + +.page--content p img { +display: block; +} diff --git a/static/css/.ipynb_checkpoints/project-checkpoint.css b/static/css/.ipynb_checkpoints/project-checkpoint.css new file mode 100644 index 0000000..190528d --- /dev/null +++ b/static/css/.ipynb_checkpoints/project-checkpoint.css @@ -0,0 +1,48 @@ +.page--content .project-link { + + grid-column: 1 / -1; + place-self: center; + display: inline-block; + border: 1px solid currentColor; + width: 300px; + height: 300px; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + text-decoration: none; + font-weight: bold; + font-style: italic; + + margin: 60px 0; + } + + .project-link:hover{ + background-color: white; + } + +.page--content .description { + +grid-column: 1 / span 2; + +} + +.page--content pre { + +grid-column: 2 / span 2; +} + +.page--header header{ +height: auto; + +} + +.page--content p { +position: relative; + +} + +.page--content p img { +display: block; + +} \ No newline at end of file diff --git a/static/css/.ipynb_checkpoints/tos-checkpoint.css b/static/css/.ipynb_checkpoints/tos-checkpoint.css new file mode 100644 index 0000000..88990f1 --- /dev/null +++ b/static/css/.ipynb_checkpoints/tos-checkpoint.css @@ -0,0 +1,4 @@ + .page--content p:first-of-type { + grid-column: 1 / span 2; + margin-bottom: 60px; + } \ No newline at end of file diff --git a/static/css/.ipynb_checkpoints/variables-checkpoint.css b/static/css/.ipynb_checkpoints/variables-checkpoint.css new file mode 100644 index 0000000..9e1d585 --- /dev/null +++ b/static/css/.ipynb_checkpoints/variables-checkpoint.css @@ -0,0 +1,24 @@ +@import url("/static/font/font.css"); + +:root { + --blue: #9edae2; + --pink: #f7d8e8; + --orange: #ffc496; + --yellow: #f9f5b0; + --green: #9fd3a8; + + --content-width: 1440px; + --radius: 12px; + --background: var(--yellow); + --font: "Pirelli"; + --title: 36px; + --text: 24px; + --app-margin: 30px; +} + +@media (max-width: 991.98px) { + :root { + --app-margin: 18px; + --text: 21px; + } +} diff --git a/static/css/annotation-compass/.ipynb_checkpoints/annotation-compass-checkpoint.css b/static/css/annotation-compass/.ipynb_checkpoints/annotation-compass-checkpoint.css new file mode 100644 index 0000000..7a722f7 --- /dev/null +++ b/static/css/annotation-compass/.ipynb_checkpoints/annotation-compass-checkpoint.css @@ -0,0 +1,61 @@ +.cards{ + grid-column: 2 / span 2; +/* display: flex; + flex-wrap: wrap; + justify-content: space-between; */ + + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-gap: var(--app-margin); +} + +.card-image{ + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + font-size: 16px; + font-weight: bold; + font-style: italic; +} + +.card-image{ +word-break: break-all; +text-align: center; +} + +.cards .card-image .thumb { +width: 96px; +height: 96px; +object-fit: contain; +border: none; +border-radius: 0; +margin: 0; +} + +@media (max-width: 991.98px) { + + .cards { + display: block; + padding: 0; + } + + .card-image{ + flex-direction: row; + justify-content: flex-start; + text-align: left; + } + + figure { + margin: 12px 0; + } + + .cards .card-image .thumb { + width: 64px; + height: 64px; + border-radius: 0; + margin-right: 12px; + } + +} \ No newline at end of file diff --git a/static/css/annotation-compass/annotation-compass.css b/static/css/annotation-compass/annotation-compass.css new file mode 100644 index 0000000..7a722f7 --- /dev/null +++ b/static/css/annotation-compass/annotation-compass.css @@ -0,0 +1,61 @@ +.cards{ + grid-column: 2 / span 2; +/* display: flex; + flex-wrap: wrap; + justify-content: space-between; */ + + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-gap: var(--app-margin); +} + +.card-image{ + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + font-size: 16px; + font-weight: bold; + font-style: italic; +} + +.card-image{ +word-break: break-all; +text-align: center; +} + +.cards .card-image .thumb { +width: 96px; +height: 96px; +object-fit: contain; +border: none; +border-radius: 0; +margin: 0; +} + +@media (max-width: 991.98px) { + + .cards { + display: block; + padding: 0; + } + + .card-image{ + flex-direction: row; + justify-content: flex-start; + text-align: left; + } + + figure { + margin: 12px 0; + } + + .cards .card-image .thumb { + width: 64px; + height: 64px; + border-radius: 0; + margin-right: 12px; + } + +} \ No newline at end of file diff --git a/static/css/annotation-compass/individual-map.css b/static/css/annotation-compass/individual-map.css new file mode 100644 index 0000000..9120f8f --- /dev/null +++ b/static/css/annotation-compass/individual-map.css @@ -0,0 +1,322 @@ +html, +body { + margin: 0; + font-family: 'Courier New'; + width: 100%; + overflow: hidden; + background-color: grey ; +} + + +.red { + color: red; +} + +.blur { + text-shadow: 0 0 8px #000; +} + +.red-blur { + color: red; + text-shadow: 0 0 8px red; + text-decoration: underline; + +} + +.background-color { + background-color: rgba(255, 0, 0, 0.6); + text-shadow: 0 0 8px black; + +} + + + + + + + +.test-form { + position: fixed; + top: 0; + left: 0; + z-index: 500; +} + +#container { + width: 100%; + height: 100vh; + background-color: #fff; +} + +#editor { + position: absolute; + display: none; + border: 1px solid tomato; + opacity: 0.5; + width: 0; + height: 0; + z-index: 100; +} + +#editor.can-draw { + opacity: 1; +} + +#editor.show-editor { + display: block; +} + +.label { + position: absolute; + + + overflow: hidden; +} + +.label.temporary { + background: none; + /* border: 1px dashed tomato; */ + box-shadow: none; + overflow: visible; +} + +.label.temporary form { + width: 100%; + height: 100%; +} + +.label.temporary textarea { + width: 100%; + height: 100%; + padding: 1ch; + border: none; + background-color: rgba(255, 255, 255, 0.6); +} + +.label.temporary textarea:focus { + outline: 1px dashed tomato; +} + +.label.temporary button { + margin-top: 4px; +} + +.label.temporary button + button { + margin-left: 4px; +} + +.label.temporary .label--number, +.label.temporary .label--close { + display: none; +} + +.label--number { + display: inline-block; + margin: 0; + padding: 0 4px; + + user-select: none; + + background-color: white; +} + +.label--close { + position: absolute; + right: 0; + + border: none; + + padding: 0 4px; + + font-size: 1rem; + + background: none; + color: white; + + cursor: pointer; +} +.label--text { + margin: 1ch 0; + padding: 0 1ch; + + overflow: hidden; + width: 100%; + height: 100%; + text-overflow: ellipsis; + white-space: pre; +} + +.text-input { + display: none; + position: absolute; + z-index: 200; + width: 100%; + height: 100vh; + + justify-content: center; + align-items: center; + + background-color: rgba(255, 99, 71, 0.95); +} + +.text-input.visible { + display: flex; +} + +.modal { + padding: 64px; +} + +.modal input { + font-size: 1.5rem; + background: none; + border: none; + color: white; + border-bottom: 1px solid white; +} + +.modal input:focus { + outline: none; + background-color: rgba(255, 255, 255, 0.25); +} + +.text-input button { + color: white; + font-weight: bold; + background: none; + border: none; + cursor: pointer; + font-size: 1.5rem; +} + +#cancel { + font-weight: normal; +} + +.background-container { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + display: flex; + flex-direction: column; +} + +.background-container img { + max-width: 70w; + max-height: 70vh; + object-fit: contain; + user-select: none; + pointer-events: none; +} + +.background-container img.visible { + display: initial; +} + +.hidden { + display: none; +} + +.info, +.transcription { + position: absolute; + right: 0; + bottom: 0; + top: 0; + z-index: 50; + + padding: 24px; + margin: 0; + + width: 25%; + line-height: 1.6; + + background-color: #111; + color: white; + + transform: translateX(100%); + transition: transform 0.4s ease-out; +} + +.transcription.active, +.info.active { + transform: translateX(0); + transition: transform 0.6s ease-in; +} + +.transcription .title, +.info .title { + margin: 0; +} + +.transcription ol { + padding: 0; + list-style-position: inside; + font-size: 1.125rem; +} + +#show-info, +#show-transcription, +.close, +button { + background: none; + + display: inline-block; + min-width: 24px; + height: 24px; + border-radius: 24px; + padding: 0 4px; + + border: 1px solid currentColor; + + color: tomato; + + cursor: pointer; +} + +#show-transcription:hover, +#show-info:hover { + border: 1px solid tomato; + background-color: tomato; + color: white; +} + +.close { + position: absolute; + right: 24px; + top: 32px; + color: white; +} + +#export-text:hover, +.close:hover { + border: 1px solid white; + background-color: white; + color: #111; +} + +#export-text { + color: white; +} + +nav { + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 50; + + padding: 24px; + text-align: right; + + pointer-events: none; +} + +nav > * { + pointer-events: all; +} + +img.hidden { + display: none; +} diff --git a/static/css/annotation-compass/style.css b/static/css/annotation-compass/style.css new file mode 100644 index 0000000..e42333c --- /dev/null +++ b/static/css/annotation-compass/style.css @@ -0,0 +1,337 @@ +html, +body { + margin: 0; + font-family: Arial, Helvetica, sans-serif; + width: 100%; + overflow: hidden; +} + +.test-form { + position: fixed; + top: 0; + left: 0; + z-index: 500; +} + +#container { + position: absolute; + left: 50%; + top: 50%; + + transform: translate(-50%, -50%); + width: 90vw; + height: 90vh; + + padding: 0; +} + +#editor { + position: absolute; + display: none; + border: 1px solid tomato; + opacity: 0.5; + width: 0; + height: 0; + top: 0; + left: 0; + z-index: 150; + pointer-events: none; +} + +#editor.can-draw { + opacity: 1; +} + +#editor.show-editor { + display: block; +} + +.label { + position: absolute; + background-color: rgba(250, 99, 72, 0.2); + /* border: 1px solid currentColor; */ + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.2); + + overflow: hidden; +} + +.label.temporary { + background: none; + /* border: 1px dashed tomato; */ + box-shadow: none; + overflow: visible; +} + +.label.temporary form { + width: 100%; + height: 100%; +} + +.label.temporary textarea { + width: 100%; + height: 100%; + padding: 1ch; + border: none; + background-color: rgba(255, 255, 255, 0.6); +} + +.label.temporary textarea:focus { + outline: 1px dashed tomato; +} + +.label.temporary button { + margin-top: 4px; +} + +.label.temporary button + button { + margin-left: 4px; +} + +.label.temporary .label--number, +.label.temporary .label--close { + display: none; +} + +.label--number { + display: inline-block; + margin: 0; + padding: 0 4px; + + user-select: none; + + background-color: white; +} + +.label--close { + position: absolute; + right: 0; + + border: none; + + padding: 0 4px; + + font-size: 1rem; + + background: none; + color: white; + + cursor: pointer; +} +.label--text { + margin: 1ch 0; + padding: 0 1ch; + + overflow: hidden; + width: 100%; + height: 100%; + text-overflow: ellipsis; + overflow-y: auto; + white-space: pre-line; +} + +.text-input { + display: none; + position: absolute; + z-index: 200; + width: 100%; + height: 100vh; + + justify-content: center; + align-items: center; + + background-color: rgba(255, 99, 71, 0.95); +} + +.text-input.visible { + display: flex; +} + +.modal input { + font-size: 1.5rem; + background: none; + border: none; + color: white; + border-bottom: 1px solid white; +} + +.modal input:focus { + outline: none; + background-color: rgba(255, 255, 255, 0.25); +} + +.text-input button { + color: white; + font-weight: bold; + background: none; + border: none; + cursor: pointer; + font-size: 1.5rem; +} + +#cancel { + font-weight: normal; +} + +.background-container { + width: 100%; + height: 100%; + margin: 0; +} + +#target { + position: absolute; + top: 0; + left: 0; + width: 0; + height: 0; + + left: 50%; + top: 50%; + + transform: translate(-50%, -50%); +} + +.background-container img { + width: auto; + height: auto; + + max-width: 100%; + max-height: 100%; + + left: 50%; + top: 50%; + + transform: translate(-50%, -50%); + + object-fit: contain; + + user-select: none; + position: relative; + pointer-events: none; +} + +.background-container img.visible { + display: initial; +} + +.hidden { + display: none; +} + +.info, +.transcription { + position: absolute; + right: 0; + bottom: 0; + top: 0; + z-index: 50; + + margin: 0; + + width: min(50%, 600px); + line-height: 1.6; + + background-color: #111; + color: white; + + transform: translateX(100%); + transition: transform 0.4s ease-out; +} + +.info .contents, +.transcription .contents { + padding: 24px; + height: 100vh; + overflow-y: auto; +} + +.contents p { + white-space: pre-line; +} + +.transcription.active, +.info.active { + transform: translateX(0); + transition: transform 0.6s ease-in; +} + +.transcription .title, +.info .title { + margin: 0; +} + +.transcription ol { + padding: 0; + list-style-position: inside; + font-size: 1.125rem; + margin-bottom: 100px; +} + +#show-info, +#show-transcription, +.close, +button { + background: none; + + display: inline-block; + min-width: 24px; + height: 24px; + border-radius: 24px; + padding: 0 4px; + + border: 1px solid currentColor; + + color: tomato; + + cursor: pointer; +} + +#show-transcription:hover, +#show-info:hover { + border: 1px solid tomato; + background-color: tomato; + color: white; +} + +.close { + position: absolute; + right: 24px; + top: 32px; + color: white; +} + +#export-text:hover, +.close:hover { + border: 1px solid white; + background-color: white; + color: #111; +} + +#export-text { + color: white; +} + +nav { + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 50; + + padding: 24px; + text-align: right; + + pointer-events: none; +} + +nav > * { + pointer-events: all; +} + +img.hidden { + display: none; +} + +.transcription .options { + margin-top: 24px; +} diff --git a/static/css/function.css b/static/css/function.css new file mode 100644 index 0000000..5320910 --- /dev/null +++ b/static/css/function.css @@ -0,0 +1,233 @@ +h3, +h2 { + margin-top: 0; +} + +.description { + grid-column: 1 / span 2; +} + +.function-io, +.endpoints, +.playground { + margin: 30px 0; +} + +.playground, +.playground-input, +.playground-output, +.notebook { + grid-column: -1 / 1; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-column-gap: 30px; +} + +.function-io { + grid-column: 1 / -1; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + place-items: start; + grid-gap: 30px; +} + +.function-io > * { + width: 100%; + height: 100%; +} + +.function-io .input, +.function-io .output, +.playground .input { + background-color: white; + aspect-ratio: 1; + border-radius: 50%; +} + +.function-io h3 { + margin: 0; +} + +.function-io ul { + font-family: "Necto"; + list-style: none; + padding: 0; +} + +.endpoints { + grid-column: 1 / -1; +} + +.endpoints code { + background-color: white; + margin: 30px 0; + white-space: initial; +} + +.endpoints .example { + margin: 15px 0; +} + +.playgroud-input .input { + grid-column: 1 / span 1; + align-self: center; +} + +.playground-output .output { + grid-column: 2 / span 2; + background-color: white; + border-radius: 12px; + padding: 12px; + min-height: calc(var(--text) * 2); +} + +.playground label { + display: block; +} + +.playground * + label { + margin-top: 24px; + margin-bottom: 6px; +} + +.playground input[type="submit"] { + margin-top: 30px; +} + +/* .notebook code { + position: relative; + grid-column: 1 / -1; + z-index: 100; +} + +pre.prettyprint.prettyprinted { + border: none; + position: relative; +} + +pre.prettyprint.prettyprinted::after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 460px; + height: 460px; + background-color: white; + border-radius: 50%; +} */ + +.notebook { + width: 100%; + /* margin-top: 60px; */ + /* padding-top: 60px; */ + /* border-top: 1px solid currentColor; */ +} + +.notebook h1::before { + content: "Documentation: "; +} + +.notebook p { + grid-column: span 2; + text-indent: 0; +} + +.notebook pre { + white-space: pre-wrap; + grid-column: 1 / -1; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-gap: 30px; +} + +.notebook .language-python { + grid-column: 1 / span 2; + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + white-space: pre; + background: none; + padding: 0; + z-index: 100; + min-height: 400px; +} + +.notebook .language-python::after { + content: ""; + position: absolute; + z-index: 0; + top: 0; + aspect-ratio: 1; + height: 100%; + border-radius: 50%; + background-color: white; + mix-blend-mode: color; + pointer-events: none; +} + +.notebook h1 { + +grid-column: 1 / -1; +} + + +.notebook p { + margin: 30px 0; + grid-column: 2 / span 2; +} + +.notebook p img { +display: block; +} + +.notebook code { + grid-column: 2 / span 2; + align-self: flex-start; + background-color: white; + padding: 12px; + border-radius: var(--radius); +} + +.notebook h2 { + grid-column: 1/-1; +} + +.notebook img { + margin: 30px 0; +} + +.notebook > * + * { + margin-top: 30px; +} + +@media (max-width: 767.98px) { + .playground, + .playground-input, + .playground-output, + .notebook, + .function-io, + .notebook pre { + display: block; + } + + .function-io .input, + .function-io .output, + .playground .input { + background: none; + aspect-ratio: auto; + } + + .playground-output { + margin-top: 30px; + } + + .page-content > * + * { + margin-top: 60px; + } + + .notebook .language-python { + min-height: 300px; + white-space: pre-wrap; + } +} diff --git a/static/css/global.css b/static/css/global.css new file mode 100644 index 0000000..764e324 --- /dev/null +++ b/static/css/global.css @@ -0,0 +1,343 @@ +html, +body { + margin: 0; + box-sizing: border-box; + background-color: var(--background); + + font-family: var(--font); + font-size: var(--text); + line-height: 1.4; + overflow-x: hidden; +} + +h1, +h2, +h3 { + font-family: var(--font); + font-weight: bold; + font-style: italic; +} + +h1 { + font-size: var(--title); + margin: 0; +} +h2, +h3 { + font-size: var(--text); +} + +a { + color: currentColor; +} + +ol, ul{ + +padding-left: 0; +} + +ul { + list-style: none; +} + +ul li::before { + content: "–"; +} + +li > ul, +li > ol, +{ +padding-left: 12px; + color: red; +} + + + + + +code, +pre { + font-family: "Necto"; + border: none; + white-space: break-spaces; +} + +input { + font-family: var(--font); + font-size: var(--text); + padding: 6px; + border: 1px solid currentColor; + border-radius: 6px; +} + +button, +input[type="submit"] { + font-family: var(--font); + font-size: var(--text); + font-weight: bold; + font-style: italic; + background-color: white; + border: 1px solid currentColor; + padding: 6px; + border-radius: 12px; + transform: scale(1); + transition: transform 0.3s ease-out; + cursor: pointer; +} + +button, +input[type="submit"]:active { + transform: scale(0.95); + transition: transform 0.1s ease-in; +} + +/* STICKER CONTAINER */ + +#sticker-container { + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; + + pointer-events: none; + + z-index: 100; + + min-height: 100vh; + height: 100%; +} + +#sticker-fix-container { + position: fixed; + left: 0; + top: 0; + bottom: 0; + right: 0; + + pointer-events: none; + + z-index: 300; + + min-height: 100vh; + height: 100%; +} + +.sticker { + position: absolute; + user-select: none; + border: 1px solid currentColor; + border-radius: var(--radius); + white-space: nowrap; + background-color: white; + font-size: 18px; + padding: 0 6px; + box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2); + text-decoration: none; + + overflow-wrap: break-word; +} + +*[data-sticker] { + position: relative; +} + +/* HEADER AND NAV */ + +.page--header { + position: fixed; + z-index: 200; + + top: 60px; + left: 50%; + transform: translate(-50%, 0); + + width: calc(100% - 2 * var(--app-margin)); + max-width: var(--content-width); + padding: 0 var(--app-margin); + + display: flex; + justify-content: center; +} + +header { + flex-grow: 1; + flex-shrink: 1; + + display: flex; + flex-direction: column; + justify-content: center; + + border: 1px solid currentColor; + border-radius: var(--radius); + background-color: var(--background); + box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.25); + height: 48px; /* comment this in page with multiple elements in the header */ + flex-basis: 48px; + + padding: 0px 12px; +} + +.page--header .title { + /* flex-grow: 0; */ + /* flex-shrink: 1; */ + /* line-height: 1; */ + margin: 0; +} + +.page--header .subtitle { + line-height: 1; + margin: 6px 0; +} + +nav { + margin-left: 12px; +} + +.page--header nav a { + display: inline-block; + width: 48px; + height: 48px; + border-radius: 50%; + border: 1px solid currentColor; + background-color: var(--background); + margin: 0; +} + +.page--header nav a + a { + margin-left: 6px; +} + +/* FOOTER */ + +.page--footer { + position: relative; + bottom: var(--app-margin); + + width: calc(100% - 2 * var(--app-margin)); + max-width: var(--content-width); + padding: 0 var(--app-margin); + + left: 50%; + transform: translate(-50%, 0); +} + +footer { + margin-top: 90px; + margin-bottom: 30px; + + padding: 6px 12px; + border: 1px solid currentColor; + border-radius: var(--radius); + + font-weight: bold; + font-style: italic; +} + +/* MAIN CONTENTS */ + +.page--content { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-column-gap: var(--app-margin); + align-items: baseline; + + max-width: var(--content-width); + padding: 0 var(--app-margin); + margin: 0 auto; + margin-top: 180px; +} + +.page--content p { + grid-column-end: span 2; + + margin: 0; + + text-indent: calc(var(--text) * 2); + line-height: 1.4; +} + +.page--content h2 { + font-size: var(--title); + margin: 0; + margin-top: calc(var(--app-margin) * 3); + margin-bottom: var(--app-margin); +} + +.page--content > * + * { + margin-top: var(--app-margin); +} + +.page--content img { + grid-column-end: span 2; + width: 100%; + margin: 60px 0; + border-radius: var(--radius); + border: 1px solid currentColor; +} + +/* GRID functional classes sorry this is not good at all but.... */ + +.c2 { + grid-column-end: span 2; +} + +.s1 { + grid-column-start: 1; +} + +.s2 { + grid-column-start: 2; +} + +/* Medium screens */ + +@media (max-width: 991.98px) { + /* HEADER MOBILE */ + + .page--header { + top: 30px; + } + + header { + min-height: 42px; + } + + .page--header .title { + font-size: 24px; + } + + .page--header .subtitle { + font-size: 21px; + } + + .page--header nav a { + width: 48px; + height: 48px; + } + + /* MAIN CONTENTS */ + + .page--content { + margin-top: 120px; + } +} + +@media (max-width: 767.98px) { + .page--content { + display: block; + } + + .page--content h2 { + margin-top: 60px; + } + + ul, ol { + list-style-position: inside; + } +} + + +.highlight { + color: blue; +} \ No newline at end of file diff --git a/static/css/home.css b/static/css/home.css new file mode 100644 index 0000000..30ca9fa --- /dev/null +++ b/static/css/home.css @@ -0,0 +1,99 @@ +.sticker { + font-size: var(--text); + pointer-events: all; +} + +.index { + margin: calc(var(--app-margin) * 2); +} + +.sheet + .sheet { + margin-top: var(--app-margin); +} + +.sheet h3 a { + text-decoration: none; +} + + +.negative { + position: relative; +/* visibility: hidden; */ + color: rgba(0,0,0,0.2); + text-decoration: none; + cursor: pointer; + line-height: 48px; + + + + background-color: rgba(0, 0, 0, 0.075); +/* background-color: var(--background); */ + border-radius: var(--radius); + padding: 3px 12px; + margin: 12px 0; +} + +/* .negative:after { + visibility: visible; + content: ""; + background-color: rgba(0, 0, 0, 0.075); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: var(--radius); +} */ + + + +.sheet > p { + display: inline-block; + margin: 6px 0; +} + +h1.negative { + display: table; +} + +.meta > h2 { + display: inline-block; + margin: 6px 0; +} + +.sheet .section { + padding: 0; + margin: 0; + margin-bottom: 6px; + + font-size: var(--title); + color: rgba(0, 0, 0, 0.1); +} + +.chat-link { + position: absolute; + z-index: 1000; + top: 60px; + right: 60px; + + background-color: springgreen; + border: 1px solid currentColor; + border-radius: 12px; + padding: 0 12px; + + text-decoration: none; + + font-weight: bold; + font-style: italic; + transform: scale(1); + transition: transform 0.2s ease-in; + +} + + + +.chat-link:hover{ + transition: transform 0.1s ease-out; + transform: scale(1.025); +} + diff --git a/static/css/intro.css b/static/css/intro.css new file mode 100644 index 0000000..c5d267d --- /dev/null +++ b/static/css/intro.css @@ -0,0 +1,33 @@ +:root { + --background: white!important; +} + +.page--content p { +grid-column: 1 / span 2; + +} + +.bubble + .bubble { + margin-top: 30px; +} + +.bubble:nth-child(2n + 2) { +/* background-color: var(--orange); */ + grid-column-start: 1; +} + + +p.bubble { + grid-column-start: 2; + margin: 30px 0; + border: 1px solid currentColor; + padding: 12px; + border-radius: var(--radius); + text-indent: 0; + justify-self: start; +} + +.page--content p.intro { + text-indent: 0; + margin-bottom: 30px; +} diff --git a/static/css/jian.css b/static/css/jian.css new file mode 100644 index 0000000..82eb019 --- /dev/null +++ b/static/css/jian.css @@ -0,0 +1,27 @@ +html, +body { + margin: 0; + font-family: 'Courier New'; + width: 100%; + overflow: hidden; + background-color: rgb(180, 180, 180) ; +} + + +.highlight { + background-color: rgba(0, 150, 255, 0.6); + text-shadow: 0 0 0px black; +} + + +.lowlight { + background-color: rgba(0, 0, 255, 0); + color: black; + text-shadow: 0 0 0px black; +} + + +.ghost { + color: black; + text-shadow: 0 0 0px black; +} \ No newline at end of file diff --git a/static/css/list.css b/static/css/list.css new file mode 100644 index 0000000..3297621 --- /dev/null +++ b/static/css/list.css @@ -0,0 +1,73 @@ +.list { + grid-column: 1 / -1; + width: 100%; + margin-top: 60px; +} + +table { + border-collapse: collapse; +} + +tr { + position: relative; + border-top: 1px solid currentColor; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-gap: 30px; +} + +tr:last-of-type { + padding-bottom: 24px; + border-bottom: 1px solid currentColor; +} + +td { + padding: 24px 0; +} + +td.title { + font-weight: bold; + font-style: italic; +} + +td.description { + grid-column: 2 / span 2; + padding-right: 90px; +} + +td.link { + position: absolute; + right: 0; + text-align: right; +} + +@media (max-width: 767.98px) { + table, + tr, + td { + display: block; + } + + tr + tr { + margin-top: 24px; + } + + td { + padding: 0; + } + + td.title { + padding-right: 30px; + margin-top: 18px; + margin-bottom: 6px; + } + + td.description { + padding-right: 0; + } + + td.link { + top: 18px; + right: 0; + } +} diff --git a/static/css/mitsotakis/archive.css b/static/css/mitsotakis/archive.css new file mode 100644 index 0000000..e1c2dc9 --- /dev/null +++ b/static/css/mitsotakis/archive.css @@ -0,0 +1,37 @@ +body { + padding: 16px; +} +.page--header { + width: auto; + top: 45px; + margin: 0; + padding: 0; +} +.sections { + margin-top: 30vh; + display: flex; + flex-direction: column-reverse; + color: var(--textcolor); + row-gap:4vh; +} +.section { + position:relative +} +.reporter { + align-self: flex-start; + width: 70vw; +} +.answer { + align-self: flex-end; + width: 70vw; + text-align: right; +} + +@media (max-width: 991.98px) { + .reporter{ + width:100%; + } + .answer{ + width:100%; + } +} \ No newline at end of file diff --git a/static/css/mitsotakis/script.js b/static/css/mitsotakis/script.js new file mode 100644 index 0000000..7ff9153 --- /dev/null +++ b/static/css/mitsotakis/script.js @@ -0,0 +1,7 @@ +// Get the button, and when the user clicks on it, execute myFunction +//document.getElementById("info-btn").onclick = function() {showInfo()}; + +/* myFunction toggles between adding and removing the show class, which is used to hide and show the dropdown content */ +function showInfo() { + document.getElementById("info").classList.toggle("show"); +} diff --git a/static/css/mitsotakis/style.css b/static/css/mitsotakis/style.css new file mode 100644 index 0000000..a6f6402 --- /dev/null +++ b/static/css/mitsotakis/style.css @@ -0,0 +1,270 @@ +@font-face { + font-family: Pirelli; + src: url("./font/pirelli-regular.woff"); +} + +@font-face { + font-family: Pirelli; + src: url("./font/pirelli-bolditalic.woff"); + font-weight: bold; +} + +@font-face { + font-family: Necto-Mono; + src: url("./font/Necto-Mono.woff"); +} +:root { + --red: tomato; + --background: rgb(233, 233, 233); + --textcolor: rgb(39, 39, 39); + --blue: #9edae2; + --pink: #f7d8e8; + --orange: #ffc496; + --yellow: #f9f5b0; + --green: #9fd3a8; + + --content-width: 1440px; + --radius: 12px; + --font: "Pirelli"; + --title: 36px; + --text: 24px; + --app-margin: 30px; +} +html { + scroll-behavior: smooth; + overflow-x: hidden; +} +body { + font-family: Pirelli; + background-color: var(--background); + color: var(--textcolor); + margin: 0; +} + +* { + box-sizing: border-box; +} +a.goto-archive { + position: fixed; + top: 16px; + right: 16px; + color: var(--red); + font-size: 1.2em; + z-index: 1; +} +.page--header { + top: 0; + width: 100%; + margin: 8vh 0; + padding: 0 16px; + display: flex; + flex-direction: row; + column-gap: 8px; + align-items: stretch; + justify-content: center; + position: fixed; + z-index: 1; +} +.page--header > * { + border: solid 1px var(--red); + border-radius: 8px; + padding: 12px; + background-color: var(--background); +} +header { + flex-grow: 1; +} +nav { + cursor: pointer; +} +h1 { + font-size: 36px; + color: var(--red); + margin: 0; + font-weight: normal; +} + +.question { + display: flex; + font-size: 1.2em; + flex-direction: column; + flex-grow: 1; + justify-content: space-between; + align-items: flex-start; + row-gap: 24px; + width: 100%; + margin-top: 28vh; + padding: 0 16px; +} + +.info { + /*background-color: white;*/ + display: none; + padding: 16px; + border: solid 1px var(--red); + border-radius: 8px; + color: var(--red); + font-size: 1em; + flex-basis: 35%; +} +.show { + display: block; +} +.q-text { + margin-bottom: 1em; + flex-basis: 65%; +} + +/*styling of form*/ +form { + padding: 16px; + display: flex; + flex-flow: wrap; + column-gap: 24px; + row-gap: 16px; + align-items: flex-start; +} +.form-box { + display: flex; + flex-direction: column; + row-gap: 8px; + flex-basis: 30%; + flex-grow: 1; +} +.form-box#apply { + align-self: flex-end; +} +textarea { + resize: none; +/* font-family: Necto-mono; */ + border-radius: 4px; + border: solid 1px grey; + transition: border-radius 70ms ease-in-out; +} +/* when the cursor is iside the text area*/ +textarea:focus { + border: solid 2px var(--red); + outline: none; + border-radius: 16px; +} + +input { + font-family: Pirelli; + width: 100%; + font-size: 1.2em; + margin: 0; +} +input:hover { + color: var(--red); +} +/*to pick the exact type of input you wanna style use "[]"*/ +input[type="radio"] { + font-family: Pirelli; + background-color: var(--red); +} +label { + font-size: 0.9em; +} + +/*custom radio button*/ +/* The container */ +.radio-label { + display: block; + position: relative; + padding-left: 35px; + margin-bottom: 12px; + cursor: pointer; + font-size: 1.2em; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +/* Hide the browser's default radio button */ +.radio-label input { + position: absolute; + opacity: 0; + cursor: pointer; +} + +/* Create a custom radio button */ +.checkmark { + position: absolute; + top: 0; + left: 0; + height: 24px; + width: 24px; + background-color: rgb(255, 255, 255); + border: solid 2px var(--red); + border-radius: 50%; +} + +/* On mouse-over change color */ +.radio-label:hover { + color: var(--red); +} + +/* When the radio button is checked, add a blue background */ +.radio-label input:checked ~ .checkmark { + background-color: var(--red); +} + +/* Create the indicator (the dot/circle - hidden when not checked) */ +.checkmark:after { + content: ""; + position: absolute; + display: none; +} + +.lbl-result { + color: grey; + font-size: 0.8em; +} +.result { + font-family: Courier; +} + +.form-end { + margin: 16px; + display: flex; + flex-direction: row; + flex-flow: nowrap; + align-items: center; + align-content: stretch; + column-gap: 8px; +} +.form-end > * { + flex-grow: 1; + flex-basis: 50%; + margin: 0; + padding: 0; +} +a.goto-form { + border: solid 1px rgb(107, 107, 107); + border-radius: 4px; + font-family: Pirelli; + width: 100%; + font-size: 1.2em; + text-decoration: none; + color: var(--textcolor); + text-align: center; + padding: 2px; +} +.goto-form:hover { + color: var(--red); + background-color: rgb(216, 216, 216); +} +.save-btn { + height: 100%; +} + +@media (max-width: 991.98px) { + :root { + --app-margin: 18px; + --text: 21px; + } + .title, + nav.h1 { + font-size: 1.5em; + } +} diff --git a/static/css/page.css b/static/css/page.css new file mode 100644 index 0000000..6bb0f82 --- /dev/null +++ b/static/css/page.css @@ -0,0 +1,37 @@ + + +.page--content pre { + grid-column: span 2; +} + + +.page--content h2 { + grid-column: 1 / -1; +} + + .page--content h2:first-of-type{ + margin-top: 0px; + } + + .page--content h3 { + grid-column: 1 / span 1; + } + + .page--content ul, + .page--content ol { + grid-column: 2 / span 2; + } + + .page--content li { + margin-top: 12px; + } + + + + .page--content p { + grid-column: 2 / span 2; + } + +.page--content p img { +display: block; +} diff --git a/static/css/project.css b/static/css/project.css new file mode 100644 index 0000000..190528d --- /dev/null +++ b/static/css/project.css @@ -0,0 +1,48 @@ +.page--content .project-link { + + grid-column: 1 / -1; + place-self: center; + display: inline-block; + border: 1px solid currentColor; + width: 300px; + height: 300px; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + text-decoration: none; + font-weight: bold; + font-style: italic; + + margin: 60px 0; + } + + .project-link:hover{ + background-color: white; + } + +.page--content .description { + +grid-column: 1 / span 2; + +} + +.page--content pre { + +grid-column: 2 / span 2; +} + +.page--header header{ +height: auto; + +} + +.page--content p { +position: relative; + +} + +.page--content p img { +display: block; + +} \ No newline at end of file diff --git a/static/css/tos.css b/static/css/tos.css new file mode 100644 index 0000000..88990f1 --- /dev/null +++ b/static/css/tos.css @@ -0,0 +1,4 @@ + .page--content p:first-of-type { + grid-column: 1 / span 2; + margin-bottom: 60px; + } \ No newline at end of file diff --git a/static/css/variables.css b/static/css/variables.css new file mode 100644 index 0000000..9e1d585 --- /dev/null +++ b/static/css/variables.css @@ -0,0 +1,24 @@ +@import url("/static/font/font.css"); + +:root { + --blue: #9edae2; + --pink: #f7d8e8; + --orange: #ffc496; + --yellow: #f9f5b0; + --green: #9fd3a8; + + --content-width: 1440px; + --radius: 12px; + --background: var(--yellow); + --font: "Pirelli"; + --title: 36px; + --text: 24px; + --app-margin: 30px; +} + +@media (max-width: 991.98px) { + :root { + --app-margin: 18px; + --text: 21px; + } +} diff --git a/static/errors/.ipynb_checkpoints/503-checkpoint.ipynb b/static/errors/.ipynb_checkpoints/503-checkpoint.ipynb new file mode 100644 index 0000000..363fcab --- /dev/null +++ b/static/errors/.ipynb_checkpoints/503-checkpoint.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/static/errors/503.ipynb b/static/errors/503.ipynb new file mode 100644 index 0000000..3a2a5ad --- /dev/null +++ b/static/errors/503.ipynb @@ -0,0 +1,58 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "817008c8-6cc9-4e39-9ec0-b73785756099", + "metadata": {}, + "source": [ + "Upss I am having a break right now, cuddling my cat." + ] + }, + { + "cell_type": "markdown", + "id": "a39983dd-f828-499b-9e30-39ec45c056a1", + "metadata": {}, + "source": [ + "I wasn't ready for this connection.\n", + "I am a bit moody right now, so I am concentrating on finding my center." + ] + }, + { + "cell_type": "markdown", + "id": "3b79c6c1-c81a-459d-abbc-2a36bda652b8", + "metadata": {}, + "source": [ + "Ah! you are here! I wasn't excepting of you! Wait to put something on me" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00670416-1257-442e-b55c-2a93b87f5931", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/static/event/functions/.ipynb_checkpoints/cocktail-checkpoint.txt b/static/event/functions/.ipynb_checkpoints/cocktail-checkpoint.txt new file mode 100644 index 0000000..efc43ed --- /dev/null +++ b/static/event/functions/.ipynb_checkpoints/cocktail-checkpoint.txt @@ -0,0 +1 @@ +drink drink glu glu \ No newline at end of file diff --git a/static/event/functions/336928__the-sacha-rush__blip3.wav b/static/event/functions/336928__the-sacha-rush__blip3.wav new file mode 100644 index 0000000..f689129 Binary files /dev/null and b/static/event/functions/336928__the-sacha-rush__blip3.wav differ diff --git a/static/event/functions/R2255-photo-step-5-medium-landscape-150.jpg b/static/event/functions/R2255-photo-step-5-medium-landscape-150.jpg new file mode 100644 index 0000000..99c8f80 Binary files /dev/null and b/static/event/functions/R2255-photo-step-5-medium-landscape-150.jpg differ diff --git a/static/event/functions/SCG_small.mp4 b/static/event/functions/SCG_small.mp4 new file mode 100644 index 0000000..e4867af Binary files /dev/null and b/static/event/functions/SCG_small.mp4 differ diff --git a/static/event/functions/cocktail.txt b/static/event/functions/cocktail.txt new file mode 100644 index 0000000..efc43ed --- /dev/null +++ b/static/event/functions/cocktail.txt @@ -0,0 +1 @@ +drink drink glu glu \ No newline at end of file diff --git a/static/event/manifesto/.ipynb_checkpoints/bubble-checkpoint.txt b/static/event/manifesto/.ipynb_checkpoints/bubble-checkpoint.txt new file mode 100644 index 0000000..db3af42 --- /dev/null +++ b/static/event/manifesto/.ipynb_checkpoints/bubble-checkpoint.txt @@ -0,0 +1 @@ +Hello this is the event mode \ No newline at end of file diff --git a/static/event/manifesto/.ipynb_checkpoints/bubble_2-checkpoint.txt b/static/event/manifesto/.ipynb_checkpoints/bubble_2-checkpoint.txt new file mode 100644 index 0000000..99d8ba1 --- /dev/null +++ b/static/event/manifesto/.ipynb_checkpoints/bubble_2-checkpoint.txt @@ -0,0 +1 @@ +We ate artichockes \ No newline at end of file diff --git a/static/event/manifesto/.ipynb_checkpoints/bubble_3-checkpoint.txt b/static/event/manifesto/.ipynb_checkpoints/bubble_3-checkpoint.txt new file mode 100644 index 0000000..b8bfd6c --- /dev/null +++ b/static/event/manifesto/.ipynb_checkpoints/bubble_3-checkpoint.txt @@ -0,0 +1 @@ +We met Cara outside our place with a red couch \ No newline at end of file diff --git a/static/event/manifesto/bubble.txt b/static/event/manifesto/bubble.txt new file mode 100644 index 0000000..db3af42 --- /dev/null +++ b/static/event/manifesto/bubble.txt @@ -0,0 +1 @@ +Hello this is the event mode \ No newline at end of file diff --git a/static/event/manifesto/bubble_2.txt b/static/event/manifesto/bubble_2.txt new file mode 100644 index 0000000..99d8ba1 --- /dev/null +++ b/static/event/manifesto/bubble_2.txt @@ -0,0 +1 @@ +We ate artichockes \ No newline at end of file diff --git a/static/event/manifesto/bubble_3.txt b/static/event/manifesto/bubble_3.txt new file mode 100644 index 0000000..b8bfd6c --- /dev/null +++ b/static/event/manifesto/bubble_3.txt @@ -0,0 +1 @@ +We met Cara outside our place with a red couch \ No newline at end of file diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..97f0a61 Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/font/.ipynb_checkpoints/font-checkpoint.css b/static/font/.ipynb_checkpoints/font-checkpoint.css new file mode 100644 index 0000000..51d0545 --- /dev/null +++ b/static/font/.ipynb_checkpoints/font-checkpoint.css @@ -0,0 +1,42 @@ +@font-face { + font-family: "Pirelli"; + src: url("./pirelli-regular.woff2") format("woff2"), url("Pirelli-Regular.woff") format("woff"); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Pirelli"; + src: url("./pirelli-bolditalic.woff") format("woff2"), + url("./pirelli-bolditalic.woff") format("woff"); + font-weight: bold; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "Pirelli"; + src: url("./pirelli-bolditalic.woff2") format("woff2"), + url("./pirelli-bolditalic.woff") format("woff"); + font-weight: bold; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "Pirelli"; + src: url("./pirelli-regular.woff2") format("woff2"), + url("./pirelli-regular.woff") format("woff"); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Necto"; + src: url("./Necto-Mono.woff2") format("woff2"), url("./Necto-Mono.woff") format("woff"); + font-weight: normal; + font-style: normal; + font-display: swap; +} diff --git a/static/font/Necto-Mono.woff b/static/font/Necto-Mono.woff new file mode 100644 index 0000000..e9306c9 Binary files /dev/null and b/static/font/Necto-Mono.woff differ diff --git a/static/font/Necto-Mono.woff2 b/static/font/Necto-Mono.woff2 new file mode 100644 index 0000000..0b273ef Binary files /dev/null and b/static/font/Necto-Mono.woff2 differ diff --git a/static/font/font.css b/static/font/font.css new file mode 100644 index 0000000..51d0545 --- /dev/null +++ b/static/font/font.css @@ -0,0 +1,42 @@ +@font-face { + font-family: "Pirelli"; + src: url("./pirelli-regular.woff2") format("woff2"), url("Pirelli-Regular.woff") format("woff"); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Pirelli"; + src: url("./pirelli-bolditalic.woff") format("woff2"), + url("./pirelli-bolditalic.woff") format("woff"); + font-weight: bold; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "Pirelli"; + src: url("./pirelli-bolditalic.woff2") format("woff2"), + url("./pirelli-bolditalic.woff") format("woff"); + font-weight: bold; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "Pirelli"; + src: url("./pirelli-regular.woff2") format("woff2"), + url("./pirelli-regular.woff") format("woff"); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Necto"; + src: url("./Necto-Mono.woff2") format("woff2"), url("./Necto-Mono.woff") format("woff"); + font-weight: normal; + font-style: normal; + font-display: swap; +} diff --git a/static/font/pirelli-bolditalic.woff b/static/font/pirelli-bolditalic.woff new file mode 100644 index 0000000..dbb17a9 Binary files /dev/null and b/static/font/pirelli-bolditalic.woff differ diff --git a/static/font/pirelli-bolditalic.woff2 b/static/font/pirelli-bolditalic.woff2 new file mode 100644 index 0000000..e712f5c Binary files /dev/null and b/static/font/pirelli-bolditalic.woff2 differ diff --git a/static/font/pirelli-regular.woff b/static/font/pirelli-regular.woff new file mode 100644 index 0000000..e614aa4 Binary files /dev/null and b/static/font/pirelli-regular.woff differ diff --git a/static/font/pirelli-regular.woff2 b/static/font/pirelli-regular.woff2 new file mode 100644 index 0000000..e6cc99a Binary files /dev/null and b/static/font/pirelli-regular.woff2 differ diff --git a/static/functions.json b/static/functions.json new file mode 100644 index 0000000..29f6fa9 --- /dev/null +++ b/static/functions.json @@ -0,0 +1 @@ +[{"title": "vernacular_map", "description": "Give a string with the name of the image-file that was annotated with the Annotation Compass; Return a string that includes all annotation-texts plus html-tags that place them back into their original position."}, {"title": "add_pen_name", "description": "add pen name inside the list"}, {"title": "shout", "description": "Repeat the vowels in a string for a specified number of times"}, {"title": "reverse", "description": "Reverse the input sentence by sentence"}, {"title": "cocktail_generator", "description": "randomly chooses ingredients from a menu for a nice cocktail recipe"}, {"title": "respell", "description": "You wont believe to this incredible function"}, {"title": "mashup", "description": "A super incredible function"}, {"title": "reveal", "description": "Yet another useful function"}, {"title": "repeat", "description": "Repeat a string for a specified number of times"}, {"title": "highlight_map", "description": "Give a string with the name of the image-file that was annotated with the Annotation Compass; Give a target-word; Return a string that includes all annotation-texts plus html-tags that place them back into their original position while highlighting the annotation-texts that include the target."}, {"title": "individual_map", "description": "give a string with the name of the image-file that was annotated with the Annotation Compass; Select one or more specific targets and return a list of all labels that include these targetsselect one or more specific users and return a list of all labels from these users."}, {"title": "bridge", "description": "A useful and nice function"}, {"title": "area_map", "description": "Give a string with the name of the image-file that was annotated with the Annotation Compass; Select a specific area of the image, return a list of all labels in that specific area."}, {"title": "stich", "description": "A incredible and nice function"}, {"title": "target_map", "description": "Give a string with the name of the image-file that was annotated with the Annotation Compass; Select one or more specific targets and return a list of all labels that include these targets."}, {"title": "ghost_map", "description": "give a string with the name of the image-file that was annotated with the Annotation Compass; Replace all characters of all annotation-texts with a ghost-glyph and return a string that includes all replaced annotation-texts plus html-tags that place them back into their original position."}, {"title": "html_tag", "description": "A wow and wow function"}] \ No newline at end of file diff --git a/static/img/.ipynb_checkpoints/bibi-checkpoint.jpg b/static/img/.ipynb_checkpoints/bibi-checkpoint.jpg new file mode 100644 index 0000000..fdcf908 Binary files /dev/null and b/static/img/.ipynb_checkpoints/bibi-checkpoint.jpg differ diff --git a/static/img/.ipynb_checkpoints/mitsotakis_test-checkpoint.jpg b/static/img/.ipynb_checkpoints/mitsotakis_test-checkpoint.jpg new file mode 100644 index 0000000..d95493d Binary files /dev/null and b/static/img/.ipynb_checkpoints/mitsotakis_test-checkpoint.jpg differ diff --git a/static/img/.ipynb_checkpoints/seagul-checkpoint.jpg b/static/img/.ipynb_checkpoints/seagul-checkpoint.jpg new file mode 100644 index 0000000..f3c11a3 Binary files /dev/null and b/static/img/.ipynb_checkpoints/seagul-checkpoint.jpg differ diff --git a/static/img/annotation_compass/first-exp/01.jpg b/static/img/annotation_compass/first-exp/01.jpg new file mode 100644 index 0000000..522014f Binary files /dev/null and b/static/img/annotation_compass/first-exp/01.jpg differ diff --git a/static/img/annotation_compass/first-exp/02.jpg b/static/img/annotation_compass/first-exp/02.jpg new file mode 100644 index 0000000..eb45e00 Binary files /dev/null and b/static/img/annotation_compass/first-exp/02.jpg differ diff --git a/static/img/annotation_compass/first-exp/03.jpg b/static/img/annotation_compass/first-exp/03.jpg new file mode 100644 index 0000000..26c828f Binary files /dev/null and b/static/img/annotation_compass/first-exp/03.jpg differ diff --git a/static/img/annotation_compass/first-exp/04.jpg b/static/img/annotation_compass/first-exp/04.jpg new file mode 100644 index 0000000..98034cd Binary files /dev/null and b/static/img/annotation_compass/first-exp/04.jpg differ diff --git a/static/img/annotation_compass/first-exp/05.jpg b/static/img/annotation_compass/first-exp/05.jpg new file mode 100644 index 0000000..9861144 Binary files /dev/null and b/static/img/annotation_compass/first-exp/05.jpg differ diff --git a/static/img/annotation_compass/first-exp/06.jpg b/static/img/annotation_compass/first-exp/06.jpg new file mode 100644 index 0000000..e6b4c88 Binary files /dev/null and b/static/img/annotation_compass/first-exp/06.jpg differ diff --git a/static/img/annotation_compass/first-exp/07.jpg b/static/img/annotation_compass/first-exp/07.jpg new file mode 100644 index 0000000..9679a9f Binary files /dev/null and b/static/img/annotation_compass/first-exp/07.jpg differ diff --git a/static/img/annotation_compass/first-exp/08.jpg b/static/img/annotation_compass/first-exp/08.jpg new file mode 100644 index 0000000..7ae9e1b Binary files /dev/null and b/static/img/annotation_compass/first-exp/08.jpg differ diff --git a/static/img/annotation_compass/first-exp/21.jpg b/static/img/annotation_compass/first-exp/21.jpg new file mode 100644 index 0000000..ca89aec Binary files /dev/null and b/static/img/annotation_compass/first-exp/21.jpg differ diff --git a/static/img/annotation_compass/first-exp/22.jpg b/static/img/annotation_compass/first-exp/22.jpg new file mode 100644 index 0000000..f4fd245 Binary files /dev/null and b/static/img/annotation_compass/first-exp/22.jpg differ diff --git a/static/img/annotation_compass/first-exp/23.mp4 b/static/img/annotation_compass/first-exp/23.mp4 new file mode 100644 index 0000000..88cf5a7 Binary files /dev/null and b/static/img/annotation_compass/first-exp/23.mp4 differ diff --git a/static/img/annotation_compass/first-exp/build-up.mp4 b/static/img/annotation_compass/first-exp/build-up.mp4 new file mode 100644 index 0000000..2404ee8 Binary files /dev/null and b/static/img/annotation_compass/first-exp/build-up.mp4 differ diff --git a/static/img/bibi.jpg b/static/img/bibi.jpg new file mode 100644 index 0000000..fdcf908 Binary files /dev/null and b/static/img/bibi.jpg differ diff --git a/static/img/cloverleaf/.ipynb_checkpoints/cloverleaf-checkpoint.jpeg b/static/img/cloverleaf/.ipynb_checkpoints/cloverleaf-checkpoint.jpeg new file mode 100644 index 0000000..6711b4c Binary files /dev/null and b/static/img/cloverleaf/.ipynb_checkpoints/cloverleaf-checkpoint.jpeg differ diff --git a/static/img/cloverleaf/.ipynb_checkpoints/perec-checkpoint.png b/static/img/cloverleaf/.ipynb_checkpoints/perec-checkpoint.png new file mode 100644 index 0000000..ebcf6a8 Binary files /dev/null and b/static/img/cloverleaf/.ipynb_checkpoints/perec-checkpoint.png differ diff --git a/static/img/cloverleaf/cloverleaf.jpeg b/static/img/cloverleaf/cloverleaf.jpeg new file mode 100644 index 0000000..6711b4c Binary files /dev/null and b/static/img/cloverleaf/cloverleaf.jpeg differ diff --git a/static/img/cloverleaf/perec.png b/static/img/cloverleaf/perec.png new file mode 100644 index 0000000..ebcf6a8 Binary files /dev/null and b/static/img/cloverleaf/perec.png differ diff --git a/static/img/infiltrating the filter/infiltrating_the_filter_1.jpg b/static/img/infiltrating the filter/infiltrating_the_filter_1.jpg new file mode 100644 index 0000000..c2b6ffd Binary files /dev/null and b/static/img/infiltrating the filter/infiltrating_the_filter_1.jpg differ diff --git a/static/img/mitsotakis_test.jpg b/static/img/mitsotakis_test.jpg new file mode 100644 index 0000000..d95493d Binary files /dev/null and b/static/img/mitsotakis_test.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/rejection_map-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/rejection_map-checkpoint.jpg new file mode 100644 index 0000000..e544ed8 Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/rejection_map-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-01-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-01-checkpoint.jpg new file mode 100644 index 0000000..b4ecf61 Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-01-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-02-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-02-checkpoint.jpg new file mode 100644 index 0000000..41fc02a Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-02-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-03-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-03-checkpoint.jpg new file mode 100644 index 0000000..b327b2e Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-03-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-04-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-04-checkpoint.jpg new file mode 100644 index 0000000..cdf09d9 Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-04-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-05-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-05-checkpoint.jpg new file mode 100644 index 0000000..6299ac3 Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-05-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-09-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-09-checkpoint.jpg new file mode 100644 index 0000000..5613d27 Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-09-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-16-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-16-checkpoint.jpg new file mode 100644 index 0000000..98a07fd Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-16-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-18-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-18-checkpoint.jpg new file mode 100644 index 0000000..4af04b5 Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-18-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-19-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-19-checkpoint.jpg new file mode 100644 index 0000000..dbee49a Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-19-checkpoint.jpg differ diff --git a/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-21-checkpoint.jpg b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-21-checkpoint.jpg new file mode 100644 index 0000000..eb6139b Binary files /dev/null and b/static/img/rejection_map/.ipynb_checkpoints/vernacular-map-experiments-21-checkpoint.jpg differ diff --git a/static/img/rejection_map/rejection_map.jpg b/static/img/rejection_map/rejection_map.jpg new file mode 100644 index 0000000..e544ed8 Binary files /dev/null and b/static/img/rejection_map/rejection_map.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-01.jpg b/static/img/rejection_map/vernacular-map-experiments-01.jpg new file mode 100644 index 0000000..b4ecf61 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-01.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-02.jpg b/static/img/rejection_map/vernacular-map-experiments-02.jpg new file mode 100644 index 0000000..41fc02a Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-02.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-03.jpg b/static/img/rejection_map/vernacular-map-experiments-03.jpg new file mode 100644 index 0000000..b327b2e Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-03.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-04.jpg b/static/img/rejection_map/vernacular-map-experiments-04.jpg new file mode 100644 index 0000000..cdf09d9 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-04.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-05.jpg b/static/img/rejection_map/vernacular-map-experiments-05.jpg new file mode 100644 index 0000000..6299ac3 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-05.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-06.jpg b/static/img/rejection_map/vernacular-map-experiments-06.jpg new file mode 100644 index 0000000..c07414e Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-06.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-07.jpg b/static/img/rejection_map/vernacular-map-experiments-07.jpg new file mode 100644 index 0000000..03e1acd Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-07.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-08.jpg b/static/img/rejection_map/vernacular-map-experiments-08.jpg new file mode 100644 index 0000000..24f00d3 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-08.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-09.jpg b/static/img/rejection_map/vernacular-map-experiments-09.jpg new file mode 100644 index 0000000..5613d27 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-09.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-10.jpg b/static/img/rejection_map/vernacular-map-experiments-10.jpg new file mode 100644 index 0000000..776f768 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-10.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-11.jpg b/static/img/rejection_map/vernacular-map-experiments-11.jpg new file mode 100644 index 0000000..822c015 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-11.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-12.jpg b/static/img/rejection_map/vernacular-map-experiments-12.jpg new file mode 100644 index 0000000..1dc91c8 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-12.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-13.jpg b/static/img/rejection_map/vernacular-map-experiments-13.jpg new file mode 100644 index 0000000..1a5d902 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-13.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-14.jpg b/static/img/rejection_map/vernacular-map-experiments-14.jpg new file mode 100644 index 0000000..c92d8d1 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-14.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-15.jpg b/static/img/rejection_map/vernacular-map-experiments-15.jpg new file mode 100644 index 0000000..86013f2 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-15.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-16.jpg b/static/img/rejection_map/vernacular-map-experiments-16.jpg new file mode 100644 index 0000000..98a07fd Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-16.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-17.jpg b/static/img/rejection_map/vernacular-map-experiments-17.jpg new file mode 100644 index 0000000..6a623ac Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-17.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-18.jpg b/static/img/rejection_map/vernacular-map-experiments-18.jpg new file mode 100644 index 0000000..4af04b5 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-18.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-19.jpg b/static/img/rejection_map/vernacular-map-experiments-19.jpg new file mode 100644 index 0000000..dbee49a Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-19.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-20.jpg b/static/img/rejection_map/vernacular-map-experiments-20.jpg new file mode 100644 index 0000000..b1c4357 Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-20.jpg differ diff --git a/static/img/rejection_map/vernacular-map-experiments-21.jpg b/static/img/rejection_map/vernacular-map-experiments-21.jpg new file mode 100644 index 0000000..eb6139b Binary files /dev/null and b/static/img/rejection_map/vernacular-map-experiments-21.jpg differ diff --git a/static/img/rotterdam_impressions/map_00.jpg b/static/img/rotterdam_impressions/map_00.jpg new file mode 100644 index 0000000..e1465c7 Binary files /dev/null and b/static/img/rotterdam_impressions/map_00.jpg differ diff --git a/static/img/rotterdam_impressions/map_01.jpg b/static/img/rotterdam_impressions/map_01.jpg new file mode 100644 index 0000000..a58d054 Binary files /dev/null and b/static/img/rotterdam_impressions/map_01.jpg differ diff --git a/static/img/rotterdam_impressions/map_02.jpg b/static/img/rotterdam_impressions/map_02.jpg new file mode 100644 index 0000000..a5e5d90 Binary files /dev/null and b/static/img/rotterdam_impressions/map_02.jpg differ diff --git a/static/img/rotterdam_impressions/map_03.jpg b/static/img/rotterdam_impressions/map_03.jpg new file mode 100644 index 0000000..08ee57b Binary files /dev/null and b/static/img/rotterdam_impressions/map_03.jpg differ diff --git a/static/img/rotterdam_impressions/map_04.jpg b/static/img/rotterdam_impressions/map_04.jpg new file mode 100644 index 0000000..23cd1cb Binary files /dev/null and b/static/img/rotterdam_impressions/map_04.jpg differ diff --git a/static/img/rotterdam_impressions/prototype_00.jpg b/static/img/rotterdam_impressions/prototype_00.jpg new file mode 100644 index 0000000..829ad0b Binary files /dev/null and b/static/img/rotterdam_impressions/prototype_00.jpg differ diff --git a/static/img/rotterdam_impressions/prototype_01.jpg b/static/img/rotterdam_impressions/prototype_01.jpg new file mode 100644 index 0000000..e9fb356 Binary files /dev/null and b/static/img/rotterdam_impressions/prototype_01.jpg differ diff --git a/static/img/rotterdam_impressions/prototype_02.jpg b/static/img/rotterdam_impressions/prototype_02.jpg new file mode 100644 index 0000000..44b26ab Binary files /dev/null and b/static/img/rotterdam_impressions/prototype_02.jpg differ diff --git a/static/img/seagul.jpg b/static/img/seagul.jpg new file mode 100644 index 0000000..f3c11a3 Binary files /dev/null and b/static/img/seagul.jpg differ diff --git a/static/js/.ipynb_checkpoints/bgColor-checkpoint.js b/static/js/.ipynb_checkpoints/bgColor-checkpoint.js new file mode 100644 index 0000000..789817f --- /dev/null +++ b/static/js/.ipynb_checkpoints/bgColor-checkpoint.js @@ -0,0 +1,6 @@ +let palette = ["--blue","--pink","--orange","--yellow","--green"]; + +window.addEventListener("load", () => { + let color = palette[(palette.length * Math.random()) | 0]; + document.documentElement.style.setProperty("--background", `var(${color})`); +}); diff --git a/static/js/.ipynb_checkpoints/bubbles-checkpoint.js b/static/js/.ipynb_checkpoints/bubbles-checkpoint.js new file mode 100644 index 0000000..155ff4c --- /dev/null +++ b/static/js/.ipynb_checkpoints/bubbles-checkpoint.js @@ -0,0 +1,13 @@ +const bubbles = document.querySelectorAll('.bubble') +console.log(bubbles) + +let colors = ["--blue","--pink","--orange","--yellow","--green"]; + + + +Array.from(bubbles).forEach(bubble=>{ + let color = colors[(colors.length * Math.random()) | 0]; + bubble.style.backgroundColor = `var(${color})`; + bubble.style.transform = `rotate(${Math.random() * 10 - 5}deg)` + +}) \ No newline at end of file diff --git a/static/js/.ipynb_checkpoints/eventMode-checkpoint.js b/static/js/.ipynb_checkpoints/eventMode-checkpoint.js new file mode 100644 index 0000000..5dd9833 --- /dev/null +++ b/static/js/.ipynb_checkpoints/eventMode-checkpoint.js @@ -0,0 +1,32 @@ +const snippetsContainer = document.getElementById('snippets-container') + +let pathname = window.location.pathname.replace('/soupboat/si16-app/','') +let page = pathname.substring(0, pathname.length - 1); +let endpoint = `https://hub.xpub.nl/soupboat/si16-app/api/is-event-mode/?page=${page}`; + +fetch(endpoint) + .then((response) => response.json()) + .then((data) => { + if (data.event && data.snippets) { + data.snippets.forEach(snippet=>{ + console.log(snippet) + if(snippet.type == 'text') textSnippet(snippet.content) + if(snippet.type == 'image') imageSnippet(snippet) + + }) + } + }); + +function textSnippet(text){ + let snippetBubble = document.createElement('div') + snippetBubble.classList.add('snippet') + snippetBubble.innerHTML = text + snippetsContainer.appendChild(snippetBubble) +} + +function imageSnippet(snippet){ + let snippetBubble = document.createElement('img') + snippetBubble.classList.add('snippet') + snippetBubble.src = "/soupboat/si16-app" + snippet.content + snippetsContainer.appendChild(snippetBubble) +} \ No newline at end of file diff --git a/static/js/.ipynb_checkpoints/inputList-checkpoint.js b/static/js/.ipynb_checkpoints/inputList-checkpoint.js new file mode 100644 index 0000000..aba9beb --- /dev/null +++ b/static/js/.ipynb_checkpoints/inputList-checkpoint.js @@ -0,0 +1,19 @@ +const listElements = document.getElementsByClassName('list-input') + +function insertAfter(referenceNode, newNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); +} + + +Array.from(listElements).forEach(input => { + let add = document.createElement('button') + console.log(input) + add.innerHTML = '+' + add.addEventListener('click', (e)=>{ + e.preventDefault() + cloneInput = input.cloneNode(true) + insertAfter(input, cloneInput) + }) + insertAfter(input, add) +}) + diff --git a/static/js/.ipynb_checkpoints/playgroundTest-checkpoint.js b/static/js/.ipynb_checkpoints/playgroundTest-checkpoint.js new file mode 100644 index 0000000..e825643 --- /dev/null +++ b/static/js/.ipynb_checkpoints/playgroundTest-checkpoint.js @@ -0,0 +1,19 @@ +const playgroundForm = document.getElementById("playground"); +const playgroundSubmit = document.getElementById("playgroundSubmit"); +const playgroundOutput = document.getElementById("playgroundOutput"); + +// console.log(playgroundForm.elements); + +playgroundSubmit.addEventListener("click", (e) => { + // sorry for this + let query = ""; + Object.keys(playgroundForm.dataset).forEach((input) => { + query += `${input}=${playgroundForm.elements[input].value}&`; + }); + let endpoint = `${playgroundForm.action}?${query}`; + fetch(endpoint) + .then(response => response.text()) + .then((data) => { + playgroundOutput.innerHTML = data + }); +}); diff --git a/static/js/annotation-compass/.ipynb_checkpoints/labels-checkpoint.js b/static/js/annotation-compass/.ipynb_checkpoints/labels-checkpoint.js new file mode 100644 index 0000000..6693a07 --- /dev/null +++ b/static/js/annotation-compass/.ipynb_checkpoints/labels-checkpoint.js @@ -0,0 +1,386 @@ +// Get the container to use as a canvas +const container = document.getElementById("container"); +const editor = document.getElementById("editor"); +const backgroundImage = document.getElementById("background-image"); +const imageTarget = document.getElementById("target"); +const backgroundContainer = document.getElementById("background-container"); + +let backgroundWidth; +let backgroundHeight; + +window.addEventListener("load", () => { + targetSize(); +}); + +window.addEventListener("resize", (e) => { + targetSize(); +}); + +function targetSize() { + backgroundWidth = backgroundImage.width; + backgroundHeight = backgroundImage.height; + + // cringe + imageTarget.style.width = backgroundWidth + "px"; + imageTarget.style.height = backgroundHeight + "px"; +} + +// List of labels +let labels = []; +let labelsObj = []; + +let closing = false; + +// Start is where the mouse is pressed, End is where the mouse is released +let startX; +let startY; +let endX; +let endY; + +// Minimum size % for the label to be created +let minimumSizeX = 1; +let minimumSizeY = 1; + +// Boolean for showing the editor during drawing +let showEditor = false; +let editorX = 0; +let editorY = 0; + +function percentagePosition(e, target) { + let targetRect = target.getBoundingClientRect(); + let x = e.clientX - targetRect.left; + let y = e.clientY - targetRect.top; + + return { x: (x / backgroundWidth) * 100, y: (y / backgroundHeight) * 100 }; +} + +window.addEventListener("mousedown", (e) => { + let percentage = percentagePosition(e, imageTarget); + + if (e.target.tagName !== "BUTTON" && e.target.tagName !== "TEXTAREA") { + startX = percentage.x; + startY = percentage.y; + + editorX = e.x; + editorY = e.y; + + // activate the editor + showEditor = true; + editor.classList.add("show-editor"); + } +}); + +// Store the coordinates and trigger the function +window.addEventListener("mouseup", (e) => { + if (e.target.tagName !== "BUTTON" && e.target.tagName !== "TEXTAREA") { + let percentage = percentagePosition(e, imageTarget); + + endX = percentage.x; + endY = percentage.y; + + // disable the editor + showEditor = false; + editor.classList.remove("show-editor"); + editor.style.width = 0; + editor.style.height = 0; + + // draw label + drawLabel(); + } +}); + +// Edit the editor box using transform instead of left / top in order to be more efficient +// (but still with width and height ehm idk if this affects the performance a lot) +// (and it is something we must care of because this event is called like every frame that the mouse is dragged) + +window.addEventListener("mousemove", (e) => { + if (showEditor) { + let minX = Math.min(editorX, e.x); + let minY = Math.min(editorY, e.y); + + let maxX = Math.max(editorX, e.x); + let maxY = Math.max(editorY, e.y); + + let width = maxX - minX; + let height = maxY - minY; + + // Apply a different class when the sizes pass the minimum size + // (i don't know if is good made like this) + if (width > minimumSizeX && height > minimumSizeY) { + editor.classList.add("can-draw"); + } else { + editor.classList.remove("can-draw"); + } + + editor.style.transform = `translate(${minX}px, ${minY}px)`; + editor.style.width = `${maxX - minX}px`; + editor.style.height = `${maxY - minY}px`; + } +}); + +// Store the coordinates and trigger the function +// container.addEventListener("mousedown", (e) => { +// // Avoid inserting a new label if the user is clicking on a close button) +// if (e.target.tagName !== "BUTTON" && e.target.tagName !== "TEXTAREA") { +// startX = e.x; +// startY = e.y; + +// // activate the editor +// showEditor = true; +// editor.classList.add("show-editor"); +// } +// }); + +// container.addEventListener("mouseup", (e) => { +// if (e.target.tagName !== "BUTTON" && e.target.tagName !== "TEXTAREA") { +// endX = e.x; +// endY = e.y; + +// // disable the editor +// showEditor = false; +// editor.classList.remove("show-editor"); +// editor.style.width = 0; +// editor.style.height = 0; + +// // draw label +// drawLabel(); +// } +// }); + +// Edit the editor box using transform instead of left / top in order to be more efficient +// (but still with width and height ehm idk if this affects the performance a lot) +// (and it is something we must care of because this event is called like every frame that the mouse is dragged) +// container.addEventListener("mousemove", (e) => { +// if (showEditor) { +// let minX = Math.min(startX, e.x); +// let minY = Math.min(startY, e.y); + +// let maxX = Math.max(startX, e.x); +// let maxY = Math.max(startY, e.y); + +// let width = maxX - minX; +// let height = maxY - minY; + +// // Apply a different class when the sizes pass the minimum size +// // (i don't know if is good made like this) +// if (width > minimumSizeX && height > minimumSizeY) { +// editor.classList.add("can-draw"); +// } else { +// editor.classList.remove("can-draw"); +// } + +// editor.style.transform = `translate(${minX}px, ${minY}px)`; +// editor.style.width = `${maxX - minX}px`; +// editor.style.height = `${maxY - minY}px`; +// } +// }); + +// Check the mouse direction and create the Label +// The origin points of the label (because is positioned with top left) are always the lowest x and y values +// The width and height are the greater x and y values (because width and height cannot be negative) + +function drawLabel() { + let minX = Math.min(startX, endX); + let minY = Math.min(startY, endY); + + let maxX = Math.max(startX, endX); + let maxY = Math.max(startY, endY); + + let width = maxX - minX; + let height = maxY - minY; + + if (width > minimumSizeX && height > minimumSizeY) { + // Create a label and push it into the array of labels + let temporaryLabel = createLabel(minX, minY, width, height, labels.length); + temporaryLabel.classList.add("temporary"); + + let form = document.createElement("form"); + let input = document.createElement("textarea"); + input.placeholder = "Describe this area"; + + let insert = document.createElement("button"); + insert.innerHTML = "Insert"; + + let cancel = document.createElement("button"); + cancel.innerHTML = "x"; + + form.appendChild(input); + form.appendChild(insert); + form.appendChild(cancel); + + temporaryLabel.appendChild(form); + + imageTarget.appendChild(temporaryLabel); + + new Promise(function (resolve, reject) { + // then if the user click insert and there is a value in the input-- > resolve the promise and return the text input to create the label, + // if the user click cancel-- > reject the promise and don't create the label + + input.focus(); + + // Insert button + insert.addEventListener("click", (e) => { + e.preventDefault(); + if (input.value) { + resolve(); + } + }); + + // Cancel button + cancel.addEventListener("click", (e) => { + e.preventDefault(); + reject(); + }); + }) + .then(() => { + // Create the label + let label = createLabel(minX, minY, width, height, labels.length); + + // Add the text input to the label + let text = document.createElement("p"); + text.classList.add("label--text"); + text.innerHTML = input.value; + label.appendChild(text); + + let labelObj = { + position: { + x: minX, + y: minY, + }, + size: { + width: width, + height: height, + }, + index: labels.length, + text: input.value, + timestamp: Date.now(), + userID: userID, + image: backgroundImage.dataset.image + }; + + uploadLabel(labelObj); + labelsObj.push(labelObj); + labels.push(label); + + imageTarget.appendChild(label); + createLabelTranscription(input.value); + }) + .catch((e) => {}) + .then(() => { + imageTarget.removeChild(temporaryLabel); + }); + } +} + +// Create the label element +function createLabel(x, y, width, height, index) { + let label = document.createElement("div"); + label.classList.add("label"); + label.style.left = `${x}%`; + label.style.top = `${y}%`; + label.style.width = `${width}%`; + label.style.height = `${height}%`; + + // data attribute index maybe we will need it later maybe not + // with the index number of the label +// label.setAttribute("data-index", index); + + // Insert the number in the label + let labelNumber = document.createElement("p"); + labelNumber.classList.add("label--number"); + labelNumber.innerHTML = index + 1; + label.appendChild(labelNumber); + + // Add a button for deleting the label + // TODO: reactive numbering oh no + let close = document.createElement("button"); + close.classList.add("label--close"); + close.innerHTML = "x"; + close.addEventListener("click", (e) => { + label.remove(); + }); + label.appendChild(close); + + return label; +} + +const transcriptionPanel = document.getElementById("transcription-panel"); +const transcriptionList = transcriptionPanel.querySelector("ol"); + +function createLabelTranscription(text) { + let transcription = document.createElement("li"); + transcription.innerHTML = text; + + transcriptionList.appendChild(transcription); +} + +function uploadLabel(obj) { + fetch("https://hub.xpub.nl/soupboat/si16/annotation-compass/add-label/", { + method: "POST", // or 'PUT' + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(obj), + }) + .then((response) => response.json()) + .then((data) => { + console.log("Success:", data); + }) + .catch((error) => { + console.error("Error:", error); + }); +} + +const load = document.getElementById("load-labels"); +load.addEventListener("click", loadLabels); + +function loadLabels() { + console.log('load labels') + load.removeEventListener("click", loadLabels); + fetch(`https://hub.xpub.nl/soupboat/si16/annotation-compass/get-labels/${backgroundImage.dataset.image}/`) + .then((response) => { + return response.json(); + }) + .then((data) => { + labelsObj.push(...data.labels); + + data.labels.forEach((label, index)=> { + +// data.labels.forEach((touple, index) => { +// let [label_id, label_x, label_y, label_width, label_height, label_text, label_timestamp, label_userID, label_image] = touple +// let labelElement = createLabel( +// label_x, +// label_y, +// label_width, +// label_height, +// index +// ); + + + let labelElement = createLabel( + label.position.x, + label.position.y, + label.size.width, + label.size.height, + index + ); + + // THIS IS TEMPORARY + labelElement.style.backgroundColor = `hsla(${Math.floor( + (label.userID / 10000000000) * 255 + )}, 100%, 75%, 0.2)`; + + // Add the text input to the label + let text = document.createElement("p"); + text.classList.add("label--text"); + text.innerHTML = label.text + labelElement.appendChild(text); + + labelElement.classList.add("loaded"); + + imageTarget.appendChild(labelElement); + + createLabelTranscription(label.text); + }); + }); +} diff --git a/static/js/annotation-compass/.ipynb_checkpoints/panels-checkpoint.js b/static/js/annotation-compass/.ipynb_checkpoints/panels-checkpoint.js new file mode 100644 index 0000000..b05df8f --- /dev/null +++ b/static/js/annotation-compass/.ipynb_checkpoints/panels-checkpoint.js @@ -0,0 +1,20 @@ +const showInfo = document.getElementById("show-info"); +const infoPanel = document.getElementById("info-panel"); + +showInfo.addEventListener("click", (e) => { + infoPanel.classList.add("active"); + infoPanel.querySelector(".close").addEventListener("click", (e) => { + infoPanel.classList.remove("active"); + }); +}); + +const showTranscription = document.getElementById("show-transcription"); +// declared previously in labels.js +// const transcriptionPanel = document.getElementById("transcription-panel"); + +showTranscription.addEventListener("click", (e) => { + transcriptionPanel.classList.add("active"); + transcriptionPanel.querySelector(".close").addEventListener("click", (e) => { + transcriptionPanel.classList.remove("active"); + }); +}); diff --git a/static/js/annotation-compass/.ipynb_checkpoints/picture-checkpoint.js b/static/js/annotation-compass/.ipynb_checkpoints/picture-checkpoint.js new file mode 100644 index 0000000..17480f7 --- /dev/null +++ b/static/js/annotation-compass/.ipynb_checkpoints/picture-checkpoint.js @@ -0,0 +1,25 @@ +// let fileName = ""; + +// window.addEventListener("load", function () { +// let input = document.querySelector('input[type="file"]'); +// input.addEventListener("change", function () { +// if (this.files && this.files[0]) { +// fileName = this.files[0].name; +// let img = document.querySelector("img"); +// img.onload = () => { +// img.classList.add("visible"); +// input.classList.add("hidden"); +// URL.revokeObjectURL(img.src); // no longer needed, free memory +// }; + +// img.src = URL.createObjectURL(this.files[0]); // set src to blob url +// } +// }); +// }); + +const imageButton = document.getElementById("show-image"); + +imageButton.addEventListener("click", (e) => { + let img = document.querySelector("img"); + img.classList.toggle("hidden"); +}); diff --git a/static/js/annotation-compass/.ipynb_checkpoints/session-checkpoint.js b/static/js/annotation-compass/.ipynb_checkpoints/session-checkpoint.js new file mode 100644 index 0000000..127c885 --- /dev/null +++ b/static/js/annotation-compass/.ipynb_checkpoints/session-checkpoint.js @@ -0,0 +1 @@ +const userID = Math.round(Math.random() * 10000000000); diff --git a/static/js/annotation-compass/.ipynb_checkpoints/text-export-checkpoint.js b/static/js/annotation-compass/.ipynb_checkpoints/text-export-checkpoint.js new file mode 100644 index 0000000..8222195 --- /dev/null +++ b/static/js/annotation-compass/.ipynb_checkpoints/text-export-checkpoint.js @@ -0,0 +1,50 @@ +const exportButton = document.getElementById("export-text"); +const imageElement = document.getElementById("background-image"); + +const checkJSON = document.getElementById("checkJSON"); +const checkTEXT = document.getElementById("checkText"); + +let fileUrl = imageElement.src; +let fileName = fileUrl.slice(fileUrl.lastIndexOf("/") + 1, fileUrl.length); +let fileTitle = fileName.slice(0, fileName.indexOf(".")) || "export"; + + +exportButton.addEventListener("click", (e) => { + console.log(checkJSON.value, checkTEXT.value) + if (checkJSON.checked) exportJSON(); + if (checkTEXT.checked) exportText(); +}); + +function exportText() { + let text = document.querySelector("ol").innerText; + let title = fileTitle + ".txt"; + download(text, title, "text/plain;charset=utf-8"); +} + +function exportJSON() { + let title = fileTitle + ".json"; + download(JSON.stringify(labelsObj), title, "application/json"); +} + +// https://stackoverflow.com/questions/13405129/javascript-create-and-save-file +// Thank you Kanchu! +// Function to download data to a file +function download(data, filename, type) { + var file = new Blob([data], { type: type }); + if (window.navigator.msSaveOrOpenBlob) + // IE10+ + window.navigator.msSaveOrOpenBlob(file, filename); + else { + // Others + var a = document.createElement("a"), + url = URL.createObjectURL(file); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + setTimeout(function () { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 0); + } +} diff --git a/static/js/annotation-compass/labels.js b/static/js/annotation-compass/labels.js new file mode 100644 index 0000000..6693a07 --- /dev/null +++ b/static/js/annotation-compass/labels.js @@ -0,0 +1,386 @@ +// Get the container to use as a canvas +const container = document.getElementById("container"); +const editor = document.getElementById("editor"); +const backgroundImage = document.getElementById("background-image"); +const imageTarget = document.getElementById("target"); +const backgroundContainer = document.getElementById("background-container"); + +let backgroundWidth; +let backgroundHeight; + +window.addEventListener("load", () => { + targetSize(); +}); + +window.addEventListener("resize", (e) => { + targetSize(); +}); + +function targetSize() { + backgroundWidth = backgroundImage.width; + backgroundHeight = backgroundImage.height; + + // cringe + imageTarget.style.width = backgroundWidth + "px"; + imageTarget.style.height = backgroundHeight + "px"; +} + +// List of labels +let labels = []; +let labelsObj = []; + +let closing = false; + +// Start is where the mouse is pressed, End is where the mouse is released +let startX; +let startY; +let endX; +let endY; + +// Minimum size % for the label to be created +let minimumSizeX = 1; +let minimumSizeY = 1; + +// Boolean for showing the editor during drawing +let showEditor = false; +let editorX = 0; +let editorY = 0; + +function percentagePosition(e, target) { + let targetRect = target.getBoundingClientRect(); + let x = e.clientX - targetRect.left; + let y = e.clientY - targetRect.top; + + return { x: (x / backgroundWidth) * 100, y: (y / backgroundHeight) * 100 }; +} + +window.addEventListener("mousedown", (e) => { + let percentage = percentagePosition(e, imageTarget); + + if (e.target.tagName !== "BUTTON" && e.target.tagName !== "TEXTAREA") { + startX = percentage.x; + startY = percentage.y; + + editorX = e.x; + editorY = e.y; + + // activate the editor + showEditor = true; + editor.classList.add("show-editor"); + } +}); + +// Store the coordinates and trigger the function +window.addEventListener("mouseup", (e) => { + if (e.target.tagName !== "BUTTON" && e.target.tagName !== "TEXTAREA") { + let percentage = percentagePosition(e, imageTarget); + + endX = percentage.x; + endY = percentage.y; + + // disable the editor + showEditor = false; + editor.classList.remove("show-editor"); + editor.style.width = 0; + editor.style.height = 0; + + // draw label + drawLabel(); + } +}); + +// Edit the editor box using transform instead of left / top in order to be more efficient +// (but still with width and height ehm idk if this affects the performance a lot) +// (and it is something we must care of because this event is called like every frame that the mouse is dragged) + +window.addEventListener("mousemove", (e) => { + if (showEditor) { + let minX = Math.min(editorX, e.x); + let minY = Math.min(editorY, e.y); + + let maxX = Math.max(editorX, e.x); + let maxY = Math.max(editorY, e.y); + + let width = maxX - minX; + let height = maxY - minY; + + // Apply a different class when the sizes pass the minimum size + // (i don't know if is good made like this) + if (width > minimumSizeX && height > minimumSizeY) { + editor.classList.add("can-draw"); + } else { + editor.classList.remove("can-draw"); + } + + editor.style.transform = `translate(${minX}px, ${minY}px)`; + editor.style.width = `${maxX - minX}px`; + editor.style.height = `${maxY - minY}px`; + } +}); + +// Store the coordinates and trigger the function +// container.addEventListener("mousedown", (e) => { +// // Avoid inserting a new label if the user is clicking on a close button) +// if (e.target.tagName !== "BUTTON" && e.target.tagName !== "TEXTAREA") { +// startX = e.x; +// startY = e.y; + +// // activate the editor +// showEditor = true; +// editor.classList.add("show-editor"); +// } +// }); + +// container.addEventListener("mouseup", (e) => { +// if (e.target.tagName !== "BUTTON" && e.target.tagName !== "TEXTAREA") { +// endX = e.x; +// endY = e.y; + +// // disable the editor +// showEditor = false; +// editor.classList.remove("show-editor"); +// editor.style.width = 0; +// editor.style.height = 0; + +// // draw label +// drawLabel(); +// } +// }); + +// Edit the editor box using transform instead of left / top in order to be more efficient +// (but still with width and height ehm idk if this affects the performance a lot) +// (and it is something we must care of because this event is called like every frame that the mouse is dragged) +// container.addEventListener("mousemove", (e) => { +// if (showEditor) { +// let minX = Math.min(startX, e.x); +// let minY = Math.min(startY, e.y); + +// let maxX = Math.max(startX, e.x); +// let maxY = Math.max(startY, e.y); + +// let width = maxX - minX; +// let height = maxY - minY; + +// // Apply a different class when the sizes pass the minimum size +// // (i don't know if is good made like this) +// if (width > minimumSizeX && height > minimumSizeY) { +// editor.classList.add("can-draw"); +// } else { +// editor.classList.remove("can-draw"); +// } + +// editor.style.transform = `translate(${minX}px, ${minY}px)`; +// editor.style.width = `${maxX - minX}px`; +// editor.style.height = `${maxY - minY}px`; +// } +// }); + +// Check the mouse direction and create the Label +// The origin points of the label (because is positioned with top left) are always the lowest x and y values +// The width and height are the greater x and y values (because width and height cannot be negative) + +function drawLabel() { + let minX = Math.min(startX, endX); + let minY = Math.min(startY, endY); + + let maxX = Math.max(startX, endX); + let maxY = Math.max(startY, endY); + + let width = maxX - minX; + let height = maxY - minY; + + if (width > minimumSizeX && height > minimumSizeY) { + // Create a label and push it into the array of labels + let temporaryLabel = createLabel(minX, minY, width, height, labels.length); + temporaryLabel.classList.add("temporary"); + + let form = document.createElement("form"); + let input = document.createElement("textarea"); + input.placeholder = "Describe this area"; + + let insert = document.createElement("button"); + insert.innerHTML = "Insert"; + + let cancel = document.createElement("button"); + cancel.innerHTML = "x"; + + form.appendChild(input); + form.appendChild(insert); + form.appendChild(cancel); + + temporaryLabel.appendChild(form); + + imageTarget.appendChild(temporaryLabel); + + new Promise(function (resolve, reject) { + // then if the user click insert and there is a value in the input-- > resolve the promise and return the text input to create the label, + // if the user click cancel-- > reject the promise and don't create the label + + input.focus(); + + // Insert button + insert.addEventListener("click", (e) => { + e.preventDefault(); + if (input.value) { + resolve(); + } + }); + + // Cancel button + cancel.addEventListener("click", (e) => { + e.preventDefault(); + reject(); + }); + }) + .then(() => { + // Create the label + let label = createLabel(minX, minY, width, height, labels.length); + + // Add the text input to the label + let text = document.createElement("p"); + text.classList.add("label--text"); + text.innerHTML = input.value; + label.appendChild(text); + + let labelObj = { + position: { + x: minX, + y: minY, + }, + size: { + width: width, + height: height, + }, + index: labels.length, + text: input.value, + timestamp: Date.now(), + userID: userID, + image: backgroundImage.dataset.image + }; + + uploadLabel(labelObj); + labelsObj.push(labelObj); + labels.push(label); + + imageTarget.appendChild(label); + createLabelTranscription(input.value); + }) + .catch((e) => {}) + .then(() => { + imageTarget.removeChild(temporaryLabel); + }); + } +} + +// Create the label element +function createLabel(x, y, width, height, index) { + let label = document.createElement("div"); + label.classList.add("label"); + label.style.left = `${x}%`; + label.style.top = `${y}%`; + label.style.width = `${width}%`; + label.style.height = `${height}%`; + + // data attribute index maybe we will need it later maybe not + // with the index number of the label +// label.setAttribute("data-index", index); + + // Insert the number in the label + let labelNumber = document.createElement("p"); + labelNumber.classList.add("label--number"); + labelNumber.innerHTML = index + 1; + label.appendChild(labelNumber); + + // Add a button for deleting the label + // TODO: reactive numbering oh no + let close = document.createElement("button"); + close.classList.add("label--close"); + close.innerHTML = "x"; + close.addEventListener("click", (e) => { + label.remove(); + }); + label.appendChild(close); + + return label; +} + +const transcriptionPanel = document.getElementById("transcription-panel"); +const transcriptionList = transcriptionPanel.querySelector("ol"); + +function createLabelTranscription(text) { + let transcription = document.createElement("li"); + transcription.innerHTML = text; + + transcriptionList.appendChild(transcription); +} + +function uploadLabel(obj) { + fetch("https://hub.xpub.nl/soupboat/si16/annotation-compass/add-label/", { + method: "POST", // or 'PUT' + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(obj), + }) + .then((response) => response.json()) + .then((data) => { + console.log("Success:", data); + }) + .catch((error) => { + console.error("Error:", error); + }); +} + +const load = document.getElementById("load-labels"); +load.addEventListener("click", loadLabels); + +function loadLabels() { + console.log('load labels') + load.removeEventListener("click", loadLabels); + fetch(`https://hub.xpub.nl/soupboat/si16/annotation-compass/get-labels/${backgroundImage.dataset.image}/`) + .then((response) => { + return response.json(); + }) + .then((data) => { + labelsObj.push(...data.labels); + + data.labels.forEach((label, index)=> { + +// data.labels.forEach((touple, index) => { +// let [label_id, label_x, label_y, label_width, label_height, label_text, label_timestamp, label_userID, label_image] = touple +// let labelElement = createLabel( +// label_x, +// label_y, +// label_width, +// label_height, +// index +// ); + + + let labelElement = createLabel( + label.position.x, + label.position.y, + label.size.width, + label.size.height, + index + ); + + // THIS IS TEMPORARY + labelElement.style.backgroundColor = `hsla(${Math.floor( + (label.userID / 10000000000) * 255 + )}, 100%, 75%, 0.2)`; + + // Add the text input to the label + let text = document.createElement("p"); + text.classList.add("label--text"); + text.innerHTML = label.text + labelElement.appendChild(text); + + labelElement.classList.add("loaded"); + + imageTarget.appendChild(labelElement); + + createLabelTranscription(label.text); + }); + }); +} diff --git a/static/js/annotation-compass/panels.js b/static/js/annotation-compass/panels.js new file mode 100644 index 0000000..b05df8f --- /dev/null +++ b/static/js/annotation-compass/panels.js @@ -0,0 +1,20 @@ +const showInfo = document.getElementById("show-info"); +const infoPanel = document.getElementById("info-panel"); + +showInfo.addEventListener("click", (e) => { + infoPanel.classList.add("active"); + infoPanel.querySelector(".close").addEventListener("click", (e) => { + infoPanel.classList.remove("active"); + }); +}); + +const showTranscription = document.getElementById("show-transcription"); +// declared previously in labels.js +// const transcriptionPanel = document.getElementById("transcription-panel"); + +showTranscription.addEventListener("click", (e) => { + transcriptionPanel.classList.add("active"); + transcriptionPanel.querySelector(".close").addEventListener("click", (e) => { + transcriptionPanel.classList.remove("active"); + }); +}); diff --git a/static/js/annotation-compass/picture.js b/static/js/annotation-compass/picture.js new file mode 100644 index 0000000..17480f7 --- /dev/null +++ b/static/js/annotation-compass/picture.js @@ -0,0 +1,25 @@ +// let fileName = ""; + +// window.addEventListener("load", function () { +// let input = document.querySelector('input[type="file"]'); +// input.addEventListener("change", function () { +// if (this.files && this.files[0]) { +// fileName = this.files[0].name; +// let img = document.querySelector("img"); +// img.onload = () => { +// img.classList.add("visible"); +// input.classList.add("hidden"); +// URL.revokeObjectURL(img.src); // no longer needed, free memory +// }; + +// img.src = URL.createObjectURL(this.files[0]); // set src to blob url +// } +// }); +// }); + +const imageButton = document.getElementById("show-image"); + +imageButton.addEventListener("click", (e) => { + let img = document.querySelector("img"); + img.classList.toggle("hidden"); +}); diff --git a/static/js/annotation-compass/session.js b/static/js/annotation-compass/session.js new file mode 100644 index 0000000..127c885 --- /dev/null +++ b/static/js/annotation-compass/session.js @@ -0,0 +1 @@ +const userID = Math.round(Math.random() * 10000000000); diff --git a/static/js/annotation-compass/text-export.js b/static/js/annotation-compass/text-export.js new file mode 100644 index 0000000..8222195 --- /dev/null +++ b/static/js/annotation-compass/text-export.js @@ -0,0 +1,50 @@ +const exportButton = document.getElementById("export-text"); +const imageElement = document.getElementById("background-image"); + +const checkJSON = document.getElementById("checkJSON"); +const checkTEXT = document.getElementById("checkText"); + +let fileUrl = imageElement.src; +let fileName = fileUrl.slice(fileUrl.lastIndexOf("/") + 1, fileUrl.length); +let fileTitle = fileName.slice(0, fileName.indexOf(".")) || "export"; + + +exportButton.addEventListener("click", (e) => { + console.log(checkJSON.value, checkTEXT.value) + if (checkJSON.checked) exportJSON(); + if (checkTEXT.checked) exportText(); +}); + +function exportText() { + let text = document.querySelector("ol").innerText; + let title = fileTitle + ".txt"; + download(text, title, "text/plain;charset=utf-8"); +} + +function exportJSON() { + let title = fileTitle + ".json"; + download(JSON.stringify(labelsObj), title, "application/json"); +} + +// https://stackoverflow.com/questions/13405129/javascript-create-and-save-file +// Thank you Kanchu! +// Function to download data to a file +function download(data, filename, type) { + var file = new Blob([data], { type: type }); + if (window.navigator.msSaveOrOpenBlob) + // IE10+ + window.navigator.msSaveOrOpenBlob(file, filename); + else { + // Others + var a = document.createElement("a"), + url = URL.createObjectURL(file); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + setTimeout(function () { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 0); + } +} diff --git a/static/js/bgColor.js b/static/js/bgColor.js new file mode 100644 index 0000000..789817f --- /dev/null +++ b/static/js/bgColor.js @@ -0,0 +1,6 @@ +let palette = ["--blue","--pink","--orange","--yellow","--green"]; + +window.addEventListener("load", () => { + let color = palette[(palette.length * Math.random()) | 0]; + document.documentElement.style.setProperty("--background", `var(${color})`); +}); diff --git a/static/js/bubbles.js b/static/js/bubbles.js new file mode 100644 index 0000000..155ff4c --- /dev/null +++ b/static/js/bubbles.js @@ -0,0 +1,13 @@ +const bubbles = document.querySelectorAll('.bubble') +console.log(bubbles) + +let colors = ["--blue","--pink","--orange","--yellow","--green"]; + + + +Array.from(bubbles).forEach(bubble=>{ + let color = colors[(colors.length * Math.random()) | 0]; + bubble.style.backgroundColor = `var(${color})`; + bubble.style.transform = `rotate(${Math.random() * 10 - 5}deg)` + +}) \ No newline at end of file diff --git a/static/js/eventMode.js b/static/js/eventMode.js new file mode 100644 index 0000000..5dd9833 --- /dev/null +++ b/static/js/eventMode.js @@ -0,0 +1,32 @@ +const snippetsContainer = document.getElementById('snippets-container') + +let pathname = window.location.pathname.replace('/soupboat/si16-app/','') +let page = pathname.substring(0, pathname.length - 1); +let endpoint = `https://hub.xpub.nl/soupboat/si16-app/api/is-event-mode/?page=${page}`; + +fetch(endpoint) + .then((response) => response.json()) + .then((data) => { + if (data.event && data.snippets) { + data.snippets.forEach(snippet=>{ + console.log(snippet) + if(snippet.type == 'text') textSnippet(snippet.content) + if(snippet.type == 'image') imageSnippet(snippet) + + }) + } + }); + +function textSnippet(text){ + let snippetBubble = document.createElement('div') + snippetBubble.classList.add('snippet') + snippetBubble.innerHTML = text + snippetsContainer.appendChild(snippetBubble) +} + +function imageSnippet(snippet){ + let snippetBubble = document.createElement('img') + snippetBubble.classList.add('snippet') + snippetBubble.src = "/soupboat/si16-app" + snippet.content + snippetsContainer.appendChild(snippetBubble) +} \ No newline at end of file diff --git a/static/js/homeSticker.js b/static/js/homeSticker.js new file mode 100644 index 0000000..66cb8e2 --- /dev/null +++ b/static/js/homeSticker.js @@ -0,0 +1,31 @@ +const negativeStickers = document.querySelectorAll(".negative"); +const container = document.getElementById("sticker-container"); + +var throttleSpawn = _.throttle(spawnSticker, 400); + +Array.from(negativeStickers).forEach((spawner) => { + spawner.addEventListener("click", (e) => spawnSticker(e)); +}); + +function spawnSticker(e) { + e.preventDefault(); + e.stopPropagation(); + let position = { x: e.pageX, y: e.pageY }; + getFromNegative(e.target, position); +} + +function getFromNegative(target, position) { + sticker = target.cloneNode(true); + sticker.classList.add("sticker"); + sticker.classList.remove("negative"); + + sticker.style.left = position.x + "px"; + sticker.style.top = position.y + "px"; + + sticker.style.transform = ` + rotate(${Math.random() * 20 - 10}deg) + translate(-50%, -100%) + `; + + container.appendChild(sticker); +} diff --git a/static/js/inputList.js b/static/js/inputList.js new file mode 100644 index 0000000..d13271a --- /dev/null +++ b/static/js/inputList.js @@ -0,0 +1,18 @@ +const listElements = document.getElementsByClassName('list-input') + +function insertAfter(referenceNode, newNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); +} + +Array.from(listElements).forEach(input => { + let add = document.createElement('button') + console.log(input) + add.innerHTML = '+' + add.addEventListener('click', (e)=>{ + e.preventDefault() + cloneInput = input.cloneNode(true) + insertAfter(input, cloneInput) + }) + insertAfter(input, add) +}) + diff --git a/static/js/lodash.js b/static/js/lodash.js new file mode 100644 index 0000000..13ec307 --- /dev/null +++ b/static/js/lodash.js @@ -0,0 +1,137 @@ +/** + * @license + * Lodash lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE + */ +;(function(){function n(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function t(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u"']/g,G=RegExp(V.source),H=RegExp(K.source),J=/<%-([\s\S]+?)%>/g,Y=/<%([\s\S]+?)%>/g,Q=/<%=([\s\S]+?)%>/g,X=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,nn=/^\w*$/,tn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,rn=/[\\^$.*+?()[\]{}|]/g,en=RegExp(rn.source),un=/^\s+|\s+$/g,on=/^\s+/,fn=/\s+$/,cn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,an=/\{\n\/\* \[wrapped with (.+)\] \*/,ln=/,? & /,sn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,hn=/\\(\\)?/g,pn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,_n=/\w*$/,vn=/^[-+]0x[0-9a-f]+$/i,gn=/^0b[01]+$/i,dn=/^\[object .+?Constructor\]$/,yn=/^0o[0-7]+$/i,bn=/^(?:0|[1-9]\d*)$/,xn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,jn=/($^)/,wn=/['\n\r\u2028\u2029\\]/g,mn="[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?(?:\\u200d(?:[^\\ud800-\\udfff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?)*",An="(?:[\\u2700-\\u27bf]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])"+mn,En="(?:[^\\ud800-\\udfff][\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]?|[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\ud800-\\udfff])",kn=RegExp("['\u2019]","g"),Sn=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]","g"),On=RegExp("\\ud83c[\\udffb-\\udfff](?=\\ud83c[\\udffb-\\udfff])|"+En+mn,"g"),In=RegExp(["[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde]|$)|(?:[A-Z\\xc0-\\xd6\\xd8-\\xde]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde](?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])|$)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?(?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:d|ll|m|re|s|t|ve))?|[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?|\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])|\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])|\\d+",An].join("|"),"g"),Rn=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]"),zn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Wn="Array Buffer DataView Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Map Math Object Promise RegExp Set String Symbol TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap _ clearTimeout isFinite parseInt setTimeout".split(" "),Bn={}; +Bn["[object Float32Array]"]=Bn["[object Float64Array]"]=Bn["[object Int8Array]"]=Bn["[object Int16Array]"]=Bn["[object Int32Array]"]=Bn["[object Uint8Array]"]=Bn["[object Uint8ClampedArray]"]=Bn["[object Uint16Array]"]=Bn["[object Uint32Array]"]=true,Bn["[object Arguments]"]=Bn["[object Array]"]=Bn["[object ArrayBuffer]"]=Bn["[object Boolean]"]=Bn["[object DataView]"]=Bn["[object Date]"]=Bn["[object Error]"]=Bn["[object Function]"]=Bn["[object Map]"]=Bn["[object Number]"]=Bn["[object Object]"]=Bn["[object RegExp]"]=Bn["[object Set]"]=Bn["[object String]"]=Bn["[object WeakMap]"]=false; +var Ln={};Ln["[object Arguments]"]=Ln["[object Array]"]=Ln["[object ArrayBuffer]"]=Ln["[object DataView]"]=Ln["[object Boolean]"]=Ln["[object Date]"]=Ln["[object Float32Array]"]=Ln["[object Float64Array]"]=Ln["[object Int8Array]"]=Ln["[object Int16Array]"]=Ln["[object Int32Array]"]=Ln["[object Map]"]=Ln["[object Number]"]=Ln["[object Object]"]=Ln["[object RegExp]"]=Ln["[object Set]"]=Ln["[object String]"]=Ln["[object Symbol]"]=Ln["[object Uint8Array]"]=Ln["[object Uint8ClampedArray]"]=Ln["[object Uint16Array]"]=Ln["[object Uint32Array]"]=true, +Ln["[object Error]"]=Ln["[object Function]"]=Ln["[object WeakMap]"]=false;var Un={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Cn=parseFloat,Dn=parseInt,Mn=typeof global=="object"&&global&&global.Object===Object&&global,Tn=typeof self=="object"&&self&&self.Object===Object&&self,$n=Mn||Tn||Function("return this")(),Fn=typeof exports=="object"&&exports&&!exports.nodeType&&exports,Nn=Fn&&typeof module=="object"&&module&&!module.nodeType&&module,Pn=Nn&&Nn.exports===Fn,Zn=Pn&&Mn.process,qn=function(){ +try{var n=Nn&&Nn.f&&Nn.f("util").types;return n?n:Zn&&Zn.binding&&Zn.binding("util")}catch(n){}}(),Vn=qn&&qn.isArrayBuffer,Kn=qn&&qn.isDate,Gn=qn&&qn.isMap,Hn=qn&&qn.isRegExp,Jn=qn&&qn.isSet,Yn=qn&&qn.isTypedArray,Qn=b("length"),Xn=x({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I", +"\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C", +"\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i", +"\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r", +"\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij", +"\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),nt=x({"&":"&","<":"<",">":">",'"':""","'":"'"}),tt=x({"&":"&","<":"<",">":">",""":'"',"'":"'"}),rt=function x(mn){function An(n){if(yu(n)&&!ff(n)&&!(n instanceof Un)){if(n instanceof On)return n;if(oi.call(n,"__wrapped__"))return Fe(n)}return new On(n)}function En(){}function On(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=T}function Un(n){this.__wrapped__=n, +this.__actions__=[],this.__dir__=1,this.__filtered__=false,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Mn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function _t(n,t,e,u,i,o){var f,c=1&t,a=2&t,l=4&t;if(e&&(f=i?e(n,u,i,o):e(n)),f!==T)return f;if(!du(n))return n;if(u=ff(n)){if(f=me(n),!c)return Ur(n,f)}else{var s=vo(n),h="[object Function]"==s||"[object GeneratorFunction]"==s;if(af(n))return Ir(n,c);if("[object Object]"==s||"[object Arguments]"==s||h&&!i){if(f=a||h?{}:Ae(n),!c)return a?Mr(n,lt(f,n)):Dr(n,at(f,n))}else{if(!Ln[s])return i?n:{};f=Ee(n,s,c)}}if(o||(o=new Zn), +i=o.get(n))return i;o.set(n,f),pf(n)?n.forEach(function(r){f.add(_t(r,t,e,r,n,o))}):sf(n)&&n.forEach(function(r,u){f.set(u,_t(r,t,e,u,n,o))});var a=l?a?ve:_e:a?Bu:Wu,p=u?T:a(n);return r(p||n,function(r,u){p&&(u=r,r=n[u]),ot(f,u,_t(r,t,e,u,n,o))}),f}function vt(n){var t=Wu(n);return function(r){return gt(r,n,t)}}function gt(n,t,r){var e=r.length;if(null==n)return!e;for(n=Qu(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===T&&!(u in n)||!i(o))return false}return true}function dt(n,t,r){if(typeof n!="function")throw new ti("Expected a function"); +return bo(function(){n.apply(T,r)},t)}function yt(n,t,r,e){var u=-1,i=o,a=true,l=n.length,s=[],h=t.length;if(!l)return s;r&&(t=c(t,k(r))),e?(i=f,a=false):200<=t.length&&(i=O,a=false,t=new Nn(t));n:for(;++ut}function Rt(n,t){return null!=n&&oi.call(n,t)}function zt(n,t){return null!=n&&t in Qu(n)}function Wt(n,t,r){for(var e=r?f:o,u=n[0].length,i=n.length,a=i,l=Ku(i),s=1/0,h=[];a--;){var p=n[a];a&&t&&(p=c(p,k(t))),s=Ci(p.length,s), +l[a]=!r&&(t||120<=u&&120<=p.length)?new Nn(a&&p):T}var p=n[0],_=-1,v=l[0];n:for(;++_r.length?t:kt(t,hr(r,0,-1)),r=null==t?t:t[Me(Ve(r))],null==r?T:n(r,t,e)}function Ut(n){return yu(n)&&"[object Arguments]"==Ot(n)}function Ct(n){ +return yu(n)&&"[object ArrayBuffer]"==Ot(n)}function Dt(n){return yu(n)&&"[object Date]"==Ot(n)}function Mt(n,t,r,e,u){if(n===t)t=true;else if(null==n||null==t||!yu(n)&&!yu(t))t=n!==n&&t!==t;else n:{var i=ff(n),o=ff(t),f=i?"[object Array]":vo(n),c=o?"[object Array]":vo(t),f="[object Arguments]"==f?"[object Object]":f,c="[object Arguments]"==c?"[object Object]":c,a="[object Object]"==f,o="[object Object]"==c;if((c=f==c)&&af(n)){if(!af(t)){t=false;break n}i=true,a=false}if(c&&!a)u||(u=new Zn),t=i||_f(n)?se(n,t,r,e,Mt,u):he(n,t,f,r,e,Mt,u);else{ +if(!(1&r)&&(i=a&&oi.call(n,"__wrapped__"),f=o&&oi.call(t,"__wrapped__"),i||f)){n=i?n.value():n,t=f?t.value():t,u||(u=new Zn),t=Mt(n,t,r,e,u);break n}if(c)t:if(u||(u=new Zn),i=1&r,f=_e(n),o=f.length,c=_e(t).length,o==c||i){for(a=o;a--;){var l=f[a];if(!(i?l in t:oi.call(t,l))){t=false;break t}}if((c=u.get(n))&&u.get(t))t=c==t;else{c=true,u.set(n,t),u.set(t,n);for(var s=i;++at?r:0,Se(t,r)?n[t]:T}function Xt(n,t,r){var e=-1;return t=c(t.length?t:[$u],k(ye())),n=Gt(n,function(n){return{ +a:c(t,function(t){return t(n)}),b:++e,c:n}}),w(n,function(n,t){var e;n:{e=-1;for(var u=n.a,i=t.a,o=u.length,f=r.length;++e=f?c:c*("desc"==r[e]?-1:1);break n}}e=n.b-t.b}return e})}function nr(n,t){return tr(n,t,function(t,r){return zu(n,r)})}function tr(n,t,r){for(var e=-1,u=t.length,i={};++et||9007199254740991t&&(t=-t>u?0:u+t),r=r>u?u:r,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Ku(u);++e=u){for(;e>>1,o=n[i];null!==o&&!wu(o)&&(r?o<=t:ot.length?n:kt(n,hr(t,0,-1)),null==n||delete n[Me(Ve(t))]}function jr(n,t,r,e){for(var u=n.length,i=e?u:-1;(e?i--:++ie)return e?br(n[0]):[];for(var u=-1,i=Ku(e);++u=e?n:hr(n,t,r)}function Ir(n,t){if(t)return n.slice();var r=n.length,r=gi?gi(r):new n.constructor(r);return n.copy(r),r}function Rr(n){var t=new n.constructor(n.byteLength);return new vi(t).set(new vi(n)), +t}function zr(n,t){return new n.constructor(t?Rr(n.buffer):n.buffer,n.byteOffset,n.length)}function Wr(n,t){if(n!==t){var r=n!==T,e=null===n,u=n===n,i=wu(n),o=t!==T,f=null===t,c=t===t,a=wu(t);if(!f&&!a&&!i&&n>t||i&&o&&c&&!f&&!a||e&&o&&c||!r&&c||!u)return 1;if(!e&&!i&&!a&&nu?T:i,u=1),t=Qu(t);++eo&&f[0]!==a&&f[o-1]!==a?[]:L(f,a), +o-=c.length,or?r?or(t,n):t:(r=or(t,Oi(n/D(t))),Rn.test(t)?Or(M(r),0,n).join(""):r.slice(0,n))}function te(t,r,e,u){function i(){for(var r=-1,c=arguments.length,a=-1,l=u.length,s=Ku(l+c),h=this&&this!==$n&&this instanceof i?f:t;++at||e)&&(1&n&&(i[2]=h[2],t|=1&r?0:4),(r=h[3])&&(e=i[3],i[3]=e?Br(e,r,h[4]):r,i[4]=e?L(i[3],"__lodash_placeholder__"):h[4]),(r=h[5])&&(e=i[5],i[5]=e?Lr(e,r,h[6]):r,i[6]=e?L(i[5],"__lodash_placeholder__"):h[6]),(r=h[7])&&(i[7]=r),128&n&&(i[8]=null==i[8]?h[8]:Ci(i[8],h[8])),null==i[9]&&(i[9]=h[9]),i[0]=h[0],i[1]=t),n=i[0], +t=i[1],r=i[2],e=i[3],u=i[4],f=i[9]=i[9]===T?c?0:n.length:Ui(i[9]-a,0),!f&&24&t&&(t&=-25),Ue((h?co:yo)(t&&1!=t?8==t||16==t?Kr(n,t,f):32!=t&&33!=t||u.length?Jr.apply(T,i):te(n,t,r,e):Pr(n,t,r),i),n,t)}function ce(n,t,r,e){return n===T||lu(n,ei[r])&&!oi.call(e,r)?t:n}function ae(n,t,r,e,u,i){return du(n)&&du(t)&&(i.set(t,n),Yt(n,t,T,ae,i),i.delete(t)),n}function le(n){return xu(n)?T:n}function se(n,t,r,e,u,i){var o=1&r,f=n.length,c=t.length;if(f!=c&&!(o&&c>f))return false;if((c=i.get(n))&&i.get(t))return c==t; +var c=-1,a=true,l=2&r?new Nn:T;for(i.set(n,t),i.set(t,n);++cr&&(r=Ui(e+r,0)),_(n,ye(t,3),r)):-1}function Pe(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e-1;return r!==T&&(u=Eu(r),u=0>r?Ui(e+u,0):Ci(u,e-1)), +_(n,ye(t,3),u,true)}function Ze(n){return(null==n?0:n.length)?wt(n,1):[]}function qe(n){return n&&n.length?n[0]:T}function Ve(n){var t=null==n?0:n.length;return t?n[t-1]:T}function Ke(n,t){return n&&n.length&&t&&t.length?er(n,t):n}function Ge(n){return null==n?n:$i.call(n)}function He(n){if(!n||!n.length)return[];var t=0;return n=i(n,function(n){if(hu(n))return t=Ui(n.length,t),true}),A(t,function(t){return c(n,b(t))})}function Je(t,r){if(!t||!t.length)return[];var e=He(t);return null==r?e:c(e,function(t){ +return n(r,T,t)})}function Ye(n){return n=An(n),n.__chain__=true,n}function Qe(n,t){return t(n)}function Xe(){return this}function nu(n,t){return(ff(n)?r:uo)(n,ye(t,3))}function tu(n,t){return(ff(n)?e:io)(n,ye(t,3))}function ru(n,t){return(ff(n)?c:Gt)(n,ye(t,3))}function eu(n,t,r){return t=r?T:t,t=n&&null==t?n.length:t,fe(n,128,T,T,T,T,t)}function uu(n,t){var r;if(typeof t!="function")throw new ti("Expected a function");return n=Eu(n),function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=T), +r}}function iu(n,t,r){return t=r?T:t,n=fe(n,8,T,T,T,T,T,t),n.placeholder=iu.placeholder,n}function ou(n,t,r){return t=r?T:t,n=fe(n,16,T,T,T,T,T,t),n.placeholder=ou.placeholder,n}function fu(n,t,r){function e(t){var r=c,e=a;return c=a=T,_=t,s=n.apply(e,r)}function u(n){var r=n-p;return n-=_,p===T||r>=t||0>r||g&&n>=l}function i(){var n=Go();if(u(n))return o(n);var r,e=bo;r=n-_,n=t-(n-p),r=g?Ci(n,l-r):n,h=e(i,r)}function o(n){return h=T,d&&c?e(n):(c=a=T,s)}function f(){var n=Go(),r=u(n);if(c=arguments, +a=this,p=n,r){if(h===T)return _=n=p,h=bo(i,t),v?e(n):s;if(g)return lo(h),h=bo(i,t),e(p)}return h===T&&(h=bo(i,t)),s}var c,a,l,s,h,p,_=0,v=false,g=false,d=true;if(typeof n!="function")throw new ti("Expected a function");return t=Su(t)||0,du(r)&&(v=!!r.leading,l=(g="maxWait"in r)?Ui(Su(r.maxWait)||0,t):l,d="trailing"in r?!!r.trailing:d),f.cancel=function(){h!==T&&lo(h),_=0,c=p=a=h=T},f.flush=function(){return h===T?s:o(Go())},f}function cu(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache; +return i.has(u)?i.get(u):(e=n.apply(this,e),r.cache=i.set(u,e)||i,e)}if(typeof n!="function"||null!=t&&typeof t!="function")throw new ti("Expected a function");return r.cache=new(cu.Cache||Fn),r}function au(n){if(typeof n!="function")throw new ti("Expected a function");return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function lu(n,t){return n===t||n!==n&&t!==t; +}function su(n){return null!=n&&gu(n.length)&&!_u(n)}function hu(n){return yu(n)&&su(n)}function pu(n){if(!yu(n))return false;var t=Ot(n);return"[object Error]"==t||"[object DOMException]"==t||typeof n.message=="string"&&typeof n.name=="string"&&!xu(n)}function _u(n){return!!du(n)&&(n=Ot(n),"[object Function]"==n||"[object GeneratorFunction]"==n||"[object AsyncFunction]"==n||"[object Proxy]"==n)}function vu(n){return typeof n=="number"&&n==Eu(n)}function gu(n){return typeof n=="number"&&-1=n; +}function du(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function yu(n){return null!=n&&typeof n=="object"}function bu(n){return typeof n=="number"||yu(n)&&"[object Number]"==Ot(n)}function xu(n){return!(!yu(n)||"[object Object]"!=Ot(n))&&(n=di(n),null===n||(n=oi.call(n,"constructor")&&n.constructor,typeof n=="function"&&n instanceof n&&ii.call(n)==li))}function ju(n){return typeof n=="string"||!ff(n)&&yu(n)&&"[object String]"==Ot(n)}function wu(n){return typeof n=="symbol"||yu(n)&&"[object Symbol]"==Ot(n); +}function mu(n){if(!n)return[];if(su(n))return ju(n)?M(n):Ur(n);if(wi&&n[wi]){n=n[wi]();for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}return t=vo(n),("[object Map]"==t?W:"[object Set]"==t?U:Uu)(n)}function Au(n){return n?(n=Su(n),n===$||n===-$?1.7976931348623157e308*(0>n?-1:1):n===n?n:0):0===n?n:0}function Eu(n){n=Au(n);var t=n%1;return n===n?t?n-t:n:0}function ku(n){return n?pt(Eu(n),0,4294967295):0}function Su(n){if(typeof n=="number")return n;if(wu(n))return F;if(du(n)&&(n=typeof n.valueOf=="function"?n.valueOf():n, +n=du(n)?n+"":n),typeof n!="string")return 0===n?n:+n;n=n.replace(un,"");var t=gn.test(n);return t||yn.test(n)?Dn(n.slice(2),t?2:8):vn.test(n)?F:+n}function Ou(n){return Cr(n,Bu(n))}function Iu(n){return null==n?"":yr(n)}function Ru(n,t,r){return n=null==n?T:kt(n,t),n===T?r:n}function zu(n,t){return null!=n&&we(n,t,zt)}function Wu(n){return su(n)?qn(n):Vt(n)}function Bu(n){if(su(n))n=qn(n,true);else if(du(n)){var t,r=ze(n),e=[];for(t in n)("constructor"!=t||!r&&oi.call(n,t))&&e.push(t);n=e}else{if(t=[], +null!=n)for(r in Qu(n))t.push(r);n=t}return n}function Lu(n,t){if(null==n)return{};var r=c(ve(n),function(n){return[n]});return t=ye(t),tr(n,r,function(n,r){return t(n,r[0])})}function Uu(n){return null==n?[]:S(n,Wu(n))}function Cu(n){return $f(Iu(n).toLowerCase())}function Du(n){return(n=Iu(n))&&n.replace(xn,Xn).replace(Sn,"")}function Mu(n,t,r){return n=Iu(n),t=r?T:t,t===T?zn.test(n)?n.match(In)||[]:n.match(sn)||[]:n.match(t)||[]}function Tu(n){return function(){return n}}function $u(n){return n; +}function Fu(n){return qt(typeof n=="function"?n:_t(n,1))}function Nu(n,t,e){var u=Wu(t),i=Et(t,u);null!=e||du(t)&&(i.length||!u.length)||(e=t,t=n,n=this,i=Et(t,Wu(t)));var o=!(du(e)&&"chain"in e&&!e.chain),f=_u(n);return r(i,function(r){var e=t[r];n[r]=e,f&&(n.prototype[r]=function(){var t=this.__chain__;if(o||t){var r=n(this.__wrapped__);return(r.__actions__=Ur(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,a([this.value()],arguments))})}),n}function Pu(){} +function Zu(n){return Ie(n)?b(Me(n)):rr(n)}function qu(){return[]}function Vu(){return false}mn=null==mn?$n:rt.defaults($n.Object(),mn,rt.pick($n,Wn));var Ku=mn.Array,Gu=mn.Date,Hu=mn.Error,Ju=mn.Function,Yu=mn.Math,Qu=mn.Object,Xu=mn.RegExp,ni=mn.String,ti=mn.TypeError,ri=Ku.prototype,ei=Qu.prototype,ui=mn["__core-js_shared__"],ii=Ju.prototype.toString,oi=ei.hasOwnProperty,fi=0,ci=function(){var n=/[^.]+$/.exec(ui&&ui.keys&&ui.keys.IE_PROTO||"");return n?"Symbol(src)_1."+n:""}(),ai=ei.toString,li=ii.call(Qu),si=$n._,hi=Xu("^"+ii.call(oi).replace(rn,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),pi=Pn?mn.Buffer:T,_i=mn.Symbol,vi=mn.Uint8Array,gi=pi?pi.g:T,di=B(Qu.getPrototypeOf,Qu),yi=Qu.create,bi=ei.propertyIsEnumerable,xi=ri.splice,ji=_i?_i.isConcatSpreadable:T,wi=_i?_i.iterator:T,mi=_i?_i.toStringTag:T,Ai=function(){ +try{var n=je(Qu,"defineProperty");return n({},"",{}),n}catch(n){}}(),Ei=mn.clearTimeout!==$n.clearTimeout&&mn.clearTimeout,ki=Gu&&Gu.now!==$n.Date.now&&Gu.now,Si=mn.setTimeout!==$n.setTimeout&&mn.setTimeout,Oi=Yu.ceil,Ii=Yu.floor,Ri=Qu.getOwnPropertySymbols,zi=pi?pi.isBuffer:T,Wi=mn.isFinite,Bi=ri.join,Li=B(Qu.keys,Qu),Ui=Yu.max,Ci=Yu.min,Di=Gu.now,Mi=mn.parseInt,Ti=Yu.random,$i=ri.reverse,Fi=je(mn,"DataView"),Ni=je(mn,"Map"),Pi=je(mn,"Promise"),Zi=je(mn,"Set"),qi=je(mn,"WeakMap"),Vi=je(Qu,"create"),Ki=qi&&new qi,Gi={},Hi=Te(Fi),Ji=Te(Ni),Yi=Te(Pi),Qi=Te(Zi),Xi=Te(qi),no=_i?_i.prototype:T,to=no?no.valueOf:T,ro=no?no.toString:T,eo=function(){ +function n(){}return function(t){return du(t)?yi?yi(t):(n.prototype=t,t=new n,n.prototype=T,t):{}}}();An.templateSettings={escape:J,evaluate:Y,interpolate:Q,variable:"",imports:{_:An}},An.prototype=En.prototype,An.prototype.constructor=An,On.prototype=eo(En.prototype),On.prototype.constructor=On,Un.prototype=eo(En.prototype),Un.prototype.constructor=Un,Mn.prototype.clear=function(){this.__data__=Vi?Vi(null):{},this.size=0},Mn.prototype.delete=function(n){return n=this.has(n)&&delete this.__data__[n], +this.size-=n?1:0,n},Mn.prototype.get=function(n){var t=this.__data__;return Vi?(n=t[n],"__lodash_hash_undefined__"===n?T:n):oi.call(t,n)?t[n]:T},Mn.prototype.has=function(n){var t=this.__data__;return Vi?t[n]!==T:oi.call(t,n)},Mn.prototype.set=function(n,t){var r=this.__data__;return this.size+=this.has(n)?0:1,r[n]=Vi&&t===T?"__lodash_hash_undefined__":t,this},Tn.prototype.clear=function(){this.__data__=[],this.size=0},Tn.prototype.delete=function(n){var t=this.__data__;return n=ft(t,n),!(0>n)&&(n==t.length-1?t.pop():xi.call(t,n,1), +--this.size,true)},Tn.prototype.get=function(n){var t=this.__data__;return n=ft(t,n),0>n?T:t[n][1]},Tn.prototype.has=function(n){return-1e?(++this.size,r.push([n,t])):r[e][1]=t,this},Fn.prototype.clear=function(){this.size=0,this.__data__={hash:new Mn,map:new(Ni||Tn),string:new Mn}},Fn.prototype.delete=function(n){return n=be(this,n).delete(n),this.size-=n?1:0,n},Fn.prototype.get=function(n){return be(this,n).get(n); +},Fn.prototype.has=function(n){return be(this,n).has(n)},Fn.prototype.set=function(n,t){var r=be(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},Nn.prototype.add=Nn.prototype.push=function(n){return this.__data__.set(n,"__lodash_hash_undefined__"),this},Nn.prototype.has=function(n){return this.__data__.has(n)},Zn.prototype.clear=function(){this.__data__=new Tn,this.size=0},Zn.prototype.delete=function(n){var t=this.__data__;return n=t.delete(n),this.size=t.size,n},Zn.prototype.get=function(n){ +return this.__data__.get(n)},Zn.prototype.has=function(n){return this.__data__.has(n)},Zn.prototype.set=function(n,t){var r=this.__data__;if(r instanceof Tn){var e=r.__data__;if(!Ni||199>e.length)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new Fn(e)}return r.set(n,t),this.size=r.size,this};var uo=Fr(mt),io=Fr(At,true),oo=Nr(),fo=Nr(true),co=Ki?function(n,t){return Ki.set(n,t),n}:$u,ao=Ai?function(n,t){return Ai(n,"toString",{configurable:true,enumerable:false,value:Tu(t),writable:true})}:$u,lo=Ei||function(n){ +return $n.clearTimeout(n)},so=Zi&&1/U(new Zi([,-0]))[1]==$?function(n){return new Zi(n)}:Pu,ho=Ki?function(n){return Ki.get(n)}:Pu,po=Ri?function(n){return null==n?[]:(n=Qu(n),i(Ri(n),function(t){return bi.call(n,t)}))}:qu,_o=Ri?function(n){for(var t=[];n;)a(t,po(n)),n=di(n);return t}:qu,vo=Ot;(Fi&&"[object DataView]"!=vo(new Fi(new ArrayBuffer(1)))||Ni&&"[object Map]"!=vo(new Ni)||Pi&&"[object Promise]"!=vo(Pi.resolve())||Zi&&"[object Set]"!=vo(new Zi)||qi&&"[object WeakMap]"!=vo(new qi))&&(vo=function(n){ +var t=Ot(n);if(n=(n="[object Object]"==t?n.constructor:T)?Te(n):"")switch(n){case Hi:return"[object DataView]";case Ji:return"[object Map]";case Yi:return"[object Promise]";case Qi:return"[object Set]";case Xi:return"[object WeakMap]"}return t});var go=ui?_u:Vu,yo=Ce(co),bo=Si||function(n,t){return $n.setTimeout(n,t)},xo=Ce(ao),jo=function(n){n=cu(n,function(n){return 500===t.size&&t.clear(),n});var t=n.cache;return n}(function(n){var t=[];return 46===n.charCodeAt(0)&&t.push(""),n.replace(tn,function(n,r,e,u){ +t.push(e?u.replace(hn,"$1"):r||n)}),t}),wo=fr(function(n,t){return hu(n)?yt(n,wt(t,1,hu,true)):[]}),mo=fr(function(n,t){var r=Ve(t);return hu(r)&&(r=T),hu(n)?yt(n,wt(t,1,hu,true),ye(r,2)):[]}),Ao=fr(function(n,t){var r=Ve(t);return hu(r)&&(r=T),hu(n)?yt(n,wt(t,1,hu,true),T,r):[]}),Eo=fr(function(n){var t=c(n,Er);return t.length&&t[0]===n[0]?Wt(t):[]}),ko=fr(function(n){var t=Ve(n),r=c(n,Er);return t===Ve(r)?t=T:r.pop(),r.length&&r[0]===n[0]?Wt(r,ye(t,2)):[]}),So=fr(function(n){var t=Ve(n),r=c(n,Er);return(t=typeof t=="function"?t:T)&&r.pop(), +r.length&&r[0]===n[0]?Wt(r,T,t):[]}),Oo=fr(Ke),Io=pe(function(n,t){var r=null==n?0:n.length,e=ht(n,t);return ur(n,c(t,function(n){return Se(n,r)?+n:n}).sort(Wr)),e}),Ro=fr(function(n){return br(wt(n,1,hu,true))}),zo=fr(function(n){var t=Ve(n);return hu(t)&&(t=T),br(wt(n,1,hu,true),ye(t,2))}),Wo=fr(function(n){var t=Ve(n),t=typeof t=="function"?t:T;return br(wt(n,1,hu,true),T,t)}),Bo=fr(function(n,t){return hu(n)?yt(n,t):[]}),Lo=fr(function(n){return mr(i(n,hu))}),Uo=fr(function(n){var t=Ve(n);return hu(t)&&(t=T), +mr(i(n,hu),ye(t,2))}),Co=fr(function(n){var t=Ve(n),t=typeof t=="function"?t:T;return mr(i(n,hu),T,t)}),Do=fr(He),Mo=fr(function(n){var t=n.length,t=1=t}),of=Ut(function(){return arguments}())?Ut:function(n){return yu(n)&&oi.call(n,"callee")&&!bi.call(n,"callee")},ff=Ku.isArray,cf=Vn?k(Vn):Ct,af=zi||Vu,lf=Kn?k(Kn):Dt,sf=Gn?k(Gn):Tt,hf=Hn?k(Hn):Nt,pf=Jn?k(Jn):Pt,_f=Yn?k(Yn):Zt,vf=ee(Kt),gf=ee(function(n,t){return n<=t}),df=$r(function(n,t){ +if(ze(t)||su(t))Cr(t,Wu(t),n);else for(var r in t)oi.call(t,r)&&ot(n,r,t[r])}),yf=$r(function(n,t){Cr(t,Bu(t),n)}),bf=$r(function(n,t,r,e){Cr(t,Bu(t),n,e)}),xf=$r(function(n,t,r,e){Cr(t,Wu(t),n,e)}),jf=pe(ht),wf=fr(function(n,t){n=Qu(n);var r=-1,e=t.length,u=2--n)return t.apply(this,arguments)}},An.ary=eu,An.assign=df,An.assignIn=yf,An.assignInWith=bf,An.assignWith=xf,An.at=jf,An.before=uu,An.bind=Ho,An.bindAll=Nf,An.bindKey=Jo,An.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return ff(n)?n:[n]},An.chain=Ye,An.chunk=function(n,t,r){if(t=(r?Oe(n,t,r):t===T)?1:Ui(Eu(t),0),r=null==n?0:n.length,!r||1>t)return[];for(var e=0,u=0,i=Ku(Oi(r/t));et?0:t,e)):[]},An.dropRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===T?1:Eu(t),t=e-t,hr(n,0,0>t?0:t)):[]},An.dropRightWhile=function(n,t){return n&&n.length?jr(n,ye(t,3),true,true):[]; +},An.dropWhile=function(n,t){return n&&n.length?jr(n,ye(t,3),true):[]},An.fill=function(n,t,r,e){var u=null==n?0:n.length;if(!u)return[];for(r&&typeof r!="number"&&Oe(n,t,r)&&(r=0,e=u),u=n.length,r=Eu(r),0>r&&(r=-r>u?0:u+r),e=e===T||e>u?u:Eu(e),0>e&&(e+=u),e=r>e?0:ku(e);r>>0,r?(n=Iu(n))&&(typeof t=="string"||null!=t&&!hf(t))&&(t=yr(t),!t&&Rn.test(n))?Or(M(n),0,r):n.split(t,r):[]},An.spread=function(t,r){if(typeof t!="function")throw new ti("Expected a function");return r=null==r?0:Ui(Eu(r),0), +fr(function(e){var u=e[r];return e=Or(e,0,r),u&&a(e,u),n(t,this,e)})},An.tail=function(n){var t=null==n?0:n.length;return t?hr(n,1,t):[]},An.take=function(n,t,r){return n&&n.length?(t=r||t===T?1:Eu(t),hr(n,0,0>t?0:t)):[]},An.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===T?1:Eu(t),t=e-t,hr(n,0>t?0:t,e)):[]},An.takeRightWhile=function(n,t){return n&&n.length?jr(n,ye(t,3),false,true):[]},An.takeWhile=function(n,t){return n&&n.length?jr(n,ye(t,3)):[]},An.tap=function(n,t){return t(n), +n},An.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new ti("Expected a function");return du(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),fu(n,t,{leading:e,maxWait:t,trailing:u})},An.thru=Qe,An.toArray=mu,An.toPairs=zf,An.toPairsIn=Wf,An.toPath=function(n){return ff(n)?c(n,Me):wu(n)?[n]:Ur(jo(Iu(n)))},An.toPlainObject=Ou,An.transform=function(n,t,e){var u=ff(n),i=u||af(n)||_f(n);if(t=ye(t,4),null==e){var o=n&&n.constructor;e=i?u?new o:[]:du(n)&&_u(o)?eo(di(n)):{}; +}return(i?r:mt)(n,function(n,r,u){return t(e,n,r,u)}),e},An.unary=function(n){return eu(n,1)},An.union=Ro,An.unionBy=zo,An.unionWith=Wo,An.uniq=function(n){return n&&n.length?br(n):[]},An.uniqBy=function(n,t){return n&&n.length?br(n,ye(t,2)):[]},An.uniqWith=function(n,t){return t=typeof t=="function"?t:T,n&&n.length?br(n,T,t):[]},An.unset=function(n,t){return null==n||xr(n,t)},An.unzip=He,An.unzipWith=Je,An.update=function(n,t,r){return null==n?n:lr(n,t,kr(r)(kt(n,t)),void 0)},An.updateWith=function(n,t,r,e){ +return e=typeof e=="function"?e:T,null!=n&&(n=lr(n,t,kr(r)(kt(n,t)),e)),n},An.values=Uu,An.valuesIn=function(n){return null==n?[]:S(n,Bu(n))},An.without=Bo,An.words=Mu,An.wrap=function(n,t){return nf(kr(t),n)},An.xor=Lo,An.xorBy=Uo,An.xorWith=Co,An.zip=Do,An.zipObject=function(n,t){return Ar(n||[],t||[],ot)},An.zipObjectDeep=function(n,t){return Ar(n||[],t||[],lr)},An.zipWith=Mo,An.entries=zf,An.entriesIn=Wf,An.extend=yf,An.extendWith=bf,Nu(An,An),An.add=Qf,An.attempt=Ff,An.camelCase=Bf,An.capitalize=Cu, +An.ceil=Xf,An.clamp=function(n,t,r){return r===T&&(r=t,t=T),r!==T&&(r=Su(r),r=r===r?r:0),t!==T&&(t=Su(t),t=t===t?t:0),pt(Su(n),t,r)},An.clone=function(n){return _t(n,4)},An.cloneDeep=function(n){return _t(n,5)},An.cloneDeepWith=function(n,t){return t=typeof t=="function"?t:T,_t(n,5,t)},An.cloneWith=function(n,t){return t=typeof t=="function"?t:T,_t(n,4,t)},An.conformsTo=function(n,t){return null==t||gt(n,t,Wu(t))},An.deburr=Du,An.defaultTo=function(n,t){return null==n||n!==n?t:n},An.divide=nc,An.endsWith=function(n,t,r){ +n=Iu(n),t=yr(t);var e=n.length,e=r=r===T?e:pt(Eu(r),0,e);return r-=t.length,0<=r&&n.slice(r,e)==t},An.eq=lu,An.escape=function(n){return(n=Iu(n))&&H.test(n)?n.replace(K,nt):n},An.escapeRegExp=function(n){return(n=Iu(n))&&en.test(n)?n.replace(rn,"\\$&"):n},An.every=function(n,t,r){var e=ff(n)?u:bt;return r&&Oe(n,t,r)&&(t=T),e(n,ye(t,3))},An.find=Fo,An.findIndex=Ne,An.findKey=function(n,t){return p(n,ye(t,3),mt)},An.findLast=No,An.findLastIndex=Pe,An.findLastKey=function(n,t){return p(n,ye(t,3),At); +},An.floor=tc,An.forEach=nu,An.forEachRight=tu,An.forIn=function(n,t){return null==n?n:oo(n,ye(t,3),Bu)},An.forInRight=function(n,t){return null==n?n:fo(n,ye(t,3),Bu)},An.forOwn=function(n,t){return n&&mt(n,ye(t,3))},An.forOwnRight=function(n,t){return n&&At(n,ye(t,3))},An.get=Ru,An.gt=ef,An.gte=uf,An.has=function(n,t){return null!=n&&we(n,t,Rt)},An.hasIn=zu,An.head=qe,An.identity=$u,An.includes=function(n,t,r,e){return n=su(n)?n:Uu(n),r=r&&!e?Eu(r):0,e=n.length,0>r&&(r=Ui(e+r,0)),ju(n)?r<=e&&-1r&&(r=Ui(e+r,0)),v(n,t,r)):-1},An.inRange=function(n,t,r){return t=Au(t),r===T?(r=t,t=0):r=Au(r),n=Su(n),n>=Ci(t,r)&&n=n},An.isSet=pf,An.isString=ju,An.isSymbol=wu,An.isTypedArray=_f,An.isUndefined=function(n){return n===T},An.isWeakMap=function(n){return yu(n)&&"[object WeakMap]"==vo(n)},An.isWeakSet=function(n){return yu(n)&&"[object WeakSet]"==Ot(n)},An.join=function(n,t){return null==n?"":Bi.call(n,t)},An.kebabCase=Lf,An.last=Ve,An.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e;if(r!==T&&(u=Eu(r),u=0>u?Ui(e+u,0):Ci(u,e-1)), +t===t){for(r=u+1;r--&&n[r]!==t;);n=r}else n=_(n,d,u,true);return n},An.lowerCase=Uf,An.lowerFirst=Cf,An.lt=vf,An.lte=gf,An.max=function(n){return n&&n.length?xt(n,$u,It):T},An.maxBy=function(n,t){return n&&n.length?xt(n,ye(t,2),It):T},An.mean=function(n){return y(n,$u)},An.meanBy=function(n,t){return y(n,ye(t,2))},An.min=function(n){return n&&n.length?xt(n,$u,Kt):T},An.minBy=function(n,t){return n&&n.length?xt(n,ye(t,2),Kt):T},An.stubArray=qu,An.stubFalse=Vu,An.stubObject=function(){return{}},An.stubString=function(){ +return""},An.stubTrue=function(){return true},An.multiply=rc,An.nth=function(n,t){return n&&n.length?Qt(n,Eu(t)):T},An.noConflict=function(){return $n._===this&&($n._=si),this},An.noop=Pu,An.now=Go,An.pad=function(n,t,r){n=Iu(n);var e=(t=Eu(t))?D(n):0;return!t||e>=t?n:(t=(t-e)/2,ne(Ii(t),r)+n+ne(Oi(t),r))},An.padEnd=function(n,t,r){n=Iu(n);var e=(t=Eu(t))?D(n):0;return t&&et){var e=n;n=t,t=e}return r||n%1||t%1?(r=Ti(),Ci(n+r*(t-n+Cn("1e-"+((r+"").length-1))),t)):ir(n,t)},An.reduce=function(n,t,r){var e=ff(n)?l:j,u=3>arguments.length;return e(n,ye(t,4),r,u,uo)},An.reduceRight=function(n,t,r){var e=ff(n)?s:j,u=3>arguments.length; +return e(n,ye(t,4),r,u,io)},An.repeat=function(n,t,r){return t=(r?Oe(n,t,r):t===T)?1:Eu(t),or(Iu(n),t)},An.replace=function(){var n=arguments,t=Iu(n[0]);return 3>n.length?t:t.replace(n[1],n[2])},An.result=function(n,t,r){t=Sr(t,n);var e=-1,u=t.length;for(u||(u=1,n=T);++en||9007199254740991=i)return n;if(i=r-D(e),1>i)return e;if(r=o?Or(o,0,i).join(""):n.slice(0,i),u===T)return r+e;if(o&&(i+=r.length-i),hf(u)){if(n.slice(i).search(u)){ +var f=r;for(u.global||(u=Xu(u.source,Iu(_n.exec(u))+"g")),u.lastIndex=0;o=u.exec(f);)var c=o.index;r=r.slice(0,c===T?i:c)}}else n.indexOf(yr(u),i)!=i&&(u=r.lastIndexOf(u),-1e.__dir__?"Right":"")}),e},Un.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),r(["filter","map","takeWhile"],function(n,t){ +var r=t+1,e=1==r||3==r;Un.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:ye(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),r(["head","last"],function(n,t){var r="take"+(t?"Right":"");Un.prototype[n]=function(){return this[r](1).value()[0]}}),r(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");Un.prototype[n]=function(){return this.__filtered__?new Un(this):this[r](1)}}),Un.prototype.compact=function(){return this.filter($u)},Un.prototype.find=function(n){ +return this.filter(n).head()},Un.prototype.findLast=function(n){return this.reverse().find(n)},Un.prototype.invokeMap=fr(function(n,t){return typeof n=="function"?new Un(this):this.map(function(r){return Lt(r,n,t)})}),Un.prototype.reject=function(n){return this.filter(au(ye(n)))},Un.prototype.slice=function(n,t){n=Eu(n);var r=this;return r.__filtered__&&(0t)?new Un(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==T&&(t=Eu(t),r=0>t?r.dropRight(-t):r.take(t-n)),r)},Un.prototype.takeRightWhile=function(n){ +return this.reverse().takeWhile(n).reverse()},Un.prototype.toArray=function(){return this.take(4294967295)},mt(Un.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),u=An[e?"take"+("last"==t?"Right":""):t],i=e||/^find/.test(t);u&&(An.prototype[t]=function(){function t(n){return n=u.apply(An,a([n],f)),e&&h?n[0]:n}var o=this.__wrapped__,f=e?[1]:arguments,c=o instanceof Un,l=f[0],s=c||ff(o);s&&r&&typeof l=="function"&&1!=l.length&&(c=s=false);var h=this.__chain__,p=!!this.__actions__.length,l=i&&!h,c=c&&!p; +return!i&&s?(o=c?o:new Un(this),o=n.apply(o,f),o.__actions__.push({func:Qe,args:[t],thisArg:T}),new On(o,h)):l&&c?n.apply(this,f):(o=this.thru(t),l?e?o.value()[0]:o.value():o)})}),r("pop push shift sort splice unshift".split(" "),function(n){var t=ri[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);An.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(ff(u)?u:[],n)}return this[r](function(r){return t.apply(ff(r)?r:[],n)}); +}}),mt(Un.prototype,function(n,t){var r=An[t];if(r){var e=r.name+"";oi.call(Gi,e)||(Gi[e]=[]),Gi[e].push({name:t,func:r})}}),Gi[Jr(T,2).name]=[{name:"wrapper",func:T}],Un.prototype.clone=function(){var n=new Un(this.__wrapped__);return n.__actions__=Ur(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Ur(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Ur(this.__views__),n},Un.prototype.reverse=function(){if(this.__filtered__){var n=new Un(this); +n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},Un.prototype.value=function(){var n,t=this.__wrapped__.value(),r=this.__dir__,e=ff(t),u=0>r,i=e?t.length:0;n=i;for(var o=this.__views__,f=0,c=-1,a=o.length;++c=this.__values__.length;return{done:n,value:n?T:this.__values__[this.__index__++]}},An.prototype.plant=function(n){ +for(var t,r=this;r instanceof En;){var e=Fe(r);e.__index__=0,e.__values__=T,t?u.__wrapped__=e:t=e;var u=e,r=r.__wrapped__}return u.__wrapped__=n,t},An.prototype.reverse=function(){var n=this.__wrapped__;return n instanceof Un?(this.__actions__.length&&(n=new Un(this)),n=n.reverse(),n.__actions__.push({func:Qe,args:[Ge],thisArg:T}),new On(n,this.__chain__)):this.thru(Ge)},An.prototype.toJSON=An.prototype.valueOf=An.prototype.value=function(){return wr(this.__wrapped__,this.__actions__)},An.prototype.first=An.prototype.head, +wi&&(An.prototype[wi]=Xe),An}();typeof define=="function"&&typeof define.amd=="object"&&define.amd?($n._=rt, define(function(){return rt})):Nn?((Nn.exports=rt)._=rt,Fn._=rt):$n._=rt}).call(this); \ No newline at end of file diff --git a/static/js/playgroundTest.js b/static/js/playgroundTest.js new file mode 100644 index 0000000..e825643 --- /dev/null +++ b/static/js/playgroundTest.js @@ -0,0 +1,19 @@ +const playgroundForm = document.getElementById("playground"); +const playgroundSubmit = document.getElementById("playgroundSubmit"); +const playgroundOutput = document.getElementById("playgroundOutput"); + +// console.log(playgroundForm.elements); + +playgroundSubmit.addEventListener("click", (e) => { + // sorry for this + let query = ""; + Object.keys(playgroundForm.dataset).forEach((input) => { + query += `${input}=${playgroundForm.elements[input].value}&`; + }); + let endpoint = `${playgroundForm.action}?${query}`; + fetch(endpoint) + .then(response => response.text()) + .then((data) => { + playgroundOutput.innerHTML = data + }); +}); diff --git a/static/js/spawnSticker.js b/static/js/spawnSticker.js new file mode 100644 index 0000000..e3b2c08 --- /dev/null +++ b/static/js/spawnSticker.js @@ -0,0 +1,52 @@ +// +// +// Container is positioned absolute and the stickers scroll +const stickerSpawners = document.querySelectorAll("[data-sticker]"); +const container = document.getElementById("sticker-container"); +var throttleSpawn = _.throttle(spawnSticker, 400); + +Array.from(stickerSpawners).forEach((spawner) => { + spawner.addEventListener("mousemove", (e) => throttleSpawn(e)); +}); + +function spawnSticker(e) { + let position = { x: e.pageX, y: e.pageY }; + let content = e.target.dataset.sticker; + container.appendChild(createSticker(content, position)); +} + +// +// Container is positioned fixed and the stickers remain in overlay +// (useful for the fixed header) +const fixedStickerSpawners = document.querySelectorAll("[data-sticker-fix]"); +const fixedContainer = document.getElementById("sticker-fix-container"); +var throttleFixedSpawn = _.throttle(spawnFixedSticker, 400); + +Array.from(fixedStickerSpawners).forEach((spawner) => { + spawner.addEventListener("mousemove", (e) => throttleFixedSpawn(e)); +}); + +function spawnFixedSticker(e) { + let position = { x: e.clientX, y: e.clientY }; + let content = e.target.dataset.stickerFix; + fixedContainer.appendChild(createSticker(content, position)); +} + +// +// +// the sticker element is the same for both function + +function createSticker(content, position) { + sticker = document.createElement("div"); + sticker.classList.add("sticker"); + sticker.innerHTML = content; + sticker.style.left = position.x + "px"; + sticker.style.top = position.y + "px"; + + sticker.style.transform = ` + translate(-50%, -50%) + rotate(${Math.random() * 40 - 20}deg) + `; + + return sticker; +} diff --git a/static/uploads/annotation-compass/1200px-Karl_Marx_001.jpg b/static/uploads/annotation-compass/1200px-Karl_Marx_001.jpg new file mode 100644 index 0000000..bdcf8cd Binary files /dev/null and b/static/uploads/annotation-compass/1200px-Karl_Marx_001.jpg differ diff --git a/static/uploads/annotation-compass/1200px-Karl_Marx_001_thumb.jpg b/static/uploads/annotation-compass/1200px-Karl_Marx_001_thumb.jpg new file mode 100644 index 0000000..a59adaa Binary files /dev/null and b/static/uploads/annotation-compass/1200px-Karl_Marx_001_thumb.jpg differ diff --git a/static/uploads/annotation-compass/185.png b/static/uploads/annotation-compass/185.png new file mode 100644 index 0000000..7806c14 Binary files /dev/null and b/static/uploads/annotation-compass/185.png differ diff --git a/static/uploads/annotation-compass/185_thumb.png b/static/uploads/annotation-compass/185_thumb.png new file mode 100644 index 0000000..25b8fb5 Binary files /dev/null and b/static/uploads/annotation-compass/185_thumb.png differ diff --git a/static/uploads/annotation-compass/47b_IMG_0411WEB.jpg.png b/static/uploads/annotation-compass/47b_IMG_0411WEB.jpg.png new file mode 100644 index 0000000..64cae0c Binary files /dev/null and b/static/uploads/annotation-compass/47b_IMG_0411WEB.jpg.png differ diff --git a/static/uploads/annotation-compass/47b_IMG_0411WEB.jpg_thumb.png b/static/uploads/annotation-compass/47b_IMG_0411WEB.jpg_thumb.png new file mode 100644 index 0000000..d4a495b Binary files /dev/null and b/static/uploads/annotation-compass/47b_IMG_0411WEB.jpg_thumb.png differ diff --git a/static/uploads/annotation-compass/Conformal_grid_before_Mobius_transformation.svg.png b/static/uploads/annotation-compass/Conformal_grid_before_Mobius_transformation.svg.png new file mode 100644 index 0000000..ccb262c Binary files /dev/null and b/static/uploads/annotation-compass/Conformal_grid_before_Mobius_transformation.svg.png differ diff --git a/static/uploads/annotation-compass/Conformal_grid_before_Mobius_transformation.svg_thumb.png b/static/uploads/annotation-compass/Conformal_grid_before_Mobius_transformation.svg_thumb.png new file mode 100644 index 0000000..7cbeb39 Binary files /dev/null and b/static/uploads/annotation-compass/Conformal_grid_before_Mobius_transformation.svg_thumb.png differ diff --git a/static/uploads/annotation-compass/Naamloos 1.png b/static/uploads/annotation-compass/Naamloos 1.png new file mode 100644 index 0000000..5558a6b Binary files /dev/null and b/static/uploads/annotation-compass/Naamloos 1.png differ diff --git a/static/uploads/annotation-compass/Naamloos 1_thumb.png b/static/uploads/annotation-compass/Naamloos 1_thumb.png new file mode 100644 index 0000000..aa9b566 Binary files /dev/null and b/static/uploads/annotation-compass/Naamloos 1_thumb.png differ diff --git a/static/uploads/annotation-compass/Screen_Shot_2021-10-15_at_12.31.53.png b/static/uploads/annotation-compass/Screen_Shot_2021-10-15_at_12.31.53.png new file mode 100644 index 0000000..1ad7ffa Binary files /dev/null and b/static/uploads/annotation-compass/Screen_Shot_2021-10-15_at_12.31.53.png differ diff --git a/static/uploads/annotation-compass/Screen_Shot_2021-10-15_at_12.31.53_thumb.png b/static/uploads/annotation-compass/Screen_Shot_2021-10-15_at_12.31.53_thumb.png new file mode 100644 index 0000000..02c50f2 Binary files /dev/null and b/static/uploads/annotation-compass/Screen_Shot_2021-10-15_at_12.31.53_thumb.png differ diff --git a/static/uploads/annotation-compass/Screen_Shot_2021-11-24_at_5.59.25_PM.png b/static/uploads/annotation-compass/Screen_Shot_2021-11-24_at_5.59.25_PM.png new file mode 100644 index 0000000..588ea67 Binary files /dev/null and b/static/uploads/annotation-compass/Screen_Shot_2021-11-24_at_5.59.25_PM.png differ diff --git a/static/uploads/annotation-compass/Screen_Shot_2021-11-24_at_5.59.25_PM_thumb.png b/static/uploads/annotation-compass/Screen_Shot_2021-11-24_at_5.59.25_PM_thumb.png new file mode 100644 index 0000000..73b5bec Binary files /dev/null and b/static/uploads/annotation-compass/Screen_Shot_2021-11-24_at_5.59.25_PM_thumb.png differ diff --git a/static/uploads/annotation-compass/Screen_Shot_2021-11-25_at_17.07.27.png b/static/uploads/annotation-compass/Screen_Shot_2021-11-25_at_17.07.27.png new file mode 100644 index 0000000..a3fa58b Binary files /dev/null and b/static/uploads/annotation-compass/Screen_Shot_2021-11-25_at_17.07.27.png differ diff --git a/static/uploads/annotation-compass/Screen_Shot_2021-11-25_at_17.07.27_thumb.png b/static/uploads/annotation-compass/Screen_Shot_2021-11-25_at_17.07.27_thumb.png new file mode 100644 index 0000000..7eb22f6 Binary files /dev/null and b/static/uploads/annotation-compass/Screen_Shot_2021-11-25_at_17.07.27_thumb.png differ diff --git a/static/uploads/annotation-compass/bulgarian.jpg b/static/uploads/annotation-compass/bulgarian.jpg new file mode 100644 index 0000000..f6c5d8f Binary files /dev/null and b/static/uploads/annotation-compass/bulgarian.jpg differ diff --git a/static/uploads/annotation-compass/bulgarian_thumb.jpg b/static/uploads/annotation-compass/bulgarian_thumb.jpg new file mode 100644 index 0000000..1a246cf Binary files /dev/null and b/static/uploads/annotation-compass/bulgarian_thumb.jpg differ diff --git a/static/uploads/annotation-compass/capi_peli.jpg b/static/uploads/annotation-compass/capi_peli.jpg new file mode 100644 index 0000000..df67ee2 Binary files /dev/null and b/static/uploads/annotation-compass/capi_peli.jpg differ diff --git a/static/uploads/annotation-compass/capi_peli_thumb.jpg b/static/uploads/annotation-compass/capi_peli_thumb.jpg new file mode 100644 index 0000000..1069282 Binary files /dev/null and b/static/uploads/annotation-compass/capi_peli_thumb.jpg differ diff --git a/static/uploads/annotation-compass/cloverleaf.jpeg b/static/uploads/annotation-compass/cloverleaf.jpeg new file mode 100644 index 0000000..6711b4c Binary files /dev/null and b/static/uploads/annotation-compass/cloverleaf.jpeg differ diff --git a/static/uploads/annotation-compass/cloverleaf_thumb.jpeg b/static/uploads/annotation-compass/cloverleaf_thumb.jpeg new file mode 100644 index 0000000..ca03af6 Binary files /dev/null and b/static/uploads/annotation-compass/cloverleaf_thumb.jpeg differ diff --git a/static/uploads/annotation-compass/download.png b/static/uploads/annotation-compass/download.png new file mode 100644 index 0000000..374fabf Binary files /dev/null and b/static/uploads/annotation-compass/download.png differ diff --git a/static/uploads/annotation-compass/download_thumb.png b/static/uploads/annotation-compass/download_thumb.png new file mode 100644 index 0000000..13598c0 Binary files /dev/null and b/static/uploads/annotation-compass/download_thumb.png differ diff --git a/static/uploads/annotation-compass/dutch.jpg b/static/uploads/annotation-compass/dutch.jpg new file mode 100644 index 0000000..4c00268 Binary files /dev/null and b/static/uploads/annotation-compass/dutch.jpg differ diff --git a/static/uploads/annotation-compass/dutch_thumb.jpg b/static/uploads/annotation-compass/dutch_thumb.jpg new file mode 100644 index 0000000..ca3f243 Binary files /dev/null and b/static/uploads/annotation-compass/dutch_thumb.jpg differ diff --git a/static/uploads/annotation-compass/etre.png b/static/uploads/annotation-compass/etre.png new file mode 100644 index 0000000..df90920 Binary files /dev/null and b/static/uploads/annotation-compass/etre.png differ diff --git a/static/uploads/annotation-compass/etre_thumb.png b/static/uploads/annotation-compass/etre_thumb.png new file mode 100644 index 0000000..e3cfe20 Binary files /dev/null and b/static/uploads/annotation-compass/etre_thumb.png differ diff --git a/static/uploads/annotation-compass/free_fun_translation.jpg b/static/uploads/annotation-compass/free_fun_translation.jpg new file mode 100644 index 0000000..dff7b23 Binary files /dev/null and b/static/uploads/annotation-compass/free_fun_translation.jpg differ diff --git a/static/uploads/annotation-compass/free_fun_translation_thumb.jpg b/static/uploads/annotation-compass/free_fun_translation_thumb.jpg new file mode 100644 index 0000000..7afc4c9 Binary files /dev/null and b/static/uploads/annotation-compass/free_fun_translation_thumb.jpg differ diff --git a/static/uploads/annotation-compass/french.jpg b/static/uploads/annotation-compass/french.jpg new file mode 100644 index 0000000..68840e9 Binary files /dev/null and b/static/uploads/annotation-compass/french.jpg differ diff --git a/static/uploads/annotation-compass/french_thumb.jpg b/static/uploads/annotation-compass/french_thumb.jpg new file mode 100644 index 0000000..20f6d29 Binary files /dev/null and b/static/uploads/annotation-compass/french_thumb.jpg differ diff --git a/static/uploads/annotation-compass/german.jpg b/static/uploads/annotation-compass/german.jpg new file mode 100644 index 0000000..5a80214 Binary files /dev/null and b/static/uploads/annotation-compass/german.jpg differ diff --git a/static/uploads/annotation-compass/german_thumb.jpg b/static/uploads/annotation-compass/german_thumb.jpg new file mode 100644 index 0000000..a092ffa Binary files /dev/null and b/static/uploads/annotation-compass/german_thumb.jpg differ diff --git a/static/uploads/annotation-compass/greek.jpg b/static/uploads/annotation-compass/greek.jpg new file mode 100644 index 0000000..8f27d36 Binary files /dev/null and b/static/uploads/annotation-compass/greek.jpg differ diff --git a/static/uploads/annotation-compass/greek_thumb.jpg b/static/uploads/annotation-compass/greek_thumb.jpg new file mode 100644 index 0000000..c85e503 Binary files /dev/null and b/static/uploads/annotation-compass/greek_thumb.jpg differ diff --git a/static/uploads/annotation-compass/img.png b/static/uploads/annotation-compass/img.png new file mode 100644 index 0000000..57fc97b Binary files /dev/null and b/static/uploads/annotation-compass/img.png differ diff --git a/static/uploads/annotation-compass/img_thumb.png b/static/uploads/annotation-compass/img_thumb.png new file mode 100644 index 0000000..b7879cc Binary files /dev/null and b/static/uploads/annotation-compass/img_thumb.png differ diff --git a/static/uploads/annotation-compass/italian.jpg b/static/uploads/annotation-compass/italian.jpg new file mode 100644 index 0000000..0bace15 Binary files /dev/null and b/static/uploads/annotation-compass/italian.jpg differ diff --git a/static/uploads/annotation-compass/italian_thumb.jpg b/static/uploads/annotation-compass/italian_thumb.jpg new file mode 100644 index 0000000..fb6fbc9 Binary files /dev/null and b/static/uploads/annotation-compass/italian_thumb.jpg differ diff --git a/static/uploads/annotation-compass/korean.jpg b/static/uploads/annotation-compass/korean.jpg new file mode 100644 index 0000000..36ced61 Binary files /dev/null and b/static/uploads/annotation-compass/korean.jpg differ diff --git a/static/uploads/annotation-compass/korean_thumb.jpg b/static/uploads/annotation-compass/korean_thumb.jpg new file mode 100644 index 0000000..cdc20f0 Binary files /dev/null and b/static/uploads/annotation-compass/korean_thumb.jpg differ diff --git a/static/uploads/annotation-compass/lions-mane.jpeg b/static/uploads/annotation-compass/lions-mane.jpeg new file mode 100644 index 0000000..bb1a736 Binary files /dev/null and b/static/uploads/annotation-compass/lions-mane.jpeg differ diff --git a/static/uploads/annotation-compass/lions-mane_thumb.jpeg b/static/uploads/annotation-compass/lions-mane_thumb.jpeg new file mode 100644 index 0000000..704592e Binary files /dev/null and b/static/uploads/annotation-compass/lions-mane_thumb.jpeg differ diff --git a/static/uploads/annotation-compass/map_description_H.jpg b/static/uploads/annotation-compass/map_description_H.jpg new file mode 100644 index 0000000..25a0328 Binary files /dev/null and b/static/uploads/annotation-compass/map_description_H.jpg differ diff --git a/static/uploads/annotation-compass/map_description_H_thumb.jpg b/static/uploads/annotation-compass/map_description_H_thumb.jpg new file mode 100644 index 0000000..d685e54 Binary files /dev/null and b/static/uploads/annotation-compass/map_description_H_thumb.jpg differ diff --git a/static/uploads/annotation-compass/mic mic.jpg b/static/uploads/annotation-compass/mic mic.jpg new file mode 100644 index 0000000..0ebf81b Binary files /dev/null and b/static/uploads/annotation-compass/mic mic.jpg differ diff --git a/static/uploads/annotation-compass/mic mic_thumb.jpg b/static/uploads/annotation-compass/mic mic_thumb.jpg new file mode 100644 index 0000000..7b322ae Binary files /dev/null and b/static/uploads/annotation-compass/mic mic_thumb.jpg differ diff --git a/static/uploads/annotation-compass/one_to_one_translation.jpg b/static/uploads/annotation-compass/one_to_one_translation.jpg new file mode 100644 index 0000000..64740e0 Binary files /dev/null and b/static/uploads/annotation-compass/one_to_one_translation.jpg differ diff --git a/static/uploads/annotation-compass/one_to_one_translation_thumb.jpg b/static/uploads/annotation-compass/one_to_one_translation_thumb.jpg new file mode 100644 index 0000000..ab39613 Binary files /dev/null and b/static/uploads/annotation-compass/one_to_one_translation_thumb.jpg differ diff --git a/static/uploads/annotation-compass/pp.png b/static/uploads/annotation-compass/pp.png new file mode 100644 index 0000000..3757ae8 Binary files /dev/null and b/static/uploads/annotation-compass/pp.png differ diff --git a/static/uploads/annotation-compass/pp_thumb.png b/static/uploads/annotation-compass/pp_thumb.png new file mode 100644 index 0000000..883d38b Binary files /dev/null and b/static/uploads/annotation-compass/pp_thumb.png differ diff --git a/static/uploads/annotation-compass/rejection_map.jpg b/static/uploads/annotation-compass/rejection_map.jpg new file mode 100644 index 0000000..ac5a8fa Binary files /dev/null and b/static/uploads/annotation-compass/rejection_map.jpg differ diff --git a/static/uploads/annotation-compass/rejection_map_thumb.jpg b/static/uploads/annotation-compass/rejection_map_thumb.jpg new file mode 100644 index 0000000..876d399 Binary files /dev/null and b/static/uploads/annotation-compass/rejection_map_thumb.jpg differ diff --git a/static/uploads/annotation-compass/roseatespoonbillyoungmaybLisaBarnesSC1.jpg b/static/uploads/annotation-compass/roseatespoonbillyoungmaybLisaBarnesSC1.jpg new file mode 100644 index 0000000..1ea157b Binary files /dev/null and b/static/uploads/annotation-compass/roseatespoonbillyoungmaybLisaBarnesSC1.jpg differ diff --git a/static/uploads/annotation-compass/roseatespoonbillyoungmaybLisaBarnesSC1_thumb.jpg b/static/uploads/annotation-compass/roseatespoonbillyoungmaybLisaBarnesSC1_thumb.jpg new file mode 100644 index 0000000..1f93edb Binary files /dev/null and b/static/uploads/annotation-compass/roseatespoonbillyoungmaybLisaBarnesSC1_thumb.jpg differ diff --git a/static/uploads/annotation-compass/rotterdam_map_1400px.jpg b/static/uploads/annotation-compass/rotterdam_map_1400px.jpg new file mode 100644 index 0000000..811710b Binary files /dev/null and b/static/uploads/annotation-compass/rotterdam_map_1400px.jpg differ diff --git a/static/uploads/annotation-compass/rotterdam_map_1400px_thumb.jpg b/static/uploads/annotation-compass/rotterdam_map_1400px_thumb.jpg new file mode 100644 index 0000000..b38171c Binary files /dev/null and b/static/uploads/annotation-compass/rotterdam_map_1400px_thumb.jpg differ diff --git a/static/uploads/annotation-compass/slices-compress.jpg b/static/uploads/annotation-compass/slices-compress.jpg new file mode 100644 index 0000000..1100abb Binary files /dev/null and b/static/uploads/annotation-compass/slices-compress.jpg differ diff --git a/static/uploads/annotation-compass/slices-compress_thumb.jpg b/static/uploads/annotation-compass/slices-compress_thumb.jpg new file mode 100644 index 0000000..9ce391a Binary files /dev/null and b/static/uploads/annotation-compass/slices-compress_thumb.jpg differ diff --git a/static/uploads/annotation-compass/space.png b/static/uploads/annotation-compass/space.png new file mode 100644 index 0000000..5284125 Binary files /dev/null and b/static/uploads/annotation-compass/space.png differ diff --git a/static/uploads/annotation-compass/space_thumb.png b/static/uploads/annotation-compass/space_thumb.png new file mode 100644 index 0000000..7abecf5 Binary files /dev/null and b/static/uploads/annotation-compass/space_thumb.png differ diff --git a/static/uploads/annotation-compass/spanish.jpg b/static/uploads/annotation-compass/spanish.jpg new file mode 100644 index 0000000..10e38c3 Binary files /dev/null and b/static/uploads/annotation-compass/spanish.jpg differ diff --git a/static/uploads/annotation-compass/spanish_thumb.jpg b/static/uploads/annotation-compass/spanish_thumb.jpg new file mode 100644 index 0000000..a2b8fe6 Binary files /dev/null and b/static/uploads/annotation-compass/spanish_thumb.jpg differ diff --git a/static/uploads/annotation-compass/thai.jpg b/static/uploads/annotation-compass/thai.jpg new file mode 100644 index 0000000..d976052 Binary files /dev/null and b/static/uploads/annotation-compass/thai.jpg differ diff --git a/static/uploads/annotation-compass/thai_thumb.jpg b/static/uploads/annotation-compass/thai_thumb.jpg new file mode 100644 index 0000000..3a44777 Binary files /dev/null and b/static/uploads/annotation-compass/thai_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify.jpg b/static/uploads/annotation-compass/think-classify.jpg new file mode 100644 index 0000000..d802b7e Binary files /dev/null and b/static/uploads/annotation-compass/think-classify.jpg differ diff --git a/static/uploads/annotation-compass/think-classify10.jpg b/static/uploads/annotation-compass/think-classify10.jpg new file mode 100644 index 0000000..953a4e5 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify10.jpg differ diff --git a/static/uploads/annotation-compass/think-classify10_thumb.jpg b/static/uploads/annotation-compass/think-classify10_thumb.jpg new file mode 100644 index 0000000..42eed88 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify10_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify11.jpg b/static/uploads/annotation-compass/think-classify11.jpg new file mode 100644 index 0000000..b3b58e5 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify11.jpg differ diff --git a/static/uploads/annotation-compass/think-classify11_thumb.jpg b/static/uploads/annotation-compass/think-classify11_thumb.jpg new file mode 100644 index 0000000..8b5f781 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify11_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify12.jpg b/static/uploads/annotation-compass/think-classify12.jpg new file mode 100644 index 0000000..f25c1fc Binary files /dev/null and b/static/uploads/annotation-compass/think-classify12.jpg differ diff --git a/static/uploads/annotation-compass/think-classify12_thumb.jpg b/static/uploads/annotation-compass/think-classify12_thumb.jpg new file mode 100644 index 0000000..c06b829 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify12_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify13.jpg b/static/uploads/annotation-compass/think-classify13.jpg new file mode 100644 index 0000000..85f6e95 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify13.jpg differ diff --git a/static/uploads/annotation-compass/think-classify13_thumb.jpg b/static/uploads/annotation-compass/think-classify13_thumb.jpg new file mode 100644 index 0000000..36f40ec Binary files /dev/null and b/static/uploads/annotation-compass/think-classify13_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify14.jpg b/static/uploads/annotation-compass/think-classify14.jpg new file mode 100644 index 0000000..a924088 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify14.jpg differ diff --git a/static/uploads/annotation-compass/think-classify14_thumb.jpg b/static/uploads/annotation-compass/think-classify14_thumb.jpg new file mode 100644 index 0000000..e8bad0f Binary files /dev/null and b/static/uploads/annotation-compass/think-classify14_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify2.jpg b/static/uploads/annotation-compass/think-classify2.jpg new file mode 100644 index 0000000..b2054cf Binary files /dev/null and b/static/uploads/annotation-compass/think-classify2.jpg differ diff --git a/static/uploads/annotation-compass/think-classify2_thumb.jpg b/static/uploads/annotation-compass/think-classify2_thumb.jpg new file mode 100644 index 0000000..7b6cf7b Binary files /dev/null and b/static/uploads/annotation-compass/think-classify2_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify3.jpg b/static/uploads/annotation-compass/think-classify3.jpg new file mode 100644 index 0000000..8d4c166 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify3.jpg differ diff --git a/static/uploads/annotation-compass/think-classify3_thumb.jpg b/static/uploads/annotation-compass/think-classify3_thumb.jpg new file mode 100644 index 0000000..df5e5c6 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify3_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify4.jpg b/static/uploads/annotation-compass/think-classify4.jpg new file mode 100644 index 0000000..f1cf368 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify4.jpg differ diff --git a/static/uploads/annotation-compass/think-classify4_thumb.jpg b/static/uploads/annotation-compass/think-classify4_thumb.jpg new file mode 100644 index 0000000..3fa6541 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify4_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify5.jpg b/static/uploads/annotation-compass/think-classify5.jpg new file mode 100644 index 0000000..0c12cda Binary files /dev/null and b/static/uploads/annotation-compass/think-classify5.jpg differ diff --git a/static/uploads/annotation-compass/think-classify5_thumb.jpg b/static/uploads/annotation-compass/think-classify5_thumb.jpg new file mode 100644 index 0000000..dbfa6eb Binary files /dev/null and b/static/uploads/annotation-compass/think-classify5_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify6.jpg b/static/uploads/annotation-compass/think-classify6.jpg new file mode 100644 index 0000000..df146b4 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify6.jpg differ diff --git a/static/uploads/annotation-compass/think-classify6_thumb.jpg b/static/uploads/annotation-compass/think-classify6_thumb.jpg new file mode 100644 index 0000000..2156bda Binary files /dev/null and b/static/uploads/annotation-compass/think-classify6_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify7.jpg b/static/uploads/annotation-compass/think-classify7.jpg new file mode 100644 index 0000000..0b5afa8 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify7.jpg differ diff --git a/static/uploads/annotation-compass/think-classify7_thumb.jpg b/static/uploads/annotation-compass/think-classify7_thumb.jpg new file mode 100644 index 0000000..c1b4742 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify7_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify8.jpg b/static/uploads/annotation-compass/think-classify8.jpg new file mode 100644 index 0000000..2554669 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify8.jpg differ diff --git a/static/uploads/annotation-compass/think-classify8_thumb.jpg b/static/uploads/annotation-compass/think-classify8_thumb.jpg new file mode 100644 index 0000000..5682eb1 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify8_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify9.jpg b/static/uploads/annotation-compass/think-classify9.jpg new file mode 100644 index 0000000..376b7b0 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify9.jpg differ diff --git a/static/uploads/annotation-compass/think-classify9_thumb.jpg b/static/uploads/annotation-compass/think-classify9_thumb.jpg new file mode 100644 index 0000000..2272e74 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify9_thumb.jpg differ diff --git a/static/uploads/annotation-compass/think-classify_thumb.jpg b/static/uploads/annotation-compass/think-classify_thumb.jpg new file mode 100644 index 0000000..0ee7fb5 Binary files /dev/null and b/static/uploads/annotation-compass/think-classify_thumb.jpg differ diff --git a/static/uploads/annotation-compass/varia_map_15_12_21.jpg b/static/uploads/annotation-compass/varia_map_15_12_21.jpg new file mode 100644 index 0000000..d027aad Binary files /dev/null and b/static/uploads/annotation-compass/varia_map_15_12_21.jpg differ diff --git a/static/uploads/annotation-compass/varia_map_15_12_21_thumb.jpg b/static/uploads/annotation-compass/varia_map_15_12_21_thumb.jpg new file mode 100644 index 0000000..6bfe619 Binary files /dev/null and b/static/uploads/annotation-compass/varia_map_15_12_21_thumb.jpg differ diff --git a/static/uploads/annotation-compass/varia_map_for_proposal_.jpg b/static/uploads/annotation-compass/varia_map_for_proposal_.jpg new file mode 100644 index 0000000..7e5a21f Binary files /dev/null and b/static/uploads/annotation-compass/varia_map_for_proposal_.jpg differ diff --git a/static/uploads/annotation-compass/varia_map_for_proposal__thumb.jpg b/static/uploads/annotation-compass/varia_map_for_proposal__thumb.jpg new file mode 100644 index 0000000..2dc8c41 Binary files /dev/null and b/static/uploads/annotation-compass/varia_map_for_proposal__thumb.jpg differ diff --git a/static/uploads/annotation-compass/vernacular_maps_tryout.jpg b/static/uploads/annotation-compass/vernacular_maps_tryout.jpg new file mode 100644 index 0000000..dff7b23 Binary files /dev/null and b/static/uploads/annotation-compass/vernacular_maps_tryout.jpg differ diff --git a/static/uploads/annotation-compass/vernacular_maps_tryout_thumb.jpg b/static/uploads/annotation-compass/vernacular_maps_tryout_thumb.jpg new file mode 100644 index 0000000..7afc4c9 Binary files /dev/null and b/static/uploads/annotation-compass/vernacular_maps_tryout_thumb.jpg differ diff --git a/static/uploads/annotation-compass/vlcsnap-2021-10-25-10h54m02s729.png b/static/uploads/annotation-compass/vlcsnap-2021-10-25-10h54m02s729.png new file mode 100644 index 0000000..9d763f5 Binary files /dev/null and b/static/uploads/annotation-compass/vlcsnap-2021-10-25-10h54m02s729.png differ diff --git a/static/uploads/annotation-compass/vlcsnap-2021-10-25-10h54m02s729_thumb.png b/static/uploads/annotation-compass/vlcsnap-2021-10-25-10h54m02s729_thumb.png new file mode 100644 index 0000000..d31821c Binary files /dev/null and b/static/uploads/annotation-compass/vlcsnap-2021-10-25-10h54m02s729_thumb.png differ diff --git a/static/uploads/annotation-compass/west_wind.jpg b/static/uploads/annotation-compass/west_wind.jpg new file mode 100644 index 0000000..dffa009 Binary files /dev/null and b/static/uploads/annotation-compass/west_wind.jpg differ diff --git a/static/uploads/annotation-compass/west_wind_thumb.jpg b/static/uploads/annotation-compass/west_wind_thumb.jpg new file mode 100644 index 0000000..3a94ded Binary files /dev/null and b/static/uploads/annotation-compass/west_wind_thumb.jpg differ diff --git a/static/uploads/annotation-compass/xpub1_rotterdam_map_1400px.jpg b/static/uploads/annotation-compass/xpub1_rotterdam_map_1400px.jpg new file mode 100644 index 0000000..ab66ffe Binary files /dev/null and b/static/uploads/annotation-compass/xpub1_rotterdam_map_1400px.jpg differ diff --git a/static/uploads/annotation-compass/xpub1_rotterdam_map_1400px_thumb.jpg b/static/uploads/annotation-compass/xpub1_rotterdam_map_1400px_thumb.jpg new file mode 100644 index 0000000..e4c6a8b Binary files /dev/null and b/static/uploads/annotation-compass/xpub1_rotterdam_map_1400px_thumb.jpg differ diff --git a/templates/.ipynb_checkpoints/400-checkpoint.html b/templates/.ipynb_checkpoints/400-checkpoint.html new file mode 100644 index 0000000..294c0c1 --- /dev/null +++ b/templates/.ipynb_checkpoints/400-checkpoint.html @@ -0,0 +1,25 @@ + + + + + + + SP16 - 400 + + + + + + +

Learning how to walk while cat-walking

+

400: bad request / invalid URL

+
+
+
    +
  • Did you put the slash at the end of the url?
  • +
  • Did you check any misspelling?
  • +
  • ...
  • +
+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/.ipynb_checkpoints/403-checkpoint.html b/templates/.ipynb_checkpoints/403-checkpoint.html new file mode 100644 index 0000000..3e6b7cd --- /dev/null +++ b/templates/.ipynb_checkpoints/403-checkpoint.html @@ -0,0 +1,22 @@ + + + + + + + SP16 - 403 + + + + + + +

Learning how to walk while cat-walking

+

403: Forbidden! wait wait, where are you going??

+

sorry, this page is not available right now, please wait for the 17th of the next month

+ + + Return to the homepage
+ + + diff --git a/templates/.ipynb_checkpoints/404-checkpoint.html b/templates/.ipynb_checkpoints/404-checkpoint.html new file mode 100644 index 0000000..8eb4bbc --- /dev/null +++ b/templates/.ipynb_checkpoints/404-checkpoint.html @@ -0,0 +1,18 @@ + + + + + + + SP16 - 404 + + + + + + +

Learning how to walk while cat-walking

+

404: Resource not found

+ Return to the homepage
+ + diff --git a/templates/.ipynb_checkpoints/500-checkpoint.html b/templates/.ipynb_checkpoints/500-checkpoint.html new file mode 100644 index 0000000..bd3f54b --- /dev/null +++ b/templates/.ipynb_checkpoints/500-checkpoint.html @@ -0,0 +1,20 @@ + + + + + + + SP16 - 500 + + + + + + +

Learning how to walk while catwalking

+

500: Blibli tried to jump from the kitchen's window to the terrace and he fell from the 3rd floor. +
Next week he was catwalking again. +

+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/.ipynb_checkpoints/502-checkpoint.html b/templates/.ipynb_checkpoints/502-checkpoint.html new file mode 100644 index 0000000..a4a6acb --- /dev/null +++ b/templates/.ipynb_checkpoints/502-checkpoint.html @@ -0,0 +1,20 @@ + + + + + + + SP16 - 502 + + + + + + +

Learning how to walk while catwalking

+

502: I wasn't ready for this connection. +
I am a bit moody right now and I am concentrating on finding my center. +

+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/.ipynb_checkpoints/503-checkpoint.html b/templates/.ipynb_checkpoints/503-checkpoint.html new file mode 100644 index 0000000..5f444ca --- /dev/null +++ b/templates/.ipynb_checkpoints/503-checkpoint.html @@ -0,0 +1,21 @@ + + + + + + + SP16 - 503 + + + + + + +

Learning how to walk while catwalking

+

503: Upss I am having a break right now , cuddling my cat. +
You could check these if you need a break too +

+ Here come's a thought..
+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/.ipynb_checkpoints/504-checkpoint.html b/templates/.ipynb_checkpoints/504-checkpoint.html new file mode 100644 index 0000000..d5a0175 --- /dev/null +++ b/templates/.ipynb_checkpoints/504-checkpoint.html @@ -0,0 +1,19 @@ + + + + + + + SP16 - 454 + + + + + + +

Learning how to walk while catwalking

+

504: gateaway timeout: can we put a waiting musichetta? +

+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/.ipynb_checkpoints/about-checkpoint.html b/templates/.ipynb_checkpoints/about-checkpoint.html new file mode 100644 index 0000000..6b833b9 --- /dev/null +++ b/templates/.ipynb_checkpoints/about-checkpoint.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + + +{% block title %} + {{title}} +{% endblock %} + + +{% block content%} + {{ content | markdown}} +{% endblock %} diff --git a/templates/.ipynb_checkpoints/annotate_image-checkpoint.html b/templates/.ipynb_checkpoints/annotate_image-checkpoint.html new file mode 100644 index 0000000..904396b --- /dev/null +++ b/templates/.ipynb_checkpoints/annotate_image-checkpoint.html @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + Collecting Labels + + + +
+
+ +
+
+
+
+ + + + + diff --git a/templates/.ipynb_checkpoints/annotation-compass-checkpoint.html b/templates/.ipynb_checkpoints/annotation-compass-checkpoint.html new file mode 100644 index 0000000..6ee39e8 --- /dev/null +++ b/templates/.ipynb_checkpoints/annotation-compass-checkpoint.html @@ -0,0 +1,30 @@ +{% extends "base.html" %} + + +{% block head %} + + +{% endblock %} + +{% block content %} + +
+{% for image, thumb in images %} +
+ + {{image}} +
+{% endfor %} +
+ +

Upload new File

+
+ + + +
+ +{% endblock %} \ No newline at end of file diff --git a/templates/.ipynb_checkpoints/base-checkpoint.html b/templates/.ipynb_checkpoints/base-checkpoint.html new file mode 100644 index 0000000..58258a0 --- /dev/null +++ b/templates/.ipynb_checkpoints/base-checkpoint.html @@ -0,0 +1,61 @@ + + + + + + + SI16 - {% block title %} {{ title }} {% endblock %} + + + + + + + + + + + + + + + + + + + {% block head %}{% endblock %} + + +
+
+
+ + + +
{%block content%} {% endblock %}
+ + + + diff --git a/templates/.ipynb_checkpoints/function-checkpoint.html b/templates/.ipynb_checkpoints/function-checkpoint.html new file mode 100644 index 0000000..aea2600 --- /dev/null +++ b/templates/.ipynb_checkpoints/function-checkpoint.html @@ -0,0 +1,113 @@ +{% extends "base.html" %} + + +{% block head %} + + + + + + +{% endblock %} + + +{% block title %} + {{title}} +{% endblock %} + + + +{% block nav %} + +{% endblock %} + + + +{% block content%} +

{{description}}

+ + +
+
+

Input

+
    + {% for (param, tp) in parameters %} +
  • {{param}} [{{tp}}]
  • + {% endfor %} +
+
+
+
+

Output

+
    +
  • {{title}} [{{output}}]
  • +
+
+
+
+

Enpoint

+ + https://hub.xpub.nl/soupboat/{{base_url}}/api/{{title}}/ + {% for (param, tp) in parameters %} + {{ "?" if loop.first else "" }} + {{param}}=<{{param}}> + {{ "&" if not loop.last else "" }} + {% endfor %} + + + + +
+
+
+
+

Try it

+ + {% for (param, tp) in parameters %} + + + {% endfor %} + + +
+
+
+
+
+
+
+ {{documentation| markdown}} +
+ +{% endblock %} + + diff --git a/templates/.ipynb_checkpoints/functions-checkpoint.html b/templates/.ipynb_checkpoints/functions-checkpoint.html new file mode 100644 index 0000000..c8680f5 --- /dev/null +++ b/templates/.ipynb_checkpoints/functions-checkpoint.html @@ -0,0 +1,31 @@ +{% extends "base.html" %} + + +{% block head %} + +{% endblock %} + + +{% block title %} + {{title}} +{% endblock %} + + + +{% block content%} +

{{description}}

+ + {% for function in functions %} + + + + + + {% endfor %} +
{{function.title}}{{function.description}}
+{% endblock %} + + diff --git a/templates/.ipynb_checkpoints/home-checkpoint.html b/templates/.ipynb_checkpoints/home-checkpoint.html new file mode 100644 index 0000000..affa65e --- /dev/null +++ b/templates/.ipynb_checkpoints/home-checkpoint.html @@ -0,0 +1,88 @@ + + + + + + + SI16 - {{ title }} + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

{{title}}

+

Experimental Publishing

+

Special Issue 16

+
+ +
+

Info

+ About + Intro + Terms of Service +
+ +
+

Projects

+ {% for project in projects %} + {{ project.title }} + {% endfor %} +
+ +
+

Functions

+ {% for function in functions %} + {{ function }} + {% endfor %} +
+ + + + +
+ + diff --git a/templates/.ipynb_checkpoints/page-checkpoint.html b/templates/.ipynb_checkpoints/page-checkpoint.html new file mode 100644 index 0000000..357de25 --- /dev/null +++ b/templates/.ipynb_checkpoints/page-checkpoint.html @@ -0,0 +1,35 @@ +{% extends "base.html" %} + + +{% block head %} + + + {% if css %} + + {% endif %} + + {% if script %} + \ No newline at end of file diff --git a/templates/.ipynb_checkpoints/tos-checkpoint.html b/templates/.ipynb_checkpoints/tos-checkpoint.html new file mode 100644 index 0000000..dd5e5e3 --- /dev/null +++ b/templates/.ipynb_checkpoints/tos-checkpoint.html @@ -0,0 +1,18 @@ + + + + + + + {{title}} + + + + + + +

{{title}}

+
{{ description }}
+
{{contents|markdown}}
+ + diff --git a/templates/400.html b/templates/400.html new file mode 100644 index 0000000..294c0c1 --- /dev/null +++ b/templates/400.html @@ -0,0 +1,25 @@ + + + + + + + SP16 - 400 + + + + + + +

Learning how to walk while cat-walking

+

400: bad request / invalid URL

+
+
+
    +
  • Did you put the slash at the end of the url?
  • +
  • Did you check any misspelling?
  • +
  • ...
  • +
+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/403.html b/templates/403.html new file mode 100644 index 0000000..3e6b7cd --- /dev/null +++ b/templates/403.html @@ -0,0 +1,22 @@ + + + + + + + SP16 - 403 + + + + + + +

Learning how to walk while cat-walking

+

403: Forbidden! wait wait, where are you going??

+

sorry, this page is not available right now, please wait for the 17th of the next month

+ + + Return to the homepage
+ + + diff --git a/templates/404.html b/templates/404.html new file mode 100644 index 0000000..8eb4bbc --- /dev/null +++ b/templates/404.html @@ -0,0 +1,18 @@ + + + + + + + SP16 - 404 + + + + + + +

Learning how to walk while cat-walking

+

404: Resource not found

+ Return to the homepage
+ + diff --git a/templates/500.html b/templates/500.html new file mode 100644 index 0000000..bd3f54b --- /dev/null +++ b/templates/500.html @@ -0,0 +1,20 @@ + + + + + + + SP16 - 500 + + + + + + +

Learning how to walk while catwalking

+

500: Blibli tried to jump from the kitchen's window to the terrace and he fell from the 3rd floor. +
Next week he was catwalking again. +

+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/502.html b/templates/502.html new file mode 100644 index 0000000..a4a6acb --- /dev/null +++ b/templates/502.html @@ -0,0 +1,20 @@ + + + + + + + SP16 - 502 + + + + + + +

Learning how to walk while catwalking

+

502: I wasn't ready for this connection. +
I am a bit moody right now and I am concentrating on finding my center. +

+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/503.html b/templates/503.html new file mode 100644 index 0000000..5f444ca --- /dev/null +++ b/templates/503.html @@ -0,0 +1,21 @@ + + + + + + + SP16 - 503 + + + + + + +

Learning how to walk while catwalking

+

503: Upss I am having a break right now , cuddling my cat. +
You could check these if you need a break too +

+ Here come's a thought..
+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/504.html b/templates/504.html new file mode 100644 index 0000000..d5a0175 --- /dev/null +++ b/templates/504.html @@ -0,0 +1,19 @@ + + + + + + + SP16 - 454 + + + + + + +

Learning how to walk while catwalking

+

504: gateaway timeout: can we put a waiting musichetta? +

+ Return to the homepage
+ + \ No newline at end of file diff --git a/templates/about.html b/templates/about.html new file mode 100644 index 0000000..6b833b9 --- /dev/null +++ b/templates/about.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + + +{% block title %} + {{title}} +{% endblock %} + + +{% block content%} + {{ content | markdown}} +{% endblock %} diff --git a/templates/annotate_image.html b/templates/annotate_image.html new file mode 100644 index 0000000..904396b --- /dev/null +++ b/templates/annotate_image.html @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + Collecting Labels + + + +
+
+ +
+
+
+
+ + + + + diff --git a/templates/annotation-compass.html b/templates/annotation-compass.html new file mode 100644 index 0000000..6ee39e8 --- /dev/null +++ b/templates/annotation-compass.html @@ -0,0 +1,30 @@ +{% extends "base.html" %} + + +{% block head %} + + +{% endblock %} + +{% block content %} + +
+{% for image, thumb in images %} +
+ + {{image}} +
+{% endfor %} +
+ +

Upload new File

+
+ + + +
+ +{% endblock %} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..58258a0 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,61 @@ + + + + + + + SI16 - {% block title %} {{ title }} {% endblock %} + + + + + + + + + + + + + + + + + + + {% block head %}{% endblock %} + + +
+
+
+ + + +
{%block content%} {% endblock %}
+ + + + diff --git a/templates/function.html b/templates/function.html new file mode 100644 index 0000000..aea2600 --- /dev/null +++ b/templates/function.html @@ -0,0 +1,113 @@ +{% extends "base.html" %} + + +{% block head %} + + + + + + +{% endblock %} + + +{% block title %} + {{title}} +{% endblock %} + + + +{% block nav %} + +{% endblock %} + + + +{% block content%} +

{{description}}

+ + +
+
+

Input

+
    + {% for (param, tp) in parameters %} +
  • {{param}} [{{tp}}]
  • + {% endfor %} +
+
+
+
+

Output

+
    +
  • {{title}} [{{output}}]
  • +
+
+
+
+

Enpoint

+ + https://hub.xpub.nl/soupboat/{{base_url}}/api/{{title}}/ + {% for (param, tp) in parameters %} + {{ "?" if loop.first else "" }} + {{param}}=<{{param}}> + {{ "&" if not loop.last else "" }} + {% endfor %} + + + + +
+
+
+
+

Try it

+ + {% for (param, tp) in parameters %} + + + {% endfor %} + + +
+
+
+
+
+
+
+ {{documentation| markdown}} +
+ +{% endblock %} + + diff --git a/templates/functions.html b/templates/functions.html new file mode 100644 index 0000000..c8680f5 --- /dev/null +++ b/templates/functions.html @@ -0,0 +1,31 @@ +{% extends "base.html" %} + + +{% block head %} + +{% endblock %} + + +{% block title %} + {{title}} +{% endblock %} + + + +{% block content%} +

{{description}}

+ + {% for function in functions %} + + + + + + {% endfor %} +
{{function.title}}{{function.description}}
+{% endblock %} + + diff --git a/templates/home.html b/templates/home.html new file mode 100644 index 0000000..affa65e --- /dev/null +++ b/templates/home.html @@ -0,0 +1,88 @@ + + + + + + + SI16 - {{ title }} + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

{{title}}

+

Experimental Publishing

+

Special Issue 16

+
+ +
+

Info

+ About + Intro + Terms of Service +
+ +
+

Projects

+ {% for project in projects %} + {{ project.title }} + {% endfor %} +
+ +
+

Functions

+ {% for function in functions %} + {{ function }} + {% endfor %} +
+ + + + +
+ + diff --git a/templates/page.html b/templates/page.html new file mode 100644 index 0000000..357de25 --- /dev/null +++ b/templates/page.html @@ -0,0 +1,35 @@ +{% extends "base.html" %} + + +{% block head %} + + + {% if css %} + + {% endif %} + + {% if script %} + \ No newline at end of file diff --git a/templates/tos.html b/templates/tos.html new file mode 100644 index 0000000..dd5e5e3 --- /dev/null +++ b/templates/tos.html @@ -0,0 +1,18 @@ + + + + + + + {{title}} + + + + + + +

{{title}}

+
{{ description }}
+
{{contents|markdown}}
+ +