Archive for the ‘Software’ Category

Imogen Heap Event

Monday, August 24th, 2009

Just wanted to say thanks to everyone who was able to make it out to Immi’s event before and after her Letterman appearance!

If you missed the event, be sure to subscribe to our youtube channel, so you can be notified when we upload the video!

http://www.youtube.com/user/Vokle

There may be more events with Imogen in the horizon, so be sure to stay tuned via twitter by following @vokle

We keep posted with her via her site www.imogenheap.com and on twitter @imogenheap of course!

Be sure to let us know who else you’d like to see and talk to live!

You can also sign up to be notified via email for big updates and events on vokle at http://www.vokle.com

Thanks again!

Ruby Dynamic DNS Script for Slicehost

Monday, July 6th, 2009

I know everyone and there mother has written one of these, so I guess I’m now my mother.  Run this as a cron to enable a pretty cheapo dynamic DNS via Slicehost.  You’ll need the ActiveResource gem to use it.


#! /usr/bin/env ruby

# */5 * * * * /usr/bin/dynamicdns.rb

require 'rubygems'

require 'activeresource'

require 'open-uri'

 

# Configure your stuff

@api_key      = 'YOUR_API_KEY'

@record_id    = 1337 #the record ID you are updating

@ttl          = 10 * 60 #ten minutes, yeah sure.

@record_type  = 'A'

@record_name  = 'vpn'

@ip_site      = 'http://checkip.dyndns.org/'

@ip_path      = '/tmp/lastip'

@log          = '/tmp/lastip.log'                                                               

API_SITE      = "https://#{@api_key}@api.slicehost.com/"

 

class Record < ActiveResource::Base;self.site = API_SITE;end;

 

# Check the last ip address

@last_ip = File.exist?(@ip_path) ? File.read(@ip_path).strip : ''

 

begin

  @ip = open(@ip_site){|f| f.read}.match(/[0-9.]+/)[0]

rescue Exception

  File.open(@log,'a+'){|f| f.puts "#{Time.now} [ERROR] - Failed to open #{@ip_site}"}

  exit(1)

end

 

# Update the email address

if @ip != @last_ip

  File.open(@ip_path,'w+'){|f| f.puts @ip} 

 

  record = Record.find(@record_id)

  record.name = @record_name

  record.record_type = @record_type

  record.data = @ip

  record.ttl  = @ttl

  record.save                                                                   

 

  File.open(@log,'a+'){|f| f.puts "#{Time.now} [INFO] - IP updated: #{@ip}"}

else

  File.open(@log,'a+'){|f| f.puts "#{Time.now} [INFO] - IP did not change"}

end

Dealing with Adobe and Serving Socket Policy Servers via NGiNX and 10 lines of code

Wednesday, June 10th, 2009

Ok, I don’t even know where to start, but I guess I’ll start by thanking Adobe for a such a high quality product (</sarcasm>).  So we are working towards our new Vokle product, dubbed Vokle Everywhere (by me, just now).

So our new product allows for embeddability of chats and to do this we use ActionScript 3.  I wouldn’t say that AS3 has its short comings, except of course, Flex, but from time to time we have some issues with it.  Like not being able to override the ‘Accept’ header in a UrlRequest and other various dumb things.  Instead we moved to a mildly liberating open source AS3 HTTP Client.

AS3HTTPClientLib is pretty sweet, the only thing that sort of sucked was that we needed a Socket Policy Server, and the last thing I want to do is run another server (already have nginx, merb, wowza, yadayadayada) like this butthole suggests.

Instead I figured, there has to be a way to just serve the crossdomain.xml file without being a giant hassle, especially since I am already serving it over HTTP for the same domain.  So I said, frig it, I’ll do it with NGiNX since NGiNX is already serving my static files.  So the upside is when my servers are running, my ‘policy server’ is serving, the downside is, I had to finagle it so it wasn’t a pain in the ass.  The problem is that ActionScript makes a ‘weird’ request when its looking for a policy server, and NGiNX doesn’t understand it, so it servers a 400 Bad Request, well, it turns out that you can just do it hackety-hack and send your crossdomain.xml file as the 400 Error Page.  This works because AS isn’t doing an HTTP Request, so it DOESNT CARE about the HTTP Status.  Bam, NGiNX Flash Socket Policy Server in 10 lines of code.

