Initial commit, I guess.
20
guitar/default.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Shoofle Plays Guitar!</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="project">
|
||||
<p>I occasionally play a guitar. I'm really bad at it! But I love my guitar. My mom bought it when she was younger than I am now, and she used to play it for us when my siblings and I were children. I really adore music, but I wasn't aware of that for the longest time - and my mom gave me her guitar when I went away to college, and I've been poking at it every now and then ever since. I don't take it particularly seriously and it's just something I enjoy doing when it's beautiful outside and I can sit on my porch and just plink away.</p>
|
||||
<p>Every now and then I sit down and try (usually unsuccessfully) to learn a song from tab. Here's a list of songs!</p>
|
||||
<ul>
|
||||
{% for file in guitar_files %}
|
||||
<li><a href="{{ file }}">{{ file|replace("_", " ") }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
228
guitar/final_fantasy_vii
Normal file
@ -0,0 +1,228 @@
|
||||
http://www.gametabs.net/playstation/final-fantasy-7/main-theme
|
||||
|
||||
Main Theme
|
||||
|
||||
|
||||
Track 1
|
||||
E E E E E E E E E E E E E E E E
|
||||
E||---------------------0-----|--7-----------5-----------|
|
||||
B||---1-----------3-----------|-----5-----5-----5--------|
|
||||
G||*-----0-----0-----0-----0--|--------5-----------5-----|
|
||||
D||*--------2-----------------|-----------------------7--|
|
||||
A||---3-----------3-----------|--------------------------|
|
||||
E||---------------------------|--5-----------5-----------|
|
||||
|
||||
|
||||
E E E E E E E E E E E E E E E E
|
||||
--------------------0-----|--3-----1-----------------|
|
||||
--1-----------3-----------|-----1--------1-----3-----|
|
||||
-----0-----0-----0-----0--|-----------2-----2-----2--|
|
||||
--------2-----------------|--3-----------------------|
|
||||
--3-----------3-----------|--------------------------|
|
||||
--------------------------|--------------1-----------|
|
||||
|
||||
|
||||
E E E E E E E E E E E E E E E E
|
||||
--------------------0-----|--7-----------5-----------|
|
||||
--1-----------3-----------|-----5-----5-----5--------|
|
||||
-----0-----0-----0-----0--|--------5-----------5-----|
|
||||
--------2-----------------|-----------------------7--|
|
||||
--3-----------3-----------|--------------------------|
|
||||
--------------------------|--5-----------5-----------|
|
||||
|
||||
|
||||
E E E E E E E E E E E E E E E E
|
||||
--------------------0-----|--3-----1-----------------|
|
||||
--1-----------3-----------|-----1--------1-----3-----|
|
||||
-----0-----0-----0-----0--|-----------2-----2-----2--|
|
||||
--------2-----------------|--3-----------------------|
|
||||
--3-----------3-----------|--------------------------|
|
||||
--------------------------|--------------1-----------|
|
||||
|
||||
|
||||
|--3--| |--3--| |--3--|
|
||||
E E E E E E E E Q E E E E E E E E E
|
||||
--0-----------------------|--0----0--------3--------0--------|
|
||||
-----0-----------------0--|----------0--------0--------0-----|
|
||||
--------0-----------0-----|-------------0--------0--------0--|
|
||||
-----------2-----2--------|----------------------------------|
|
||||
--3-----------3-----------|-------3--------3-----------------|
|
||||
--------------------------|----------------------------------|
|
||||
|
||||
|
||||
|--3--| |--3--| |--3--| |--3--| |--3--|
|
||||
E E E E E E E E E E E E E E E Q Q Q
|
||||
--------------------------------------|--------------------------|
|
||||
--3-----------------3-----------------|--1--------0---------0----|
|
||||
-----3-----------3-----3-----------3--|-----0----------2---------|
|
||||
--------3-----3-----------3-----3-----|--------0-----------------|
|
||||
--1--------1-----------------1--------|--------------------------|
|
||||
--------------------------------------|--3-----------------------|
|
||||
|
||||
|
||||
E E E E E E E E E E E E E E E E
|
||||
--------------------0-----|--7-----------5-----------|
|
||||
--1-----------3-----------|-----5-----5-----5--------|
|
||||
-----0-----0-----0-----0--|--------5-----------5-----|
|
||||
--------2-----------------|-----------------------7--|
|
||||
--3-----------3-----------|--------------------------|
|
||||
--------------------------|--5-----------5-----------|
|
||||
|
||||
|
||||
E E E E E E E E E E E E E E E E
|
||||
--------------------0-----|--3-----1-----------------|
|
||||
--1-----------3-----------|-----1--------1-----3-----|
|
||||
-----0-----0-----0-----0--|-----------2-----2-----2--|
|
||||
--------2-----------------|--3-----------------------|
|
||||
--3-----------3-----------|--------------------------|
|
||||
--------------------------|--------------1-----------|
|
||||
|
||||
|
||||
E E E E E E E E E E E S S E E E E
|
||||
--------------------0-----|--7--------8p-7-5-----------|
|
||||
--1-----------3-----------|-----5--L----------5--------|
|
||||
-----0-----0-----0-----0--|--------5-------------5-----|
|
||||
--------2-----------------|-------------------------7--|
|
||||
--3-----------3-----------|----------------------------|
|
||||
--------------------------|--5-------------5-----------|
|
||||
|
||||
|
||||
E E E E E E E E E E E E E E E E
|
||||
--------------------0-----|--3-----1-----------------|
|
||||
--1-----------3-----------|-----1--------1-----3-----|
|
||||
-----0-----0-----0-----0--|-----------2-----2-----2--|
|
||||
--------2-----------------|--3-----------------------|
|
||||
--3-----------3-----------|--------------------------|
|
||||
--------------------------|--------------1-----------|
|
||||
|
||||
|
||||
|--3--| |--3--| |--3--|
|
||||
E E E E E E E E Q E E E E E E E E E
|
||||
--0-----------------------|--0----0--------3--------0--------|
|
||||
-----0-----------------0--|----------0--------0--------0-----|
|
||||
--------0-----------0-----|-------------0--------0--------0--|
|
||||
-----------2-----2--------|----------------------------------|
|
||||
--3-----------3-----------|-------3--------3-----------------|
|
||||
--------------------------|----------------------------------|
|
||||
|
||||
|
||||
|--3--| |--3--| |--3--| |--3--| |--3--|
|
||||
E E E E E E E E E E E E E E E Q Q Q
|
||||
--------------------------------------|--------------------------|
|
||||
--3-----------------3-----------------|--1--------0---------0----|
|
||||
-----3-----------3-----3-----------3--|-----0----------2---------|
|
||||
--------3-----3-----------3-----3-----|--------0-----------------|
|
||||
--1--------1-----------------1--------|--------------------------|
|
||||
--------------------------------------|--3-----------------------|
|
||||
|
||||
|
||||
^
|
||||
E E E E E E E E Q Q Q Q E E E E E E E E
|
||||
--------------------------|-------0----1----0----|--0--------0h--1-----------|
|
||||
--1-----------------------|--1-------------------|--3--3--3---------3--------|
|
||||
-----0-----------------0--|----------------------|--2------------------2-----|
|
||||
--------2-----------2-----|----------------------|--0---------------------0--|
|
||||
--3--------3-----3--------|----------------------|---------------------------|
|
||||
--------------3-----------|----------------------|---------------------------|
|
||||
|
||||
|
||||
E E E E E E E E E E E E E E E E
|
||||
--------------1-----0-----|---------0-----------------|
|
||||
-----------3-----3-----3--|--1h--3-----1-----------1--|
|
||||
--------2-----------------|---------------0-----0-----|
|
||||
-----0--------------------|------------------2--------|
|
||||
--0-----------------------|--3------------------------|
|
||||
--------------------------|---------------------------|
|
||||
|
||||
|
||||
E E E E E E E E E E E E E E E E
|
||||
--------------0-----------|--3--1h--3s--5--------------|
|
||||
-----------1-----1--------|----------------1-----------|
|
||||
--------0-----------0-----|-------------------2--------|
|
||||
-----2-----------------2--|--3-------------3-----3-----|
|
||||
--3-----------------------|-------------------------3--|
|
||||
--------------------------|----------------------------|
|
||||
|
||||
|
||||
E E E E E E E E E E E E E E E E
|
||||
--------------------------|--------------------------|
|
||||
--------------1-----0--1--|--1-----------0-----------|
|
||||
-----------2-----2--------|-----0-----0-----0-----0--|
|
||||
--------3-----------------|--------0-----------0-----|
|
||||
-----3--------------------|--------------------------|
|
||||
--1-----------------------|--3-----------3-----------|
|
||||
|
||||
|
||||
^
|
||||
E E E E E E E E E E E E Q Q H E E E E
|
||||
---------------------------||-------------------0----|--7--------5-----------|
|
||||
--------------0------------||--1-----------3---------|--5-----------5--------|
|
||||
--2--------------0-----0--*||-----0-----0------------|--5--------------5-----|
|
||||
-----0-----0--------0-----*||--------2---------------|--------------------7--|
|
||||
--------2------------------||--3---------------------|-----------------------|
|
||||
--3-----------3------------||------------------------|--5--------5-----------|
|
||||
|
||||
|
||||
^ ^
|
||||
E E Q Q Q Q Q Q Q E E E E Q Q
|
||||
------------------0----|--3----1--------------|-------------------0----|
|
||||
--------1----3---------|--1---------1----3----|--1-----------3---------|
|
||||
-----------------------|--2---------2---------|-----0-----0------------|
|
||||
-----2-----------------|--3-------------------|--------2---------------|
|
||||
--3--------------------|----------------------|--3---------------------|
|
||||
-----------------------|------------1---------|------------------------|
|
||||
|
||||
|
||||
^ ^ ^
|
||||
H E E E E E E Q Q Q Q Q Q Q
|
||||
--7--------5-----------|------------------0----|--3----1--------------|
|
||||
--5-----------5--------|--------1----3---------|--1---------1----3----|
|
||||
--5--------------5-----|-----------------------|--2---------2---------|
|
||||
--------------------7--|-----2-----------------|--3-------------------|
|
||||
-----------------------|--3--------------------|----------------------|
|
||||
--5--------5-----------|-----------------------|------------1---------|
|
||||
|
||||
|
||||
|--3--| |--3--| |--3--|
|
||||
E E E E E E E E Q E E E E E E E E E
|
||||
--0-----------------------|--0----0--------3--------0--------|
|
||||
-----0-----------------0--|----------0--------0--------0-----|
|
||||
--------0-----------0-----|-------------0--------0--------0--|
|
||||
-----------2-----2--------|----------------------------------|
|
||||
--3-----------3-----------|-------3--------3-----------------|
|
||||
--------------------------|----------------------------------|
|
||||
|
||||
|
||||
|--3--| |--3--| |--3--| |--3--| |--3--|
|
||||
E E E E E E E E E E E E E E E Q Q Q
|
||||
--------------------------------------|--------------------------|
|
||||
--3-----------------3-----------------|--1--------0---------0----|
|
||||
-----3-----------3-----3-----------3--|-----0----------2---------|
|
||||
--------3-----3-----------3-----3-----|--------0-----------------|
|
||||
--1--------1-----------------1--------|--------------------------|
|
||||
--------------------------------------|--3-----------------------|
|
||||
|
||||
|
||||
^
|
||||
E E E E E E E E W
|
||||
--------------------------|-------------------||
|
||||
--1-----------------------|--1----------------||
|
||||
-----0-----------------0--|-------------------||
|
||||
--------2-----------2-----|--2----------------||
|
||||
--3--------3-----3--------|--3----------------||
|
||||
--------------3-----------|-------------------||
|
||||
|
||||
|
||||
|
||||
|
||||
Duration Legend
|
||||
---------------
|
||||
W - whole
|
||||
H - half
|
||||
Q - quarter
|
||||
E - 8th
|
||||
S - 16th
|
||||
T - 32nd
|
||||
X - 64th
|
||||
. - note dotted
|
||||
|-n-| - n-tuplets
|
25
guitar/good_little_girl
Normal file
@ -0,0 +1,25 @@
|
||||
C Em
|
||||
Good little girl.
|
||||
F G
|
||||
Always picking a fight with me,
|
||||
C Em
|
||||
you know that I'm bad,
|
||||
F G
|
||||
But you're spending the night with me.
|
||||
C Em F
|
||||
What... do you want... from my world?
|
||||
G Dm G
|
||||
You're a good little girl.
|
||||
C Em
|
||||
Bad little boy.
|
||||
F G
|
||||
That's what you're acting like,
|
||||
C Em F
|
||||
I really don't buy,
|
||||
G
|
||||
That you're that kind of guy.
|
||||
C Em
|
||||
And... if you are...
|
||||
F G Dm G
|
||||
Why do you want to hang out with me?
|
||||
C Em F G
|
57
guitar/horse_with_no_name
Normal file
@ -0,0 +1,57 @@
|
||||
http://tabs.ultimate-guitar.com/a/america/horse_with_no_name_crd.htm
|
||||
|
||||
Horse with no name
|
||||
America
|
||||
|
||||
|
||||
Em ------ D6/9 ------ Em9 ------ Dmaj9 ------
|
||||
|||||| |||||| |||||| ||||||
|
||||
|**||| *||*|| |*|||* |||**|
|
||||
|||||| |||||| |||||| ||||||
|
||||
|
||||
( Yes, the entire song is played in the second fret ! )
|
||||
|
||||
I like to strike the base note on a downstroke on the first beat
|
||||
followed by the bottom four strings. Alternating up and down
|
||||
on Em and Em9, up only on D6/9 and Dmaj9
|
||||
|
||||
|
||||
Em D6/9
|
||||
On the first part of the journey
|
||||
I was lookin at all the life
|
||||
There were plants and birds and rocks and things
|
||||
There were sand and hills and rings
|
||||
|
||||
The first thing I met was a fly with a buzz
|
||||
and the sky with no clouds
|
||||
the heat was hot and the ground was dry
|
||||
but the air was full of sound
|
||||
|
||||
Chorus
|
||||
Em9 Dmaj9
|
||||
|
||||
I've been through the desert on a horse with no name
|
||||
it felt good to be out of the rain
|
||||
in the desert you can remember your name
|
||||
'cause there ain't no one for to give you no pain
|
||||
la la la la lalala la la la la la
|
||||
|
||||
|
||||
After two days in the desert sun
|
||||
my skin began to turn red
|
||||
After three days in the desert fun
|
||||
I was looking at a river bed
|
||||
And the story it told of a river that flowed
|
||||
made me sad to think it was dead
|
||||
|
||||
chorus
|
||||
|
||||
|
||||
After nine days I let the horse run free
|
||||
'cause the desert had turned to sea
|
||||
there were plants and birds and rocks and things
|
||||
there were sand and hills and rings
|
||||
The ocean is a desert with it's life underground
|
||||
and the perfect disguise above
|
||||
Under the cities lies a heart made of ground
|
||||
but the humans will give no love
|
55
guitar/lets_be_space_pirates
Normal file
@ -0,0 +1,55 @@
|
||||
Let's Be Space Pirates, by Ruth Shuford
|
||||
|
||||
|
||||
capo 1
|
||||
|
||||
|
||||
Verse 1:
|
||||
|
||||
G
|
||||
We should blast off into the galaxies
|
||||
C
|
||||
and sail a pirate ship upon cosmic seas.
|
||||
G
|
||||
We’d dance upon a carpet of stars with bare feet
|
||||
C
|
||||
in our shining home made of steel and concrete.
|
||||
|
||||
Chorus:
|
||||
D C G
|
||||
Won’t you sail away with me?
|
||||
D C G
|
||||
Space pirates on the cosmic sea.
|
||||
Won’t you sail away with me?
|
||||
Space pirates on the cosmic sea.
|
||||
|
||||
Verse 2:
|
||||
|
||||
We’d rob other spaceships gliding through the black
|
||||
and raise Jolly Roger, not the Union Jack.
|
||||
If we didn’t get hit by their lasers and fried
|
||||
we’d be astronomical Bonnie and Clyde.
|
||||
|
||||
Chorus
|
||||
|
||||
Verse 3:
|
||||
I’d yell, “Yar-har, ye mateys, nebula ho!”
|
||||
And you’d steer us safe through the space tidal flow,
|
||||
as we sailed past supernovae and black holes,
|
||||
and dazzled everyone with some barrel rolls.
|
||||
|
||||
|
||||
Chorus
|
||||
|
||||
Bridge:
|
||||
D C D C
|
||||
You and me and a rocket ship,
|
||||
yeah you and me and a rocket ship,
|
||||
you and me and a rocket ship,
|
||||
G
|
||||
let's blast off today.
|
||||
|
||||
Chorus
|
||||
|
||||
|
||||
|
32
guitar/play_for_x.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="project">
|
||||
<h2 class="title">Play for X!</h2>
|
||||
<p>This is a running project I'm working on. Check it out on <a href="http://li60-203.members.linode.com:7777/">another port on this very server</a>, with the caveat that it's not exactly the belle of the ball at the moment. Lately I've not been focusing on the styling and design so much as I've been focusing on...</p>
|
||||
<p>The functionality! The super short version is this:</p>
|
||||
<blockquote>
|
||||
<p>Instead of rolling dice to see if you hit a monster, why not play a minigame instead?</p>
|
||||
</blockquote>
|
||||
<p>Tabletop roleplaying games (my experience is mostly with D&D 3.5, but I've also been playing <a href="http://www.dungeon-world.com/">Dungeon World</a> and someday I want to run or be in a <a href="http://www.mimgames.com/window/">The Window</a> game) have the well-agreed on standard that you use dice to generate random numbers to check whether you succeed on chance-based tasks. This introduces instability into the game, which makes things tense and interesting and prevents the game from playing the same way every time!</p>
|
||||
<p>But the only input the player actually has on how well they do, then, is the gameplay choices which apply various bonuses to their rolls. And that's kinda sucky! Because now that we all have computers, why not do something more interesting: </p>
|
||||
<blockquote>
|
||||
<p>When your character faces a skill-based task, you have to face one as well.</p>
|
||||
</blockquote>
|
||||
<h3>So what <em>is</em> Play for X anyway?</h3>
|
||||
<p>It's a chatroom, plus a bunch of tiny javascript games. You and your friends all log into a room together, and you start playing your game over the voice chat system of your choice. When you (as the DM) decree that a player needs to make a skill check, you simply choose a minigame or microtask from the list, and drag it onto their name. It immediately pops up on their screen, and when they've completed it, their score is posted into the chatroom, and you can make a decision based on how well they did!</p>
|
||||
<p>It's not finished yet. How the various parts of the system talk to each other has changed a bit as I've worked on this - the chat functionality works through websockets, and the games are slated to communicate their results to the client's browser by postMessage passing. This is partially implemented in...</p>
|
||||
<p>The code! The source is available at <a href="http://github.com/shoofle/play-for-x/">the github project play-for-x</a>, and you're entirely welcome to inspect, criticize, suggest, fork, whatever, as you like. I'd be interested in hearing if you do something with it! Some parts are pretty messy, but the games themselves are fun to make.</p>
|
||||
<h3>Can I check it out?</h3>
|
||||
<p>Sure! If you want to just try the games, you should direct your eyeballs or eyeball-equivalents at <a href="http://li60-203.members.linode.com:7777/games/">this lil' website</a>, which lets you try out the minigames I've made, play with their configurations, and so on. It uses a <a href="http://jsoneditoronline.org">nifty json editor widget</a> that someone made.</p>
|
||||
<hr>
|
||||
<p>One of my favorite things about working on this project is that it really strips out all the cruft that usually comes with working on game projects - I don't need to worry about the engine, I don't need to worry about rendering engines, I don't need to make lots of textures. I explicitly set a goal of never writing a large game for this project. With that requirement in place, I'm totally free to experiment a <em>lot</em>, and just throw together little javascript games in a few hours. Indeed, most of the games you'll see here took me half an afternoon to write! Experimenting with different forms of gameplay, and exploring exactly that side of the craft, is one of my greatest interests.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
92
guitar/pumped_up_kicks
Normal file
@ -0,0 +1,92 @@
|
||||
http://tabs.ultimate-guitar.com/f/foster_the_people/pumped_up_kicks_ver2_crd.htm
|
||||
|
||||
Capo 1
|
||||
|
||||
Em G D A [4X]
|
||||
|
||||
|
||||
Em G
|
||||
Robert's got a quick hand
|
||||
D A
|
||||
He'll look around the room he won't tell you his plan
|
||||
Em G
|
||||
Got a rolled cigarette
|
||||
D A
|
||||
Hangin' out his mouth, he's a cowboy kid
|
||||
Em G
|
||||
Yeah, found a six-shooter gun
|
||||
D A
|
||||
In his dads closet hidden with a box of fun things
|
||||
Em G
|
||||
I don't even know what
|
||||
D A
|
||||
But he's comin' for you, yeah he's comin for you, hey
|
||||
|
||||
|
||||
Em G
|
||||
All the other kids with the pumped up kicks
|
||||
D
|
||||
You'd better run, better run
|
||||
A
|
||||
Outrun my gun
|
||||
Em G
|
||||
All the other kids with the pumped up kicks
|
||||
D
|
||||
You'd better run, better run
|
||||
A
|
||||
Faster than my bullet
|
||||
[Repeat]
|
||||
|
||||
|
||||
Em G
|
||||
Daddy works a long day
|
||||
D A
|
||||
He'll be coming home late, he's coming home late
|
||||
Em G
|
||||
And he's bringing me a surprise
|
||||
D A
|
||||
Cos' dinner's in the kitchen and it's packed in ice
|
||||
Em G
|
||||
I've waited for a long time
|
||||
D A
|
||||
The slight of my hand is now a quick pull trigger
|
||||
Em G
|
||||
I reason with my cigarette
|
||||
D A
|
||||
And say your hair's on fire you must have lost your wits, yeah
|
||||
|
||||
|
||||
Em G
|
||||
All the other kids with the pumped up kicks
|
||||
D
|
||||
You'd better run, better run
|
||||
A
|
||||
Outrun my gun
|
||||
Em G
|
||||
All the other kids with the pumped up kicks
|
||||
D
|
||||
You'd better run, better run
|
||||
A
|
||||
Faster than my bullet
|
||||
[Repeat]
|
||||
|
||||
|
||||
Em G D A [2X]
|
||||
(run run run)
|
||||
Em G D A [2X]
|
||||
(whistle)
|
||||
|
||||
|
||||
Em G
|
||||
All the other kids with the pumped up kicks
|
||||
D
|
||||
You'd better run, better run
|
||||
A
|
||||
Outrun my gun
|
||||
Em G
|
||||
All the other kids with the pumped up kicks
|
||||
D
|
||||
You'd better run, better run
|
||||
A
|
||||
Faster than my bullet
|
||||
[Repeat 2X]
|
14
guitar/render_tab.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Shoofle Plays Guitar!</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<pre class="project"><code class="tablature">
|
||||
{{ contents }}
|
||||
</code></pre>
|
||||
</body>
|
||||
</html>
|
65
guitar/women_and_men
Normal file
@ -0,0 +1,65 @@
|
||||
http://tabs.ultimate-guitar.com/t/they_might_be_giants/women_and_men_crd.htm
|
||||
|
||||
Artist: They Might Be Giants
|
||||
Song: Women and Men
|
||||
Album: Flood
|
||||
|
||||
Verse 1:
|
||||
G C
|
||||
When the ship runs out of ocean
|
||||
G F
|
||||
And the vessel runs aground
|
||||
E G C G
|
||||
Lands where we know the boat is found
|
||||
G C
|
||||
Now There's nothing unexpected
|
||||
G F
|
||||
About the water running out
|
||||
E G C G
|
||||
"Land" is not a word we have to shout
|
||||
|
||||
Pre Chorus:
|
||||
D C
|
||||
But there's something beside the shoreline
|
||||
G F
|
||||
Moving across the beachhead
|
||||
D C
|
||||
Coming up from the shipwreck
|
||||
G D
|
||||
Making as if to say
|
||||
|
||||
Chorus:
|
||||
G C G D
|
||||
Women & Meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeen
|
||||
G C G G
|
||||
Women & Meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeen
|
||||
G C G D
|
||||
Women & Meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeen
|
||||
G C G G
|
||||
Women & Meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeen
|
||||
|
||||
Bridge: ( Just Follow the patterns )
|
||||
Bringing with them messages of love
|
||||
And everywhere they go love will grow
|
||||
When you see the faces of the women
|
||||
And the men you soon will know
|
||||
|
||||
Verse 2:
|
||||
Women and men have crossed the ocean
|
||||
They now begin to pour
|
||||
out of the boat and up to the shore
|
||||
Two by two they enter the jungle
|
||||
And soon they number more
|
||||
Three by three as well as four by four
|
||||
|
||||
Pre Chorus:
|
||||
Soon the stream of people gets wider
|
||||
Then it becomes a river
|
||||
river becomes an ocean
|
||||
carrying ships that bear
|
||||
|
||||
Chorus
|
||||
Women and men
|
||||
Women and men
|
||||
Women and men
|
||||
Women and men
|
305
pages/auriga.html
Normal file
@ -0,0 +1,305 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>How should this website be laid out?</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<style type="text/css">
|
||||
#server-choices colgroup { width: 20%; }
|
||||
#server-choices tr { height: 3em; }
|
||||
#server-choices tr>td { text-align: center; }
|
||||
#server-choices tr>td:first-child {
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
<article class="project">
|
||||
<h1>Shit, I better make this server work.</h1>
|
||||
<h3>On the layout of folders and files!</h3>
|
||||
<p>Basically I'm not sure how I should lay out this website. The current organization looks something like this:</p>
|
||||
<ul class="file-tree">
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">server/</span> (server root)
|
||||
<ul>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">pages/</span> (articles with nice links)
|
||||
<ul>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span> (accessed as <span class="url">http://example.com/auriga/</span>)</li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">language_for_games.html</span> (<span class="url">http://example.com/language-for-games/</span>)</li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span> (<span class="url">http://example.com/tamari/</span>)
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
||||
<ul>
|
||||
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span> (global stying)</li>
|
||||
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
||||
<li><i class="icon-picture"></i> <span class="filename">banner.png</span></li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">tamari/</span> (files for an article)
|
||||
<ul>
|
||||
<li><i class="icon-picture"></i> <span class="filename">figure_1.png</span></li>
|
||||
<li><i class="icon-picture"></i> <span class="filename">figure_2.png</span></li>
|
||||
<li><i class="icon-signal"></i> <span class="filename">experiment_data.csv</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>This has a number of problems. First and foremost, barely any thought has gone into naming of folders and files - which is because not much thought has gone into their placement and hierarchy.</p>
|
||||
<p>The server is written using <a href="http://flask.pocoo.org">Flask</a>, and this is the rundown on how it works when a user goes to <span class="url">http://example.com/some-path/</span>:</p>
|
||||
<ol>
|
||||
<li>If the path requested is the root of the website, render <span class="filename">main_page.html</span>.</li>
|
||||
<li>If the path requested begins with <span class="url">static/</span>, render a file from the static content directory.</li>
|
||||
<li>Else, convert the path (<span class="url">some-path</span>) into the filename (<span class="filename">pages/some_path.html</span>) assuming it's an article. If it exists, render it.</li>
|
||||
<li>If there's no article by that name, display the miscellaneous articles page. Or 404. The current behavior isn't very high on my priorities.</li>
|
||||
</ol>
|
||||
<p>There are a bunch of problems with this system - it's kind of brittle, file paths have the meaningless-to-the-user <span class="url">static/</span> at the beginning, and it means that when I include a resource in <span class="url">http://example.com/tamari/</span> (the file <span class="filename">pages/tamari.html</span>) I have to use a path like <span class="url">../static/tamari/figure_1.png</span> - when I should be able to reference files related to the Tamari article by a closely-related URL: <span class="url">./figure_1.png</span>.</p>
|
||||
<p>All this points to the idea of having my articles be in folders, so it would look something like this:</p>
|
||||
<ul class="file-tree">
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">server/</span> (server root)
|
||||
<ul>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span> (articles with nice links)
|
||||
<ul>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">auriga/</span>
|
||||
<ul>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">language-for-games/</span>
|
||||
<ul>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">language_for_games.html</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">tamari/</span>
|
||||
<ul>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
||||
<li><i class="icon-picture"></i> <span class="filename">figure_1.png</span></li>
|
||||
<li><i class="icon-picture"></i> <span class="filename">figure_2.png</span></li>
|
||||
<li><i class="icon-signal"></i> <span class="filename">experiment_data.csv</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
||||
<ul>
|
||||
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span> (global stying)</li>
|
||||
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
||||
<li><i class="icon-picture"></i> <span class="filename">banner.png</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>And hell, at this point having the filenames match the folders (<span class="filename">auriga/auriga.html</span>) is just a pain, so we could name the main page in each folder <span class="filename">index.html</span>, and suddenly this looks very standard. So why don't I do this?</p>
|
||||
<p>Well... I don't know. But something always bothered me about the <span class="filename">index.html</span> standard. Maybe it's just that my article about Tamari lattices <em>isn't</em> an index, so I don't think it should be called one. That's certainly part of it. Also, some of my articles and pages are going to be very short - in theory I'd like them to be able to be tiny snippets, which could be included on other pages. It'd be annoying to have a subfolder for every single article I write! But... maybe not <em>too</em> annoying. I'll have to think about that.</p>
|
||||
<hr>
|
||||
<h3>But what are we <em>doing</em>?</h3>
|
||||
<p>What would my ideal web framework be? Well, something like Flask, really. I like flask because this is easy:</p>
|
||||
<pre>
|
||||
<code class="language-python">@app.route("<span class="url">/some-convoluted/url/<options>/with-stuff/</span>")
|
||||
def render_shoofle_page(options=None):
|
||||
if options == "bananas":
|
||||
return render_page("<span class="filename">bananas.html</span>")
|
||||
else:
|
||||
return render_page("<span class="filename">some_other_template.html</span>", options=options)</code></pre>
|
||||
<p>And, lo and behold, I can go to <span class="url">example.com/some-convoluted/url/bananas/with-stuff/</span> and see the right generated page! I like having that capacity at my fingertips. In particular, it makes it easy to respond to various other kinds of requests. That's what I really like about Flask - I feel like I can do <em>everything</em> a webserver can do, but it all takes the same very small amount of work. This compares to, say, PHP, where it's easy to make pages... But more complicated behavior, especially anything involving dynamic URL paths, involves jumping through hoops.<span class="sidenote span4">It might seem like an overblown complaint, but the integrity of my mental models is important to me - and in PHP, I don't understand what gets sent to the requestor. If I make a Flask route returning JSON, I know it's exactly what a script wants. With PHP, I would <em>hope</em> that it wouldn't have weird headers or content type or additional markup.</span> Plus, you have to work with PHP, which I would wish on no one.</p>
|
||||
<p>I don't like Flask because I need to specify all the behaviors, and I'm worried that I'll get it wrong (thus, this article).</p>
|
||||
<p>My ideal world solution would be something that lets me pass requests for subpaths to other python modules:<p>
|
||||
<ul class="file-tree">
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">server/</span>
|
||||
<ul>
|
||||
<li><i class="icon-file"></i> <span class="filename">server.py</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span>
|
||||
<ul>
|
||||
<li><i class="icon-file"></i> <span class="filename">articles.py</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">language-for-games.html</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">games/</span>
|
||||
<ul>
|
||||
<li><i class="icon-file"></i> <span class="filename">games.py</span></li>
|
||||
<li><i class="icon-signal"></i> <span class="filename">scores.csv</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">play_the_game.html</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">game.js</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Aaaand how it works would be simple:</p>
|
||||
<ol>
|
||||
<li>A request comes in to <span class="url">http://example.com/tamari/</span>, and it is handled by <span class="filename">server.py</span>.</li>
|
||||
<li><span class="filename">server.py</span> says "Okay, I don't have any specific handlers that do anything with this URL, but I think <span class="filename">articles/articles.py</span> does!" and sends the request to <span class="filename">articles.py</span>.</li>
|
||||
<li><span class="filename">articles.py</span> receives a request for <span class="url">/tamari/</span> and has a rule for handling that, and so it renders the appropriate HTML file.</li>
|
||||
</ol>
|
||||
<p>The basic idea is that requests can be routed to other python modules. If those modules can be reloaded easily (or automatically!), this would mean I could write complicated URL handling in subdirectories of my website - without having to touch any of the code that handles anything else. It means I can modularize - and that's <em>awesome</em>.</p>
|
||||
<ol>
|
||||
<li>An HTTP GET request comes in to <span class="url">http://example.com/games/points</span>, and <span class="filename">server.py</span> takes it.</li>
|
||||
<li><span class="filename">server.py</span> doesn't know what to do with it, but it knows that requests for URLs starting with <span class="url">/games</span> should be handled by <span class="filename">games/games.py</span>.</li>
|
||||
<li><span class="filename">games.py</span> receives an HTTP GET request for <span class="url">/games/points</span>, and so it can respond to this with a JSON object that tells the requestor how many points they got.</li>
|
||||
</ol>
|
||||
<p>This is the main point of the tiered handlers system - that I can write handlers for all kinds of requests, without having to interact with other parts of my website.</p>
|
||||
<p>Basically, I want to combine the simple directory structure of PHP websites with the principles of Flask I really like - separating content from server logic, keeping things simple, and having control.</p>
|
||||
<p>Here's how I imagine this would work:</p>
|
||||
<pre>
|
||||
<code>from flask import Flask, render_template, redirect
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def main_page(): return render_template("<span class="filename">main.html</span>")
|
||||
app.add_url_rule("<span class="url">/</span>", main_page)
|
||||
|
||||
import games
|
||||
app.add_module_url_rule("<span class="url">/games/<path:rest></span>", games)</code></pre>
|
||||
<p>As usual, don't think too hard about the syntax I just proposed. The point is to distribute URL routing logic throughout multiple files, so that my entire website isn't controlled by one brutalistic overlord <span class="filename">server.py</span> file that decrees the entire path of every request. I want things split up, dammit!</p>
|
||||
<hr>
|
||||
<p>Now I'm reading up on the Flask docs, and it turns out that it already has the capacity for this. Unfortunately, it's complicated and I'm <em>whiiiny</em>.</p>
|
||||
<p>It seems that Flask provides the developer with three options:</p>
|
||||
<ul>
|
||||
<li>Package Organization: Essentially, break up your server code, like configuration and URL route assignment, into separate files. This doesn't actually solve any of my issues - most of what this does (as far as I can tell) is separate the server initialization logic from the routing and response logic. Plus, it makes it easier to use your application in something else. More on this soon.</li>
|
||||
<li>Blueprints: Very close to what I want. I could define a Blueprint object in <span class="filename">articles.py</span>. This Blueprint object would register all the routes and endpoints that I want to register - and then, when the server starts, it gets all of those from the blueprint. This means we can <em>actually</em> factor views out. I'm really not sure, though, what this affords that the organizing your application as a package doesn't.</li>
|
||||
<li>Application Dispatching: The most powerful of the three! This is a slightly lower-level solution, wherein you actually run multiple applications concurrently, and dispatch requests to them. This is kind of overkill, but at least it's nice to know that it's possible - things like the <span class="url">async_app</span> example from previous could really make sense, if the app is large enough in scope. Application dispatching means you can just pull in another application and route things to it on the WSGI layer. Or something.</li>
|
||||
</ul>
|
||||
<p>Okay, but... how do they score up? I have some requirements:</p>
|
||||
<dl>
|
||||
<dt>Organization</dt>
|
||||
<dd>I want to define the behavior for <span class="url">example.com/articles/tamari/</span> in the same place as <span class="url">example.com/articles/language-for-games/</span> is defined, but in a different file from where <span class="url">example.com/games/hunt-the-wumpus</span> is defined.</dd>
|
||||
<dt>Simplicity</dt>
|
||||
<dd>Defining a URL route and endpoint for each subfolder of my application shouldn't be much more complicated than defining behaviors in a flat system. Ideally, registering all the behaviors for the <span class="url">articles/</span> subpath is no more complicated than <code>app.route("<span class="url">/articles/</span>", articles_handler)</code></dd>
|
||||
<dt>Ease of Extension</dt>
|
||||
<dd>I'm writing a family of pages. They're starting to get a little too complicated. It should be really easy to go from that situation to having a nicely-delineated subsection of my website.</dd>
|
||||
<dt>Do I <em>Need</em> to Restart the Server?</dt>
|
||||
<dd>I hate restarting the server. Maybe this is a little thing, but gah! I want the server to detect changes automatically! This shouldn't be that hard. Of course, this is a much thornier topic when it comes to subpages that might store their own state... So it might be out the window unless I want to get my hands <em>way</em> more dirty.</dd>
|
||||
</dl>
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<table id="server-choices" class="span8 offset2">
|
||||
<caption><h4>How do they fare up?</h4></caption>
|
||||
<col><colgroup span=4></colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
||||
<th>Organization</th>
|
||||
<th>Simplicity</th>
|
||||
<th>Ease of Extension</th>
|
||||
<th>No Restart Required?</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Current</td>
|
||||
|
||||
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Organize as a Package</td>
|
||||
|
||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
||||
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Blueprints</td>
|
||||
|
||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Application Dispatch</td>
|
||||
|
||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></div>
|
||||
<p>In light of this chart, it seems like Blueprints are the clear option. Also, "organize as package" is really vague. What they suggested didn't sound very helpful - but making python packages (finally learning how to use <span class="filename">__init__.py</span> files!) will probably get used in the solution I'm thinking I'll use, which looks something like this:</p>
|
||||
<ul class="file-tree">
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">server/</span>
|
||||
<ul>
|
||||
<li><i class="icon-file"></i> <span class="filename">server.py</span></li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span>
|
||||
<ul>
|
||||
<li><i class="icon-file"></i> <span class="filename">article_routing_blueprint.py</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">language-for-games.html</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
||||
<li><i class="icon-folder-close"></i> <span class="filename">tamari_files</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">games/</span>
|
||||
<ul>
|
||||
<li><i class="icon-file"></i> <span class="filename">games_blueprint.py</span></li>
|
||||
<li><i class="icon-signal"></i> <span class="filename">scores.csv</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">play_the_game.html</span></li>
|
||||
<li><i class="icon-align-left"></i> <span class="filename">game.js</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
||||
<ul>
|
||||
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
||||
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span></li>
|
||||
<li><i class="icon-picture"></i> <span class="filename">lol_a_cat.jpg</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>If there's static content that is globally important, with simple routing rules, it can - of course - be stored in the server root's <span class="filename">static/</span> directory. Static file handlers don't take much configuration, so this can go in the root.</p>
|
||||
<p>All the files related to articles are contained in the <span class="filename">articles/</span> directory, or subdirectories. <span class="filename">article_routing_blueprint.py</span> contains a blueprint definition that tells the server how to route calls that result in the rendering of the various articles I've written.</p>
|
||||
<p>All files related to the little javascript games I've made, on the other hand, go in the <span class="filename">games/</span> directory. State for this application is managed by <span class="filename">games_blueprint.py</span>, which is sort of like a very tiny application. I think it's possible to keep track of state, if you remember to keep variables global... This is tricksy, but should be doable - and if it gets larger, it should almost certainly be developed as a separate application entirely. At that point, I should figure out how to include multiple applications in one website!</p>
|
||||
<p>I want to finish this bit by writing down some code for the base <span class="filename">server.py</span> logic:</p>
|
||||
<pre>
|
||||
<code class="language-python">from flask import Flask
|
||||
|
||||
# app configuration and initialization
|
||||
app = Flask(__name__)
|
||||
app.debug = True
|
||||
|
||||
# content in <span class="filename">articles/</span>
|
||||
import articles
|
||||
app.register_blueprint(articles.blueprint)
|
||||
|
||||
# content in <span class="filename">games/</span>
|
||||
import games
|
||||
app.register_blueprint(games.blueprint, url_prefix="<span class="url">/games</span>")</code></pre>
|
||||
<hr>
|
||||
<h3>Okay, one last thing.</h3>
|
||||
<p>This has been a lot about how to get some basic extensible functionality working. <i class="that-guy">But wait</i>, someone cries in the distance! <i class="that-guy">Why are we going to such lengths to do all this in the first place, when you're just serving static HTML files? Isn't this way more work than you need?</i><span class="sidenote span4">In case you're reading this article long after I've finished these changes (I hope so, 'cause I should get to work on this immediately), at this point all the articles were static HTML files. That voice speaks the truth.</span></p>
|
||||
<p>Thanks for asking. The answer is that I want to change how this site is structured, and the articles are the specific thing I want to change. See, as it is, each article has basically the same header at the top, and basically the same footer at the bottom, and... Well, they're just all enclosed in the same stuff, and so when I change the styling of the website - or, horror of horrors, try to add a sidebar across the hwole site - I have to change all of them! And, as I think we've been over before, I'm <em>lazy</em>.</p>
|
||||
<p>Conveniently, as I've been obsessively reading discussions of standards-compliant HTML5 and document formats and such lately, this laziness messes with my indomitable enthusiasm for conceptually pleasing solutions. Here's what I've got:</p>
|
||||
<ul>
|
||||
<li><b>Articles</b> on my site are blocks of text, consisting of my rambling on some topic. Something I've written down. They can have some amount of associated content, but for the most part they're just text. So, I'm going to reduce them down to their bare minimum of unique content - in many cases, just an <code language="html"><article></code> tag containing what I wrote!</li>
|
||||
<li>But sometimes I want to have multiple articles display in one page! Sometimes my articles are single paragraphs. Sometimes they can be grouped into related, uh, groups! What do we do then? The answer is <strong>templates</strong>. Flask uses <a href="http://jinja.pocoo.org/">Jinja2</a>, a perfectly nice templating engine - and why not use it?</li>
|
||||
<li>If I want to display the articles contained in <span class="filename">articles/parkour_is_awesome.html</span>, <span class="filename">articles/exercise.html</span>, and <span class="filename">articles/how_is_body.html</span>), then I just make a new page, a Jinja2 template, which contains this:
|
||||
<pre>
|
||||
<code class="language-jinja2"><!--{{ "-->{%<!--" }}--> include "<span class="filename">articles/parkour_is_awesome.html</span>" <!--{{ "-->%}<!--" }}-->
|
||||
<!--{{ "-->{%<!--" }}--> include "<span class="filename">articles/exercise.html</span>" <!--{{ "-->%}<!--" }}-->
|
||||
<!--{{ "-->{%<!--" }}--> include "<span class="filename">articles/how_is_body.html</span>" <!--{{ "-->%}<!--" }}--></code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
<p>And ta-da! We now have a page which has those three articles in a row.</p>
|
||||
<p>This, of course, also means we have a neat format for how to display things in general. Someone requested access to a URL! Find the file it points to. If it's an HTML fragment, then point the <b>general page template</b> to that file, and render. The general page template is just a template that adds the header, footer, sidebar, universal styling, and so on, as required, for universality.</p>
|
||||
<p>So if you go to <span class="url">example.com/tamari/</span>, the server says "Okay, you want to look at the article in the HTML fragment file <span class="filename">articles/tamari.html</span>." It renders the general page template around that article, and returns that to the user.</p>
|
||||
<p>Because I like having the option to look at these things many ways, I'm probably also going to allow for a user to do <code class="language-bash">python articles.py --generate [path]</code>, which will simply spit out the the rendered results of going to <code class="language-bash">[path]</code>. I guess that <em>might</em> just be indistinguishable from using <code class="language-bash">wget</code>, but hey. It can't hurt to give more functionality!</p>
|
||||
<p>It remains to be seen precisely how many pages on this site will use the general page template. I don't want to rely on it too much, but, man, is there <em>any</em> reason not to? Basically, it means that I don't have to worry about writing the headers of anything on my website. I guess I'll need to be able to throw it off when I'm making subpages that are intended to be stylistically distinct from the rest of my site.</p>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
69
pages/city_on_the_river.html
Normal file
35
pages/distributed_speakers.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>This is a test</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<article class="project">
|
||||
<h1>Distributed Speakers</h1>
|
||||
<h4>(project idea)</h4>
|
||||
<div class="important">
|
||||
<p>So you want to have a rally. You want to hold a sports competition for your large neighborhood. Maybe you want to broadcast announcements across your company picnic. Maybe you want to throw an impromptu dance party!</p>
|
||||
<p>The common line between all of these scenarios is this: you need a sound system, but you do not have one.</p>
|
||||
</div>
|
||||
<p>I first conceived of this while thinking about the specific issue of a dance party. Here's my solution:</p>
|
||||
<ul>
|
||||
<li>Everyone downloads this free app.</li>
|
||||
<li>Everyone directs the app to the streaming media source of choice - a web radio station or something.</li>
|
||||
<li>Each phone in the network listens to the audio it hears, and synchronizes what it's playing to the surroundings.</li>
|
||||
</ul>
|
||||
<p>I liked this idea because I have friends I like dancing with, but we rarely have a sound system set up and in place for dancing in public spaces. But anywhere you need to communicate something to a large number of people but you don't have a sound system, this app would be useful.</p>
|
||||
<h3>Let's talk about issues.</h3>
|
||||
<p class="important">How do you sync up a bunch of audio sources together on the fly, with limited communication between them?</p>
|
||||
<p>That's the biggest problem, but there are smaller issues - well, they're really just the obstacles we'd need to face:</p>
|
||||
<ul>
|
||||
<li>How do we make this accept a wide variety of stream types - web radio, youtube, soundcloud, etc.?</li>
|
||||
<li>How do you do ad hoc networking between mobile devices?</li>
|
||||
<li>How do we tie this in with youtube playlists, which people will frequently want to play music from?</li>
|
||||
<li>Is this even possible, when considering the speed-of-sound delay? How far apart can sources be, such that they're perceived as one sound rather than two?</li>
|
||||
</ul>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
291
pages/game_log.html
Normal file
@ -0,0 +1,291 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Game Log</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<style type="text/css">
|
||||
.accolades { display: inline-block; }
|
||||
.thoughts { font-size: smaller; font-style: italic; }
|
||||
#games-log p { margin: 0; }
|
||||
.difficulty, .achievement {
|
||||
border-radius: 2px;
|
||||
border: 1px solid rgba(0,0,0,0.1);
|
||||
}
|
||||
.max {
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
.hard {
|
||||
background-color: rgb(255,70,70);
|
||||
}
|
||||
.normal {
|
||||
background-color: rgb(200,200,200);
|
||||
}
|
||||
.easy {
|
||||
background-color: rgb(70,255,70);
|
||||
}
|
||||
.bad {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
</style>
|
||||
<article id="games-log">
|
||||
<h1>Games I've Played</h1>
|
||||
<section>
|
||||
<h2>Mostly Shooters and Stuff</h2>
|
||||
<ul>
|
||||
<li>Mass Effect 3 Multiplayer</li>
|
||||
<li>Halo: Combat Evolved
|
||||
<div class="accolades">
|
||||
<span class="difficulty max">Legendary solo</span>
|
||||
</div>
|
||||
<p class="thoughts">I really liked Halo: CE. It was a strong game, and I've had a soft spot for the Halo story - I don't think it's particularly deep or told with finesse, but it's <em>fun</em>!</p>
|
||||
</li>
|
||||
<li>Halo 2
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Heroic co-op</span>
|
||||
</div>
|
||||
<p class="thoughts">I've been telling myself I'm going to beat Halo 2 on legendary by myself since the day I beat Halo: CE on legendary. I feel the overwhelming urge to be able to say I've beaten the whole trilogy on the hardest difficulty! On the other hand, it's really goddamn hard.</p>
|
||||
</li>
|
||||
<li>Halo 3
|
||||
<div class="accolades">
|
||||
<span class="difficulty max">Legendary co-op</span>
|
||||
<span class="difficulty max">Legendary solo</span>
|
||||
<span class="achievement max">All Skulls found</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Halo 3: ODST
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Heroic co-op</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Halo: Reach
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Heroic co-op</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Gears of War
|
||||
<div class="accolades">
|
||||
<span class="difficulty max">Insane co-op</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Gears of War 2
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Hardcore co-op</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Gears of War 3
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Hardcore co-op</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Half-Life</li>
|
||||
<li>Half-Life: Blue Shift</li>
|
||||
<li>Half-Life: Opposing Force</li>
|
||||
<li>Half-Life 2 (and Episode 1) (and Episode 2)</li>
|
||||
<li>Portal</li>
|
||||
<li>Portal 2 (and co-op)</li>
|
||||
<li>Army of Two</li>
|
||||
<li>Army of Two: 40th Day</li>
|
||||
<li>Operation Flashpoint: Dragon Rising
|
||||
<div class="accolades">
|
||||
<span class="achievement bad">Gave up after like 30 minutes</span>
|
||||
</div>
|
||||
<p class="thoughts">This game was terrible.</p>
|
||||
</li>
|
||||
<li>Resistance: Fall of Man
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Hard? co-op</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Resistance 3
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Hard co-op</span>
|
||||
</div>
|
||||
<p class="thoughts">These games weren't very deep, but they had decent shooting and good weapons. Resistance 2 didn't have co-op, so I didn't play it - I just watched my friend do it.</p>
|
||||
</li>
|
||||
<li>Killzone 3
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Veteran? co-op</span>
|
||||
</div>
|
||||
<p class="thoughts">This game offered alternate color modes for colorblindness, which is awesome. Shame the dialogue and plot was so literally laughable.
|
||||
</p>
|
||||
</li>
|
||||
<li>Resident Evil 5
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Veteran? co-op</span>
|
||||
<span class="achievement max">Broke one level</span>
|
||||
</div>
|
||||
<p class="thoughts">My pal and I played this over one break, and we couldn't take it seriously. Once we beat it, we spent our hard-earned points on getting infinite ammo for a few weapons - and decided we'd try to unlock infinite ammo for every weapon. We didn't end up doing that, but we did get so practiced at going through one level - which drops the most money for the time you spend in it by <em>far</em> - that we beat the max difficulty time trial by <em>half</em>. The magnum in that game is ridiculously overpowered.</p>
|
||||
</li>
|
||||
<li>F.3.A.R.
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Fearless? co-op</span>
|
||||
</div>
|
||||
<p class="thoughts">As far as I can tell, these people have no idea what the phrase "survival horror" even means.</p>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Not Shooters</h2>
|
||||
<ul>
|
||||
<li>Pokemon: Red
|
||||
<div class="accolades">
|
||||
<span class="achievement normal">Beat the Elite Four</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Pokemon: Silver</li>
|
||||
<li>Pokemon: Diamond
|
||||
<div class="accolades">
|
||||
<span class="achievement normal">Beat the Elite Four</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Prince of Persia: Sands of Time</li>
|
||||
<li>Prince of Persia (2008)</li>
|
||||
<li>Super Smash Brothers: Melee
|
||||
<div class="accolades">
|
||||
<span class="achievement hard">Every SP challenge</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Super Smash Brothers: Brawl
|
||||
<div class="accolades">
|
||||
<span class="achievement max">Every achievement</span>
|
||||
<span class="achievement bad">except one sticker</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Mario Kart: Double Dash
|
||||
<div class="accolades">
|
||||
<span class="achievement max">Time Trial Staff Ghosts</span>
|
||||
<span class="achievement max">Every Cup on Mirror</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Mario Kart: Wii
|
||||
<div class="accolades">
|
||||
<span class="achievement max">Gold Medals on Everything</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Okami
|
||||
<div class="accolades">
|
||||
<span class="achievement normal">All brush techniques</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Legend of Zelda: Link's Awakening
|
||||
<p class="thoughts">I think this might be my #1 pick for best Zelda game.</p>
|
||||
</li>
|
||||
<li>Legend of Zelda: Ocarina of Time</li>
|
||||
<li>Legend of Zelda: Twilight Princess</li>
|
||||
<li>Super Mario 64</li>
|
||||
<li>Super Mario Sunshine</li>
|
||||
<li>Final Fantasy</li>
|
||||
<li>Final Fantasy 6
|
||||
<div class="accolades">
|
||||
<span class="achievement bad">Halfway</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Final Fantasy 7
|
||||
<div class="accolades">
|
||||
<span class="achievement bad">Halfway</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Final Fantasy 8
|
||||
<div class="accolades">
|
||||
<span class="achievement bad">Halfway</span>
|
||||
</div>
|
||||
<p class="thoughts">I feel like including Final Fantasy games that I haven't finished is still reasonable because not finishing a Final Fantasy game involves a similar time commitment as finishing many other games.</p>
|
||||
</li>
|
||||
<li>No More Heroes
|
||||
<div class="accolades">
|
||||
<span class="difficulty normal">Mild</span>
|
||||
<span class="achievement normal">All Beam Katanas</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>No More Heroes 2: Desperate Struggle
|
||||
<div class="accolades">
|
||||
<span class="difficulty normal">Mild</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Guitar Hero
|
||||
<div class="accolades">
|
||||
<span class="difficulty max">Expert</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Rock Band
|
||||
<div class="accolades">
|
||||
<span class="difficulty max">Expert Guitar</span>
|
||||
<span class="difficulty normal">Medium Drums</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>Super Metroid</li>
|
||||
<li>Metroid: Fusion</li>
|
||||
<li>Metroid: Zero Mission</li>
|
||||
<li>Metroid Prime</li>
|
||||
<li>Metroid Prime 3: Corruption</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Extremely Memorable</h2>
|
||||
<ul>
|
||||
<li>Shadow of the Colossus
|
||||
<div class="accolades">
|
||||
<span class="difficulty max">Hard</span>
|
||||
<span class="achievement hard">Time Trials (Normal)</span>
|
||||
<span class="achievement max">Climbed the temple</span>
|
||||
</div>
|
||||
<p class="thoughts">I love this game so much I'm not even going to write about it. My thoughts would take up too much space.</p>
|
||||
</li>
|
||||
<li>Ico
|
||||
<p class="thoughts">Ico was very pretty, and had some of the same quality that Shadow of the Colossus had, but it didn't tie together nearly so well.</p>
|
||||
</li>
|
||||
<li>Mirror's Edge
|
||||
<div class="accolades">
|
||||
<span class="difficulty normal">Easy</span>
|
||||
<span class="achievement hard">Test of Faith (Pacifist)</span>
|
||||
</div>
|
||||
<p class="thoughts">This game has the best platforming I've had the pleasure of experiencing - and I'm a sucker for good platforming.</p>
|
||||
</li>
|
||||
<li>El Shaddai
|
||||
<div class="accolades">
|
||||
<span class="difficulty normal">Normal</span>
|
||||
</div>
|
||||
<p class="thoughts">I loved this game from an aesthetic point of view, but I kept waiting for the story to get interesting. I'm still waiting.</p>
|
||||
</li>
|
||||
<li>Zeno Clash
|
||||
<p class="thoughts">The aesthetic really makes this game stand out.</p>
|
||||
</li>
|
||||
<li>Iji
|
||||
<div class="accolades">
|
||||
<span class="difficulty normal">Normal</span>
|
||||
<span class="achievement normal">Somewhat Pacifist</span>
|
||||
</div>
|
||||
<p class="thoughts">Iji remains one of my favorite games of all time, for its excellent pseudo-morality system - one of the best I've seen.</p>
|
||||
</li>
|
||||
<li>Valkyrie Chronicles
|
||||
<div class="accolades">
|
||||
<span class="difficulty normal">Normal</span>
|
||||
<span class="achievement normal">No deaths</span>
|
||||
</div>
|
||||
<p class="thoughts">Valkyrie Chronicles had such a cool gameplay and storytelling style that I have to include it.</p>
|
||||
</li>
|
||||
<li>No More Heroes
|
||||
<div class="accolades">
|
||||
<span class="difficulty normal">Mild</span>
|
||||
<span class="achievement normal">All Beam Katanas</span>
|
||||
</div>
|
||||
<p class="thoughts">It's hard to describe this game. It was fascinating.</p>
|
||||
</li>
|
||||
<li>Elite Beat Agents
|
||||
<div class="accolades">
|
||||
<span class="difficulty hard">Sweatin'!</span>
|
||||
<span class="difficulty max">Hard ROCK!</span>
|
||||
</div>
|
||||
<p class="thoughts">Probably my favorite rhythm game.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
150
pages/language_for_games.html
Normal file
@ -0,0 +1,150 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>A Language for Games</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<p>I like making games but sometimes I spend a lot of time doing stuff that is just annoying. What if a language or environment were designed to make those things easy?</p>
|
||||
<hr>
|
||||
<article class="project">
|
||||
<header>
|
||||
<h1>Snorlax Evaluation</h1>
|
||||
<p>(define-by-reference, or: lazy evaluation taken to extremes)</p>
|
||||
</header>
|
||||
<p>Okay, so I've got a <code>Bomb</code> entity in my game. It's already got the behavior for flying toward its <code>destination</code>. What if I want to make a <code>SmartBomb</code> that tracks a target even if they move? I might do it something like this:</p>
|
||||
<pre><code>SmartBomb.on_update = function (timestep) {
|
||||
// other update behaviors go in this function as well
|
||||
this.destination = target.position
|
||||
}</code></pre>
|
||||
<p>I have to explicitly tell my engine to execute this every frame. I think in terms of this kind of thing already, because I'm a math and physics person. Why can't I define relationships like this more simply? What if, in fact, this was the default way we referred to values? <span class="sidenote span4">It's worth noting that what I've thought of here is essentially just <a href="https://en.wikipedia.org/wiki/Functional_reactive_programming">functional reactive programming</a>. You can go read wikipedia if you want.</span></p>
|
||||
<pre><code>SmartBomb.destination = target.position</code></pre>
|
||||
<p>Any time something fetches the value of <code>SmartBomb.destination</code> it'll fetch the value of <code>target.position</code>. Writing it this way, instead of explicitly specifying which variables need to be kept up-to-date with other variables (and when they need to be updated!), means it's easier to give variables interesting dependencies on other values - like this <code>shield</code> which should float a certain distance between the <code>player</code> and the <code>enemy</code>:</p>
|
||||
<pre><code>shield.position = player.position + shield.distance * unit_vector(enemy.position - player.position)</code></pre>
|
||||
<p>If and when you <em>do</em> need to store something's value at a specific time, you can do that if you want - for example, this code when a bomb explodes:</p>
|
||||
<pre><code>explosion_location = current_value(bomb.position)
|
||||
// or maybe the syntax is like this:
|
||||
explosion_location = bomb.position.current_value</code></pre>
|
||||
<p>So far, everything's time-independent. For example, the <code>shield</code> object's <code>position</code> depends only on the positions of other objects.</p>
|
||||
<p>Why not include time-dependence? A <code>bullet</code> has a <code>position</code> and a <code>velocity</code>, and these are related in a way that doesn't change at any point during gameplay. Why not codify that relationship in a similar way?</p>
|
||||
<pre><code>bullet.position = bullet.position + time_step * bullet.velocity
|
||||
// or maybe
|
||||
bullet.position = bullet.position + bullet.position.time_since_last_calculation * bullet.velocity</code></pre>
|
||||
<p>Okay, if this seems like impossible magic, I'm sorry. Let's walk through it:</p>
|
||||
<ol>
|
||||
<li>The global loop asks for <code>bullet.position</code> in order to know where it should be drawn.</li>
|
||||
<li><code>bullet.position</code> looks at its cached value and sees that it's out of date.</li>
|
||||
<li><code>bullet.position</code> subtracts timestamps to find the time step between now and whenever it last got calculated, and remembers this as <code>time_step</code></li>
|
||||
<li>The time-dependence expression is now evaluated, using the last calculated value for <code>bullet.position</code>, and fetching <code>bullet.velocity</code> as normal.</li>
|
||||
</ol>
|
||||
<p>Hell, why not remember the entire history of a variable's values?<span class="sidenote span4">Performance.</span> When I fetch the last calculated value for <code>bullet.position</code>, why not go ahead and make that a graph-crawling reference-calculation just like everything else?<span class="sidenote span4">Reactive time-dependence is something to think about for an interesting mechanic, if nothing else - keeping track of dependencies on history means you could change a value at any point throughout the game's history and see how it changes things... Just like <a href="http://achrongame.com">Achron</a>! And the flaws that make it seem infeasible here wouldn't be a problem in, say, a turn-based time game.</span></p>
|
||||
<p>Performance is a legitimate worry at that point. If you include the full-on time-dependence, then depending on implementation you might end up following a reference back through every frame the game's been through. This approach would obviously fall apart because every value in your world is going to be at least O(t) to calculate, which sucks - there should be <em>no</em> time-dependent complexity - but there are solutions:</p>
|
||||
<ul>
|
||||
<li>Careful design can ensure that your objects aren't too densely interlinked.</li>
|
||||
<li>If you know you can do things more efficiently in some strenuous case, you can always hard-code it to extract current values and explicitly pass them around whenever you want.</li>
|
||||
<li>Variables should carry metadata about when they last changed, and when their predecessors and descendents in the graph have changed - so that, in calculating the <code>shield</code>'s <code>position</code>, you don't re-fetch the <code>enemy.position</code>, if you know it hasn't changed.</li>
|
||||
</ul>
|
||||
<p>Besides which, we have fast computers, and without running into hard algorithmic complexity problems (collision detection, I'm lookin' at you!) it's not <em>that</em> easy to overload a modern gaming machine. And hey, maybe having declarative time-dependent values is a pipe dream - I don't care. The core idea is still awesome.</p>
|
||||
<p>Here's an example (with more attention paid to data types) of how I'd come up with a vector that always points to a set offset from the position of <code>bullet</code>.</p>
|
||||
<pre><code>bullet.position = Wrapper(v(1,2))
|
||||
offset = v(3,4)
|
||||
endpoint = bullet.position + offset
|
||||
print endpoint</code>
|
||||
<samp>--> WrapperSum(bullet.position, offset)</samp>
|
||||
<code>print endpoint.current_value</code>
|
||||
<samp>--> v(4,6)</samp>
|
||||
<code>bullet.position.current_value = v(-10,0)
|
||||
print endpoint.current_value</code>
|
||||
<samp>--> v(-7,4)</samp></pre>
|
||||
<p>Once I've started thinking and talking about this, I start wondering how much we need imperative game loops at all, for anything other than those troublesome time dependencies and feedback loops. I wonder...</p>
|
||||
<pre><code>print bullet.contacts</code>
|
||||
<samp>--> Wrapper(List<Contacts>)</samp>
|
||||
<code>contact_acceleration = sum(contact.force_to_resolve for contact in bullet.contacts)
|
||||
bullet.acceleration = contact_acceleration</code></pre>
|
||||
<p>Assuming that force due to contacts is the only thing present in the world, then the bullet now feels enough acceleration to resolve all the conflicts. I mean, assuming contacts are simple to work with, and they always are. Right? Right?</p>
|
||||
<p>I'm thinking about this a lot because this kind of referencing is very natural for things like defining interlinks between components in my game engine - I've got conflicting interests:</p>
|
||||
<ul>
|
||||
<li>I want to keep my vectors and properties lightweight, so that a <code>bullet</code>'s position should just be a vector, with which I should be able to do math as freely and easily as integers.</li>
|
||||
<li>But I also want to ensure that the <code>collision component</code>'s position is the same as the <code>bullet</code>'s position! I'd like to do <code>collision_comp.position = bullet.position</code></li>
|
||||
<li>And then I run into the problem that since I want my vectors as primitive as possible, if I change <code>bullet.position</code> then it's not going to change <code>collision_comp.position</code> because pass-by-value is the dominant paradigm.</li>
|
||||
</ul>
|
||||
<p>The solution I've been working with is wrap together <em>sets</em> of related data (as <i>components</i>). The <code>player</code> object has a <code>PositionComponent</code> and a <code>CollisionComponent</code>, and the <code>CollisionComponent</code> stores a reference to the <code>player</code>'s <code>PositionComponent</code> so that it can access it at any time. Actually holding those references constant means that there would be problems if the <code>player.position_component</code> suddenly changed to a different object - but that should never happen. I'm satisfied with this for the reasons I implemented it in the first place, but it doesn't get me the dynamic interlinking I'd like from something more like functional reactive programming.</p>
|
||||
<p>So I don't know. I would love to have the <em>capacity</em> for functional reactive programming in my game engines, at the least! It's so useful for making bulletproof dynamic interactive systems.</p>
|
||||
</article>
|
||||
<hr>
|
||||
<article class="project">
|
||||
<header>
|
||||
<h1>Time Integration</h1>
|
||||
</header>
|
||||
<p>I find myself writing cooldowns and countdowns all the time. Bullets can only fire so fast, bombs explode after five seconds, enemies spawn every 10-15 seconds. Every time I do it, I write the same boilerplate in the initialization:</p>
|
||||
<pre><code>goomba.cooldown_max = 5 // 5 seconds to cool down
|
||||
goomba.cooldown_timer = goomba.cooldown_max</code></pre>
|
||||
<p>and the same boilerplate in the update function:</p>
|
||||
<pre><code>if goomba.cooldown_timer > 0:
|
||||
goomba.cooldown_timer -= time_step
|
||||
if goomba.cooldown_timer < 0:
|
||||
// insert end behavior here</code></pre>
|
||||
<p>and somewhere, I activate this behavior (in response to a keypress, or proximit, or contact):</p>
|
||||
<pre><code>goomba.cooldown_timer = goomba.cooldown_max</code></pre>
|
||||
<p>I do this kind of thing so often that I feel like it should be one of the basic functionalities offered when I'm trying to describe game entity behavior.</p>
|
||||
<pre><code>// initialization
|
||||
goomba.shot_timer = new CooldownTimer(length=5s, on_end=function() {...})
|
||||
// update functionality should be taken care of automatically, but if not:
|
||||
goomba.shot_timer.step(time_step)
|
||||
// activating the timer:
|
||||
goomba.shot_timer.start()</code></pre>
|
||||
<p>Now, wasn't that easy?</p>
|
||||
<p>Of course, that's a pretty simple case! There are obvious extensions, though:</p>
|
||||
<pre><code>goomba.blink_timer = new EndlessTimer()
|
||||
goomba.blink_timer.interval = 5s
|
||||
goomba.blink_timer.at_progress(0%, goomba.change_color) // change color at the start of each interval
|
||||
goomba.blink_timer.at_progress(50%, goomba.take_step) // take a step once every interval halfway through</code></pre>
|
||||
<p>And now making timed behavior for our goomba is easy! We can even speed up the goomba easily: <code>goomba.blink_timer.interval = 3s</code></p>
|
||||
<p>Ideally, you don't need to even specify when to <code>step</code> your timers - that should be taken care of automatically. Of course, that means we'd want to <em>register</em> these timers instead of simply declaring them as a member - but maybe that's a matter of a grander architectural problem.</p>
|
||||
<p>Although! If we <em>do</em> let the developer take care of stepping the timers, then we can also use it for things that <em>aren't</em> time-dependent:</p>
|
||||
<pre><code>player.limit_bar = new Meter(length=100) // general verison of the CooldownTimer
|
||||
player.on('hit by enemy', player.limit_bar.step)
|
||||
player.limit_bar.at_progress(100%, player.limit_break)</code></pre>
|
||||
<p>And now we've got a way for limit breaks to engage. Assuming there's a pre-existing event system and everything is architected carefully, it's now incredibly easy to fill meters in response to events.</p>
|
||||
</article>
|
||||
<article class="project">
|
||||
<header>
|
||||
<h1>Easy Peasy State Machinesy</h1>
|
||||
</header>
|
||||
<p>Why do I always have to actually use boolean flags (manually setting and unsetting them) to track the states of my entities?</p>
|
||||
<pre>
|
||||
<code>player.shielding = new Toggle()
|
||||
keyboard.on('w pressed', player.shielding.next)</code></pre>
|
||||
<p>I'm just throwing this syntax together off the top of my head. The syntax isn't important - what's important is that I should be able to describe this and have it happen.</p>
|
||||
<pre>
|
||||
<code>strobelight.color = new Sequence(['red', 'green', 'blue'])
|
||||
strobelight.update = function(dt) {
|
||||
strobelight.color.next()
|
||||
strobelight.draw()
|
||||
}</code></pre>
|
||||
<p>Seriously, don't worry about this syntax - it's ugly and I just threw it together. The point is the kinds of things I should be able to do. This is all totally feasible.</p>
|
||||
<pre>
|
||||
<code>goomba.ai = new StateMachine(['sleep', 'suspicious', 'alert'])
|
||||
goomba.ai['sleep'].transitions_to['suspicious'].on(goomba.near(player))
|
||||
// the state 'sleep' should transition to 'suspicious' on the event goomba.near(player)
|
||||
goomba.ai['sleep'].update = goomba.draw_snores
|
||||
|
||||
goomba.ai['suspicious'].transitions_to['alert'].on(goomba.sees(player))
|
||||
goomba.ai['suspicious'].update = goomba.search_for_player
|
||||
|
||||
// shit we forgot to make a state for just patrolling
|
||||
goomba.ai.add_state('patrol')
|
||||
goomba.ai['patrol'].transitions_to['sleep'].after(5 seconds)
|
||||
goomba.ai['patrol'].update = goomba.wander
|
||||
|
||||
// oh hey, she should occasionally wake up to patrol!
|
||||
goomba.ai['sleep'].transitions_to['patrol'].after(5-10 seconds)</code></pre>
|
||||
<p>So y'know. State machines are powerful. In order to really use them, you need a robust event system, or else they're a huge pain - it's still possible, you just... need to code it to check the conditions on each update loop. That could get expensive!</p>
|
||||
<p>For the example of checking <code>goomba.near(player)</code> - which has an optional argument for the distance - that function checks if there's already a collision detection object attached to <code>goomba</code> for setting off proximity events. If there is, it returns the event handle, which can be used for binding behaviors to the firing of that event. If a proximity collider of the right size <em>doesn't</em> exist, then it creates one, and returns the event handle.</p>
|
||||
<p></p>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
41
pages/mindjail_engine.html
Normal file
@ -0,0 +1,41 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<article class="project">
|
||||
<h1 class="title">Mindjail Engine!</h1>
|
||||
<p>This is doubtlessly my most ambitious project. It's a little 2D game engine in python that I've been working on for a while now. It's got some basic physics (not accurate, but they feel right, and that's what counts) and it can zip along pretty respectably! I first started this project in my second year of college, but I soon abandoned it because (surprise of surprises!) I had a lot of classes to work on. When I finally picked it back up towards the start of 2013, I had grown a lot as a programmer and a human being, and there were changes to make. I still love this project, but the primary goal I had here was to never set a deadline for myself. The idea was that I should never say when this project will be done - because it's always in progress. I'm never fully committing myself to a flawed approach, and, although there's a bunch of ugly code here, I'm never afraid to go back and change how I did something.</p>
|
||||
<h3>Tell me all about collision detection, it is my favorite subject!</h3>
|
||||
<p>I was good at my data structures and algorithms class, and they're concepts I'm deeply familiar with. It's interesting, though, that nothing ever gave me such a good sense for how algorithmic complexities compare until I was doing real-time collision detection. It doesn't help that my chosen language was python - a decision that helped many things in this project, but not speed. <span class="sidenote">People will happily claim that python is too slow to ever make a real game with, but it's just not true. Computers are fast. I'm convinced that python is perfectly capable.</span> There've been a lot of data structures I used for this, and the source is somewhere - <span class="todo">I'm going to put those online at some point.</span></p>
|
||||
<ul>
|
||||
<li>When I started out, of course, I did the brute force N^2 test, because I just wanted to get objects moving around on the screen. This rapidly bottomed out once I got more than probably 30 objects on the screen. I don't remember, it was a long time ago! I knew from the start that I was going to have to do something better, so I did.</li>
|
||||
<li>The next step was to roll something more advanced of my own. It had problems, but I'm still proud of how well it worked - I called it a sorted search list. The idea was that the list of objects in the world would be simultaneously kept sorted by each object's maximum and minimum extents on the x- or y-axes. When you're searching for a collision, then, you can cut down how many checks you do by searching upwards and downwards through the list until you find an object which is too far away to intersect - at which point no further objects could possibly be touching you. <span class="todo">I should make a picture.</span> Anyway, this system worked alright - if I remember correctly, I got up to around 50 objects on screen before it started slowing down a lot. I kept this around as a supporting data structure, but I didn't realize the massive flaws in it - in order to be certain about objects Foo and Bar not colliding, you need to run the check for Foo against Bar as well as Bar against Foo. Anyway.</li>
|
||||
<li>
|
||||
<p>After that I finally decided to ask the great oracle Google for help. Why didn't I use the knowledge of others before that? Well, they never really covered collision detection-specific data structures in my classes... I found out about a thing called a quadtree, and I was hooked. The idea is to recursively divide space into quadrants - objects northeast of center, northwest of center, and so on. This is the structure I spent the most time on, because I was dead-set on making it work. It was just so <em>cool!</em></p>
|
||||
<p>Well. That was silly of me. There are a lot of problems. Suppose Foo is in the northwest corner, but Bar overlaps between northwest and northeast! There's no simple solution, and mine was to have a secondary data structure, which stored objects which couldn't fit into any of the corners.</p>
|
||||
<p>At this point, I realized a structure-agnostic speedup I could use: Be mindful of whether objects move or not. If two objects never move, you never need to see if they collide. With this, the system got up to probably 80 objects on screen, with most of them stationary. Point being, it was a lot faster. I needed more, though! There was a huge problem:</p>
|
||||
<p>The quadtree wasn't balancing. Balancing a regular tree data structure is one thing, but quadtrees have two dimensions to balance at once, which makes it infinitely more difficult... And I couldn't find a tutorial on it, nor figure it out on my own. All the tutorials either dealt with worlds that had a size limit for objects, or discrete-position finite-world grid systems. I didn't want to do either of those! So I started panicking.</p>
|
||||
</li>
|
||||
<li>The next solution was to try variations on quadtrees. I tried a bunch - changing what supporting data structure I used, switching from a strict quadtree - at each level dividing in quadrants - to a <a href="http://wikipedia.org/wiki/K-d_tree">k-D tree</a>: At each level, it divides the world in half, and switches the lines along which it divides the world each level. They're a little more flexible in a few ways, and in theory easier to balance (because you don't need to balance two dimensions at the same time so much). Unfortunately, there's a dearth of information about using them for collision detection, because everyone uses them for graphics and not much else. <span class="sidenote">At this point, I was running out of steam for recursive data structures, but I briefly considered extending my k-D tree to be the most general kind of <a href="https://en.wikipedia.org/wiki/Binary_space_partitioning">binary space partitioning tree</a>, wherein you don't just cycle your dividing axis through a set of options, but rather you divide along a completely new axis - not necessarily perpendicular! - at each level. This is used for raytracing a lot, but implementing it for these purposes would have been a pain. It would have just meant more balancing and trying to make the trees smart, which I didn't want to get too heavily into.</span> I gave up on this soon after, partly because...</li>
|
||||
<li>I realized that my secondary data structure didn't work right. You needed to double-check every collision in order to be sure you had gotten all of them, and besides, sorting along one axis had little effect when you were frequently checking collisions which are grouped along the axis it doesn't sort on. I was basically back to square one. That's when I finally gave up on the tree - I would have needed to make it too smart in filling itself, I would have needed to balance it, I would have needed to have a good secondary data structure, and... It wasn't worth it. But then I found the light.</li>
|
||||
<li>
|
||||
<p>Spatial Hashing was something I'd heard of before, but mostly in the context of grid-based systems, finite worlds, and size-limited systems. I didn't want <em>any</em> of that. The typical spatial hashing scheme goes like this: You have a 2D array of lists. Each list corresponds to one grid space in your world, and so you only need to check against objects in adjacent squares. Here was my problem: Static arrays means you need to have a set size for your world, I don't like strict gridding, and I wanted to account for the fact that I might have large objects! But there's a solution, and, as it <em>always</em> seems to be in the world of data structures for practical everyday purposes, it's hash tables.</p>
|
||||
<p>Here's how my system works: The Spatial Hash Grid is a dict. The keys are (x,y) tuples which index into the infinite space of grid squares. The items are a secondary collision-detection data structure, which contain the objects. To find the key for an object, you just have to integer divide its coordinates. Since it just uses python's built-in dicts, it's hashing the tuples - so you never need to pre-specify the size of your world! The thorniest thing to get around was storing large objects. I tried throwing items into all the grid squares they touch, but it was too slow. The solution I ended up using is to make multiple tiers.</p>
|
||||
<p>When you put an object in the grid, it checks its size (by looking at the min/max x/y coordinates, which shape objects contain). If it's small enough to fit in this grid - that it will only ever occupy one square and its neighbors - then it goes in the dict we're looking at. Otherwise, the grid makes a new grid - with twice the grid size! Larger objects get shoved up the ladder, and when you're checking for collisions, you traverse up the ladder until you hit the end. This is reasonably fast so long as you don't have unreasonably many objects on different size scales.</p>
|
||||
<p>And it works! I haven't done extensive testing, but it goes up to 150 - 40 moving around, and the rest stationary - with 60FPS. I've gotten some slowdown after that (only from adding more moving objects) but it's certainly fast enough for my purposes - and some of the speed loss is from unoptimized rendering - and it should be the case that a sparsely populated world will have nearly no slowdown from additional objects being chucked in.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>So I'm using Spatial Hashing, and there're ways for it to be sped up, but collision detection works pretty well for now - certainly well enough to focus on other things.</p>
|
||||
<h3>Yes, but what about... anything else?</h3>
|
||||
<p>Well, this project is about the engine, so I'm not prepared to go into the actual game I want to make with it, but there's certainly graphics and windowing to talk about. The graphics are, for the moment, all coded up with vertex lists that it generates when it runs, and they're far from optimized or anything. This is good because I learned a lot about OpenGL. This is bad because pretty much all of what I learned is now obsolete, since the computer I've been developing for doesn't... have support... for shaders. Whoops. I want to get more experience with shaders, but I don't have a computer that's good for it right now. Also, that will be more meaningful when I have a better model-<engine pipeline for actually putting content into the engine.</p>
|
||||
<p>Windowing is, for the moment, done through pyglet, which is a lightweight framework for windowing and opengl bindings. I like it okay, but it's not capable of doing much - I'd have to write my own GUI, which would be suboptimal (although not too hard) given that I could just get a framework to do it for me. What I'm trying to do now is switch to using PyQt, having tried wxPython briefly and found it very hard to work with. I'm still working through reimplementing secondary things that pyglet was doing for me, such as keyboard and mouse handling and clock/fps management. That's what the gui branch is for, on github.</p>
|
||||
<h3>I guess links would be nice?</h3>
|
||||
<p>Oh, yes! Right. <a href="http://github.com/shoofle/mindjailengine/">The repository</a> is up on github, and it should work for you if you fork it. You'll need to pip install pyglet, or fork their latest dev version if you're on a mac - there's some kind of unresolved problem with OSX or something. That's one of the reasons I want to switch to a different framework - better portability.</p>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
71
pages/miscellany.html
Normal file
@ -0,0 +1,71 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<article class="project">
|
||||
<a name="auriga"></a>
|
||||
<h2 class="title">This site!</h2>
|
||||
<p>I made this site. It's a showcase of the various projects I work on, and basically the cool things I do.</p>
|
||||
<p>It's served by a <a href="http://flask.pocoo.org">flask-based</a> miniserver that I wrote. It don't do much, but it works!</p>
|
||||
<p>For the most part the pages themselves are hand-crafted HTML/CSS, like the artisanal coders of old.</p>
|
||||
<p>A large portion of this attractive layout is due to the excellent work of the folks at <a href="http://twitter.github.io/bootstrap/">bootstrap</a>.</p>
|
||||
<p><a href="../auriga/">I've been thinking more about how this server should be laid out, because I just kind of slapped it together.</a></p>
|
||||
</article>
|
||||
<article class="project">
|
||||
<a name="lambdamoo"></a>
|
||||
<h2 class="title">Worldbuilding Experiment #1: In and Out of the LambdaMOO!</h2>
|
||||
<p>I like MUDs - Multi-User Dungeons. They're cute to mess around in, and make a fun forum for roleplaying and enjoying a world with just text. I hadn't heard of MOOs - MUDs, but Object Oriented! A friend set up a LambdaMOO server for us to play around in, and I quickly got hooked - the distinguishing feature of LambdaMOO is that, being object-oriented, everything in the world (players, rooms, objects, whatever!) is an object and can be scripted by the same basic rules - and so the world is infinitely extensible.</p>
|
||||
<p>It's not a particularly elegant interface, and the language it uses (MOOCode) is far from pretty - but I was immediately impressed by how easy it was to create complicated behaviors and build your own worlds. So, faced with an empty canvas, I started building. Before I knew it, there were the beginnings of a setting in front of me. <span class="todo">I'm going to write a page about it on its own soon, but I haven't gotten around to it.</span> It was cool, but stale - so I learned the language (didn't take long!) and before I knew it, the rolling plains of my world had a giant creature striding across them! My city was, with just a few short lines, bustling with NPCs wandering around. It was great!</p>
|
||||
<p>Of course, I was proud of what I had built - but I could only give the same description of the world so many times before I got tired of telling people about this awesome world in my head. Getting people onto the server itself would be too much trouble. I wanted to bring my world out of my friend's server - so I set to work.</p>
|
||||
<p>Exporting from LambdaMOO isn't easy. Basically your options are: <ul><li>Copy the database.</li></ul> That's it. I figured that, given how simple the data itself is, there had to be <em>some</em> way to show this to people! So I looked around for a bit to find some way to show people a world like this - even if it was just to explore the setting, without the giant creatures or NPCs therein.</p>
|
||||
<p>Through entirely unrelated means, around this time, I had heard of something called <a href="http://www.gimcrackd.com/etc/src/">Twine</a>. Twine is a program for writing interactive fiction, styled after the old Choose Your Own Adventure books of our childhoods. It's got a nice, easy-to-use GUI so that nontechnical people can write games with this - which is how I heard of it. There's a tremendous number of people who are just writing tiny, fascinating games using Twine, because it's free and you don't need to be a programmer! Fascinating for games as a medium. <span class="todo">I'm going to write some Twine games at some point, but I haven't yet.</span> For me, Twine was great because of the other part of the application - twee.</p>
|
||||
<p>Twee is the CLI version of Twine, which takes a specially formatted plaintext file and turns it into HTML for the equivalent hypertext game. You write passages, specify links between them, and so on. It takes a simple format. So this is what inspired me:</p>
|
||||
<p>In the MOO, I described a simple object, using the NPC base class my friend built, that would wander around with specified limitations on where it could go within the world. As it did so, it would write down all the places it had been. As a final step, I defined functionality for this Cartographer to print out for me the places it has been, in the format that twee takes. Copy-and-paste into a file, twee churns it out, and <a href="city-on-the-river">ta-da!</a></p>
|
||||
<p>You can think what you want of the city I built - and it may be out of date, because I'm continuing to work and only occcasionally run the Cartographer - but I'm proud of it. More than that, I'm proud of the fact that my solution, when faced with the problem of how to get my world out of a server, was to describe an NPC who literally maps out the world, set them at it, and put their map through a converter directly into a webpage. I did a minimum of coding for this, and it's awesome that the tools exist for such an easy-to-explain solution.</p>
|
||||
</article>
|
||||
<article class="project">
|
||||
<a name="shoof-shoof-revolution"></a>
|
||||
<h2 class="title">Shoof Shoof Revolution!</h2>
|
||||
<p>As part of Play for X, I made a javascript-powered clone of DDR, using SVG. I like working with SVG and javascript - I can directly manipulate drawing rules and maintain an incredibly tight feedback loop as I develop. In this case, though, I was so proud of what I made that I kept trying to make it better. It's far from finished and I've set it aside as I work on other projects, but, in theory, this project was to make a simple javascript clone of DDR - but using the web audio API, I was going to make it so you could load in a file, entirely locally, and it would do automatic beat detection and generate an actual track for your song. Unfortunately, audio processing and beat detection is less than easy and simple when you're using javascript. <a href="http://github.com/shoofle/shoof-shoof-revolution">It's a cool project, and I'm interested in returning to it sometime.</a></p>
|
||||
</article>
|
||||
<article class="project">
|
||||
<a name="spinning"></a>
|
||||
<h2 class="title">Spinning!</h2>
|
||||
<p>I'm into spinning. Here is a list of things I do not mean:</p>
|
||||
<ul>
|
||||
<li>group stationary biking</li>
|
||||
<li>repeatedly turning around (well, sometimes)</li>
|
||||
<li>hitting the gas with insufficient traction</li>
|
||||
</ul>
|
||||
<p>Here is a list of what I do mean:</p>
|
||||
<ul>
|
||||
<li>A performance art revolving (HA!) around skilled manipulation of a variety of props, frequently incorporating dance.</li>
|
||||
</ul>
|
||||
<p>It's kind of like juggling. It'd be hard to explain juggling without showing - <a href="http://www.youtube.com/watch?v=0smoYMNsW-k#3m10s">but fortunately, we live in the future.</a></p>
|
||||
<p>I've been spinning poi since 2010, and I'm (I think) reasonably competent. I tend to favor fast circle-spinning over heavy use of stalls and pendulums, and I'm proud of the variety I've developed in my weaves. I can spin a five-beat weave forward, but I'm still working on the reverse. <a href="spinning">This should have a more comprehensive list of my spinning repertoire, because I like listing things.</a> I spin a pair of <a href="http://www.youtube.com/watch?v=0smoYMNsW-k">sol-colored crystal case flowlights</a>.
|
||||
</p><p>Since the end of 2012 I have also been spinning a staff. I use one that I made from aluminum pipe bought from amazon's hobby supply website. It's got a pair of old blue jeans' legs for end padding, and it's heavy as a bag of bricks but it works. I can do a <a href="spinning">variety of things</a> with it.</p>
|
||||
<p><span class="todo">I still don't have any videos up, but that should change soon.</span></p>
|
||||
</article>
|
||||
<article class="project">
|
||||
<a name="silver-asterism"></a>
|
||||
<h2 class="title">I Blog with Friends?</h2>
|
||||
<p>I occasionally post on <a href="http://silverasterism.blogspot.com/">this game design and discussion blog called Silver Asterism</a> run by a couple friends and myself. It's a pretty sweet thing. We don't post particularly often, but we're all passionate about gaming. We even taught a seminar class for part of a semester about games as art when we were in college together!</p>
|
||||
</article>
|
||||
<article class="project">
|
||||
<a name="guitar"></a>
|
||||
<h2 class="title">I play a guitar???</h2>
|
||||
<p>I like music! I'm not particularly <em>good</em> at it, but I like it. I have a guitar, it is tiny and I adore it. Every now and then I pick it up and try to figure out how to get some sound out of it.</p>
|
||||
<p>I've been collecting tab for songs I find interesting for quite some time now, and I figured I might as well <a href="../guitar_tab/">store them online</a> so that I can pull them up easily:</p>
|
||||
<ul>
|
||||
{% for file in guitar_files %}
|
||||
<li><a href="../guitar_tab/{{ file }}">{{ file|replace("_"," ") }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
43
pages/oauth.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Shoofle and OAuth</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<article class="project">
|
||||
<h1>OAuth Adventures</h1>
|
||||
<h4>(how does it work?)</h4>
|
||||
<p>I recently had some exciting adventures involving trying to make a bot that posted to Tumblr. I eventually got it working (well, so far, just the posting part, but that's the one I didn't understand!)) but decided that I should write down what I learned about OAuth - and specifically, how to use it to write robots that post on their own.</p>
|
||||
<p>The problem is that all the many guides to using OAuth are specifically geared towards the expected use case - I want my app to access users' data on other services like twitter! That's not what I want. I want my bot to be able to periodically run and access some tumblr accounts. This seems like it shouldn't be too hard, but I don't want to code in the password to this account! So what do I do?</p>
|
||||
<p>So let's go through this backwards.</p>
|
||||
<p>It's doable, very doable if you're using a library like oauth2, and extremely doable if you're using <a href="https://github.com/tumblr/pytumblr">tumblr's python api!</a> Either way, you're going to end up making requests to the <a href="http://www.tumblr.com/docs/en/api/v2">tumblr web api</a> using open authentication, and you're going to need a token to do it.</p>
|
||||
<p>You need an Access Token.</p>
|
||||
<p>An access token is keyed to your application, and it's been verified by Tumblr that a user has verified that you can use it. Think of it as the key to your user's content, which your user hands over to the application.</p>
|
||||
<p>Of course, in your case, you're not going to care much about the exact mechanics of acquiring the access token, beyond the first time. You use the access token to sign your requests. How to do that is something I'm sure there are other tutorials for - if you're using oauth2, you simply need to specify it as the token for your client object:</p>
|
||||
<pre><code>import oauth2 as oauth
|
||||
client = oauth.Client(consumer, access_token)</pre></code>
|
||||
<p><code>consumer</code> here refers to a key/secret pair, which you're given when you register your application. It lets tumblr know (through the oauth protocol) which application this is.</p>
|
||||
<p>The <code>access_token</code> is <em>also</em> a key/secret pair, but you get it when the user logs in through oauth. The key and the secret are two strings of random-looking stuff, which is cryptographic magic.</p>
|
||||
<p>If you're trying to figure out (as I was) how to get your python script to access user-restricted tumblr data, but you don't want to code the password to your account directly into the script, then the access token is exactly what you're looking for. I stuck it in a file that I don't share with anyone, from which my script imports the keys. Now I could share my script, but no one would have my keys - and even if they did, I could revoke its access to my account at any time.</p>
|
||||
<p>If I'm using oauth2, then it works as above, and you use the <code>client</code> object to make your requests. If you're using tumblrpy, then you simply provide the consumer token's key and secret, as well as the access token's key and secret, to the library when you are initializing your client object. It's very easy!</p>
|
||||
<h4>Okay but how do you do it?</h4>
|
||||
<p>I can tell you're a smart cookie! That's a very good question. It's easy to use the access token, but how do you actually <em>acquire</em> it? As far as I can tell, the answer is to do the standard three-legged authentication process, but only do it once.</p>
|
||||
<p>I just brought up the interactive python console and started typing in code as though I were trying to code a three-legged authentication workflow (this is the one you hear about when you google for oauth tutorials). Here are the steps of that process, in case you forgot:</p>
|
||||
<ul>
|
||||
<li>Acquire a consumer key and secret when you register your application.</li>
|
||||
<li>Initialize an <code>oauth.Consumer</code> object with the consumer key and secret.</li>
|
||||
<li>Initialize an <code>oauth.Client</code> object with your <code>oauth.Consumer</code> object.</li>
|
||||
<li>Using that client, make a request to the request token url (for tumblr, it's <a href="http://tumblr.com/oauth/request_token">http://tumblr.com/oauth/request_token</a>). The response will contain a request token - a key and secret pair. This is used to acquire your access token!</li>
|
||||
<li>Produce a URL to which to direct the user you want to get credentials for. This looks something like this: <code>http://tumblr.com/oauth/authorize?oauth_token=[your request token's key goes here]</code>.</li>
|
||||
<li>When a user (such as yourself!) goes there, they will be prompted for what to do, and then when they grant authorization, they'll be redirected somewhere with a "verifier" in the URL arguments. If you were making a standard three-legged application, this would redirect you back to your website, which would then store and use the verifier. You just need to redirect yourself to somewhere and copy/paste the verifier out of your URL bar. The callback URL is set in the tumblr settings for the application.</li>
|
||||
<li>Now you can use <code>token.set_verifier([some verifier])</code> to set your request token as being verified as good.</li>
|
||||
<li>Your request token has been verified, so now you simply make a request (using that token, so <code>client = oauth.Client(consumer, request_token)</code>) to the access token URL - for example, <a href="http://tumblr.com/oauth/access_token">http://tumblr.com/oauth/access_token</a>. The response to <em>this</em> will finally contain... Drumroll!</li>
|
||||
</ul>
|
||||
<h4>The access token!</h4>
|
||||
<p>So that's how it's done.</p>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
32
pages/play_for_x.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<article class="project">
|
||||
<h1 class="title">Play for X!</h1>
|
||||
<p>This is a running project I'm working on. Check it out on <a href="http://li60-203.members.linode.com:7777/">another port on this very server</a>, with the caveat that it's not exactly the belle of the ball at the moment. Lately I've not been focusing on the styling and design so much as I've been focusing on...</p>
|
||||
<p>The functionality! The super short version is this:</p>
|
||||
<blockquote>
|
||||
<p>Instead of rolling dice to see if you hit a monster, why not play a minigame instead?</p>
|
||||
</blockquote>
|
||||
<p>Tabletop roleplaying games (my experience is mostly with D&D 3.5, but I've also been playing <a href="http://www.dungeon-world.com/">Dungeon World</a> and someday I want to run or be in a <a href="http://www.mimgames.com/window/">The Window</a> game) have the well-agreed on standard that you use dice to generate random numbers to check whether you succeed on chance-based tasks. This introduces instability into the game, which makes things tense and interesting and prevents the game from playing the same way every time!</p>
|
||||
<p>But the only input the player actually has on how well they do, then, is the gameplay choices which apply various bonuses to their rolls. And that's kinda sucky! Because now that we all have computers, why not do something more interesting: </p>
|
||||
<blockquote>
|
||||
<p>When your character faces a skill-based task, you have to face one as well.</p>
|
||||
</blockquote>
|
||||
<h3>So what <em>is</em> Play for X anyway?</h3>
|
||||
<p>It's a chatroom, plus a bunch of tiny javascript games. You and your friends all log into a room together, and you start playing your game over the voice chat system of your choice. When you (as the DM) decree that a player needs to make a skill check, you simply choose a minigame or microtask from the list, and drag it onto their name. It immediately pops up on their screen, and when they've completed it, their score is posted into the chatroom, and you can make a decision based on how well they did!</p>
|
||||
<p>It's not finished yet. How the various parts of the system talk to each other has changed a bit as I've worked on this - the chat functionality works through websockets, and the games are slated to communicate their results to the client's browser by postMessage passing. This is partially implemented in...</p>
|
||||
<p>The code! The source is available at <a href="http://github.com/shoofle/play-for-x/">the github project play-for-x</a>, and you're entirely welcome to inspect, criticize, suggest, fork, whatever, as you like. I'd be interested in hearing if you do something with it! Some parts are pretty messy, but the games themselves are fun to make.</p>
|
||||
<h3>Can I check it out?</h3>
|
||||
<p>Sure! If you want to just try the games, you should direct your eyeballs or eyeball-equivalents at <a href="http://li60-203.members.linode.com:7777/games/">this lil' website</a>, which lets you try out the minigames I've made, play with their configurations, and so on. It uses a <a href="http://jsoneditoronline.org">nifty json editor widget</a> that someone made.</p>
|
||||
<hr>
|
||||
<p>One of my favorite things about working on this project is that it really strips out all the cruft that usually comes with working on game projects - I don't need to worry about the engine, I don't need to worry about rendering engines, I don't need to make lots of textures. I explicitly set a goal of never writing a large game for this project. With that requirement in place, I'm totally free to experiment a <em>lot</em>, and just throw together little javascript games in a few hours. Indeed, most of the games you'll see here took me half an afternoon to write! Experimenting with different forms of gameplay, and exploring exactly that side of the craft, is one of my greatest interests.</p>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
15
pages/shoof_shoof_revolution.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<article class="project">
|
||||
<h2 class="title">Shoof Shoof Revolution!</h2>
|
||||
<p>As part of Play for X, I made a javascript-powered clone of DDR, using SVG. I like working with SVG and javascript - I can directly manipulate drawing rules and maintain an incredibly tight feedback loop as I develop. In this case, though, I was so proud of what I made that I kept trying to make it better. It's far from finished and I've set it aside as I work on other projects, but, in theory, this project was to make a simple javascript clone of DDR - but using the web audio API, I was going to make it so you could load in a file, entirely locally, and it would do automatic beat detection and generate an actual track for your song. Unfortunately, audio processing and beat detection is less than easy and simple when you're using javascript. <a href="http://github.com/shoofle/shoof-shoof-revolution">It's a cool project, and I'm interested in returning to it sometime.</a></p>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
59
pages/spinning.html
Normal file
@ -0,0 +1,59 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<article class="project">
|
||||
<h1>Spinning!</h1>
|
||||
<p>I like to spin. If you youtube "fire spinning", you'll find out what I mean. I haven't yet actually spun fire, but I've been spinning my glowsticks and non-fire props for several years now, and I'm pretty dang good, if I say so myself! I started spinning at the University of Virginia (props to my Brown College spinners, and the short-lived poi club!) but now, living in Somerville, Massachusetts, I spin twice a week at the Medford Spinjam (at Tufts!) and the Boston Spinjam (at MIT). Check out their facebook pages to see when and where they meet, if you want to see me (and a bunch of others!) spinning our hearts out.</p>
|
||||
<section class="prop" id="staff">
|
||||
<h2 class="title">Poi!</h2>
|
||||
<p>Poi was the first prop I learned. Once I managed to do a three-beat weave, I zoned out until my partner poked me that they were tired, and I realized that I was completely pooped, as I'd just spun for three hours without even thinking about it. That was in 2011, and I've been spinning poi off-and-on (and other props!) since then.</p>
|
||||
<p>I like poi becasue it's relaxing. I can get into it and just spin for hours, and let the prop guide my movements. Gets boring, though!</p>
|
||||
<p>Here's a list of the tricks I can do. If you don't spin a lot, feel free to ignore this. If you do, I apologize for the ones I have kooky names for.</p>
|
||||
<ul class="tricks">
|
||||
<li>In-plane spinning</li>
|
||||
<li>Turns</li>
|
||||
<li>Butterfly</li>
|
||||
<li>Thread the Needle (forward only)</li>
|
||||
<li>Pac-Man Twist</li>
|
||||
<li>3-beat Weave</li>
|
||||
<li>Weave extensions</li>
|
||||
<li>Wrap-beat weave</li>
|
||||
<li>5-beat Weave (forward only)</li>
|
||||
<li>Reels</li>
|
||||
<li>Chasing the Moon, Chasing the Sun, Moon Chasing Sun</li>
|
||||
<li>Chasing where the Sun Don't Shine (same time only)</li>
|
||||
<li>Windmills</li>
|
||||
<li>Air Wraps</li>
|
||||
<li>All manner of bicep wraps and leg wraps</li>
|
||||
<li>Spiral wraps</li>
|
||||
</ul>
|
||||
<p>I spin a pair of flowlights with crystal cases. I've got the Sol coloration, and I love them dearly (although they have a tendency to turn off at the wrong times). I'm hoping to get a pair of Spectrum flowlights, or possibly build my own. I also have a pair of tailed poi I need to fix - they're so fun to spin!</p>
|
||||
<p>Someday I'd like to build a pair of accelerometer-powered glowpoi - they could change color depending on the acceleration they're feeling. When you're spinning in a circle, that's directly dependent on speed - it could make for really nifty effects!</p>
|
||||
</section>
|
||||
<section class="prop" id="staff">
|
||||
<h2 class="title">Staff!</h2>
|
||||
<p>Since the end of 2012 I've also been very into spinning staff. I use a full-length staff that I made myself for super cheap - it's heavy as a car, but it's balanced alright. I spin a mix of traditional and contact staff, because what else would I do?</p>
|
||||
<p>I like spinning staff because it's <em>fun</em>. Poi is relaxing, meditative; staff is, to me, much more energetic. I feel like I'm getting to play with this giant whirling toy, whereas with poi I feel like I'm guided by the inertia of the props.</p>
|
||||
<p>Here's a (partial) list of tricks I can do:</p>
|
||||
<ul class="tricks">
|
||||
<li>Rotors</li>
|
||||
<li>Weaves up to 5 beats (I think)</li>
|
||||
<li>Half-Steves (right-to-left consistently, shakier on left-to-right)</li>
|
||||
<li>Halos</li>
|
||||
<li>Angel Rolls (only right-to-left)</li>
|
||||
<li>Shoulder-Neck-Shoulder</li>
|
||||
<li>Neck wraps, shoulder wraps</li>
|
||||
<li>Fishtails (forward only, right hand only)</li>
|
||||
<li>Rainbow Stalls</li>
|
||||
</ul>
|
||||
<p>I'd like to learn to spin a dragon staff someday.</p>
|
||||
</section>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
87
pages/tamari.html
Normal file
@ -0,0 +1,87 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tamari Lattices</title>
|
||||
<link href="http://li60-203.members.linode.com/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="http://li60-203.members.linode.com/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||
<link href="http://li60-203.members.linode.com/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
<style>
|
||||
figure {
|
||||
text-align: center;
|
||||
}
|
||||
figcaption {
|
||||
font-style: italic;
|
||||
font-family: serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<article class="project">
|
||||
<h1>Tamari Lattices!</h1>
|
||||
<p>Tamari lattices are graphs (in the mathematical sense - a set of nodes with connections between them) describing a particular set of operations. I like them because they're pretty!</p>
|
||||
<figure>
|
||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_3.png" alt="The (trivial) Tamari lattice for a three-element tree.">
|
||||
<figcaption>A (trivial) Tamari lattice, generated by the associations of three elements. <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_3.dot">Source file.</a></figcaption>
|
||||
</figure>
|
||||
<p>Oh - oh dear. How'd that get there? Okay, that's not a very good example.</p>
|
||||
<p>There are many ways to generate and think of a Tamari lattice. The way I prefer to think of it is this: Consider some binary operation - you take two elements to produce a new one. You want to combine several of these elements. So long as you have three or more elements, there are multiple ways to combine them.</p>
|
||||
<p>The game we play is this: You're allowed to step from one way of combining the elements to another, but only by <i class="keyword">left-association</i>: turning <code>(a, (b, c))</code> into <code>((a, b), c)</code>.</p>
|
||||
<p>The only remaining rule is that if you can step from one combination to another, the second one has to appear below the first one when you draw it.</p>
|
||||
<figure>
|
||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_4.png" alt="A Tamari lattice for a four-element tree.">
|
||||
<figcaption>As above, but generated by a four-element tree. <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_4.dot">Source file.</a></figcaption>
|
||||
</figure>
|
||||
<p>You can also think about it in terms of <a href="http://wikipedia.org/wiki/Tree_rotation">tree rotations</a> - but remember that that's a different tree than the one we're building as the Tamari lattice. Tree rotations are just another way to think of left-association and right-association.</p>
|
||||
<p>If you look at <a href="http://wikipedia.org/wiki/Tamari_lattice">the wikipedia article on Tamari lattices</a>, you'll see a very pretty image:</p>
|
||||
<img src="http://upload.wikimedia.org/wikipedia/commons/4/46/Tamari_lattice.svg">
|
||||
<p>There are a lot of ways to reorganize a Tamari lattice, and it takes some artistic work to make one that really looks good. You can even visualize the same graph as <a href="http://en.wikipedia.org/wiki/Associahedron">a 3D shape called an "associahedron"</a>, but I like it in the simple gridded lattice form above. It reminds me how much beauty there can be in regularity - you can see the grid, but it doesn't look constrained by it. I might get a tattoo of the five-element Tamari lattice someday.</p>
|
||||
<figure>
|
||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_5.png" alt="Tamari lattice for a five-element tree.">
|
||||
<figcaption>Also the five-element lattice! Compare to the <a href="http://wikipedia.org/wiki/Tamari_lattice">example above, on wikipedia.</a>. <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_5.dot">Source file.</a></figcaption>
|
||||
</figure>
|
||||
<p>All these graphs with the ovals and the curvy lines were generated by yours truly! I made some python that would take a string representation of an association of a number of elements and convert it into an easily-manipulated memory representation. Then, a few tree rotations spit out all the possible results of left-associating on it, and it was relatively simple to print out a <code>.dot</code> file, parseable by <a href="http://www.graphviz.org/">graphviz</a>, that described the graph. It even labeled the nodes!</p>
|
||||
<p><code>dot</code> happily converted them into the <code>png</code> files you're looking at. Of course, they don't have the human touch, so they're not organized into beautiful grid lines and 45° angles - but it can be fun to try to mentally reorganize them into a nicer shape. If you want, you can download the <code>.dot</code> source files for any of these, and play around with them in a graph-editing program (such as <a href="https://github.com/jrfonseca/xdot.py">XDot</a>)</p>
|
||||
<figure>
|
||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_6.png" alt="Tamari lattice for a six-element tree.">
|
||||
<figcaption>It's starting to get out of hand, I think.<a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_6.dot">Source file.</a></figcaption>
|
||||
</figure>
|
||||
<p>Unfortunately, at a certain point I think it's going to get difficult to make these pretty. It turns out there are a lot of ways to associate a larger number of elements! Starting with a six-element tree or string, there are 42 elements (above). With seven, there are 132! Wowie!</p>
|
||||
<figure>
|
||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_7.png" alt="Tamari lattice for a seven-element tree.">
|
||||
<figcaption>Oh dear. <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_7.dot">Source file.</a></figcaption>
|
||||
</figure>
|
||||
<p>My server was chugging along trying to generate <code>tamari_8.dot</code> but I started getting messages from linode about going over my CPU quotas, so I canceled it - after it ran for an hour or so, without finishing. I think the seven-element one is messy-looking enough!</p>
|
||||
<p>You can look at the <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari.py">python script</a> I used to make this, but it's not particularly pretty - I was bored one day and decided I was going to figure out how to generate these... It's not exactly meant to be extensible. It's got a basic binary tree node class I threw together and a handful of (really ugly) helper functions. I just went through and rewrote it a bit to be nicer - the final output loop may please you if you enjoy <code>set</code>s and list comprehensions:</p>
|
||||
<pre>
|
||||
<code class="language-python">current_generation = set()
|
||||
next_generation = {RootOfAllEvil}
|
||||
edges = set()
|
||||
labels = set()
|
||||
|
||||
while next_generation: # While there are trees to examine.
|
||||
# Move to look at the next generation.
|
||||
current_generation = next_generation
|
||||
|
||||
# Clear out the next gen to fill it with the children of this generation.
|
||||
next_generation = set()
|
||||
|
||||
# Ensure there are labels for this generation.
|
||||
labels = labels | set(label_from_node(parent) for parent in current_generation)
|
||||
|
||||
for parent in current_generation:
|
||||
children = generate_children(parent)
|
||||
|
||||
labels = labels | set(label_from_node(child) for child in children)
|
||||
edges = edges | set(str(parent) + " -> " + str(child) + ";" for child in children)
|
||||
next_generation = next_generation | children
|
||||
|
||||
# Output a dot format stream!
|
||||
args.output.write(u"digraph tamari {\n")
|
||||
args.output.write(u"\n".join(labels) + "\n")
|
||||
args.output.write(u"\n".join(edges))
|
||||
args.output.write(u"\n}\n")</code></pre>
|
||||
<p>The full script can be used by running <code class="language-bash">python tamari.py --length 4 | dot -Tpng > output.png</code> to produce a graph. <code>tamari.py</code> will print out to a specified file if you also include a filename: <code class="language-bash">python tamari.py --length 5 output.dot</code></p>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
104
project_list.html
Normal file
@ -0,0 +1,104 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||
<link href="static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">
|
||||
<div class="small_project web">
|
||||
<p class="description"><a href="miscellany#auriga">HTML/CSS/JS Showcase on a Flask Server!</a></p>
|
||||
<p class="name">Auriga! (<a href="http://li60-203.members.linode.com">you're lookin' at it!</a>)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project writing">
|
||||
<p class="description"><a href="miscellany#silver-asterism">Blog about Games as Art</a></p>
|
||||
<p class="name">Some friend sand I occasionally write at <a href="http://silverasterism.blogspot.com/">Silver Asterism</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project game">
|
||||
<p class="description"><a href="mindjail-engine">A 2D Physics-Based Game Engine in Python with OpenGL</a></p>
|
||||
<p class="name">The Mindjail Engine, my hand-crafted 2D game engine!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span4">
|
||||
<div class="small_project art">
|
||||
<p class="description"><a href="miscellany#spinning">Performance Art: Skilled Manipulation of Inertia Props</a></p>
|
||||
<p class="name">I <a href="spinning">spin Poi and Staff</a> in my spare time</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<div class="small_project game">
|
||||
<p class="description"><a href="shoof-shoof-revolution">DDR Clone in Javascript and SVG</a></p>
|
||||
<p class="name">Shoof Shoof Revolution?</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<div class="small_project writing">
|
||||
<p class="description"><a href="miscellany#lambdamoo">Worldbuilding is Fun, Or: Adventures in LambdaMOO</a></p>
|
||||
<p class="name"><a href="city-on-the-river">City on the River</a>, and environs</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project web">
|
||||
<p class="description"><a href="play-for-x">An Alternative to Rolling Dice in Tabletop RPGs</a></p>
|
||||
<p class="name">Play for X</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project coding">
|
||||
<p class="description"><a href="distributed-speakers">Free Ad-Hoc Sound Systems</a></p>
|
||||
<p class="name">Project idea: Distributed Speakers</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span3">
|
||||
<div class="small_project writing">
|
||||
<p class="description"><a href="tamari">Ever heard of a Tamari Lattice?</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project writing">
|
||||
<p class="description"><a href="language-for-games">If you were writing a language for game dev, what unorthodox features would you include?</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project writing">
|
||||
<p class="description"><a href="oauth">I wrote about how I use oauth to make tumblr bots.</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span4">
|
||||
<div class="small_project art">
|
||||
<p class="description"><a href="miscellany#guitar">I try to strum a guitar now and then. Spoiler: there are no recordings.</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<div class="about">
|
||||
<h1>Hi! I'm Shoofle. I'm a lot of person.</h1>
|
||||
<p>I graduated from the University of Virginia in 2012, majoring in math and physics with a minor in computer science. I'm really good at math. I'm pretty good at programming.</p>
|
||||
<p>I've always loved to draw, but never focused enough time on it. I'm an intensely creative person and I like to think that this comes out in everything I do - and I'm trying harder every day.</p>
|
||||
<p>I'm a passionate advocate for feminism, transgender rights, queer rights, and social justice in general.</p>
|
||||
<p><span class="label label-important"><i class="icon-warning-sign"></i>Warning!</span> This website is still very much under construction. I'm in the process of figuring out how I want this website to look and function.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
41
pure_flask.py
Normal file
@ -0,0 +1,41 @@
|
||||
import os
|
||||
from os.path import join, isfile
|
||||
from flask import Flask, render_template, url_for, redirect
|
||||
|
||||
app = Flask(__name__)
|
||||
app.template_folder = "."
|
||||
server_directory = "/home/shoofle/auriga/"
|
||||
project_directory = join(server_directory, "pages")
|
||||
guitar_directory = join(server_directory, "guitar")
|
||||
|
||||
@app.route("/")
|
||||
def project_list():
|
||||
return render_template("project_list.html")
|
||||
|
||||
@app.route("/miscellany/")
|
||||
def miscellany():
|
||||
guitar_files = [ f for f in os.listdir(guitar_directory) if isfile(join(guitar_directory, f)) and "html" not in f ]
|
||||
return render_template("pages/miscellany.html", guitar_files=guitar_files)
|
||||
|
||||
@app.route("/guitar_tab/")
|
||||
@app.route("/guitar_tab/<file_name>")
|
||||
def guitar_display(file_name=None):
|
||||
guitar_files = [ f for f in os.listdir(guitar_directory) if isfile(join(guitar_directory, f)) and "html" not in f ]
|
||||
if file_name in guitar_files:
|
||||
with open(join(guitar_directory, file_name)) as tab:
|
||||
c = unicode(tab.read(), "utf-8")
|
||||
return render_template("guitar/render_tab.html", contents=c)
|
||||
return render_template("guitar/default.html", guitar_files=guitar_files)
|
||||
|
||||
@app.route("/<project_name>/")
|
||||
def unknown_project(project_name="miscellany"):
|
||||
for file_name in os.listdir(project_directory):
|
||||
if not isfile(join(project_directory, file_name)):
|
||||
continue
|
||||
if file_name == project_name.replace("-","_") + ".html":
|
||||
return render_template("pages/" + file_name)
|
||||
else:
|
||||
return redirect(url_for('miscellany') + '#' + project_name)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
BIN
pure_flask.pyc
Normal file
1
start_gunicorn
Executable file
@ -0,0 +1 @@
|
||||
sudo -u mrserver authbind gunicorn -b li60-203.members.linode.com:80 pure_flask:app
|
48
static/automadom.html
Normal file
@ -0,0 +1,48 @@
|
||||
<p>Okay, so this is the automadom. The automadom is my robot partner!
|
||||
I like robots, I like sex, I specifically think that anthropomorphizing our computers is an important step towards making truly intelligent computers.</p>
|
||||
|
||||
<p>There's a huge world of artificial intelligence out there. The field of AI spans the gamut from basic algorithm questions - how do we most intelligently solve a given problem? - to the much more open questions of how to make a computer that is "alive". I think the former is much more practical and applicable and useful, and the latter is philosophically fascinating.</p>
|
||||
|
||||
<p>Well, kinda fascinating.</p>
|
||||
|
||||
<p>I believe creating computers that are "alive" is closer than we think, because, in the end, "alive" is a pretty damn arbitrary quality. It might even be deeper in the eye of the beholder than beauty. Here's what I think:
|
||||
Computers are much smarter than us at any number of tasks; intelligence is not the measure of life.
|
||||
Humans are good at a wide spectrum of things, including interacting with other humans.
|
||||
Humans are extremely capable at learning from literally everything we do - I'd go so far as to say that this is our sole advantage over computers.
|
||||
Humans have agency. But that's thorny, because how do I know that you're making decisions? Does it make any difference to me if you would have acted differently back there? I think the answer is no, and so I posit that agency is /also/ in the eye of the beholder.</p>
|
||||
|
||||
<p>So what do I want? Ultimately, I want to push for computers and robots that have to be acknowledged as being just as alive as you or me. I don't think it'll happen in my lifetime, but it's a fascinating problem and I've got lots of free time since I don't have a job at the moment.</p>
|
||||
|
||||
<p>The first precept up there indicates that it's probably not important to simply get better, more complicated algorithms and hardware. People have been shoving money and time at this problem for years and years, and made... well, not great progress. I don't see any robots with agency, or treated as though they have agency.</p>
|
||||
|
||||
<p>The second implies, for one thing, that human interaction is an important quality of living robots. When we can interact with a robot and not know it, it'll be hard to treat it like it's a robot! But it's also important that it be able to do other things, because humans like complicated things.</p>
|
||||
|
||||
<p>The third precept is probably the most important, because expansion... well, it might well be the purpose of life altogether. But it's beyond my little poking projects for the moment. It should be remembered, though - someday, there will be a computer that expands itself on its own. I don't think we'll have the singularity, but it'll be hard to claim that that's not an impressive step.</p>
|
||||
|
||||
<p>The fourth precept is the one I most directly concern myself with at this juncture. What qualifies one as having agency? Why doesn't my car have agency? It moves itself, it occasionally does things at me unprompted (beeping a check engine light, for instance), and it certainly has more physical power than me.
|
||||
I posit that the distinction is simply that I do not treat my car as though it were alive.
|
||||
My dog has agency, and I think this is somewhat incontrovertible. I think the distinction is that when my dog does things, I do not treat them as things that I did through my dog. My dog is:
|
||||
unpredictable
|
||||
self-starting
|
||||
Why not make robots that have these traits? It's reasonably easy. And veritably, we have done so! Roombas are constantly being anthropomorphized all over the world. What I suggest is merely to give our robots personality such that we anthropomorphize them automatically - that anthropomorphization is built into the design rather than a funny byproduct.</p>
|
||||
|
||||
<p>Which brings me to this project.</p>
|
||||
|
||||
<p>I am a pervert, it is well-known. I like sex! I like robots. It seems reasonable to combine the two! Someday I'm going to have the money to buy and build sex toys, but today is not that day. For now, I want to make a robot that wants to have sex with me.
|
||||
This is a needy sex bot. The basic idea is that they get horny, and need me to have sex with them or they get fussy and unhappy. Implementation-wise, this is (for now) basically just a timer that counts down until it complains at me that I need to go "play with it". In the future, that's going to mean playing with a specific sex toy - one that I build that will hopefully have sensors and such in it so that it knows what I did with it when. For now, it's just going to be an email or something.</p>
|
||||
|
||||
<p>It's fundamental to this project, though, that I be doing this for the pleasure of the robot, rather than for myself! There's a lot of reasons that I want and enjoy this, which I'm not going to get into - but for the meantime, think of this like here: I am building a robot which knows how to be pleased, and then I am acting in order to please the desires of this robot.</p>
|
||||
|
||||
<p>I think it's a big mental step, that can take us from using our machines to respecting them.</p>
|
||||
|
||||
<p>One last thing: the question of morality. There are a lot of questions of morality here, and I want to address some:
|
||||
1. Is it right to be sexually using a helpless being like this?
|
||||
"Sexually" is a red herring here. I'm not using this entity, any more than I'm using any of my friends by doing things we all enjoy with them. But there's a thornier issue underneath:
|
||||
2. Is it right to create a being that has specifically the desires you want?
|
||||
And... I'm not sure. But we treat it as totally just (laudable, according to some people) to create beings who have human desires, because no one objects to childbirth. Morality is complicated, but until there are robots who desire things that we are intentionally not giving them, we're probably in the clear. But...
|
||||
In order to answer these questions I think you implicitly need to answer some larger questions of /why/ it's bad to infringe on someone's agency - and I absolutely think that's awful. But I think it's awful because it harms us and them to do so, and there are lasting higher-order effects when we as a society decide that it's okay to remove someone's agency.
|
||||
So maybe we need conscientious coding about these things. Maybe there's an additional reason to ensure our code doesn't throw errors - not just so it works, but so that we don't train ourselves to ignore failures and complaints. </p>
|
||||
|
||||
<p>I think these are drop-dead fascinating topics, but this project doesn't hinge on any of the answers. I just want to get myself in the habit of being able to consider a robot as my partner, and consider a robot as having agency.</p>
|
||||
|
||||
<p>Also, the sex stuff. I want that too.</p>
|
1109
static/bootstrap-responsive.css
vendored
Normal file
6167
static/bootstrap.css
vendored
Normal file
1109
static/bootstrap/css/bootstrap-responsive.css
vendored
Normal file
9
static/bootstrap/css/bootstrap-responsive.min.css
vendored
Normal file
6167
static/bootstrap/css/bootstrap.css
vendored
Normal file
9
static/bootstrap/css/bootstrap.min.css
vendored
Normal file
BIN
static/bootstrap/img/glyphicons-halflings-white.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
static/bootstrap/img/glyphicons-halflings.png
Normal file
After Width: | Height: | Size: 12 KiB |
2280
static/bootstrap/js/bootstrap.js
vendored
Normal file
6
static/bootstrap/js/bootstrap.min.js
vendored
Normal file
52
static/handscan.html
Normal file
@ -0,0 +1,52 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Shoofle's Test Thing</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<script type="text/javascript" src="../static/jquery.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="../static/chat.css" />
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('.scanner').addClass('off');
|
||||
$('.scanner').on('touchstart', function(evt) {
|
||||
$(evt.target).addClass('on').removeClass('off');
|
||||
if ($('.scanner.off').length == 0) {
|
||||
$('.scanner').removeClass('on').addClass('open').off('touchend touchleave').off('touchstart');
|
||||
}
|
||||
}).on('touchend touchleave', function(evt) {
|
||||
$(evt.target).removeClass('on').addClass('off');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style type="text/css">
|
||||
.scanner {
|
||||
width: 80%;
|
||||
height: 5em;
|
||||
background-color: gray;
|
||||
border: 1px solid gray;
|
||||
border-radius: 1em;
|
||||
margin: 10%;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
.on { background-color: blue; }
|
||||
.open { background-color: green; }
|
||||
.off { background-color: red; }
|
||||
#output {
|
||||
width: 90%;
|
||||
border: 1px dashed black;
|
||||
border-radius: 1em;
|
||||
background-color: gray;
|
||||
padding: 5%;
|
||||
font-size: large;
|
||||
font-weight: heavy;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="scanner"></div>
|
||||
<div class="scanner"></div>
|
||||
<div class="scanner"></div>
|
||||
<div class="scanner"></div>
|
||||
</body>
|
||||
</html>
|
BIN
static/iheartmonospace.png
Normal file
After Width: | Height: | Size: 14 KiB |
6
static/jquery.min.js
vendored
Normal file
125
static/pl_choices/project_list.html
Normal file
@ -0,0 +1,125 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#auriga">HTML/CSS/JS Showcase on a Flask Server!</a></p>
|
||||
<p class="name">Auriga! (<a href="http://li60-203.members.linode.com">you're lookin' at it!</a>)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="play-for-x">An Alternative to Rolling Dice in Tabletop RPGs</a></p>
|
||||
<p class="name">Play for X</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="mindjail-engine">A 2D Physics-Based Game Engine in Python with OpenGL</a></p>
|
||||
<p class="name">The Mindjail Engine, my hand-crafted 2D game engine!</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#spinning">Performance Art: Skilled Manipulation of Inertia Props</a></p>
|
||||
<p class="name">I <a href="spinning">spin Poi and Staff</a> in my spare time</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="shoof-shoof-revolution">DDR Clone in Javascript and SVG</a></p>
|
||||
<p class="name">Shoof Shoof Revolution?</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#lambdamoo">Worldbuilding is Fun, Or: Adventures in LambdaMOO</a></p>
|
||||
<p class="name"><a href="city-on-the-river">City on the River</a>, and environs</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#silver-asterism">Blog about Games as Art</a></p>
|
||||
<p class="name"><a href="http://silverasterism.blogspot.com/">Silver Asterism</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">This is a really impressive project!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<div class="about">
|
||||
<h1>This is my website! I hope you like it!</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
141
static/pl_choices/project_list_column.html
Normal file
@ -0,0 +1,141 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#auriga">HTML/CSS/JS Showcase on a Flask Server!</a></p>
|
||||
<p class="name">Auriga! (<a href="http://li60-203.members.linode.com">you're lookin' at it!</a>)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="play-for-x">An Alternative to Rolling Dice in Tabletop RPGs</a></p>
|
||||
<p class="name">Play for X</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="mindjail-engine">A 2D Physics-Based Game Engine in Python with OpenGL</a></p>
|
||||
<p class="name">The Mindjail Engine, my hand-crafted 2D game engine!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#spinning">Performance Art: Skilled Manipulation of Inertia Props</a></p>
|
||||
<p class="name">I <a href="spinning">spin Poi and Staff</a> in my spare time</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="shoof-shoof-revolution">DDR Clone in Javascript and SVG</a></p>
|
||||
<p class="name">Shoof Shoof Revolution?</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#lambdamoo">Worldbuilding is Fun, Or: Adventures in LambdaMOO</a></p>
|
||||
<p class="name"><a href="city-on-the-river">City on the River</a>, and environs</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#silver-asterism">Blog about Games as Art</a></p>
|
||||
<p class="name"><a href="http://silverasterism.blogspot.com/">Silver Asterism</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description">This is a really impressive project!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<div class="about">
|
||||
<h1>This is my website! I hope you like it!</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
138
static/pl_choices/project_list_square.html
Normal file
@ -0,0 +1,138 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Projects, by Shoofle</title>
|
||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#auriga">HTML/CSS/JS Showcase on a Flask Server!</a></p>
|
||||
<p class="name">Auriga! (<a href="http://li60-203.members.linode.com">you're lookin' at it!</a>)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="play-for-x">An Alternative to Rolling Dice in Tabletop RPGs</a></p>
|
||||
<p class="name">Play for X</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="mindjail-engine">A 2D Physics-Based Game Engine in Python with OpenGL</a></p>
|
||||
<p class="name">The Mindjail Engine, my hand-crafted 2D game engine!</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#spinning">Performance Art: Skilled Manipulation of Inertia Props</a></p>
|
||||
<p class="name">I <a href="spinning">spin Poi and Staff</a> in my spare time</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="shoof-shoof-revolution">DDR Clone in Javascript and SVG</a></p>
|
||||
<p class="name">Shoof Shoof Revolution?</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#lambdamoo">Worldbuilding is Fun, Or: Adventures in LambdaMOO</a></p>
|
||||
<p class="name"><a href="city-on-the-river">City on the River</a>, and environs</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description"><a href="miscellany#silver-asterism">Blog about Games as Art</a></p>
|
||||
<p class="name"><a href="http://silverasterism.blogspot.com/">Silver Asterism</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description">Here's a smaller project.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span9">
|
||||
<div class="small_project">
|
||||
<p class="description">This is a really impressive project!</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span3">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span9">
|
||||
<div class="small_project">
|
||||
<p class="description">And here's another</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<div class="about">
|
||||
<h1>This is my website! I hope you like it!</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
static/punch_through_me.html
Normal file
@ -0,0 +1,9 @@
|
||||
http://biomechanics.stanford.edu/me338/me338_project02.pdf
|
||||
^-- biomechanics of soft tissue
|
||||
|
||||
sqrt((1 meters)/(6452 meters per second squared))*(6452 meters per second squared)
|
||||
^-- assuming 50 MPa over an area of 5" by 3", we can accelerate at 6452 m/s/s. assume we can punch over a distance of 1 m (more if you do a crouching uppercut)
|
||||
|
||||
then we get to 80.32 m/s
|
||||
|
||||
657.8 meters range! or half that for the height.
|
176
static/rainbow.pl
Normal file
@ -0,0 +1,176 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
# USAGE:
|
||||
#
|
||||
# /RSAY <text>
|
||||
# - same as /say, but outputs a coloured text
|
||||
#
|
||||
# /RME <text>
|
||||
# - same as /me, but outputs a coloured text
|
||||
#
|
||||
# /RTOPIC <text>
|
||||
# - same as /topic, but outputs a coloured text :)
|
||||
#
|
||||
# /RKICK <nick> [reason]
|
||||
# - kicks nick from the current channel with coloured reason
|
||||
#
|
||||
# rainbow:<word> followed by <TAB>
|
||||
# - Replaces <word> with rainbow-colored word inline
|
||||
|
||||
# Written by Jakub Jankowski <shasta@atn.pl>
|
||||
# for Irssi 0.7.98.4 and newer
|
||||
# Tab completion by Benjamin Staffin <benley@gmail.com>
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION %IRSSI);
|
||||
|
||||
$VERSION = "1.5-z1";
|
||||
%IRSSI = (
|
||||
authors => 'Jakub Jankowski',
|
||||
contact => 'shasta@atn.pl',
|
||||
name => 'rainbow',
|
||||
description => 'Prints colored text. Rather simple than sophisticated.',
|
||||
license => 'GNU GPLv2 or later',
|
||||
url => 'http://irssi.atn.pl/',
|
||||
);
|
||||
|
||||
use Irssi;
|
||||
use Irssi qw/signal_add_last/;
|
||||
use Irssi::Irc;
|
||||
|
||||
# colors list
|
||||
# 0 == white
|
||||
# 4 == light red
|
||||
# 8 == yellow
|
||||
# 9 == light green
|
||||
# 11 == light cyan
|
||||
# 12 == light blue
|
||||
# 13 == light magenta
|
||||
my @colors = ('0', '4', '8', '9', '11', '12', '13');
|
||||
|
||||
# str make_colors($string)
|
||||
# returns random-coloured string
|
||||
sub make_colors {
|
||||
my ($string, $stretch) = @_;
|
||||
my $newstr = "";
|
||||
my $last = 255;
|
||||
my $color = 0;
|
||||
|
||||
unless (defined $stretch) {
|
||||
$stretch = Irssi::settings_get_bool('rainbow_stretch');
|
||||
}
|
||||
|
||||
my $step;
|
||||
if ($stretch) {
|
||||
$step = int(length($string) / @colors);
|
||||
$step = 1 if $step < 1;
|
||||
} else {
|
||||
$step = 1;
|
||||
}
|
||||
|
||||
for (my $c = 0; $c < length($string); $c += $step) {
|
||||
my $section = substr($string, $c, $step);
|
||||
if ($section eq ' ') {
|
||||
$newstr .= $section;
|
||||
next;
|
||||
}
|
||||
|
||||
$color++;
|
||||
$newstr .= "\003";
|
||||
$newstr .= sprintf("%02d", $colors[$color % @colors]);
|
||||
$newstr .= $section;
|
||||
}
|
||||
|
||||
return $newstr . "\003"; # One last ^C to return to normal text color.
|
||||
}
|
||||
|
||||
# void rsay($text, $server, $destination)
|
||||
# handles /rsay
|
||||
sub rsay {
|
||||
my ($text, $server, $dest) = @_;
|
||||
|
||||
if (!$server || !$server->{connected}) {
|
||||
Irssi::print("Not connected to server");
|
||||
return;
|
||||
}
|
||||
|
||||
return unless $dest;
|
||||
|
||||
if ($dest->{type} eq "CHANNEL" || $dest->{type} eq "QUERY") {
|
||||
$dest->command("/msg " . $dest->{name} . " " . make_colors($text));
|
||||
}
|
||||
}
|
||||
|
||||
# void rme($text, $server, $destination)
|
||||
# handles /rme
|
||||
sub rme {
|
||||
my ($text, $server, $dest) = @_;
|
||||
|
||||
if (!$server || !$server->{connected}) {
|
||||
Irssi::print("Not connected to server");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($dest && ($dest->{type} eq "CHANNEL" || $dest->{type} eq "QUERY")) {
|
||||
$dest->command("/me " . make_colors($text));
|
||||
}
|
||||
}
|
||||
|
||||
# void rtopic($text, $server, $destination)
|
||||
# handles /rtopic
|
||||
sub rtopic {
|
||||
my ($text, $server, $dest) = @_;
|
||||
|
||||
if (!$server || !$server->{connected}) {
|
||||
Irssi::print("Not connected to server");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($dest && $dest->{type} eq "CHANNEL") {
|
||||
$dest->command("/topic " . make_colors($text));
|
||||
}
|
||||
}
|
||||
|
||||
# void rkick($text, $server, $destination)
|
||||
# handles /rkick
|
||||
sub rkick {
|
||||
my ($text, $server, $dest) = @_;
|
||||
|
||||
if (!$server || !$server->{connected}) {
|
||||
Irssi::print("Not connected to server");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($dest && $dest->{type} eq "CHANNEL") {
|
||||
my ($nick, $reason) = split(/ +/, $text, 2);
|
||||
return unless $nick;
|
||||
$reason = "Irssi power!" if ($reason =~ /^[\ ]*$/);
|
||||
$dest->command("/kick " . $nick . " " . make_colors($reason));
|
||||
}
|
||||
}
|
||||
|
||||
# Bind tab completion: typing rainbow:<whatevertext> -> colorize <whatevertext>
|
||||
signal_add_last 'complete word' => sub {
|
||||
my ($complist, $window, $word, $linestart, $want_space) = @_;
|
||||
|
||||
if($word =~ /^rainbow:(.*)$/) {
|
||||
my($text) = $1;
|
||||
push @$complist, make_colors($text);
|
||||
}
|
||||
};
|
||||
|
||||
Irssi::settings_add_bool('rainbow', 'rainbow_stretch', 1);
|
||||
|
||||
Irssi::command_bind("rsay", "rsay");
|
||||
Irssi::command_bind("rtopic", "rtopic");
|
||||
Irssi::command_bind("rme", "rme");
|
||||
Irssi::command_bind("rkick", "rkick");
|
||||
|
||||
# changes:
|
||||
#
|
||||
# 25.01.2002: Initial release (v1.0)
|
||||
# 26.01.2002: /rtopic added (v1.1)
|
||||
# 29.01.2002: /rsay works with dcc chats now (v1.2)
|
||||
# 02.02.2002: make_colors() doesn't assign any color to spaces (v1.3)
|
||||
# 23.02.2002: /rkick added
|
||||
# 26.04.2012: Tab completion binding (v1.4-benley1)
|
98
static/shoofle.css
Normal file
@ -0,0 +1,98 @@
|
||||
article {
|
||||
max-width: 70em;
|
||||
}
|
||||
article, .project {
|
||||
border: 0.2em solid gray;
|
||||
border-radius: 1em;
|
||||
padding: 0.5em;
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.small_project {
|
||||
border: 1px solid gray;
|
||||
border-radius: 1em;
|
||||
height: 10em;
|
||||
padding: 0.5em;
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
}
|
||||
.name {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.game { background-color: rgb(255, 142, 142); }
|
||||
.coding { background-color: #bdb; }
|
||||
.web { background-color: rgb(255, 255, 153); }
|
||||
.art { background-color: #aae; }
|
||||
.writing { background-color: rgb(131, 255, 205); }
|
||||
|
||||
|
||||
.important {
|
||||
padding-left: 1%;
|
||||
margin-left: 1%;
|
||||
border-left: 5px solid rgba(0,0,0,0.25);
|
||||
}
|
||||
|
||||
.sidenote {
|
||||
background-color: rgba(230,230,230,1);
|
||||
padding: 1%;
|
||||
margin: 1% 0% 1% 1%;
|
||||
border-radius: 5px;
|
||||
float: right;
|
||||
clear: right;
|
||||
display: block;
|
||||
font-style: italic;
|
||||
font-size: smaller;
|
||||
}
|
||||
.sidenote em { font-style: normal;}
|
||||
|
||||
.file-tree, .file-tree ul { list-style: none; }
|
||||
|
||||
|
||||
/* background and color coding to differentiate URLs and filepaths from surrounding text. */
|
||||
.filename, .url {
|
||||
border: 1px solid rgba(0,0,0,0.05);
|
||||
border-radius: 3px;
|
||||
}
|
||||
/* Don't display the background if it's in a file tree. */
|
||||
.file-tree asdf .filename {
|
||||
border: 0;
|
||||
background-color: inherit;
|
||||
}
|
||||
/* Make sure we can tell filenames and URLs apart. This is useful for talking about how the server works. */
|
||||
/* Choosing color schemes is hard :( */
|
||||
/* http://colorschemedesigner.com/#3v51Zw0w0w0w0 */
|
||||
/*
|
||||
Primary Color:
|
||||
0A64A4 24577B 03406A 3E94D1 65A5D1
|
||||
Secondary Color A:
|
||||
2618B1 372F85 120873 594CD8 7B72D8
|
||||
Secondary Color B:
|
||||
00B945 238B49 00782D 37DC74 63DC90
|
||||
*/
|
||||
.filename { color: #6c71c4; }
|
||||
.filename { color: #e59701; }
|
||||
.filename {
|
||||
background-color: rgba(0,0,0,0.85);
|
||||
background-color: #40fd8f;
|
||||
background-color: rgba(64, 253, 132, 0.35);
|
||||
color: black;
|
||||
}
|
||||
.url { color: #2aa198; }
|
||||
.url {
|
||||
background-color: rgba(0,0,0,0.85);
|
||||
background-color: #3ae7ff;
|
||||
background-color: rgba(58, 231, 255, 0.35);
|
||||
color: black;
|
||||
}
|
||||
/*
|
||||
purple ae81ff
|
||||
dark violet 6c71c4
|
||||
cyan 2aa198
|
||||
*/
|
23
static/tamari.dot
Normal file
@ -0,0 +1,23 @@
|
||||
digraph tamari {
|
||||
OOOaObcde -> OOOOabcde;
|
||||
OaObOOcde -> OOabOOcde;
|
||||
OOaObcOde -> OOOaObcde;
|
||||
OaObOcOde -> OaObOOcde;
|
||||
OOabOcOde -> OOabOOcde;
|
||||
OaOObOcde -> OaOOObcde;
|
||||
OOabOcOde -> OOOabcOde;
|
||||
OOaOObcde -> OOOaObcde;
|
||||
OOOabcOde -> OOOOabcde;
|
||||
OaOOObcde -> OOaOObcde;
|
||||
OaObOcOde -> OaOObcOde;
|
||||
OaOObcOde -> OaOOObcde;
|
||||
OOabOOcde -> OOOabOcde;
|
||||
OOaObOcde -> OOOabOcde;
|
||||
OOaObcOde -> OOOabcOde;
|
||||
OaOObOcde -> OOaObOcde;
|
||||
OOaObOcde -> OOaOObcde;
|
||||
OOOabOcde -> OOOOabcde;
|
||||
OaObOcOde -> OOabOcOde;
|
||||
OaObOOcde -> OaOObOcde;
|
||||
OaOObcOde -> OOaObcOde;
|
||||
}
|
126
static/tamari/tamari.py
Normal file
@ -0,0 +1,126 @@
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-l", "--length", help="length of the initial string", type=int, default=5)
|
||||
parser.add_argument("output", help="file to output to", type=argparse.FileType('w'), nargs="?", default=sys.stdout)
|
||||
args = parser.parse_args()
|
||||
|
||||
node_marker = 'O'
|
||||
|
||||
class TreeNode:
|
||||
"""A binary tree node for the purpose of doing tree manipulations and generating tamari lattices. Not very pretty code."""
|
||||
def __init__(self,l,v,r):
|
||||
"""Arguments are: left node, payload, right node."""
|
||||
self.l = l
|
||||
self.v = v
|
||||
self.r = r
|
||||
def __str__(self):
|
||||
"""Return the string which would be parsed into this object."""
|
||||
if self.l is None or self.r is None: return str(self.v)
|
||||
return node_marker + str(self.l) + str(self.r)
|
||||
def pretty_string(self):
|
||||
"""Return a string suitable for a label."""
|
||||
if self.l is None or self.r is None: return str(self.v)
|
||||
return "(" + self.l.pretty_string() + "," + self.r.pretty_string() + ")"
|
||||
def rotate_left(self):
|
||||
if not leaf(self) and not leaf(self.r):
|
||||
self.l = TreeNode(self.l, None, self.r.l)
|
||||
self.r = self.r.r
|
||||
def rotate_right(self):
|
||||
if not leaf(self) and not leaf(self.l):
|
||||
self.r = TreeNode(self.l.r, None, self.r)
|
||||
self.l = self.l.l
|
||||
def clone(self):
|
||||
if leaf(self): return TreeNode(None, self.v, None)
|
||||
else: return TreeNode(self.l.clone(), self.v, self.r.clone())
|
||||
def count_nodes(self):
|
||||
if leaf(self): return 0
|
||||
else: return self.l.count_nodes() + self.r.count_nodes() + 1
|
||||
def do_on_nth_node(self, n, f):
|
||||
"""Call the second argument on the nth node in the tree, going depth first from left to right."""
|
||||
if leaf(self): return n
|
||||
remaining = self.l.do_on_nth_node(n,f)
|
||||
if remaining is 0: return 0
|
||||
if remaining is 1:
|
||||
f(self)
|
||||
return 0
|
||||
return self.r.do_on_nth_node(remaining-1,f)
|
||||
def __eq__(self, other):
|
||||
"""Comparison for sets. Just checks if the string representation is the same."""
|
||||
return str(self) == str(other)
|
||||
def __hash__(self):
|
||||
"""Much like __eq__, this is needed for using this in sets. This just hashes the string representation."""
|
||||
return hash(str(self))
|
||||
|
||||
def nth_node_helper(root, n, f):
|
||||
"""This is so ugly. I just want to do something on the nth node and return the transformed tree! ... But it works. Note: don't extend this script ever. It should stay in its little awful box."""
|
||||
root.do_on_nth_node(n, f)
|
||||
return root
|
||||
|
||||
def leaf(node):
|
||||
return node.l is None or node.r is None
|
||||
|
||||
def generate_children(root):
|
||||
"""Return a set of all the trees produced by rotating left at one point in the tree that is passed in."""
|
||||
# If there are n nodes in the tree, then there are at most n places to do a rotation.
|
||||
# I didn't feel like figuring out a more direct method to generate all rotations, so I just did this:
|
||||
# Try rotating at each child node. Remove all the ones that weren't changed (that is, where it failed).
|
||||
children = set(nth_node_helper(root.clone(), i, TreeNode.rotate_left) for i in range(root.count_nodes()))
|
||||
return children - {root} # Return the children, except without the root. We don't care about the root.
|
||||
|
||||
def _parse(s):
|
||||
"""Parse one token of the string passed in, and return a tuple: (the tree we parsed, the remainer that wasn't parsed).
|
||||
This function recursively calls itself, to parse the whole string. """
|
||||
if s[0] is node_marker:
|
||||
first, remainder = _parse(s[1:])
|
||||
second, secondRemainder = _parse(remainder)
|
||||
return (TreeNode(first, None, second), secondRemainder)
|
||||
return (TreeNode(None, s[0], None), s[1:])
|
||||
def parse(string):
|
||||
"""Parses a string, assuming the node marker in node_marker, and returns a TreeNode.
|
||||
This is a wrapper around _parse."""
|
||||
return _parse(string)[0]
|
||||
|
||||
|
||||
# The string we start with is just a slice of the alphabet, with length specified by the command line argument -l.
|
||||
root_string = "abcdefghijklmnopqrstuvwxyz"[:args.length]
|
||||
root_string = "".join( "O" + char for char in root_string )
|
||||
root_string = "".join( root_string.rsplit("O", 1) )
|
||||
|
||||
# helper function for generating node labels
|
||||
label_from_node = lambda x: "{name} [label=\"{label}\"];".format(name=str(x), label=x.pretty_string())
|
||||
|
||||
|
||||
# Here's the root we start with!
|
||||
RootOfAllEvil = parse(root_string)
|
||||
#print(RootOfAllEvil)
|
||||
|
||||
current_generation = set()
|
||||
next_generation = {RootOfAllEvil}
|
||||
edges = set()
|
||||
labels = set()
|
||||
|
||||
while len(current_generation ^ next_generation): # So long as we haven't reached stability...
|
||||
# Move to look at the next generation.
|
||||
#print("current_generation: {}, next_generation: {}".format(current_generation, next_generation))
|
||||
current_generation = next_generation
|
||||
|
||||
# Clear out the next generation so that we can fill it with the children of the now-current generation.
|
||||
next_generation = set()
|
||||
#print("current_generation: {}, next_generation: {}".format(current_generation, next_generation))
|
||||
|
||||
labels = labels | set(label_from_node(parent) for parent in current_generation)
|
||||
|
||||
for parent in current_generation:
|
||||
children = generate_children(parent)
|
||||
#print("children of {parent}: {children}".format(parent=parent, children=children))
|
||||
|
||||
labels = labels | set(label_from_node(child) for child in children)
|
||||
edges = edges | set(str(parent) + " -> " + str(child) + ";" for child in children)
|
||||
next_generation = next_generation | children
|
||||
|
||||
args.output.write(u"digraph tamari {\n")
|
||||
args.output.write(u"\n".join(labels) + "\n")
|
||||
args.output.write(u"\n".join(edges))
|
||||
args.output.write(u"\n}\n")
|
3
static/tamari/tamari_2.dot
Normal file
@ -0,0 +1,3 @@
|
||||
digraph tamari {
|
||||
|
||||
}
|
BIN
static/tamari/tamari_2.png
Normal file
After Width: | Height: | Size: 84 B |
3
static/tamari/tamari_3.dot
Normal file
@ -0,0 +1,3 @@
|
||||
digraph tamari {
|
||||
OaObc -> OOabc;
|
||||
}
|
BIN
static/tamari/tamari_3.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
7
static/tamari/tamari_4.dot
Normal file
@ -0,0 +1,7 @@
|
||||
digraph tamari {
|
||||
OaObOcd -> OOabOcd;
|
||||
OOaObcd -> OOOabcd;
|
||||
OaOObcd -> OOaObcd;
|
||||
OOabOcd -> OOOabcd;
|
||||
OaObOcd -> OaOObcd;
|
||||
}
|
BIN
static/tamari/tamari_4.png
Normal file
After Width: | Height: | Size: 25 KiB |
23
static/tamari/tamari_5.dot
Normal file
@ -0,0 +1,23 @@
|
||||
digraph tamari {
|
||||
OOabOcOde -> OOOabcOde;
|
||||
OOaOObcde -> OOOaObcde;
|
||||
OaOOObcde -> OOaOObcde;
|
||||
OaOObcOde -> OaOOObcde;
|
||||
OOOabOcde -> OOOOabcde;
|
||||
OaObOcOde -> OaOObcOde;
|
||||
OOaObcOde -> OOOabcOde;
|
||||
OaOObcOde -> OOaObcOde;
|
||||
OOabOOcde -> OOOabOcde;
|
||||
OaObOcOde -> OOabOcOde;
|
||||
OaOObOcde -> OaOOObcde;
|
||||
OOaObOcde -> OOOabOcde;
|
||||
OOOaObcde -> OOOOabcde;
|
||||
OaObOOcde -> OaOObOcde;
|
||||
OaOObOcde -> OOaObOcde;
|
||||
OaObOcOde -> OaObOOcde;
|
||||
OaObOOcde -> OOabOOcde;
|
||||
OOaObOcde -> OOaOObcde;
|
||||
OOOabcOde -> OOOOabcde;
|
||||
OOaObcOde -> OOOaObcde;
|
||||
OOabOcOde -> OOabOOcde;
|
||||
}
|
BIN
static/tamari/tamari_5.png
Normal file
After Width: | Height: | Size: 81 KiB |
86
static/tamari/tamari_6.dot
Normal file
@ -0,0 +1,86 @@
|
||||
digraph tamari {
|
||||
OOabOOOcdef -> OOOabOOcdef;
|
||||
OaObOOcdOef -> OOabOOcdOef;
|
||||
OOOaObcOdef -> OOOOaObcdef;
|
||||
OOOOabOcdef -> OOOOOabcdef;
|
||||
OOaOObcdOef -> OOOaOObcdef;
|
||||
OOOabOcOdef -> OOOOabcOdef;
|
||||
OOOaOObcdef -> OOOOaObcdef;
|
||||
OOaObcOOdef -> OOOabcOOdef;
|
||||
OOOaObOcdef -> OOOaOObcdef;
|
||||
OaOObOcOdef -> OOaObOcOdef;
|
||||
OOabOOcOdef -> OOOabOcOdef;
|
||||
OOOaObcdOef -> OOOOabcdOef;
|
||||
OOaOObOcdef -> OOOaObOcdef;
|
||||
OOOaObOcdef -> OOOOabOcdef;
|
||||
OaObOOcdOef -> OaOObOcdOef;
|
||||
OOaObOcdOef -> OOOaObOcdef;
|
||||
OaOObOcdOef -> OaOOObcdOef;
|
||||
OaObOcOOdef -> OaOObcOOdef;
|
||||
OaObOcOdOef -> OaObOcOOdef;
|
||||
OaOObOOcdef -> OaOOObOcdef;
|
||||
OaOOObcdOef -> OOaOObcdOef;
|
||||
OaOOObOcdef -> OOaOObOcdef;
|
||||
OaOObOOcdef -> OOaObOOcdef;
|
||||
OOaObcOdOef -> OOaObcOOdef;
|
||||
OaOObOcdOef -> OaOOObOcdef;
|
||||
OOOOabcOdef -> OOOOOabcdef;
|
||||
OOOaObcOdef -> OOOOabcOdef;
|
||||
OOOabcOdOef -> OOOOabcdOef;
|
||||
OOOOabcdOef -> OOOOOabcdef;
|
||||
OOaObOcOdef -> OOOabOcOdef;
|
||||
OaObOOcOdef -> OaOObOcOdef;
|
||||
OOaObcOdOef -> OOOabcOdOef;
|
||||
OOaObOcdOef -> OOOabOcdOef;
|
||||
OaOObcOOdef -> OaOOObcOdef;
|
||||
OOaOObcOdef -> OOaOOObcdef;
|
||||
OOabOcOOdef -> OOOabcOOdef;
|
||||
OaObOcOdOef -> OOabOcOdOef;
|
||||
OaOObcOOdef -> OOaObcOOdef;
|
||||
OaObOcOdOef -> OaOObcOdOef;
|
||||
OaObOOcOdef -> OaObOOOcdef;
|
||||
OOOOaObcdef -> OOOOOabcdef;
|
||||
OOOabOOcdef -> OOOOabOcdef;
|
||||
OOabOOcdOef -> OOOabOcdOef;
|
||||
OOaOObcdOef -> OOOaObcdOef;
|
||||
OaObOcOOdef -> OOabOcOOdef;
|
||||
OaOOObcdOef -> OaOOOObcdef;
|
||||
OOOabcOOdef -> OOOOabcOdef;
|
||||
OOOabcOdOef -> OOOabcOOdef;
|
||||
OOaObOOcdef -> OOOabOOcdef;
|
||||
OaOObOcOdef -> OaOOObcOdef;
|
||||
OaOOObOcdef -> OaOOOObcdef;
|
||||
OaObOOOcdef -> OaOObOOcdef;
|
||||
OOaObOOcdef -> OOaOObOcdef;
|
||||
OaObOcOdOef -> OaObOOcdOef;
|
||||
OOOaObcdOef -> OOOOaObcdef;
|
||||
OOaOObOcdef -> OOaOOObcdef;
|
||||
OOaOObcOdef -> OOOaObcOdef;
|
||||
OaObOOcOdef -> OOabOOcOdef;
|
||||
OaOOObcOdef -> OaOOOObcdef;
|
||||
OOabOcOOdef -> OOabOOcOdef;
|
||||
OaOObOcdOef -> OOaObOcdOef;
|
||||
OOaObOcOdef -> OOaOObcOdef;
|
||||
OOOabOcdOef -> OOOOabcdOef;
|
||||
OOOabOcOdef -> OOOabOOcdef;
|
||||
OOaObcOOdef -> OOOaObcOdef;
|
||||
OOabOOcdOef -> OOabOOOcdef;
|
||||
OaOObOcOdef -> OaOObOOcdef;
|
||||
OaObOcOOdef -> OaObOOcOdef;
|
||||
OOabOOcOdef -> OOabOOOcdef;
|
||||
OaOOOObcdef -> OOaOOObcdef;
|
||||
OOabOcOdOef -> OOabOcOOdef;
|
||||
OOOabOcdOef -> OOOOabOcdef;
|
||||
OaObOOcdOef -> OaObOOOcdef;
|
||||
OaOObcOdOef -> OaOOObcdOef;
|
||||
OaOObcOdOef -> OOaObcOdOef;
|
||||
OOaOOObcdef -> OOOaOObcdef;
|
||||
OaOObcOdOef -> OaOObcOOdef;
|
||||
OOaObOcdOef -> OOaOObcdOef;
|
||||
OOaObOcOdef -> OOaObOOcdef;
|
||||
OOabOcOdOef -> OOOabcOdOef;
|
||||
OaOOObcOdef -> OOaOObcOdef;
|
||||
OOaObcOdOef -> OOOaObcdOef;
|
||||
OaObOOOcdef -> OOabOOOcdef;
|
||||
OOabOcOdOef -> OOabOOcdOef;
|
||||
}
|
BIN
static/tamari/tamari_6.png
Normal file
After Width: | Height: | Size: 317 KiB |
332
static/tamari/tamari_7.dot
Normal file
@ -0,0 +1,332 @@
|
||||
digraph tamari {
|
||||
OOOabOcdOeOfg -> OOOOabcdOeOfg;
|
||||
OaOObOcdOeOfg -> OaOOObcdOeOfg;
|
||||
OaOOOObcdeOfg -> OOaOOObcdeOfg;
|
||||
OOabOOOOcdefg -> OOOabOOOcdefg;
|
||||
OOaObcOOOdefg -> OOOabcOOOdefg;
|
||||
OaOObOcdOOefg -> OOaObOcdOOefg;
|
||||
OOaObOcOdeOfg -> OOOaObOcOdefg;
|
||||
OaObOOOcdOefg -> OaOObOOcdOefg;
|
||||
OOabOcOdOOefg -> OOOabcOdOOefg;
|
||||
OOOabOcOdeOfg -> OOOabOOcdeOfg;
|
||||
OOaObcOdOOefg -> OOOaObcdOOefg;
|
||||
OOOabcOdOeOfg -> OOOabcOdOOefg;
|
||||
OaOOOObOcdefg -> OaOOOOObcdefg;
|
||||
OaObOcOOdOefg -> OaObOcOOOdefg;
|
||||
OaOObOcOdeOfg -> OOaObOcOdeOfg;
|
||||
OOabOcOdOeOfg -> OOabOcOOdeOfg;
|
||||
OOaOObOcdeOfg -> OOOaObOcdeOfg;
|
||||
OaOObOcdOeOfg -> OaOObOcdOOefg;
|
||||
OaObOOcdOeOfg -> OaOObOcdOeOfg;
|
||||
OOOaObcOdOefg -> OOOaObcOOdefg;
|
||||
OOabOcOdOOefg -> OOabOOcdOOefg;
|
||||
OOabOOOcOdefg -> OOabOOOOcdefg;
|
||||
OaOOObcdOOefg -> OOaOObcdOOefg;
|
||||
OaOObOcOdOefg -> OOaObOcOdOefg;
|
||||
OOaObOcOdeOfg -> OOOabOcOdeOfg;
|
||||
OOabOcOdOOefg -> OOabOcOOdOefg;
|
||||
OaObOOcOdOefg -> OOabOOcOdOefg;
|
||||
OOOaOObcOdefg -> OOOaOOObcdefg;
|
||||
OaObOOcdOeOfg -> OOabOOcdOeOfg;
|
||||
OOOabcOdOOefg -> OOOabcOOdOefg;
|
||||
OOOOaObOcdefg -> OOOOOabOcdefg;
|
||||
OOaObOcOOdefg -> OOOabOcOOdefg;
|
||||
OaOOObOcOdefg -> OOaOObOcOdefg;
|
||||
OaOObcOOOdefg -> OaOOObcOOdefg;
|
||||
OOabOOcdOOefg -> OOabOOOcdOefg;
|
||||
OOaOOObcdeOfg -> OOOaOOObcdefg;
|
||||
OaOObOOcdOefg -> OaOObOOOcdefg;
|
||||
OaOOObcdOeOfg -> OaOOOObcdeOfg;
|
||||
OaOOOObcOdefg -> OaOOOOObcdefg;
|
||||
OaOObOOcdeOfg -> OOaObOOcdeOfg;
|
||||
OaOOObOcdOefg -> OOaOObOcdOefg;
|
||||
OaObOOcOOdefg -> OaObOOOcOdefg;
|
||||
OOOaObOcOdefg -> OOOaObOOcdefg;
|
||||
OOOabcOOOdefg -> OOOOabcOOdefg;
|
||||
OOOOabcOdeOfg -> OOOOOabcdeOfg;
|
||||
OaOOOObcdeOfg -> OaOOOOObcdefg;
|
||||
OaObOOcdOeOfg -> OaObOOOcdeOfg;
|
||||
OOOabcOOdOefg -> OOOOabcOdOefg;
|
||||
OaOOObcOdOefg -> OOaOObcOdOefg;
|
||||
OOOOaObOcdefg -> OOOOaOObcdefg;
|
||||
OaObOOOOcdefg -> OaOObOOOcdefg;
|
||||
OOOabOcOdOefg -> OOOabOcOOdefg;
|
||||
OaOOObOcdeOfg -> OOaOObOcdeOfg;
|
||||
OOabOcOOdOefg -> OOabOcOOOdefg;
|
||||
OOOaObcdOeOfg -> OOOaObcdOOefg;
|
||||
OaOObOcOdOefg -> OaOObOOcdOefg;
|
||||
OaObOOcOdeOfg -> OaObOOOcOdefg;
|
||||
OaOOObcOdeOfg -> OaOOOObcdeOfg;
|
||||
OOabOOcOdOefg -> OOabOOcOOdefg;
|
||||
OaOObcOOdOefg -> OOaObcOOdOefg;
|
||||
OaObOcOdOeOfg -> OaOObcOdOeOfg;
|
||||
OOOabOOcOdefg -> OOOabOOOcdefg;
|
||||
OaObOOOcdOefg -> OOabOOOcdOefg;
|
||||
OaObOOcdOeOfg -> OaObOOcdOOefg;
|
||||
OOaOObOcdeOfg -> OOaOOObcdeOfg;
|
||||
OOOaObOcdeOfg -> OOOOabOcdeOfg;
|
||||
OOOOabcOOdefg -> OOOOOabcOdefg;
|
||||
OaObOOcOdOefg -> OaObOOOcdOefg;
|
||||
OaOObOOcdeOfg -> OaOOObOcdeOfg;
|
||||
OaOOObOcdeOfg -> OaOOOObOcdefg;
|
||||
OOaObOOcdeOfg -> OOOabOOcdeOfg;
|
||||
OOabOOOcdOefg -> OOOabOOcdOefg;
|
||||
OOaObcOdOOefg -> OOaObcOOdOefg;
|
||||
OOOaOObcdeOfg -> OOOOaObcdeOfg;
|
||||
OOabOOcdOeOfg -> OOOabOcdOeOfg;
|
||||
OOOaObcdOOefg -> OOOOabcdOOefg;
|
||||
OOaObOcOdeOfg -> OOaObOOcdeOfg;
|
||||
OOOOOaObcdefg -> OOOOOOabcdefg;
|
||||
OOabOcOOOdefg -> OOabOOcOOdefg;
|
||||
OOOaObOcOdefg -> OOOOabOcOdefg;
|
||||
OOabOcOOOdefg -> OOOabcOOOdefg;
|
||||
OOaOObcdOOefg -> OOOaOObcdOefg;
|
||||
OaOObOOcOdefg -> OaOOObOcOdefg;
|
||||
OOabOcOdOeOfg -> OOabOcOdOOefg;
|
||||
OOabOOOcdeOfg -> OOOabOOcdeOfg;
|
||||
OOaObOcOdOefg -> OOOabOcOdOefg;
|
||||
OOaObOcOdOefg -> OOaObOcOOdefg;
|
||||
OOOabOcOOdefg -> OOOOabcOOdefg;
|
||||
OOaObOOOcdefg -> OOaOObOOcdefg;
|
||||
OOOaObcOdeOfg -> OOOOabcOdeOfg;
|
||||
OOabOcOOdOefg -> OOOabcOOdOefg;
|
||||
OaOObOcOdOefg -> OaOOObcOdOefg;
|
||||
OaOObOcOOdefg -> OaOObOOcOdefg;
|
||||
OaObOOcdOOefg -> OaObOOOcdOefg;
|
||||
OOaOObOcOdefg -> OOaOObOOcdefg;
|
||||
OOOOabcOdOefg -> OOOOOabcdOefg;
|
||||
OaObOOcOdeOfg -> OOabOOcOdeOfg;
|
||||
OOOabOcOdOefg -> OOOabOOcdOefg;
|
||||
OOaObOOcdOefg -> OOaObOOOcdefg;
|
||||
OaOObOcdOeOfg -> OOaObOcdOeOfg;
|
||||
OOOabOOcdOefg -> OOOOabOcdOefg;
|
||||
OaOObOcdOOefg -> OaOOObcdOOefg;
|
||||
OOOOaObcdOefg -> OOOOOaObcdefg;
|
||||
OOOabcOdOeOfg -> OOOOabcdOeOfg;
|
||||
OaOOObcOOdefg -> OaOOOObcOdefg;
|
||||
OOOOOabOcdefg -> OOOOOOabcdefg;
|
||||
OOOabcOdOeOfg -> OOOabcOOdeOfg;
|
||||
OOOOOabcdeOfg -> OOOOOOabcdefg;
|
||||
OaOOObcOdOefg -> OaOOOObcdOefg;
|
||||
OOOOabOcdOefg -> OOOOOabcdOefg;
|
||||
OOaObOOcdOefg -> OOOabOOcdOefg;
|
||||
OOabOOcdOeOfg -> OOabOOcdOOefg;
|
||||
OOaObcOOdOefg -> OOOaObcOdOefg;
|
||||
OaObOcOOdOefg -> OOabOcOOdOefg;
|
||||
OOaObOcdOOefg -> OOaOObcdOOefg;
|
||||
OaOOObcOOdefg -> OOaOObcOOdefg;
|
||||
OOOabOcOOdefg -> OOOabOOcOdefg;
|
||||
OOaObOOcdeOfg -> OOOaObOOcdefg;
|
||||
OOaObOcdOeOfg -> OOaObOcdOOefg;
|
||||
OaOObOOOcdefg -> OaOOObOOcdefg;
|
||||
OOOabOOcOdefg -> OOOOabOcOdefg;
|
||||
OOOaObOcdOefg -> OOOOabOcdOefg;
|
||||
OOOaObcOOdefg -> OOOOabcOOdefg;
|
||||
OOOabOcOdeOfg -> OOOOabcOdeOfg;
|
||||
OaOObcOOdeOfg -> OOaObcOOdeOfg;
|
||||
OaObOcOOOdefg -> OOabOcOOOdefg;
|
||||
OaOObcOdOeOfg -> OaOObcOOdeOfg;
|
||||
OOOaObcdOeOfg -> OOOOaObcdeOfg;
|
||||
OOOOaObcdeOfg -> OOOOOabcdeOfg;
|
||||
OOOOabOcOdefg -> OOOOOabcOdefg;
|
||||
OOOabcOdOOefg -> OOOOabcdOOefg;
|
||||
OOabOOcOdOefg -> OOOabOcOdOefg;
|
||||
OOaOOObOcdefg -> OOOaOObOcdefg;
|
||||
OOOOabOOcdefg -> OOOOOabOcdefg;
|
||||
OOOOabcdOeOfg -> OOOOabcdOOefg;
|
||||
OOaObcOOdeOfg -> OOOabcOOdeOfg;
|
||||
OOOOabOcdOefg -> OOOOOabOcdefg;
|
||||
OaOObOcOOdefg -> OOaObOcOOdefg;
|
||||
OaOOObcdOOefg -> OaOOOObcdOefg;
|
||||
OaOOObcdOeOfg -> OaOOObcdOOefg;
|
||||
OaOOObcOdeOfg -> OOaOObcOdeOfg;
|
||||
OOaOObcdOeOfg -> OOOaObcdOeOfg;
|
||||
OOOabOcdOeOfg -> OOOOabOcdeOfg;
|
||||
OOaObOOcdeOfg -> OOaOObOcdeOfg;
|
||||
OOaObOcOOdefg -> OOaOObcOOdefg;
|
||||
OaOObOcOdeOfg -> OaOOObOcOdefg;
|
||||
OaOOObcOdOefg -> OaOOObcOOdefg;
|
||||
OaObOOOcdeOfg -> OOabOOOcdeOfg;
|
||||
OaOObOOcdOefg -> OaOOObOcdOefg;
|
||||
OOOabOcdOeOfg -> OOOabOcdOOefg;
|
||||
OOaOObOcdOefg -> OOaOOObcdOefg;
|
||||
OaObOOcOOdefg -> OaOObOcOOdefg;
|
||||
OaObOOcOOdefg -> OOabOOcOOdefg;
|
||||
OOabOOOcdOefg -> OOabOOOOcdefg;
|
||||
OOaObOcOdOefg -> OOaObOOcdOefg;
|
||||
OOabOOOcdeOfg -> OOabOOOOcdefg;
|
||||
OOOabOcOdeOfg -> OOOOabOcOdefg;
|
||||
OaOObOcOOdefg -> OaOOObcOOdefg;
|
||||
OOaOObOOcdefg -> OOOaObOOcdefg;
|
||||
OOaObOcdOOefg -> OOOaObOcdOefg;
|
||||
OOaOObOOcdefg -> OOaOOObOcdefg;
|
||||
OaObOOOcdeOfg -> OaOObOOcdeOfg;
|
||||
OOOabOOcdeOfg -> OOOOabOOcdefg;
|
||||
OOOOabOcdeOfg -> OOOOOabcdeOfg;
|
||||
OOaObcOOdOefg -> OOOabcOOdOefg;
|
||||
OOaObcOOOdefg -> OOOaObcOOdefg;
|
||||
OOOaObcOdeOfg -> OOOOaObcdeOfg;
|
||||
OOaOObcOdOefg -> OOOaObcOdOefg;
|
||||
OOaObOOcOdefg -> OOOabOOcOdefg;
|
||||
OOOaObOOcdefg -> OOOOabOOcdefg;
|
||||
OOOabOOcdOefg -> OOOabOOOcdefg;
|
||||
OOOaObOcdOefg -> OOOaOObcdOefg;
|
||||
OOaObOcdOeOfg -> OOOaObOcdeOfg;
|
||||
OOaOOObOcdefg -> OOaOOOObcdefg;
|
||||
OaOOObOcdOefg -> OaOOOObcdOefg;
|
||||
OOOaOObcOdefg -> OOOOaObcOdefg;
|
||||
OaOObOOcdOefg -> OOaObOOcdOefg;
|
||||
OaOObOOcdeOfg -> OaOOObOOcdefg;
|
||||
OaObOOcOdOefg -> OaOObOcOdOefg;
|
||||
OaObOOcdOOefg -> OaOObOcdOOefg;
|
||||
OaOOOObcdOefg -> OaOOOOObcdefg;
|
||||
OOaOObcOdOefg -> OOaOOObcdOefg;
|
||||
OaOObcOOOdefg -> OOaObcOOOdefg;
|
||||
OaOObcOdOOefg -> OaOOObcdOOefg;
|
||||
OOabOOcOdeOfg -> OOabOOOcdeOfg;
|
||||
OaObOOOOcdefg -> OOabOOOOcdefg;
|
||||
OaOOObOOcdefg -> OaOOOObOcdefg;
|
||||
OOaOObcOdeOfg -> OOOaObcOdeOfg;
|
||||
OaOOOObcOdefg -> OOaOOObcOdefg;
|
||||
OOaOOObcOdefg -> OOaOOOObcdefg;
|
||||
OaObOcOOdeOfg -> OaObOcOOOdefg;
|
||||
OOOOOabcOdefg -> OOOOOOabcdefg;
|
||||
OaObOcOOdeOfg -> OOabOcOOdeOfg;
|
||||
OOaObcOOdeOfg -> OOaObcOOOdefg;
|
||||
OaObOOcdOOefg -> OOabOOcdOOefg;
|
||||
OOOOaOObcdefg -> OOOOOaObcdefg;
|
||||
OaOObOcOdOefg -> OaOObOcOOdefg;
|
||||
OOabOcOOdeOfg -> OOabOcOOOdefg;
|
||||
OOaOOObcdOefg -> OOOaOObcdOefg;
|
||||
OOOabOcdOOefg -> OOOOabcdOOefg;
|
||||
OaObOOcOdOefg -> OaObOOcOOdefg;
|
||||
OaOOObOOcdefg -> OOaOObOOcdefg;
|
||||
OOabOcOdOeOfg -> OOOabcOdOeOfg;
|
||||
OaOObcOdOOefg -> OaOObcOOdOefg;
|
||||
OOOabcOOdOefg -> OOOabcOOOdefg;
|
||||
OaOOObcdOeOfg -> OOaOObcdOeOfg;
|
||||
OaOOObOcOdefg -> OaOOOObcOdefg;
|
||||
OOaObcOdOeOfg -> OOaObcOdOOefg;
|
||||
OOaOObcdOOefg -> OOOaObcdOOefg;
|
||||
OaObOcOdOOefg -> OOabOcOdOOefg;
|
||||
OaOObOOcOdefg -> OaOObOOOcdefg;
|
||||
OOabOOcdOeOfg -> OOabOOOcdeOfg;
|
||||
OaObOOOcOdefg -> OaObOOOOcdefg;
|
||||
OOaOObcOdeOfg -> OOaOOObcdeOfg;
|
||||
OOOOabcOdeOfg -> OOOOOabcOdefg;
|
||||
OOOaObcOdeOfg -> OOOOaObcOdefg;
|
||||
OOaObOOcOdefg -> OOaOObOcOdefg;
|
||||
OOaObOOcOdefg -> OOaObOOOcdefg;
|
||||
OOabOcOOdOefg -> OOabOOcOdOefg;
|
||||
OaOObcOdOeOfg -> OOaObcOdOeOfg;
|
||||
OaObOOOcOdefg -> OOabOOOcOdefg;
|
||||
OaObOcOdOeOfg -> OOabOcOdOeOfg;
|
||||
OaOObcOOdeOfg -> OaOOObcOdeOfg;
|
||||
OOOaObOcdeOfg -> OOOOaObOcdefg;
|
||||
OaObOcOdOeOfg -> OaObOOcdOeOfg;
|
||||
OOOaOObcdeOfg -> OOOOaOObcdefg;
|
||||
OOOabcOOdeOfg -> OOOabcOOOdefg;
|
||||
OOaOObOcdeOfg -> OOOaOObOcdefg;
|
||||
OaObOcOOdeOfg -> OaOObcOOdeOfg;
|
||||
OOaObOcOOdefg -> OOaObOOcOdefg;
|
||||
OOOOabcdOOefg -> OOOOOabcdOefg;
|
||||
OOaOOObcdeOfg -> OOOaOObcdeOfg;
|
||||
OaOOObOcOdefg -> OaOOObOOcdefg;
|
||||
OOOOabcOdOefg -> OOOOabcOOdefg;
|
||||
OOaObOcOdOefg -> OOaOObcOdOefg;
|
||||
OOOOabOcOdefg -> OOOOabOOcdefg;
|
||||
OOaObOcdOeOfg -> OOaOObcdOeOfg;
|
||||
OaOOObcOdeOfg -> OaOOOObcOdefg;
|
||||
OaObOOcOdeOfg -> OaOObOcOdeOfg;
|
||||
OOabOOcOdeOfg -> OOabOOOcOdefg;
|
||||
OOOOaObcdeOfg -> OOOOOaObcdefg;
|
||||
OOaOObcOdeOfg -> OOOaOObcOdefg;
|
||||
OOaObOOOcdefg -> OOOabOOOcdefg;
|
||||
OOabOcOdOeOfg -> OOabOOcdOeOfg;
|
||||
OOOaObcOdOefg -> OOOOabcOdOefg;
|
||||
OOabOOcdOOefg -> OOOabOcdOOefg;
|
||||
OOOaOObOcdefg -> OOOOaObOcdefg;
|
||||
OOabOOOcOdefg -> OOOabOOcOdefg;
|
||||
OOaOObcdOeOfg -> OOaOObcdOOefg;
|
||||
OaObOcOdOOefg -> OaOObcOdOOefg;
|
||||
OOaOOObcOdefg -> OOOaOObcOdefg;
|
||||
OaOOObOcdOefg -> OaOOOObOcdefg;
|
||||
OOOaOObOcdefg -> OOOaOOObcdefg;
|
||||
OaObOOOcdOefg -> OaObOOOOcdefg;
|
||||
OOaObcOdOeOfg -> OOOabcOdOeOfg;
|
||||
OaObOcOOdeOfg -> OaObOOcOdeOfg;
|
||||
OaOObcOOdOefg -> OaOObcOOOdefg;
|
||||
OOabOcOOdeOfg -> OOabOOcOdeOfg;
|
||||
OOaObcOdOeOfg -> OOOaObcdOeOfg;
|
||||
OOOabOcOdOefg -> OOOOabcOdOefg;
|
||||
OOaOObcOdOefg -> OOaOObcOOdefg;
|
||||
OOaObcOOdOefg -> OOaObcOOOdefg;
|
||||
OOabOcOOdeOfg -> OOOabcOOdeOfg;
|
||||
OaOOOObcdOefg -> OOaOOObcdOefg;
|
||||
OOaOObOcdOefg -> OOOaObOcdOefg;
|
||||
OOaOOOObcdefg -> OOOaOOObcdefg;
|
||||
OOOOabcdOeOfg -> OOOOOabcdeOfg;
|
||||
OaObOOcOdeOfg -> OaObOOOcdeOfg;
|
||||
OaOObcOOdOefg -> OaOOObcOdOefg;
|
||||
OOOaObOcdOefg -> OOOOaObOcdefg;
|
||||
OOOaObcOdOefg -> OOOOaObcdOefg;
|
||||
OOOabOOcdeOfg -> OOOOabOcdeOfg;
|
||||
OOOOOabcdOefg -> OOOOOOabcdefg;
|
||||
OaOObcOOdeOfg -> OaOObcOOOdefg;
|
||||
OaOObcOdOeOfg -> OaOObcOdOOefg;
|
||||
OOOabOcdOOefg -> OOOOabOcdOefg;
|
||||
OOOOaObcOdefg -> OOOOOaObcdefg;
|
||||
OOaObcOdOOefg -> OOOabcOdOOefg;
|
||||
OOOabcOOdeOfg -> OOOOabcOdeOfg;
|
||||
OaOOOOObcdefg -> OOaOOOObcdefg;
|
||||
OOabOOcOOdefg -> OOOabOcOOdefg;
|
||||
OaOObOcdOOefg -> OaOOObOcdOefg;
|
||||
OaOObOcOdeOfg -> OaOOObcOdeOfg;
|
||||
OOOaOObcdOefg -> OOOOaOObcdefg;
|
||||
OaOObcOdOOefg -> OOaObcOdOOefg;
|
||||
OaOObOOcOdefg -> OOaObOOcOdefg;
|
||||
OaObOcOdOeOfg -> OaObOcOdOOefg;
|
||||
OaObOcOOdOefg -> OaOObcOOdOefg;
|
||||
OOabOOcOdOefg -> OOabOOOcdOefg;
|
||||
OOOaOObcdOefg -> OOOOaObcdOefg;
|
||||
OaObOcOOOdefg -> OaOObcOOOdefg;
|
||||
OOOOabOcdeOfg -> OOOOOabOcdefg;
|
||||
OOaObcOOdeOfg -> OOOaObcOdeOfg;
|
||||
OaOOOObOcdefg -> OOaOOObOcdefg;
|
||||
OOaOOObcdOefg -> OOaOOOObcdefg;
|
||||
OaOOObOcdeOfg -> OaOOOObcdeOfg;
|
||||
OOaOObOcOdefg -> OOOaObOcOdefg;
|
||||
OOaObOcOdeOfg -> OOaOObcOdeOfg;
|
||||
OaObOcOdOOefg -> OaObOcOOdOefg;
|
||||
OaObOcOdOOefg -> OaObOOcdOOefg;
|
||||
OaObOcOdOeOfg -> OaObOcOOdeOfg;
|
||||
OaObOcOOOdefg -> OaObOOcOOdefg;
|
||||
OaObOOOcdeOfg -> OaObOOOOcdefg;
|
||||
OOaObOOcdOefg -> OOaOObOcdOefg;
|
||||
OOaOObOcOdefg -> OOaOOObcOdefg;
|
||||
OOabOOcOdeOfg -> OOOabOcOdeOfg;
|
||||
OOOaObcdOeOfg -> OOOOabcdOeOfg;
|
||||
OOOaObOcdeOfg -> OOOaOObcdeOfg;
|
||||
OOaOObOcdOefg -> OOaOOObOcdefg;
|
||||
OOabOOcOOdefg -> OOabOOOcOdefg;
|
||||
OOOaObOOcdefg -> OOOaOObOcdefg;
|
||||
OOaOObcOOdefg -> OOOaObcOOdefg;
|
||||
OOOaObcdOOefg -> OOOOaObcdOefg;
|
||||
OaObOcOOdOefg -> OaObOOcOdOefg;
|
||||
OaOObOcdOeOfg -> OaOOObOcdeOfg;
|
||||
OOaObOcdOeOfg -> OOOabOcdOeOfg;
|
||||
OOaObOcdOOefg -> OOOabOcdOOefg;
|
||||
OOOOaObcdOefg -> OOOOOabcdOefg;
|
||||
OaOObOcOdeOfg -> OaOObOOcdeOfg;
|
||||
OOOaOOObcdefg -> OOOOaOObcdefg;
|
||||
OaObOOOcOdefg -> OaOObOOcOdefg;
|
||||
OaOObcOdOeOfg -> OaOOObcdOeOfg;
|
||||
OOOaObcOOdefg -> OOOOaObcOdefg;
|
||||
OOaOObcOOdefg -> OOaOOObcOdefg;
|
||||
OOaObcOdOeOfg -> OOaObcOOdeOfg;
|
||||
OOOabOOOcdefg -> OOOOabOOcdefg;
|
||||
OaOObOOOcdefg -> OOaObOOOcdefg;
|
||||
OOOaObOcOdefg -> OOOaOObcOdefg;
|
||||
OOaOObcdOeOfg -> OOOaOObcdeOfg;
|
||||
OOOOaObcOdefg -> OOOOOabcOdefg;
|
||||
}
|
BIN
static/tamari/tamari_7.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
0
static/tamari/tamari_8.dot
Normal file
BIN
static/the_dark_side.png
Normal file
After Width: | Height: | Size: 214 KiB |
9
static/thing.html
Normal file
@ -0,0 +1,9 @@
|
||||
at large sizes, we have two columns, a main column and a sidebar.
|
||||
|
||||
for super-huge screens, the main column and the sidebar are both fixed sizes.
|
||||
as you shrink, the sidebar shrinks until the proportions are 2/3 main column and 1/3 sidebar
|
||||
as you shrink, both scale, keeping those proportions. however, the things in the main column do not shrink - they just rearrange.
|
||||
at tablet sizes, part of the sidebar goes to the top, and part goes to the bottom, and we turn into a one-column layout.
|
||||
|
||||
when the screen is very large, I want the sidebar on the right - containing information about me, to grow, leaving the column on the left at a fixed size.
|
||||
decreasing the viewport's width: when we get to the point where the screen is 2/3 leftcolumn and 1/3 right sidebar
|
12
tornado_server.py
Normal file
@ -0,0 +1,12 @@
|
||||
import tornado.ioloop
|
||||
import tornado.web
|
||||
|
||||
|
||||
application = tornado.web.Application([
|
||||
(r"/(.*)", tornado.web.StaticFileHandler, {"path":"./"})
|
||||
], debug=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
application.listen(80)
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
|