sn.printf.net

2008-08-18

I made a lot of progress this weekend on the project I brought to the forefront once I put aside all the other projects I realized I wasn’t that interested in.

Rancher’s Delight, if you don’t know, is a game engine I’m making based on the SNES classic Harvest Moon. Its primary goal is to faithfully recreate the underlying engine for the original game. Once that is done, I will extend it to allow for a programmable system that will enable anybody to create any kind of Harvest Moon-like game they wish.

What I accomplished this weekend:

  • removed the old code that dealt with resizing the viewed area to make sprites and locations larger. If I need this again it can easily be rewritten, but it has to fit into the new underlying framework.
  • wrote different functions to take into account the character moving versus the world scrolling under him. The former is used when there’s no more location to scroll in that direction, and coming away from the edge of a map where he’s not in the center yet. The latter is used for everything else.
  • added in-game objects, and ensured that they are stationary with the background when the character moves.
  • added a prototype of the messaging system, using font rendering for the messages and a surface with the original dialogue box on it. It can fit a bit more content than the old fixed-length one, but the content needs to be hand-checked to ensure it doesn’t spill over the edge of the box. It may be worth it to enforce a cut-off just in case.
  • started enforcing cardinality in a character’s facing direction, along with slowly putting together sprite sheets.
  • started playing around with, then polished off, cycling sprites for movement.
  • completely refactored everything up to this point, making everything a lot cleaner. There’s now a sort of God object, the Camera, which takes care of all kinds of relationships between things. Already a lot more relationships can be refactored out, but I can’t see the most effective ways to do so until the whole thing gets a lot more complicated. Primarily I’m starting to see the difference between an object doing something, and the user seeing what it does.
  • introduced a frame length to cycled sprites, which I’ll need to tweak along with the movement speed to get the best recreation of how Jack moves in Harvest Moon. This is really important to get right, as a the timing of the game and how people play it rely on the movement of the main character for precise schedules.
  • stitched together the exterior of the farm, where all the magic happens.
  • created a tool to replace the soon-to-be game objects in a location (such as the stumps and weeds in the exterior farm) with random ground tiles. Fairly simple and effective.

So, yeah. A decent amount of work. You can keep track of the progress on the GitHub feed of commits for the project, as well as test and try it out yourself by cloning my repository:

git clone git://github.com/ardekantur/ranchers_delight.git

In the meantime, here’s a pre-release screenshot :-) It’s Jack spending some alone time on the church roof.

Jack contemplates jumping off the church roof.

by Ardekantur at 2008-08-18 04:37

2008-08-15

From Monday, I'll be pretty much offline for two weeks. I'll be on Holiday so this means if you drop me an email, you'll probably not get a reply from me until September.

While offline, I'll be taking the time to learn a few new things (including more HaXe, ANSI C and some server architecture stuff). If anyone can suggest any good free e-books to read, drop me a line.

2008-08-15 19:48

In an effort to focus, and more importantly, focus on the projects that I really want to work on, and would benefit from personally, I’ve removed the following projects from GitHub:

  • my fork of rest-client
  • bulletin
  • wondercroc
  • uproar
  • clementine
  • flint
  • quandry
  • ioaxiom
  • taskforce

If you had any interest in any of these projects, let me know and I could provide you the source, or any guidance for what I had planned for them. As it stands, this leaves me with Taskomaly, which I’m slowly waning interest in since my move to Things, and Rancher’s Delight, which, as a game and a very large undertaking, probably won’t see a lot of progress. This leaves me with a virtually clean slate with which to start thinking about problems I’m interested in solving.

by Ardekantur at 2008-08-15 04:09

2008-08-14

Mostly this is just farting around but I thought I’d post about it because it’s an interesting idea, at least in theory.

GUIDs are good but I wanted to do one better. So I created SUUIDs. Super Universally Unique IDs. The format of the current version, v2.0, is thus:

2/xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxx

Where x is a case-sensitive alphanumeric character. This gives us somewhere in the area of 3.35×10^64 possible combinations, and a lot of interesting characteristics.

  • For example, if the address space of a given ID is all hexadecimal, and the last four characters are IPv6, this functions just as well as an IPv6 address format. Thus, The IPv6 address 2001:0db8:0000:0000:0000:0000:1428:57ab is notated as 2/20010db8-00000000-00000000-142857ab-IPv6. If a field contains all the same character, you can replace the ending hyphen with a comma and the field with a single instance of that character, so that IP address could also be 2/20010db8-0,0,142857ab-IPv6.
  • In the same token, the same rules apply to a message that ends in 0MD5 — that’s an MD5 checksum as well as a unique address.

An implementation in Ruby:

	module SUUID
	  def self.gen
	   chars = ("a".."z").to_a + ("1".."9").to_a + ("A".."Z").to_a
	   x = [8, 8, 8, 8, 4]
	   x.map! {|i| i = Array.new(i, '').collect{chars[rand(chars.size)]}.join }
	   return "2/" + x.join('-')
	  end
	end

It’s not pretty, but it gets the job done. You could always throw a more random source of entropy at it, use the system date, time, whatever. Don’t particularly care about the implementation.

Here’s what a couple look like — to get used to the idea :-)

2/f9nuBgzm-HGTE4bSK-ZEfkfsRp-T3SXgpXA-5LNC
2/hoyOCd7o-V48NQGvv-OS5RBDIl-CG1FRNqG-Xd3j
2/sUZd6aGa-1J55rs9C-lxH1mvPA-I9PAvkOh-ZLVj

Additionally, you can omit the version number, which so far still allows for distinction between version 1 and version 2 (version 1 didn’t have lowercase letters). This means you have a nice set of directory names at your disposal.

mkdir /DOMejDTy-APESCioG-yyXpXBNL-lYAuQogL-Uep9
mkdir `curl -X POST http://example.com/suuid/provider`

I have no idea how checksums, hashes, verified randomness all fit into something like this. Just something fun and stupid to keep me occupied today.

by Ardekantur at 2008-08-14 00:26

2008-08-12

Taskomaly Logo

So, yeah. Taskomaly 0.1.0 (now 0.1.1 to deal with some things) is released, but I’m not too happy about it. It’s a very confining release. Here’s what you need to know, things that are implicit in the code, but not in the documentation.

  • Project names are converted into symbols for no real reason, but they lose their formatting in the process. “My IBM Project” will become :my_ibm_project, which will then get transformed into “My ibm project:” when the project name is formatted for a task file.
  • Comments are ignored and not parsed, and not brought into a formatted task file.

I think that’s it, but those are constricting things nonetheless. Tests pass, but only because I use special cases for these things. I know. I’m ashamed. I’m going to add better criteria for all the tests, and stick it out until the next release.

But basically anything that you want to do with papers, projects, and tasks is available for you. The README explains how to integrate it with Tasko.

Right. The whole thing needs an overhaul API wise. Already. I’m not sure if that’s a function of my using TDD naively, or if I’m just a bad programmer. Let’s say a little bit of both.

In any event, what there is, is well-documented. On top of that, if you have any issues or test cases you want to provide, throw them to me at my Lighthouse project for Taskomaly. Things like that would be wonderfully appreciated, since this is the sort of project that builds itself based on the most common habits of the people who use it.

Enjoy!

