We're growing into something new. Read More
o_sam_o

Sam Cavenagh


Conviz - Convict Visualisation

A website I created to house visualizations of the British Convict Transportation Registry. It contains over 15 visualizations and also makes the registry easier to search and filter. Please note that the sites design is largely copied from Press75's Transmit wordpress theme.

enable :inline_templates

get '/:username' do |username|
  pass if username.blank?
  resp = Net::HTTP.get_response(URI.parse("http://api.forrst.com/api/v2/users/posts?username=#{username}"))
  data = resp.body
  result = JSON.parse(data).with_indifferent_access
  pass if result[:stat] == 'fail'

  response['Cache-Control'] = "public, max-age=3600"
  content_type 'application/atom+xml'
  builder do |x|

    x.feed(xmlns: "http://www.w3.org/2005/Atom") {

      x.title     "Posts by Forrster #{username}"
      x.updated   to_xs_date_time Time.now.utc
      x.link      href: url("/#{username}"), rel: "self"
      x.id        "#{username}:forrster:post:feed"

      result[:resp].each do |post|
        x.entry {
          x.title     post[:title]
          x.link      href: post[:post_url]
          x.id        post[:post_url]
          x.content   haml(:content, locals: {post: post}), type: 'html'
          x.updated   to_xs_date_time post[:updated_at]
          x.author    { x.name username }
        }
      end
    }

  end
end

not_found do
  "Forrst user not found. Try: #{url("/kyle")}"
end

def to_xs_date_time(time)
  DateTime.parse(time.to_s).strftime('%Y-%m-%dT%H:%M:%S%z').insert(-3, ':')
end

__END__

@@ content

- if post[:url].blank?
  %h2= post[:title]
- else
  %h2
    %a{href: post[:url]}= post[:title]

- unless post[:snaps].blank? || post[:snaps][:mega_url].blank?
  %img{src: post[:snaps][:mega_url]}
- unless post[:content].blank?
  %pre= post[:content]
- unless post[:formatted_description].blank?
  %p= post[:formatted_description]

Forrst Atom Feed

Here is my attempt to create something useful with the Forrst API. It's a Sinatra app that generates an atom feed of a users posts. Does this functionality already exist within Forrst? An example can be found here. The complete project can be found here.

require 'rubygems'
require 'json'
require 'net/http'

users = []

(1...30_000).each do |i|
  resp = Net::HTTP.get_response(URI.parse("http://api.forrst.com/api/v2/users/info?id=#{i}"))
  data = resp.body

  result = JSON.parse(data)
  next unless result['resp']['username']

  p "User #{result['resp']['username']}: followers: #{result['resp']['followers']}"
  users << {:username => result['resp']['username'], :followers => result['resp']['followers'].to_i}
 
  sleep 5 if i % 30 == 0
end

users.sort!{ |x,y| y[:followers] <=> x[:followers] }

print "\n\n\n=== Users with most followers ===\n"
(0...9).each do |i|
  p "User: #{users[i][:username]} Followers #{users[i][:followers]}"
end

p "Finished"

Who is being followed on Forrst

This is a small extension to my previous Who to follow on Forrst post. The above script uses the new forrst API to find the users with the most followers. I'll try to think of something more productive to do with the API in the coming weeks. Results User: @kyle Followers 13645 User: @forrst Followers 1937 User: @chriscoyier Followers 1697 User: @jakerocheleau Followers 1399 User: @Pasquale Followers 1196 User: @rnorgan Followers 912 User: @ryancarson Followers 885 User: @Mlconley Followers 756 User: @chrisspooner Followers 720

package com.forrst.bugger.bug;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class GenericBug<T> implements Bug, InvocationHandler {
	
	protected T target = null;
	private List<MethodCall> methodLog = new ArrayList<MethodCall>();
	
	public GenericBug(T target){
		this.target = target;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		methodLog.add(new MethodCall(method, args));
		return method.invoke(target, args);
	}

	@Override
	public void printLog() {
		for(MethodCall call : methodLog){
			System.out.println("METHOD CALL: " + call.getMethod().getName() + " with: " + call.getArgsAsString());
		}
	}

	@Override
	public void replayActions() {
		for(MethodCall call : methodLog){
			try {
				call.getMethod().invoke(target, call.getArgs());
			} catch (Exception e) {
				// TODO add error handling
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}
	}

	public <T> T buggedTarget(Class<T> targetInterface){
		  return (T) java.lang.reflect.Proxy.newProxyInstance(this.getTarget().getClass().getClassLoader(),
		                                                  new Class[]{targetInterface},
		                                                  this);
	}
	
	private T getTarget() {
		return target;
	}
	
	private class MethodCall {
		private Method method;
		private Object[] args;
		
		public MethodCall(final Method method, final Object[] args) {
			super();
			this.method = method;
			this.args = args;
		}

		public Method getMethod() {
			return method;
		}

		public Object[] getArgs() {
			return args;
		}
		
		public String getArgsAsString(){
			String argsString = "";
			if (args != null) {
				for (int i = 0; i < args.length; i++) {
					Object arg = args[i];
					if (i != 0) {
						argsString += ", ";
					}
					argsString += arg;
				}
			}
			return argsString;
		}
	}

}

RE: How to think of... Macros

This is a response to @cue's How to think of... Marcros post. Here is a quote from the original post that outlines the exercise: Imagine that you are a spy and have been assigned the task to infiltrate a robot factory to plant a tracking device which will allow you to place a bug in every robot produced by the factory and record every action it makes. My comment on this post was that @cue's implementation would require updating the bug every time the robot changed. I suggested using reflections and byte code manipulation with a library such as ASM would avoid this limitation. I have never used ASM before and it turns out it is way more complicated that i ever imagined it would be, thus I have gone with an alternative implementation that uses InvocationHandler. This implementation does have the limitation that the generic bug must be applied to an object at an interface level. Fortunately @cue's example did provide a Robot interface. Here is some sample code that shows how the generic bug is used: GenericBug<Robot> bug = new GenericBug<Robot>(new SimpleRobot()); Robot robot = bug.buggedTarget(Robot.class); robot.alert(); robot.move(100, 200); robot.log("Robot test log"); System.out.println("== Bug Log =="); bug.printLog(); System.out.println("== Bug Replay =="); bug.replayActions(); Raw Code » Sample source code can be downloaded from here.

<select name="simple-select">
  <option>One</option>
  <option>Two</option>
  <option>Three</option>
</select>

<script>
   $('select[name=simple-select]').select2Buttons();
</script>

jQuery plugin for threadless.com style selects

jQuery plugin for converting a standard html select into threadless.com style buttons. This plugin was inspired by a question from @greatpotato a few weeks ago. Features Converts normal HTML selects into button like elements (a tags) Supports JS change callbacks Supports disabled options Supports disabled selects Supports OptGroups Allows no default selection (like threadless) Demo Here Code and Documentation Here

Babazee

This is a project I was working on over 2 years ago (after my son was born). The idea was an online site for tracking your child's achievements e.g. height, weight, walking and talking. It had a social aspect where you could see playmates stats and comment on achievements. I got the project to a place where it was ready for early beta testing but never did a big marketing push and ended up moving onto other projects.

Swarms - Torrent/Movie Discovery

Screenshot of a torrent discovery site I was working on last year. The popularity of movies is determined by swarm size. Ultimately I abandoned the project because of the legal implications of trying to run such a site. Please note the page design borrows very heavily from this wordpress theme