kaka.farm

Unnamed repository; edit this file 'description' to name the repository.
git clone https://kaka.farm/~git/kaka.farm
Log | Files | Refs | README

commit 75f83aaa80c9baf67f15478938e4b544473b9e14
parent dfb792fdd21ea53d4c7cafae74dba075d19d0212
Author: Yuval Langer <yuval.langer@gmail.com>
Date:   Fri, 19 Jan 2024 15:25:23 +0200

Merge kaka.farm repository with the dabbling repository.

Diffstat:
Adabbling/.gitignore | 4++++
Adabbling/.gitlab-ci.yml | 11+++++++++++
Adabbling/README.rst | 0
Adabbling/html/annoying-sawtooth-alarm.html | 48++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/index.html | 45+++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/kakalog.js | 33+++++++++++++++++++++++++++++++++
Adabbling/html/quadratic-bezier-curves/index.html | 11+++++++++++
Adabbling/html/quadratic-bezier-curves/main.js | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/quadratic-bezier-curves/style.css | 11+++++++++++
Adabbling/html/shades-of-grey/index.html | 11+++++++++++
Adabbling/html/shades-of-grey/main.js | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/shades-of-grey/style.css | 11+++++++++++
Adabbling/html/sokoban/kakalog-state.js | 4++++
Adabbling/html/sokoban/sokoban-web.js | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/sokoban/sokoban.css | 4++++
Adabbling/html/sokoban/sokoban.html | 26++++++++++++++++++++++++++
Adabbling/html/sokoban/sokoban.js | 279+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/sokoban/sokoban_tests.js | 34++++++++++++++++++++++++++++++++++
Adabbling/html/spinning-shapes/index.html | 11+++++++++++
Adabbling/html/spinning-shapes/main.js | 305++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/spinning-shapes/style.css | 11+++++++++++
Adabbling/html/tau-mandala/index.css | 11+++++++++++
Adabbling/html/tau-mandala/index.html | 19+++++++++++++++++++
Adabbling/html/tau-mandala/tau-mandala.svg | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/tau/2020-darts.html | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/tau/2020.html | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/the-dancing-polygon-screensaver/index.html | 11+++++++++++
Adabbling/html/the-dancing-polygon-screensaver/main.js | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/html/the-dancing-polygon-screensaver/style.css | 11+++++++++++
Adabbling/html/wtc_plaza_2001-09-11/freesound.org/data/previews/239/239900_4079949-lq.mp3 | 0
Adabbling/html/wtc_plaza_2001-09-11/freesound.org/data/previews/344/344150_6179115-lq.mp3 | 0
Adabbling/html/wtc_plaza_2001-09-11/index.html | 23+++++++++++++++++++++++
Adabbling/html/wtc_plaza_2001-09-11/wtc_plaza_2001-09-11.js | 290+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/poetry.lock | 1561+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/pyproject.toml | 32++++++++++++++++++++++++++++++++
Adabbling/src/dabbling/WTC_plaza_2001-09-11.py | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/src/dabbling/__init__.py | 1+
Adabbling/src/dabbling/console.py | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/src/dabbling/dragon_curve.py | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/src/dabbling/hilbert_curve/hilbert_curve.py | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adabbling/tests/__init__.py | 0
Adabbling/tests/test_dabbling.py | 5+++++
42 files changed, 4087 insertions(+), 0 deletions(-)