$ gem sources -a http://gems.github.com
$ sudo gem install ardekantur-taskomaly

If you get any version from GitHub that’s not 0.1.1, wait a couple minutes and try again. GitHub says it takes up to ten minutes to propagate a gem change, and I haven’t been keeping track of time.

by Ardekantur at 2008-08-12 03:08

2008-08-09

Version 1.3- August 9, 2008

  • Fixed a minor UI bug where not all references were updated when the “Rename ProgID to File Type” preference was changed.
  • About/Help link now points to this program’s own landing page instead of it’s blog category.
  • The information url comment in exported .reg files has been updated to this program’s own page instead of it’s blog category.
  • The program now checks for updates automatically when it is launched. This can be disabled in Advanced Configuration.
  • A couple of additional minor UI adjustments (including a misspelled word in the error dialog- whoops!).
  • Added a dialog to enable the deletion of both an extensions and ProgID’s.
  • Fixed an rare bug that caused an immediate crash (both XP and Vista) based on information from online crash reports.
  • Fixed a bug where extensions without ProgID’s would have a blank Friendly Type Name instead of EXT File, which is what Windows Explorer shows.
  • Program identification comment at the top of generated .reg files now includes the version number.
  • Moved the “Include extensions without a ProgID” checkbox to the extensions filter options list.

Several interesting changes in this release.  Also, I’ve enabled comments on the blog.

by Factor Mystic at 2008-08-09 23:04

Taking queues from Adam Wiggin’s first commit to his Rush project, simply a design document and some specs, and Err the Blog’s post about BDD and generating specs from YAML, I’ve written a small Rake task that will take a single file design document in YAML and separate it out into the components you specify. For example:

spec/design.yml

Website Integration:
    - should be able to log in from the front page and land at your profile
 
OpenID module:
    - should accept an OpenID URL
    - should return an error message if the URL cannot be reached
 
User:
    - should have a valid user name
    - should return an error if creating a duplicate user name is attempted

And then:

rake design

Takes the section headers, and flattens them as the filenames. So this particular design creates three different files, website_integration_spec.rb, openid_module_spec.rb, and user_spec.rb. They’ll look like this:

spec/user_spec.rb

require File.dirname(__FILE__) + '/spec_helper'
 
describe 'User' do
 
  it 'should have a valid user name'
  it 'should return an error if creating a duplicate user name is attempted'
 
end

And just like that, you have your specs, ready to go!

Here it is:

Please note that it will destroy those files if they already exist, replacing them! I really don’t care if you lose your existing specs! Back them up if you want to try this! You have been warned! This is more of a technique for a brand new project, anyway.

Also, please note that I’ve embedded the rake task as a GitHub Gist paste, so feel free to fork it and modify it. I’d be interested in seeing cleaner, more interesting implementations of my 30-second hack. Additionally, please choose view raw if you want to copy it, seeing as how GitHub seems to bork on a newline character in the code snippet.

by Ardekantur at 2008-08-09 04:55

2008-08-08

Brief Overview

Okay, so here we go. This is going to be a bit of a rambling adventure, because that’s the only way it can follow what I actually managed to accomplish.

I’ve been obsessed with learning LINQ to SQL since I first heard of it, but never really had the time. Besides time constraints, I was also put off by the fact that there seemed to be nothing coming from the Oracle camp regarding the exciting new technology I saw unfolding. After a while I began hearing whispers of the Entity Framework, a complete object-relational mapping solution coming from the Microsoft camp, and was immediately interested. I had never really taken a look at the other available ORM solutions for .NET, NHibernate and the like, simply because I thought there would be a slim chance I would be able to use both Oracle and LINQ with them without too much trouble. As it stands, I had exactly that trouble with Entity Framework, but it feels justified in a weird way. I’m sure after this I’ll try taking a look around for other available solutions, but so far this looks extremely promising, if a little unpolished.

This all starts off with EFOracleProvider, an Entity Framework-friendly provider used to generate the necessary classes and mapping files for database access. Compiling EFOracleProvider gave me a DLL and some configuration settings I could toss at the already existing data model generator, EdmGen.exe, to generate the classes that map to the database tables and fields I specified.

I’m going to show you the files I worked with in all of this, but I’m not going to obfuscate them, or simplify them. I’m going to give you an idea of the exact situation I was in, in order to show you the problems I encountered, and how easy it is to encounter them. I’d also like to remind you that use of EFOracleProvider is not recommended in production environments, as it is extremely rough quality code. This was more of an adventure than a focused goal, but it raises a lot of questions.

Observing the Database

My first step, after compiling EFOracleProvider, was to create a storage model for the part of the database I wanted to present to .NET. I decided to go straight to our live database and take my queues from it. I took a small cross-section of our available schema — just a single table, with two columns, both VARCHAR2s.

    +--------------------------+
    | tblAsset                 |
    +--------------------------+
    | Asset_Number             |
    | Asset_Type               |
    +--------------------------+

Yes, Asset_Number is a string. It refers to alphanumeric serial numbers. But it’s also our primary key, so it’ll make do. In any event.

The storage model file is XML, and fairly easy to create, but has a lot of hidden gotchas that we’ll cover.

<?xml version="1.0" encoding="utf-8"?>    
<Schema Namespace="TestAppEFModel.Administration" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl" Provider="EFOracleProvider" ProviderManifestToken="10g">
  <EntityContainer Name="dbo">
    <EntitySet Name="Assets" EntityType="TestAppEFModel.Administration.Assets" Table="tblAsset" />
  </EntityContainer>	  
  <EntityType Name="Assets">
    <Key>
      <PropertyRef Name="Asset_Number" />
    </Key>
    <Property Name="Asset_Number" Type="varchar2" Nullable="false" StoreGeneratedPattern="Identity" />
    <Property Name="Asset_Type" Type="varchar2" MaxLength="50" />
  </EntityType>
</Schema>

Fairly straightforward. We’re reminded in the EFOracleProvider documentation to set the ProvierManifestToken to the relevant version number of our database. You’ll note that your namespace seems to require a secondary class. You cannot place your entities in TestAppEFModel, you need to create something like TestAppEFModel.Administration. Also note that I’ve manually specified the table name in the EntitySet tag, since it does not map cleanly to what .NET expects.

Fire up EdmGen.exe:

    C:\OracleEFTests>edmgen.exe /mode:FromSSDLGeneration \
        /c:"Data Source=TNSNAME;User ID=user_id;Password=password..." \
        /project:TestApp /prov:EFOracleProvider \
        /inssdl:TestAppEFModel.Oracle.ssdl /project:TestAppEFModel
    Microsoft (R) EdmGen version 3.5.0.0
    Copyright (C) Microsoft Corporation 2007. All rights reserved.

    Creating conceptual layer from storage layer...
    Writing msl file...
    Writing csdl file...
    Writing object layer file...
    Writing views file...

    Generation Complete -- 0 errors, 0 warnings

Preparing the Application

There are two basic steps to preparing your application: Providing a DLL of the object model, and configuring your application for use with EFOracleProvider and your database. Providing the DLL is easy enough — take the two .cs files created by EdmGen.exe and throw them into a project, and reference that project in your app.

