├── .gitignore ├── Gemfile ├── config.ru ├── views ├── team.haml ├── home.haml ├── layout.haml ├── stylesheets │ └── screen.sass └── _time_zones.haml ├── Gemfile.lock ├── Readme.md ├── public └── script.js └── coffeetime.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .rvmrc 3 | .sass-cache 4 | config.yml 5 | deploy.yml 6 | db.sqlite3 7 | tmp -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'haml' 4 | gem 'sass' 5 | gem 'sinatra' 6 | gem 'twitter' -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | 4 | Bundler.require 5 | 6 | require './coffeetime' 7 | 8 | run CoffeeTime 9 | -------------------------------------------------------------------------------- /views/team.haml: -------------------------------------------------------------------------------- 1 | - if @team.coffee_time_now? 2 | #yes yes 3 | 4 | #instructions= random_quip 5 | 6 | - else 7 | #yes not currently 8 | 9 | #instructions Direct message @isitcoffeetime to set -------------------------------------------------------------------------------- /views/home.haml: -------------------------------------------------------------------------------- 1 | #yes yes 2 | 3 | #byline 4 | = surround '(', ')' do 5 | Always, but you can 6 | / %a{:href => '#custom'} customise 7 | %a{:href => 'https://github.com/hughevans/isitcoffeetime.com'} customise 8 | 9 | / #custom{:style => 'display: none;'} 10 | / %form{:action => '/teams', :method => 'post'} 11 | / .form_line 12 | / %label{:for => 'name'} isitcoffeetime.com/ 13 | / %input{:id => 'name', :name => 'team[name]', :type => 'text'} 14 | / .form_line 15 | / %label{:for => 'twitter_account'} twitter user 16 | / %input{:id => 'twitter_account', :name => 'team[twitter_account]', :type => 'text'} 17 | / .form_line 18 | / %label{:for => 'time_zone'} time zone 19 | / %select{:id => 'time_zone', :name => 'team[time_zone]'} 20 | / = haml(:_time_zones, :layout => false) 21 | / %div#submit 22 | / %button{:type => 'submit'} Submit -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | activesupport (3.1.3) 5 | multi_json (~> 1.0) 6 | addressable (2.2.6) 7 | faraday (0.7.5) 8 | addressable (~> 2.2.6) 9 | multipart-post (~> 1.1.3) 10 | rack (>= 1.1.0, < 2) 11 | haml (3.1.3) 12 | multi_json (1.0.3) 13 | multipart-post (1.1.4) 14 | rack (1.3.5) 15 | rack-protection (1.1.4) 16 | rack 17 | sass (3.1.10) 18 | simple_oauth (0.1.5) 19 | sinatra (1.3.1) 20 | rack (~> 1.3, >= 1.3.4) 21 | rack-protection (~> 1.1, >= 1.1.2) 22 | tilt (~> 1.3, >= 1.3.3) 23 | tilt (1.3.3) 24 | twitter (2.0.0) 25 | activesupport (~> 3.0) 26 | faraday (~> 0.7) 27 | multi_json (~> 1.0) 28 | simple_oauth (~> 0.1) 29 | twitter-text (~> 1.4) 30 | twitter-text (1.4.13) 31 | activesupport 32 | 33 | PLATFORMS 34 | ruby 35 | 36 | DEPENDENCIES 37 | haml 38 | sass 39 | sinatra 40 | twitter 41 | -------------------------------------------------------------------------------- /views/layout.haml: -------------------------------------------------------------------------------- 1 | !!! Strict 2 | %html{:xmlns =>'http://www.w3.org/1999/xhtml', 'xml:lang' => 'en', :lang => 'en'} 3 | 4 | %head 5 | %meta{'http-equiv' => 'Content-Type', :content => 'text/html; charset=utf-8'} 6 | %title Is it coffee time? 7 | %link{:href => '/screen.css', :media => 'screen', :rel => 'stylesheet', :type => 'text/css'} 8 | %script{:src => 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js', :type => 'text/javascript'} 9 | %script{:src => 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js', :type => 'text/javascript'} 10 | / %script{:src => '/script.js', :type => 'text/javascript'} 11 | 12 | %body 13 | = yield 14 | 15 | / :javascript 16 | / var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); 17 | / document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); 18 | / 19 | / :javascript 20 | / try { 21 | / var pageTracker = _gat._getTracker("UA-8998734-1"); 22 | / pageTracker._trackPageview(); 23 | / } catch(err) {}; -------------------------------------------------------------------------------- /views/stylesheets/screen.sass: -------------------------------------------------------------------------------- 1 | body 2 | :background-color #fff 3 | :color #000 4 | :margin 0 5 | :padding 0 6 | :text-align center 7 | :font 8 | :family "Helvetica Neue", Helvetica, "Swis721 BT", Arial, "sans-serif" 9 | :size 14px 10 | :text-shadow 0 1px -1px rgba(0,0,0,.1) 11 | 12 | a 13 | :color #0000DE 14 | 15 | #yes 16 | :text-align center 17 | :margin-top 160px 18 | :font 19 | :weight bold 20 | :size 160px 21 | 22 | #byline 23 | :text-align center 24 | :margin-top 10px 25 | :font-size 14px 26 | 27 | #instructions 28 | :font 29 | :size 40px 30 | :family Georgia, serif 31 | :style italic 32 | :color #909090 33 | :margin-top 40px 34 | 35 | #custom 36 | :background #efefef 37 | :font-size 24px 38 | :margin 20px auto 39 | :padding 10px 40 | :width 425px 41 | :-webkit-border-radius 10px 42 | input, select 43 | :border 1px #999 solid 44 | :font-family "Helvetica Neue", Helvetica, "Swis721 BT", Arial, "sans-serif" 45 | :font-size 24px 46 | :margin-left 5px 47 | :width 190px 48 | :padding 2px 5px 49 | :-webkit-border-radius 5px 50 | select 51 | :width 202px 52 | :padding 2px 53 | button 54 | :background #ccc 55 | :border 0 56 | :color #000 57 | :font-family "Helvetica Neue", Helvetica, "Swis721 BT", Arial, "sans-serif" 58 | :font-size 24px 59 | :padding 3px 5px 60 | :-webkit-border-radius 5px 61 | .form_line 62 | :text-align right 63 | :margin-bottom 15px -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # isitcoffeetime.com 2 | 3 | One of those lame sites that just says "yes" in big letters all the time. But wait, there's more! This allows you to customise and create your own isitcoffeetime.com/_you_ page that can be set to "yes" by Twitter direct messaging _@isitcoffeetime_ with "now" or "11am" etc. It's just a goofball thing that you can throw into campfire etc. to get you and your team out for some caffination. 4 | 5 | Hacked out by the attendees of [Canberra Ruby Crew](http://canberraruby.com/) many moons ago. 6 | 7 | ## Contributors 8 | 9 | * [Hugh Evans](http://github.com/hughevans) 10 | * [Max Wheeler](http://github.com/makenosound) 11 | * [Tim Riley](http://github.com/timriley) 12 | * [Shoaib Burq](http://github.com/sabman) 13 | 14 | ## Licence 15 | 16 | Copyright (c) 2010 Hugh Evans 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /public/script.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $('#byline a').click(function() { 3 | $('#yes').animate({marginTop:'-40px'}); 4 | $('#byline').hide(); 5 | $('#custom').slideDown('normal', function() { 6 | $('input#name').focus(); 7 | }); 8 | return false; 9 | }); 10 | 11 | // TODO: add some kind of delay here (every 1s while there are still keypress events, for example) 12 | $('input#name, input#twitter_account, select#time_zone').keyup(function(press) { 13 | // Don't check when tabbing into field or pressing shift 14 | if ((press.keyCode != 9) && (press.keyCode != 16)) { 15 | validateAttribute(this); 16 | } 17 | }); 18 | 19 | $('input#name, input#twitter_account, select#time_zone').blur(function () { 20 | validateAttribute(this); 21 | }); 22 | 23 | $('select#time_zone').change(function () { 24 | validateAttribute(this); 25 | }); 26 | 27 | $('#custom form').submit(function() { 28 | $.ajax({ 29 | type: 'POST', 30 | url: this.action, 31 | dataType: 'json', 32 | data: $(this).serialize(), 33 | success: function(rsp) { 34 | if(rsp.success) { 35 | location.href = '/' + rsp.team.name; 36 | } 37 | else { 38 | $('#custom #submit').effect('shake', { times:3, distance:8 }, 100); 39 | } 40 | } 41 | }); 42 | return false; 43 | }); 44 | 45 | function validateAttribute(e) { 46 | var element = $(e); 47 | $.ajax({ 48 | type: 'POST', 49 | url: '/teams?validate=' + element.attr('id'), 50 | dataType: 'json', 51 | data: element.serialize(), 52 | success: function(rsp) { 53 | if(rsp.no_errors) { 54 | element.css({'border-color' : '#999', 'color' : '#000'}); 55 | } 56 | else { 57 | element.css({'border-color' : 'red'}); 58 | if(element.attr('tagName') != 'SELECT') { 59 | element.css({'color' : 'red'}); 60 | } 61 | } 62 | } 63 | }); 64 | }; 65 | }); 66 | -------------------------------------------------------------------------------- /coffeetime.rb: -------------------------------------------------------------------------------- 1 | require 'sinatra/base' 2 | 3 | # require "yaml" 4 | # require "active_model" 5 | # require "mongoid" 6 | # require "tzinfo" 7 | # require "json" 8 | # require "haml" 9 | # # require "httparty" 10 | # gem "twitter" 11 | # require "twitter" 12 | # require "twitter/httpauth" 13 | # require "chronic" 14 | 15 | # configure do 16 | # Mongoid::Config.instance.from_hash(YAML.load(File.read("config/database.yml"))) 17 | # CONFIG = YAML.load(File.read("config/config.yml")) 18 | # end 19 | 20 | # module TwitterSession 21 | # def twitter_session 22 | # @twitter_session ||= Twitter::Base.new(twitter_auth) 23 | # end 24 | # 25 | # def twitter_auth 26 | # @twitter_auth ||= Twitter::HTTPAuth.new( 27 | # CONFIG["twitter"]["username"], 28 | # CONFIG["twitter"]["password"] 29 | # ) 30 | # end 31 | # end 32 | 33 | # class Team 34 | # include Mongoid::Document 35 | # 36 | # field :name 37 | # field :time_zone 38 | # field :twitter_account 39 | # 40 | # validates_presence_of :name, :time_zone, :twitter_account 41 | # 42 | # validates_format_of :name, 43 | # :with => /^[A-Za-z0-9]+[A-Za-z0-9\-_]*$/, 44 | # :message => "Can only include a-z, dashes and unerscores" 45 | # 46 | # validates_uniqueness_of :name, :message => "Not available" 47 | # 48 | # def validate 49 | # if errors.empty? && Twitter.user(self.twitter_account).error? 50 | # errors[:twitter_account] << "Does not exist" 51 | # end 52 | # end 53 | # 54 | # def messages 55 | # # @messages ||= DirectMessage.messages_for(self.twitter_account) 56 | # DirectMessage.messages_for(self.twitter_account) 57 | # end 58 | # 59 | # def coffee_times 60 | # messages.map { |msg| 61 | # time = Chronic.parse(msg.text) 62 | # time..(time + 20*60) if time 63 | # }.compact 64 | # end 65 | # 66 | # def coffee_time_now? 67 | # coffee_times.any? {|d| d.include?(Time.now)} 68 | # end 69 | # 70 | # include TwitterSession 71 | # 72 | # def after_save 73 | # begin 74 | # twitter_session.friendship_create(self.twitter_account) 75 | # rescue Twitter::General 76 | # # bah, already following - pre-check? 77 | # end 78 | # end 79 | # end 80 | 81 | # class DirectMessage 82 | # attr_accessor :username, :created_at, :text 83 | # 84 | # def initialize(attributes = {}) 85 | # @username = attributes[:username] 86 | # @created_at = attributes[:created_at] 87 | # @text = attributes[:text] 88 | # end 89 | # 90 | # self.extend(TwitterSession) 91 | # 92 | # def self.get_messages 93 | # twitter_session.direct_messages.map do |msg| 94 | # self.new( 95 | # :username => msg.sender_screen_name, 96 | # :created_at => Time.parse(msg.created_at), 97 | # :text => msg.text 98 | # ) 99 | # end 100 | # end 101 | # 102 | # def self.messages_for(user, since=24*60) 103 | # get_messages.select do |msg| 104 | # msg.username == user && msg.created_at > (Time.now.utc - (since*60)) 105 | # end 106 | # end 107 | # end 108 | 109 | helpers do 110 | include Rack::Utils; alias_method :h, :escape_html 111 | 112 | def random_quip 113 | quips = [ 114 | "it sure is...", 115 | "and don’t you know it...", 116 | "finally!", 117 | "go get it!", 118 | "why not try a ristretto?", 119 | "emphatically", 120 | "so hit up decafsucks.com" 121 | ] 122 | quips[rand(quips.size)] 123 | end 124 | end 125 | 126 | class CoffeeTime < Sinatra::Base 127 | get '/' do 128 | haml :home 129 | end 130 | 131 | get "/:style.css" do 132 | content_type "text/css", :charset => "utf-8" 133 | sass :"stylesheets/#{params[:style]}" 134 | end 135 | 136 | # post "/teams" do 137 | # content_type :json 138 | # team = Team.new(params[:team]) 139 | # if attribute = params[:validate] 140 | # status 200 141 | # team.valid? 142 | # if team.errors[attribute.to_sym].empty? 143 | # {:no_errors => true}.to_json 144 | # else 145 | # {:no_errors => false, :errors => team.errors[attribute.to_sym]}.to_json 146 | # end 147 | # else 148 | # begin 149 | # team.save 150 | # status 201 151 | # {:success => true, :team => {:name => team.name}}.to_json 152 | # rescue # TODO: mongoid exception failed save 153 | # status 200 154 | # {:success => false, :errors => team.errors}.to_json 155 | # end 156 | # end 157 | # end 158 | 159 | # get "/:team_name" do 160 | # @team = Team.find(:first, :conditions => {:name => params[:team_name]}) 161 | # # raise(Sinatra::NotFound) 162 | # haml :team 163 | # end 164 | end 165 | -------------------------------------------------------------------------------- /views/_time_zones.haml: -------------------------------------------------------------------------------- 1 | %option{:value => ''} 2 | %option{:value => 'International Date Line West'} International Date Line West 3 | %option{:value => 'Midway Island'} Midway Island 4 | %option{:value => 'Samoa'} Samoa 5 | %option{:value => 'Hawaii'} Hawaii 6 | %option{:value => 'Alaska'} Alaska 7 | %option{:value => 'Pacific Time (US & Canada)'} Pacific Time (US & Canada) 8 | %option{:value => 'Tijuana'} Tijuana 9 | %option{:value => 'Arizona'} Arizona 10 | %option{:value => 'Chihuahua'} Chihuahua 11 | %option{:value => 'Mazatlan'} Mazatlan 12 | %option{:value => 'Mountain Time (US & Canada)'} Mountain Time (US & Canada) 13 | %option{:value => 'Central America'} Central America 14 | %option{:value => 'Central Time (US & Canada)'} Central Time (US & Canada) 15 | %option{:value => 'Guadalajara'} Guadalajara 16 | %option{:value => 'Mexico City'} Mexico City 17 | %option{:value => 'Monterrey'} Monterrey 18 | %option{:value => 'Saskatchewan'} Saskatchewan 19 | %option{:value => 'Bogota'} Bogota 20 | %option{:value => 'Eastern Time (US & Canada)'} Eastern Time (US & Canada) 21 | %option{:value => 'Indiana (East)'} Indiana (East) 22 | %option{:value => 'Lima'} Lima 23 | %option{:value => 'Quito'} Quito 24 | %option{:value => 'Caracas'} Caracas 25 | %option{:value => 'Atlantic Time (Canada)'} Atlantic Time (Canada) 26 | %option{:value => 'La Paz'} La Paz 27 | %option{:value => 'Santiago'} Santiago 28 | %option{:value => 'Newfoundland'} Newfoundland 29 | %option{:value => 'Brasilia'} Brasilia 30 | %option{:value => 'Buenos Aires'} Buenos Aires 31 | %option{:value => 'Georgetown'} Georgetown 32 | %option{:value => 'Greenland'} Greenland 33 | %option{:value => 'Mid-Atlantic'} Mid-Atlantic 34 | %option{:value => 'Azores'} Azores 35 | %option{:value => 'Cape Verde Is.'} Cape Verde Is. 36 | %option{:value => 'Casablanca'} Casablanca 37 | %option{:value => 'Dublin'} Dublin 38 | %option{:value => 'Edinburgh'} Edinburgh 39 | %option{:value => 'Lisbon'} Lisbon 40 | %option{:value => 'London'} London 41 | %option{:value => 'Monrovia'} Monrovia 42 | %option{:value => 'UTC'} UTC 43 | %option{:value => 'Amsterdam'} Amsterdam 44 | %option{:value => 'Belgrade'} Belgrade 45 | %option{:value => 'Berlin'} Berlin 46 | %option{:value => 'Bern'} Bern 47 | %option{:value => 'Bratislava'} Bratislava 48 | %option{:value => 'Brussels'} Brussels 49 | %option{:value => 'Budapest'} Budapest 50 | %option{:value => 'Copenhagen'} Copenhagen 51 | %option{:value => 'Ljubljana'} Ljubljana 52 | %option{:value => 'Madrid'} Madrid 53 | %option{:value => 'Paris'} Paris 54 | %option{:value => 'Prague'} Prague 55 | %option{:value => 'Rome'} Rome 56 | %option{:value => 'Sarajevo'} Sarajevo 57 | %option{:value => 'Skopje'} Skopje 58 | %option{:value => 'Stockholm'} Stockholm 59 | %option{:value => 'Vienna'} Vienna 60 | %option{:value => 'Warsaw'} Warsaw 61 | %option{:value => 'West Central Africa'} West Central Africa 62 | %option{:value => 'Zagreb'} Zagreb 63 | %option{:value => 'Athens'} Athens 64 | %option{:value => 'Bucharest'} Bucharest 65 | %option{:value => 'Cairo'} Cairo 66 | %option{:value => 'Harare'} Harare 67 | %option{:value => 'Helsinki'} Helsinki 68 | %option{:value => 'Istanbul'} Istanbul 69 | %option{:value => 'Jerusalem'} Jerusalem 70 | %option{:value => 'Kyev'} Kyev 71 | %option{:value => 'Minsk'} Minsk 72 | %option{:value => 'Pretoria'} Pretoria 73 | %option{:value => 'Riga'} Riga 74 | %option{:value => 'Sofia'} Sofia 75 | %option{:value => 'Tallinn'} Tallinn 76 | %option{:value => 'Vilnius'} Vilnius 77 | %option{:value => 'Baghdad'} Baghdad 78 | %option{:value => 'Kuwait'} Kuwait 79 | %option{:value => 'Moscow'} Moscow 80 | %option{:value => 'Nairobi'} Nairobi 81 | %option{:value => 'Riyadh'} Riyadh 82 | %option{:value => 'St. Petersburg'} St. Petersburg 83 | %option{:value => 'Volgograd'} Volgograd 84 | %option{:value => 'Tehran'} Tehran 85 | %option{:value => 'Abu Dhabi'} Abu Dhabi 86 | %option{:value => 'Baku'} Baku 87 | %option{:value => 'Muscat'} Muscat 88 | %option{:value => 'Tbilisi'} Tbilisi 89 | %option{:value => 'Yerevan'} Yerevan 90 | %option{:value => 'Kabul'} Kabul 91 | %option{:value => 'Ekaterinburg'} Ekaterinburg 92 | %option{:value => 'Islamabad'} Islamabad 93 | %option{:value => 'Karachi'} Karachi 94 | %option{:value => 'Tashkent'} Tashkent 95 | %option{:value => 'Chennai'} Chennai 96 | %option{:value => 'Kolkata'} Kolkata 97 | %option{:value => 'Mumbai'} Mumbai 98 | %option{:value => 'New Delhi'} New Delhi 99 | %option{:value => 'Sri Jayawardenepura'} Sri Jayawardenepura 100 | %option{:value => 'Kathmandu'} Kathmandu 101 | %option{:value => 'Almaty'} Almaty 102 | %option{:value => 'Astana'} Astana 103 | %option{:value => 'Dhaka'} Dhaka 104 | %option{:value => 'Novosibirsk'} Novosibirsk 105 | %option{:value => 'Rangoon'} Rangoon 106 | %option{:value => 'Bangkok'} Bangkok 107 | %option{:value => 'Hanoi'} Hanoi 108 | %option{:value => 'Jakarta'} Jakarta 109 | %option{:value => 'Krasnoyarsk'} Krasnoyarsk 110 | %option{:value => 'Beijing'} Beijing 111 | %option{:value => 'Chongqing'} Chongqing 112 | %option{:value => 'Hong Kong'} Hong Kong 113 | %option{:value => 'Irkutsk'} Irkutsk 114 | %option{:value => 'Kuala Lumpur'} Kuala Lumpur 115 | %option{:value => 'Perth'} Perth 116 | %option{:value => 'Singapore'} Singapore 117 | %option{:value => 'Taipei'} Taipei 118 | %option{:value => 'Ulaan Bataar'} Ulaan Bataar 119 | %option{:value => 'Urumqi'} Urumqi 120 | %option{:value => 'Osaka'} Osaka 121 | %option{:value => 'Sapporo'} Sapporo 122 | %option{:value => 'Seoul'} Seoul 123 | %option{:value => 'Tokyo'} Tokyo 124 | %option{:value => 'Yakutsk'} Yakutsk 125 | %option{:value => 'Adelaide'} Adelaide 126 | %option{:value => 'Darwin'} Darwin 127 | %option{:value => 'Brisbane'} Brisbane 128 | %option{:value => 'Canberra'} Canberra 129 | %option{:value => 'Guam'} Guam 130 | %option{:value => 'Hobart'} Hobart 131 | %option{:value => 'Melbourne'} Melbourne 132 | %option{:value => 'Port Moresby'} Port Moresby 133 | %option{:value => 'Sydney'} Sydney 134 | %option{:value => 'Vladivostok'} Vladivostok 135 | %option{:value => 'Magadan'} Magadan 136 | %option{:value => 'New Caledonia'} New Caledonia 137 | %option{:value => 'Solomon Is.'} Solomon Is. 138 | %option{:value => 'Auckland'} Auckland 139 | %option{:value => 'Fiji'} Fiji 140 | %option{:value => 'Kamchatka'} Kamchatka 141 | %option{:value => 'Marshall Is.'} Marshall Is. 142 | %option{:value => 'Wellington'} Wellington 143 | %option{:value => "Nuku'alofa"} Nuku'alofa --------------------------------------------------------------------------------