Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 1-10 of 42 total  RSS 

Creating a bucket in Amazon S3 through an irb session

1) Log into an irb session, and enter your S3 login details.
require 'rubygems'
require 'aws/s3'

  AWS::S3::Base.establish_connection!(
    :access_key_id     => 'REPLACE_ME',
    :secret_access_key => 'REPLACE_ME'
  )

output:
=> #<AWS::S3::Connection:0xb75e0594 @http=#<Net::HTTP s3.amazonaws.com:80 open=false>, @secret_access_key="", @options={:server=>"s3.amazonaws.com", :access_key_id=>"", :port=>80, :secret_access_key=>"", :persistent=>true}, @access_key_id="19S45GYAGWK8DC2B8VG2">

2) Browse the existing buckets.
AWS::S3::Service.buckets

output:
=> [#<AWS::S3::Bucket:0xb75cc850 @object_cache=[], @attributes={"name"=>"ogg.twitteraudio.com", "creation_date"=>Sat Apr 26 10:40:16 UTC 2008}>, #<AWS::S3::Bucket:0xb75cc83c @object_cache=[], @attributes={"name"=>"t1000", "creation_date"=>Fri Apr 25 21:35:21 UTC 2008}>, #<AWS::S3::Bucket:0xb75cc814 @object_cache=[], @attributes={"name"=>"t2000", "creation_date"=>Fri Apr 25 21:53:15 UTC 2008}>]

3) Browse the buckets in a programmatical way.
AWS::S3::Service.buckets.each {|b| puts b.name}

output:
ogg.twitteraudio.com
t1000
t2000


4) Add a new bucket called t3000.
AWS::S3::Bucket.create('t3000')

output:
=> true

5) Observe adding the bucket again doesn't cause an error.
AWS::S3::Bucket.create('t3000')

output:
=> true

6) View the buckets again.
AWS::S3::Service.buckets

output:
=> [#<AWS::S3::Bucket:0xb75cc850 @object_cache=[], @attributes={"name"=>"ogg.twitteraudio.com", "creation_date"=>Sat Apr 26 10:40:16 UTC 2008}>, #<AWS::S3::Bucket:0xb75cc83c @object_cache=[], @attributes={"name"=>"t1000", "creation_date"=>Fri Apr 25 21:35:21 UTC 2008}>, #<AWS::S3::Bucket:0xb75cc814 @object_cache=[], @attributes={"name"=>"t2000", "creation_date"=>Fri Apr 25 21:53:15 UTC 2008}>]

Note: You would expect t3000 to be in there however it didn't appear possibly because of the bucket permissions.

7) Let's then look for bucket t3000.
t3000 = AWS::S3::Bucket.find('t3000')

output:
=> #<AWS::S3::Bucket:0xb76df724 @object_cache=[], @attributes={"prefix"=>nil, "name"=>"t3000", "marker"=>nil, "max_keys"=>1000, "is_truncated"=>false, "xmlns"=>"http://s3.amazonaws.com/doc/2006-03-01/"}>

8) Now that we've found the bucket let's upload a text file called works.txt.
file = "works.txt"

output:
=> "works.txt"
AWS::S3::S3Object.store(file, open(file), 't3000', :access => :public_read)

output:
=> #<AWS::S3::S3Object::Response:0x-608926458 200 OK>

9) Setting the file access to :public_read allows us to view the file from the http location http://t3000.s3.amazonaws.com/works.txt

References:
http://amazon.rubyforge.org/
upload_to_s3 - Ruby S3 upload client [dzone.com]

*update: 14:30 30 April 2008 *
I didn't use Bucket.objects(:reload) which is the reason why the bucket t3000 didn't show up with the statement Service.buckets

Reference: spatten design - Amazon S3, Ruby and Rails slides [spattendesign.com]

Redirect a URL with Ruby CGI

#!/usr/bin/ruby

require 'cgi'

cgi = CGI.new
print cgi.header({'Status' => '302 Moved', 'location' =>  'http://www.wired.com'})

or
url = 'http://www.wired.com/'
print cgi.header({'status'=>'REDIRECT', 'Location'=>url})


References:
RE: cgi redirect [nagaokaut.ac.jp]
Ruby/CGI - assari [mokehehe.com]
HTTP/1.1: Status Code Definitions [w3.org]

https://hosted67.renlearn.com/77571/HomeConnect/Login.aspx

// description of your code here

// insert code here..