I had initially put all of the test and generation files in one root directory on my disk, just to keep track of them. This turned out to be a good idea for a secondary reason. In your application configuration, you must provide access to the metadata files you’ve just created. The example code in the EFOracleProvider project used the following syntax in its App.config:

<add name="NorthwindEntities"
        connectionString="provider=EFOracleProvider;metadata=res://NorthwindEFModel/NorthwindEFModel.NorthwindEFModel.csdl|res://NorthwindEFModel/NorthwindEFModel.NorthwindEFModel.msl|res://NorthwindEFModel/NorthwindEFModel.NorthwindEFModel.ssdl;Provider Connection String='data source=XE;user id=edmuser;password=123456'" providerName="System.Data.EntityClient" />

Note those res:// addresses. I imagine those are used to refer to resource files, but I didn’t see any of the projects involved actually containing one. On top of that, there’s that double-namespace thing, i.e. NorthwindEFModel.NorthwindEFModel.csdl. I couldn’t get this syntax to even work a little bit with my configuration, so I just pointed my application at the root directory I created, that contained all of the necessary files. I imagine on a test or application server, leaving these files in a common place may be the most useful option.

<add name="TestServer"
    connectionString="provider=EFOracleProvider;metadata=C:\OracleEFTests\TestAppEFModel.csdl|C:\OracleEFTests\TestAppEFModel.msl|C:\OracleEFTests\TestAppEFModel.Oracle.ssdl;Provider Connection String='Data Source=TNSNAME;User ID=user_id;Password=password...'"  />

Don’t forget to add EFOracleProvider to the <DbProviderFactories> section of your configuration, as well. Also note that I didn’t use the providerName attribute, which in the test code was listed as System.Data.EntityClient, even though the provider in the connection string is our good old EFOracleProvider.

Finally, write a small piece of code to test the functionality.

using System;
using System.Collections.Generic;
using System.Data.EntityClient;
using System.Linq;
using System.Configuration;
using System.Text;
using TestAppEFModel;
 
namespace TestAppEFOracleTests
{
    class Program
    {
        public static void Main()
        {
            TestAppEFModelContext context = new TestAppEFModelContext( ConfigurationManager.ConnectionStrings["TestServer"].ConnectionString );
 
            var query = from asset in context.Assets
                        where asset.Asset_Type == "TEST ASSET TYPE"
                        select asset;
 
            foreach(var asset in query)
                Console.WriteLine("{0}, {1}", 
                    asset.Asset_Number, 
                    asset.Asset_Type);
        }
    }
}

The Troubles

And we’re good to go, right? Not quite.

ORA-00942: table or view does not exist

Whoops. What did we do wrong? Well, let’s look at the SQL that was generated.

SELECT
    "Extent1"."Asset_Number",
    "Extent1"."Asset_Type"
FROM
    "tblAsset" "Extent1"
WHERE
    (N'TEST ASSET TYPE' = "Extent1"."Asset_Type")

What’s wrong with that? Actually, something very subtle and dangerous that I’m sure is causing Oracle a lot of pain in trying to get a provider out for the Entity Framework. Observer the following session in SQL*Plus:

SQL> DESC tblAsset;

Name           Null?    Type          
-------------- -------- --------------

ASSET_NUMBER   NOT NULL VARCHAR2(50)  
ASSET_TYPE              VARCHAR2(50)  

SQL> DESC "tblAsset";
ERROR:
ORA-04043: object "tblAsset" does not exist

SQL> DESC "TBLASSET";
Name           Null?    Type          
-------------- -------- --------------

ASSET_NUMBER   NOT NULL VARCHAR2(50)  
ASSET_TYPE              VARCHAR2(50)  

This hearkens back to a long-standing conflict in dealing with Oracle and mixed-case or reserved identifier names, to wit: In order to ensure that table names that happen to be reserved keywords can be used, we need to enclose them in double-quotes. But we can create tables with or without quotes, with differing cases, and create two different tables. We may not be able to rely on the user telling us the exactly correct name of a table in our storage model file, but we can’t convert it to all caps without the risk of accidentally referring to a different table!

My solution at this point was to cave and refer to the table name in all caps in my storage model file. But now the problem is the column names! And we can’t refer to a column name in the storage model, but we can in the mapping file, the .msl, but we can’t simply generate the mapping file, change the column names to all caps, and have it compile. What I ended up doing was simply referring to all of the fields in all caps in the storage model, which of course breaks our code, making us refer to asset.ASSET_TYPE, as well as uglifying the constructor code for creating new objects:

/// <summary>
/// Create a new Assets object.
/// </summary>
/// <param name="aSSET_NUMBER">Initial value of ASSET_NUMBER.</param>
public static Assets CreateAssets(string aSSET_NUMBER)

One More Thing

So, those are the big things, the deal-breakers. The largest problem to me is the idea that we can specify a table name in our storage model file, but not column names. This seems entirely too half-baked to me, but maybe I just don’t understand the conceptual tactics behind a move like that.

And I just noticed this as I was signing off, a quick bizarre thing I wanted to try:

var query = context.Assets.Where( a => a.ASSET_TYPE.Contains("A") ).Take(10);

Take the top ten items that have an uppercase A in them. Simple enough, right? Nope. A rewriting of the generated SQL:

SELECT 
    asset_number, 
    asset_type 
FROM 
    tblAsset 
WHERE ((INSTR('A', asset_type)) >0) 
AND   ( ROWNUM <= (10) )

This is a mess. First off, that ROWNUM clause is not going to do what we expect, no matter what the rest of the query is. Secondly, INSTR takes its parameters in the reverse order. Little things like this are going to be the hell Oracle would have to go through to get a decent provider out there for Entity Framework, and I don’t even envy them a little bit.

One more thing I want to say about all of this. The work I did above took seven hours, a lot of Googling, a lot of searching through documentation, and a lot of guessing. The following is how everything above would be handled in my current favorite Ruby ORM.

class Asset
  include DataMapper::Resource
  property :asset_type, String
  property :asset_number, String
end
 
query = Asset.get :asset_type => 'TEST ASSET TYPE'

This is not to compare languages or ideologies, but methodologies. Simplicity always trumps complexity in the software engineering world. Always always always. Make Entity Framework easier for people to use, and it could be a godsend for shops that want a Microsoft-written ORM solution.

I’ll try and answer any questions anyone has, but this is literally the maximum scope of what I was able to accomplish. I’ll probably throw myself back at it later this weekend.

by Ardekantur at 2008-08-08 17:07

2008-08-01

So it's been about 48 hours since I decided to go down the HaXe route for Helium: Adobe AIR Installer Framework and I've decided to to a quick review of it.

Before I start I do have to admit one thing - I think I did jump the gun a little in settling on HaXe so quickly. I've barely got to an intermediate level with ActionScript 3 (having a good JavaScript and Python background I think helped me pick it up so quick) when I discovered it.

... Read More (361 words)

2008-08-01 01:00

Yay! So thanks to the folks on the #haxe IRC channel and mailing list, I've managed to fix my initial issues with Helium. Turns out there was an issue with the way the ASWing library is compiled and looks like it's been solved. As a side note, the community is really friendly. I've found that a few communities such as the Django and jQuery communities are really helpful and the HaXe community is no exception.

... Read More (206 words)

2008-08-01 01:00

Less than two weeks to go until my Holiday - I can't wait, I'm going a little crazy right now Smile

