--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--