To enable ’socket policy server’ functionality in NGiNX simply add another ’server’ directive to your nginx.conf and drop your crossdomain.xml file in whatever folder your NGiNX server is serving its statics from.


    server {

      listen 843;

      server_name  localhost;

      location / {

        rewrite ^(.*)$ /crossdomain.xml;

      }

      error_page 400 /crossdomain.xml;

 

      location = /crossdomain.xml {

        root html;

      }

    }

 

Sweet, start your nginx server and use the only useful thing from the Adobe blog post:


perl -e 'printf "<policy-file-request/>%c",0' | nc 127.0.0.1 843

And you should see your policy file:


<?xml version="1.0"?>

<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">

<cross-domain-policy>

  <allow-access-from domain="*" secure="false" to-ports="*"/>

  <site-control permitted-cross-domain-policies="master-only" />

</cross-domain-policy>

MovingParts: Auto versioning your Javascript and CSS

Tuesday, March 17th, 2009

This tutorial has a few moving parts.  It could be easily recreated with any stack, but for this post I used Nginx and Merb.

Why?

We like to keep things fast.  Two ways we do that is compress the hell out of our js/css and set the cache time on our assets to max.  This is cool to do and obvious, the thing that sucks is when its time to roll out new javascript or css making sure the clients get the updates.

What?

For this example I am using merb and merb-assets (w/ my latest merb patch), nginx and ruby-yui.

Step1 - Add version info to assets with merb-assets

In our code base we have a version for our site, set in a variable like WWW_VERSION.  Using this variable it is easy (with the newest merb-assets plugin) to modify the path of all of your assets on the fly.

Stick this in your init.rb…


WWW_VERSION = "0.1.0"

# this will make require_js "application"

# => /javascripts/application.0.1.0.js

# instead of /javascripts/application.js

Merb::Plugins.config[:asset_helpers][:js_suffix] = ".#{WWW_VERSION}"

Merb::Plugins.config[:asset_helpers][:css_suffix] = ".#{WWW_VERSION}"

 

At this point in time merb is going to start outputting modified paths to your assets that contain version numbers.  This is cool because now when we modify javascript or css and bump the version number it will cause the clients that have cached the static assets to redownload them since the file path is different.  The part that sucks is renaming a bunch of javascript and css files.

Step2 - Lying about file names

Renaming a bunch of files does suck!  So don’t do it.  Instead have that sneaky russian Nginx lie about it for you.

Stick this in you nginx.conf…


location ~ ^/(javascripts|stylesheets) {

  rewrite ^/(javascripts|stylesheets)\/([^\d]+)(?:\.[0-9]+)*\.(js|css)$ /$1/$2.$3;

  expires max;

  break;

}

This rewrite rule will make nginx route any javascript/stylesheet to the original file if it contains a version number.  So a request like to ‘/javascripts/application.0.1.0.js’ will be rewritten to ‘/javascripts/application.js’.  Nifty.

 

Step3 - Compress those assets

You can compress your assets in a number of ways, I’ll go with shameless self promotion and recommend RubyYUI.  RubyYUI is a ruby wrapper for the Java-based YUI  Compressor.  It lets you glob paths instead of doing one file at a time and add suffixes to files.  All sorts of things.

You can do something like this in a vlad or capistrano task during deployment.


require 'rubygems'

require 'ruby-yui'

# this will cause the files to be compressed in place

Yui.new("./public/javascripts",:stomp => true, :suffix => nil).compress

Yui.new("./public/stylesheets",:stomp => true, :suffix => nil, :type=>:css).compress

 