Links

  1. Facelift - An alternative to sIFR.
  2. Django db - A place for sharing model types for Django

2008-08-01 01:00

2008-07-31

Links

  1. Flare - Actionscript library for data visualization.
  2. Spawning + Django - Spawning is a new WSGI server to check out.
  3. Is this real?
  4. XHTML 1.1 Basic
  5. 12 PHP optimization tips
... Read More (96 words)

2008-07-31 22:52

Today I have been embedding a javascript interpreter in python:

>>> from qtscript import *
>>> q = js()
>>> q("function f(x) { return x*2}")
'undefined'
>>> q['f'](2)
4.0
>>> def id(x): return x
...
>>> q['id'] = id
>>> q('id(4)')
4.0
>>> q('id')([1,2,3])
[1.0, 2.0, 3.0]
>>> q("function g(x) { return x(10)}")
'undefined'
>>> q('g(id)')
10.0
>>> f = q['f']
>>> g = q['g']
>>> g(f)
20.0
>>>


from PyQt4 import QtScript

def py_to_qsv(engine,a):
    if callable(a):
        def qtfunction(context,engine):
            args = []
            for x in xrange(0,context.argumentCount()):
                b = context.argument(x)
                c = qsv_to_py(engine,b)
                args.append(c)
            ret = a(*args)
            return py_to_qsv(engine,ret)
        
        return engine.newFunction(qtfunction)
    elif hasattr(a,"items"):
        qargs = engine.newObject()
        for x,b in a.items():
            qargs.setProperty(x,py_to_qsv(engine,b))
        return qargs
    elif hasattr(a,"__iter__"):
        qargs = engine.newArray()
        for x,b in enumerate(a):
            qargs.setProperty(x,py_to_qsv(engine,b))
        return qargs
    else:
        return QtScript.QScriptValue(engine,a)


def qsv_to_py(engine,a):
    if a.isNumber():
        return float(a.toNumber())
    elif a.isArray():
        i = QtScript.QScriptValueIterator(a)
        o = []
        while i.hasNext():
            i.next()
            o.append(qsv_to_py(engine,i.value()))
        return o
    elif a.isNull():
        return None
    elif a.isBoolean():
        return bool(a.toBoolean())
    elif a.isFunction():
        class qtfunction:
            def __init__(self,o):
                self.o=o
                self.e=engine
            def __call__(self,*args):
                qargs = py_to_qsv(engine,args) 
                return qsv_to_py(self.e,self.o.call(self.e.globalObject(),qargs))
        return qtfunction(a)
    elif a.isObject() and not a.isFunction():
        i = QtScript.QScriptValueIterator(a)
        o = {}
        while i.hasNext():
            i.next()
            o[str(i.name())] = qsv_to_py(engine,i.value())
        return o
    else:
        return str(a.toString())

class js:
    def __init__(self):
        self.engine = QtScript.QScriptEngine()
    def __call__(self,*args):
        return qsv_to_py(self.engine,self.engine.evaluate(*args))
    def __getitem__(self,name):
        return qsv_to_py(self.engine,self.engine.globalObject().property(name))
    def __setitem__(self,name,value):
        return self.engine.globalObject().setProperty(name,py_to_qsv(self.engine,value))


def repl():
    q = js()
    a = raw_input()
    while a:
        print q(a)
        a = raw_input()


2008-07-31 12:12

2008-07-30

Links

  1. Ignosticism - An atheist would say, "I don't believe God exists"; an agnostic would say, "I don't know whether or not God exists"; and an ignostic would say, "I don't know what you mean when you say, 'God exists' ".
  2. Russell's teapot
  3. Testing Web application security using Google's ratproxy
... Read More (140 words)

2008-07-30 20:19

Known for my promptness, it is no surprise that I've taken approximately 28 days to reply to the indubitable Anne K. Halsall's tagging of myself and several esteemed others to give the wonderful world of the internet my story (of all people!). Not only that, but to be listed with the people she listed me with! I can cross off "Appear in a list with Mark Dalrymple and Aaron Hillegass" off my life's to-do list.

Without further ado, I present the story, as requested, many moons ago.

How old were you when you started programming?

Ah. This is an interesting question. Normally here, you'd get a fantastically woven tale of discovering a UNIX machine deep within the bowels of your college, and plugging away for hours and hours learning as much as possible, or even having an Apple ][ as a child, and pecking away at sweet BASIC programs.

I did not do this. Not at all.

I started programming when I was 17.

The Setup.

Most of my pre-programming life was spent enjoying other people's hard work -- I played video games. A lot of video games. I played a bit of baseball growing up, but by the time third grade rolled around, I had two loves in my life: Playing Oregon Trail in Typing class, and music.

My father was a trumpet player in his younger days, and coincidentally, also one of the first computer programmers at his university. Despite being a architecture major, he loved computers and got involved with them as much as he could. When I came to live with my father in Texas when I was 8, he began influencing my childhood with his love of computers, and I was hooked. My dad and I bonded over computers, and he taught me everything I could possibly absorb.

Back then, we were Microsoft men. We anticipated the release of new versions of Windows and Office with great anticipation, so that we could pick them apart and learn everything about them. We got the internet in 1994 or so, good old AOL. We jumped ship to cable internet as soon as it was possibly available, learning about ethernet and Windows networking (ugh), and everything as we went.

However, I really knew nothing about software. In fact, I knew more about interrupts, device communication, and USB long before I ever understood what a pointer was. As I grew up, I cared less and less about about what came out of Redmond, and more and more about what my computer could actually do. I embraced software in the form of computer games, eventually playing at a pretty high level in a couple of my favorites (competitive gaming, ugh). I was also into music a lot, playing trumpet, baritone/euphonium, tuba, and finally trombone throughout my childhood and into high school. I played with various pieces of musical software in my later years: Reason and Fruity Loops mostly, and somewhat enjoyed that.

By my senior year, I was pretty sure I'd be majoring in music, Trombone Performance I believe, and that computers were just a hobby.

How I got started programming (and changed my complete life plan)

Two things, or maybe, more specifically, two people completely destroyed that idea.

A good amount of my time was spent playing text based games oddly enough. My friends and I were into MUDs big time, which was rather odd in a time where Everquest was insanely popular. One friend, in particular, really liked MUDs, enough to learn how they work, and began work on one himself. At some point, I joined the fray. I had a bit of experience working on a MUD we all played, doing text-based level design. It was rather basic, but involved a lot of writing, and I enjoyed it a lot. So, I went about sitting next to him, writing room after room after room. Every now and then, I looked over and saw it - a stark black background with bright glowing white letters, arranged haphazardly in weird patterns on his screen. It was code.

My quick looks slowly became long stares, and as I saw what he was doing, and what it became, I was blown away. I guess I had never really though about software, and how it was made. I recalled back to my excitement over software releases, and realized how much excitement throughout my entire life was completely based on software. This was awesome, and I wanted to be able to do it. The next day, I went to the local Borders and picked up my very first programming book: Practical Programming in C++. I read the book every day. I ended up reading it around five times before I graduated high school. I loved it so much, I ended up taking a computer science class my senior year, which was a joke at that time. I excelled, helped other people understand, and loved every second of it. I had only ever been really good at one other thing: music, and it was awesome to have something else to join the party. Little did I know, I was a terrible programmer, but no matter, it was an amazing feeling.

