├── VERSION ├── .rspec ├── .document ├── raw_data └── Gaz_places_national.txt ├── bin └── to_town ├── lib ├── to_town │ ├── generators │ │ ├── templates │ │ │ └── mongoid_example.yml │ │ └── mongodb.rb │ ├── data_migration.rb │ ├── db_connection.rb │ ├── point.rb │ ├── cli.rb │ └── converter │ │ └── us.rb └── to_town.rb ├── spec ├── us_spec.rb ├── to_town_spec.rb └── spec_helper.rb ├── Gemfile ├── .gitignore ├── LICENSE.txt ├── Rakefile ├── Gemfile.lock ├── to_town.gemspec └── README.rdoc /VERSION: -------------------------------------------------------------------------------- 1 | 0.0.4 -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -------------------------------------------------------------------------------- /.document: -------------------------------------------------------------------------------- 1 | lib/**/*.rb 2 | bin/* 3 | - 4 | features/**/*.feature 5 | LICENSE.txt 6 | -------------------------------------------------------------------------------- /raw_data/Gaz_places_national.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengjia/to_town/master/raw_data/Gaz_places_national.txt -------------------------------------------------------------------------------- /bin/to_town: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | $LOAD_PATH.unshift File.expand_path('../lib', File.dirname(__FILE__)) 4 | 5 | require 'to_town/cli' 6 | ToTown::CLI.start -------------------------------------------------------------------------------- /lib/to_town/generators/templates/mongoid_example.yml: -------------------------------------------------------------------------------- 1 | defaults: &defaults 2 | host: localhost 3 | 4 | development: 5 | <<: *defaults 6 | database: to_town_development 7 | 8 | test: 9 | <<: *defaults 10 | database: to_town_test -------------------------------------------------------------------------------- /lib/to_town.rb: -------------------------------------------------------------------------------- 1 | require 'to_town/point' 2 | require 'to_town/db_connection' 3 | 4 | module ToTown 5 | 6 | def self.check(lat, lng, limit = 20) 7 | # TODO validation 8 | # TODO add a limit 9 | Point.near(latlng: [ lat, lng ]).limit(limit) 10 | end 11 | 12 | end -------------------------------------------------------------------------------- /lib/to_town/data_migration.rb: -------------------------------------------------------------------------------- 1 | # store the imported file so it won't be imported again 2 | 3 | module ToTown 4 | 5 | class DataMigration 6 | 7 | include Mongoid::Document 8 | include Mongoid::Timestamps 9 | 10 | field :filename 11 | 12 | end 13 | 14 | end -------------------------------------------------------------------------------- /lib/to_town/generators/mongodb.rb: -------------------------------------------------------------------------------- 1 | require 'thor/group' 2 | 3 | module ToTown 4 | module Generators 5 | class Mongodb < Thor::Group 6 | 7 | include Thor::Actions 8 | 9 | def genenrate 10 | template("mongoid_example.yml", "mongoid.yml") 11 | end 12 | 13 | def self.source_root 14 | File.dirname(__FILE__) + "/templates" 15 | end 16 | 17 | end 18 | end 19 | end -------------------------------------------------------------------------------- /lib/to_town/db_connection.rb: -------------------------------------------------------------------------------- 1 | require 'to_town/generators/mongodb' 2 | 3 | RACK_ENV ||= 'development' 4 | 5 | unless File.exists?('mongoid.yml') 6 | ToTown::Generators::Mongodb.start 7 | end 8 | 9 | db_config = YAML::load File.open('mongoid.yml' ) 10 | db_name = db_config[RACK_ENV]['database'] 11 | Mongoid.configure do |config| 12 | config.master = Mongo::Connection.new.db(db_name) 13 | config.autocreate_indexes = true 14 | end -------------------------------------------------------------------------------- /lib/to_town/point.rb: -------------------------------------------------------------------------------- 1 | require 'mongoid' 2 | 3 | module ToTown 4 | 5 | class Point 6 | 7 | include Mongoid::Document 8 | 9 | field :latlng, :type => Array 10 | field :name 11 | field :town_type 12 | field :state 13 | field :geoid 14 | field :ansicode 15 | field :aland, :type => Integer 16 | field :awater, :type => Integer 17 | 18 | index [[:latlng, Mongo::GEO2D]] 19 | end 20 | 21 | end -------------------------------------------------------------------------------- /spec/us_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'to_town/converter/us' 3 | require 'to_town/data_migration' 4 | 5 | describe "Us" do 6 | 7 | it "should create a migration record" do 8 | ToTown::DataMigration.all.length.should == 0 9 | ToTown::Converter::Us.run(dry = 1) 10 | ToTown::DataMigration.all.length.should == 1 11 | ToTown::DataMigration.first.filename.should == "Gaz_places_national.txt" 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /spec/to_town_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'to_town' 3 | require 'to_town/point' 4 | 5 | describe "ToTown" do 6 | 7 | it "should have a check class method" do 8 | ToTown.should respond_to :check 9 | end 10 | 11 | it "should return a list of points" do 12 | ToTown::Point.create(:name => "name1", :latlng => [50,51] ) 13 | points = ToTown.check(50,50) 14 | points.length.should == 1 15 | points.first.name.should == "name1" 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | # Add dependencies required to use your gem here. 3 | # Example: 4 | # gem "activesupport", ">= 2.3.5" 5 | 6 | # Add dependencies to develop your gem here. 7 | # Include everything needed to run rake, tests, features, etc. 8 | 9 | gem "bundler" 10 | gem 'mongoid', "~> 2.0.0" 11 | gem 'thor' 12 | gem 'bson_ext' 13 | 14 | group :development do 15 | gem "jeweler", "~> 1.6.2" 16 | gem 'ruby-debug19' 17 | gem "awesome_print" 18 | gem 'fabrication' 19 | end 20 | 21 | group :test do 22 | gem 'rspec' 23 | gem 'simplecov', :require => false 24 | gem 'autotest' 25 | end 26 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 2 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 3 | 4 | RACK_ENV = 'test' 5 | 6 | require "bundler" 7 | Bundler.require(:default, :test) 8 | 9 | require 'simplecov' 10 | require 'to_town/db_connection' 11 | 12 | # Requires supporting files with custom matchers and macros, etc, 13 | # in ./support/ and its subdirectories. 14 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} 15 | 16 | SimpleCov.start 17 | 18 | RSpec.configure do |config| 19 | # config.mock_with :rspec 20 | config.before :each do 21 | Mongoid.master.collections.select {|c| c.name !~ /system/ }.each(&:drop) 22 | end 23 | end -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | mongoid.yml 2 | 3 | # rcov generated 4 | coverage 5 | 6 | # rdoc generated 7 | rdoc 8 | 9 | # yard generated 10 | doc 11 | .yardoc 12 | 13 | # bundler 14 | .bundle 15 | 16 | # jeweler generated 17 | pkg 18 | 19 | # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: 20 | # 21 | # * Create a file at ~/.gitignore 22 | # * Include files you want ignored 23 | # * Run: git config --global core.excludesfile ~/.gitignore 24 | # 25 | # After doing this, these files will be ignored in all your git projects, 26 | # saving you from having to 'pollute' every project you touch with them 27 | # 28 | # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line) 29 | # 30 | # For MacOS: 31 | # 32 | #.DS_Store 33 | 34 | # For TextMate 35 | #*.tmproj 36 | #tmtags 37 | 38 | # For emacs: 39 | #*~ 40 | #\#* 41 | #.\#* 42 | 43 | # For vim: 44 | #*.swp 45 | 46 | # For redcar: 47 | #.redcar 48 | 49 | # For rubinius: 50 | #*.rbc 51 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 zhengjia 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /lib/to_town/cli.rb: -------------------------------------------------------------------------------- 1 | # TODO require all converters and generators 2 | 3 | require 'thor' 4 | require 'to_town' 5 | require 'to_town/converter/us' 6 | require 'to_town/generators/mongodb' 7 | 8 | module ToTown 9 | class CLI < Thor 10 | 11 | desc "populate", "populate data to mongodb" 12 | def populate 13 | ToTown::Converter::Us.run 14 | end 15 | 16 | desc "check", "acceps two required arguments --lat and --lng, and an optional --limit" 17 | method_option :lat, :required => true 18 | method_option :lng, :required => true 19 | method_option :limit, :type => :numeric 20 | def check 21 | points = ToTown.check(options[:lat].to_f, options[:lng].to_f, options[:limit]) 22 | points.each do |point| 23 | puts %{ #{point.name} #{point.state}\t 24 | type: #{point.town_type}\t 25 | latitude: #{point.latlng[0]}\t 26 | longitude: #{point.latlng[1]}\t 27 | land area: #{point.aland}\t 28 | water area: #{point.awater} 29 | } 30 | end 31 | end 32 | 33 | desc "config", "generate database configuration file mongoid.yml" 34 | def config(db_name='mongo') 35 | case db_name 36 | when "mongo" 37 | ToTown::Generators::Mongodb.start 38 | end 39 | end 40 | 41 | end 42 | end -------------------------------------------------------------------------------- /lib/to_town/converter/us.rb: -------------------------------------------------------------------------------- 1 | require 'iconv' 2 | require 'to_town/point' 3 | require 'to_town/data_migration' 4 | require 'to_town/db_connection' 5 | 6 | module ToTown 7 | 8 | module Converter 9 | 10 | class Us 11 | FILE_NAME = "Gaz_places_national.txt" 12 | FILE_LOCATION = File.expand_path("../../../raw_data/#{FILE_NAME}" , File.dirname(__FILE__)) 13 | 14 | def self.run(dry = 0) 15 | iconv = Iconv.new('UTF-8//IGNORE', 'UTF-8') 16 | if ToTown::DataMigration.where(:filename => FILE_NAME).empty? 17 | if dry == 0 18 | File.open(FILE_LOCATION, "r") do |file| 19 | # pass the title 20 | file.gets 21 | while line = file.gets 22 | line = iconv.iconv(line) unless line.valid_encoding? 23 | data = line.chomp.split(/\t/) 24 | name_town_type = data[3].split(/ ((?=[[:lower:]])|CDP)/) 25 | ToTown::Point.create(:state => data[0], :geoid => data[1], :ansicode => data[2], :name => name_town_type[0], :town_type => (name_town_type-[name_town_type[0]]).join, :aland => data[4], :awater => data[5], :latlng => [data[8].to_f, data[9].to_f] ) 26 | end # end while 27 | end # end File.open 28 | end # end if dry == 0 29 | ToTown::DataMigration.create(:filename => FILE_NAME) 30 | end # end if 31 | end 32 | 33 | end 34 | 35 | end 36 | 37 | end -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'rubygems' 4 | require 'bundler' 5 | begin 6 | Bundler.setup(:default, :development) 7 | rescue Bundler::BundlerError => e 8 | $stderr.puts e.message 9 | $stderr.puts "Run `bundle install` to install missing gems" 10 | exit e.status_code 11 | end 12 | require 'rake' 13 | 14 | require 'jeweler' 15 | Jeweler::Tasks.new do |gem| 16 | # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options 17 | gem.name = "to_town" 18 | gem.homepage = "http://github.com/zhengjia/to_town" 19 | gem.license = "MIT" 20 | gem.summary = %Q{Find nearby towns of a geographic latitude and longitude} 21 | gem.description = %Q{Find nearby towns of a geographic latitude and longitude} 22 | gem.email = "jiazheng@live.com" 23 | gem.authors = ["zhengjia"] 24 | gem.executables = ['to_town'] 25 | end 26 | Jeweler::RubygemsDotOrgTasks.new 27 | 28 | require 'rspec/core' 29 | require 'rspec/core/rake_task' 30 | RSpec::Core::RakeTask.new(:spec) do |spec| 31 | spec.pattern = FileList['spec/**/*_spec.rb'] 32 | end 33 | 34 | RSpec::Core::RakeTask.new(:rcov) do |spec| 35 | spec.pattern = 'spec/**/*_spec.rb' 36 | spec.rcov = true 37 | end 38 | 39 | task :default => :spec 40 | 41 | require 'rake/rdoctask' 42 | Rake::RDocTask.new do |rdoc| 43 | version = File.exist?('VERSION') ? File.read('VERSION') : "" 44 | 45 | rdoc.rdoc_dir = 'rdoc' 46 | rdoc.title = "to_town #{version}" 47 | rdoc.rdoc_files.include('README*') 48 | rdoc.rdoc_files.include('lib/**/*.rb') 49 | end 50 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | ZenTest (4.5.0) 5 | activemodel (3.0.9) 6 | activesupport (= 3.0.9) 7 | builder (~> 2.1.2) 8 | i18n (~> 0.5.0) 9 | activesupport (3.0.9) 10 | archive-tar-minitar (0.5.2) 11 | autotest (4.4.6) 12 | ZenTest (>= 4.4.1) 13 | awesome_print (0.4.0) 14 | bson (1.3.1) 15 | bson_ext (1.3.1) 16 | builder (2.1.2) 17 | columnize (0.3.3) 18 | diff-lcs (1.1.2) 19 | fabrication (1.0.0) 20 | git (1.2.5) 21 | i18n (0.5.0) 22 | jeweler (1.6.2) 23 | bundler (~> 1.0) 24 | git (>= 1.2.5) 25 | rake 26 | linecache19 (0.5.12) 27 | ruby_core_source (>= 0.1.4) 28 | mongo (1.3.1) 29 | bson (>= 1.3.1) 30 | mongoid (2.0.2) 31 | activemodel (~> 3.0) 32 | mongo (~> 1.3) 33 | tzinfo (~> 0.3.22) 34 | rake (0.9.2) 35 | rspec (2.6.0) 36 | rspec-core (~> 2.6.0) 37 | rspec-expectations (~> 2.6.0) 38 | rspec-mocks (~> 2.6.0) 39 | rspec-core (2.6.4) 40 | rspec-expectations (2.6.0) 41 | diff-lcs (~> 1.1.2) 42 | rspec-mocks (2.6.0) 43 | ruby-debug-base19 (0.11.25) 44 | columnize (>= 0.3.1) 45 | linecache19 (>= 0.5.11) 46 | ruby_core_source (>= 0.1.4) 47 | ruby-debug19 (0.11.6) 48 | columnize (>= 0.3.1) 49 | linecache19 (>= 0.5.11) 50 | ruby-debug-base19 (>= 0.11.19) 51 | ruby_core_source (0.1.5) 52 | archive-tar-minitar (>= 0.5.2) 53 | simplecov (0.4.2) 54 | simplecov-html (~> 0.4.4) 55 | simplecov-html (0.4.5) 56 | thor (0.14.6) 57 | tzinfo (0.3.28) 58 | 59 | PLATFORMS 60 | ruby 61 | 62 | DEPENDENCIES 63 | autotest 64 | awesome_print 65 | bson_ext 66 | bundler 67 | fabrication 68 | jeweler (~> 1.6.2) 69 | mongoid (~> 2.0.0) 70 | rspec 71 | ruby-debug19 72 | simplecov 73 | thor 74 | -------------------------------------------------------------------------------- /to_town.gemspec: -------------------------------------------------------------------------------- 1 | # Generated by jeweler 2 | # DO NOT EDIT THIS FILE DIRECTLY 3 | # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' 4 | # -*- encoding: utf-8 -*- 5 | 6 | Gem::Specification.new do |s| 7 | s.name = %q{to_town} 8 | s.version = "0.0.4" 9 | 10 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= 11 | s.authors = ["zhengjia"] 12 | s.date = %q{2011-06-19} 13 | s.default_executable = %q{to_town} 14 | s.description = %q{Find nearby towns of a geographic latitude and longitude} 15 | s.email = %q{jiazheng@live.com} 16 | s.executables = ["to_town"] 17 | s.extra_rdoc_files = [ 18 | "LICENSE.txt", 19 | "README.rdoc" 20 | ] 21 | s.files = [ 22 | ".document", 23 | ".rspec", 24 | "Gemfile", 25 | "Gemfile.lock", 26 | "LICENSE.txt", 27 | "README.rdoc", 28 | "Rakefile", 29 | "VERSION", 30 | "bin/to_town", 31 | "lib/to_town.rb", 32 | "lib/to_town/cli.rb", 33 | "lib/to_town/converter/us.rb", 34 | "lib/to_town/data_migration.rb", 35 | "lib/to_town/db_connection.rb", 36 | "lib/to_town/generators/mongodb.rb", 37 | "lib/to_town/generators/templates/mongoid_example.yml", 38 | "lib/to_town/point.rb", 39 | "raw_data/Gaz_places_national.txt", 40 | "spec/spec_helper.rb", 41 | "spec/to_town_spec.rb", 42 | "spec/us_spec.rb", 43 | "to_town.gemspec" 44 | ] 45 | s.homepage = %q{http://github.com/zhengjia/to_town} 46 | s.licenses = ["MIT"] 47 | s.require_paths = ["lib"] 48 | s.rubygems_version = %q{1.6.2} 49 | s.summary = %q{Find nearby towns of a geographic latitude and longitude} 50 | 51 | if s.respond_to? :specification_version then 52 | s.specification_version = 3 53 | 54 | if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then 55 | s.add_runtime_dependency(%q, [">= 0"]) 56 | s.add_runtime_dependency(%q, ["~> 2.0.0"]) 57 | s.add_runtime_dependency(%q, [">= 0"]) 58 | s.add_runtime_dependency(%q, [">= 0"]) 59 | s.add_development_dependency(%q, ["~> 1.6.2"]) 60 | s.add_development_dependency(%q, [">= 0"]) 61 | s.add_development_dependency(%q, [">= 0"]) 62 | s.add_development_dependency(%q, [">= 0"]) 63 | else 64 | s.add_dependency(%q, [">= 0"]) 65 | s.add_dependency(%q, ["~> 2.0.0"]) 66 | s.add_dependency(%q, [">= 0"]) 67 | s.add_dependency(%q, [">= 0"]) 68 | s.add_dependency(%q, ["~> 1.6.2"]) 69 | s.add_dependency(%q, [">= 0"]) 70 | s.add_dependency(%q, [">= 0"]) 71 | s.add_dependency(%q, [">= 0"]) 72 | end 73 | else 74 | s.add_dependency(%q, [">= 0"]) 75 | s.add_dependency(%q, ["~> 2.0.0"]) 76 | s.add_dependency(%q, [">= 0"]) 77 | s.add_dependency(%q, [">= 0"]) 78 | s.add_dependency(%q, ["~> 1.6.2"]) 79 | s.add_dependency(%q, [">= 0"]) 80 | s.add_dependency(%q, [">= 0"]) 81 | s.add_dependency(%q, [">= 0"]) 82 | end 83 | end 84 | 85 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = to_town 2 | 3 | Find nearby towns of a geographic latitude and longitude. Currently it only has US locations. 4 | Other data sources can be added if available. 5 | 6 | == Usage 7 | 8 | * Install the gem: gem install to_town 9 | * add to_town to your Gemfile 10 | * add require 'to_town' to your code 11 | * You can get a list of nearby points by calling ToTown.check(some_latitude_value, some_longitude_value, results_limit) 12 | 13 | Command line: 14 | * run `to_town config` to generate a mongoid.yml in the current directory 15 | * run `to_town populate` to load the data to mongodb 16 | * run `to_town --lat=some_latitude_value --lng=some_longitude_value` to check the result 17 | 18 | Example: 19 | 20 | to_town check --lat=45.018625 --lng=-93.239039 --limit=10 21 | 22 | St. Anthony MN 23 | type: city 24 | latitude: 45.027324 25 | longitude: -93.215533 26 | land area: 5831140 27 | water area: 305693 28 | 29 | Columbia Heights MN 30 | type: city 31 | latitude: 45.049104 32 | longitude: -93.246749 33 | land area: 8832769 34 | water area: 284420 35 | 36 | Hilltop MN 37 | type: city 38 | latitude: 45.053564 39 | longitude: -93.250129 40 | land area: 310173 41 | water area: 0 42 | 43 | Lauderdale MN 44 | type: city 45 | latitude: 44.994407 46 | longitude: -93.203134 47 | land area: 1086715 48 | water area: 2752 49 | 50 | New Brighton MN 51 | type: city 52 | latitude: 45.064894 53 | longitude: -93.209271 54 | land area: 16731107 55 | water area: 1545061 56 | 57 | Minneapolis MN 58 | type: city 59 | latitude: 44.963324 60 | longitude: -93.268284 61 | land area: 139789184 62 | water area: 9052448 63 | 64 | Fridley MN 65 | type: city 66 | latitude: 45.084246 67 | longitude: -93.26005 68 | land area: 26329217 69 | water area: 1873882 70 | 71 | Falcon Heights MN 72 | type: city 73 | latitude: 44.988048 74 | longitude: -93.174718 75 | land area: 5785375 76 | water area: 16906 77 | 78 | Roseville MN 79 | type: city 80 | latitude: 45.015422 81 | longitude: -93.155011 82 | land area: 33679465 83 | water area: 2168129 84 | 85 | Arden Hills MN 86 | type: city 87 | latitude: 45.071161 88 | longitude: -93.165504 89 | land area: 22253249 90 | water area: 2743210 91 | 92 | == Data source 93 | 94 | * US 2010 Census http://www.census.gov/geo/www/gazetteer/files/Gaz_places_national.txt. 95 | 96 | == Contributing to to_town 97 | 98 | * Fork the project 99 | * Start a feature/bugfix branch 100 | * Send pull request 101 | 102 | == Copyright 103 | 104 | Copyright (c) 2011 zhengjia. See LICENSE.txt for 105 | further details. 106 | 107 | --------------------------------------------------------------------------------