diff --git a/dabbling/.gitignore b/dabbling/.gitignore @@ -0,0 +1,4 @@ +dabbling.egg-info +dabbling/__pycache__ +*.png +*.svg diff --git a/dabbling/.gitlab-ci.yml b/dabbling/.gitlab-ci.yml @@ -0,0 +1,11 @@ +image: alpine:latest + +pages: + stage: deploy + script: + - mv html public + artifacts: + paths: + - public + only: + - master diff --git a/dabbling/README.rst b/dabbling/README.rst diff --git a/dabbling/html/annoying-sawtooth-alarm.html b/dabbling/html/annoying-sawtooth-alarm.html @@ -0,0 +1,48 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <script type="text/javascript"> +'use strict'; + + +(function() { + function main() { + let f = 440; + let v = 1; + let audio = new window.AudioContext; + + let oscillator = audio.createOscillator(); + + oscillator.type = 'sine'; + oscillator.frequency.setValueAtTime(f, audio.currentTime); + oscillator.connect(audio.destination); + oscillator.start(); + + function changeFrequency() { + //alert(f); + if ((f > 880) || (f < 440)) { + f = Math.min(Math.max(f, 440), 880); + v *= -1; + }; + + f += 10 * v; + + oscillator.type = 'sawtooth'; + oscillator.frequency.setValueAtTime(f, audio.currentTime); + oscillator.connect(audio.destination); + //oscillator.start(); + + window.setTimeout(changeFrequency, 10); + }; + + window.setTimeout(changeFrequency, 10); + }; + + window.addEventListener('load', main); +})(); + </script> + </head> + <body> + </body> +</html> diff --git a/dabbling/html/index.html b/dabbling/html/index.html @@ -0,0 +1,45 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Dabbling in the hidden arts of programming. A useless crap repository.</title> + </head> + <body> + <h1>Dabbling</h1> + <h2>"projects":</h2> + <ul> + <li> + <a href="tau/2020-darts.html">τ Day 2020 darts</a> + </li> + <li> + <a href="sokoban/sokoban.html">Sokoban</a> + </li> + <li> + <a href="tau-mandala/">τ mandala</a> + </li> + <li> + <a href="wtc_plaza_2001-09-11/">WTC plaza circa 2001-09-11</a> + </li> + <li> + <a href="the-dancing-polygon-screensaver/">The Dancing Polygon Screensaver</a> + </li> + <li> + <a href="quadratic-bezier-curves/">Quadratic Bezier Curves</a> + </li> + <li> + <a href="shades-of-grey/">Shades of Grey</a> + </li> + <li> + <a href="spinning-shapes/">Spinning Shapes</a> + </li> + </ul> + <h2>Dabbling code repositories:</h2> + <h3>Main repository:</h3> + <a href="https://codeberg.org/yuvallangerontheroad/dabbling">codeberg.org</a> + <h3>Mirror repositories:</h3> + <ul> + <li><a href="https://gitlab.com/yuvallangerontheroad/dabbling">gitlab.com</a></li> + <li><a href="https://framagit.org/yuvallangerontheroad/dabbling/-/import">Framagit</a></li> + </ul> + </body> +</html> diff --git a/dabbling/html/kakalog.js b/dabbling/html/kakalog.js @@ -0,0 +1,33 @@ +'use strict'; + + +console.log('kakalog.js start.'); + + +(function() { + function change_console() { + if (window.kakalog_activated) { + [ + 'debug', + 'error', + 'info', + 'log', + 'trace', + ].forEach(function_name=>{ + let old_function = console[function_name]; + let new_function = function(...stuff) { + old_function(...stuff); + let log_element = document.getElementById('log'); + let log_text = `${function_name}: ${stuff}`; + log_element.innerText = `${log_element.innerText}\n${log_text}`; + }; + console[function_name] = new_function; + }); + }; + }; + + window.addEventListener('load', change_console); +})(); + + +console.log('kakalog.js end.'); diff --git a/dabbling/html/quadratic-bezier-curves/index.html b/dabbling/html/quadratic-bezier-curves/index.html @@ -0,0 +1,11 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8" /> + <script src="main.js" type="text/javascript"></script> + <link rel="stylesheet" href="style.css"></link> + </head> + <body> + <canvas id="canvas" width="800" height="600"></canvas> + </body> +</html> diff --git a/dabbling/html/quadratic-bezier-curves/main.js b/dabbling/html/quadratic-bezier-curves/main.js @@ -0,0 +1,153 @@ +'use strict;' + +Math.TAU = 2 * Math.PI; + +(function() { + let line_a = [ + [Math.random(), Math.random()], + [Math.random(), Math.random()], + ]; + + let line_b = [ + [Math.random(), Math.random()], + [Math.random(), Math.random()], + ]; + + const HSV_VALUE_VALUE = 0.7; + const HSV_SATURATION_VALUE = 0.7; + const WANTED_NUMBER_OF_LINES = 50; + + function lerp(p, a, b) { + return p * (b - a) + a; + } + + function lerp_2d(p, a, b) { + return [ + lerp(p, a[0], b[0]), + lerp(p, a[1], b[1]), + ]; + } + + function hsv_to_rgb(hue, saturation, value) { + // https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB + // H in [0, 1] (position on the color wheel) + // S in [0, 1] + // V in [0, 1] + + let chroma = value * saturation; + + let hue_tag = hue * 6; + + let x = chroma * (1 - Math.abs((hue_tag % 2) - 1)); + + let red_1, green_1, blue_1; + + if (hue_tag >= 0 && hue_tag < 1) { + [red_1, green_1, blue_1] = [chroma, x, 0]; + } else if (hue_tag >= 1 && hue_tag < 2) { + [red_1, green_1, blue_1] = [x, chroma, 0]; + } else if (hue_tag >= 2 && hue_tag < 3) { + [red_1, green_1, blue_1] = [0, chroma, x]; + } else if (hue_tag >= 3 && hue_tag < 4) { + [red_1, green_1, blue_1] = [0, x, chroma]; + } else if (hue_tag >= 4 && hue_tag < 5) { + [red_1, green_1, blue_1] = [x, 0, chroma]; + } else if (hue_tag >= 5 && hue_tag < 6) { + [red_1, green_1, blue_1] = [chroma, 0, x]; + }; + + let m = value - chroma; + + return [red_1 + m, green_1 + m, blue_1 + m]; + } + + function draw_line(line, rgb) { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + ctx.beginPath(); + + ctx.strokeStyle = `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`; + + ctx.moveTo(canvas.width * line[0][0], canvas.height * line[0][1]); + ctx.lineTo(canvas.width * line[1][0], canvas.height * line[1][1]); + + ctx.stroke(); + } + + function uniform_random_direction() { + let uniform = Math.random(); + let direction_vector = [ + Math.cos(uniform * Math.TAU), + Math.sin(uniform * Math.TAU), + ]; + return direction_vector; + } + + function draw() { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + ctx.clearRect(0, 0, canvas.width, canvas.height); + + //draw_line(line_a, [255, 255, 255]); + //draw_line(line_b, [255, 255, 255]); + + + for (let current_line_number = 0; current_line_number < WANTED_NUMBER_OF_LINES; current_line_number++) { + let bezier_curve_portion = current_line_number / (WANTED_NUMBER_OF_LINES - 1); + let rgb = hsv_to_rgb( + bezier_curve_portion, + HSV_SATURATION_VALUE, + HSV_VALUE_VALUE, + ).map(x => 255 * x); + + let bezier_line = [ + lerp_2d(bezier_curve_portion, line_a[0], line_a[1]), + lerp_2d(bezier_curve_portion, line_b[0], line_b[1]), + ]; + + draw_line(bezier_line, rgb); + } + } + + function resize_window() { + // https://stackoverflow.com/a/32119392 + + let canvas = document.getElementById('canvas'); + + canvas.width = window.innerWidth; + canvas.style.width = window.innerWidth; + canvas.height = window.innerHeight; + canvas.style.height = window.innerHeight; + + draw(); + } + + function make_new_world() { + line_a = [ + [Math.random(), Math.random()], + [Math.random(), Math.random()], + ]; + line_b = [ + [Math.random(), Math.random()], + [Math.random(), Math.random()], + ]; + } + + function main() { + let canvas = document.getElementById('canvas'); + + resize_window(); + make_new_world(); + + canvas.addEventListener('click', function() { + make_new_world(); + draw(); + }); + + window.addEventListener('resize', resize_window) + } + + window.addEventListener('load', main); +})(); diff --git a/dabbling/html/quadratic-bezier-curves/style.css b/dabbling/html/quadratic-bezier-curves/style.css @@ -0,0 +1,11 @@ +/* Stolen from https://developer.mozilla.org/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it */ + +* { + padding: 0; + margin: 0; +} +canvas { + background: #000; + display: block; + margin: 0 auto; +} diff --git a/dabbling/html/shades-of-grey/index.html b/dabbling/html/shades-of-grey/index.html @@ -0,0 +1,11 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8" /> + <script src="main.js" type="text/javascript"></script> + <link rel="stylesheet" href="style.css"></link> + </head> + <body> + <canvas id="canvas" width="800" height="600"></canvas> + </body> +</html> diff --git a/dabbling/html/shades-of-grey/main.js b/dabbling/html/shades-of-grey/main.js @@ -0,0 +1,101 @@ +(function() { + let number_of_rectangles = 2; + let factor = 2; + const INTERVAL = 750; + + function hsv_to_rgb(hue, saturation, value) { + // https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB + // H in [0, 1] (position on the color wheel) + // S in [0, 1] + // V in [0, 1] + + let chroma = value * saturation; + + let hue_tag = hue * 6; + + let x = chroma * (1 - Math.abs((hue_tag % 2) - 1)); + + let [red_1, green_1, blue_1] = ((hue_tag, chroma, x)=>{ + if (hue_tag >= 0 && hue_tag < 1) { return [chroma, x, 0]; + } else if (hue_tag >= 1 && hue_tag < 2) { return [x, chroma, 0]; + } else if (hue_tag >= 2 && hue_tag < 3) { return [0, chroma, x]; + } else if (hue_tag >= 3 && hue_tag < 4) { return [0, x, chroma]; + } else if (hue_tag >= 4 && hue_tag < 5) { return [x, 0, chroma]; + } else if (hue_tag >= 5 && hue_tag < 6) { return [chroma, 0, x]; + } + })(hue_tag, chroma, x); + + let m = value - chroma; + + return [red_1 + m, green_1 + m, blue_1 + m]; + } + + function draw() { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + console.info(canvas.width, number_of_rectangles); + + ctx.clearRect(0, 0, canvas.width, canvas.height); + + let rectangle_width = canvas.width / number_of_rectangles; + + for ( + let rectangle_number = 0; + rectangle_number < number_of_rectangles; + rectangle_number++ + ) { + ctx.beginPath(); + + let rect_hsv_value = (number_of_rectangles - rectangle_number - 1) / (number_of_rectangles - 1); + let rgb = hsv_to_rgb(0, 0, rect_hsv_value).map(x=>255 * x); + ctx.fillStyle = `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`; + + let rectangle_x = rectangle_number * rectangle_width; + + ctx.fillRect(Math.floor(rectangle_x), 0, Math.ceil(rectangle_width), canvas.height); + } + } + + function resize_window() { + // https://stackoverflow.com/a/32119392 + + let canvas = document.getElementById('canvas'); + + canvas.width = window.innerWidth; + canvas.style.width = window.innerWidth; + canvas.height = window.innerHeight; + canvas.style.height = window.innerHeight; + } + + function main() { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + resize_window(); + //reset_world(); + + //canvas.addEventListener('click', reset_world); + + window.addEventListener('resize', ()=>{resize_window(); draw();}) + + draw(); + + setInterval( + ()=>{ + if (number_of_rectangles > canvas.width) { + factor = 0.5; + number_of_rectangles = 2**Math.floor(Math.log2(canvas.width)); + } else if (number_of_rectangles <= 2) { + factor = 2; + number_of_rectangles = 2; + } + number_of_rectangles = factor * number_of_rectangles; + draw(); + }, + INTERVAL, + ); + } + + window.addEventListener('load', main); +})(); diff --git a/dabbling/html/shades-of-grey/style.css b/dabbling/html/shades-of-grey/style.css @@ -0,0 +1,11 @@ +/* Stolen from https://developer.mozilla.org/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it */ + +* { + padding: 0; + margin: 0; +} +canvas { + background: #000; + display: block; + margin: 0 auto; +} diff --git a/dabbling/html/sokoban/kakalog-state.js b/dabbling/html/sokoban/kakalog-state.js @@ -0,0 +1,4 @@ +'use strict'; + + +window.kakalog_activated = false; diff --git a/dabbling/html/sokoban/sokoban-web.js b/dabbling/html/sokoban/sokoban-web.js @@ -0,0 +1,57 @@ +'use strict'; + + +(function() { + function load_game() { + return JSON.parse(window.localStorage.getItem('game')); + }; + + + function save_game(game) { + window.localStorage.setItem('game', JSON.stringify(game)); + }; + + + function main() { + let game = load_game() || sokoban.new_game(); + + let text_element = document.getElementById('text'); + text_element.innerText = sokoban.game_to_text(game); + + [ + ['up', sokoban.action_step_up], + ['down', sokoban.action_step_down], + ['left', sokoban.action_step_left], + ['right', sokoban.action_step_right], + ['next_level', sokoban.action_next_level], + ['restart_level', sokoban.action_restart_level], + ['undo', sokoban.action_undo], + ['save', save_game], + ].forEach(([element_id, action_function])=>{ + let button = document.getElementById(element_id); + console.debug(button) + function click_handler() { + console.debug('click: ' + element_id); + action_function(game); + text_element.innerText = sokoban.game_to_text(game); + }; + button.addEventListener('click', click_handler); + }); + + [ + ['new', sokoban.new_game], + ['load', load_game], + ].forEach(([element_id, action_function])=>{ + let button = document.getElementById(element_id); + console.debug(button) + function click_handler() { + console.debug('click: ' + element_id); + game = action_function(); + text_element.innerText = sokoban.game_to_text(game); + }; + button.addEventListener('click', click_handler); + }); + }; + + window.addEventListener('load', main); +})(); diff --git a/dabbling/html/sokoban/sokoban.css b/dabbling/html/sokoban/sokoban.css @@ -0,0 +1,4 @@ +body { + color: grey; + background: black; +} diff --git a/dabbling/html/sokoban/sokoban.html b/dabbling/html/sokoban/sokoban.html @@ -0,0 +1,26 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Kaka Farm's Sokoban clone: no bells no whistles no glory.</title> + <link href="sokoban.css" rel="stylesheet"></style> + <script type="text/javascript" src="kakalog-state.js"></script> + <script type="text/javascript" src="../kakalog.js"></script> + <script type="text/javascript" src="sokoban.js"></script> + <script type="text/javascript" src="sokoban-web.js"></script> + </head> + <body> + <pre id="text"></pre> + <button id="up" type="button">↑</button> + <button id="down" type="button">↓</button> + <button id="left" type="button">←</button> + <button id="right" type="button">→</button> + <button id="next_level" type="button">continue</button> + <button id="restart_level" type="button">restart</button> + <button id="undo" type="button">undo</button> + <button id="save" type="button">save game</button> + <button id="load" type="button">load game</button> + <button id="new" type="button">new game</button> + <pre id="log"></pre> + </body> +</html> diff --git a/dabbling/html/sokoban/sokoban.js b/dabbling/html/sokoban/sokoban.js @@ -0,0 +1,279 @@ +'use strict'; + + +console.log('sokoban.js start.'); + + +let sokoban = (function() { + let levels = [ + ` +############## +#.@...*....z.# +############## +`, + ` + ##### + #...# + #*..# + ###..*## + #..*.*.# +###.#.##.# ###### +#...#.##.#####..zz# +#.*..*..........zz# +#####.###.#@##..zz# + #.....######### + ####### +`, + ]; + let level_win_test_not_all_endings = ` + ##### + #...# + #...# + ###...## + #......# +###.#.##.# ###### +#...#.##.#####..zz# +#..z.*..........zz# +#####.###.#@##..zz# + #.....######### + ####### +`; + let level_win_test_all_endings = ` + ##### + #...# + #...# + ###...## + #......# +###.#.##.# ###### +#...#.##.#####....# +#..z.*............# +#####.###.#@##....# + #.....######### + ####### +`; + + function read_level_text(s) { + let state = { + rocks: [], + walls: [], + floors: [], + endings: [], + }; + let lines = s.split('\n'); + let max_x = Math.max(...lines.map(line=>line.length)); + for (let y = 0; y < lines.length; y++) { + state.walls[y] = []; + state.rocks[y] = []; + state.floors[y] = []; + state.endings[y] = []; + for (let x = 0; x < lines[y].length; x++) { + if (lines[y][x] == '@') { + state.player_position = [x, y]; + state.floors[y][x] = '.'; + } else if (lines[y][x] == '*') { + state.rocks[y][x] = '*'; + state.floors[y][x] = '.'; + } else if (lines[y][x] == '#') { + state.walls[y][x] = '#'; + } else if (lines[y][x] == 'z') { + state.endings[y][x] = 'z'; + } else if (lines[y][x] == '.') { + state.floors[y][x] = '.'; + }; + }; + }; + + return state; + }; + + function here_player(state, [x, y]) { + return ( + state.player_position[0] == x && + state.player_position[1] == y + ); + } + function here_wall(state, [x, y]) { + return state.walls[y][x] == '#'; + } + function here_rock(state, [x, y]) { + return state.rocks[y][x] == '*'; + } + function here_ending(state, [x, y]) { + return state.endings[y][x] == 'z'; + } + function here_floor(state, [x, y]) { + return state.floors[y][x] == '.'; + } + function move_rock(state, [fx, fy], [tx, ty]) { + delete state.rocks[fy][fx]; + state.rocks[ty][tx] = '*'; + } + + + function is_won(game) { + for (let y = 0; y < game.level_state.rocks.length; y++) { + if (game.level_state.rocks[y] != undefined) { + for (let x = 0; x < game.level_state.rocks[y].length; x++) { + if (here_rock(game.level_state, [x, y]) != here_ending(game.level_state, [x, y])) { + return false; + } + } + } + } + return true; + }; + + + function copy_level_state(game) { + let state_copy = [ + {}, + 'rocks', + 'floors', + 'walls', + 'endings', + ].reduce((acc, entity_name)=>{ + acc[entity_name] = ( + game + .level_state[entity_name] + .map(line=>line.map(c=>c)) + ); + return acc; + }); + state_copy.player_position = game.level_state.player_position.map(p=>p); + return state_copy; + }; + + + function action_step(game, direction) { + if (!is_won(game)) { + let p0 = game.level_state.player_position; + let p1 = [ + p0[0] + direction[0], + p0[1] + direction[1]]; + let p2 = [ + p1[0] + direction[0], + p1[1] + direction[1]]; + + let is_blocked = ( + here_wall(game.level_state, p1) || ( + here_rock(game.level_state, p1) && ( + here_rock(game.level_state, p2) || + here_wall(game.level_state, p2)))); + let is_pushing = ( + here_rock(game.level_state, p1) && + !here_rock(game.level_state, p2)); + + if (!is_blocked) { + game.number_of_steps += 1; + let old_state = copy_level_state(game); + game.undo_stack.push(old_state); + if (is_pushing) { + move_rock(game.level_state, p1, p2); + }; + game.level_state.player_position = p1; + }; + }; + }; + + function action_step_up(game) { action_step(game, [0, -1]); }; + function action_step_down(game) { action_step(game, [0, 1]); }; + function action_step_left(game) { action_step(game, [-1, 0]); }; + function action_step_right(game) { action_step(game, [1, 0]); }; + + + function action_next_level(game) { + if (is_won(game) && game.current_level_number < levels.length) { + game.number_of_steps = 0; + game.undo_stack = []; + game.current_level_number += 1; + game.level_state = read_level_text(levels[game.current_level_number]); + }; + }; + + + function action_restart_level(game) { + game.number_of_steps = 0; + game.undo_stack = []; + game.level_state = read_level_text(levels[game.current_level_number]); + }; + + + function action_undo(game) { + if (game.undo_stack.length > 0) { + game.number_of_steps -= 1; + game.level_state = game.undo_stack.pop(); + } + } + + + function game_to_text(game) { + console.log(game.undo_state); + let s = ''; + + if (is_won(game)) { + s = s.concat('Won! Press c to continue.'); + } + s = s.concat(`Level ${game.current_level_number + 1}. Step ${game.number_of_steps}.`); + + let max_y = Math.max( + game.level_state.rocks.length, + game.level_state.endings.length, + game.level_state.floors.length, + game.level_state.walls.length, + game.level_state.player_position[1], + ); + for (let y = 0; y < max_y; y++) { + let max_x = Math.max( + game.level_state.rocks[y].length, + game.level_state.endings[y].length, + game.level_state.floors[y].length, + game.level_state.walls[y].length, + game.level_state.player_position[0], + ); + for (let x = 0; x < max_x; x++) { + if (here_player(game.level_state, [x, y])) { + s = s.concat('@'); + } else if (here_wall(game.level_state, [x, y])) { + s = s.concat('#'); + } else if (here_rock(game.level_state, [x, y])) { + s = s.concat('*'); + } else if (here_floor(game.level_state, [x, y])) { + s = s.concat('.'); + } else if (here_ending(game.level_state, [x, y])) { + s = s.concat('z'); + } else { + s = s.concat(' '); + } + }; + s = s.concat('\n'); + }; + + return s.trimEnd(); + }; + + + function new_game() { + return { + current_level_number: 0, + level_state: read_level_text(levels[0]), + undo_stack: [], + number_of_steps: 0, + }; + }; + + + return { + action_next_level, + action_restart_level, + action_step_down, + action_step_left, + action_step_right, + action_step_up, + action_undo, + game_to_text, + new_game, + }; +})(); + + +console.log('sokoban.js end.'); diff --git a/dabbling/html/sokoban/sokoban_tests.js b/dabbling/html/sokoban/sokoban_tests.js @@ -0,0 +1,34 @@ +console.log('tests start'); + +console.log(sokoban); + +let game = sokoban.new_game(); +[ + sokoban.action_step_right, + sokoban.action_step_right, + sokoban.action_step_right, + sokoban.action_step_right, + sokoban.action_step_right, + sokoban.action_step_right, + sokoban.action_step_right, + sokoban.action_step_right, + sokoban.action_next_level, +].forEach(action_function=>{ + let s = sokoban.game_to_text(game); + console.log(`before: +${s} +KAKAKAKAKAKAKAKAKAKAKAKAKAKAKAKA` + ); + action_function(game); + s = sokoban.game_to_text(game); + console.log(`after: +${s} +KAKAKAKAKAKAKAKAKAKAKAKAKAKAKAKA` + ); +}) +sokoban.action_next_level(game); +let s = sokoban.game_to_text(game); +console.log(`after: ${s}`) +sokoban.action_next_level(game); +s = sokoban.game_to_text(game); +console.log(`after: ${s}`) diff --git a/dabbling/html/spinning-shapes/index.html b/dabbling/html/spinning-shapes/index.html @@ -0,0 +1,11 @@ +<!doctype html> +<html> + <head> + <script src="main.js" type="text/javascript"></script> + <meta charset="utf-8" /> + <link rel="stylesheet" href="style.css" /> + </head> + <body> + <canvas id="canvas" width=1000 height=500></canvas> + </body> +</html> diff --git a/dabbling/html/spinning-shapes/main.js b/dabbling/html/spinning-shapes/main.js @@ -0,0 +1,305 @@ +Math.TAU = 2 * Math.PI; + +(function() { + let turn = 0; + let last_time = 0; + let math_ts; + let math_yss; + let math_polygon_radiuses; + let canvas_ts; + let canvas_yss; + let canvas_polygon_radiuses; + + const NUMBER_OF_POLYGONS = 7; + const POLYGON_HEIGHT_MARGIN = 0.075; + const TURN_PER_MILLISECOND = 0.0005; + const CYCLE_LENGTH = 20; + const NUMBER_OF_SAMPLES = 500; + const START_T = 0; + const END_T = CYCLE_LENGTH; + const math_graph_y_extents = [ + [-1.2, 1.2], + [-1.2, 1.2], + [-1.2, 1.2], + [-1.2, 1.2], + [-1.2, 1.2], + [-1.2, 1.2], + [-1.2, 1.2], + ]; + + + + const functions = [ + /* + turn => step_on(turn % CYCLE_LENGTH, 1, 1.5) - step_on(turn % CYCLE_LENGTH, 2, 2.5) + + step_on(turn % CYCLE_LENGTH, 3, 3.5) - step_on(turn % CYCLE_LENGTH, 4, 4.5) + + step_on(turn % CYCLE_LENGTH, 5, 5.5) - step_on(turn % CYCLE_LENGTH, 6, 6.5) + + + step_on(turn % CYCLE_LENGTH, 7, 7.5) - step_on(turn % CYCLE_LENGTH, 8.5, 9) + + step_on(turn % CYCLE_LENGTH, 9.5, 10) - step_on(turn % CYCLE_LENGTH, 11, 11.5) + + step_on(turn % CYCLE_LENGTH, 12, 12.5) - step_on(turn % CYCLE_LENGTH, 13.5, 14) + + + step_on(turn % CYCLE_LENGTH, 14.5, 15) - step_on(turn % CYCLE_LENGTH, 15.5, 16) + + step_on(turn % CYCLE_LENGTH, 16.5, 17) - step_on(turn % CYCLE_LENGTH, 17.5, 18) + + step_on(turn % CYCLE_LENGTH, 18.5, 19) - step_on(turn % CYCLE_LENGTH, 19.5, 20), + */ + turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 7), + turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 6), + turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 5), + turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 4), + turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 3), + turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 2), + turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH), + ]; + + function quadratic_stepper(t) { + if (t < 0) { + return 0; + } else if (t < 0.5) { + return 2 * t**2; + } else if (t < 1) { + return (-2*((t-1)**2) + 1); + } else { + return 1; + } + } + + function lerp(t, a, b) { + return (b - a) * t + a; + } + + function superlerp(t, a, b, c, d) { + // [a, b] ; -a + // [0, b-a] ; /(b-a) + // [0, 1] ; *(d-c) + // [0, d-c] ; +c + // [c, d] + return (t - a) / (b - a) * (d - c) + c; + } + + function step_on(t, a, b) { + return quadratic_stepper(superlerp(t, a, b, 0, 1)); + } + + function step_on_step_off(t, a, b, c, d) { + return step_on(t, a, b) - step_on(t, c, d); + } + + function from_math_coordinates_to_canvas_coordinates(x, y, x_extents, y_extents) { + let canvas = document.getElementById('canvas'); + + // a, b / - a + // 0, b-a / * w + // 0, (b-a)w / /(b-a) + // 0, w + + // a, b / *(-1) + // -b, -a / +b + // 0, (b-a) / * h + // 0, (b-a)h / /(b-a) + // 0, h + + return [ + (x - x_extents[0]) * canvas.width / (x_extents[1] - x_extents[0]), + ((-y) + y_extents[1]) * canvas.height / (y_extents[1] - y_extents[0]), + ]; + } + + function make_regular_polygon_path2d(x, y, radius, number_of_sides, turn) { + // `x` and `y` are the center of the triangle. + // `radius` is the distance from the center to a vertex. + // `number_of_sides` of the polygon. + // `turn` is a value [0, 1] where 1 is a full turn. + + let regular_polygon = new Path2D(); + + regular_polygon.moveTo( + x + Math.cos(turn * Math.TAU) * radius, + y + Math.sin(turn * Math.TAU) * radius, + ); + + for (let vertex_i = 1; vertex_i < number_of_sides; vertex_i++) { + regular_polygon.lineTo( + x + Math.cos((vertex_i / number_of_sides + turn) * Math.TAU) * radius, + y + Math.sin((vertex_i / number_of_sides + turn) * Math.TAU) * radius, + ); + } + + regular_polygon.closePath(); + + return regular_polygon; + } + + function linspace(start, stop, number_of_points) { + let l = []; + for (let point_i = 0; point_i < number_of_points; point_i++) { + l.push(superlerp(point_i, 0, number_of_points - 1, start, stop)); + } + return l; + } + + function draw_polygon(number_of_sides, turn, polygon_center_y, polygon_radius_addition) { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + ctx.beginPath() + ctx.fillStyle = '#f0f'; // Fuchia from https://www.w3schools.com/colors/colors_names.asp + ctx.strokeStyle = '#f0f'; + ctx.fill( + make_regular_polygon_path2d( + canvas.width / 2, + polygon_center_y, + 20 * canvas.height / 500 + polygon_radius_addition, + number_of_sides, + turn, + ), + ); + ctx.stroke( + make_regular_polygon_path2d( + canvas.width / 2, + polygon_center_y, + 20 * canvas.height / 500 + polygon_radius_addition, + number_of_sides, + turn, + ), + ); + } + + function draw_graph(polygon_i) { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + ctx.beginPath() + ctx.strokeStyle = 'white'; + ctx.moveTo(canvas_ts[0], canvas_yss[polygon_i][0]); + for (let point_i = 1; point_i < NUMBER_OF_SAMPLES; point_i++) { + ctx.lineTo(canvas_ts[point_i], canvas_yss[polygon_i][point_i]); + } + ctx.stroke(); + } + + function draw_position_circle(x, y) { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + ctx.beginPath(); + ctx.fillStyle = "#00bfff"; // DeepSkyBlue from https://www.w3schools.com/colors/colors_names.asp + ctx.arc(x, y, canvas.height / 80, 0, Math.TAU, false); + ctx.fill(); + } + + function draw() { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + ctx.beginPath(); + ctx.fillStyle='black'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + ctx.beginPath(); + ctx.strokeStyle = 'white'; + + //ctx.moveTo(START_T, functions[polygon_i](-1) * canvas.width); + + ctx.lineWidth = 2; + + // [50, h - 50] + // 0, 1, 2 / /n-1 + // 0, 0.5, 1 / *(h-h0.1) + // 0, 0.5(0.9h), 0.9h / +h0.05 + // 50, 0.5(h-100)+0.05h, 0.9h+0.05h + for (let polygon_i = 0; polygon_i < NUMBER_OF_POLYGONS; polygon_i++) { + // top and bottom of the are dedicated to this graph. + let y_top = polygon_i * canvas.height / NUMBER_OF_POLYGONS; + let y_bottom = (polygon_i + 1) * canvas.height / NUMBER_OF_POLYGONS; + + // the vertical value of the center of the current polygon. + let polygon_y = superlerp( + polygon_i, + 0, + NUMBER_OF_POLYGONS - 1, + POLYGON_HEIGHT_MARGIN * canvas.height, + canvas.height * (1 - POLYGON_HEIGHT_MARGIN), + ); + + // Get all cached values of the mathematical and graphical + let current_sample_i = Math.floor(turn / CYCLE_LENGTH * canvas_ts.length) % canvas_ts.length; + let current_math_t = math_ts[current_sample_i]; //superlerp(current_math_t, START_T, END_T, 0, canvas.width); + let current_canvas_t = canvas_ts[current_sample_i]; + let current_math_y = math_yss[polygon_i][current_sample_i]; + //let current_math_y = functions[1](current_math_t); + let current_canvas_y = canvas_yss[polygon_i][current_sample_i]; // superlerp(current_math_y, -1.2, 1.2, y_bottom, y_top); + + draw_graph(polygon_i); + + draw_polygon(polygon_i + 3, current_math_y, polygon_y, canvas_polygon_radiuses[polygon_i][current_sample_i]); + + draw_position_circle(current_canvas_t, current_canvas_y); + } + } + + function step(time_since_start) { + draw(); + + turn = TURN_PER_MILLISECOND * time_since_start; + + window.requestAnimationFrame(step); + } + + function resize_window() { + // https://stackoverflow.com/a/32119392 + + let canvas = document.getElementById('canvas'); + + canvas.width = window.innerWidth; + canvas.style.width = window.innerWidth; + canvas.height = window.innerHeight; + canvas.style.height = window.innerHeight; + + cache_canvas_data(); + } + + function cache_math_data() { + math_ts = Float32Array.from(linspace(START_T, END_T, NUMBER_OF_SAMPLES)); + math_yss = []; + math_polygon_radiuses = []; + for (let polygon_i = 0; polygon_i < NUMBER_OF_POLYGONS; polygon_i++) { + math_yss.push(Float32Array.from(math_ts)); + for (let t_i = 0; t_i < math_ts.length; t_i++) { + let y = functions[polygon_i](math_ts[t_i]); + math_yss[polygon_i][t_i] = y; + } + math_polygon_radiuses[polygon_i] = math_yss[polygon_i].map(y => (y > 0.7) ? (y - 0.7) : 0); + } + } + + function cache_canvas_data() { + let canvas = document.getElementById('canvas'); + + canvas_yss = []; + canvas_polygon_radiuses = []; + for (let polygon_i = 0; polygon_i < NUMBER_OF_POLYGONS; polygon_i++) { + let y_top = polygon_i * canvas.height / NUMBER_OF_POLYGONS; + let y_bottom = (polygon_i + 1) * canvas.height / NUMBER_OF_POLYGONS; + + canvas_ts = math_ts.map(t => superlerp(t, START_T, END_T, 0, canvas.width)); + canvas_yss[polygon_i] = math_yss[polygon_i].map( + y => superlerp( + y, + math_graph_y_extents[polygon_i][0], + math_graph_y_extents[polygon_i][1], + y_bottom, y_top)); + canvas_polygon_radiuses[polygon_i] = math_polygon_radiuses[polygon_i].map(x => x * (canvas.height / 500) * 100) + } + } + + function main() { + cache_math_data(); + resize_window(); + + window.addEventListener('resize', resize_window) + window.requestAnimationFrame(step); + } + + window.addEventListener('load', main); +})(); diff --git a/dabbling/html/spinning-shapes/style.css b/dabbling/html/spinning-shapes/style.css @@ -0,0 +1,11 @@ +/* Stolen from https://developer.mozilla.org/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it */ + +* { + padding: 0; + margin: 0; +} +canvas { + background: #000; + display: block; + margin: 0 auto; +} diff --git a/dabbling/html/tau-mandala/index.css b/dabbling/html/tau-mandala/index.css @@ -0,0 +1,11 @@ +object { + /* + width: 100vw; + */ + /* + height: 100vh; + */ + width: 100%; + height: 100%; + border: 5px dotted red; +} diff --git a/dabbling/html/tau-mandala/index.html b/dabbling/html/tau-mandala/index.html @@ -0,0 +1,19 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>τ mandala</title> + <link href="index.css" rel="stylesheet"> + </head> + <body> + <object data="tau-mandala.svg" type="image/svg+xml"></object> + + <p> + Tau mandala idea stolen from <a href="https://youtube.com/c/Mathologer">Mathologer</a>'s T-shirt in his <a href="https://youtu.be/O1sPvUr0YC0">doubling cubes and squaring circles</a> video. + </p> + + <p> + Used one of <a href="http://www.petercollingridge.co.uk/">Peter Collingridge</a>'s example SVG files (<a href="https://github.com/petercollingridge/code-for-blog/">up on his github repo</a>) from his <a href="http://www.petercollingridge.co.uk/tutorials/svg/interactive/javascript/">interactive SVG with javascript tutorial</a> as a skeleton for my SVG file. It is not much of code, but credit is due. + </p> + </body> +</html> diff --git a/dabbling/html/tau-mandala/tau-mandala.svg b/dabbling/html/tau-mandala/tau-mandala.svg @@ -0,0 +1,83 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="-10 -10 20 20"> + <script type="text/javascript"><![CDATA[ +'use strict'; + + +Math.TAU = 2 * Math.PI; + +function internal_angle(n) { + return (n - 2) * Math.TAU / (n * 2); +}; + +function set_view_box(svg_element, radius, margin) { + let high_margin = radius * (1 + margin); + let low_margin = -high_margin; + let width = high_margin - low_margin; + svg.setAttributeNS('http://www.w3.org/2000/svg', 'viewBox', `${low_margin} ${low_margin} ${width} ${width}`); +}; + + +function rotate(point, angle) { + let [x, y] = point; + let [c_a, s_a] = [Math.cos(angle), Math.sin(angle)]; + return [ + x * c_a - y * s_a, + x * s_a + y * c_a, + ]; +}; + + +let radiuses = [1.0]; +let polygon_paths = []; +for (let nagon = 3; nagon < 100; nagon++) { + let radius = radiuses[radiuses.length - 1]; + let internal_angle = (nagon - 2) * Math.TAU / (2 * nagon); + radius = radius / Math.sin(internal_angle / 2); + radiuses.push(radius); + let polygon_path = []; + for (let i = 0; i < nagon; i++) { + let angle = Math.TAU * i / nagon; + let point = rotate([0, -radius], angle); + polygon_path.push(point); + }; + polygon_paths.push(polygon_path); +}; + + +let svg = document.getElementsByTagName('svg')[0]; +set_view_box(svg, radiuses[radiuses.length - 1], 0.1); +radiuses.forEach((r, i, radiuses)=>{ + let element = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); + element.setAttributeNS(null, 'cx', 0); + element.setAttributeNS(null, 'cy', 0); + element.setAttributeNS(null, 'r', r); + element.setAttributeNS(null, 'fill', 'none'); + element.setAttributeNS(null, 'stroke', 'black'); + element.setAttributeNS(null, 'stroke-width', 0.1 / (i + 1)); + svg.appendChild(element); +}); + +polygon_paths.forEach((polygon_path, i, polygon_paths)=>{ + let polygon_element = document.createElementNS('http://www.w3.org/2000/svg', 'polygon'); + let points = ( + polygon_path + .map(point=>`${point[0]} ${point[1]}`) + .reduce((acc, x)=>acc.concat(' ').concat(x)) + ); + polygon_element.setAttributeNS(null, 'points', points); + polygon_element.setAttributeNS(null, 'fill', 'none'); + polygon_element.setAttributeNS(null, 'stroke', 'black'); + polygon_element.setAttributeNS(null, 'stroke-width', 0.2 / (i + 1)); + let animate_transform_element = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform'); + animate_transform_element.setAttributeNS(null, 'attributeName', 'transform'); + animate_transform_element.setAttributeNS(null, 'attributeType', 'XML'); + animate_transform_element.setAttributeNS(null, 'type', 'rotate'); + animate_transform_element.setAttributeNS(null, 'from', '0 0 0'); + animate_transform_element.setAttributeNS(null, 'to', '360 0 0'); + animate_transform_element.setAttributeNS(null, 'dur', `${Math.log(i+10, 2)}s`); + animate_transform_element.setAttributeNS(null, 'repeatCount', 'indefinite'); + polygon_element.appendChild(animate_transform_element); + svg.appendChild(polygon_element); +}); +]]></script> +</svg> diff --git a/dabbling/html/tau/2020-darts.html b/dabbling/html/tau/2020-darts.html @@ -0,0 +1,83 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8" /> + <title>Tau Day 2020</title> + <style tyle="text/css"> +canvas { + border: 5px dotted red; +} + </style> + <script type="text/javascript"> +'use strict'; + +( + function() { + // COME ON ECMA! + // It is that easy! + // Get to it! + Math.TAU = 2 * Math.PI; + + let number_of_points = 0; + let number_of_points_inside = 0; + function lerp(from, to, t) { + return to * t + from * (1 - t); + } + function unit_coordinate_to_canvas_coordinate(unit_x, canvas_length, margin) { + return lerp(canvas_length * margin, canvas_length * (1 - margin), (unit_x + 1)/2); + } + function main() { + let canvas = document.querySelector('#canvas'); + let c = canvas.getContext('2d'); + let margin = 0.1; + + c.beginPath(); + c.arc(canvas.width / 2, canvas.height / 2, 0.5 * canvas.width - margin * canvas.width, 0, Math.TAU, false); + c.stroke(); + let unit_x = lerp(-1, 1, Math.random()); + let unit_y = lerp(-1, 1, Math.random()); + let canvas_x = unit_coordinate_to_canvas_coordinate(unit_x, canvas.width, margin); + let canvas_y = unit_coordinate_to_canvas_coordinate(unit_y, canvas.height, margin); + + number_of_points += 1 + + if ((unit_x * unit_x + unit_y * unit_y) < 1) { + c.fillStyle = 'red'; + number_of_points_inside += 1; + } else { + c.fillStyle = 'black'; + }; + c.beginPath(); + c.arc(canvas_x, canvas_y, 1, 0, Math.TAU, false); + c.fill(); + let tau_approximation = 8 * number_of_points_inside / number_of_points; + let tau_error = Math.TAU - tau_approximation; + let tau_text = `τ approximation = += ${Math.floor(tau_approximation * 100) / 100} + ${number_of_points_inside} += 8 * ------ + ${number_of_points} + +error = ${tau_error}`; + let tau_text_element = document.querySelector('#text'); + tau_text_element.innerText = tau_text; + if (Math.abs(tau_error) < 0.001) { + tau_text = `${tau_text} +HAPPY τ DAY!`; + tau_text_element.innerText = tau_text; + return; + } + + window.requestAnimationFrame(main); + }; + + window.addEventListener('load', main); + } +)(); + </script> + </head> + <body> + <pre id="text"></pre> + <canvas id="canvas" width="500" height="500"></canvas> + </body> +</html> diff --git a/dabbling/html/tau/2020.html b/dabbling/html/tau/2020.html @@ -0,0 +1,100 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8" /> + <title>Tau Day 2020</title> + <style tyle="text/css"> +canvas { + border: 5px dotted red; +} + </style> + <script type="text/javascript"> +'use strict'; + +( + function() { + let min_size_factor = 1; + let max_size_factor = 100; + let current_size_factor_phase = 0.0; + let size_factor_phase_increment = 0.01; + function lerp(from, to, t) { + return to * t + from * (1 - t); + } + function saw(phase) { + let new_phase = phase % 1.0; + let signal = 0; + if (new_phase < 0.25) { + signal = lerp(0, 1, new_phase / 0.25); + } else if (new_phase < 0.75) { + signal = lerp(1, -1, (new_phase - 0.25) / 0.5); + } else { + signal = lerp(-1, 0, (new_phase - 0.75) / 0.25); + }; + return signal; + } + function unit_coordinate_to_canvas_coordinate(unit_x, canvas_length, margin) { + return lerp(canvas_length * margin, canvas_length * (1 - margin), (unit_x + 1)/2); + } + function index_to_unit_coordinate(i, points_on_edge, size_factor) { + return (2 * i / (points_on_edge - 1) - 1) * size_factor; + } + function main() { + let canvas = document.querySelector('#canvas'); + let c = canvas.getContext('2d'); + c.fillStyle = 'white'; + c.fillRect(0, 0, canvas.width, canvas.height); + let margin = 0.1; + + let size_factor_signal = saw(current_size_factor_phase); + let current_size_factor = lerp(max_size_factor, min_size_factor, (size_factor_signal + 1) / 2); + + c.beginPath(); + c.arc(canvas.width / 2, canvas.height / 2, 0.5 * canvas.width - margin * canvas.width, 0, 2 * Math.PI, false); + c.stroke(); + + let points_on_edge = 100; + let number_of_points = 0; + let number_of_points_inside = 0; + for (let i = 0; i < points_on_edge; ++i) { + for (let j = 0; j < points_on_edge; ++j) { + let unit_x = index_to_unit_coordinate(i, points_on_edge, current_size_factor); + let unit_y = index_to_unit_coordinate(j, points_on_edge, current_size_factor); + if ((unit_x > 1) || (unit_y > 1) || (unit_x < -1) || (unit_y < -1)) { + continue; + } + + let canvas_x = unit_coordinate_to_canvas_coordinate(unit_x, canvas.width, margin); + let canvas_y = unit_coordinate_to_canvas_coordinate(unit_y, canvas.height, margin); + + number_of_points += 1 + + if ((unit_x * unit_x + unit_y * unit_y) < 1) { + c.fillStyle = 'red'; + number_of_points_inside += 1; + } else { + c.fillStyle = 'black'; + }; + c.beginPath(); + c.arc(canvas_x, canvas_y, 1, 0, 2 * Math.PI, false); + c.fill(); + } + }; + + current_size_factor_phase = (current_size_factor_phase + size_factor_phase_increment) % 1.0; + + c.fillStyle = 'blue'; + c.font = '10px helvetica'; + c.fillText(`τ (approx): ${8 * number_of_points_inside / number_of_points} #points: ${number_of_points} #inside: ${number_of_points_inside}`, 10, 10); + // window.requestAnimationFrame(main); + }; + window.setInterval(main, 1000); + + window.addEventListener('load', main); + } +)(); + </script> + </head> + <body> + <canvas id="canvas" width="500" height="500"></canvas> + </body> +</html> diff --git a/dabbling/html/the-dancing-polygon-screensaver/index.html b/dabbling/html/the-dancing-polygon-screensaver/index.html @@ -0,0 +1,11 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8" /> + <script src="main.js" type="text/javascript"></script> + <link rel="stylesheet" href="style.css"></link> + </head> + <body> + <canvas id="canvas" width="800" height="600"></canvas> + </body> +</html> diff --git a/dabbling/html/the-dancing-polygon-screensaver/main.js b/dabbling/html/the-dancing-polygon-screensaver/main.js @@ -0,0 +1,217 @@ +'use strict;' + +Math.TAU = 2 * Math.PI; + +(function() { + let start_time; + let elapsed_time; + let previous_timestamp; + + let polygons_vertices = []; + let polygon_velocity = []; + + let hsv_values = [[0, 1, 0.7]]; + let color_wheel_velocity = 0.01; + + let wanted_number_of_polygons = 50; + let pixels_per_step = 10; + + function hsv_to_rgb(hue, saturation, value) { + // https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB + // H in [0, 1] (position on the color wheel) + // S in [0, 1] + // V in [0, 1] + + let chroma = value * saturation; + + let hue_tag = hue * 6; + + let x = chroma * (1 - Math.abs((hue_tag % 2) - 1)); + + let [red_1, green_1, blue_1] = ((hue_tag, chroma, x)=>{ + if (hue_tag >= 0 && hue_tag < 1) { return [chroma, x, 0]; + } else if (hue_tag >= 1 && hue_tag < 2) { return [x, chroma, 0]; + } else if (hue_tag >= 2 && hue_tag < 3) { return [0, chroma, x]; + } else if (hue_tag >= 3 && hue_tag < 4) { return [0, x, chroma]; + } else if (hue_tag >= 4 && hue_tag < 5) { return [x, 0, chroma]; + } else if (hue_tag >= 5 && hue_tag < 6) { return [chroma, 0, x]; + } + })(hue_tag, chroma, x); + + let m = value - chroma; + + return [red_1 + m, green_1 + m, blue_1 + m]; + } + + function move_and_bounce_1d(position, velocity, maximum_value) { + let new_position = position + velocity; + + if (new_position > maximum_value) { + return [2 * maximum_value - new_position, -Math.abs(velocity)]; + } else if (new_position < 0) { + return [Math.abs(new_position), Math.abs(velocity)]; + } else { + return [new_position, velocity]; + }; + + } + + function move_and_bounce_2d(position, velocity, width, height) { + let [position_x, velocity_x] = move_and_bounce_1d(position[0], velocity[0], width); + let [position_y, velocity_y] = move_and_bounce_1d(position[1], velocity[1], height); + + return [ + [position_x, position_y], + [velocity_x, velocity_y], + ]; + } + + function move_polygon(polygon_vertices, polygon_velocity) { + for (let vertex_number = 0; vertex_number < polygon_vertices.length; vertex_number++) { + let [new_position, new_velocity] = move_and_bounce_2d( + polygon_vertices[vertex_number], + polygon_velocity[vertex_number], + canvas.width, + canvas.height, + ); + + polygon_vertices[vertex_number] = new_position; + polygon_velocity[vertex_number] = new_velocity; + } + }; + + function draw_polygon(ctx, polygon_vertices, rgb) { + ctx.beginPath(); + + ctx.strokeStyle = `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`; + + ctx.moveTo(polygon_vertices[0][0], polygon_vertices[0][1]); + + for (let vertex_number = 1; vertex_number < polygon_vertices.length; vertex_number++) { + ctx.lineTo(polygon_vertices[vertex_number][0], polygon_vertices[vertex_number][1]); + } + + ctx.closePath(); + ctx.stroke(); + } + + function uniform_random_direction() { + let uniform = Math.random(); + let direction_vector = [ + Math.cos(uniform * Math.TAU), + Math.sin(uniform * Math.TAU), + ]; + return direction_vector; + } + + function step_polygons() { + if (polygons_vertices.length >= wanted_number_of_polygons) { + // Remove oldest polygon, the one at position 0. + polygons_vertices = polygons_vertices.slice(1, polygons_vertices.length); + } + + // Get the newest polygon at position n-1. + let current_polygon_vertices = polygons_vertices[polygons_vertices.length - 1]; + + // Clone our latest polygon. + let new_polygon_vertices = current_polygon_vertices.map(vertex => vertex.map(axis => axis)); + + move_polygon(new_polygon_vertices, polygon_velocity); + + polygons_vertices.push(new_polygon_vertices); + } + + function step_hsv_values() { + if (hsv_values.length >= wanted_number_of_polygons) { + // Remove oldest hsv value, the one at position 0. + hsv_values = hsv_values.slice(1, hsv_values.length); + } + + // Get the newest hsv_value at position n-1. + let current_hsv_value = hsv_values[hsv_values.length - 1]; + + // Clone. + let new_hsv_value = current_hsv_value.map(axis => axis); + + // Spin the hue around in the color wheel. + new_hsv_value[0] = (new_hsv_value[0] + color_wheel_velocity) % 1; + + hsv_values.push(new_hsv_value); + } + + function draw_polygons(ctx, polygons_vertices, hsv_values) { + for (let current_polygon = 0; current_polygon < polygons_vertices.length; current_polygon++) { + let rgb = hsv_to_rgb( + hsv_values[current_polygon][0], + hsv_values[current_polygon][1], + hsv_values[current_polygon][2], + ).map(x => 255 * x); + draw_polygon(ctx, polygons_vertices[current_polygon], rgb); + } + } + + function step(timestamp) { + if (start_time === undefined) { + start_time = timestamp; + } + + elapsed_time = timestamp - start_time; + + delta_time = timestamp - previous_timestamp; + + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + ctx.clearRect(0, 0, canvas.width, canvas.height); + + step_polygons(); + step_hsv_values(); + + draw_polygons(ctx, polygons_vertices, hsv_values); + + previous_timestamp = timestamp; + + window.requestAnimationFrame(step) + } + + function resize_window() { + // https://stackoverflow.com/a/32119392 + + let canvas = document.getElementById('canvas'); + + canvas.width = window.innerWidth; + canvas.style.width = window.innerWidth; + canvas.height = window.innerHeight; + canvas.style.height = window.innerHeight; + } + + function reset_world() { + polygons_vertices = [[ + [canvas.width / 2, canvas.height / 3], + [2 * canvas.width / 3, 2 * canvas.height / 3], + [canvas.width / 3, 2 * canvas.height / 3], + ]]; + + polygon_velocity = [ + uniform_random_direction(), + uniform_random_direction(), + uniform_random_direction(), + ].map(vertex => vertex.map(axis => pixels_per_step * axis)); + } + + function main() { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + resize_window(); + reset_world(); + + canvas.addEventListener('click', reset_world); + + window.addEventListener('resize', resize_window) + + window.requestAnimationFrame(step); + } + + window.addEventListener('load', main); +})(); diff --git a/dabbling/html/the-dancing-polygon-screensaver/style.css b/dabbling/html/the-dancing-polygon-screensaver/style.css @@ -0,0 +1,11 @@ +/* Stolen from https://developer.mozilla.org/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it */ + +* { + padding: 0; + margin: 0; +} +canvas { + background: #000; + display: block; + margin: 0 auto; +} diff --git a/dabbling/html/wtc_plaza_2001-09-11/freesound.org/data/previews/239/239900_4079949-lq.mp3 b/dabbling/html/wtc_plaza_2001-09-11/freesound.org/data/previews/239/239900_4079949-lq.mp3 Binary files differ. diff --git a/dabbling/html/wtc_plaza_2001-09-11/freesound.org/data/previews/344/344150_6179115-lq.mp3 b/dabbling/html/wtc_plaza_2001-09-11/freesound.org/data/previews/344/344150_6179115-lq.mp3 Binary files differ. diff --git a/dabbling/html/wtc_plaza_2001-09-11/index.html b/dabbling/html/wtc_plaza_2001-09-11/index.html @@ -0,0 +1,23 @@ +<!doctype html> +<html> + <head> + <meta charset="UTF-8"> + <title>WTC Plaza circa 2001-09-11.</title> + <script type="text/javascript" src="wtc_plaza_2001-09-11.js"></script> + </head> + <body> + WTC Plaza circa 2001-09-11: + <canvas id="canvas" width="500" height="500"></canvas> + <audio id="scream_audio" src="freesound.org/data/previews/239/239900_4079949-lq.mp3"></audio> + <audio id="thump_audio" src="freesound.org/data/previews/344/344150_6179115-lq.mp3"></audio> + <button id="jump_button">Jump</button> + <button id="clear_button">Clear</button> + <hr> + <aside> + <a href="https://freesound.org/people/TheSubber13/sounds/239900/">The Scream</a> is licensed <a href="http://creativecommons.org/licenses/by-nc/3.0/">CC-By-NC 3.0 (boo!)</a> by <a href="https://freesound.org/people/TheSubber13/">TheSubber13</a>. + </aside> + <aside> + <a href="https://freesound.org/people/Brokenphono/sounds/344150/">The Thump</a> is licensed <a href="http://creativecommons.org/publicdomain/zero/1.0/">CC-Zero 1.0</a> by <a href="https://freesound.org/people/Brokenphono/">Brokenphono</a>. + </aside> + </body> +</html> diff --git a/dabbling/html/wtc_plaza_2001-09-11/wtc_plaza_2001-09-11.js b/dabbling/html/wtc_plaza_2001-09-11/wtc_plaza_2001-09-11.js @@ -0,0 +1,290 @@ +'use strict'; + +// Why is it not part of the standard yet? +Math.TAU = 2 * Math.PI; + +(function() { + let audio_context; + let scream_audio_data; + let thump_audio_data; + + let BLOOD_COLOR = (0, 0, 255, 255); + let STICK_FIGURE_COLOR = (0, 0, 0, 255); + + function lerp(portion, start, stop) { + return portion * (stop - start) + start; + } + + function make_random_direction() { + let uniform = Math.random(); + return [ + Math.cos(Math.TAU * uniform), + Math.sin(Math.TAU * uniform), + ]; + }; + + function add_random_position(original_position, distance) { + let new_direction = make_random_direction(); + + return [ + original_position[0] + distance * new_direction[0], + original_position[1] + distance * new_direction[1], + ]; + } + + function make_random_stick_figure_positions() { + let head_neck_distance = 0.05; + let elbow_neck_distance = 0.050; + let arm_tip_elbow_distance = 0.050; + let pelvis_neck_distance = 0.125; + let knee_pelvis_distance = 0.075; + let leg_tip_knee_distance = 0.075; + + let head_position = [Math.random(), Math.random()]; + + let neck_position = add_random_position(head_position, head_neck_distance); + + let left_elbow_position = add_random_position(neck_position, elbow_neck_distance); + let right_elbow_position = add_random_position(neck_position, elbow_neck_distance); + + let left_arm_tip_position = add_random_position(left_elbow_position, arm_tip_elbow_distance); + let right_arm_tip_position = add_random_position(right_elbow_position, arm_tip_elbow_distance); + + let pelvis_position = add_random_position(neck_position, pelvis_neck_distance); + + let left_knee_position = add_random_position(pelvis_position, knee_pelvis_distance); + let right_knee_position = add_random_position(pelvis_position, knee_pelvis_distance); + + let left_leg_top_position = add_random_position(left_knee_position, leg_tip_knee_distance); + let right_leg_top_position = add_random_position(right_knee_position, leg_tip_knee_distance); + + return [ + head_position, + neck_position, + left_elbow_position, + right_elbow_position, + left_arm_tip_position, + right_arm_tip_position, + pelvis_position, + left_knee_position, + right_knee_position, + left_leg_top_position, + right_leg_top_position, + ]; + } + + + + + function make_blood_splatter_positions(stick_figure_positions) { + let blood_splatter_positions = []; + + for (let i = 0; i < 3; i++) { + blood_splatter_positions.push( + add_random_position(stick_figure_positions[1], 0.05 * (i + 1)) + ); + } + + for (let i = 0; i < 3; i++) { + blood_splatter_positions.push( + add_random_position(stick_figure_positions[6], 0.05 * (i + 1)) + ); + } + + return blood_splatter_positions; + } + + function draw_blood_splatter(blood_splatter_positions) { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + let image_width = ctx.canvas.width; + let image_height = ctx.canvas.height; + + let blood_splatter_positions_in_image = blood_splatter_positions.map( + position => [ + Math.floor(position[0] * image_width), + Math.floor(position[1] * image_height), + ] + ); + + + ctx.fillStyle = '#f00'; + + ctx.beginPath(); + ctx.arc(blood_splatter_positions_in_image[0][0], blood_splatter_positions_in_image[0][1], 20, 0, Math.TAU); + ctx.fill(); + + ctx.beginPath(); + ctx.arc(blood_splatter_positions_in_image[1][0], blood_splatter_positions_in_image[1][1], 10, 0, Math.TAU); + ctx.fill(); + + ctx.beginPath(); + ctx.arc(blood_splatter_positions_in_image[2][0], blood_splatter_positions_in_image[2][1], 5, 0, Math.TAU); + ctx.fill(); + + ctx.beginPath(); + ctx.arc(blood_splatter_positions_in_image[3][0], blood_splatter_positions_in_image[3][1], 20, 0, Math.TAU); + ctx.fill(); + + ctx.beginPath(); + ctx.arc(blood_splatter_positions_in_image[4][0], blood_splatter_positions_in_image[4][1], 10, 0, Math.TAU); + ctx.fill(); + + ctx.beginPath(); + ctx.arc(blood_splatter_positions_in_image[5][0], blood_splatter_positions_in_image[5][1], 5, 0, Math.TAU); + ctx.fill(); + + ctx.fill() + } + + + function draw_stick_figure(stick_figure_positions) { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + let image_width = ctx.canvas.width; + let image_height = ctx.canvas.height; + + let stick_figure_positions_in_image = stick_figure_positions.map( + x => [ + Math.floor(x[0] * image_width), + Math.floor(x[1] * image_height), + ] + ); + console.debug(stick_figure_positions_in_image) + + ctx.fillStyle = '#000'; + ctx.strokeStyle = '#000'; + ctx.lineWidth = 2; + + ctx.beginPath(); + ctx.arc( + stick_figure_positions_in_image[0][0], + stick_figure_positions_in_image[0][1], + 15, + 0, + Math.TAU, + false); + ctx.fill(); + + let connections = [ + [0, 1], + [1, 2], + [1, 3], + [2, 4], + [3, 5], + [1, 6], + [7, 6], + [8, 6], + [7, 9], + [8, 10], + ]; + for (let i = 0; i < connections.length; i++) { + ctx.beginPath(); + let origin_coordinates = stick_figure_positions_in_image[connections[i][0]]; + let destination_coordinates = stick_figure_positions_in_image[connections[i][1]]; + console.debug([origin_coordinates, destination_coordinates]) + ctx.moveTo(origin_coordinates[0], origin_coordinates[1]); + ctx.lineTo(destination_coordinates[0], destination_coordinates[1]); + ctx.stroke(); + } + } + + function draw_jumper() { + let stick_figure_positions = make_random_stick_figure_positions(); + let blood_splatter_positions = make_blood_splatter_positions(stick_figure_positions); + + console.debug(stick_figure_positions); + console.debug(blood_splatter_positions); + + draw_blood_splatter(blood_splatter_positions); + draw_stick_figure(stick_figure_positions); + } + + + function jump() { + let scream_rate_fraction = lerp(Math.random(), 0.90, 1.45); + let scream_audio_buffer = make_audio_buffer(scream_audio_data, scream_rate_fraction); + let scream_source = make_audio_buffer_source(scream_audio_buffer); + scream_source.start(); + + setTimeout(function() { + scream_source.stop(); + + let thump_audio_buffer = make_audio_buffer(thump_audio_data, 1); + let thump_audio_source = make_audio_buffer_source(thump_audio_buffer); + + thump_audio_source.currentTime = 0.2; + + thump_audio_source.start() + + draw_jumper(); + }, 1700.0 / scream_rate_fraction); + } + + function clear_canvas() { + let canvas = document.getElementById('canvas'); + let ctx = canvas.getContext('2d'); + + ctx.clearRect(0, 0, canvas.width, canvas.height); + } + + async function get_audio_data(audio_file_path) { + let response = await fetch(audio_file_path); + + let array_buffer = await response.arrayBuffer(); + + return await audio_context.decodeAudioData(array_buffer); + } + + function make_audio_buffer(audio_data, sample_rate_fraction) { + let audio_buffer = audio_context.createBuffer( + audio_data.numberOfChannels, + audio_data.getChannelData(0).length, + audio_data.sampleRate * sample_rate_fraction, + ); + + for (let channel_number = 0; channel_number < audio_buffer.numberOfChannels; channel_number++) { + let current_buffer = audio_buffer.getChannelData(channel_number); + let audio_data_channel = audio_data.getChannelData(channel_number); + + for (let sample_number = 0; sample_number < current_buffer.length; sample_number++) { + current_buffer[sample_number] = audio_data_channel[sample_number]; + } + } + + return audio_buffer; + } + + function make_audio_buffer_source(audio_buffer) { + let buffer_source = audio_context.createBufferSource(); + + buffer_source.buffer = audio_buffer; + + buffer_source.connect(audio_context.destination); + + return buffer_source; + } + + async function main() { + audio_context = new AudioContext(); + + let scream_audio_element = document.getElementById('scream_audio'); + let thump_audio_element = document.getElementById('thump_audio'); + + scream_audio_data = await get_audio_data(scream_audio_element.src); + thump_audio_data = await get_audio_data(thump_audio_element.src); + + let canvas = document.getElementById('canvas'); + canvas.addEventListener('click', jump); + + let jump_button = document.getElementById('jump_button'); + jump_button.addEventListener('click', jump); + + let clear_button = document.getElementById('clear_button'); + clear_button.addEventListener('click', clear_canvas); + } + + window.addEventListener('load', main); +})(); diff --git a/dabbling/poetry.lock b/dabbling/poetry.lock @@ -0,0 +1,1561 @@ +[[package]] +category = "dev" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +name = "appdirs" +optional = false +python-versions = "*" +version = "1.4.4" + +[[package]] +category = "main" +description = "Disable App Nap on OS X 10.9" +marker = "python_version >= \"3.3\" and sys_platform == \"darwin\" or platform_system == \"Darwin\"" +name = "appnope" +optional = false +python-versions = "*" +version = "0.1.0" + +[[package]] +category = "dev" +description = "Atomic file writes." +marker = "sys_platform == \"win32\"" +name = "atomicwrites" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.4.0" + +[[package]] +category = "main" +description = "Classes Without Boilerplate" +name = "attrs" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "19.3.0" + +[package.extras] +azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] +dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] +docs = ["sphinx", "zope.interface"] +tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] + +[[package]] +category = "main" +description = "Specifications for callback functions passed in to an API" +marker = "python_version >= \"3.3\"" +name = "backcall" +optional = false +python-versions = "*" +version = "0.2.0" + +[[package]] +category = "main" +description = "Screen-scraping library" +name = "beautifulsoup4" +optional = false +python-versions = "*" +version = "4.9.1" + +[package.dependencies] +soupsieve = [">1.2", "<2.0"] + +[package.extras] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +category = "dev" +description = "The uncompromising code formatter." +name = "black" +optional = false +python-versions = ">=3.6" +version = "19.10b0" + +[package.dependencies] +appdirs = "*" +attrs = ">=18.1.0" +click = ">=6.5" +pathspec = ">=0.6,<1" +regex = "*" +toml = ">=0.9.4" +typed-ast = ">=1.4.0" + +[package.extras] +d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] + +[[package]] +category = "main" +description = "An easy safelist-based HTML-sanitizing tool." +name = "bleach" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "3.1.5" + +[package.dependencies] +packaging = "*" +six = ">=1.9.0" +webencodings = "*" + +[[package]] +category = "main" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi" +optional = false +python-versions = "*" +version = "2020.6.20" + +[[package]] +category = "main" +description = "Universal encoding detector for Python 2 and 3" +name = "chardet" +optional = false +python-versions = "*" +version = "3.0.4" + +[[package]] +category = "main" +description = "Composable command line interface toolkit" +name = "click" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "7.1.2" + +[[package]] +category = "main" +description = "Cross-platform colored terminal text." +marker = "python_version >= \"3.3\" and sys_platform == \"win32\" or sys_platform == \"win32\"" +name = "colorama" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.4.3" + +[[package]] +category = "dev" +description = "Code coverage measurement for Python" +name = "coverage" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "5.1" + +[package.dependencies] +[package.dependencies.toml] +optional = true +version = "*" + +[package.extras] +toml = ["toml"] + +[[package]] +category = "main" +description = "Composable style cycles" +name = "cycler" +optional = false +python-versions = "*" +version = "0.10.0" + +[package.dependencies] +six = "*" + +[[package]] +category = "main" +description = "Decorators for Humans" +name = "decorator" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" +version = "4.4.2" + +[[package]] +category = "main" +description = "XML bomb protection for Python stdlib modules" +name = "defusedxml" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.6.0" + +[[package]] +category = "main" +description = "Discover and load entry points from installed packages." +name = "entrypoints" +optional = false +python-versions = ">=2.7" +version = "0.3" + +[[package]] +category = "main" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.9" + +[[package]] +category = "main" +description = "Read metadata from Python packages" +marker = "python_version < \"3.8\"" +name = "importlib-metadata" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "1.6.1" + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "rst.linker"] +testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] + +[[package]] +category = "main" +description = "IPython Kernel for Jupyter" +name = "ipykernel" +optional = false +python-versions = ">=3.5" +version = "5.3.0" + +[package.dependencies] +appnope = "*" +ipython = ">=5.0.0" +jupyter-client = "*" +tornado = ">=4.2" +traitlets = ">=4.1.0" + +[package.extras] +test = ["pytest (!=5.3.4)", "pytest-cov", "flaky", "nose"] + +[[package]] +category = "main" +description = "IPython: Productive Interactive Computing" +name = "ipython" +optional = false +python-versions = ">=3.6" +version = "7.15.0" + +[package.dependencies] +appnope = "*" +backcall = "*" +colorama = "*" +decorator = "*" +jedi = ">=0.10" +pexpect = "*" +pickleshare = "*" +prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" +pygments = "*" +setuptools = ">=18.5" +traitlets = ">=4.2" + +[package.extras] +all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.14)", "pygments", "qtconsole", "requests", "testpath"] +doc = ["Sphinx (>=1.3)"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["notebook", "ipywidgets"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.14)"] + +[[package]] +category = "main" +description = "Vestigial utilities from IPython" +name = "ipython-genutils" +optional = false +python-versions = "*" +version = "0.2.0" + +[[package]] +category = "main" +description = "IPython HTML widgets for Jupyter" +name = "ipywidgets" +optional = false +python-versions = "*" +version = "7.5.1" + +[package.dependencies] +ipykernel = ">=4.5.1" +nbformat = ">=4.2.0" +traitlets = ">=4.3.1" +widgetsnbextension = ">=3.5.0,<3.6.0" + +[package.dependencies.ipython] +python = ">=3.3" +version = ">=4.0.0" + +[package.extras] +test = ["pytest (>=3.6.0)", "pytest-cov", "mock"] + +[[package]] +category = "main" +description = "An autocompletion tool for Python that can be used for text editors." +marker = "python_version >= \"3.3\"" +name = "jedi" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.17.1" + +[package.dependencies] +parso = ">=0.7.0,<0.8.0" + +[package.extras] +qa = ["flake8 (3.7.9)"] +testing = ["Django (<3.1)", "colorama", "docopt", "pytest (>=3.9.0,<5.0.0)"] + +[[package]] +category = "main" +description = "A very fast and expressive template engine." +name = "jinja2" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.11.2" + +[package.dependencies] +MarkupSafe = ">=0.23" + +[package.extras] +i18n = ["Babel (>=0.8)"] + +[[package]] +category = "main" +description = "An implementation of JSON Schema validation for Python" +name = "jsonschema" +optional = false +python-versions = "*" +version = "3.2.0" + +[package.dependencies] +attrs = ">=17.4.0" +pyrsistent = ">=0.14.0" +setuptools = "*" +six = ">=1.11.0" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" + +[package.extras] +format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] +format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"] + +[[package]] +category = "main" +description = "Jupyter metapackage. Install all the Jupyter components in one go." +name = "jupyter" +optional = false +python-versions = "*" +version = "1.0.0" + +[package.dependencies] +ipykernel = "*" +ipywidgets = "*" +jupyter-console = "*" +nbconvert = "*" +notebook = "*" +qtconsole = "*" + +[[package]] +category = "main" +description = "Jupyter protocol implementation and client libraries" +name = "jupyter-client" +optional = false +python-versions = ">=3.5" +version = "6.1.3" + +[package.dependencies] +jupyter-core = ">=4.6.0" +python-dateutil = ">=2.1" +pyzmq = ">=13" +tornado = ">=4.1" +traitlets = "*" + +[package.extras] +test = ["ipykernel", "ipython", "mock", "pytest"] + +[[package]] +category = "main" +description = "Jupyter terminal console" +name = "jupyter-console" +optional = false +python-versions = ">=3.5" +version = "6.1.0" + +[package.dependencies] +ipykernel = "*" +ipython = "*" +jupyter-client = "*" +prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" +pygments = "*" + +[package.extras] +test = ["pexpect"] + +[[package]] +category = "main" +description = "Jupyter core package. A base package on which Jupyter projects rely." +name = "jupyter-core" +optional = false +python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,>=2.7" +version = "4.6.3" + +[package.dependencies] +pywin32 = ">=1.0" +traitlets = "*" + +[[package]] +category = "main" +description = "A fast implementation of the Cassowary constraint solver" +name = "kiwisolver" +optional = false +python-versions = ">=3.6" +version = "1.2.0" + +[[package]] +category = "main" +description = "Safely add untrusted strings to HTML/XML markup." +name = "markupsafe" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.1.1" + +[[package]] +category = "main" +description = "Python plotting package" +name = "matplotlib" +optional = false +python-versions = ">=3.6" +version = "3.2.2" + +[package.dependencies] +cycler = ">=0.10" +kiwisolver = ">=1.0.1" +numpy = ">=1.11" +pyparsing = ">=2.0.1,<2.0.4 || >2.0.4,<2.1.2 || >2.1.2,<2.1.6 || >2.1.6" +python-dateutil = ">=2.1" + +[[package]] +category = "main" +description = "The fastest markdown parser in pure Python" +name = "mistune" +optional = false +python-versions = "*" +version = "0.8.4" + +[[package]] +category = "dev" +description = "More routines for operating on iterables, beyond itertools" +name = "more-itertools" +optional = false +python-versions = ">=3.5" +version = "8.4.0" + +[[package]] +category = "dev" +description = "Optional static typing for Python" +name = "mypy" +optional = false +python-versions = ">=3.5" +version = "0.780" + +[package.dependencies] +mypy-extensions = ">=0.4.3,<0.5.0" +typed-ast = ">=1.4.0,<1.5.0" +typing-extensions = ">=3.7.4" + +[package.extras] +dmypy = ["psutil (>=4.0)"] + +[[package]] +category = "dev" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +name = "mypy-extensions" +optional = false +python-versions = "*" +version = "0.4.3" + +[[package]] +category = "main" +description = "Converting Jupyter Notebooks" +name = "nbconvert" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "5.6.1" + +[package.dependencies] +bleach = "*" +defusedxml = "*" +entrypoints = ">=0.2.2" +jinja2 = ">=2.4" +jupyter-core = "*" +mistune = ">=0.8.1,<2" +nbformat = ">=4.4" +pandocfilters = ">=1.4.1" +pygments = "*" +testpath = "*" +traitlets = ">=4.2" + +[package.extras] +all = ["pytest", "pytest-cov", "ipykernel", "jupyter-client (>=5.3.1)", "ipywidgets (>=7)", "pebble", "tornado (>=4.0)", "sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "sphinxcontrib-github-alt", "ipython", "mock"] +docs = ["sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "sphinxcontrib-github-alt", "ipython", "jupyter-client (>=5.3.1)"] +execute = ["jupyter-client (>=5.3.1)"] +serve = ["tornado (>=4.0)"] +test = ["pytest", "pytest-cov", "ipykernel", "jupyter-client (>=5.3.1)", "ipywidgets (>=7)", "pebble", "mock"] + +[[package]] +category = "main" +description = "The Jupyter Notebook format" +name = "nbformat" +optional = false +python-versions = ">=3.5" +version = "5.0.7" + +[package.dependencies] +ipython-genutils = "*" +jsonschema = ">=2.4,<2.5.0 || >2.5.0" +jupyter-core = "*" +traitlets = ">=4.1" + +[package.extras] +test = ["pytest", "pytest-cov", "testpath"] + +[[package]] +category = "main" +description = "A web-based notebook environment for interactive computing" +name = "notebook" +optional = false +python-versions = ">=3.5" +version = "6.0.3" + +[package.dependencies] +Send2Trash = "*" +ipykernel = "*" +ipython-genutils = "*" +jinja2 = "*" +jupyter-client = ">=5.3.4" +jupyter-core = ">=4.6.1" +nbconvert = "*" +nbformat = "*" +prometheus-client = "*" +pyzmq = ">=17" +terminado = ">=0.8.1" +tornado = ">=5.0" +traitlets = ">=4.2.1" + +[package.extras] +test = ["nose", "coverage", "requests", "nose-warnings-filters", "nbval", "nose-exclude", "selenium", "pytest", "pytest-cov", "nose-exclude"] + +[[package]] +category = "main" +description = "NumPy is the fundamental package for array computing with Python." +name = "numpy" +optional = false +python-versions = ">=3.6" +version = "1.19.0" + +[[package]] +category = "main" +description = "Core utilities for Python packages" +name = "packaging" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "20.4" + +[package.dependencies] +pyparsing = ">=2.0.2" +six = "*" + +[[package]] +category = "main" +description = "Powerful data structures for data analysis, time series, and statistics" +name = "pandas" +optional = false +python-versions = ">=3.6.1" +version = "1.0.5" + +[package.dependencies] +numpy = ">=1.13.3" +python-dateutil = ">=2.6.1" +pytz = ">=2017.2" + +[package.extras] +test = ["pytest (>=4.0.2)", "pytest-xdist", "hypothesis (>=3.58)"] + +[[package]] +category = "main" +description = "Utilities for writing pandoc filters in python" +name = "pandocfilters" +optional = false +python-versions = "*" +version = "1.4.2" + +[[package]] +category = "main" +description = "A Python Parser" +marker = "python_version >= \"3.3\"" +name = "parso" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.7.0" + +[package.extras] +testing = ["docopt", "pytest (>=3.0.7)"] + +[[package]] +category = "dev" +description = "Utility library for gitignore style pattern matching of file paths." +name = "pathspec" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.8.0" + +[[package]] +category = "main" +description = "Pexpect allows easy control of interactive console applications." +marker = "python_version >= \"3.3\" and sys_platform != \"win32\"" +name = "pexpect" +optional = false +python-versions = "*" +version = "4.8.0" + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +category = "main" +description = "Tiny 'shelve'-like database with concurrency support" +marker = "python_version >= \"3.3\"" +name = "pickleshare" +optional = false +python-versions = "*" +version = "0.7.5" + +[[package]] +category = "dev" +description = "plugin and hook calling mechanisms for python" +name = "pluggy" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.13.1" + +[package.dependencies] +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" + +[package.extras] +dev = ["pre-commit", "tox"] + +[[package]] +category = "main" +description = "Python client for the Prometheus monitoring system." +name = "prometheus-client" +optional = false +python-versions = "*" +version = "0.8.0" + +[package.extras] +twisted = ["twisted"] + +[[package]] +category = "main" +description = "Library for building powerful interactive command lines in Python" +name = "prompt-toolkit" +optional = false +python-versions = ">=3.6.1" +version = "3.0.5" + +[package.dependencies] +wcwidth = "*" + +[[package]] +category = "main" +description = "Run a subprocess in a pseudo terminal" +marker = "python_version >= \"3.3\" and sys_platform != \"win32\" or os_name != \"nt\"" +name = "ptyprocess" +optional = false +python-versions = "*" +version = "0.6.0" + +[[package]] +category = "dev" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +name = "py" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.8.2" + +[[package]] +category = "main" +description = "Pygments is a syntax highlighting package written in Python." +name = "pygments" +optional = false +python-versions = ">=3.5" +version = "2.6.1" + +[[package]] +category = "main" +description = "Python parsing module" +name = "pyparsing" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "2.4.7" + +[[package]] +category = "main" +description = "Persistent/Functional/Immutable data structures" +name = "pyrsistent" +optional = false +python-versions = "*" +version = "0.16.0" + +[package.dependencies] +six = "*" + +[[package]] +category = "dev" +description = "pytest: simple powerful testing with Python" +name = "pytest" +optional = false +python-versions = ">=3.5" +version = "5.4.3" + +[package.dependencies] +atomicwrites = ">=1.0" +attrs = ">=17.4.0" +colorama = "*" +more-itertools = ">=4.0.0" +packaging = "*" +pluggy = ">=0.12,<1.0" +py = ">=1.5.0" +wcwidth = "*" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" + +[package.extras] +checkqa-mypy = ["mypy (v0.761)"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + +[[package]] +category = "dev" +description = "Pytest plugin for measuring coverage." +name = "pytest-cov" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.10.0" + +[package.dependencies] +coverage = ">=4.4" +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "pytest-xdist", "virtualenv"] + +[[package]] +category = "main" +description = "Extensions to the standard Python datetime module" +name = "python-dateutil" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +version = "2.8.1" + +[package.dependencies] +six = ">=1.5" + +[[package]] +category = "main" +description = "World timezone definitions, modern and historical" +name = "pytz" +optional = false +python-versions = "*" +version = "2020.1" + +[[package]] +category = "main" +description = "Python for Window Extensions" +marker = "sys_platform == \"win32\"" +name = "pywin32" +optional = false +python-versions = "*" +version = "228" + +[[package]] +category = "main" +description = "Python bindings for the winpty library" +marker = "os_name == \"nt\"" +name = "pywinpty" +optional = false +python-versions = "*" +version = "0.5.7" + +[[package]] +category = "main" +description = "Python bindings for 0MQ" +name = "pyzmq" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*" +version = "19.0.1" + +[[package]] +category = "main" +description = "Jupyter Qt console" +name = "qtconsole" +optional = false +python-versions = "*" +version = "4.7.4" + +[package.dependencies] +ipykernel = ">=4.1" +ipython-genutils = "*" +jupyter-client = ">=4.1" +jupyter-core = "*" +pygments = "*" +pyzmq = ">=17.1" +qtpy = "*" +traitlets = "*" + +[package.extras] +doc = ["Sphinx (>=1.3)"] +test = ["pytest", "mock"] + +[[package]] +category = "main" +description = "Provides an abstraction layer on top of the various Qt bindings (PyQt5, PyQt4 and PySide) and additional custom QWidgets." +name = "qtpy" +optional = false +python-versions = "*" +version = "1.9.0" + +[[package]] +category = "dev" +description = "Alternative regular expression module, to replace re." +name = "regex" +optional = false +python-versions = "*" +version = "2020.6.8" + +[[package]] +category = "main" +description = "Python HTTP for Humans." +name = "requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.24.0" + +[package.dependencies] +certifi = ">=2017.4.17" +chardet = ">=3.0.2,<4" +idna = ">=2.5,<3" +urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" + +[package.extras] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] + +[[package]] +category = "main" +description = "Send file to trash natively under Mac OS X, Windows and Linux." +name = "send2trash" +optional = false +python-versions = "*" +version = "1.5.0" + +[[package]] +category = "main" +description = "Python 2 and 3 compatibility utilities" +name = "six" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "1.15.0" + +[[package]] +category = "main" +description = "A modern CSS selector implementation for Beautiful Soup." +name = "soupsieve" +optional = false +python-versions = "*" +version = "1.9.6" + +[[package]] +category = "main" +description = "Terminals served to xterm.js using Tornado websockets" +name = "terminado" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.8.3" + +[package.dependencies] +ptyprocess = "*" +pywinpty = ">=0.5" +tornado = ">=4" + +[[package]] +category = "main" +description = "Test utilities for code working with files and commands" +name = "testpath" +optional = false +python-versions = "*" +version = "0.4.4" + +[package.extras] +test = ["pathlib2"] + +[[package]] +category = "dev" +description = "Python Library for Tom's Obvious, Minimal Language" +name = "toml" +optional = false +python-versions = "*" +version = "0.10.1" + +[[package]] +category = "main" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +name = "tornado" +optional = false +python-versions = ">= 3.5" +version = "6.0.4" + +[[package]] +category = "main" +description = "Traitlets Python config system" +name = "traitlets" +optional = false +python-versions = "*" +version = "4.3.3" + +[package.dependencies] +decorator = "*" +ipython-genutils = "*" +six = "*" + +[package.extras] +test = ["pytest", "mock"] + +[[package]] +category = "dev" +description = "a fork of Python 2 and 3 ast modules with type comment support" +name = "typed-ast" +optional = false +python-versions = "*" +version = "1.4.1" + +[[package]] +category = "dev" +description = "Backported and Experimental Type Hints for Python 3.5+" +name = "typing-extensions" +optional = false +python-versions = "*" +version = "3.7.4.2" + +[[package]] +category = "main" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "1.25.9" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] + +[[package]] +category = "main" +description = "Measures the displayed width of unicode strings in a terminal" +name = "wcwidth" +optional = false +python-versions = "*" +version = "0.2.4" + +[[package]] +category = "main" +description = "Character encoding aliases for legacy web content" +name = "webencodings" +optional = false +python-versions = "*" +version = "0.5.1" + +[[package]] +category = "main" +description = "IPython HTML widgets for Jupyter" +name = "widgetsnbextension" +optional = false +python-versions = "*" +version = "3.5.1" + +[package.dependencies] +notebook = ">=4.4.1" + +[[package]] +category = "main" +description = "Backport of pathlib-compatible object wrapper for zip files" +marker = "python_version < \"3.8\"" +name = "zipp" +optional = false +python-versions = ">=3.6" +version = "3.1.0" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] +testing = ["jaraco.itertools", "func-timeout"] + +[metadata] +content-hash = "c205bfedb77cae261819851755bd1943d571e7e00cb9df898ede7a8052902301" +python-versions = ">=3.6.1,<4" + +[metadata.files] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] +appnope = [ + {file = "appnope-0.1.0-py2.py3-none-any.whl", hash = "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0"}, + {file = "appnope-0.1.0.tar.gz", hash = "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"}, +] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, + {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, +] +backcall = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] +beautifulsoup4 = [ + {file = "beautifulsoup4-4.9.1-py2-none-any.whl", hash = "sha256:e718f2342e2e099b640a34ab782407b7b676f47ee272d6739e60b8ea23829f2c"}, + {file = "beautifulsoup4-4.9.1-py3-none-any.whl", hash = "sha256:a6237df3c32ccfaee4fd201c8f5f9d9df619b93121d01353a64a73ce8c6ef9a8"}, + {file = "beautifulsoup4-4.9.1.tar.gz", hash = "sha256:73cc4d115b96f79c7d77c1c7f7a0a8d4c57860d1041df407dd1aae7f07a77fd7"}, +] +black = [ + {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, + {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, +] +bleach = [ + {file = "bleach-3.1.5-py2.py3-none-any.whl", hash = "sha256:2bce3d8fab545a6528c8fa5d9f9ae8ebc85a56da365c7f85180bfe96a35ef22f"}, + {file = "bleach-3.1.5.tar.gz", hash = "sha256:3c4c520fdb9db59ef139915a5db79f8b51bc2a7257ea0389f30c846883430a4b"}, +] +certifi = [ + {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, + {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, +] +chardet = [ + {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, + {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, +] +click = [ + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, +] +colorama = [ + {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, + {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, +] +coverage = [ + {file = "coverage-5.1-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65"}, + {file = "coverage-5.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2"}, + {file = "coverage-5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04"}, + {file = "coverage-5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6"}, + {file = "coverage-5.1-cp27-cp27m-win32.whl", hash = "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796"}, + {file = "coverage-5.1-cp27-cp27m-win_amd64.whl", hash = "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730"}, + {file = "coverage-5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0"}, + {file = "coverage-5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a"}, + {file = "coverage-5.1-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf"}, + {file = "coverage-5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9"}, + {file = "coverage-5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768"}, + {file = "coverage-5.1-cp35-cp35m-win32.whl", hash = "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2"}, + {file = "coverage-5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7"}, + {file = "coverage-5.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0"}, + {file = "coverage-5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019"}, + {file = "coverage-5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c"}, + {file = "coverage-5.1-cp36-cp36m-win32.whl", hash = "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1"}, + {file = "coverage-5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7"}, + {file = "coverage-5.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355"}, + {file = "coverage-5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489"}, + {file = "coverage-5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd"}, + {file = "coverage-5.1-cp37-cp37m-win32.whl", hash = "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e"}, + {file = "coverage-5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a"}, + {file = "coverage-5.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55"}, + {file = "coverage-5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c"}, + {file = "coverage-5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef"}, + {file = "coverage-5.1-cp38-cp38-win32.whl", hash = "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24"}, + {file = "coverage-5.1-cp38-cp38-win_amd64.whl", hash = "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0"}, + {file = "coverage-5.1-cp39-cp39-win32.whl", hash = "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4"}, + {file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"}, + {file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"}, +] +cycler = [ + {file = "cycler-0.10.0-py2.py3-none-any.whl", hash = "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d"}, + {file = "cycler-0.10.0.tar.gz", hash = "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"}, +] +decorator = [ + {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, + {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"}, +] +defusedxml = [ + {file = "defusedxml-0.6.0-py2.py3-none-any.whl", hash = "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93"}, + {file = "defusedxml-0.6.0.tar.gz", hash = "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"}, +] +entrypoints = [ + {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"}, + {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, +] +idna = [ + {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, + {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, +] +importlib-metadata = [ + {file = "importlib_metadata-1.6.1-py2.py3-none-any.whl", hash = "sha256:15ec6c0fd909e893e3a08b3a7c76ecb149122fb14b7efe1199ddd4c7c57ea958"}, + {file = "importlib_metadata-1.6.1.tar.gz", hash = "sha256:0505dd08068cfec00f53a74a0ad927676d7757da81b7436a6eefe4c7cf75c545"}, +] +ipykernel = [ + {file = "ipykernel-5.3.0-py3-none-any.whl", hash = "sha256:a8362e3ae365023ca458effe93b026b8cdadc0b73ff3031472128dd8a2cf0289"}, + {file = "ipykernel-5.3.0.tar.gz", hash = "sha256:731adb3f2c4ebcaff52e10a855ddc87670359a89c9c784d711e62d66fccdafae"}, +] +ipython = [ + {file = "ipython-7.15.0-py3-none-any.whl", hash = "sha256:1b85d65632211bf5d3e6f1406f3393c8c429a47d7b947b9a87812aa5bce6595c"}, + {file = "ipython-7.15.0.tar.gz", hash = "sha256:0ef1433879816a960cd3ae1ae1dc82c64732ca75cec8dab5a4e29783fb571d0e"}, +] +ipython-genutils = [ + {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, + {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, +] +ipywidgets = [ + {file = "ipywidgets-7.5.1-py2.py3-none-any.whl", hash = "sha256:13ffeca438e0c0f91ae583dc22f50379b9d6b28390ac7be8b757140e9a771516"}, + {file = "ipywidgets-7.5.1.tar.gz", hash = "sha256:e945f6e02854a74994c596d9db83444a1850c01648f1574adf144fbbabe05c97"}, +] +jedi = [ + {file = "jedi-0.17.1-py2.py3-none-any.whl", hash = "sha256:1ddb0ec78059e8e27ec9eb5098360b4ea0a3dd840bedf21415ea820c21b40a22"}, + {file = "jedi-0.17.1.tar.gz", hash = "sha256:807d5d4f96711a2bcfdd5dfa3b1ae6d09aa53832b182090b222b5efb81f52f63"}, +] +jinja2 = [ + {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, + {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, +] +jsonschema = [ + {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, + {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, +] +jupyter = [ + {file = "jupyter-1.0.0-py2.py3-none-any.whl", hash = "sha256:5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78"}, + {file = "jupyter-1.0.0.tar.gz", hash = "sha256:d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"}, + {file = "jupyter-1.0.0.zip", hash = "sha256:3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7"}, +] +jupyter-client = [ + {file = "jupyter_client-6.1.3-py3-none-any.whl", hash = "sha256:cde8e83aab3ec1c614f221ae54713a9a46d3bf28292609d2db1b439bef5a8c8e"}, + {file = "jupyter_client-6.1.3.tar.gz", hash = "sha256:3a32fa4d0b16d1c626b30c3002a62dfd86d6863ed39eaba3f537fade197bb756"}, +] +jupyter-console = [ + {file = "jupyter_console-6.1.0-py2.py3-none-any.whl", hash = "sha256:b392155112ec86a329df03b225749a0fa903aa80811e8eda55796a40b5e470d8"}, + {file = "jupyter_console-6.1.0.tar.gz", hash = "sha256:6f6ead433b0534909df789ea64f0a14cdf9b6b2360757756f08182be4b9e431b"}, +] +jupyter-core = [ + {file = "jupyter_core-4.6.3-py2.py3-none-any.whl", hash = "sha256:a4ee613c060fe5697d913416fc9d553599c05e4492d58fac1192c9a6844abb21"}, + {file = "jupyter_core-4.6.3.tar.gz", hash = "sha256:394fd5dd787e7c8861741880bdf8a00ce39f95de5d18e579c74b882522219e7e"}, +] +kiwisolver = [ + {file = "kiwisolver-1.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:443c2320520eda0a5b930b2725b26f6175ca4453c61f739fef7a5847bd262f74"}, + {file = "kiwisolver-1.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:efcf3397ae1e3c3a4a0a0636542bcad5adad3b1dd3e8e629d0b6e201347176c8"}, + {file = "kiwisolver-1.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fccefc0d36a38c57b7bd233a9b485e2f1eb71903ca7ad7adacad6c28a56d62d2"}, + {file = "kiwisolver-1.2.0-cp36-none-win32.whl", hash = "sha256:60a78858580761fe611d22127868f3dc9f98871e6fdf0a15cc4203ed9ba6179b"}, + {file = "kiwisolver-1.2.0-cp36-none-win_amd64.whl", hash = "sha256:556da0a5f60f6486ec4969abbc1dd83cf9b5c2deadc8288508e55c0f5f87d29c"}, + {file = "kiwisolver-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7cc095a4661bdd8a5742aaf7c10ea9fac142d76ff1770a0f84394038126d8fc7"}, + {file = "kiwisolver-1.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c955791d80e464da3b471ab41eb65cf5a40c15ce9b001fdc5bbc241170de58ec"}, + {file = "kiwisolver-1.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:603162139684ee56bcd57acc74035fceed7dd8d732f38c0959c8bd157f913fec"}, + {file = "kiwisolver-1.2.0-cp37-none-win32.whl", hash = "sha256:03662cbd3e6729f341a97dd2690b271e51a67a68322affab12a5b011344b973c"}, + {file = "kiwisolver-1.2.0-cp37-none-win_amd64.whl", hash = "sha256:4eadb361baf3069f278b055e3bb53fa189cea2fd02cb2c353b7a99ebb4477ef1"}, + {file = "kiwisolver-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c31bc3c8e903d60a1ea31a754c72559398d91b5929fcb329b1c3a3d3f6e72113"}, + {file = "kiwisolver-1.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d52b989dc23cdaa92582ceb4af8d5bcc94d74b2c3e64cd6785558ec6a879793e"}, + {file = "kiwisolver-1.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e586b28354d7b6584d8973656a7954b1c69c93f708c0c07b77884f91640b7657"}, + {file = "kiwisolver-1.2.0-cp38-none-win32.whl", hash = "sha256:d069ef4b20b1e6b19f790d00097a5d5d2c50871b66d10075dab78938dc2ee2cf"}, + {file = "kiwisolver-1.2.0-cp38-none-win_amd64.whl", hash = "sha256:18d749f3e56c0480dccd1714230da0f328e6e4accf188dd4e6884bdd06bf02dd"}, + {file = "kiwisolver-1.2.0.tar.gz", hash = "sha256:247800260cd38160c362d211dcaf4ed0f7816afb5efe56544748b21d6ad6d17f"}, +] +markupsafe = [ + {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, + {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, +] +matplotlib = [ + {file = "matplotlib-3.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a47abc48c7b81fe6e636dde8a58e49b13d87d140e0f448213a4879f4a3f73345"}, + {file = "matplotlib-3.2.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:20bcd11efe194cd302bd0653cb025b8d16bcd80442359bfca8d49dc805f35ec8"}, + {file = "matplotlib-3.2.2-cp36-cp36m-win32.whl", hash = "sha256:2a6d64336b547e25730b6221e7aadfb01a391a065d43b5f51f0b9d7f673d2dd2"}, + {file = "matplotlib-3.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:4416825ebc9c1f135027a30e8d8aea0edcf45078ce767c7f7386737413cfb98f"}, + {file = "matplotlib-3.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:465c752278d27895e23f1379d6fcfa3a2990643b803c25e3bc16a10641d2346a"}, + {file = "matplotlib-3.2.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:81de040403a33bf3c68e9d4a40e26c8d24da00f7e3fadd845003b7e106785da7"}, + {file = "matplotlib-3.2.2-cp37-cp37m-win32.whl", hash = "sha256:006413f08ba5db1f5b1e0d6fbdc2ac9058b062ccf552f57182563a78579c34b4"}, + {file = "matplotlib-3.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:da06fa530591a141ffbe1712bbeec784734c3436b40c942d21652f305199b5d9"}, + {file = "matplotlib-3.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:894dd47c0a6ce38dc19bc87d1f7e2b0608310b2a18d1572291157450b05ce874"}, + {file = "matplotlib-3.2.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1ab264770e7cf2cf4feb99f22c737066aef21ddf1ec402dc255450ac15eacb7b"}, + {file = "matplotlib-3.2.2-cp38-cp38-win32.whl", hash = "sha256:91c153f4318e3c67c035fd1185f5ea2613f15008b73b66985033033f6fe54bbd"}, + {file = "matplotlib-3.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:a68e42e22f7fd190a532e4215e142276970c2d54040a0c46842fcb3db8b6ec5b"}, + {file = "matplotlib-3.2.2-cp39-cp39-win32.whl", hash = "sha256:647cf232ccf6265d2ba1ac4103e8c8b6ac7b03a40da3421234ffb03dda217f59"}, + {file = "matplotlib-3.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:31d32c83bb2b617377c6156f75e88b9ec2ded289e47ad4ff0f263dc1019d88b1"}, + {file = "matplotlib-3.2.2-pp36-pypy36_pp73-win32.whl", hash = "sha256:67065d938df34478451af62fbd0670d2b51c4d859fb66673064eb5de8660dd7c"}, + {file = "matplotlib-3.2.2.tar.gz", hash = "sha256:3d77a6630d093d74cbbfebaa0571d00790966be1ed204e4a8239f5cbd6835c5d"}, +] +mistune = [ + {file = "mistune-0.8.4-py2.py3-none-any.whl", hash = "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4"}, + {file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"}, +] +more-itertools = [ + {file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"}, + {file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"}, +] +mypy = [ + {file = "mypy-0.780-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:d3b4941de44341227ece1caaf5b08b23e42ad4eeb8b603219afb11e9d4cfb437"}, + {file = "mypy-0.780-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1f3976a945ad7f0a0727aafdc5651c2d3278e3c88dee94e2bf75cd3386b7b2f4"}, + {file = "mypy-0.780-cp35-cp35m-win_amd64.whl", hash = "sha256:eadb865126da4e3c4c95bdb47fe1bb087a3e3ea14d39a3b13224b8a4d9f9a102"}, + {file = "mypy-0.780-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:75eed74d2faf2759f79c5f56f17388defd2fc994222312ec54ee921e37b31ad4"}, + {file = "mypy-0.780-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2f8c098f12b402c19b735aec724cc9105cc1a9eea405d08814eb4b14a6fb1a41"}, + {file = "mypy-0.780-cp36-cp36m-win_amd64.whl", hash = "sha256:62eb5dd4ea86bda8ce386f26684f7f26e4bfe6283c9f2b6ca6d17faf704dcfad"}, + {file = "mypy-0.780-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:00cb1964a7476e871d6108341ac9c1a857d6bd20bf5877f4773ac5e9d92cd3cd"}, + {file = "mypy-0.780-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:974bebe3699b9b46278a7f076635d219183da26e1a675c1f8243a69221758273"}, + {file = "mypy-0.780-cp37-cp37m-win_amd64.whl", hash = "sha256:64c36eb0936d0bfb7d8da49f92c18e312ad2e3ed46e5548ae4ca997b0d33bd59"}, + {file = "mypy-0.780-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d31291df31bafb997952dc0a17ebb2737f802c754aed31dd155a8bfe75112c57"}, + {file = "mypy-0.780-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a5e5bb12b7982b179af513dddb06fca12285f0316d74f3964078acbfcf4c68f2"}, + {file = "mypy-0.780-cp38-cp38-win_amd64.whl", hash = "sha256:5d142f219bf8c7894dfa79ebfb7d352c4c63a325e75f10dfb4c3db9417dcd135"}, + {file = "mypy-0.780-py3-none-any.whl", hash = "sha256:127de5a9b817a03a98c5ae8a0c46a20dc44442af6dcfa2ae7f96cb519b312efa"}, + {file = "mypy-0.780.tar.gz", hash = "sha256:4ef13b619a289aa025f2273e05e755f8049bb4eaba6d703a425de37d495d178d"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +nbconvert = [ + {file = "nbconvert-5.6.1-py2.py3-none-any.whl", hash = "sha256:f0d6ec03875f96df45aa13e21fd9b8450c42d7e1830418cccc008c0df725fcee"}, + {file = "nbconvert-5.6.1.tar.gz", hash = "sha256:21fb48e700b43e82ba0e3142421a659d7739b65568cc832a13976a77be16b523"}, +] +nbformat = [ + {file = "nbformat-5.0.7-py3-none-any.whl", hash = "sha256:ea55c9b817855e2dfcd3f66d74857342612a60b1f09653440f4a5845e6e3523f"}, + {file = "nbformat-5.0.7.tar.gz", hash = "sha256:54d4d6354835a936bad7e8182dcd003ca3dc0cedfee5a306090e04854343b340"}, +] +notebook = [ + {file = "notebook-6.0.3-py3-none-any.whl", hash = "sha256:3edc616c684214292994a3af05eaea4cc043f6b4247d830f3a2f209fa7639a80"}, + {file = "notebook-6.0.3.tar.gz", hash = "sha256:47a9092975c9e7965ada00b9a20f0cf637d001db60d241d479f53c0be117ad48"}, +] +numpy = [ + {file = "numpy-1.19.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:63d971bb211ad3ca37b2adecdd5365f40f3b741a455beecba70fd0dde8b2a4cb"}, + {file = "numpy-1.19.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b6aaeadf1e4866ca0fdf7bb4eed25e521ae21a7947c59f78154b24fc7abbe1dd"}, + {file = "numpy-1.19.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:13af0184177469192d80db9bd02619f6fa8b922f9f327e077d6f2a6acb1ce1c0"}, + {file = "numpy-1.19.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:356f96c9fbec59974a592452ab6a036cd6f180822a60b529a975c9467fcd5f23"}, + {file = "numpy-1.19.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa1fe75b4a9e18b66ae7f0b122543c42debcf800aaafa0212aaff3ad273c2596"}, + {file = "numpy-1.19.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:cbe326f6d364375a8e5a8ccb7e9cd73f4b2f6dc3b2ed205633a0db8243e2a96a"}, + {file = "numpy-1.19.0-cp36-cp36m-win32.whl", hash = "sha256:a2e3a39f43f0ce95204beb8fe0831199542ccab1e0c6e486a0b4947256215632"}, + {file = "numpy-1.19.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7b852817800eb02e109ae4a9cef2beda8dd50d98b76b6cfb7b5c0099d27b52d4"}, + {file = "numpy-1.19.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d97a86937cf9970453c3b62abb55a6475f173347b4cde7f8dcdb48c8e1b9952d"}, + {file = "numpy-1.19.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a86c962e211f37edd61d6e11bb4df7eddc4a519a38a856e20a6498c319efa6b0"}, + {file = "numpy-1.19.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d34fbb98ad0d6b563b95de852a284074514331e6b9da0a9fc894fb1cdae7a79e"}, + {file = "numpy-1.19.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:658624a11f6e1c252b2cd170d94bf28c8f9410acab9f2fd4369e11e1cd4e1aaf"}, + {file = "numpy-1.19.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:4d054f013a1983551254e2379385e359884e5af105e3efe00418977d02f634a7"}, + {file = "numpy-1.19.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:26a45798ca2a4e168d00de75d4a524abf5907949231512f372b217ede3429e98"}, + {file = "numpy-1.19.0-cp37-cp37m-win32.whl", hash = "sha256:3c40c827d36c6d1c3cf413694d7dc843d50997ebffbc7c87d888a203ed6403a7"}, + {file = "numpy-1.19.0-cp37-cp37m-win_amd64.whl", hash = "sha256:be62aeff8f2f054eff7725f502f6228298891fd648dc2630e03e44bf63e8cee0"}, + {file = "numpy-1.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dd53d7c4a69e766e4900f29db5872f5824a06827d594427cf1a4aa542818b796"}, + {file = "numpy-1.19.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:30a59fb41bb6b8c465ab50d60a1b298d1cd7b85274e71f38af5a75d6c475d2d2"}, + {file = "numpy-1.19.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:df1889701e2dfd8ba4dc9b1a010f0a60950077fb5242bb92c8b5c7f1a6f2668a"}, + {file = "numpy-1.19.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:33c623ef9ca5e19e05991f127c1be5aeb1ab5cdf30cb1c5cf3960752e58b599b"}, + {file = "numpy-1.19.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:26f509450db547e4dfa3ec739419b31edad646d21fb8d0ed0734188b35ff6b27"}, + {file = "numpy-1.19.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7b57f26e5e6ee2f14f960db46bd58ffdca25ca06dd997729b1b179fddd35f5a3"}, + {file = "numpy-1.19.0-cp38-cp38-win32.whl", hash = "sha256:a8705c5073fe3fcc297fb8e0b31aa794e05af6a329e81b7ca4ffecab7f2b95ef"}, + {file = "numpy-1.19.0-cp38-cp38-win_amd64.whl", hash = "sha256:c2edbb783c841e36ca0fa159f0ae97a88ce8137fb3a6cd82eae77349ba4b607b"}, + {file = "numpy-1.19.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:8cde829f14bd38f6da7b2954be0f2837043e8b8d7a9110ec5e318ae6bf706610"}, + {file = "numpy-1.19.0.zip", hash = "sha256:76766cc80d6128750075378d3bb7812cf146415bd29b588616f72c943c00d598"}, +] +packaging = [ + {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, + {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, +] +pandas = [ + {file = "pandas-1.0.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:faa42a78d1350b02a7d2f0dbe3c80791cf785663d6997891549d0f86dc49125e"}, + {file = "pandas-1.0.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9c31d52f1a7dd2bb4681d9f62646c7aa554f19e8e9addc17e8b1b20011d7522d"}, + {file = "pandas-1.0.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8778a5cc5a8437a561e3276b85367412e10ae9fff07db1eed986e427d9a674f8"}, + {file = "pandas-1.0.5-cp36-cp36m-win32.whl", hash = "sha256:9871ef5ee17f388f1cb35f76dc6106d40cb8165c562d573470672f4cdefa59ef"}, + {file = "pandas-1.0.5-cp36-cp36m-win_amd64.whl", hash = "sha256:35b670b0abcfed7cad76f2834041dcf7ae47fd9b22b63622d67cdc933d79f453"}, + {file = "pandas-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c9410ce8a3dee77653bc0684cfa1535a7f9c291663bd7ad79e39f5ab58f67ab3"}, + {file = "pandas-1.0.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:02f1e8f71cd994ed7fcb9a35b6ddddeb4314822a0e09a9c5b2d278f8cb5d4096"}, + {file = "pandas-1.0.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:b3c4f93fcb6e97d993bf87cdd917883b7dab7d20c627699f360a8fb49e9e0b91"}, + {file = "pandas-1.0.5-cp37-cp37m-win32.whl", hash = "sha256:5759edf0b686b6f25a5d4a447ea588983a33afc8a0081a0954184a4a87fd0dd7"}, + {file = "pandas-1.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:ab8173a8efe5418bbe50e43f321994ac6673afc5c7c4839014cf6401bbdd0705"}, + {file = "pandas-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:13f75fb18486759da3ff40f5345d9dd20e7d78f2a39c5884d013456cec9876f0"}, + {file = "pandas-1.0.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5a7cf6044467c1356b2b49ef69e50bf4d231e773c3ca0558807cdba56b76820b"}, + {file = "pandas-1.0.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ae961f1f0e270f1e4e2273f6a539b2ea33248e0e3a11ffb479d757918a5e03a9"}, + {file = "pandas-1.0.5-cp38-cp38-win32.whl", hash = "sha256:f69e0f7b7c09f1f612b1f8f59e2df72faa8a6b41c5a436dde5b615aaf948f107"}, + {file = "pandas-1.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:4c73f373b0800eb3062ffd13d4a7a2a6d522792fa6eb204d67a4fad0a40f03dc"}, + {file = "pandas-1.0.5.tar.gz", hash = "sha256:69c5d920a0b2a9838e677f78f4dde506b95ea8e4d30da25859db6469ded84fa8"}, +] +pandocfilters = [ + {file = "pandocfilters-1.4.2.tar.gz", hash = "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"}, +] +parso = [ + {file = "parso-0.7.0-py2.py3-none-any.whl", hash = "sha256:158c140fc04112dc45bca311633ae5033c2c2a7b732fa33d0955bad8152a8dd0"}, + {file = "parso-0.7.0.tar.gz", hash = "sha256:908e9fae2144a076d72ae4e25539143d40b8e3eafbaeae03c1bfe226f4cdf12c"}, +] +pathspec = [ + {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, + {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, +] +pexpect = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] +pickleshare = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] +pluggy = [ + {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, + {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +] +prometheus-client = [ + {file = "prometheus_client-0.8.0-py2.py3-none-any.whl", hash = "sha256:983c7ac4b47478720db338f1491ef67a100b474e3bc7dafcbaefb7d0b8f9b01c"}, + {file = "prometheus_client-0.8.0.tar.gz", hash = "sha256:c6e6b706833a6bd1fd51711299edee907857be10ece535126a158f911ee80915"}, +] +prompt-toolkit = [ + {file = "prompt_toolkit-3.0.5-py3-none-any.whl", hash = "sha256:df7e9e63aea609b1da3a65641ceaf5bc7d05e0a04de5bd45d05dbeffbabf9e04"}, + {file = "prompt_toolkit-3.0.5.tar.gz", hash = "sha256:563d1a4140b63ff9dd587bda9557cffb2fe73650205ab6f4383092fb882e7dc8"}, +] +ptyprocess = [ + {file = "ptyprocess-0.6.0-py2.py3-none-any.whl", hash = "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"}, + {file = "ptyprocess-0.6.0.tar.gz", hash = "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0"}, +] +py = [ + {file = "py-1.8.2-py2.py3-none-any.whl", hash = "sha256:a673fa23d7000440cc885c17dbd34fafcb7d7a6e230b29f6766400de36a33c44"}, + {file = "py-1.8.2.tar.gz", hash = "sha256:f3b3a4c36512a4c4f024041ab51866f11761cc169670204b235f6b20523d4e6b"}, +] +pygments = [ + {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, + {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +pyrsistent = [ + {file = "pyrsistent-0.16.0.tar.gz", hash = "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"}, +] +pytest = [ + {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, + {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, +] +pytest-cov = [ + {file = "pytest-cov-2.10.0.tar.gz", hash = "sha256:1a629dc9f48e53512fcbfda6b07de490c374b0c83c55ff7a1720b3fccff0ac87"}, + {file = "pytest_cov-2.10.0-py2.py3-none-any.whl", hash = "sha256:6e6d18092dce6fad667cd7020deed816f858ad3b49d5b5e2b1cc1c97a4dba65c"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, + {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, +] +pytz = [ + {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, + {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, +] +pywin32 = [ + {file = "pywin32-228-cp27-cp27m-win32.whl", hash = "sha256:37dc9935f6a383cc744315ae0c2882ba1768d9b06700a70f35dc1ce73cd4ba9c"}, + {file = "pywin32-228-cp27-cp27m-win_amd64.whl", hash = "sha256:11cb6610efc2f078c9e6d8f5d0f957620c333f4b23466931a247fb945ed35e89"}, + {file = "pywin32-228-cp35-cp35m-win32.whl", hash = "sha256:1f45db18af5d36195447b2cffacd182fe2d296849ba0aecdab24d3852fbf3f80"}, + {file = "pywin32-228-cp35-cp35m-win_amd64.whl", hash = "sha256:6e38c44097a834a4707c1b63efa9c2435f5a42afabff634a17f563bc478dfcc8"}, + {file = "pywin32-228-cp36-cp36m-win32.whl", hash = "sha256:ec16d44b49b5f34e99eb97cf270806fdc560dff6f84d281eb2fcb89a014a56a9"}, + {file = "pywin32-228-cp36-cp36m-win_amd64.whl", hash = "sha256:a60d795c6590a5b6baeacd16c583d91cce8038f959bd80c53bd9a68f40130f2d"}, + {file = "pywin32-228-cp37-cp37m-win32.whl", hash = "sha256:af40887b6fc200eafe4d7742c48417529a8702dcc1a60bf89eee152d1d11209f"}, + {file = "pywin32-228-cp37-cp37m-win_amd64.whl", hash = "sha256:00eaf43dbd05ba6a9b0080c77e161e0b7a601f9a3f660727a952e40140537de7"}, + {file = "pywin32-228-cp38-cp38-win32.whl", hash = "sha256:fa6ba028909cfc64ce9e24bcf22f588b14871980d9787f1e2002c99af8f1850c"}, + {file = "pywin32-228-cp38-cp38-win_amd64.whl", hash = "sha256:9b3466083f8271e1a5eb0329f4e0d61925d46b40b195a33413e0905dccb285e8"}, + {file = "pywin32-228-cp39-cp39-win32.whl", hash = "sha256:ed74b72d8059a6606f64842e7917aeee99159ebd6b8d6261c518d002837be298"}, + {file = "pywin32-228-cp39-cp39-win_amd64.whl", hash = "sha256:8319bafdcd90b7202c50d6014efdfe4fde9311b3ff15fd6f893a45c0868de203"}, +] +pywinpty = [ + {file = "pywinpty-0.5.7-cp27-cp27m-win32.whl", hash = "sha256:b358cb552c0f6baf790de375fab96524a0498c9df83489b8c23f7f08795e966b"}, + {file = "pywinpty-0.5.7-cp27-cp27m-win_amd64.whl", hash = "sha256:1e525a4de05e72016a7af27836d512db67d06a015aeaf2fa0180f8e6a039b3c2"}, + {file = "pywinpty-0.5.7-cp35-cp35m-win32.whl", hash = "sha256:2740eeeb59297593a0d3f762269b01d0285c1b829d6827445fcd348fb47f7e70"}, + {file = "pywinpty-0.5.7-cp35-cp35m-win_amd64.whl", hash = "sha256:33df97f79843b2b8b8bc5c7aaf54adec08cc1bae94ee99dfb1a93c7a67704d95"}, + {file = "pywinpty-0.5.7-cp36-cp36m-win32.whl", hash = "sha256:e854211df55d107f0edfda8a80b39dfc87015bef52a8fe6594eb379240d81df2"}, + {file = "pywinpty-0.5.7-cp36-cp36m-win_amd64.whl", hash = "sha256:dbd838de92de1d4ebf0dce9d4d5e4fc38d0b7b1de837947a18b57a882f219139"}, + {file = "pywinpty-0.5.7-cp37-cp37m-win32.whl", hash = "sha256:5fb2c6c6819491b216f78acc2c521b9df21e0f53b9a399d58a5c151a3c4e2a2d"}, + {file = "pywinpty-0.5.7-cp37-cp37m-win_amd64.whl", hash = "sha256:dd22c8efacf600730abe4a46c1388355ce0d4ab75dc79b15d23a7bd87bf05b48"}, + {file = "pywinpty-0.5.7-cp38-cp38-win_amd64.whl", hash = "sha256:8fc5019ff3efb4f13708bd3b5ad327589c1a554cb516d792527361525a7cb78c"}, + {file = "pywinpty-0.5.7.tar.gz", hash = "sha256:2d7e9c881638a72ffdca3f5417dd1563b60f603e1b43e5895674c2a1b01f95a0"}, +] +pyzmq = [ + {file = "pyzmq-19.0.1-cp27-cp27m-macosx_10_9_intel.whl", hash = "sha256:58688a2dfa044fad608a8e70ba8d019d0b872ec2acd75b7b5e37da8905605891"}, + {file = "pyzmq-19.0.1-cp27-cp27m-win32.whl", hash = "sha256:87c78f6936e2654397ca2979c1d323ee4a889eef536cc77a938c6b5be33351a7"}, + {file = "pyzmq-19.0.1-cp27-cp27m-win_amd64.whl", hash = "sha256:97b6255ae77328d0e80593681826a0479cb7bac0ba8251b4dd882f5145a2293a"}, + {file = "pyzmq-19.0.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:15b4cb21118f4589c4db8be4ac12b21c8b4d0d42b3ee435d47f686c32fe2e91f"}, + {file = "pyzmq-19.0.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:931339ac2000d12fe212e64f98ce291e81a7ec6c73b125f17cf08415b753c087"}, + {file = "pyzmq-19.0.1-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:2a88b8fabd9cc35bd59194a7723f3122166811ece8b74018147a4ed8489e6421"}, + {file = "pyzmq-19.0.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:bafd651b557dd81d89bd5f9c678872f3e7b7255c1c751b78d520df2caac80230"}, + {file = "pyzmq-19.0.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8952f6ba6ae598e792703f3134af5a01af8f5c7cf07e9a148f05a12b02412cea"}, + {file = "pyzmq-19.0.1-cp35-cp35m-win32.whl", hash = "sha256:54aa24fd60c4262286fc64ca632f9e747c7cc3a3a1144827490e1dc9b8a3a960"}, + {file = "pyzmq-19.0.1-cp35-cp35m-win_amd64.whl", hash = "sha256:dcbc3f30c11c60d709c30a213dc56e88ac016fe76ac6768e64717bd976072566"}, + {file = "pyzmq-19.0.1-cp36-cp36m-macosx_10_9_intel.whl", hash = "sha256:6ca519309703e95d55965735a667809bbb65f52beda2fdb6312385d3e7a6d234"}, + {file = "pyzmq-19.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4ee0bfd82077a3ff11c985369529b12853a4064320523f8e5079b630f9551448"}, + {file = "pyzmq-19.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ba6f24431b569aec674ede49cad197cad59571c12deed6ad8e3c596da8288217"}, + {file = "pyzmq-19.0.1-cp36-cp36m-win32.whl", hash = "sha256:956775444d01331c7eb412c5fb9bb62130dfaac77e09f32764ea1865234e2ca9"}, + {file = "pyzmq-19.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b08780e3a55215873b3b8e6e7ca8987f14c902a24b6ac081b344fd430d6ca7cd"}, + {file = "pyzmq-19.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:21f7d91f3536f480cb2c10d0756bfa717927090b7fb863e6323f766e5461ee1c"}, + {file = "pyzmq-19.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:bfff5ffff051f5aa47ba3b379d87bd051c3196b0c8a603e8b7ed68a6b4f217ec"}, + {file = "pyzmq-19.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:07fb8fe6826a229dada876956590135871de60dbc7de5a18c3bcce2ed1f03c98"}, + {file = "pyzmq-19.0.1-cp37-cp37m-win32.whl", hash = "sha256:342fb8a1dddc569bc361387782e8088071593e7eaf3e3ecf7d6bd4976edff112"}, + {file = "pyzmq-19.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:faee2604f279d31312bc455f3d024f160b6168b9c1dde22bf62d8c88a4deca8e"}, + {file = "pyzmq-19.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b9d21fc56c8aacd2e6d14738021a9d64f3f69b30578a99325a728e38a349f85"}, + {file = "pyzmq-19.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:af0c02cf49f4f9eedf38edb4f3b6bb621d83026e7e5d76eb5526cc5333782fd6"}, + {file = "pyzmq-19.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5f1f2eb22aab606f808163eb1d537ac9a0ba4283fbeb7a62eb48d9103cf015c2"}, + {file = "pyzmq-19.0.1-cp38-cp38-win32.whl", hash = "sha256:f9d7e742fb0196992477415bb34366c12e9bb9a0699b8b3f221ff93b213d7bec"}, + {file = "pyzmq-19.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:5b99c2ae8089ef50223c28bac57510c163bfdff158c9e90764f812b94e69a0e6"}, + {file = "pyzmq-19.0.1-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:cf5d689ba9513b9753959164cf500079383bc18859f58bf8ce06d8d4bef2b054"}, + {file = "pyzmq-19.0.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:aaa8b40b676576fd7806839a5de8e6d5d1b74981e6376d862af6c117af2a3c10"}, + {file = "pyzmq-19.0.1.tar.gz", hash = "sha256:13a5638ab24d628a6ade8f794195e1a1acd573496c3b85af2f1183603b7bf5e0"}, +] +qtconsole = [ + {file = "qtconsole-4.7.4-py2.py3-none-any.whl", hash = "sha256:89442727940126c65c2f94a058f1b4693a0f5d4c4b192fd6518ba3b11f4791aa"}, + {file = "qtconsole-4.7.4.tar.gz", hash = "sha256:fd48bf1051d6e69cec1f9e2596cfaa94e3c726c70c5d848681ebce10c029f5fd"}, +] +qtpy = [ + {file = "QtPy-1.9.0-py2.py3-none-any.whl", hash = "sha256:fa0b8363b363e89b2a6f49eddc162a04c0699ae95e109a6be3bb145a913190ea"}, + {file = "QtPy-1.9.0.tar.gz", hash = "sha256:2db72c44b55d0fe1407be8fba35c838ad0d6d3bb81f23007886dc1fc0f459c8d"}, +] +regex = [ + {file = "regex-2020.6.8-cp27-cp27m-win32.whl", hash = "sha256:fbff901c54c22425a5b809b914a3bfaf4b9570eee0e5ce8186ac71eb2025191c"}, + {file = "regex-2020.6.8-cp27-cp27m-win_amd64.whl", hash = "sha256:112e34adf95e45158c597feea65d06a8124898bdeac975c9087fe71b572bd938"}, + {file = "regex-2020.6.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:92d8a043a4241a710c1cf7593f5577fbb832cf6c3a00ff3fc1ff2052aff5dd89"}, + {file = "regex-2020.6.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bae83f2a56ab30d5353b47f9b2a33e4aac4de9401fb582b55c42b132a8ac3868"}, + {file = "regex-2020.6.8-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b2ba0f78b3ef375114856cbdaa30559914d081c416b431f2437f83ce4f8b7f2f"}, + {file = "regex-2020.6.8-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:95fa7726d073c87141f7bbfb04c284901f8328e2d430eeb71b8ffdd5742a5ded"}, + {file = "regex-2020.6.8-cp36-cp36m-win32.whl", hash = "sha256:e3cdc9423808f7e1bb9c2e0bdb1c9dc37b0607b30d646ff6faf0d4e41ee8fee3"}, + {file = "regex-2020.6.8-cp36-cp36m-win_amd64.whl", hash = "sha256:c78e66a922de1c95a208e4ec02e2e5cf0bb83a36ceececc10a72841e53fbf2bd"}, + {file = "regex-2020.6.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:08997a37b221a3e27d68ffb601e45abfb0093d39ee770e4257bd2f5115e8cb0a"}, + {file = "regex-2020.6.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2f6f211633ee8d3f7706953e9d3edc7ce63a1d6aad0be5dcee1ece127eea13ae"}, + {file = "regex-2020.6.8-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:55b4c25cbb3b29f8d5e63aeed27b49fa0f8476b0d4e1b3171d85db891938cc3a"}, + {file = "regex-2020.6.8-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:89cda1a5d3e33ec9e231ece7307afc101b5217523d55ef4dc7fb2abd6de71ba3"}, + {file = "regex-2020.6.8-cp37-cp37m-win32.whl", hash = "sha256:690f858d9a94d903cf5cada62ce069b5d93b313d7d05456dbcd99420856562d9"}, + {file = "regex-2020.6.8-cp37-cp37m-win_amd64.whl", hash = "sha256:1700419d8a18c26ff396b3b06ace315b5f2a6e780dad387e4c48717a12a22c29"}, + {file = "regex-2020.6.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:654cb773b2792e50151f0e22be0f2b6e1c3a04c5328ff1d9d59c0398d37ef610"}, + {file = "regex-2020.6.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:52e1b4bef02f4040b2fd547357a170fc1146e60ab310cdbdd098db86e929b387"}, + {file = "regex-2020.6.8-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:cf59bbf282b627130f5ba68b7fa3abdb96372b24b66bdf72a4920e8153fc7910"}, + {file = "regex-2020.6.8-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5aaa5928b039ae440d775acea11d01e42ff26e1561c0ffcd3d805750973c6baf"}, + {file = "regex-2020.6.8-cp38-cp38-win32.whl", hash = "sha256:97712e0d0af05febd8ab63d2ef0ab2d0cd9deddf4476f7aa153f76feef4b2754"}, + {file = "regex-2020.6.8-cp38-cp38-win_amd64.whl", hash = "sha256:6ad8663c17db4c5ef438141f99e291c4d4edfeaacc0ce28b5bba2b0bf273d9b5"}, + {file = "regex-2020.6.8.tar.gz", hash = "sha256:e9b64e609d37438f7d6e68c2546d2cb8062f3adb27e6336bc129b51be20773ac"}, +] +requests = [ + {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, + {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"}, +] +send2trash = [ + {file = "Send2Trash-1.5.0-py3-none-any.whl", hash = "sha256:f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b"}, + {file = "Send2Trash-1.5.0.tar.gz", hash = "sha256:60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2"}, +] +six = [ + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, +] +soupsieve = [ + {file = "soupsieve-1.9.6-py2.py3-none-any.whl", hash = "sha256:feb1e937fa26a69e08436aad4a9037cd7e1d4c7212909502ba30701247ff8abd"}, + {file = "soupsieve-1.9.6.tar.gz", hash = "sha256:7985bacc98c34923a439967c1a602dc4f1e15f923b6fcf02344184f86cc7efaa"}, +] +terminado = [ + {file = "terminado-0.8.3-py2.py3-none-any.whl", hash = "sha256:a43dcb3e353bc680dd0783b1d9c3fc28d529f190bc54ba9a229f72fe6e7a54d7"}, + {file = "terminado-0.8.3.tar.gz", hash = "sha256:4804a774f802306a7d9af7322193c5390f1da0abb429e082a10ef1d46e6fb2c2"}, +] +testpath = [ + {file = "testpath-0.4.4-py2.py3-none-any.whl", hash = "sha256:bfcf9411ef4bf3db7579063e0546938b1edda3d69f4e1fb8756991f5951f85d4"}, + {file = "testpath-0.4.4.tar.gz", hash = "sha256:60e0a3261c149755f4399a1fff7d37523179a70fdc3abdf78de9fc2604aeec7e"}, +] +toml = [ + {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, + {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, +] +tornado = [ + {file = "tornado-6.0.4-cp35-cp35m-win32.whl", hash = "sha256:5217e601700f24e966ddab689f90b7ea4bd91ff3357c3600fa1045e26d68e55d"}, + {file = "tornado-6.0.4-cp35-cp35m-win_amd64.whl", hash = "sha256:c98232a3ac391f5faea6821b53db8db461157baa788f5d6222a193e9456e1740"}, + {file = "tornado-6.0.4-cp36-cp36m-win32.whl", hash = "sha256:5f6a07e62e799be5d2330e68d808c8ac41d4a259b9cea61da4101b83cb5dc673"}, + {file = "tornado-6.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c952975c8ba74f546ae6de2e226ab3cc3cc11ae47baf607459a6728585bb542a"}, + {file = "tornado-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:2c027eb2a393d964b22b5c154d1a23a5f8727db6fda837118a776b29e2b8ebc6"}, + {file = "tornado-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:5618f72e947533832cbc3dec54e1dffc1747a5cb17d1fd91577ed14fa0dc081b"}, + {file = "tornado-6.0.4-cp38-cp38-win32.whl", hash = "sha256:22aed82c2ea340c3771e3babc5ef220272f6fd06b5108a53b4976d0d722bcd52"}, + {file = "tornado-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c58d56003daf1b616336781b26d184023ea4af13ae143d9dda65e31e534940b9"}, + {file = "tornado-6.0.4.tar.gz", hash = "sha256:0fe2d45ba43b00a41cd73f8be321a44936dc1aba233dee979f17a042b83eb6dc"}, +] +traitlets = [ + {file = "traitlets-4.3.3-py2.py3-none-any.whl", hash = "sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44"}, + {file = "traitlets-4.3.3.tar.gz", hash = "sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7"}, +] +typed-ast = [ + {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, + {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, + {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, + {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, + {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, + {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, + {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, + {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, + {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, + {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, + {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, + {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, + {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, + {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, + {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, + {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, + {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, + {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, + {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, + {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, + {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, +] +typing-extensions = [ + {file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"}, + {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"}, + {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, +] +urllib3 = [ + {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, + {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, +] +wcwidth = [ + {file = "wcwidth-0.2.4-py2.py3-none-any.whl", hash = "sha256:79375666b9954d4a1a10739315816324c3e73110af9d0e102d906fdb0aec009f"}, + {file = "wcwidth-0.2.4.tar.gz", hash = "sha256:8c6b5b6ee1360b842645f336d9e5d68c55817c26d3050f46b235ef2bc650e48f"}, +] +webencodings = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] +widgetsnbextension = [ + {file = "widgetsnbextension-3.5.1-py2.py3-none-any.whl", hash = "sha256:bd314f8ceb488571a5ffea6cc5b9fc6cba0adaf88a9d2386b93a489751938bcd"}, + {file = "widgetsnbextension-3.5.1.tar.gz", hash = "sha256:079f87d87270bce047512400efd70238820751a11d2d8cb137a5a5bdbaf255c7"}, +] +zipp = [ + {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, + {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, +] diff --git a/dabbling/pyproject.toml b/dabbling/pyproject.toml @@ -0,0 +1,32 @@ +[tool.poetry] +name = "dabbling" +version = "0.1.0" +description = "" +authors = ["Yuval Langer"] +license = "agpl-3.0-or-later" + +[tool.poetry.dependencies] +python = ">=3.6.1,<4" +beautifulsoup4 = ">=4,<5" +jupyter = ">=1,<2" +matplotlib = ">=3.2,<4" +#manimlib = ">=0.1,<0.2" +requests = ">=2,<3" +pandas = ">=1,<2" +click = "^7.1" + +[tool.poetry.dev-dependencies] +pytest = "^" +mypy = "^0.780" +coverage = {extras = ["toml"], version = "^5.1"} +pytest-cov = "^2.9.0" +black = "^19.10b0" + +[tool.poetry.scripts] +dragon-curve = "src.dabbling.console:main_dragon" +hilbert-curve = "src.dabbling.console:main_hilbert" + +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" + diff --git a/dabbling/src/dabbling/WTC_plaza_2001-09-11.py b/dabbling/src/dabbling/WTC_plaza_2001-09-11.py @@ -0,0 +1,178 @@ +import math +import random +from subprocess import Popen + +import cv2 +import numpy as np + + +BLOOD_COLOR = (0, 0, 255, 255) +STICK_FIGURE_COLOR = (0, 0, 0, 255) + + +def make_random_direction_exp(): + return math.e ** (1j * math.tau * random.random()) + + +def make_random_direction_sin_cos(): + uniform = random.random() + return complex( + cos(math.tau * uniform), + math.sin(math.tau * uniform), + ) + + +def make_random_stick_figure_positions(): + head_neck_distance = 0.05 + elbow_neck_distance = arm_tip_elbow_distance = 0.1 + pelvis_neck_distance = 0.15 + knee_pelvis_distance = 0.1 + leg_tip_knee_distance = 0.1 + + head_position = random.random() + random.random() * 1j + + neck_position = head_position + head_neck_distance * math.e ** ( + math.tau * 1j * random.random() + ) + + left_elbow_position = neck_position + elbow_neck_distance * math.e ** ( + math.tau * 1j * random.random() + ) + right_elbow_position = neck_position + elbow_neck_distance * math.e ** ( + math.tau * 1j * random.random() + ) + + left_arm_tip_position = left_elbow_position + arm_tip_elbow_distance * math.e ** ( + math.tau * 1j * random.random() + ) + right_arm_tip_position = right_elbow_position + arm_tip_elbow_distance * math.e ** ( + math.tau * 1j * random.random() + ) + + pelvis_position = neck_position + pelvis_neck_distance * math.e ** ( + math.tau * 1j * random.random() + ) + + left_knee_position = pelvis_position + knee_pelvis_distance * math.e ** ( + math.tau * 1j * random.random() + ) + right_knee_position = pelvis_position + knee_pelvis_distance * math.e ** ( + math.tau * 1j * random.random() + ) + + left_leg_top_position = left_knee_position + leg_tip_knee_distance * math.e ** ( + math.tau * 1j * random.random() + ) + right_leg_top_position = right_knee_position + leg_tip_knee_distance * math.e ** ( + math.tau * 1j * random.random() + ) + + return [ + (x.real, x.imag) + for x in ( + head_position, + neck_position, + left_elbow_position, + right_elbow_position, + left_arm_tip_position, + right_arm_tip_position, + pelvis_position, + left_knee_position, + right_knee_position, + left_leg_top_position, + right_leg_top_position, + ) + ] + + +def make_blood_splatter_positions(stick_figure_positions): + return [ + (x.real, x.imag) + for x in [ + complex(*stick_figure_positions[1]) + + 0.05 * i * math.e ** (math.tau * 1j * random.random()) + for i in range(3) + ] + [ + complex(*stick_figure_positions[6]) + + 0.05 * i * math.e ** (math.tau * 1j * random.random()) + for i in range(3) + ]] + + +def draw_blood_splatter(image, blood_splatter_positions): + image_height, image_width = image.shape[:2] + + blood_splatter_positions = [ + (int(x * image_width), int(y * image_height)) + for x, y in blood_splatter_positions + ] + + + cv2.circle(image, blood_splatter_positions[0], 20, BLOOD_COLOR, -1) + cv2.circle(image, blood_splatter_positions[1], 10, BLOOD_COLOR, -1) + cv2.circle(image, blood_splatter_positions[2], 5, BLOOD_COLOR, -1) + + cv2.circle(image, blood_splatter_positions[3], 20, BLOOD_COLOR, -1) + cv2.circle(image, blood_splatter_positions[4], 10, BLOOD_COLOR, -1) + cv2.circle(image, blood_splatter_positions[5], 5, BLOOD_COLOR, -1) + + +def draw_stick_figure(image, stick_figure_positions): + # https://docs.opencv.org/4.x/d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2 + # https://docs.opencv.org/4.x/dc/da5/tutorial_py_drawing_functions.html + + image_height, image_width = image.shape[:2] + + stick_figure_positions = [ + (int(x * image_width), int(y * image_height)) for x, y in stick_figure_positions + ] + + # create blank image + + cv2.circle(image, stick_figure_positions[0], 15, STICK_FIGURE_COLOR, -1) + + for index_a, index_b in [ + (0, 1), + (1, 2), + (1, 3), + (2, 4), + (3, 5), + (1, 6), + (7, 6), + (8, 6), + (7, 9), + (8, 10), + ]: + cv2.line( + image, + stick_figure_positions[index_a], + stick_figure_positions[index_b], + STICK_FIGURE_COLOR, + 5, + ) + + +def main(): + random.seed(0) + + image_width, image_height = 500, 500 + + image = 255 * np.ones(shape=[image_width, image_height, 4], dtype=np.uint8) + + for i in range(100): + stick_figure_positions = make_random_stick_figure_positions() + + blood_splatter_positions = make_blood_splatter_positions(stick_figure_positions) + + draw_blood_splatter(image, blood_splatter_positions) + + draw_stick_figure(image, stick_figure_positions) + + cv2.imwrite(f"prakdan_{i:02d}.png", image) + + convert_process = Popen(['convert', 'prakdan_*.png', 'prakdan.gif']) + + convert_process.wait() + +if __name__ == "__main__": + main() diff --git a/dabbling/src/dabbling/__init__.py b/dabbling/src/dabbling/__init__.py @@ -0,0 +1 @@ +__version__ = '0.1.0' diff --git a/dabbling/src/dabbling/console.py b/dabbling/src/dabbling/console.py @@ -0,0 +1,49 @@ +import click + +from . import __version__ +from .dragon_curve import dragon_curve, path_to_curvy_svg_no_clue, path_to_svg_file_content, write_matplotlib_png +from .hilbert_curve import hilbert_curve, make_svg_content + + +@click.command() +@click.option( + '--iterations', + '-n', + default='5', + help='Number of iterations', + metavar='ITERS', + show_default=True, +) +@click.version_option(version=__version__) +def main_dragon(iterations: str): + l = dragon_curve(int(iterations)) + + svg_content = path_to_svg_file_content(l) + with open('dragon-curve.svg', 'w') as f: + f.write(svg_content) + + svg_content = path_to_curvy_svg_no_clue(l) + with open('dragon-curvy-no-clue.svg', 'w') as f: + f.write(svg_content) + + write_matplotlib_png(l) + + click.echo(l) + + +@click.command() +@click.option( + '--iterations', + '-n', + default='5', + help='Number of iterations', + metavar='ITERS', + show_default=True, +) +@click.version_option(version=__version__) +def main_hilbert(iterations: str): + l = hilbert_curve(int(iterations)) + + svg_content = make_svg_content(l) + with open('hilbert-curve.svg', 'w') as f: + f.write(svg_content) diff --git a/dabbling/src/dabbling/dragon_curve.py b/dabbling/src/dabbling/dragon_curve.py @@ -0,0 +1,114 @@ +__version__ = '0.1.0' + + +from typing import List, Tuple + + +PathType = List[Tuple[int, int]] + + +def ccw(p: Tuple[int, int]) -> Tuple[int, int]: + return [-p[1], p[0]] + + +def dragon_curve(generation_number: int) -> PathType: + l = [[0, 0], [1, 0]] + + for i in range(generation_number): + new_portion = [ccw(n) for n in l[1:]] + new_pivot = new_portion[-1] + l = new_portion[::-1] + l + l = [ + [n[0] - new_pivot[0], + n[1] - new_pivot[1]] + for n in l] + + return l + + +def write_matplotlib_png(dragon_curve_path: PathType): + import matplotlib.pyplot as plt + + plt.scatter( + [n[0] for n in dragon_curve_path], + [n[1] for n in dragon_curve_path]) + plt.show() + plt.savefig('dragon-curve.png') + + +def transform(values, low, high): + min_value = min(values) + max_value = max(values) + old_difference = max_value - min_value + new_difference = high - low + # values = [n - min_value for n in values] # [0, max-min = old_difference] + # values = [n / old_difference for n in values] # [0, 1] + # values = [n * new_difference for n in values] # [0, new_difference = high - low] + # values = [n + low for n in values] # [low, high] + return [(n - min_value) * new_difference / old_difference + low + for n in values] + + +def path_to_svg_file_content( + path: PathType, + image_width=500, + image_height=500, + left_border=50, + right_border=50, + bottom_border=50, + top_border=50, + ) -> str: + path = list(zip( + transform([p[0] for p in path], left_border, image_width - right_border), + transform([p[1] for p in path], top_border, image_width - bottom_border))) + + svg_path = ''.join(f'L{p[0]} {p[1]}' for p in path) + + return f''' +<svg width="{image_width}" height="{image_height}" fill="white" xmlns="http://www.w3.org/2000/svg"> + + <path fill="none" stroke="black" stroke-linejoin="round" stroke-width="0.7" d="M{path[0][0]} {path[0][1]}{svg_path}"/> + +</svg> + '''.strip() + + +def path_to_curvy_svg_no_clue( + path: PathType, + image_width=500, + image_height=500, + left_border=50, + right_border=50, + bottom_border=50, + top_border=50, + ) -> str: + ''' + path = list(zip( + transform([p[0] for p in path], left_border, image_width - right_border), + transform([p[1] for p in path], top_border, image_width - bottom_border))) + ''' + + min_x = min(p[0] for p in path) + min_y = min(p[1] for p in path) + max_x = max(p[0] for p in path) + max_y = max(p[1] for p in path) + + stroke_width = (max_x - min_x) * 0.01 + + consecutives = list(zip(path[:-1], path[1:])) + + svg_path = ''.join(f'L{p[0]} {p[1]}' for p in path) + + svg_path += ( + ''.join( + f'M{pair[0][0]} {pair[0][1]}' + f'A2 2 0 0 0 {pair[1][0]} {pair[1][1]}' + for pair in consecutives)) + + return f''' +<svg width="{image_width}" height="{image_height}" viewBox="{min_x-1} {min_y-1} {max_x-min_x+1} {max_y-min_y+1}" fill="white" xmlns="http://www.w3.org/2000/svg"> + + <path fill="none" stroke="black" stroke-linejoin="round" stroke-width="{stroke_width}" d="M{path[0][0]} {path[0][1]}{svg_path}"/> + +</svg> + '''.strip() diff --git a/dabbling/src/dabbling/hilbert_curve/hilbert_curve.py b/dabbling/src/dabbling/hilbert_curve/hilbert_curve.py @@ -0,0 +1,129 @@ +def mirror_on_y(path): + max_x = max(p[0] for p in path) + return [(abs(p[0] - max_x), p[1]) for p in path] + + +def mirror_on_x(path): + max_y = max(p[1] for p in path) + return [(p[0], abs(p[1] - max_y)) for p in path] + + +def mirror_on_xy(path): + return [(p[1], p[0]) for p in path] + + +def right_flip(path): + path = mirror_on_y(path) + path = mirror_on_xy(path) + path = mirror_on_y(path) + + return path + + +def left_flip(path): + return mirror_on_xy(path) + + +def hilbert_curve(iterations): + curve_coordinates = [ + (0, 0), + (0, 1), + (1, 1), + (1, 0), + ] + + for i in range(iterations): + curve_coordinates = ( + left_flip(curve_coordinates) + + [(p[0], p[1] + 2 ** (i + 1)) for p in curve_coordinates] + + [(p[0] + 2 ** (i + 1), p[1] + 2 ** (i + 1)) for p in curve_coordinates] + + [(p[0] + 2 ** (i + 1), p[1]) for p in right_flip(curve_coordinates)] + ) + + return curve_coordinates + + +def hilbert_curve_complex(iterations): + path = [ + 0 + 0j, + 0 + 1j, + 1 + 1j, + 1 + 0j, + ] + + def lower_left(path, iteration): + path = [p * (-1j) for p in path] + path = [p.conjugate() for p in path] + return path + + def upper_left(path, iteration): + path = [p + 1j * 2**iteration for p in path] + return path + + def upper_right(path, iteration): + path = [p + (1 + 1j) * 2**iteration for p in path] + return path + + def lower_right(path, iteration): + path = [p - 1j for p in path] + path = [p.conjugate() for p in path] + path = [p * (-1j) for p in path] + path = [p + 1j for p in path] + path = [p + 2**iteration for p in path] + return path + + normalizer = 1 + for i in range(iterations): + path = ( + lower_left(path, i + 1) + + upper_left(path, i + 1) + + upper_right(path, i + 1) + + lower_right(path, i + 1) + ) + + print(path) + + normalizer *= 2**(i + 1) - 1 + + path = [p / normalizer for p in path] + + return path + + +def make_svg_content( + path, + image_width = 500, + image_height = 500, + ): + min_x = min(p[0] for p in path) + min_y = min(p[1] for p in path) + max_x = max(p[0] for p in path) + max_y = max(p[1] for p in path) + margins = ' '.join( + map( + str, + ( + min_x - 0.05 * (max_x - min_x), + min_y - 0.05 * (max_y - min_y), + max_x + 1.05 * (max_x - min_x), + max_y + 1.05 * (max_y - min_y), + ))) + path = mirror_on_x(path) + stroke_width = min(0.001 * (max_x - min_x), 0.1) + svg_path = f'M{path[0][0]} {path[0][1]}' + ''.join(f'L{p[0]} {p[1]}' for p in path[1:]) + return f''' +<svg width="{image_width}" height="{image_height}" viewBox="{margins}" fill="white" xmlns="http://www.w3.org/2000/svg"> + <path stroke="black" stroke-width="{stroke_width}" d="{svg_path}"/> +</svg>''' + + +if __name__ == '__main__': + import sys + path = hilbert_curve(int(sys.argv[1])) + svg_content = make_svg_content(path) + with open('hilbert-curve.svg', 'w') as f: + f.write(svg_content) + path = hilbert_curve_complex(int(sys.argv[1])) + svg_content = make_svg_content([(p.real, p.imag) for p in path]) + with open('hilbert-curve-complex.svg', 'w') as f: + f.write(svg_content) diff --git a/dabbling/tests/__init__.py b/dabbling/tests/__init__.py diff --git a/dabbling/tests/test_dabbling.py b/dabbling/tests/test_dabbling.py @@ -0,0 +1,5 @@ +from dabbling import __version__ + + +def test_version(): + assert __version__ == '0.1.0'