No, there is another...

I love skateboarding video games. I mean really love them. I absolutely adored Tony Hawk's Pro Skater, and pretty much everything about the series of games.

A friend of many of my friends, let's call him Andy, since that's his name, played this game at an insane level. I never knew this mind you, all I knew is that one day, I heard that Andy played Tony Hawk so well, that Neversoft wanted to hire him to test Tony Hawk. This was it. At this point, I realized that video games were a major industry, and that computer software of all kinds, was an even bigger industry. It all brought me to the realization that music needed to be the hobby, and that I needed to make software for a living. After some careful thought, I realized that this plan was much more feasible than using money made from music to fund my software plans. I graduated high school, and enrolled in college as a computer science major.

Coincidentally, Andy was on stage during the premiere of Guitar Hero World Tour, playing drums, which caused me to freak out. He's now a designer at Neversoft, and I LOVE Guitar Hero.

What was your first language?

I guess C++, which is really quite bad. Never ever use C++ as the language you learn programming with, it's awful. When I graduated, I got a Powerbook G4, much to the bickering of my father, who wanted me to get a Dell or something, but I knew what I was doing. :)

That was the first machine I owned that I ever programmed on, and I refused to write a line of C++ on it. I bought Cocoa book after Cooca book, taught myself Objective-C with the help of Steven Kochan, and Cocoa with the help of Aaron Hillegass, and never looked back.

What was the first real program you wrote?

Jeez, this is a hard one to answer.

There were tons of little one-offs, and the projects from Aaron's book, not to mention five years of CS assignments. Adium is the first I ever shipped any code, so I'll say it was that, though of course, I didn't write all of that.

The first thing I actually wrote and finished all by myself and could be called a real program was actually Photo Touch. All the real experience I had up until then had been on teams, because I love working on teams of amazing people.

What languages have you used since then?

Well, Objective-C primarily. However, I've dabbled in all kinds of stuff: C, [C++], Java, Javascript, Python, Ruby, and Prolog.

What was your first professional programming gig?

This is a hard one to answer.

In November of 2006, I decided I wanted to work on an open source project, in what I will call the best decision I've ever made in my life. I chose Adium, and was asked to join the development team in December of the same year. Despite the fact that since that initial flurry of activity, I haven't gotten to work on it nearly enough due to the insanity stemming from my association with the project, leading to my actual first professional programming gig. I hold Adium in high regard, and will never forget the impact it's had so far.

I accepted my first professional gig in May of 2007, as an intern at a little fruit company, who's work I'm quite partial about. I worked on a pretty secret project, that would eventually become MainStage. I had the incredible luck to land my dream job of working on the Audio/Music team at said fruit company, which had been my dream since getting my first Mac out of high school, which came with Garageband 1.0, which I loved to death.

If there is one thing you learned along the way that you would tell new developers, what would it be?

NETWORK. I try to kid myself that I got really really lucky, but ultimately, my networking decisions (combined with a ton of luck, seriously) are what got me where I am. Take the time to get to know people, I am still around 9,999,999 beers in debt to Colin Barrett at this point.

Find smart people. Surround yourself with them. Most importantly, show off anything you think is cool. Everyone loves something cool. Not only will you inspire yourself to keep doing what you do, but you'll inspire hundreds, if not thousands of others, to keep at it as well.

What's the most fun you've had programming [that I can talk about]?

A tough one! ;)

I quite enjoyed writing Photo Touch, and showing it to my fellow students at school. Despite it being rather simple, I had a gigantic group of younger students surrounding me asking me questions about it, Mac programming, and working for fruit companies.

It was a real turning point, that let me know I was on the right track, and vindication about your life choices is extremely important.

Corollary: Why aren't you writing video games?

Great question!

I got into application development for some unknown, odd reason. I realized that applications make the world go round. Every day, we use a multitude of applications to make our lives work the way they do, and that writing these applications posed a unique challenge: How do you write something that someone wants to use every day of their life?

I'm still not really sure, although I suspect that I'm at the right place to find out, all things considered.

I imagine someday, I may make a foray into game programming. I've certainly given it some thought lately, but my love for user interfaces is what keeps me here, and doing what I do, and hopefully making apps that people use every day of their lives.

Thanks to Anne, Colin, Steve Kochan, Aaron Hillegass, Mark Dalrymple, and well, pretty much everyone involved.

2008-07-30 01:23

2008-07-29

Links

  1. Flexcover - Flexcover is a code coverage tool for Flex, AIR and AS3.
  2. Haxe2.0 Available
  3. Optimizing PHP
  4. DjangoCon & Django 1.0 updates
  5. Pushup - Pushup is an effort to push the web forward by helping users upgrade their outdated browsers.
... Read More (85 words)

2008-07-29 23:20

2008-07-28

First of all, welcome to my new look site.

Recently, I've been getting rather fed up with Wordpress. From the slow page loading times, to the JavaScript errors in the admin interface and the ever increasing white screens. I think version 2.6 was released too fast and unfortunately this was the last straw for me.

So I looked into a few different options. I've been wanting to something a bit different here anyway, so I ended up choosing WikyBlog. The application is a Wiki can that be used as a blog and I think it will give me the drive to do more technical and in-depth articles, rather than crappy updates that serve no purpose.

... Read More (171 words)

2008-07-28 10:55

Version 1.2

  • Fixed a critical bug that caused an immediate crash on Vista x64.
  • Added automatic online error reporting (can be disabled in Advanced Configuration).
  • Added a friendly error dialog when the program crashes, replacing the generic .Net one.
  • A couple of minor UI adjustments.
Default Programs Editor- Error Dialog

Default Programs Editor- Error Dialog

What information does the crash report have?
OS version, last executed method from a logging functions, and a stack trace. No personal identifying information. Each crash dump is saved to C:\Users\<user>\AppData\Local\factormystic.net\Default Programs Editor\<version>\ , which is also where the advanced.config file is saved.

64 bit

The x64 bug was quite odd. I was initially debugging on a vanialla rtm install, and the program worked fine. It wasn’t until I installed hotfix KB932471, an update for .Net 3.0, that it successfully crashed. I’m not sure exactly what changed in the framework to make it start crashing, but the bug was a relatively simple fix.

Download.

by Factor Mystic at 2008-07-28 04:24

2008-07-27

I’ve spent the past couple of hours futzing around with Sinatra and Rack being hooked up to the latest Phusion Passenger, and I’ve come across a bizarre problem. Let’s see what I can illustrate.

I have a Slicehost VPS, and I threw a DynDNS address at it because I didn’t feel like registering a domain name for something that was essentially supposed to be a playground. I set it up so that subdomains would also get redirected to my slice, since I didn’t want Phusion interfering with some PHP, Trac, and SVN stuff I also have running on it. My configuration basically looks like this:

/etc/apache2/sites-available/phusion-passenger

<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName  projects.example.com
        DocumentRoot /var/projects
        <Directory /var/projects>
                Options -Indexes
        </Directory>
        RackBaseURI /sinatra_test
</VirtualHost>