ProjectX client-side code

This Ruby code uses a unified XML format to create a password record on a web server. It's intended to be run as a batch file which gets called from another Ruby application called maintain_projectx which gets called from a cronjob.

In this example the password is stored on the server not for authentication but simply to provide a reminder service in the event the user forgets it.

require 'net/http'
require 'rexml/document'
include REXML

class ProjectXClient
  attr :doc
  def initialize(raw_url)
    url = URI.escape(raw_url)
    xml_data = Net::HTTP.get_response(URI.parse(url)).body
    @doc = Document.new(xml_data)
  end
  
end

if __FILE__ == $0

  xml_project = <<PROJECT
  <project name='password'>
    <method name='create'>
      <params>
        <param var='password' val='p6789c'/>
        <param var='title' val='hotmail'/>
      </params>
    </method>
  </project>
PROJECT
  
  pxc = ProjectXClient.new("http://yourdomain.com/p/projectx.cgi?xml_project=" + xml_project)
  doc = pxc.doc
  puts doc
    
end


output -what's returned from the server is an XML response containing a result. The result echos the method executed and the output from that method, which in this instance is the xml record node 'entry'.
<result method='rtn_create'>
  <append id='19367'>
    <entry id='19367'>
      <password>p6789c</password>
      <title>hotmail</title>
      <description/>
    </entry>
  </append>
</result>


Getting Started With WWW::Mechanize

This Ruby code uses WWW:mechanize to act like a web browser.

 require 'rubygems'
 require 'mechanize'

 agent = WWW::Mechanize.new
 page = agent.get('http://google.com/')


Refer to the documentation at http://mechanize.rubyforge.org/mechanize/. Then gem install mechanize, and try running the code in an irb session.