Now you have compressed assets in place in your deployed app and nginx will rewrite any versioned paths to your compressed files.  Bump your version number and all your clients will start getting the new compressed files.  Wee.

Why IE doesn’t drop Flash NetConnections / NetStreams and how to fix it.

Tuesday, March 10th, 2009

Problem

The Adobe Flash Player ActiveX control for Internet Explorer 7 (I don’t know about IE6) will not disconnect NetConnections if the connection was made by a swf instance loaded in a tab and only that tab was closed. If IE itself is closed though the NetConnection will be dropped. This could lead to hung “ghost” connections where you won’t hear any audio, etc. but your Wowza Media Server (and maybe Flash Media Server, who knows?) will still think the client is connected.

Explanation

Laziness on the part of two large corporations.

Solution

Register a JS handler function for window.onbeforeunload that uses the Flash ExternalInterface to call a function in your swf that manually closes the NetConnection. The event “onbeforeunload” is recognized and executed by IE, Safari and Firefox before the onunload event is fired. It is apparently not handled by Opera AFAIK but that’s ok since IE is the only one that actually needs this fix.

In your ActionScript 3 code somewhere:


import flash.external.ExternalInterface;

....

private someFunction():void{

if( ExternalInterface.available ){

ExternalInterface.addCallback("disconnect", disconnect);

}

}

private function disconnect():void {

_my_net_connection1.close();

}

In your Javascript code for the page that loads your swf:


window.onbeforeunload = function(){

// pure JS

var swf = document.getElementById('mySwf');

swf.disconnect();

// jQuery 1.2.6 version

$("#mySwf")[0].disconnect();

}

The End

(image originally from visualizeus)

Ruby YUI

Monday, December 15th, 2008

Well, ok, it’s not that Yui, but now that I’ve got your attention, I’ve made a ruby wrapper for the YUI JavaScript compressor.  What’s the point in that you say.  Well, I’d ideally like to keep my javascript like I keep my Sass/CSS.  The source I work on in one place, the ‘compiled’ stuff in a public one.  Why?  It just feels cleaner, and I like clean.

So whats it do?  Well essentially the same thing as the YUI compressor command line except that it will process an entire folder structure.  It also has the ability to bundle all the compressed files into one file.  It includes Thor tasks so you can use it from the command line and a ruby Yui class so you can access it programatically.

You can git it (haha, ‘git it’, git it? God damn I’m funny) from: http://github.com/coryodaniel/ruby-yui/tree/master

What using it look like, well:


require 'rubygems'
require 'ruby-yui'

yui = Yui.new "./public/javascripts"

yui.minify #=> true | false
yui.bundle #=> path to bundle or nil
yui.clobber #=> cleans up generated files

#Shortcut
Yui.compress "./public/javascripts" #=> same thing as Yui#minify
Yui.clobber "./public/javascripts" #=> cleans up generated files

Yui#initialize and Yui.compress also take params hashes:


yui = Yui.new "public/javascripts", {

# clobber files before compressing new ones
:clobber        => false,

# change the java command to run it
:java_cli       => "java -jar",

# alternate  YUI jar file
:yui_jar        => File.join(YUI_ROOT,"ext","yuicompressor-2.4.2.jar"),

# change the suffix used on the compressed file
:suffix         => "yui-min",

# change the out path; NOTE: the outpath is String#sub for the input path
# ./public/javascripts/main.js => ./my/out/path/main.js
:out_path       => nil,

# :js or :css
:type           => :js,

# YUI parameters
:charset        => nil,
:preserve_semi  => false,
:disable_opt    => false,
:nomunge        => false
}

DataMapper Remixable Updates

Friday, December 5th, 2008

DM Remixables 0.9.7 RC 2 is out.  Includes clean accessor name creation, more specs, and the ability to assign methods from the Remixable to generated and remixing classes.  Woot, woot.  See the specs and readme for examples.