Then I set up /webapps/sinatra_test, along with the latest version of Sinatra, as outlined on the “Bleeding Edge” section of the Sinatra website. The Phusion Passenger documentation provides instructions on the proper way to format your Rack directories, which includes a tmp directory, a public directory, and a config.ru. Add my actual Sinatra application, and I have a setup that looks like this:

root@slice:/webapps/sinatra_test# ls -l
total 16
-rw-r--r-- 1 www-data www-data  326 Jul 27 15:19 config.ru
-rw-r--r-- 1 www-data www-data  235 Jul 27 15:44 myapp.rb
drwxr-xr-x 2 www-data www-data 4096 Jul 27 05:54 public
lrwxrwxrwx 1 www-data www-data   10 Jul 27 06:13 sinatra -> ../sinatra
drwxr-xr-x 2 www-data www-data 4096 Jul 27 15:46 tmp

All good to go, right? You’d think. There’s some bizarre things going on with Phusion, or Rack, or Sinatra, in terms of discerning correct actions and mapping them to URL endpoints.

My Sinatra application:

myapp.rb

  $:.unshift File.dirname(__FILE__) + '/sinatra/lib'
  require 'sinatra'
 
  get '' do
    "Rootless test"
  end
 
  get '/' do
    "Root test"
  end
 
  get '/other' do
    "Other application part"
  end
 
  get '/other/' do
    "This is a different endpoint"
  end

As well as the config.ru I’m using for it:

config.ru

  $:.unshift File.dirname(__FILE__) + '/sinatra/lib'
  require 'sinatra'
 
  Sinatra::Application.default_options.merge!(
    :run => false,
    :env => :development,
    :raise_errors => true,
    :app_file => 'myapp.rb'
  )
 
  log = File.new("sinatra.log", "a")
  STDOUT.reopen(log)
  STDERR.reopen(log)
 
  require 'myapp'
  run Sinatra.application

And this is what I get when I play with curl.

~ $ curl http://projects.example.com/sinatra_test/other
Other application part

~ $ curl http://projects.example.com/sinatra_test/other/
This is a different endpoint

~ $ curl http://projects.example.com/sinatra_test
Rootless test

~ $ curl http://projects.example.com/sinatra_test/
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /sinatra_test/
on this server.</p>
...

What’s going on? other and other/ are considered different endpoints, which makes sense, I imagine. I’m not an HTTP wizard. Even if the root of the sinatra_test directory and the same root with an ending slash are considered different endpoints, then why wouldn’t I be able to access the latter? Especially with it defined explicitly in my Sinatra application? Even more, especially since if this was a distinction, as in the case of other and other/, but isn’t working the same way for the root URL?

Curioser and curioser. I have no idea if the problem is with Sinatra, Rack, Phusion, or my Apache configuration, and I’ve played around with omitting or specifying explicitly an ending forward slash for the DocumentRoot and RackBaseURI. Some of you may point out that I’ve specified -Indexes for the VirtualHost configuration, but if that isn’t specified, then navigating to http://projects.example.com/sinatra_test/ generates an empty directory listing, since it is pointing to my empty public folder.

So that’s where I am. Any insight would be appreciated, but I’ll keep hacking at it.

EDIT Well, there’s some relief for me - disabling mod_autoindex in Apache does the trick. I’m still not sure how I feel about the two endpoints — one with trailing slash and one with — being distinct, but at least there’s a viable solution. If you don’t have a reason to use mod_autoindex, disable it, and it will stop the interference. If you do need it, I’m not entirely sure what you would do.

by Ardekantur at 2008-07-27 19:49

GitHub, purveyors of high-quality source control beauty, released Gist just the other day. Gist, in a nutshell, is pasteable texts controlled by git. Every single one has its own repository. So in theory you can download them, fork them, and thanks to the GitHub guys, embed them in your own webpages. This provides a unique opportunity to ensure that the posts you write about edge community stuff — I’m looking at you, Rails and Merb jerks :-) — can remain relevant. Simply write a Gist with your source code and corresponding output, and embed that in your blog. Tag that blog entry somehow with a reminder to check it every four months or something. And, every four months, when something reminds you, you take another look at the source code snippet, and make sure it’s relevant.

What needs fixing with Gist?

  • Downloading snippets at all doesn’t seem to work. It makes sense to not have that button when it comes to snippets comprised of a single file, but with being able to specify multiple files for a single snippet, downloading should archive and download them all.
  • It should be possible to only embed one part of a snippet, instead of all parts of them, in the case when multiple files are specified.

What would be awesome?

  • Being able to specify a certain file of the snippet as an rspec or Test::Unit file for the snippet. This way, we can have auto-testing snippets. This is clearly in a fantastical sort of realm, but who knows what will be possible when Gist becomes more robust?

by Ardekantur at 2008-07-27 03:16

2008-07-25

Why shouldn’t we be allowed to have multiple files with the same name in one directory, so long as they’re all different versions of the same file?

To wit:

$ ls -al
-rw-r--r--   1 ardekantur  staff      60 Jul  6 23:20 hello_world.c
-rw-------   1 ardekantur  staff      62 Jul  5 13:00 hello_world.c
-rw-r--r--   1 ardekantur  staff      61 Jul  7 00:35 hello_world.c

by Ardekantur at 2008-07-25 19:05

Fourth in the series of “how or why shaim does what it does”:

  1. WPF versus IM typing notifications
  2. WPF windows, in my Winforms application?
  3. .NET 3.0 functionality in .NET 2.0: a sorting, filtering, bindable list (Part Two)

Right on the heels of the two-parter on the BindingListCollection, this little spiel will continue the trend of describing the core contact list and its data structures, and how it all works with the UI. We’ll also touch on the threading model - or complete lack thereof - of the shaim core and its plugins.

A little GUI development background, but not much

A graphical UI (any graphical UI, not just shaim’s) can only be updated by the thread that created it. If another thread tries to update some text, or move a window, or change something’s color, the UI could deadlock and that is not good. The process of executing code on the UI thread is called invoking : any thread can call the Invoke method on a UI object, give it some code to execute, and that code will be executed on the UI thread so it can safely update the UI.

shaim’s hedonistic threading free-for-all

With one notable exception - which is the subject of this post - the shaim core doesn’t make much of an attempt to control the threading of its plugins. Each plugin is free to do whatever it wants, and shaim events aren’t guaranteed to be synchronized to anything in particular (the core does synchronize access to its data structures so that operations like ContactList.UpdateContactStatus will execute in the order they were called).

Let’s take OscarLib as an example. The initial login sequence of OSCAR is a pretty rigid call-response setup, so when the network socket receives data, it processes and sends a response on the same thread. The synchronous processing ensures that there aren’t any responses out of order from the packets that initiated them. This all changes, however, once the OSCAR session is initialized and asynchronous messages like status updates start coming in. Processing something like an incoming message may take a noticeable amount of time, and if it’s being processed on the same thread that received it, the socket might end up missing a packet. To solve this problem, the socket uses the ThreadPool.QueueUserWorkItem method to dispatch an incoming packet. The packet is processed by a random thread in the thread pool, a system-allocated collection of threads that are meant to be spawned for processing information in the background (that is, not in the main process, which in this case is the thread that owns the socket).

“Processed by a random thread” - so these events are not happening on the UI thread. Huh. Problems ahoy!

The easy part: dispatching shaim events in the UI

