--Apple-Mail-3-601619372
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	delsp=yes;
	format=flowed

Begin forwarded message:

> From: Florian Gross <flgr / ccan.de>
> Date: April 28, 2006 5:15:32 PM CDT
> To: Ruby Quiz <james / grayproductions.net>
> Subject: Re: [QUIZ] cat2rafb (#77)
>
> Moin.
>
> Just sending this to you before the end of the spoiler period so I  
> don't forget to submit this in time. :)
>
> A cool thing I discovered is that you can actually post and receive  
> binary data to RAFB without any trouble as long as it is not too  
> long. So it is possible to (ab)use it as a storage for small files  
> of any kind.
>
> Feel free to repost it to the ML as soon as the spoiler period is  
> over.
>
> Thanks for continuing to manage Ruby Quiz. It's still a lot of fun  
> to take part!
>
> Kind regards,
> Florian Gross
--Apple-Mail-3-601619372
Content-Transfer-Encoding: quoted-printable
Content-Type: application/x-ruby;
	x-unix-mode=0666;
	name="cat2rafb.rb"
Content-Disposition: attachment;
	filename=cat2rafb.rb

#!/usr/bin/ruby=20-W2=0D=0A=0D=0Arequire=20'open-uri'=0D=0Arequire=20=
'cgi'=0D=0A=0D=0Amodule=20URI=0D=0A=20=20#=20Builds=20a=20query=20string=20=
from=20the=20specified=20(key=20=3D>=20value)=20hash=0D=0A=20=20def=20=
self.build_query(data)=0D=0A=20=20=20=20data.map=20do=20|key,=20value|=0D=
=0A=20=20=20=20=20=20[CGI.escape(key.to_s),=20=
CGI.escape(value.to_s)].join("=3D")=0D=0A=20=20=20=20end.join("&")=0D=0A=20=
=20end=0D=0Aend=0D=0A=0D=0A=0D=0A=0D=0Amodule=20RAFB=0D=0A=20=20extend=20=
self=0D=0A=0D=0A=20=20class=20RAFBError=20<=20StandardError;=20end=0D=0A=20=
=20class=20TooFastError=20<=20RAFBError;=20end=0D=0A=0D=0A=20=20MainURI=20=
=3D=20URI("http://rafb.net/paste/")=20unless=20defined?(MainURI)=0D=0A=20=
=20PostURI=20=3D=20MainURI=20+=20"paste.php"=20unless=20=
defined?(PostURI)=0D=0A=0D=0A=20=20#=20Fetch=20page=0D=0A=20=20main_data=20=
=3D=20MainURI.read=0D=0A=0D=0A=20=20#=20Find=20type=20option=20HTML=0D=0A=
=20=20type_section=20=3D=20main_data[%r{<select=20name=3D"lang"=20=
id=3D"lang">(.+?)</select>}m,=201]=0D=0A=0D=0A=20=20#=20Delete=20=
commented=20out=20options=0D=0A=20=20type_section.gsub!(/<!--.*?-->/,=20=
"")=0D=0A=0D=0A=20=20#=20Parse=20types=20from=20type=20option=20HTML=0D=0A=
=20=20type_re=20=3D=20%r{<option=20=
value=3D"([^"]+)"\s*((?:selected)?)[^>]*>([^<]+)</option>}=0D=0A=20=20=
type_data=20=3D=20type_section.scan(type_re)=0D=0A=0D=0A=20=20#=20Find=20=
the=20default=20type=0D=0A=20=20DefaultType=20=3D=20type_data.find=20do=20=
|(value,=20selected,=20label)|=0D=0A=20=20=20=20selected=20!=3D=20""=0D=0A=
=20=20end.last=20unless=20defined?(DefaultType)=0D=0A=0D=0A=20=20#=20=
Build=20{label=20=3D>=20value}=20map=20from=20type=20data=0D=0A=20=20=
TypeMap=20=3D=20type_data.inject({})=20do=20|map,=20(value,=20selected,=20=
label)|=0D=0A=20=20=20=20map.merge(label=20=3D>=20value,=20value=20=3D>=20=
value)=0D=0A=20=20end=20unless=20defined?(TypeMap)=0D=0A=20=20Types=20=3D=20=
TypeMap.keys.sort=20unless=20defined?(Types)=0D=0A=0D=0A=20=20#=20Posts=20=
the=20supplied=20data=20to=20RAFB=20and=20returns=20the=20resulting=20=
URI.=0D=0A=20=20#=20type=20has=20to=20be=20an=20element=20of=20Types=20=
and=20defaults=20to=20DefaultType.=0D=0A=20=20#=20You=20can=20supply=20=
an=20optional=20nickname,=20description=20and=20tab=20conversion=20size.=0D=
=0A=20=20#=20If=20you=20don't=20supply=20a=20tab=20conversion=20size=20=
tabs=20are=20left=20untouched.=0D=0A=20=20#=20Can=20raise=20a=20=
RAFB::TooFastError=20if=20you=20repost=20too=20frequently.=0D=0A=20=20=
def=20post(data,=20type=20=3D=20DefaultType,=20nickname=20=3D=20"",=20=
description=20=3D=20"",=20tab_size=20=3D=20nil)=0D=0A=20=20=20=20unless=20=
Types.include?(type)=0D=0A=20=20=20=20=20=20raise(ArgumentError,=20=
"Unsupported=20type=20%p"=20%=20type)=0D=0A=20=20=20=20end=0D=0A=0D=0A=20=
=20=20=20convert_tabs=20=3D=20tab_size=20||=20"No"=0D=0A=20=20=20=20=
query=20=3D=20URI.build_query(=0D=0A=20=20=20=20=20=20"lang"=20=3D>=20=
TypeMap[type],=0D=0A=20=20=20=20=20=20"nick"=20=3D>=20nickname,=0D=0A=20=20=
=20=20=20=20"desc"=20=3D>=20description,=0D=0A=20=20=20=20=20=20=
"cvt_tabs"=20=3D>=20convert_tabs,=0D=0A=20=20=20=20=20=20"text"=20=3D>=20=
data=0D=0A=20=20=20=20)=0D=0A=0D=0A=20=20=20=20=
Net::HTTP.start(PostURI.host)=20do=20|http|=0D=0A=20=20=20=20=20=20=
response=20=3D=20http.post(PostURI.path,=20query,=0D=0A=20=20=20=20=20=20=
=20=20'content-type'=20=3D>=20'application/x-www-form-urlencoded')=0D=0A=20=
=20=20=20=20=20location=20=3D=20response["location"]=0D=0A=0D=0A=20=20=20=
=20=20=20if=20location=20=3D=3D=20"/paste/toofast.html"=20then=0D=0A=20=20=
=20=20=20=20=20=20raise(TooFastError,=20"Posting=20too=20fast.=20Try=20=
reposting=20later.")=0D=0A=20=20=20=20=20=20else=0D=0A=20=20=20=20=20=20=20=
=20MainURI=20+=20location=0D=0A=20=20=20=20=20=20end=0D=0A=20=20=20=20=
end=0D=0A=20=20end=0D=0A=20=20alias=20:write=20:post=0D=0A=20=20alias=20=
:save=20:post=0D=0A=0D=0A=20=20#=20Same=20as=20RAFB.post(),=20but=20will=20=
retry=20when=20you=20are=20posting=20too=20fast.=0D=0A=20=20def=20=
retry_post(*args)=0D=0A=20=20=20=20delay=20=3D=201=0D=0A=0D=0A=20=20=20=20=
begin=0D=0A=20=20=20=20=20=20post(*args)=0D=0A=20=20=20=20rescue=20=
TooFastError=20=3D>=20error=0D=0A=20=20=20=20=20=20sleep=20delay=0D=0A=20=
=20=20=20=20=20delay=20*=3D=202=0D=0A=20=20=20=20=20=20retry=0D=0A=20=20=20=
=20end=0D=0A=20=20end=0D=0A=0D=0A=20=20#=20Reads=20code=20from=20RAFB.=0D=
=0A=20=20#=20You=20can=20either=20supply=20a=20full=20RAFB=20URI=20or=20=
URI=20string=20or=20the=20identifier=0D=0A=20=20#=20as=20a=20String.=0D=0A=
=20=20def=20fetch(uri)=0D=0A=20=20=20=20unless=20uri.is_a?(URI)=0D=0A=20=20=
=20=20=20=20uri=20=3D=20uri.to_s=0D=0A=0D=0A=20=20=20=20=20=20unless=20=
uri.include?("rafb.net")=0D=0A=20=20=20=20=20=20=20=20uri=20=3D=20=
MainURI.to_s=20+=20"results/#{uri}.html"=0D=0A=20=20=20=20=20=20end=0D=0A=
=0D=0A=20=20=20=20=20=20unless=20uri.include?("http")=0D=0A=20=20=20=20=20=
=20=20=20uri=20=3D=20"http://"=20+=20uri=0D=0A=20=20=20=20=20=20end=0D=0A=
=20=20=20=20end=0D=0A=0D=0A=20=20=20=20uri=20=3D=20=
URI(uri.to_s.sub(/\.html$/,=20".txt"))=0D=0A=0D=0A=20=20=20=20unless=20=
uri.host=20=3D=3D=20"rafb.net"=0D=0A=20=20=20=20=20=20=
raise(ArgumentError,=20"Invalid=20host=20%p"=20%=20uri.host)=0D=0A=20=20=20=
=20end=0D=0A=0D=0A=20=20=20=20unless=20=
uri.path[%r{^/paste/results/[^/.]+\.txt$}]=0D=0A=20=20=20=20=20=20=
raise(ArgumentError,=20"Invalid=20path=20%p"=20%=20uri.path)=0D=0A=20=20=20=
=20end=0D=0A=0D=0A=20=20=20=20open(uri)=20{=20|res|=20res.read=20}=0D=0A=20=
=20end=0D=0A=20=20alias=20:read=20:fetch=0D=0A=20=20alias=20:load=20=
:fetch=0D=0Aend=0D=0A=0D=0Aclass=20String=0D=0A=20=20#=20Posts=20the=20=
supplied=20String=20to=20RAFB=20and=20returns=20the=20resulting=20URI.=0D=
=0A=20=20def=20on_rafb(*more)=0D=0A=20=20=20=20RAFB.retry_post(self,=20=
*more)=0D=0A=20=20end=0D=0A=0D=0A=20=20#=20Reads=20a=20String=20from=20=
RAFB=20using=20the=20supplied=20url.=0D=0A=20=20def=20=
self.from_rafb(uri)=0D=0A=20=20=20=20RAFB.fetch(uri)=0D=0A=20=20end=0D=0A=
end=0D=0A=0D=0A=0D=0A=0D=0Amodule=20RubyURL=0D=0A=20=20extend=20self=0D=0A=
=0D=0A=20=20MainURI=20=3D=20URI("http://rubyurl.com/")=20unless=20=
defined?(MainURI)=0D=0A=20=20PostURI=20=3D=20MainURI=20+=20=
"/rubyurl/create"=20unless=20defined?(PostURI)=0D=0A=0D=0A=20=20#=20=
Posts=20a=20URI=20to=20RubyURL=20and=20returns=20the=20new=20URI.=0D=0A=20=
=20def=20post(uri)=0D=0A=20=20=20=20query=20=3D=20URI.build_query(=0D=0A=20=
=20=20=20=20=20"rubyurl[website_url]"=20=3D>=20uri=0D=0A=20=20=20=20)=0D=0A=
=20=20=20=20data=20=3D=20open([PostURI,=20query].join("?"))=20{=20|res|=20=
res.read=20}=0D=0A=20=20=20=20uri_re=20=3D=20%r{<a=20=
href=3D"([^"]+)">\1</a>}=0D=0A=20=20=20=20URI(data[uri_re,=201])=0D=0A=20=
=20end=0D=0A=20=20alias=20:write=20:post=0D=0A=20=20alias=20:save=20=
:post=0D=0A=20=20alias=20:shorten=20:post=0D=0A=0D=0A=20=20#=20Fetches=20=
the=20new=20URI=20from=20RubyURL=20and=20returns=20it.=0D=0A=20=20def=20=
fetch(uri)=0D=0A=20=20=20=20unless=20uri.is_a?(URI)=0D=0A=20=20=20=20=20=20=
uri=20=3D=20uri.to_s=0D=0A=0D=0A=20=20=20=20=20=20unless=20=
uri.include?("rubyurl.com")=0D=0A=20=20=20=20=20=20=20=20uri=20=3D=20=
MainURI.to_s=20+=20uri=0D=0A=20=20=20=20=20=20end=0D=0A=0D=0A=20=20=20=20=
=20=20unless=20uri.include?("http")=0D=0A=20=20=20=20=20=20=20=20uri=20=3D=
=20"http://"=20+=20uri=0D=0A=20=20=20=20=20=20end=0D=0A=20=20=20=20end=0D=
=0A=0D=0A=20=20=20=20uri=20=3D=20URI(uri)=0D=0A=0D=0A=20=20=20=20unless=20=
uri.host=20=3D=3D=20"rubyurl.com"=0D=0A=20=20=20=20=20=20=
raise(ArgumentError,=20"Invalid=20host=20%p"=20%=20uri.host)=0D=0A=20=20=20=
=20end=0D=0A=0D=0A=20=20=20=20unless=20uri.path.include?("/go/index/")=0D=
=0A=20=20=20=20=20=20uri.path=20=3D=20"/go/index"=20+=20uri.path=0D=0A=20=
=20=20=20end=0D=0A=0D=0A=20=20=20=20unless=20=
uri.path[%r{^/go/index/[^/.]+$}]=0D=0A=20=20=20=20=20=20=
raise(ArgumentError,=20"Invalid=20path=20%p"=20%=20uri.path)=0D=0A=20=20=20=
=20end=0D=0A=0D=0A=20=20=20=20Net::HTTP.start(uri.host)=20do=20|http|=0D=0A=
=20=20=20=20=20=20response=20=3D=20http.get(uri.path)=0D=0A=20=20=20=20=20=
=20response["location"]=0D=0A=20=20=20=20end=0D=0A=20=20end=0D=0A=20=20=
alias=20:read=20:fetch=0D=0A=20=20alias=20:load=20:fetch=0D=0A=20=20=
alias=20:unshorten=20:fetch=20=20=0D=0Aend=0D=0A=0D=0Amodule=20URI=0D=0A=20=
=20#=20Returns=20this=20URI's=20RubyURL=20URI.=0D=0A=20=20def=20=
on_rubyurl(*more)=0D=0A=20=20=20=20RubyURL.post(self,=20*more)=0D=0A=20=20=
end=0D=0A=0D=0A=20=20#=20Constructs=20a=20URI=20from=20a=20RubyURL=20=
URI.=0D=0A=20=20def=20self.from_rubyurl(uri)=0D=0A=20=20=20=20=
RubyURL.fetch(uri)=0D=0A=20=20end=0D=0Aend=0D=0A=0D=0A=0D=0A=0D=0Aif=20=
__FILE__=20=3D=3D=20$0=20then=0D=0A=20=20require=20'optparse'=0D=0A=20=20=
require=20'abbrev'=0D=0A=0D=0A=20=20class=20Array=0D=0A=20=20=20=20def=20=
groups_of(count)=0D=0A=20=20=20=20=20=20unless=20count=20>=200=0D=0A=20=20=
=20=20=20=20=20=20raise(ArgumentError,=20"Invalid=20count=20%p"=20%=20=
count)=0D=0A=20=20=20=20=20=20end=0D=0A=0D=0A=20=20=20=20=20=20ary=20=3D=20=
self.dup=0D=0A=20=20=20=20=20=20result=20=3D=20[]=0D=0A=20=20=20=20=20=20=
while=20group=20=3D=20ary.slice!(0,=20count)=20and=20not=20group.empty?=0D=
=0A=20=20=20=20=20=20=20=20result=20<<=20group=0D=0A=20=20=20=20=20=20=
end=0D=0A=0D=0A=20=20=20=20=20=20return=20result=0D=0A=20=20=20=20end=0D=0A=
=20=20end=0D=0A=0D=0A=20=20TypeNames=20=3D=20RAFB::Types.abbrev=0D=0A=0D=0A=
=20=20Options=20=3D=20{=0D=0A=20=20=20=20:Type=20=3D>=20=
RAFB::Types.grep("Plain=20Text").first=20||=20RAFB::DefaultType,=0D=0A=20=
=20=20=20:Nickname=20=3D>=20ENV["USERNAME"]=20||=20ENV["USER"],=0D=0A=20=20=
=20=20:Description=20=3D>=20"",=0D=0A=20=20=20=20:TabSize=20=3D>=20nil,=0D=
=0A=20=20=20=20:ShortenURI=20=3D>=20true=0D=0A=20=20}=0D=0A=0D=0A=20=20=
ARGV.options=20do=20|opts|=0D=0A=20=20=20=20script_name=20=3D=20=
File.basename($0)=0D=0A=20=20=20=20id=20=3D=20%q$Id:=20cat2rafb.rb=20117=20=
2006-04-28=2022:09:29Z=20flgr=20$=0D=0A=20=20=20=20version=20=3D=20=
id.split("=20")[2=20..=20-1].join("=20")=20rescue=20"unknown"=0D=0A=0D=0A=
=20=20=20=20opts.banner=20=3D=20"Usage:=20ruby=20#{script_name}=20=
[options]"=0D=0A=0D=0A=20=20=20=20opts.separator=20""=0D=0A=20=20=20=20=
opts.separator=20"Submits=20code=20to=20RAFB=20codepaste=20and=20returns=20=
the=20URL."=0D=0A=20=20=20=20opts.separator=20""=0D=0A=0D=0A=0D=0A=20=20=20=
=20opts.separator=20"Specific=20options:"=0D=0A=0D=0A=20=20=20=20types=20=
=3D=20RAFB::Types.map=20do=20|type|=0D=0A=20=20=20=20=20=20type.inspect=0D=
=0A=20=20=20=20end.groups_of(5).map=20do=20|group|=0D=0A=20=20=20=20=20=20=
"=20=20"=20+=20group.join(",=20")=20+=20","=0D=0A=20=20=20=20end=0D=0A=20=
=20=20=20#=20Delete=20last=20comma=0D=0A=20=20=20=20types[-1][-1]=20=3D=20=
""=0D=0A=0D=0A=20=20=20=20opts.on("--type=3Dtype",=20String,=20"-T",=20=
String,=0D=0A=20=20=20=20=20=20"Specify=20type=20of=20posted=20code.",=0D=
=0A=20=20=20=20=20=20"You=20can=20specify=20the=20first=20few=20=
characters=20of",=0D=0A=20=20=20=20=20=20"a=20type=20when=20it=20is=20=
clear=20which=20is=20meant.",=0D=0A=20=20=20=20=20=20"Possible=20values=20=
are:",=0D=0A=20=20=20=20=20=20*(types=20+=0D=0A=20=20=20=20=20=20=20=
["Default:=20#{Options[:Type].inspect}"])=0D=0A=20=20=20=20)=20do=20=
|type|=0D=0A=20=20=20=20=20=20if=20TypeNames.include?(type)=20then=0D=0A=20=
=20=20=20=20=20=20=20Options[:Type]=20=3D=20TypeNames[type]=0D=0A=20=20=20=
=20=20=20else=0D=0A=20=20=20=20=20=20=20=20raise(ArgumentError,=20=
"Invalid=20type=20%p"=20%=20type)=0D=0A=20=20=20=20=20=20end=0D=0A=20=20=20=
=20end=0D=0A=0D=0A=20=20=20=20opts.on("--nick=3Dnick",=20String,=20"-N",=20=
String,=0D=0A=20=20=20=20=20=20"Nick=20name=20to=20use=20as=20author=20=
of=20posted=20code.",=0D=0A=20=20=20=20=20=20"Default:=20Current=20user=20=
(#{Options[:Nickname]})"=0D=0A=20=20=20=20)=20{=20|Options[:Nickname]|=20=
}=0D=0A=0D=0A=20=20=20=20opts.on("--description=3Ddesc",=20=
"--desc=3Ddesc",=20"-D",=0D=0A=20=20=20=20=20=20"Description=20to=20use=20=
for=20posted=20code.",=0D=0A=20=20=20=20=20=20"Default:=20None"=0D=0A=20=20=
=20=20)=20{=20|Options[:Description]|=20}=0D=0A=0D=0A=20=20=20=20=
opts.on("--tab-size=3Dsize",=20"--tabs=3Dsize",=20"-t",=0D=0A=20=20=20=20=
=20=20"Convert=20tabs=20to=20size=20space=20characters.",=0D=0A=20=20=20=20=
=20=20"Default:=20Don't=20convert"=0D=0A=20=20=20=20)=20{=20=
|Options[:TabSize]|=20}=0D=0A=0D=0A=20=20=20=20=
opts.on("--no-shorten-uri",=20"-U",=0D=0A=20=20=20=20=20=20"Don't=20=
shorten=20the=20URI=20from=20RAFB=20via=20RubyURL."=0D=0A=20=20=20=20)=20=
{=20Options[:ShortenURI]=20=3D=20false=20}=0D=0A=0D=0A=20=20=20=20=
opts.separator=20""=0D=0A=0D=0A=0D=0A=20=20=20=20opts.separator=20=
"Common=20options:"=0D=0A=0D=0A=20=20=20=20opts.on_tail("-h",=20=
"--help",=0D=0A=20=20=20=20=20=20"Show=20this=20message."=0D=0A=20=20=20=20=
)=20{=20puts=20opts;=20exit=20}=0D=0A=20=20=20=20opts.on_tail("-V",=20=
"--version",=0D=0A=20=20=20=20=20=20"Show=20the=20version=20of=20this=20=
program."=0D=0A=20=20=20=20)=20{=20puts=20"#{script_name},=20=
#{version}";=20exit=20}=0D=0A=0D=0A=20=20=20=20opts.parse!=0D=0A=20=20=
end=0D=0A=0D=0A=20=20data=20=3D=20ARGF.read=0D=0A=20=20uri=20=3D=20=
RAFB.post(data,=20Options[:Type],=20Options[:Nickname],=0D=0A=20=20=20=20=
Options[:Description],=20Options[:TabSize])=0D=0A=0D=0A=20=20if=20=
Options[:ShortenURI]=20then=0D=0A=20=20=20=20uri=20=3D=20=
RubyURL.post(uri)=0D=0A=20=20end=0D=0A=0D=0A=20=20puts=20uri=0D=0Aend=

--Apple-Mail-3-601619372
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed



--Apple-Mail-3-601619372--