DataMapper is Viewable

Friday, December 5th, 2008

Even when I’m panicking I’m a fan of datamapper.  I like how clean it generally makes my code, but I do notice that I tend to have the same queries cropping up from time to time either in the same application or in other apps using my model library.  This just wasn’t dry enough for me, so I made dm-is-viewable.  It gives sql-like view functionality to DataMapper Resources.  It’s a pretty simple plugin, but lets take a look, um kay?

Let’s start with a really simple User class…


class User
  include DataMapper::Resource
  belongs_to :location

  property :id, Serial
  property :name, String
  property :username, String
  property :password, String

  property :gender, String
  property :age, Integer

  property :favorite_color, String
  property :favorite_number, Integer
end

class Location
  include DataMapper::Resource

  has n, :users

  property :id, Serial
  property :name, String
  property :desc, String
end

Making your resource viewable is pretty easy, first grab the dm-is-viewable gem, then say that your resource is viewable. Views take the exact same parameters that you could pass to Resource.all. The only difference is that dm-is-viewable stores them until they are called.


class User
  include DataMapper::Resource
  is :viewable  

  #lets create some views
  create_view :legal_women, :gender => 'female', :age.gt => 18
  create_view :serial_killers, :favorite_number => 666, :favorite_color => 'black'

  #... Resource code *SNIP SNIP*
end

See the befores and afters below:


# Legal Women Before
User.all(:gender => 'female', :age.gt => 18)

# Legal Women After
User.view :legal_women

# Serial killers before
User.all(:favorite_number => 666, :favorite_color => 'black')

# Serial killers after
User.view :serial_killers

# You can also pass further limiting query parameters to #view.
# Legal Local Women Before
User.all(:gender => 'female', :age.gt => 18, User.location.name => 'Los Angeles')

# Legel Local Women After
User.view :legal_women, User.location.name => 'Los Angeles'

# Passing additional parameters FURTHERS the limitation of records, so..
User.view :legal_women, :gender => 'male'
# => Would return nil, the query would essentially be generated as:
#  SELECT * from users where gender = 'male' and gender = 'female'

Simply, clean, useful. Woot.

Examining WarningShot::FileResolver (As an example resolver)

Tuesday, November 11th, 2008

Read about it on GitHub, (who’s formatting didn’t bastardize it, as much).

Massive Flaw in DataMapper 0.9.6 - Write Once Read Many Many Many Many Many, Im outta space here…

Thursday, October 30th, 2008

So I found a pretty massive flaw in DataMapper (ticket @ lighthouse).  Whenever using the :fields attribute when doing Resource#first or Resource#all a crap load (techincally speaking) of queries are fired at MySQL.  I put a ticket in and a lot of information and links to some pasties with examples (see lighthouse).  I don’t have the time to look into this now, being that I have a deadline Saturday, but it’s a pretty serious problem and I’m sure a lot of people are experiencing it and don’t realize it.

To try it out for yourself lets use Merb (and Ive tried it without merb, and without any dm plugins and the problem still persists).

Steps to reproduce:


merb-gen app my_test_app

cd ./my_test_app

merb -i

DataMapper.auto_migrate!

#turn on dm loggering (thats what I call it)

DataObjects::Mysql.logger = DataObjects::Logger.new('log/dm.log', 0)

# create a few users, then, get their IDs, I dare you...

User.all(:fields=>[:id])

So, the problem is if you look at your mysql log or DataMapper Query Log you’ll see a crapload of selects trying to get what the first select in the list retrieved.  The funnier part is, the subsequent selects are selecting the fields that aren’t included in the :fields list.

Why is this a huge problem?  That query above for my 3 user test table generated about 90 trips to MySQL.  The ‘friend button’ on Vokle.com just generated about 240 trips to MySQL in one click, that’s how I found the issue in the first place.

Someone fix this please!?  If its not fixed by Saturday (my day ‘off’), I’m going to look into it.

Happy (bug) hunting.