Each shaim event defined by the core defines a delegate that can handle itself (tee hee).

public class ShaimMessageReceivedEvent : ShaimIncomingEvent
{
    public delegate void Handler(ShaimMessageReceivedEvent);
}

When a plugin registers to handle a specific event, it uses a method that matches the signature of the event’s Handler delegate. We can define a very very simple incoming message handler registered by the UI plugin that will display the message to the shaim user:

private void HandleIncomingMessage(ShaimMessageReceivedEvent evnt)
{
    Conversation conv = FindConversation(evnt.Contact); // Gets a reference to the conversation window for this contact
    conv.AppendMessage(evnt.Message);  // Appends the text of the message to the conversation window
}

Simple, but it won’t work right. When this event comes in on a thread other than the UI thread - and it most assuredly will - the UI will lock up and WPF may even throw an exception and die unexpectedly and leave a ton of debt for its family to take care of, but it had no life insurance and the whole debacle ends in bankruptcy.

Let’s avoid that by dispatching the incoming event onto the UI thread:

// A simple delegate that will be initialized in a single method's scope
private delegate void AnonymousInvoker();

private void HandleIncomingMessage(ShaimMessageReceivedEvent evnt)
{
    AnonymousInvoker invoker = delegate
    {
        Conversation conv = FindConversation(evnt.Contact); // Gets a reference to the conversation window for this contact
        conv.AppendMessage(evnt.Message);  // Appends the text of the message to the conversation window
    };
    // Invoke the operation on the UI thread
    Application.Current.Dispatcher.BeginInvoke(invoker);
}

It’s a bit more verbose, and it has to be done for every incoming event, but it’s 100% thread-safe. It also has the benefit of removing the responsibility of marshalling every event onto the UI thread from the core. This is a desirable trait because it encapsulates UI responsibility within the UI plugin. The shaim framework might not even have an active UI plugin, so there’d be no reason for the core to have to perform the extra logic.

The hard part: dispatching binding events in the core

The above works well when the developer is defining their own event handlers, but it doesn’t solve the thread dispatch problem when something happens for which there isn’t an explicit shaim event. When there’s a direct binding between a data structure and the UI, and another thread updates the data structure, the binding attempts to update on the same thread that invoked the change and the UI craps itself. This presents a huge problem for the contact list and its constituent objects and collections, all of which are directly bound by the UI and updated by random threads spewing out of the plugins.

Well hell, there goes our fever-dream of the core not knowing anything about dispatching onto the UI. Fortunately, we can at least design the solution so that the core doesn’t have to know anything specific about the UI. It has to know two things: one, that the UI requires dispatching, and two, how to dispatch an event onto the UI thread. In turn, the UI has to expose information about whether it requires dispatching, and provide a generic mechanism for doing dispatch.

An interface is defined that provides a method to check whether if dispatch is required, and a method to do the dispatch:

/// <summary>
/// Specifies an interface for an object that can dispatch method calls onto the UI thread
/// </summary>
public interface IUIDispatcher
{
    /// <summary>
    /// Dispatches a delegated method onto the UI thread
    /// </summary>
    /// <param name="methodDelegate">The delegate to invoke on the UI thread</param>
    /// <param name="parameters">A list of parameters to pass to the method</param>
    void Dispatch(Delegate methodDelegate, params object[] parameters);
    /// <summary>
    /// Checks to see if the currently executed thread has access to the UI thread
    /// </summary>
    /// <returns><c>true</c> if a method can be executed in the context of the UI thread</returns>
    bool CheckAccess();
}

…and the UI plugin interface is extended to request one of these buggers from the UI plugin:

public interface IUIPlugin
{
    ...
    /// <summary>
    /// Gets a <see cref="IUIDispatcher"/> object to delegate method calls to the UI thread
    /// </summary>
    /// <returns>A new <see cref="IUIDispatcher"/></returns>
    IUIDispatcher CreateDispatcher();
}

Each UI plugin will define their IUIDispatcher differently, but the WPF plugin does it like so:

public class UIDispatcher : IUIDispatcher
{
    private DispatcherPriority dispatchPriority;

    /// <summary>
    /// Initializes a new UIDispatcher
    /// </summary>
    /// <param name="dispatcherPriority">The priority at which to dispatch method calls</param>
    public UIDispatcher(DispatcherPriority dispatcherPriority)
    {
        this.dispatchPriority = dispatcherPriority;
    }

    #region IUIDispatcher Members

    public void Dispatch(Delegate methodDelegate, params object[] parameters)
    {
        if (Application.Current != null)
        {
            if (parameters.Length > 0)
            {
                Application.Current.Dispatcher.Invoke(dispatchPriority, methodDelegate, parameters[0]);
            }
            else
            {
                Application.Current.Dispatcher.Invoke(dispatchPriority, methodDelegate);
            }
        }
    }

    public bool CheckAccess()
    {
        return Application.Current.Dispatcher.Thread == System.Threading.Thread.CurrentThread;
    }

    #endregion
}

Using the IUIDispatcher in the BindingListCollection

Let’s take a look back at the BindingListCollection. It raises binding events in response to things like adding or removing items, as well as moving items around in response to status or name updates. Since those updates may be coming from some crazy random thread, it’ll need to use the IUIDispatcher to raise those events. The following is pseudocodeish, but it illustrates the point; consult the actual BindingListCollection code for details on the move operation and how the IUIDispatcher gets assigned.

private IUIDispatcher uiDispatcher;
...
private delegate void MoveInListHandler(T item);

void MoveInList(T item)
{
    // If there is no UI dispatcher or we're on the right thread...
    if(uiDispatcher == null || uiDispatcher.CheckAccess())
    {
        // Do the MoveInList action, finding new indexes and moving the item
    }
    else
    {
        // There is a UI dispatcher to contend with, and we're on the wrong thread
        // Invoke the current method on the UI thread, then the above code will execute correctly
        uiDispatcher.Dispatch(new MoveInListHandler(MoveInList), item);
    }
}

Presto! This method is used throughout the BindingListCollection and the ContactList to ensure directly bound data members are updated on the correct thread, and no UI plugin has to be concerned about where updates are coming from.

Ensuring events are invoked correctly is a pain in the ass, but a wholly necessary one. The IUIDispatcher is the best method I could design, but if any readers have ideas about how shaim could institute a threading model that doesn’t involve *every* plugin operation being executed on the UI thread, I’d love to hear about it in the comments.

by Chris at 2008-07-25 16:03

2008-07-23

I’m sure this is a horror in dozens of ways, but eruby sucks and my host doesn’t have mod_ruby. So I got creative.

The .htaccess rewrites requests for any file ending in .rb to this handler.php, which confirms that the requested ruby script exists, then executes it and prints the result.

<?php
//PHP script to execute ruby scripts when the host doesn’t have a cgi handler for .rb
//Use with this .htaccess:

/*
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*)\.rb$ handler.php?rb=$1.rb [NC,QSA]
*/

$file = $_GET['rb'];

if(in_array($file, scandir(‘.’)))
{
foreach(
$_REQUEST as $key=>$value) if($key != ‘rb’) $args .= “ $key=”.urlencode($value);
echo
exec(escapeshellcmd(‘./’.$file.$args));
}
else
{
echo
‘404- Page not found’;
}
?>

