Code
X Window Manager Part 1 – Hello XCB
Minimal X Install
Debian net install. Base system only.
# aptitude install xorg
$ startx
Hello XCB
# aptitude install build-essential libx11-dev libxcb1-dev
Debian 6 Install Log Redux
System Install
[Configure Wifi]
# aptitude update
# aptitude install debian-multimedia-keyring
# aptitude update
# aptitude install sudo
# visudo
# aptitude install xorg openbox obconf menu
Add the following to ~/.xinitrc
exec openbox-session
$ startx
Appearance
# aptitude install gtk-theme-switch gtk2-engines
Use the gtk-theme-switch2 application to switch the GTK+ theme.
cp /etc/xdg/openbox/menu.xml ~/.config/openbox/menu.xml
Arch Linux – Macbook Pro
Install Arch
Basic Arch install without networking using the core CD image. Make sure to add wireless_tools from base-devel.
Configure Wifi
I had to blacklist the bcma module. YMMV. There’s some good info here: https://wiki.archlinux.org/index.php/Broadcom_wireless
The network uses WPA encryption
Verify that the kernel module has been loaded and the hardware is ready to use:
$ iwconfig
Bring the interface up:
$ ip link set wlan0 up
List available networks:
$ iwlist wlan0 scan
Rename the default wpa_supplicant.conf:
$ mv /etc/wpa_supplicant.conf /etc/wpa_supplicant.conf.original
Generate a new wpa_supplicant.conf:
$ wpa_passphrase "ESSID" "SECRET PASSKEY" > /etc/wpa_supplicant.conf
Associate adapter with access point:
$ wpa_supplicant -B -Dwext -i wlan0 -c /etc/wpa_supplicant.conf
Get an IP address via DHCP:
$ dhcpcd wlan0
Test:
$ ping -c 3 www.google.com
Add the following to /etc/rc.local:
$ ip link set wlan0 up
$ wpa_supplicant -B -Dwext -i wlan0 -c /etc/wpa_supplicant.conf
$ dhcpcd wlan0
Reboot and you should be connected to the wireless network.
Configure Pacman and Update the System
Edit /etc/pacman.d/mirrorlist and choose a mirror:
$ nano /etc/pacman.d/mirrorlist
Update the system:
$ pacman -Syu
Add a User
# useradd -m -g users -G audio,lp,optical,storage,video,wheel,games,power,scanner -s /bin/bash kyle
# passwd kyle
Sudo
# pacman -S sudo
Add your user to the sudoers list
# visudo
Add the following to the end of the file
kyle ALL=(ALL) ALL
ALSA
# pacman -S alsa-utils
Use alsamixer to unmute the channels
Packer
Install packer
sudo pacman -S git
cd ~/
mkdir src
cd src
git clone https://github.com/bruenig/packer.git
cd packer
chmod 755 packer
sudo ln -s /home/kyle/src/packer/packer /usr/bin/packer
X and Openbox
# pacman -S xorg-server xorg-apps xorg-xinit xterm openbox
Add exec openbox-session to ~/.xinitrc
Nvidia Driver
# pacman -S nvidia nvidia-utils
Reboot.
# nvidia-xconfig
Trackpad Driver
# packer -S xf86-input-mtrack-git
Add the following to your /etc/X11/xorg.conf
Section "InputClass"
MatchIsTouchpad "on"
Identifier "Touchpads"
Driver "mtrack"
Option "IgnoreThumb" "true"
Option "IgnorePalm" "true"
Option "Sensitivity" "0.7"
Option "ButtonIntegrated" "false"
EndSection
More options here: https://github.com/BlueDragonX/xf86-input-mtrack
Freetype Configuration
TODO
Chromium and Flash
# pacman -S chromium flashplugin
Rails Development
Install RVM:
$ bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)
Close your terminal and open a new one.
Dropbox
Install Dropbox:
# pacman -S dropbox
$ dropbox start
Log in to Dropbox.
PostgreSQL
# pacman -S postgresql
$ createuser -s -U postgres
Enter name of role to add: kyle
$ createdb
Login Redirection with Rails 3.1, Devise, and CanCan
This approach satisfies a few common requirements:
- Requests by non-signed in users should redirect to the sign in page. Post sign in, the user should be redirected to their original destination.
- Requests by signed in users to resources which they cannot access (
CanCan::AccessDenied) should redirect to an error page.
Modify Application Controller
First, update your application controller.
Create Error View
Create app/views/error/403.html.erb. The contents of the file are unimportant.
Create Session Controller
Generate a new session controller:
rails g controller Sessions
Here’s how it should look:
Update Routes
Update your routes so Devise knows to make use of your new sessions controller.
Move New Session View
Move your new session view (if you generated them) from /app/views/devise/session/new.html.erb to /app/views/session/new.html.erb.
HINT: Set config.consider_all_requests_local in /config/environments/development.rb to false to test this while in development.
Ralink RT2870/RT3070 in Debian 6 (Squeeze)
About a year ago, I got this cheap-o USB 802.1n wireless adapter for $15. lsusb reports the device as: Bus 002 Device 002: ID 148f:3070 Ralink Technology, Corp. RT2870/RT3070 Wireless Adapter. In theory, this adapter should be supported out of the box using the rt2870sta module. Of course, just working would be too easy.
To get the wireless adapter to work, we first have to blacklist a few kernel modules.
NOTE: While these instructions are for Debian 6, they should apply to most Debian-based distributions.
Create the following files in /etc/modprobe.d:
$ cd /etc/modprobe.d
$ touch rt2800lib.conf rt2800pci.conf rt2800usb.conf rt2x00lib.conf rt2x00pci.conf rt2x00usb.conf rt61pci.conf
Next, add the following to each file. replacing the name of the module you want to blacklist as necessary (the pattern here should be obvious):
$ cat rt2800lib.conf
blacklist rt2800lib
Next, we need a couple packages. First, install wireless-tools. This should be available on your install media.
$ sudo apt-get install wireless-tools
Next, install the firmware-ralink package. Assuming you don’t yet have an internet connection, you probably won’t find this on your install media as it’s in non-free. I downloaded the package on another computer, transfered it over on a flash drive, and installed it manually.
Reboot. Cross your fingers.
Connecting
# aptitude install wpasupplicant
# iwlist wlan0 scan
# nano /etc/network/interfaces
Add the following:
auto wlan0
iface wlan0 inet dhcp
wpa-ssid ESSID
wpa-psk PASSPHRASE
Bring up the interface.
# ifup wlan0
A Simple Chat Room in Node.js
In this post, we’ll be building a simple chat room using node.js. Here’s how it’ll look:
Getting Started
Install node, socket.io, and express
First, make sure you’ve installed node.js. You’ll also want to grab a copy of the socket.io library and the express framework. These can both be installed with npm via the express and socket.io packages.
Directory Structure
Before we cover each file in detail, here’s how everything fits together. Place the chat directory wherever you like, mine is in ~/projects/chat.
$ ls -R chat
chat/:
public server.js
chat/public:
client index.html
chat/public/client:
socket.io.js
server.js
index.html
Coming Soon…
Next time, we’ll bring canvas to the party. Here’s a preview of what we’ll be building in the next installment:
McMurdo
Lately, Cyclops and Max have been watching the McMurdo Station Webcam. They requested this script after they got sick of saving images manually and searching for ways to animate them.
Uses the excellent Beautiful Soup library, which makes HTML parsing a snap. The program saves images named 1.jpg, 2.jpg, etc. every few seconds. Because the filename on this partiular webcam changes with each new image, we have to rescrape the page each time we want a new image.
Cyclops runs Windows, but this stuff should run wherever Python and ffmpeg are available.
mcmurdo.py
encode.bat
Videos
Nyx 0.0.2
What’s New?
- Nyx is now hosted on GitHub
- Vertex buffer objects
- Supports Python 3
- OBJ model support
Example
Screenshots
304,135 triangles. The transparency is just so that we can see a little more detail.
Since there’s no support for lighting yet, without the transparency all we’d
see would be a silhouette.
Notes
The OBJ loader is implemented in 18 lines of Python. There is no error checking and it only supports vertices and triangles, but it loads models exported from Blender just fine. Neat.Node.js on Mac OS X
Installation
First, install Mac OS X and Xcode. Install Homebrew:$ sudo chown -R $USER /usr/local
$ curl -Lsf http://github.com/mxcl/homebrew/tarball/master | tar xz
--strip 1 -C/usr/local
Install Node.js and Express:
$ brew install node
$ brew install npm
$ npm install express
Add the following to ~/.bash_profile:
export NODE_PATH="/usr/local/lib/node/"
You can verify that NODE_PATH has been set correctly by running the node program and inspecting require.paths. You should see something like this:
$ node
> require.paths
[ '/usr/local/lib/node/'
, '/Users/kyle/.node_libraries'
, '/usr/local/Cellar/node/0.2.3/lib/node'
]
> require('express');
{ version: '1.0.0rc3'
, Server:
{ [Function: Server]
super_: { [Function: Server] super_: [Object] } }
, createServer: [Function]
}
Sample Program
Test it out. Put the following in a file namedtest.js:
var express = require('express');
var app = express.createServer();
app.get('/', function (req, res) {
res.send('Hello World');
});
app.listen(3000);
Run It
Run usingnode:
$ node test.js
And visit http://localhost:3000/ in your browser.
Up Next…
Here’s what we’ll be building in the next post:Node.js on WebFaction
Installing Node
I was able to build Node successfully on my WebFaction host using the following:
$ ./configure --jobs=1 --prefix=$HOME
$ make
$ make install
All set
$ node --version
v0.2.3
Testing Node.js
I created a custom app in the WebFaction control panel and mapped it to a subdomain, http://node.purslane.webfactional.com/.
I then dropped the following into a file named test.js:
This is simply the basic HTTP server example from the Node.js website, tweaked slightly to include the port that WebFactional chose for my custom app.
Where you put the code isn’t important. I saved it to ~/webapps/node/test.js. Seemed as good a place as any.
Running the server:
$ node test.js
Server running at http://node.purslane.webfactional.com/
Visiting the URL in my web browser resulted in the expected Hello World message.
Object Oriented JavaScript
The Constructor Invocation Pattern
function Greeter(opts) {
this.who = opts.who;
};
Greeter.prototype.greet = function() {
document.writeln("Hello " + this.who);
};
var g = new Greeter({who: "Kyle"});
g.greet();
Prototypal Inheritance
if(typeof Object.beget !== 'function') {
Object.beget = function(o) {
var F = function() {};
F.prototype = o;
return new F();
};
}
var greeter = {
who: "Kyle",
greet: function() {
document.writeln("Hello " + this.who);
}
}
var anotherGreeter = Object.beget(greeter);
anotherGreeter.who = "Frank";
anotherGreeter.greet();
A Simple Node.js TCP Server in CoffeeScript
First Attempt
tcp: require 'tcp'
onConnect: ->
socket.write 'hello\r\n'
onData: (data) ->
socket.write data
onEnd: ->
socket.write 'goodbye\r\n'
socket.end()
server: tcp.createServer (socket) ->
socket.setEncoding 'utf8'
socket.addListener 'connect', onConnect
socket.addListener 'data', onData
socket.addListener 'end', onEnd
server.listen 7000, 'localhost'
Second Attempt
class Server
constructor: ->
@server: tcp.createServer (socket) ->
socket.setEncoding 'utf8'
socket.addListener 'connect', -> socket.write 'hello'
socket.addListener 'data', (data) -> socket.write data
socket.addListener 'end', -> socket.write 'goodbye'
@server.listen 8000, 'localhost'
server: new Server()
Python Decorators
class decoratorWithoutArgs(object):
def __init__(self, fn):
self.fn = fn
def __call__(self, *args):
self.fn(*args)
class decoratorWithArgs(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, f):
def wrapped(*args):
f(*args)
return wrapped
@decoratorWithoutArgs
def foo():
pass
@decoratorWithArgs(10)
def bar():
pass
if __name__ == "__main__":
foo()
bar()
Extending Python with ctypes
ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.
This tutorial assumes a Debian based GNU/Linux distribution. You may have to install build-essential.
Writing your shared library
We’ll start by creating our shared library. Type the following into your favorite text editor and save the file as testlib.c:
const char *say_hello() {
return "Hello, World\n";
}
Compile and link thusly:
gcc -g -c -Wall testlib.c
gcc -shared -Wl,-soname,libtestlib.so.1 -o libtestlib.so.1 testlib.o -lc
If you didn’t encounter any errors, you should be left with a file named libtestlib.so.1 in the same directory as your source.
Next, you’ll want to make sure that ldconfig can load your library. The easiest way to do this is to create a file named testlib.conf in /etc/ld.so.conf.d/ containing the path where your shared library can be found.
Run the following command to verify that ldconfig can see your library:
ldconfig -v | grep testlib
With luck you should see something like this:
/home/kyle/src/ctypes_test/testlib:
libtestlib.so.1 -> libtestlib.so.1
Using your shared library with ctypes
Fire up the interactive interpreter and type the following:
>>> from ctypes import cdll, c_char_p
>>> testlib = cdll.LoadLibrary('libtestlib.so.1')
>>> testlib.say_hello.restype = c_char_p
>>> testlib.say_hello()
Hello, World
>>>
You should, of course, see Hello, World displayed as the return value.
A little abstraction never hurts
Here’s a quick example of making your ctypes bindings a little easier to use:
from ctypes import cdll, c_char_p
class TestLib:
def __init__(self):
self.lib = cdll.LoadLibrary("libtestlib.so.1")
self.lib.say_hello.restype = c_char_p
def say_hello(self):
return self.lib.say_hello()
testlib = TestLib()
print testlib.say_hello()
OBJ Loader
Loads face and vertex data from .OBJ files. Doesn’t support groups, materials, texture coords, normals, etc… Not a particularly robust solution, but it’s simple and terse. This is a work in progress.
import re
def load_obj(filename):
verts = []
faces = []
f = open(filename, 'r')
lexemizer = re.compile(r'([^\s]+)')
for l in f.readlines():
if l[0] == '#': continue
tokens = lexemizer.findall(l)
if tokens:
if tokens[0] == 'v':
v = [float(tokens[1]), float(tokens[2]), float(tokens[3])]
verts.append(v)
if tokens[0] == 'g':
pass
if tokens[0] == 'f':
f = []
for v in tokens[1:]:
f.append(int(v))
faces.append(f)
An introduction to Pymunk
For this tutorial, we’re putting pygame and rabbyt on the back burner and focusing our attention on pymunk. Pymunk is a pythonic wrapper around the Chipmunk 2d physics library. In this tutorial we create a simulation in which we drop a ball on to a flat surface. As the simulation runs, we periodically print the ball’s height. Graphing this value against time gives us the following:
Astute readers will notice that the ball seems to bounce before it hits the floor. This is influenced by the value we pass to space.step. Calling space.step with a smaller value (i.e. higher resolution) would give us a more accurate graph. Of course, assuming we ran our higher resolution simulation for the same amount of time, we’d have a lot more values to graph.
In our next tutorial we’ll be combining pymunk, pyglet, and pygame and creating a full-fledged graphical physics simulation.