output (extract):
=> #<WWW::Mechanize::Page
 {url #<URI::HTTP:0xfdbbbb286 URL:http://www.google.com/>}
 {meta}
 {title "Google"}
 {iframes}
 {frames}
 {links
  #<WWW::Mechanize::Page::Link
   "Images"
   "http://images.google.com/imghp?hl=en&tab=wi">
  #<WWW::Mechanize::Page::Link
   "Maps"
   "http://maps.google.com/maps?hl=en&tab=wl">
  #<WWW::Mechanize::Page::Link
   "News"
   "http://news.google.com/nwshp?hl=en&tab=wn">
  #<WWW::Mechanize::Page::Link
   "Shopping"
   "http://www.google.com/prdhp?hl=en&tab=wf">
  #<WWW::Mechanize::Page::Link
   "Gmail"
   "http://mail.google.com/mail/?hl=en&tab=wm">

bScan - Simple Web Aplications Scanner

// Web application scanner (ex: phpBB, myCMS, myBlog, mySite etc..) - Only in PHP !
// Find XSS, sql injection, remote file inclusion

#####################################################################################
#	Black_H  / Nooz -- 30:01:07 
#	Bl4ck.H<>gmail<>com
#

class BScan

#####################################################################################
#	Regex
#

@@space    = '([[:space:]]*)'

@@userdat  = '('
@@userdat += '(\$_SERVER\[([\'\"]*)HTTP_)|'
@@userdat += '(\$_GET)|'
@@userdat += '(\$_POST)|'
@@userdat += '(\$_COOKIE)|'
@@userdat += '(\$_REQUEST)|'
@@userdat += '(\$_FILES)|'
@@userdat += '(\$_ENV)|'
@@userdat += '(\$_HTTP_COOKIE_VARS)|'
@@userdat += '(\$_HTTP_ENV_VARS)|'
@@userdat += '(\$_HTTP_GET_VARS)|'
@@userdat += '(\$_HTTP_POST_FILES)|'
@@userdat += '(\$_HTTP_POST_VARS)|'
@@userdat += '(\$_HTTP_SERVER_VARS\[([\'\"]*)HTTP_)'
@@userdat += ')'

@@regex = Hash.new
@@regex = 
	{'TYPE' => 'vars overwrite','LEVEL' => '2','REGEX' => /extract#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'vars overwrite','LEVEL' => '2','REGEX' => /import_request_variables#{@@space}\((.*)\)/i},
	{'TYPE' => 'fopen vuln','LEVEL' => '3','REGEX' => /fopen#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'copy vuln','LEVEL' => '3','REGEX' => /copy#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'fwrite vuln','LEVEL' => '3','REGEX' => /fwrite#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'sql injection','LEVEL' => '2','REGEX' => /(mysql_query|mssql_query|mysqli_query)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'crlf injection','LEVEL' => '1','REGEX' => /mail#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'cross site scripting','LEVEL' => '1','REGEX' => /\<\?\=#{@@space}(.*)#{@@userdat}/i},
	{'TYPE' => 'cross site scripting','LEVEL' => '1','REGEX' => /(print|echo|print_r|var_dump)#{@@space}(|\(|\")(.*)#{@@userdat}/i},
	{'TYPE' => 'php code execution','LEVEL' => '3','REGEX' => /eval#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'php code execution','LEVEL' => '3','REGEX' => /file_put_contents#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'variable attribution', 'LEVEL' => '2','REGEX' => /(.*)\$#{@@userdat}(.*)/i},
	{'TYPE' => 'chmod affectation','LEVEL' => '1','REGEX' => /chmod#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'file disclosure','LEVEL' => '2','REGEX' => /(readfile|file_get_contents|file)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'file disclosure','LEVEL' => '2','REGEX' => /(show_source|highlight_file)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'bzopen vuln','LEVEL' => '2','REGEX' => /bzopen#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'file deletion','LEVEL' => '2','REGEX' => /(rmdir|unlink|delete)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'command execution','LEVEL' => '3','REGEX' => /(exec|system|passthru|shell_exec|proc_open|pcntl_exec)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'buffer overflow','LEVEL' => '3','REGEX' => /(confirm_phpdoc_compiled|mssql_pconnect|mssql_connect|crack_opendict|snmpget|ibase_connect)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'ip falsification','LEVEL' => '1','REGEX' => /(.*)(HTTP_CLIENT_IP|HTTP_X_FORWARDED_FOR|HTTP_PC_REMOTE_ADDR)(.*)/i},
	{'TYPE' => 'putenv vuln','LEVEL' => '2','REGEX' => /putenv#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'full path disclosure','LEVEL' => '1','REGEX' => /(htmlentities|htmlspecialchars)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'magic_quotes_gpc bypass','LEVEL' => '1','REGEX' => /(stripslashes|urldecode)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'file inclusion','LEVEL' => '3','REGEX' => /(include|include_once|require|require_once)#{@@space}(|\(|\")(.*)#{@@userdat}/i}

#####################################################################################
#	Main
#

  def initialize()

	################
	#	Usage

if (ARGV.length < 4)
puts  '
 ---------------------------------------------------------------------
|             Credits: Black_H <bl4ck.h@gmail.com>                    |
|                 URL: Lemon-Inside.sup.fr                            |
|                Note: Premier code Ruby                              |
 ---------------------------------------------------------------------

 ---------------------------------------------------------------------
|   Usage:  scan.rb -d <Dossier> -i <Save.html>                       |
|   Ex:  scan.rb -d ./ -i output.html                                 |
 ---------------------------------------------------------------------		
 '
 end
 
	################
	#	Options & Vars
	
	@@scan_alldir =  self.options('d')
	@@out_file =  self.options('i')
	
	@@ban = [".", "..", "scan.rb", @@out_file.to_s]

	@@scan_buffer = Array.new
	
	################
	#	Options Error ?
	
	if (@@scan_alldir != false and @@scan_alldir.empty? == false)
	self.dscan(@@scan_alldir)
	self.output(@@scan_buffer)
	@@scan_buffer = ''
	end


	

  end

#####################################################################################
#	Dir Scan 
#
  
  def dscan(dir)
      
	d = Dir.open(dir.to_s)
	d = d.sort - @@ban
	
      d.each { |fichier|

      case File.ftype(dir+fichier)
        when "directory"
          self.dscan(dir + fichier + "/")
        when "file"
		  puts  'Scan => ' + dir + fichier 
          self.fscan(dir + fichier)
      end

	  }
  end

#####################################################################################
#	File Scan 
#
  
  def fscan(file)

	fichier = File.readlines(file)
	i = 1

	fichier.each { |line|
						
		@@regex.each  { |info|
			
			test = (line  =~ info['REGEX']) 
		
				if (test) 
			
				@@scan_buffer += ['FILE' => file, 'LINE' => i.to_s, 'MATCH' => line, 'LEVEL' => info['LEVEL'], 'TYPE' => info['TYPE']]
				#	5 , 1 , 3 , 4 , 2
				next @@scan_buffer
				end
		}

	i += 1
  	} 
	
  end

#####################################################################################
#	Output buffer
#
  
  def output(buffer)
  
	@html_hmodel = '<html>'
	@html_hmodel += '<style type="text/css">'
	@html_hmodel += '<!--'
	@html_hmodel += '.level0 {background-color: #CCCCCC;}'
	@html_hmodel += '.level1 {background-color: #33FF66;}'
	@html_hmodel += '.level2 {background-color: #FFFF33;}'
	@html_hmodel += '.level3 {background-color: #FF0000;}'
	@html_hmodel += '--></style><body><h1>BScan v1.0</h1><pre>'

	code = @html_hmodel
	
	buffer.each { |infos|
	
	keys = infos.keys
	code += "<span class='level" + infos["LEVEL"] + "'>" + keys[1].to_s + ' : ' + infos["TYPE"] + '</span><br />'
	code += "<span class='" + infos["LEVEL"] + "'>" + keys[3].to_s + ' : ' + infos["LEVEL"] + '</span><br />'
	code += "<span class='" + infos["LEVEL"] + "'>" + keys[4].to_s + ' : ' + infos["FILE"] + '</span><br />'
	code += "<span class='" + infos["LEVEL"] + "'>" + keys[0].to_s + ' : ' + infos["LINE"] + '</span><br />'
	code += "<span class='" + infos["LEVEL"] + "'>" + keys[2].to_s + ' : ' + infos["MATCH"] + '</span><br />'
	

	}
		code += "</pre></body></html>"
		fhtml = File.open(@@out_file.to_s, "w")
		fhtml.write code
		code = ''

	
  end
#####################################################################################
#	Parse & Get Options
#
 
  def options(param)
  
	i = 0
		ARGV.each  { |valeur|
		
    		if (valeur == '-' + param.to_s)
				return ARGV[i+1]
			elseif (valeur != '-' + param.to_s)
				return false
			end
		i += 1
		}
		
	end
  
end

scan = BScan.new

Ruby equivalent of a simple Wget

Reads the file contents from a URL. I used this code to work around the problem with the Ruby RSS reader which couldn't read the RSS file from digg.com. The reason being that the website would not allow files to be downloaded without supplying the User-Agent string.

require 'open-uri'
puts open('http://digg.com/rss/index.xml',
     'User-Agent' => 'Ruby-Wget').read

Ruby remote file checker

require 'rubygems'
require 'open-uri'
require 'net/http'

def remote_file_exists?(url)
  url = URI.parse(url)
  Net::HTTP.start(url.host, url.port) do |http|
    return http.head(url.request_uri).code == "200"
  end
end

Resolving a tinyURL to destination URL

Resolving a tinyURL to its original destination URL in a fastest way.

    < ?php

    // request like this http://<domain>/tinyurl.php?c=<tinyurl>

    $num = $_GET['c'];

    if($fp = fsockopen ("tinyurl.com", 80, $errno, $errstr, 30))
    {
    if ($fp) {
    fputs ($fp, "HEAD /$num HTTP/1.0\r\nHost: tinyurl.com\r\n\r\n");
    while (!feof($fp)) {$headers .= fgets ($fp,128);}
    fclose ($fp);
    }
    $arr1=explode("Location:",$headers);
    $arr=explode("\n",trim($arr1[1]));
    echo trim($arr[0]);
    }
    ?>


http://www.webforth.com/2007/07/resolving-tinyurls-to-the-desination-url

Punycoded URLs in Ruby

This is just a proof-of-concept snippet for how to internationalize domain names using punycode4r (sudo gem install punycode4r).

For more information please see:
- Punycode
- Internationalized domain name



#!/usr/local/bin/ruby -Ku

# NOTE: The following is not the complete source code by Kazuhiro NISHIYAMA.
#       For the full source code with more features, comments & test cases please see: 
#       open -e `gem environment gemdir`/gems/punycode4r-0.2.0/lib/punycode.rb
#
# This is pure Ruby implementing Punycode (RFC 3492).
# (original ANSI C code (C89) implementing Punycode is in RFC 3492)
#
# copyright (c) 2005 Kazuhiro NISHIYAMA
# You can redistribute it and/or modify it under the same terms as Ruby.


require "unicode"     # sudo gem install unicode

module Punycode

  module Status
    class Error < StandardError; end
    class PunycodeSuccess; end
    # Input is invalid.
    class PunycodeBadInput < Error; end
    # Output would exceed the space provided.
    class PunycodeBigOutput< Error; end
    # Input needs wider integers to process.
    class PunycodeOverflow < Error; end
  end
  include Status


  BASE = 36; TMIN = 1; TMAX = 26; SKEW = 38; DAMP = 700
  INITIAL_BIAS = 72; INITIAL_N = 0x80; DELIMITER = 0x2D

  module_function

  def basic(cp)
    cp < 0x80
  end

  def delim(cp)
    cp == DELIMITER
  end

  def decode_digit(cp)
    cp - 48 < 10 ? cp - 22 :  cp - 65 < 26 ? cp - 65 :
      cp - 97 < 26 ? cp - 97 : BASE
  end

  def encode_digit(d, flag)
    return d + 22 + 75 * ((d < 26) ? 1 : 0) - ((flag ? 1 : 0) << 5)
  end

  def flagged(bcp)
    (0...26) === (bcp - 65)
  end

  def encode_basic(bcp, flag)
    # bcp -= (bcp - 97 < 26) << 5;
    if (0...26) === (bcp - 97)
      bcp -= 1 << 5
    end
    # return bcp + ((!flag && (bcp - 65 < 26)) << 5);
    if !flag and (0...26) === (bcp - 65)
      bcp += 1 << 5
    end
    bcp
  end

  MAXINT = 1 << 64


  def adapt(delta, numpoints, firsttime)
    delta = firsttime ? delta / DAMP : delta >> 1
    delta += delta / numpoints

    k = 0
    while delta > ((BASE - TMIN) * TMAX) / 2
      delta /= BASE - TMIN
      k += BASE
    end

    k + (BASE - TMIN + 1) * delta / (delta + SKEW)
  end

  def punycode_encode(input_length, input, case_flags, output_length, output)

    n = INITIAL_N
    delta = out = 0
    max_out = output_length[0]
    bias = INITIAL_BIAS

    input_length.times do |j|
      if basic(input[j])
        raise PunycodeBigOutput if max_out - out < 2
        output[out] =
          if case_flags
            encode_basic(input[j], case_flags[j])
          else
            input[j]
          end
        out+=1
      # elsif (input[j] < n)
      #   raise PunycodeBadInput
      # (not needed for Punycode with unsigned code points)
      end
    end

    h = b = out

    if b > 0
      output[out] = DELIMITER
      out+=1
    end

   while h < input_length

      m = MAXINT
      input_length.times do |j|
        # next if basic(input[j])
        # (not needed for Punycode)
        m = input[j] if (n...m) === input[j]
      end

      raise PunycodeOverflow if m - n > (MAXINT - delta) / (h + 1)
      delta += (m - n) * (h + 1)
      n = m

      input_length.times do |j|
        # Punycode does not need to check whether input[j] is basic:
        if input[j] < n # || basic(input[j])
          delta+=1
          raise PunycodeOverflow if delta == 0
        end

        if input[j] == n

          q = delta; k = BASE
          while true
            raise PunycodeBigOutput if out >= max_out
            t = if k <= bias # + TMIN # +TMIN not needed
                  TMIN
                elsif k >= bias + TMAX
                  TMAX
                else
                  k - bias
                end
            break if q < t
            output[out] = encode_digit(t + (q - t) % (BASE - t), false)
            out+=1
            q = (q - t) / (BASE - t)
            k += BASE
          end

          output[out] = encode_digit(q, case_flags && case_flags[j])
          out+=1
          bias = adapt(delta, h + 1, h == b)
          delta = 0
          h+=1
        end
      end

      delta+=1; n+=1
    end

    output_length[0] = out
    return PunycodeSuccess
  end

  def punycode_decode(input_length, input, output_length, output, case_flags)

    n = INITIAL_N

    out = i = 0
    max_out = output_length[0]
    bias = INITIAL_BIAS

    b = 0
    input_length.times do |j|
      b = j if delim(input[j])
    end
    raise PunycodeBigOutput if b > max_out

    b.times do |j|
      case_flags[out] = flagged(input[j]) if case_flags
      raise PunycodeBadInput unless basic(input[j])
      output[out] = input[j]
      out+=1
    end

    in_ = b > 0 ? b + 1 : 0
    while in_ < input_length

      oldi = i; w = 1; k = BASE
      while true
        raise PunycodeBadInput if in_ >= input_length
        digit = decode_digit(input[in_])
        in_+=1
        raise PunycodeBadInput if digit >= BASE
        raise PunycodeOverflow if digit > (MAXINT - i) / w
        i += digit * w
        t = if k <= bias # + TMIN # +TMIN not needed
              TMIN
            elsif k >= bias + TMAX
              TMAX
            else
              k - bias
            end
        break if digit < t
        raise PunycodeOverflow if w > MAXINT / (BASE - t)
        w *= BASE - t
        k += BASE
      end

      bias = adapt(i - oldi, out + 1, oldi == 0)

      raise PunycodeOverflow if i / (out + 1) > MAXINT - n
      n += i / (out + 1)
      i %= out + 1

      # not needed for Punycode:
      # raise PUNYCODE_INVALID_INPUT if decode_digit(n) <= base
      raise PunycodeBigOutput if out >= max_out

      if case_flags
        #memmove(case_flags + i + 1, case_flags + i, out - i)
        case_flags[i + 1, out - i] = case_flags[i, out - i]

        # Case of last character determines uppercase flag:
        case_flags[i] = flagged(input[in_ - 1])
      end

      #memmove(output + i + 1, output + i, (out - i) * sizeof *output)
      output[i + 1, out - i] = output[i, out - i]
      output[i] = n
      i+=1

      out+=1
    end

    output_length[0] = out
    return PunycodeSuccess
  end

  def encode(unicode_string, case_flags=nil, print_ascii_only=false)
    input = unicode_string.unpack('U*')
    output = [0] * (ACE_MAX_LENGTH+1)
    output_length = [ACE_MAX_LENGTH]

    punycode_encode(input.size, input, case_flags, output_length, output)

    outlen = output_length[0]
    outlen.times do |j|
      c = output[j]
      unless c >= 0 && c <= 127
        raise Error, "assertion error: invalid output char"
      end
      unless PRINT_ASCII[c]
        raise PunycodeBadInput
      end
      output[j] = PRINT_ASCII[c] if print_ascii_only
    end

    output[0..outlen].map{|x|x.chr}.join('').sub(/\0+\z/, '')
  end

  def decode(punycode, case_flags=[])
    input = []
    output = []

    if ACE_MAX_LENGTH*2 < punycode.size
      raise PunycodeBigOutput
    end
    punycode.each_byte do |c|
      unless c >= 0 && c <= 127
        raise PunycodeBadInput
      end
      input.push(c)
    end

    output_length = [UNICODE_MAX_LENGTH]
    Punycode.punycode_decode(input.length, input, output_length,
                             output, case_flags)
    output.pack('U*')
  end

  UNICODE_MAX_LENGTH = 256
  ACE_MAX_LENGTH = 256

  # The following string is used to convert printable
  # characters between ASCII and the native charset:

  PRINT_ASCII =
    "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" \
    "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" \
    " !\"\#$%&'()*+,-./" \
    "0123456789:;<=>?" \
    "@ABCDEFGHIJKLMNO" \
    "PQRSTUVWXYZ[\\]^_" \
    "`abcdefghijklmno" \
    "pqrstuvwxyz{|}~\n"
end



# cf. http://snippets.dzone.com/posts/show/4527

UTF8REGEX = /\A(?:                                                            
              [\x09\x0A\x0D\x20-\x7E]            # ASCII
            | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
            |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
            | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
            |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
            |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
            | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
            |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
            )*\z/mnx


UTF8_REGEX_MBYTE = /(?:                                 
                 [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
               |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
               | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
               |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
               |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
               | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
               |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
               )/mnx



# cf. http://demo.icu-project.org/icu-bin/idnbrowser (samples)
# on Mac OS X you can check the Ruby conversions with the GUI app PunyCode, http://software.dibomedia.de/products/show/2

str = "http://www.ﺱﺲﺷ.com/"
str = "www.сделат картинки.com"
str = "http://www.сделаткартинки.com/"
str = "http://tūdaliņ.lv/"
str = "http://www.zürich.com/"
str = "http://www.hören.at/"
str = "http://www.žlutý kůň.com/"
str = "www.färgbolaget.nu"
str = "www.brændendekærlighed.com"
str = "www.mäkitorppa.com"
str = "www.färjestadsbk.net"
str = "あーるいん.com"
str = "www.예비교사.com"
str = "www.ハンドボールサムズ.com"
str = "www.日本平.jp"
str = "www.räksmörgås.se"
str = "www.różyczka.pl/