Here’s an example ruby script using this hack- nothing special to do here at all:

#!/usr/local/bin/ruby

require ‘cgi’

print “Hello from Ruby!<br>”
print “All of the input variables:<hr>”

ARGV.each do |arg|
print CGI::unescape(arg.to_s)
print “<br>”
end

All the GET, POST, and COOKIE variables are at your fingertips in ARGV! (You could get them with Ruby’s CGI module as well.)

So here’s what it looks like to users:

Screenshot of ruby without mod_ruby hack

Screenshot of ruby without mod_ruby hack

by Factor Mystic at 2008-07-23 21:38

2008-07-22

I was holding off writing this post until I was calmed down about it, but you know what? This is angryinterface.

I submit Exhibit F:


Yet Another Fucking Login Prompt. I saw Shapeways on Mashable and thought "hey, I would love to fabricate some gears, and maybe some other stuff", so I go to look at their site.

But nooooooo, you have log in. Does no one understand that I (and everyone else) have a thousand fucking logins to every site in existence? Do I really need to login to BROWSE your site? That's ridiculous.

I hate your site, I hate your stupid login prompts.

by Blake Householder (noreply@blogger.com) at 2008-07-22 16:02

2008-07-19

As part of a foolish attempt to get people to learn prolog, I've been writing some tutorials.

It has been fun, and some people were interested, but busy/lazy. I was planning to build up to a proper lisp interpreter, but I haven't got that far yet.

eval(X,O) :- defined(X,A), eval(A,O).
eval([X|T],O) :- defined(X,A), eval([A|T],O).

eval(X,X) :- number(X); X = t ; X = [].

eval([quote,X],X).
eval([lambda|X],[lambda|X]).
eval([define,X,Y],t) :- \+ defined(X,_), asserta(defined(X,Y)).

eval([cond],_) :- !, fail.
eval([cond,[H,A]|_],Z) :- eval(H,O), \+ O = [],!, eval(A,Z).
eval([cond,_|T],Z) :- eval([cond|T],Z),!.

eval([F|A],X) :- eval_list(A,Ae), apply(F,Ae,X),!.

eval_list([],[]).
eval_list([H|T],[Ho|To]) :- eval(H,Ho), eval_list(T,To).

apply(add,[X,Y],Z) :- Z is X + Y.
apply(add,[X,Y|T],Z) :- I is X + Y, apply(add,[I|T],Z).

apply(mul,[X,Y],Z) :- Z is X * Y.
apply(mul,[X,Y|T],Z) :- I is X * Y, apply(mul,[I|T],Z).

apply(sub,[X,Y],Z) :- Z is X - Y.
apply(div,[X,Y],Z) :- Z is X / Y.

apply(mod,[X,Y],Z) :- Z is X mod Y.
apply(pow,[X,Y],Z) :- Z is X ** Y.

apply(eq,[X,Y],t) :- X = Y.
apply(eq,[X,Y],[]) :- \+ X = Y.

apply(atom,[X],t) :- atom(X); X = [].
apply(atom,[[_|_]],[]).

apply(cons,[X|[Y]],[X|Y]).
apply(car,[[X|_]],X).
apply(cdr,[[_|T]],T).

apply([lambda,[],E],[],O) :- eval(E,O).
apply([lambda,[A|Ta],E],[L|Tl],O) :- subst(A,L,E,E2), apply([lambda,Ta,E2],Tl,O).

subst(_,_,[],[]).
subst(A,B,[A|T],[B|L]) :- subst(A,B,T,L).
subst(A,B,[H|T],[H|L]) :- subst(A,B,T,L).
subst(A,B,A,B).
subst(_,_,X,X).

% gprolog
:- predicate_property(defined,dynamic).
% swi prolog
:- dynamic defined/2.

defined(_,[]) :- !,fail.


Due to the implementation being a little quirky on purpose, we can do things like:
?-  eval_list([[define,3,4],[add,3,3]],X).

X = [t, 8] 

Yes
?- eval_list([[define,quote,sub],[quote,8,2]],X).

X = [t, 6] 

Yes
?- eval_list([[define,define,add],[define,3,[quote,8,2]]],X).

X = [t, 10] 

Yes
?-


As well as more normal things like this:
?- eval_list([[define,square,[lambda,[x],[mul,x,x]]],[square,4]],X).

X = [t, 16] 

Yes

2008-07-19 14:34

Windows and Linux users seem to be perpetually stiffed when it comes to beautiful, near-perfect applications. Apple has a distinct aesthetic lead: Textmate and Stanza are two programs that are unparalleled on the other major operating systems. I want them.

The closest I've come is my iPod touch, because one of my two dream programs has a free portable version. If you guessed Stanza, you'd be right. If you guessed Textmate, what the hell is wrong with you?

I've always hated reading books on the computer screen, but if there's a glimmer of hope, it's Stanza. Just look at that reflection in the tilted screenshot above. Mmm. Looks better than the slickest Windows alternative you can muster. The problem with the portable version is I'm stuck with books from Feedbooks.com, and, while it's not a bad catalog, you can't upload your own eBooks if you don't have an Apple computer somewhere with Stanza.

But what's this pretty new entry in my settings menu after installing Stanza that lets me change something called a catalog? That sounds cool, but what's a catalog, exactly? I pulled up the default, http://catalog.lexcycle.com/:

<catalog title="Lexcycle Online Catalog"
       maintainer="catalog@lexcycle.com"
       description="Online catalog of free titles
                      hosted by lexcycle.com">
  <catalog title="Free Books by Feedbooks"
           location="feedbooks/proxy/proxy.php" >>

<catalog title="International Classics" location="greatbooks/catalog.xml" >> <catalog title="Religious Texts" location="religious/religious.xml" >> </catalog> Oh, hi, XML. Those links eventually end up at epub files, an open ebook standard—basically zipped up CSS and XHTML that Stanza can download and display. I decided to make an epub file, upload a custom catalog, and see if my iPod liked me.

Result? It likes me bunches.

If you're on Windows or Linux, and you want a book that isn't in the Feedbooks catalog, do this:

1. Get or create an epub file.

2. Upload it somewhere.

3. Make an XML file that looks kind of like this:

<catalog title="detabbed's Pirate ePub Catalog"
       maintainer="detabbed@gmail.com"
       description="Free words!">
<item title="Marquez - One Hundred Years of Solitude"
    location="http://detabbed.googlepages.com/000001.epub">>

</catalog>

4. Upload that somewhere. If you use the pastebin clone I provided, be sure to click "Show as plain text" and use that URL for the next step.

5. In your iPhone or iPod touch, go to Settings -> Stanza -> Advanced and plug in the URL to your personal catalog. Ex.

Primary Online Catalog http://rafb.net/p/gRg9bm28.txt

Now when you pull up Stanza's Online Catalog option you should see your books listed, ready to be devoured.

by Matt Eckert (noreply@blogger.com) at 2008-07-19 11:33

Pixelmator’s lasso tool is all or nothing. That is to say, if you wish to select something with it, you must hold down your mouse button the entirety of the time you are making your selection. This makes it impossible to do anything but the most basic of selections. Nothing refined or nuanced. This is extremely frustrating.

by Ardekantur at 2008-07-19 03:39