tag:blogger.com,1999:blog-13683771746870535642024-02-07T03:08:03.501-06:00name change in progressprogramming tips, simple math, silly drawings and useless rantsAnonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.comBlogger36125tag:blogger.com,1999:blog-1368377174687053564.post-25093062648619464222013-11-05T12:20:00.000-06:002013-11-18T13:46:05.526-06:00Bluetooth headphones on Arch: a new twist in the sagaAs of a few days ago the official <code>blueman</code> build for Arch switched from depending on <code>bluez4</code> to <code>bluez</code> (which is to say, <code>bluez5</code>). If you missed my <a href="http://vlsd.blogspot.com/2013/11/bluetooth-headphones-and-arch-linux.html">previous post</a>, I already had gotten my bluetooth headphones working pretty well with <code>bluez4</code>, ALSA and <code>blueman</code>. This new update broke my setup, and sent me on my way to new adventures in <code>bluezland(TM)</code>.<br />
<br />
I haven't gotten much to work yet. I'm sorry. But as I get things working I'll update this post. This is what I've done:<br />
<br />
<u><b>Tue Nov 5 11:51:07 CST 2013</b></u><br />
I updated my system and everything was "broken". I sent a few bug reports, posted a few things on Arch forums, the usual. There are a few problems, and I'll describe them as best I can. First off, <code>bluez5</code> dropped <code>ALSA</code> support, so I had to install <code>pulseaudio-git</code> from the <code>AUR</code>, since the official repo version of <code>pulseaudio</code> does not yet have <code>bluez5</code> support. Then there's the issue that <code>blueman-manager</code> and <code>blueman-applet</code> won't work anymore, they just error out with a <code>dbus</code> error that seems to indicate (to my limited knowledge) that they were not properly updated to the new <code>bluez5</code> API. So I turned to knowledge gleaned from <a href="https://wiki.archlinux.org/index.php/Bluetooth#With_bluez5">recent edits</a> of the Arch Wiki and tried to use the new command like tool that comes with <code>bluez5</code>, <code>bluetoothctl</code>. At first, this looks awesome. It has its own little shell, color output and everything. The main problem is that it doesn't really work. I can't use it to pair my headphones, and I can't use it to connect to them. The errors a terse, to say the least. So I looked for another alternative and tried using <code>gnome-bluetooth</code>, which is what most people use, I think. The problem with <code>gnome-bluetooth</code> is that, unless you're running gnome, it doesn't come with a system tray applet anymore, so there is no way to connect to your device. This is what I ended up doing: 1. install <code>gnome-bluetooth</code>; 2. run <code>bluetoothctl</code> and remove your device from the list, if it is there; 4. install and run <code>pulseaudio</code>; 3. run <code>bluetooth-wizard</code> and pair with your device, it will also autoconnect and it should now work (test with running speaker-test). The one issue I ran into is turning the headphones off and back on. They will not automatically reconnect they way they did under <code>blueman</code>. Instead, it seems to work to go into <code>bluetoothctl</code> and manually connect (see image).
<div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-OrG8dNtSYLM/Unk029g0uLI/AAAAAAAABI8/lY3HzI86Ki4/s1600/screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-OrG8dNtSYLM/Unk029g0uLI/AAAAAAAABI8/lY3HzI86Ki4/s1600/screenshot.png" /></a></div>
The other problem is a lack of control over the bitpool rate (maybe there's a way, but I don't know it yet) so every once in a while the sound gets chopped up and dropped.
<br /><br />
<u><b>Mon Nov 18 13:26:28 CST 2013</b></u></br />
I managed to figure out how to only use <code>bluetoothctl</code> for pairing and connecting, so that I don't have to rely on <code>gnome-bluetooth</code> any longer. The trick was to turn the agent on before trying to pair. Note that tab completion works inside <code>bluetoothctl</code>, so all these calls are pretty easy to make.
<pre class="prettyprint"># bluetoothctl
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# agent on
Agent registered
[bluetooth]# scan on
Discovery started
[CHG] Controller 00:13:46:4D:6A:C6 Discovering: yes
[NEW] Device 00:1D:BA:29:50:D3 DR-BT50
[bluetooth]# pair 00:1D:BA:29:50:D3
Attempting to pair with 00:1D:BA:29:50:D3
[CHG] Device 00:1D:BA:29:50:D3 Connected: yes
[CHG] Device 00:1D:BA:29:50:D3 Paired: yes
Pairing successful
[CHG] Device 00:1D:BA:29:50:D3 Connected: no
[bluetooth]# connect 00:1D:BA:29:50:D3
Attempting to connect to 00:1D:BA:29:50:D3
[CHG] Device 00:1D:BA:29:50:D3 Connected: yes
Connection successful
[bluetooth]# scan off
Discovery stopped
[CHG] Controller 00:13:46:4D:6A:C6 Discovering: no
[bluetooth]# exit</pre>
Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com21tag:blogger.com,1999:blog-1368377174687053564.post-692380183608716242013-11-05T11:07:00.000-06:002013-11-05T11:08:49.875-06:00Bluetooth headphones and Arch Linux: the endless battleSo a few years back I had the brilliant idea to get on the <a href="http://en.wikipedia.org/wiki/Bluetooth">bluetooth</a> bandwagon and get me a nice pair of headphones, because, you know, wires are for suckers. Pretty standard pair of Sony DR-BT50. And pretty much for as long as I've had the headphones I've had headaches. Not that they're physically uncomfortable... quite the opposite. The cushion is made of the softest skin, probably ripped straight off of a newborn baby's ass. No, it's the bluetooth that's been giving me the problems. Not so much in Windows, but who uses Windows anyway? They worked for a while on my MacBook, although with a bunch of caveats and weird behavior (I could lock my computer up if I accidentally closed the lid before turning the headphones off... WHAT?!) until the screen broke and while I was fixing it I accidentally nicked the bluetooth antenna that's weirdly placed behind the LCD. <br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://www.blogcdn.com/www.engadget.com/media/2007/02/2-26-07-dr-bt50.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="http://www.blogcdn.com/www.engadget.com/media/2007/02/2-26-07-dr-bt50.jpg" /></a></div>
<br />
But mostly I use Linux on a day to day basis, especially at work where I listen to most of my music. And I need headphones, because me blasting <a href="http://en.wikipedia.org/wiki/Cynic_(band)">Cynic</a> before noon would get the rats all agitated and whatnot. And let me tell you, blutooth on Linux is about as developed as cuisine on an airplane. Except where airplane food has stayed the same over, I dunno, the past 50 years or so (has there been any time when they did not offer peanuts and soda?) bluetooth on Linux changes about every six months. The main stack is called <a href="http://www.bluez.org/"><b>bluez</b></a> and the developers are churning the versions and modifying the API something fierce. Not so much with the documentation. In fact it seems like the documentation has been dwindling in size. For example, there used to be a wiki. Was it amazing? No, but it gave people a starting point. Now the only way to get to the wiki, which is mostly about bluez4 (the version most people are still using) is to use <a href="http://web.archive.org/web/20100311005319/http://wiki.bluez.org/">the way back machine</a>. Anyway, this guy here does a much better job than me at describing all the <a href="http://jamesbond3142.no-ip.org/blog/?viewDetailed=00031">ridiculousness</a> surrounding the topic.<br />
<br />
What I meant to say before I got off the rails is that, every time some update to <b>bluez</b> or <b>pulseaudio</b> rolls in, my poor headphones stop working. And even if they do work, there's a lot of crackling and just general instability. So the other day I said "enough is enough!" and started looking at the issue like a researcher. I did not get as far as James Bond (see above) but I'll tell you what I did find. This is how my setup works now, it's relatively simple, and I might simplify it even further later, as things start breaking more.<br />
<br />
For one, I am running Arch, and somehow Arch decided that <b>bluez5</b> is the default version of the bluetooth stack even though nothing really seems to work with it yet. Whatever, first step is to install <b>bluez4</b>, which is <b>bluez 4.101</b> or something<br />
along those lines. Next you need something to help you pair and connect to your headphones. I've heard you can use the command line for this, but the actual commands seem to change every few months so I haven't been able to get it to work. Instead I installed <b>blueman</b>. Now, I paired my headphones, it asked for a PIN, had to look it up and it turns most headphones use <b>0000</b> a their PIN. Next, in order to get them to connect I had to add<br />
<pre class="prettyprint"><code>Enable=Sink,Source,Socket</code></pre>
in <b>/etc/bluetooth/audio.conf</b>. Connected like magic!<br />
<br />
One big step done, we move on to getting sound through. For the longest time I used <b>pulseaudio</b>, which is supposed to work<br />
out of the box with <b>bluez</b>. <b>Blueman</b> even has a nice plugin to switch the output to your headphones when you connect them and then switch it back when you disconnect. The problem with this setup is that everything is magic. I have no idea how any of this works, it's code that talks to other code on <b>dbus</b> in ways I'd have to spend a month or more to figure out. So, after having some issues with this and being able to figure out nothing, I completely ditched pulse and switched to good old <a href="http://www.alsa-project.org/main/index.php/Main_Page"><b>ALSA</b></a>. What this means is I added this file in my <b>~/.asoundrc</b>:<br />
<pre class="prettyprint"><code>pcm.btheadset {
type plug
slave {
pcm {
type bluetooth
device 00:1D:BA:29:50:D3
profile "auto"
bitpool "31"
}
}
hint {
show on
description "BT Headset"
}
}
ctl.btheadset {
type bluetooth
}
</code></pre>
<br />
<br />
You'll want to change the device to match the mac address that <b>blueman</b> gives you for your particular headphones. Everything else is pretty self explanatory except for profile (I have no idea what it does) and bitpool, which I will explain momentarily. <br />
<br />
Having done the above you can check your also read it by connecting your headphones and running <b>aplay -L</b>. Your new bluetooth sink should come up. You can even get sound by running <b>speaker-test -D btheadset</b>. Not very pleasant, but it tests that things are working. Now you should be able to select the <b>btheadset</b> output in your media player of choice. <br />
<br />
After all this hassle there is one thing left: sound quality. I was getting interruptions and hangs every few seconds with the default config. This is where the bitpool value comes in. I don't actually know what it means and what it does, but reading a bunch of forums I realized it might be helpful. It's not even documented very well... I had to read the source file in C to see that it was in fact set to some magic numbers at compile time by default. Anyway, I played around with it, and it seems to be some sort of quality vs. skips control. The higher the number the higher the chance of a skip, but the better the sound quality between skips. Make the number too low and you'll get phone quality on your headset. Since I listen to my music over ssh, and have it downsampled to 128bits anyway, I care not about high quality, so I probably made that number slightly smaller than I needed to, but I get absolutely no skips now. And that does it. This should hold me for a while, until <b>bluez4</b> goes completely out the window and <b>bluez5</b> forces us to use <b>pulseaudio</b> with its magic touch and cryptic error messages that nobody understands...
Anyway, I leave you off with a track from the new Cynic album. Enjoy!<br /><br />
<iframe width="420" height="315" src="//www.youtube.com/embed/_fhVLykF3nU" frameborder="0" allowfullscreen></iframe>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com20tag:blogger.com,1999:blog-1368377174687053564.post-9414956537744402712013-10-22T12:43:00.000-05:002013-11-05T11:39:45.135-06:00Installing ROS on Arch (part 1)Call me masochistic, but today I try and install <a href="http://wiki.ros.org/">ROS</a> on Arch Linux. If you guys don't know <a href="https://www.archlinux.org/">Arch</a> is this really cool distro that's pretty much always on the bleeding edge of things and has a huge and supportive community behind it. There are plenty of pre-compiled packages for the core and a huge user repository where everyone can make their own package to be downloaded and compiled by others. It is quite peachy. ROS on the other hand is this monster of software that's basically only supported on <a href="http://www.ubuntu.com/">Ubuntu</a> and has a dependency tree larger that <b>xorg</b> or <b>gnome</b> combined (citation needed). <br />
<br />
Now, why would I want to run ROS on Arch? It's simple: Arch is my current system and I have it set up the way I like it, but I need to use ROS to write code for this new piece of awesome technology we bought, the <a href="http://www.simlab.co.kr/Allegro-Hand.htm">Allegro Hand</a>. It's currently a secondary project, but I plan on getting the hand running on my machine so I don't have to ssh (or, even worse, physically log in) to a Ubuntu machine every time I want to test out code. But, back to the problem at hand (hehe).
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://www.simlab.co.kr/Allegro-Hand-flash/Allegro_Hand_flash_05.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="http://www.simlab.co.kr/Allegro-Hand-flash/Allegro_Hand_flash_05.png" /></a></div>
<br />
Along with this huge dependency tree there's another problem: the default python on Arch is <span style="font-family: "Courier New",Courier,monospace;">python3</span> while ROS assumes that everyone in their right minds <span style="font-size: small;"><span style="font-family: inherit;">would use <span style="font-family: "Courier New",Courier,monospace;">python2</span> as their default, so it simply hardcodes the string <span style="font-family: "Courier New",Courier,monospace;">"python" </span>in every script and path because... well... why would anyone have <span style="font-family: "Courier New",Courier,monospace;">/usr/bin/python</span> point to anything else than <span style="font-family: "Courier New",Courier,monospace;">python2</span>? Does a different version of python even exist? (deep sarcasm). Anyway this is a problem I'll get to later, because we don't encounter it until we download the sources, which is itself sort of a pain. </span></span><br />
<span style="font-size: small;"><span style="font-family: inherit;"><br /></span></span>
<span style="font-size: small;"><span style="font-family: inherit;">First off, the best thing you can do for yourself if you are running Arch is to install <span style="font-family: "Courier New",Courier,monospace;"><a href="https://wiki.archlinux.org/index.php/Yaourt">yaourt</a></span>, from the french repositories. The french word for yogurt, this is an awesome little tool that lets you install AUR packages with more or less the same amount of effort as regular packages. It's also a transparent wrapper for <span style="font-family: "Courier New",Courier,monospace;">pacman</span>, so all the comma</span></span>nds you know and love work exactly the same way.<br />
<br />
Now that you have <span style="font-family: "Courier New",Courier,monospace;">yaourt</span> it's time to install some dependencies. These are the things I had to install:<br />
<pre class="prettyprint">aur/wstool-git
aur/python2-rospkg
aur/python2-catkin_pkg
aur/python2-rosinstall_generator-git
aur/ros-arch-deps
</pre>
That last one took a long time and maybe the first four should be listed as dependencies to it, I don't know. Maybe one doesn't even need it. Let me know if you know. Anyway, I installed it. Then, I followed the steps in the ROS installation document:<br />
<pre class="prettyprint">$ mkdir ~/ros_catkin_ws
$ cd ~/ros_catkin_ws
$ rosinstall_generator desktop --rosdistro hydro \
> --deps --wet-only > hydro-desktop-wet.rosinstall
$ wstool init -j8 src hydro-desktop-wet.rosinstall
</pre>
<span style="font-family: inherit;"><span style="font-size: small;"> What this did was pull the source for hydro with the desktop variant in <span style="font-family: "Courier New",Courier,monospace;">~/ros_catkin_ws/src</span></span></span><br />
<br />
<span style="font-family: inherit;"><span style="font-size: small;">Ok </span></span>now that we're here we're gonna skip the call to <span style="font-family: "Courier New",Courier,monospace;">rosdep</span> because that's going to just give us errors saying that we don't have the required dependencies because they don't exist on arch. I am NOT patching <span style="font-family: "Courier New",Courier,monospace;">rosdep</span> to take care of that. Instead I go right ahead and try and build the damned thing:<br />
<pre class="prettyprint">
$ ./src/catkin/bin/catkin_make_isolated --install
</pre>
But guess what! This errors out, because catkin_make is a python script and it calls <span style="font-family: "Courier New",Courier,monospace;">python</span> expecting it to be <span style="font-family: "Courier New",Courier,monospace;">python2</span>, but instead it gets <span style="font-family: "Courier New",Courier,monospace;">python3</span> on my system. None of the things we just installed are present for <span style="font-family: "Courier New",Courier,monospace;">python3</span>, since they only have <span style="font-family: "Courier New",Courier,monospace;">python2</span> versions. Ugly ugly. I still don't know how to fix this, other than a <span style="font-family: "Courier New",Courier,monospace;">sed</span> on all the files in the <span style="font-family: "Courier New",Courier,monospace;">src</span> folder. And for those asking, hell no I'm not gonna change my default python system wide. It's not a matter of ease, it's a matter of principle dammit.
Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-54848920943845460712013-05-28T11:14:00.000-05:002013-11-05T11:09:29.807-06:00Blogjob!<p>Hey everyone! I know I don't post often but someone out there might be reading this. And if you do you are cool enough to learn about this great new show my partner --- beautiful genius <a href="http://ericaricardo.com/">Erica D</a> --- has been working on since forever. It is called <a href="http://www.blogjobshow.com/">Blogjob: giving blogjobs is a terrible way to make a living</a> and it is about the people who write the fake internets.</p>
<p>Wait, what? Let's pause for a second: you know those sites that serve only as link hubs for Google to parse so that their links get higher up in search results? Back in the day there would be a large page with a LOT of links and search terms, and no content or anything. You could write a bot to do that. Google has gotten wise to it however, so now the links are hidden within nonsense blogs. You might have heard of this practice, it's called <a href="http://en.wikipedia.org/wiki/Search_engine_optimization">SEO</a> blogging. And a bunch of hapless comparative lit majors get paid minimum wage to write those blogs posts. So yeah, that's what this show is about: one of the dirtiest and most despised jobs in tech, just a step above those guys who fill your inbox with ads about Viagra. But enough intro. I linked below the most popular episode released so far, and my personal favorite, episode 4. Watch it and judge for yourself!</p><br /><br />
<iframe width="640" height="360" src="http://www.youtube.com/embed/NRVoOcElaX0" frameborder="0" allowfullscreen></iframe>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-77868276652877741632013-02-24T20:16:00.001-06:002013-02-24T21:12:29.803-06:00How to choose the correct format for your academic figure<p>If you're using jpeg for all of your graphics, you probably want to read this. If you are using BMP for all your graphics you either really know what you're doing or you MUST read this.</p>
<p>I often get asked about figure generation and converting figures from one format to another, usually for use in a presentation or academic paper. Of course, a lot of this is a matter of taste, but sometimes I see what people do and it makes me want to start a huge lecture about the ubiquitous abuse of jpegs and the distinction between vector graphics and bitmap graphics. But I'm usually a generous person, and often I just give them a few quick hints. So here it is, for your pleasure, the basics of graphics formats and their intended uses. <b>Caveat:</b> I am by no means an expert at this stuff. Most of what I know is from the wikipedia articles.</p>
<h2>Vector or Bitmap?</h2>
<p>Before I go into the nitty-gritty, there's a few things we need to discuss. The main one is the distinction between vector graphics and bitmap graphics. These are the two main paradigms of image storage and understanding the strengths and limitations of both is crucial.</p>
Instead of a long diatribe, however, I will try and present this in as few images and words as possible. The image below, which I pulled from Wikipedia, summarizes this section:
<p>
<div class="separator" style="clear: both; text-align: center;">
<img border="0" width="200" src="http://upload.wikimedia.org/wikipedia/commons/a/aa/VectorBitmapExample.svg" /></div>
</p>
<p>
To put it in words, there are two main ways of representing images inside a computer: <a href="http://en.wikipedia.org/wiki/Raster_graphics">raster</a> (or bitmap) images are stored as arrays of numbers, where each number represents the color and transparency of one tiny block of the image, a pixel; a <a href="http://en.wikipedia.org/wiki/Vector_graphics">vector image</a> is instead stored as a collection of lines and circles and other similar geometric primitives, generally known as paths. In a bitmap image two points cannot be closest than one pixel apart, which is a function of the resolution of your image. So, when you zoom in, eventually you hit that pixel limit and your image starts looking like an old Atari game. In a vector image the position of each end of a line (or primitive node) is stored as a high precision number, which means that if the distance between two points is greater than 1e-12 you will eventually be able to tell them apart by zooming in enough (although I would recommend spending your time on more valuable endeavors, like writing blog posts for the benefit of the technologically hungry).
</p>
<p>
If the above didn't make sense, or it did but the implications are not clear, or if you simply don't care about the details, here is what it boils down to: <b>use raster formats for things you do not know the geometry of</b>, like scanned in pictures of your dog or screenshots of your sweet desktop arrangement; <b>use vector graphics for images where geometry is known or obvious</b>, like computer generated graphs, schematics, or cartoons.
</p>
<h2>Common image formats and what to use when</h2>
<p>The above stuff is all well and good, but it doesn't really tell you why using jpegs indiscriminately is bad, and that's what you're here for, right? Since nothing is better explained than by example, I'll give a few scenarios and my personal preference (and reasons) for doing the voodoo that I do.
</p>
<h3>Pictures of my dog</h3><p>
Ok, I don't actually have a dog, but if I were to have one I would name it <a href="https://www.google.com/search?q=Jake+the+dog&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a&um=1&ie=UTF-8&hl=en&tbm=isch&source=og&sa=N&tab=wi&ei=yK4qUYPbB5H-rAGOsICoAQ&biw=1063&bih=592&sei=yq4qUYbyOMe5rQG3v4CIDA">Jake</a> and take a million photos of him, and stick that stuff in <a href="http://www.gimp.org/">GIMP</a> in order to add party hats to its cute head. If you have an amateur camera like mine, it will likely not give you much of an option as to the type of image it saves. It will probably be JPEG, and with good reason: <a href="http://en.wikipedia.org/wiki/JPEG">JPEG</a> is a compression algorithm for raster images that is specifically designed to work well on standard photographic material. For example, JPEG does really well (high compression ratio with very small loss in perceived quality) for pictures of sand, or dogs, i.e. where there is already a lot of information we perceive as nothing more than just noise. It does and adequate job for pictures of faces, but it does a not so good job for certain Joan Miro paintings, where it often fails to preserve edge sharpness. Unfortunately your crappy camera does not give you an option, so this is the best you're going to get, so just turn the compression quality to High and live with it. Or else buy a decent camera that allows you to store images in raw format (large files, no compression) or tiff (lossless compression) but at that point you're turning into a professional photographer and you're only reading my post for the jokes.</p>
<h3>Screenshots and scanned images</h3><p>
Because JPEG compression does not do well with edges, and because computer generated images, like screenshots, often involve sharp edges, some clever people got together and invented a different compression algorithm: <a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics">PNG</a> (portable network graphics). This is in many ways similar to JPEG, but is in no way a replacement. Rather, it complements it. While JPEG is good at encoding originally noisy raster images and bad at edges, PNG is good at edges but bad at preserving the noisiness of sand on a beach. That is why, when you take a screenshot, save it as a PNG. And, most importantly, don't save it as a JPEG and then change it to a PNG: every time you re-encode you lose quality and suffer from the downsides of your algorithm.
I made the images below to show the differences between the two formats. First up is a picture of tux, the beloved linux penguin:</p>
<p style="text-align:center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtLMn781p_tegY2cJhB2qISvklZ-fjylHoAzcqhg13bT_72Xi5WKwlVReRN4TByDKgmuwQEd9MluvJuz2wINUI8YQB_pBEqgehIm0L2Hy0c2pCU9aKO0eRQiICth35aX0WGlymUk2xx3C2/s1600/tux-mix.png" imageanchor="1" ><img align="center" width="600" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtLMn781p_tegY2cJhB2qISvklZ-fjylHoAzcqhg13bT_72Xi5WKwlVReRN4TByDKgmuwQEd9MluvJuz2wINUI8YQB_pBEqgehIm0L2Hy0c2pCU9aKO0eRQiICth35aX0WGlymUk2xx3C2/s320/tux-mix.png" /></a></p>
<p>
I encoded the image as both PNG and JPEG to have the same file size. They look pretty similar, but if you zoom in you start to notice nasty artifacts in the JPEG version. Here are the original files for comparison: <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGDC07-Pd8j3N4JSCt-6zlvOx5F6wkhKZPhwFYexaso03pYqK48UfY_UGg-mnNNpuDayZEe-cEnFUvohlqZvGdN9-Z7N5DitrSMMX1-RgYgJ8P5cU1xYdlXp0jVEY16AYLYItOR6RhWZMd/s1600/tux.jpg" imageanchor="1" >tux.jpg</a> and <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_4jSoaI6zz_XKv3YnAxsx5jZ02tq_BVD35jO9FrG0OZTTRf2q1u_SBA1uKPeP_51QO1UhKHedW8hmUyi6Mk2kyJ5XETmyrl7a7fXc16vfKFsrLveXw-j4YXX7kvqcV4zJDkB3e45l_cYr/s1600/tux.png" imageanchor="1" >tux.png</a>.
On the other hand, this next image shows the downside of PNG. </p>
<p style="text-align:center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyvvUVt4znZZt-fDpe0Kc36QATwTBu0-vxttoROS5boaP0Az557jHb7RK019pALks3VEYykddmLM2Ud7nbyMiA_N5ad4m7PZ08pjz5LDgVsUSLRDNcjIU077_jvU30wIlHawMAIILNKKuM/s1600/gravel-mix.jpg" imageanchor="1" ><img width="500" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyvvUVt4znZZt-fDpe0Kc36QATwTBu0-vxttoROS5boaP0Az557jHb7RK019pALks3VEYykddmLM2Ud7nbyMiA_N5ad4m7PZ08pjz5LDgVsUSLRDNcjIU077_jvU30wIlHawMAIILNKKuM/s320/gravel-mix.jpg" /></a>
</p>
<p>
Both images look (at least to me) to be the same quality, but the size of each file is very different. And that's with a low level of JPEG compression. I could have dialed the compression up quite a bit with very little changes to the observed quality. Again, original images are <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIZ263spVmrOVNVxbgaE-wXQvVeQVOie27u9qBPjrnhOIhsws-EKAzS6-yDWOic2GzxcSb-0SqbY7y1kYEekMDbq9XHtaVz8VWo27TXj8sFfuKzkr7qJHbHzZEzDm4fYiNkVNwIX1cJNnm/s1600/gravel.jpg" imageanchor="1" >gravel.jpg</a> and <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu_YeTO1nwG5h33EtzwmrCypJA-29bIL7BITa0YY_Rj1B1Kdstsjz5e_pqEpwZZuRIckxluvQnBVlcfcr7oxAHt-VrS9waL87gby5u81xWcRFxFbjNmYQRZh9NNavCZCBFrbZMXU5NoL86/s1600/gravel.png" imageanchor="1" >gravel.png</a>.
</p>
<p>
Other uses for PNGs are creating a raster image of an icon or cartoon or sketch. All the twitter icons in all your apps: they are likely pngs. Most webcomics publish their art as PNG. If you are going to scan a sweet doodle you made, or save that drawing you made using your wacom tablet, PNG is probably your best choice. You get the gist, I hope.
</p>
<p>
One small note here: if you're scanning documents that are mostly text, and your scanning software is not something last modified in the previous century, you likely have the option to use <a href="http://en.wikipedia.org/wiki/Optical_character_recognition">OCR</a> (Optical Character Recognition) while scanning, and obtain a PDF. If you have this option, I highly recommend you use it. It will try and do character recognition for your document, which will result in your being able to select text from your scanned document and copy-pasta it anywhere you want it. Not to mention that, unless you mess with the options, the original image of the scanned document will still be what is visible, so regardless of the quality of OCR, your document is still be readable by eye. </p>
<h3>Graphs and Sketches</h3><p>
And here we are at my favorite section, and that is creating vector graphics from scratch. This is your best option whenever you create digital images outside of the restrictions in the previous sections. So, when do you create images on a computer? A lot of people I know use MATLAB to generate plots of their data. Others use R or python or whathave you. Sure, you can save your graphs as a high resolution JPEG and lug around 50 files one megabyte each, digital storage is cheap and getting cheaper, right? But what if you really want to zoom in on one of those plots later on? What if you want to change some text on it, but you lost all the data and regenerating the plot is out of the question? You use JPEG and you're hosed. That's why you use a vector format instead: <a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics">SVG</a>, <a href="http://en.wikipedia.org/wiki/PDF">PDF</a>, <a href="http://en.wikipedia.org/wiki/Encapsulated_PostScript">EPS</a>. The advantages are plenty: your file will be smaller in size and also editable outside of the software that created it; not to mention you can zoom in up to infinity. You can use Adobe Illustrator (costs $) or <a href="http://inkscape.org/">Inkscape</a> (open source) to edit any of the text or even change the colors of your curves or thickness of your axes. Everything is easy!
Now that we're at vector graphics software, let's say you want to make a diagram, or sketch of a mechanism. Are you going to use Photoshop? Boo! Photoshop (and its free cousin, gimp) are great programs but they are made for editing photos and other image manipulation tasks (as their names imply). Sure, they both have *some* vector graphics capabilities built in, but if you're going to make a clean sketch it's like using a bread knife to mow the lawn: it will work, but do you really want to do it when there's a brand new lawn mower in the garage? So go ahead and download <a href="http://inkscape.org/">Inkscape</a> or <a href="http://ipe7.sourceforge.net/">ipe</a> (they are free) and play around for a while. Save your stuff as SVG if you're going to post it on the web, or PDF if you're going to use it in your dissertation ($\LaTeX$ ftw).</p>
<h3>When Vector Graphics Goes Bad</h3><p>
I have encountered only one significant case where all the above information would have had me using vector format for an image but instead the correct choice was to encode it as PNG: a vector image with a very large number of primitives. Imagine you are doing a scatter plot of something like ten thousand data points, and you save it as PDF. There will be points all over each other, you won't be able to actually see more than a few hundred of them, but yet the image will be a few megabytes in size and it will take seconds to load (I know, I could just become a patient person, but I'd rather spend my time figuring things out rather than waiting on needless computation). So, all of a sudden, the love affair with vector format has come to bite you in the proverbial ass. Maybe your paper is even too big to submit to the conference! You have a few options, depending on how crafty you want to be. First, just give up, save that image as PNG, go home and have a cold one. If you want to be fancy, you can do the following. Save two images, one just the axes and the text, saved in SVG format. The other, just the troublesome datapoints, in PNG format. You can then go into your favorite vector image program and merge them together, save as a PDF. PDFs are awesome because they allow you to mix vector and raster images. You will still be able to select the text, modify later and everything else, except for the data points. But your image will be small and manageable again. </p>
<h2>Conclusion</h2><p>
There is one format suitable for every purpose. When in doubt, read the wikipedia entry for it. You will learn a ton. Then use that information to your advantage to make your stuff look consistently good, have consistently small file sizes (and load times), and finally help yourself out by keeping as much of an image editable as you can. I could not count the times my adviser wanted a slightly larger font on my figure and because of poor planning it meant I had to re-run an overnight simulation to do it. I've been there and done that, and you don't have to repeat my mistakes!</p>
Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com1tag:blogger.com,1999:blog-1368377174687053564.post-88769946616796135762012-11-13T16:38:00.002-06:002013-02-24T21:12:04.181-06:00Adaptive Time Step Integrators in SciPyFor one of my projects at school I have to numericaly integrate a bunch of ODEs, something I would normally do using ode45 in Matlab or NDSolve in Mathematica. However, since the rest of my code is written in Python, and I really don't want to install the bloatware that is Matlab on my clean linux machine, I've decided I was going to try out the ODE libraries that come with numpy and scipy. As it turns out, they're not too bad, but their documentation is. So, it took me a while to figure out how to do this, and I'm guessing someone else will probably benefit from this post (I know it would have saved me about a day's work, at least).<br><br>
So, it turns out that scipy doesn't really implement its own ode solver, but instead wraps a bunch of FORTRAN code, and just silently drops like 80% of the functionality of that code without documenting much of what it kept and what it ignored. Anyway, after sifting through a bunch of forums and a whole bunch of source code, I came to the conclusion that the only function that can <b>actually</b> do adaptive time stepping <b>and</b> supply dense output is the wrapper around the vode integrator. The other thing that I needed was to detect when my trajectory crosses a certain boundary defined by $\phi(y) = 0$ and trigger an event at that point. In my case I simply needed to restart integration after adding the crossing point to the solution array.
The following code does what I needed:
<pre class="prettyprint">
<code class="lang-py">def f(t, y):
# define your \dot{y}=f(y,t) here
def phi(y):
# this function defines the boundary that is crossed
from scipy.integrate import ode
# set up the solver, with a maximum time step of 1e-1
# an initial condition of y0 = init and t0 = 0
solver = ode(f)
solver.set_integrator('vode', max_step=1e-1)
solver.set_initial_value(init, 0)
tfinal = 30 # run this for 30 seconds
t = [0]
y = [init]
# call the solver iteratively with the 'step' option
# what this does is it returns the result of the integration
# after the next (variable) time step, and the length of that step
while solver.successful() and solver.t < tfinal :
solver.integrate(tfinal, step=True)
y.append(solver.y);
t.append(solver.t);
# check for zero crossing
gg1 = phi(y[-1])
gg0 = phi(y[-2])
if gg0*gg1 < 0 :
# find zero crossing
# simple linear interpolation will do for now
tcross = t[-2] - gg0*(t[-1]-t[-2])/(gg1-gg0)
ycross = y[-2] - gg0*(y[-1]-y[-2])/(gg1-gg0)
# replace wrong y and t
y[-1] = ycross
t[-1] = tcross
# reset integration and start again
solver.set_initial_value(ycross, tcross)
print("crossed the boundary at time ", tcross)
</code></pre>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-90842230712558689352012-10-26T16:39:00.001-05:002013-02-24T21:12:29.805-06:00Exporting Videos in Mathematica (the hard but nice way)Have you ever tried to export your sweet looking Mathematica animation only to end up with some crappy quality video that doesn't seem to play anywhere? Well, you're about to leave that behind for good, because I'm going to teach you how to obtain videos of perfect quality out of that accursed IDE. The way we'll do it is we'll export high quality pdf/png frames of your movie, and then stitch them all together into a custom video.
First off you'll need some tools. I used ffmpeg and imagemagick, command line utilities, in order to convert pdfs to pngs and stitch frames together. On linux they are easily available from your repositories. For Debian, for example, you just do
<pre class="prettyprint"><code class="lang-bsh">apt-get install ffmpeg imagemagick</code></pre>
On OS X it's also relatively simple, provided you're already using macports (or fink, or homebrew). For macports, the command is
<pre class="prettyprint"><code class="lang-bsh">sudo port install ffmpeg imagemagick</code></pre>
For Windows you're on your own, since I haven't ran that platform in years and I don't know how you get software for it anymore. I'm sure you can find a tool for the purpose somewhere on Google.
Ok, I'll also assume you have Mathematica installed (otherwise you wouldn't be reading this) and a good understanding of how to use it. Then you want some code very similar to what I pasted below, as well as an implementation of the Draw[] function.
<pre class="prettyprint">
<code class="lang-ml">
(* make sure that the default export path is in the same place as your .nb file *)
(* I actually have this as the first line in pretty much all Mathematica files *)
SetDirectory[DirectoryName[ToFileName[
"FileName"/.NotebookInformation[SelectedNotebook[]]
]]]
(* export slides *)
Do[
(* here I export every 5th slide, but they have to be named
sequentially, hence the Ceiling[] call. *)
oFile = StringForm["./frames/frame`1`.pdf", Ceiling[i/5]];
oFile = ToString[oFile];
(* this call exports a picture to oFile *)
(* Draw[i] takes the frame number and returns a graphics object *)
Export[oFile, Graphics[Draw[i], (* extra options for Graphics[] *) ]],
(* the do loop counter, picking every 5th frame*)
{i, 1, Length[tk], 5}
];
</code></pre>
Ok, you need to change the code to suit your needs, but most of the heavy lifting gets done in the Draw[] function, which you already know how to write, right? We're exporting to pdf, which makes for some really good quality. If you do it all right you should have a subfolder called frames filled with pdf files named frame1.pdf, frame2.pdf, and so on. This is awesome, we're halfway done!
Next you need to stitch those frames together. If you're in Windows, you best be using cygwin or something equivalent, otherwise you're on your own. In *nix, you open a terminal (don't worry, it won't bite), cd to the frames directory and run
ffmpeg :
<pre class="prettyprint"><code class="lang-bsh">cd ~/path/to/math/code/file/frames
for f in frame*.pdf do convert -density 300 "$f" "{$f/.pdf}".png done
ffmpeg -q:v 1 -r 25 -i frame%d.png video.mp4
</code></pre>
What this does is convert all the pdfs to png, with a 300dpi density and then it merges all the frames into a video, showing 25 frames per second (-r 25) and keeping the video quality of the original images unchanged (-q:v 1). That's it, you're done!Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-18734050949291188022012-10-17T14:02:00.002-05:002013-02-24T21:12:04.179-06:00Chain Rule under Einstein NotationOK, so the other day I was trying to do all this symbolic math in order to get expressions for the derivatives of certain mappings from one vector space into another. Ultimately, all this would go into a Python function. When dealing with the first derivative things are pretty easy, because all you have is matrix-vector multiplication, and you can easily do that using NumPy's dot() function. The problem was that second and higher derivatives started showing in my formulas. These are higher dimensional tensors, and all of a sudden it is not clear what row multiplies what column when (for example, there are two ways to right multiply a 3-tensor to a vector) and what dimensions get added where when derivatives are taken. In particular, I was having a lot of trouble with applying chain rule. After reading <a href="http://en.wikipedia.org/wiki/Ricci_calculus" target="_blank">the wikipedia article on Ricci calculus</a> I wrote down a simple little rule for chain rule in index notation. Here it is:<br />
<br />
Suppose we have a vector valued mapping $A^i(\mathbf{x})=B^i\left(\mathbf{C}\left(\mathbf{x}\right)\right)$ and we want to find its derivative with respect to $x^i$. We do this by applying chain rule, but first a little bit about the notation. The superscript denotes that $\mathbf{A}$ is a column vector, and the little equality above simply says that the $i$th element of $\mathbf{A}$ is equal to the $i$th element of $\mathbf{B}$. Now, we want to take the derivative with respect to $x$, which is also a column vector. The standard notation for this is<br />
\[ \partial_{x^j}A^i(\mathbf{x}) = A^i_{,\,j}. \]<br />
Now, on to chain rule. We drop the arguments of the functions, since they are unambiguous. Then, we write:<br />
\[ A^i_{,\,j} = B^i_{,\,k}C^k_{,\,l}x^l_{,\,j} = B^i_{,\,k}C^k_{,\,l}\delta^l_j = B^i_{,\,k}C^k_{,\,j} .\]<br />
And that's it! Now you know how to do chain rule, so taking derivatives and calculating them in [insert favorite programming language here] should be a piece of cake!<br />
<br />
p.s. I might have been a little bit sloppy in my terminology and notation, but I am open to suggestions. <br />
p.p.s. I have enabled $\LaTeX$ in my posts and comments. Feel free to give it a try!
<script type="text/javascript">MathJax.Hub.Queue(["Typeset",MathJax.Hub]);</script>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com1tag:blogger.com,1999:blog-1368377174687053564.post-75049309531350252962012-10-09T15:32:00.000-05:002013-02-24T21:12:44.925-06:00vim trick #2Yet another very useful vim trick: do you ever open a system config file but forget to open it with <b class="prettyprint">sudo</b>? You make the changes but then, when it's time to save it, you're hosed. You have to save as a temp file, then move it to the right place, a whole lot of ugly. Well, not anymore! Put this in your <b class="prettyprint">.vimrc</b> file and save with <b class="prettyprint">:w!!</b> instead of <b class="prettyprint">:w</b>. That's it!
<pre class="prettyprint">cmap :w!! %!sudo tee > /dev/null %</pre>
What this does is sends the current file to 'sudo tee'. Now, tee here is used as a hack, as its regular function is to both redirect input to a file and to standard output. We are not interested in the standard output so we pipe that to <b class="prettyprint">/dev/null</b> (otherwise it shows up in the vim window), and tell tee to overwrite the file we have open, with <b class="prettyprint">sudo</b> power. One last thing is, vim will ask you to reload the file, because it was modified outside of the editor (duh!), so go ahead and do that. Nifty, eh?Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-64580132357768072522012-08-01T13:22:00.000-05:002013-02-24T21:11:08.738-06:00Make ntfs-3g automount your drive in write mode under OS X<style type="text/css">
pre.CICodeFormatter{
font-family:arial;
font-size:12px;
border:1px dashed #CCCCCC;
width:99%;
height:auto;
overflow:auto;
background:#f0f0f0;
line-height:20px;
padding:0px;
color:#000000;
text-align:left;
}
pre.CICodeFormatter code{
color:#000000;
word-wrap:normal;
}
</style>
I just found a great <a href="http://fernandoff.posterous.com/ntfs-write-support-on-osx-lion-with-ntfs-3g-f">blog post</a> on how to get your NTFS write on in OS X (Lion). I won't go into details, since the other post does, but for the impatient, here is the route I chose to take, since I already had most of the things installed and up to date: using macports I installed fuse4x and ntfs-3g, and the I replaced the /sbin/mount_ntfs binary with the one provided on the site (it is basically a script that calls the ntfs-3g utility with the proper arguments). That's it!
<p>
<u>Edit:</u><br>
Turns out the method above, while it does work, makes for very slow write (and read) speeds, especially over USB. So I switched to a commercial version made by <a href="http://www.paragon-software.com/home/ntfs-mac/">Paragon</a> which boasts (and so far seems to deliver) speeds comparable to native file systems. Sorry open source, I love you, but I don't want to wait an eternity to copy my files to my usb drive.Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-36869914251779892972012-05-09T12:42:00.000-05:002013-02-24T21:12:44.924-06:00vi tricks #1<style type="text/css">
pre.CICodeFormatter{
font-family:arial;
font-size:12px;
border:1px dashed #CCCCCC;
width:99%;
height:auto;
overflow:auto;
background:#f0f0f0;
line-height:20px;
padding:0px;
color:#000000;
text-align:left;
}
pre.CICodeFormatter code{
color:#000000;
word-wrap:normal;
}
</style>
Been working with vim lately and every day I discover new tricks. I figured I'd post things here as I they might be of help not only to me, but also to the internet at large.<br />
<br />
First up, suppose you want to insert a large number of the same character or string, for example in order to write a comment box, or something similar. Instead of typing "*" 30 or so times, thus shortening the life of the "8" key on your keyboard, you can do this, in normal mode:
<pre class="CICodeFormatter" ><code class="CICodeFormatter"> <number>i<string><ESC>
</code></pre>
For example, want to make a lot of $$$? Just type
<pre class="CICodeFormatter" ><code class="CICodeFormatter">300000i$<ESC>
</code></pre>
and you'll be set for a life(ish)!Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-48364889072350405192011-01-12T20:22:00.000-06:002013-02-24T21:15:15.503-06:00war of the worlds<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhngm8q_r8D6dv_Rq2LJTnWu5ffWiu6lUuL_PPUmA9pD67P7VcGX6lrKFfP2gsXiSiUxVnAmvyOKOfsZsml4niVgLLZabOD21hzKwFucGAPt6Jl-8-VD9g-SaikWGjeJaGY99tROgZ0oROA/s1600/spider_spawn.JPG" imageanchor="1" style="clear: right; margin-bottom: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhngm8q_r8D6dv_Rq2LJTnWu5ffWiu6lUuL_PPUmA9pD67P7VcGX6lrKFfP2gsXiSiUxVnAmvyOKOfsZsml4niVgLLZabOD21hzKwFucGAPt6Jl-8-VD9g-SaikWGjeJaGY99tROgZ0oROA/s400/spider_spawn.JPG" width="400" /></a></div>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com4tag:blogger.com,1999:blog-1368377174687053564.post-55721770191634782442010-07-26T12:46:00.000-05:002013-02-24T21:15:15.504-06:00exhibitionist vampire dragon<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3PV_YJSNQdBMK40iq6XSCEbuEtwsjmArQprlGh_2qsfy3vXOeD3ldz9OBsoHmabxIljtUxcyf-GNSDej55Nwo2xdyFOi2MklJN8BuZx-R-wEKvtTbgSnZ4-nkckwdqjVMHh8hzDvQYhl-/s1600/covered.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3PV_YJSNQdBMK40iq6XSCEbuEtwsjmArQprlGh_2qsfy3vXOeD3ldz9OBsoHmabxIljtUxcyf-GNSDej55Nwo2xdyFOi2MklJN8BuZx-R-wEKvtTbgSnZ4-nkckwdqjVMHh8hzDvQYhl-/s320/covered.png" width="304" /></a></div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNBa1oSZwybAGers2R0oOqM61cJPDPtZxmcezczmFFRUe3HUUdoE2EGFKsHbs3gMsa6o-qPpYkmHHyS2a5dkmraBkCrKUkWYXl4EUyh5QXURAJu4vOlIhqLb2o6VOWvCXpcBOy_V_UKmv6/s1600/exposed.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNBa1oSZwybAGers2R0oOqM61cJPDPtZxmcezczmFFRUe3HUUdoE2EGFKsHbs3gMsa6o-qPpYkmHHyS2a5dkmraBkCrKUkWYXl4EUyh5QXURAJu4vOlIhqLb2o6VOWvCXpcBOy_V_UKmv6/s320/exposed.png" width="304" /></a>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-41432483577453538592010-07-26T12:42:00.000-05:002013-02-24T21:15:15.498-06:00mandala<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi66mLtvVXZT6g8q0awgghwmt9icM97315-5_1Ft9IhsxdYkyZGJ6rpHW3X3GOsgZvOmLj9K6vF-JFlBZbu1RpyF1mGoa7tDk1aX1wi84_hHiqiN0mLGvvb-eS_rTUmMsmIMzy4lQR7Vwvz/s1600/colored.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="382" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi66mLtvVXZT6g8q0awgghwmt9icM97315-5_1Ft9IhsxdYkyZGJ6rpHW3X3GOsgZvOmLj9K6vF-JFlBZbu1RpyF1mGoa7tDk1aX1wi84_hHiqiN0mLGvvb-eS_rTUmMsmIMzy4lQR7Vwvz/s400/colored.png" width="400" /></a></div><br />
<div style="text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgd7XJoJI_MwpwfssVaHObM5JnOPLTbjP78B2EdMnUjdirPFD0bKnTpwmO35Illx1E9SjJu7QLou-opckyiJRT6Cp5mv3sAOyhiJwKYe8ewP__brOJsXziwmX_ig5SeDSWOVi-XjQRxBP5/s1600/bw.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgd7XJoJI_MwpwfssVaHObM5JnOPLTbjP78B2EdMnUjdirPFD0bKnTpwmO35Illx1E9SjJu7QLou-opckyiJRT6Cp5mv3sAOyhiJwKYe8ewP__brOJsXziwmX_ig5SeDSWOVi-XjQRxBP5/s400/bw.png" width="400" /></a></div><br />
If the symmetry seems a little bit too perfect, that's because it is. I cheated and only drew a quarter of the image.Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-7915292027458333302010-07-16T22:45:00.000-05:002013-02-24T21:15:15.509-06:00punk<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLWPEzFVw_ODcVhiy4O_oRg-FKs53psH9k6PTGPCDahMo5YQ7nu-DkqnLC2rrRXvM5bVryMzMZDSVyRM0kZXVm0oehjQfH00kgZKTYVSEWtyuuX3OKw3D3VPDAvIyNf8VTfgf2Sgwoffa9/s1600/punk.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLWPEzFVw_ODcVhiy4O_oRg-FKs53psH9k6PTGPCDahMo5YQ7nu-DkqnLC2rrRXvM5bVryMzMZDSVyRM0kZXVm0oehjQfH00kgZKTYVSEWtyuuX3OKw3D3VPDAvIyNf8VTfgf2Sgwoffa9/s400/punk.png" width="356" /></a></div>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com1tag:blogger.com,1999:blog-1368377174687053564.post-35564773371654549222010-01-12T22:49:00.000-06:002013-02-24T21:15:15.493-06:00curly<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDbTjYezJYUZoPSU3ePze20vgqyTd6UCEjcvvHnhQ2PciUzBCzExQGkh8L_4U3hfXC87EyU1KDXesEb2cR9QCRJzlScIteDdu_Ipp0IIMi0PvA9uFktX0Owk59fcsXqj_G9lKpbLThUXlc/s1600-h/curly.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDbTjYezJYUZoPSU3ePze20vgqyTd6UCEjcvvHnhQ2PciUzBCzExQGkh8L_4U3hfXC87EyU1KDXesEb2cR9QCRJzlScIteDdu_Ipp0IIMi0PvA9uFktX0Owk59fcsXqj_G9lKpbLThUXlc/s400/curly.png" /></a><br />
</div>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com1tag:blogger.com,1999:blog-1368377174687053564.post-46225603561505066262010-01-09T15:40:00.000-06:002013-02-24T21:15:15.501-06:00go out in a blaze of glory<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjArimIsh7V5zjGesvDkHAS1KRzuDaPnpHw-Csx1Kq04bmLSztJOgKaDk5pMY0g4EXHSk5mWPgVV-J0fPKErzWLRPYFRG8rWNtHD3yBduTBHnMV9shglMegbKhEU82axJ6gdh1VBlWzFI6e/s1600-h/suicide.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjArimIsh7V5zjGesvDkHAS1KRzuDaPnpHw-Csx1Kq04bmLSztJOgKaDk5pMY0g4EXHSk5mWPgVV-J0fPKErzWLRPYFRG8rWNtHD3yBduTBHnMV9shglMegbKhEU82axJ6gdh1VBlWzFI6e/s400/suicide.png" /></a><br />
</div>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-61388667058416197202009-11-09T20:12:00.000-06:002013-02-24T21:15:15.505-06:00emotionally aware<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5zmlO2X0pngEBD2IPViPWg-41egrS5wPrzjbrgi9scJtb_40BrWyfRYhBjMq0QY8aBhYSTwqhKgF3EmLrV_yMCyaQzaihslR2maiwdvZARFxWJVKN2PFEqqq6ZOtIxduc3K8cXvQfJDGK/s1600-h/jar_collection.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5zmlO2X0pngEBD2IPViPWg-41egrS5wPrzjbrgi9scJtb_40BrWyfRYhBjMq0QY8aBhYSTwqhKgF3EmLrV_yMCyaQzaihslR2maiwdvZARFxWJVKN2PFEqqq6ZOtIxduc3K8cXvQfJDGK/s400/jar_collection.png" /></a><br />
</div>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com2tag:blogger.com,1999:blog-1368377174687053564.post-41098000729764398662009-11-05T21:02:00.001-06:002013-02-24T21:15:15.497-06:00candy bar comics<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUGod-Fz6Vn_BT6gB7HIwWUNXOgQG4Aphn9_uaf8OSDb9pX2bs8Hs3a6ajnr-xO_VoGpoxIf8-_C4ixjb8OQCgXHFFq_h76IjjNgkqgvYqCHiDYvRZSrKixBej2HtUqyuerJLtqIvQeBMl/s1600-h/candy_bars.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUGod-Fz6Vn_BT6gB7HIwWUNXOgQG4Aphn9_uaf8OSDb9pX2bs8Hs3a6ajnr-xO_VoGpoxIf8-_C4ixjb8OQCgXHFFq_h76IjjNgkqgvYqCHiDYvRZSrKixBej2HtUqyuerJLtqIvQeBMl/s400/candy_bars.png" /></a><br />
</div>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-39236856991746413872009-11-01T18:04:00.000-06:002013-02-24T21:15:15.495-06:00dude was partying without a permit<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhELoHt6aJQC_E-gkJD_Crsr8T25zm3hHyEaTE23hINI0AIohFaLMsBZM64kC_bdcLRQxT4TfNL3QgwEYSlX0TjdoL54GZ9Uz9OIjptIhLlcLPh92zRCmfccKgYajMdc8WGjgkhbBheu6Od/s1600-h/illegal_alien.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhELoHt6aJQC_E-gkJD_Crsr8T25zm3hHyEaTE23hINI0AIohFaLMsBZM64kC_bdcLRQxT4TfNL3QgwEYSlX0TjdoL54GZ9Uz9OIjptIhLlcLPh92zRCmfccKgYajMdc8WGjgkhbBheu6Od/s320/illegal_alien.png" /></a><br />
</div>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com1tag:blogger.com,1999:blog-1368377174687053564.post-9339495118663388842009-11-01T14:23:00.003-06:002013-02-24T21:15:15.513-06:00motivational series #1<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzRLKT6ylXjchtRqXx49-TfQ13uM8oqMwdhAWb8uhDHG4Hu4Wi5QpL6KmZMwg4BX0IoepU-87t8vF1g9ok5EuFPBFz9dM-JxPxhNowqep8N8NtYYgJoNNCQTgyh04uyv5hA76MUkfQvb79/s1600-h/turd_sammy_1_sml.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzRLKT6ylXjchtRqXx49-TfQ13uM8oqMwdhAWb8uhDHG4Hu4Wi5QpL6KmZMwg4BX0IoepU-87t8vF1g9ok5EuFPBFz9dM-JxPxhNowqep8N8NtYYgJoNNCQTgyh04uyv5hA76MUkfQvb79/s400/turd_sammy_1_sml.png" /></a><br />
</div>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-45183577460038450572009-10-24T15:20:00.000-05:002013-02-24T21:15:15.500-06:00birthday drama<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAxaPUl0E_5bMS3Xvuksb3iSbARn_BpKivoZ1ILxvvg6wOcXPMjg8Sone-6yXmCeNahfGrUiCLth_9mw-Q9EvfIfnZ8n-u8s3Ca8Jepb-uvgUSs-bURXOcgwqCKoP6kcU-uYgkkvGc3mAt/s1600-h/birthday_asshole.png"><img style="cursor: pointer; width: 320px; height: 238px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAxaPUl0E_5bMS3Xvuksb3iSbARn_BpKivoZ1ILxvvg6wOcXPMjg8Sone-6yXmCeNahfGrUiCLth_9mw-Q9EvfIfnZ8n-u8s3Ca8Jepb-uvgUSs-bURXOcgwqCKoP6kcU-uYgkkvGc3mAt/s320/birthday_asshole.png" alt="" id="BLOGGER_PHOTO_ID_5396264064539097538" border="0" /></a><br /><br />in case it's not clear, that's a middle finger salute, not a thumbs up.Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com1tag:blogger.com,1999:blog-1368377174687053564.post-36724701002095418872009-10-13T21:59:00.002-05:002013-02-24T21:15:52.763-06:00retaliation<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyH9UWUD-9zyPORVTKFWogPLSF4rexfwTlqSM-bypJcYoEHXQD-0zz9y3Vixxlvo4tSatNu6d2Xy9xTKAW9CjSCzdWUuNU4fb7GEPWAw6pRTiXQZCDzdaL8E8rJMHrgCVRainH-Y76lu0w/s1600-h/six_fingered_glove_trace.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyH9UWUD-9zyPORVTKFWogPLSF4rexfwTlqSM-bypJcYoEHXQD-0zz9y3Vixxlvo4tSatNu6d2Xy9xTKAW9CjSCzdWUuNU4fb7GEPWAw6pRTiXQZCDzdaL8E8rJMHrgCVRainH-Y76lu0w/s400/six_fingered_glove_trace.png" width="400" /></a></div><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The text sucked. Please provide suggestions. Maybe along the lines of<br />
"You killed my father. Prepare to die!" ?Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com1tag:blogger.com,1999:blog-1368377174687053564.post-79506238967712668992009-10-12T22:00:00.001-05:002013-02-24T21:15:15.511-06:00Breaking up is hard to do<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWr-0L2lUcXeXbCSyG9BaK3BnLkNGKl_VX7yk2wA8wVIhAYFrLNbAl2pHNCkJUAdckakk0Sb9ydc504M9VYubU6BemWJb3XOnOK0HvaRKZoc4626Cyimn2DSUXT1s5xAeTK1hkLFA9R4oI/s1600-h/breakup.png"><img style="cursor: pointer; width: 320px; height: 239px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWr-0L2lUcXeXbCSyG9BaK3BnLkNGKl_VX7yk2wA8wVIhAYFrLNbAl2pHNCkJUAdckakk0Sb9ydc504M9VYubU6BemWJb3XOnOK0HvaRKZoc4626Cyimn2DSUXT1s5xAeTK1hkLFA9R4oI/s320/breakup.png" alt="" id="BLOGGER_PHOTO_ID_5391914285463630882" border="0" /></a>Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0tag:blogger.com,1999:blog-1368377174687053564.post-79432782519633803692009-09-16T10:53:00.001-05:002009-11-01T18:15:31.553-06:00milk dumping, now and thenHere's how they used to do it back in 1934 in Wisconsin<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrDS50JrzU_MJxEAi9RfR4neVOgY59_ge3zNzHTnmysAfcNK_pUbZSyGVruhHNKHbBEvDcwABe-T-6_ZyjCE5AbmrWeHWLmaZxgx2ZvSlmpGBgBfhyCDTmfXAMQyFcWh8CB4AlBvstezXy/s1600-h/milk.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5382094308507683234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrDS50JrzU_MJxEAi9RfR4neVOgY59_ge3zNzHTnmysAfcNK_pUbZSyGVruhHNKHbBEvDcwABe-T-6_ZyjCE5AbmrWeHWLmaZxgx2ZvSlmpGBgBfhyCDTmfXAMQyFcWh8CB4AlBvstezXy/s320/milk.jpg" style="cursor: pointer; height: 192px; width: 320px;" /></a><br />
<br />
and here is how they do it in 2009 Belgium<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9iOjL8LLs3kxSVlcInMlg3ekyYNlm49bNgtAnhOSjZnqnvt5q95DsHkb6fmQQY5N1DjUZif3w0AFeqRrqvVFGwgqq10PmItDedF-zsxs2FGKoV8H1RKtfeOJO9GpqPvJRidy26YgkEiq9/s1600-h/r2223507258.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5382094317778277954" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9iOjL8LLs3kxSVlcInMlg3ekyYNlm49bNgtAnhOSjZnqnvt5q95DsHkb6fmQQY5N1DjUZif3w0AFeqRrqvVFGwgqq10PmItDedF-zsxs2FGKoV8H1RKtfeOJO9GpqPvJRidy26YgkEiq9/s320/r2223507258.jpg" style="cursor: pointer; height: 199px; width: 320px;" /></a><br />
<br />
I think it's safe to say that milk dumping technology has seen major advances in the last century.Anonymoushttp://www.blogger.com/profile/08508338548233449099noreply@blogger.com0