├── README.md ├── chapter-2-gists ├── Gemfile ├── Gemfile.lock ├── README.md ├── gist.help ├── hi.rb └── index.erb ├── chapter-3-wikis-and-gollum ├── Gemfile ├── Gemfile.lock ├── README.md ├── image.rb └── index.html ├── chapter-4-python-and-search ├── .gitignore ├── agithub.py └── test.py ├── chapter-5-dotnet-and-the-commit-status-api ├── .gitattributes ├── .gitignore ├── NancyApplication1.Tests │ ├── NancyApplication1.Tests.csproj │ ├── Test.cs │ └── packages.config ├── NancyApplication1.sln ├── NancyApplication1.userprefs └── NancyApplication1 │ ├── Bootstrapper.cs │ ├── Handler.cs │ ├── NancyApplication1.csproj │ ├── Properties │ └── AssemblyInfo.cs │ ├── Web.Debug.config │ ├── Web.Release.config │ ├── Web.config │ └── packages.config ├── chapter-6-ruby-and-jekyll ├── .gitignore ├── Gemfile ├── README.md ├── _config.yml ├── _layouts │ ├── default.html │ └── post.html ├── _posts │ ├── 2000-05-23-third-day-in-salvador.md │ ├── 2000-08-28-the-hill-tribes-of-northern-thailand.md │ ├── 2000-12-21-passion-play-of-oberammergau.md │ ├── 2001-01-12-angrezis-in-bharat.md │ ├── 2001-01-12-cuba-the-good-and-bad.md │ ├── 2001-01-12-mexico-belize-guatemala.md │ ├── 2001-01-12-nemaste.md │ ├── 2001-01-12-south-africa.md │ ├── 2001-01-23-viagiatore.md │ ├── 2001-02-14-solo-tango-in-buenos-aires.md │ ├── 2001-03-11-solo-tango-in-buenos-aires.md │ ├── 2001-04-05-lava-beds-ate-our-shoes-maui-hi.md │ ├── 2001-08-19-mystic-connecticut.md │ ├── 2001-08-20-travel-tips-for-the-first-time-to-cuba.md │ ├── 2001-10-10-travel-in-italy-after-september-th.md │ ├── 2001-10-17-watch-out-for-borin-the-cab-driver.md │ ├── 2001-10-18-diving-in-dubrovnik.md │ ├── 2001-10-21-mirogoj-cemetery-in-zagreb.md │ ├── 2001-11-03-smoking-in-the-hague.md │ ├── 2001-12-02-check-out-this-travel-planning-website.md │ ├── 2001-12-07-family-trip-to-rajasthan.md │ ├── 2001-12-30-bhutan-monsoons-and-miracles.md │ ├── 2002-05-07-the-bardo-museum.md │ ├── 2002-05-26-water-festival-in-bangkok.md │ ├── 2002-07-06-a-day-in-beijing.md │ ├── 2002-07-06-the-great-wall.md │ ├── 2002-10-10-a-day-in-krakow-poland.md │ ├── 2002-10-10-a-visit-to-montmartre-in-paris.md │ ├── 2002-10-10-romantic-prague.md │ ├── 2002-10-10-two-days-in-st-petersburg.md │ └── 2003-03-23-beautiful-belize.md ├── assets │ ├── css │ │ ├── bootstrap.min.css │ │ └── site.css │ └── images │ │ ├── book.gif │ │ ├── camera.gif │ │ ├── hut.gif │ │ ├── paper.gif │ │ ├── phone.gif │ │ ├── photo.gif │ │ ├── postcard.gif │ │ ├── star.gif │ │ └── tower.gif ├── index.md ├── run.rb ├── scraper.rb └── scraper_spec.rb ├── chapter-7-android-and-git-data ├── .gitignore ├── .idea │ ├── .name │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── gradle.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations.xml │ └── vcs.xml ├── README.md ├── app │ ├── .gitignore │ ├── app.iml │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ └── ghru │ │ │ └── MainActivityTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── ghru │ │ │ │ ├── GitHubHelper.java │ │ │ │ └── MainActivity.java │ │ └── res │ │ │ ├── layout │ │ │ ├── logged_in.xml │ │ │ └── main.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── ghru │ │ └── GitHubHelperTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── secrets.xml.sample └── settings.gradle ├── chapter-8-coffeescript-and-hubot ├── .editorconfig ├── .gitignore ├── HUBOT_README.md ├── Procfile ├── README.md ├── bin │ ├── hubot │ └── hubot.cmd ├── external-scripts.json ├── hubot-scripts.json ├── lib │ └── handler.coffee ├── package.json ├── scripts │ └── pr-delegator.coffee └── spec │ └── pr-delegator.spec.coffee └── chapter-9-javascript-and-git-data ├── .gitignore ├── .powder ├── README.md ├── angular-mocks.js ├── angular.js ├── base64.js ├── base64.min.js ├── bootstrap.min.css ├── cities.json ├── coffeetech-annotate.spec.js ├── coffeetech.js ├── coffeetech.spec.js ├── config.ru ├── error ├── firebase-mock.js ├── fixtures-cities.js ├── fixtures-portland.js ├── github.js ├── index.html ├── karma.config.js ├── node └── github-local-login.js ├── package.json ├── portland.json ├── spec ├── requestSpec.coffee └── spec-helper.coffee └── underscore-min.js /README.md: -------------------------------------------------------------------------------- 1 | Code samples for the book ["Building Tools with GitHub"](http://shop.oreilly.com/product/0636920043027.do) from O'Reilly. 2 | 3 | I'd really love to know how you found this repository and what you want to do with the code samples. [Will you fill out this quick five question survey](https://docs.google.com/forms/d/1sxc7Aq2GVtWQwIp9VPGsIe2J5twsuc3qap6CjeKws5c/edit?usp=forms_home&ths=true)? 4 | -------------------------------------------------------------------------------- /chapter-2-gists/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'sinatra' 4 | gem 'octokit' 5 | -------------------------------------------------------------------------------- /chapter-2-gists/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.3.8) 5 | faraday (0.9.2) 6 | multipart-post (>= 1.2, < 3) 7 | multipart-post (2.0.0) 8 | octokit (4.2.0) 9 | sawyer (~> 0.6.0, >= 0.5.3) 10 | rack (1.6.4) 11 | rack-protection (1.5.3) 12 | rack 13 | sawyer (0.6.0) 14 | addressable (~> 2.3.5) 15 | faraday (~> 0.8, < 0.10) 16 | sinatra (1.4.7) 17 | rack (~> 1.5) 18 | rack-protection (~> 1.4) 19 | tilt (>= 1.3, < 3) 20 | tilt (2.0.2) 21 | 22 | PLATFORMS 23 | ruby 24 | 25 | DEPENDENCIES 26 | octokit 27 | sinatra 28 | 29 | BUNDLED WITH 30 | 1.11.2 31 | -------------------------------------------------------------------------------- /chapter-2-gists/README.md: -------------------------------------------------------------------------------- 1 | Run these commands: 2 | 3 | ``` 4 | gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 5 | \curl -sSL https://get.rvm.io | bash -s stable 6 | . ~/.rvm/scripts/rvm 7 | rvm install 2.1.0 8 | gem install bundler 9 | bundle 10 | bundle exec ruby hi.rb 11 | ``` 12 | -------------------------------------------------------------------------------- /chapter-2-gists/gist.help: -------------------------------------------------------------------------------- 1 | $ gist --help 2 | Gist (v4.2.0) lets you upload to https://gist.github.com/ 3 | 4 | The content to be uploaded can be passed as a list of files, if none are 5 | specified STDIN will be read. The default filename for STDIN is "a.rb", and all 6 | filenames can be overridden by repeating the "-f" flag. The most useful reason 7 | to do this is to change the syntax highlighting. 8 | 9 | If you'd like your gists to be associated with your GitHub account, so that you 10 | can edit them and find them in future, first use `gist --login` to obtain an 11 | Oauth2 access token. This is stored and used by gist in the future. 12 | 13 | Private gists do not have guessable URLs and can be created with "-p", you can 14 | also set the description at the top of the gist by passing "-d". 15 | 16 | Anonymous gists are not associated with your GitHub account, they can be created 17 | with "-a" even after you have used "gist --login". 18 | 19 | If you would like to shorten the resulting gist URL, use the -s flag. This will 20 | use GitHub's URL shortener, git.io. You can also use -R to get the link to the 21 | raw gist. 22 | 23 | To copy the resulting URL to your clipboard you can use the -c option, or to 24 | just open it directly in your browser, use -o. Using the -e option will copy the 25 | embeddable URL to the clipboard. You can add `alias gist='gist -c'` to your 26 | shell's rc file to configure this behaviour by default. 27 | 28 | Instead of creating a new gist, you can update an existing one by passing its ID 29 | or URL with "-u". For this to work, you must be logged in, and have created the 30 | original gist with the same GitHub account. 31 | 32 | Usage: gist [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] [-P] [-f NAME|-t EXT]* FILE* 33 | gist --login 34 | 35 | --login Authenticate gist on this computer. 36 | -f, --filename [NAME.EXTENSION] Sets the filename and syntax type. 37 | -t, --type [EXTENSION] Sets the file extension and syntax type. 38 | -p, --private Makes your gist private. 39 | --no-private 40 | -d, --description DESCRIPTION Adds a description to your gist. 41 | -s, --shorten Shorten the gist URL using git.io. 42 | -u, --update [ URL | ID ] Update an existing gist. 43 | -a, --anonymous Create an anonymous gist. 44 | -c, --copy Copy the resulting URL to the clipboard 45 | -e, --embed Copy the embed code for the gist to the clipboard 46 | -o, --open Open the resulting URL in a browser 47 | --no-open 48 | -P, --paste Paste from the clipboard to gist 49 | -R, --raw Raw url of the new gist 50 | -h, --help Show this message. 51 | -v, --version Print the version. 52 | -------------------------------------------------------------------------------- /chapter-2-gists/hi.rb: -------------------------------------------------------------------------------- 1 | require 'sinatra' 2 | require 'octokit' 3 | 4 | set :bind, '0.0.0.0' 5 | set :views, "." 6 | 7 | helpers do 8 | def h(text) 9 | Rack::Utils.escape_html(text) 10 | end 11 | end 12 | 13 | get '/:username' do |username| 14 | gists = Octokit.gists username, :per_page => 5 15 | tuples = [] 16 | gists.each do |g| 17 | g[:files].fields.each do |f| 18 | data = g[:files][f].rels[:raw].get.data 19 | tuples << [ f, data ] 20 | end 21 | end 22 | erb :index, locals: { :tuples => tuples, username: username } 23 | end 24 | 25 | get '/' do 26 | "Try adding a GitHub username to the URL..." 27 | end 28 | 29 | get "/favicon.ico" do 30 | end 31 | -------------------------------------------------------------------------------- /chapter-2-gists/index.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

User <%= username %>'s last five gists

5 | 6 | <% tuples.each do |t| %> 7 |
8 | <%= t[0] %>: 9 | <%= h t[1] %> 10 |
11 | <% end %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /chapter-3-wikis-and-gollum/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'sinatra' 4 | gem 'gollum-lib' 5 | gem "rugged" 6 | gem "zip" 7 | -------------------------------------------------------------------------------- /chapter-3-wikis-and-gollum/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | charlock_holmes (0.7.3) 5 | diff-lcs (1.2.5) 6 | github-markup (1.3.3) 7 | gitlab-grit (2.7.3) 8 | charlock_holmes (~> 0.6) 9 | diff-lcs (~> 1.1) 10 | mime-types (~> 1.15) 11 | posix-spawn (~> 0.3) 12 | gollum-grit_adapter (1.0.0) 13 | gitlab-grit (~> 2.7, >= 2.7.1) 14 | gollum-lib (4.1.0) 15 | github-markup (~> 1.3.3) 16 | gollum-grit_adapter (~> 1.0) 17 | nokogiri (~> 1.6.4) 18 | rouge (~> 1.9) 19 | sanitize (~> 2.1.0) 20 | stringex (~> 2.5.1) 21 | mime-types (1.25.1) 22 | mini_portile2 (2.0.0) 23 | nokogiri (1.6.7.2) 24 | mini_portile2 (~> 2.0.0.rc2) 25 | posix-spawn (0.3.11) 26 | rack (1.6.4) 27 | rack-protection (1.5.3) 28 | rack 29 | rouge (1.10.1) 30 | rugged (0.23.3) 31 | sanitize (2.1.0) 32 | nokogiri (>= 1.4.4) 33 | sinatra (1.4.7) 34 | rack (~> 1.5) 35 | rack-protection (~> 1.4) 36 | tilt (>= 1.3, < 3) 37 | stringex (2.5.2) 38 | tilt (2.0.2) 39 | zip (2.0.2) 40 | 41 | PLATFORMS 42 | ruby 43 | 44 | DEPENDENCIES 45 | gollum-lib 46 | rugged 47 | sinatra 48 | zip 49 | 50 | BUNDLED WITH 51 | 1.11.2 52 | -------------------------------------------------------------------------------- /chapter-3-wikis-and-gollum/README.md: -------------------------------------------------------------------------------- 1 | Run these commands: 2 | 3 | ``` 4 | gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 5 | \curl -sSL https://get.rvm.io | bash -s stable 6 | . ~/.rvm/scripts/rvm 7 | rvm install 2.1.0 8 | gem install bundler 9 | brew install icu4c || sudo apt-get install libicu-dev 10 | brew install cmake || sudo apt-get install cmake 11 | bundle 12 | mkdir ../../sample-wiki 13 | pushd ../../sample-wiki 14 | git init . 15 | git add . 16 | popd 17 | bundle exec ruby hi.rb ../../sample-wiki 18 | ``` 19 | 20 | This represents a slight change from the printed text. The last few lines 21 | create a new repository, then we pass it as parameter to the script (since this 22 | script already resides in a repository...) 23 | -------------------------------------------------------------------------------- /chapter-3-wikis-and-gollum/image.rb: -------------------------------------------------------------------------------- 1 | require 'sinatra' 2 | require 'gollum-lib' 3 | require 'tempfile' 4 | require 'zip/zip' 5 | require 'rugged' 6 | 7 | set :bind, '0.0.0.0' 8 | 9 | def index( message=nil ) 10 | response = File.read(File.join('.', 'index.html')) 11 | response.gsub!( "\n", "

Received and unpacked #{message}

" ) if message 12 | response 13 | end 14 | 15 | wiki = Gollum::Wiki.new ARGV.shift 16 | get '/' do 17 | index() 18 | end 19 | 20 | post '/unpack' do 21 | @repo = Rugged::Repository.new('.') 22 | @index = Rugged::Index.new 23 | files = [] 24 | dir = File.join "images", @repo.head.target 25 | 26 | zip = params[:zip][:tempfile] 27 | 28 | Zip::ZipFile.open( zip ) { |zipfile| 29 | zipfile.each do |f| 30 | contents = zipfile.read( f.name ) 31 | filename = f.name.split( File::SEPARATOR ).pop 32 | if contents and filename and filename =~ /(png|jp?g|gif)$/i 33 | write_file_to_repo contents, filename, dir # Write the file 34 | files << filename 35 | end 36 | end 37 | write_review_file files, dir # write out a review file 38 | build_commit() # Build a commit from the new files 39 | } 40 | index( params[:zip][:filename] ) 41 | end 42 | 43 | def write_review_file( files, dir ) 44 | review_filename = "Review.md" 45 | contents = "## Review Images\n\n" 46 | files.each do |f| 47 | contents += "### #{f} \n[[#{dir}/#{f}]]\n\n" 48 | end 49 | contents += "[Prior revision (only when viewing history)](#{@repo.head.target})\n\n" 50 | 51 | File.write review_filename, contents 52 | oid = @repo.write( contents, :blob ) 53 | @index.add(:path => review_filename, :oid => oid, :mode => 0100644) 54 | end 55 | 56 | def get_credentials 57 | contents = File.read File.join( ENV['HOME'], ".gitconfig" ) 58 | @email = $1 if contents =~ /email = (.+)$/ 59 | @name = $1 if contents =~ /name = (.+)$/ 60 | end 61 | 62 | def build_commit 63 | get_credentials() 64 | options = {} 65 | options[:tree] = @index.write_tree(@repo) 66 | options[:author] = { :email => @email, :name => @name, :time => Time.now } 67 | options[:committer] = { :email => @email, :name => @name, :time => Time.now } 68 | options[:message] = params[:message] 69 | options[:parents] = @repo.empty? ? [] : [ @repo.head.target ].compact 70 | options[:update_ref] = 'HEAD' 71 | 72 | Rugged::Commit.create(@repo, options) 73 | 74 | end 75 | 76 | def write_file_to_repo( contents, filename, dir ) 77 | Dir.mkdir "images" unless File.exists? "images" 78 | Dir.mkdir dir unless File.exists? dir 79 | full_name = File.join dir, filename 80 | File.write full_name, contents 81 | oid = @repo.write( contents, :blob ) 82 | @index.add(:path => full_name, :oid => oid, :mode => 0100644) 83 | end 84 | 85 | -------------------------------------------------------------------------------- /chapter-3-wikis-and-gollum/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | Choose a zip file: 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter-4-python-and-search/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1.Tests/NancyApplication1.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {98D6F82A-5BB0-4E78-A557-9DA24212A44D} 7 | Library 8 | NancyApplication1.Tests 9 | NancyApplication1.Tests 10 | v4.5 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug 17 | DEBUG; 18 | prompt 19 | 4 20 | false 21 | 22 | 23 | full 24 | true 25 | bin\Release 26 | prompt 27 | 4 28 | false 29 | 30 | 31 | 32 | 33 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll 34 | 35 | 36 | ..\packages\Nancy.1.3.0\lib\net40\Nancy.dll 37 | 38 | 39 | ..\packages\CsQuery.1.3.3\lib\net40\CsQuery.dll 40 | 41 | 42 | ..\packages\Nancy.Testing.1.3.0\lib\net40\Nancy.Testing.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {887A8565-4A10-44C8-82EF-F2F2D1D2BFBF} 55 | NancyApplication1 56 | 57 | 58 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1.Tests/Test.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Nancy; 3 | using Nancy.Testing; 4 | using Nancy.Bootstrapper; 5 | using System.Collections.Generic; 6 | using Nancy.Session; 7 | 8 | using NancyApplication1; 9 | 10 | namespace NancyApplication1.Tests 11 | { 12 | 13 | public static class BootstrapperExtensions 14 | { 15 | public static void WithSession(this IPipelines pipeline, 16 | IDictionary session) 17 | { 18 | pipeline.BeforeRequest.AddItemToEndOfPipeline(ctx => 19 | { 20 | ctx.Request.Session = new Session(session); 21 | return null; 22 | }); 23 | } 24 | } 25 | 26 | [TestFixture ()] 27 | public class Test 28 | { 29 | private ConfigurableBootstrapper bootstrapper; 30 | private Browser browser; 31 | 32 | [SetUp] 33 | public void Setup(){ 34 | this.bootstrapper = new ConfigurableBootstrapper(with => { 35 | with.Module(); 36 | }); 37 | this.browser = new Browser (bootstrapper); 38 | } 39 | 40 | [Test ()] 41 | public void FetchesUserDetails () 42 | { 43 | var result = this.browser.Get ("/mojombo", 44 | with => with.HttpRequest ()); 45 | Assert.AreEqual (HttpStatusCode.OK, result.StatusCode); 46 | Assert.IsTrue (result.Body.AsString() 47 | .Contains("Tom Preston-Werner")); 48 | } 49 | 50 | [Test] 51 | public void HandlesAuthorization() 52 | { 53 | // Mismatched CSRF token 54 | bootstrapper.WithSession(new Dictionary { 55 | { "CSRF:State", "sometoken" }, 56 | }); 57 | var result = this.browser.Get ("/authorize", (with) => { 58 | with.HttpRequest(); 59 | with.Query("state", "someothertoken"); 60 | }); 61 | Assert.AreEqual (HttpStatusCode.Unauthorized, result.StatusCode); 62 | 63 | // Matching CSRF token 64 | bootstrapper.WithSession(new Dictionary { 65 | { "CSRF:State", "sometoken" }, 66 | { "OrigUrl", "http://success" }, 67 | }); 68 | result = this.browser.Get ("/authorize", (with) => { 69 | with.HttpRequest(); 70 | with.Query("state", "sometoken"); 71 | }); 72 | result.ShouldHaveRedirectedTo ("/authorize/success"); 73 | } 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NancyApplication1", "NancyApplication1\NancyApplication1.csproj", "{887A8565-4A10-44C8-82EF-F2F2D1D2BFBF}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NancyApplication1.Tests", "NancyApplication1.Tests\NancyApplication1.Tests.csproj", "{98D6F82A-5BB0-4E78-A557-9DA24212A44D}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {887A8565-4A10-44C8-82EF-F2F2D1D2BFBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {887A8565-4A10-44C8-82EF-F2F2D1D2BFBF}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {887A8565-4A10-44C8-82EF-F2F2D1D2BFBF}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {887A8565-4A10-44C8-82EF-F2F2D1D2BFBF}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {98D6F82A-5BB0-4E78-A557-9DA24212A44D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {98D6F82A-5BB0-4E78-A557-9DA24212A44D}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {98D6F82A-5BB0-4E78-A557-9DA24212A44D}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {98D6F82A-5BB0-4E78-A557-9DA24212A44D}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1.userprefs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1/Bootstrapper.cs: -------------------------------------------------------------------------------- 1 | using Nancy; 2 | using Nancy.Bootstrapper; 3 | using Nancy.Security; 4 | using Nancy.Session; 5 | using Nancy.TinyIoc; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Web; 10 | 11 | namespace NancyApplication1 12 | { 13 | public class Bootstrapper : DefaultNancyBootstrapper 14 | { 15 | protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) 16 | { 17 | CookieBasedSessions.Enable(pipelines); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1/Handler.cs: -------------------------------------------------------------------------------- 1 | using Nancy; 2 | using Octokit; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Configuration; 6 | using System.Linq; 7 | using System.Web; 8 | 9 | namespace NancyApplication1 10 | { 11 | public class Handler : NancyModule 12 | { 13 | private const string clientId = "be8f08cb9a0471772f88"; 14 | private const string clientSecret = "41f67b9c2ec542449b83039aed56b64a56bf523b"; 15 | private readonly GitHubClient client = new GitHubClient(new ProductHeaderValue("MyHello")); 16 | 17 | public Handler() 18 | { 19 | Get["/{user}", true] = async (parms, ct) => 20 | { 21 | var user = await client.User.Get(parms.user.ToString()); 22 | return String.Format("{0} people love {1}!", user.Followers, user.Name); 23 | }; 24 | 25 | // No need to write about this 26 | Get["/{user}/{repo}/{sha}", true] = async (parms, ct) => 27 | { 28 | var accessToken = Session["accessToken"] as string; 29 | if (string.IsNullOrEmpty(accessToken)) 30 | return RedirectToOAuth(); 31 | client.Credentials = new Credentials(accessToken); 32 | 33 | try 34 | { 35 | IEnumerable statuses = await client.Repository.CommitStatus.GetAll( 36 | parms.user, parms.repo, parms.sha); 37 | return string.Join("
", 38 | statuses.Select(x => string.Format("{0}: {1}", x.UpdatedAt, x.State))); 39 | } 40 | catch (NotFoundException) 41 | { 42 | return HttpStatusCode.NotFound; 43 | } 44 | }; 45 | 46 | Get["/{user}/{repo}/{sha}/{status}", true] = async (parms, ct) => 47 | { 48 | var accessToken = Session["accessToken"] as string; 49 | if (string.IsNullOrEmpty(accessToken)) 50 | return RedirectToOAuth(); 51 | client.Credentials = new Credentials(accessToken); 52 | 53 | CommitState newState = Enum.Parse(typeof(CommitState), parms.status, true); 54 | try 55 | { 56 | await client.Repository.CommitStatus.Create( 57 | parms.user, parms.repo, parms.sha, new NewCommitStatus 58 | { 59 | State = newState, 60 | TargetUrl = new Uri(Request.Url.SiteBase), 61 | Context = "arbitrary", 62 | }); 63 | } 64 | catch (NotFoundException) 65 | { 66 | return HttpStatusCode.NotFound; 67 | } 68 | return String.Format( 69 | @"Done! Go to this API endpiont " + 70 | @"or the local view", 71 | parms.user, parms.repo, parms.sha); 72 | }; 73 | 74 | Get["/authorize", true] = async (parms, ct) => 75 | { 76 | var csrf = Session["CSRF:State"] as string; 77 | Session.Delete("CSRF:State"); 78 | if (csrf != Request.Query["state"]) 79 | { 80 | return HttpStatusCode.Unauthorized; 81 | } 82 | 83 | var successUrl = ConfigurationManager.AppSettings["baseUrl"] + "/authorize/success"; 84 | var token = await client.Oauth.CreateAccessToken( 85 | new OauthTokenRequest(clientId, clientSecret, Request.Query["code"].ToString()) 86 | { 87 | RedirectUri = new Uri(successUrl) 88 | }); 89 | Session["accessToken"] = token.AccessToken; 90 | return Response.AsRedirect(successUrl); 91 | }; 92 | 93 | Get["/authorize/success"] = _ => 94 | { 95 | var origUrl = Session["OrigUrl"].ToString(); 96 | Session.Delete("OrigUrl"); 97 | return Response.AsRedirect(origUrl); 98 | }; 99 | } 100 | 101 | private Response RedirectToOAuth() 102 | { 103 | var csrf = Guid.NewGuid().ToString(); 104 | Session["CSRF:State"] = csrf; 105 | Session["OrigUrl"] = this.Request.Path; 106 | 107 | var request = new OauthLoginRequest(clientId) 108 | { 109 | Scopes = { "repo:status" }, 110 | State = csrf 111 | }; 112 | var oauthLoginUrl = client.Oauth.GetGitHubLoginUrl(request); 113 | return Response.AsRedirect(oauthLoginUrl.ToString()); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1/NancyApplication1.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {887A8565-4A10-44C8-82EF-F2F2D1D2BFBF} 8 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 9 | Library 10 | Properties 11 | NancyApplication1 12 | NancyApplication1 13 | v4.5 14 | true 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | false 30 | 31 | 32 | pdbonly 33 | true 34 | bin\ 35 | TRACE 36 | prompt 37 | 4 38 | false 39 | 40 | 41 | 42 | 43 | ..\packages\Octokit.0.11.0\lib\net45\Octokit.dll 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | ..\packages\Nancy.0.21.1\lib\net40\Nancy.dll 57 | 58 | 59 | ..\packages\Nancy.Hosting.Aspnet.0.21.1\lib\net40\Nancy.Hosting.Aspnet.dll 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Web.config 74 | 75 | 76 | Web.config 77 | 78 | 79 | 80 | 10.0 81 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | True 91 | True 92 | 0 93 | / 94 | http://localhost:7820/ 95 | False 96 | False 97 | 98 | 99 | False 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 116 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("NancyApplication1")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("NancyApplication1")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f5a1ef9b-f09f-4091-8696-dd47e042528b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /chapter-5-dotnet-and-the-commit-status-api/NancyApplication1/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | cached 3 | _site 4 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "github-pages" 4 | gem "rspec" 5 | gem "mechanize" 6 | gem "vcr" 7 | gem "webmock" 8 | gem "therubyracer" -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/README.md: -------------------------------------------------------------------------------- 1 | Run these commands: 2 | 3 | ``` 4 | gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 5 | \curl -sSL https://get.rvm.io | bash -s stable 6 | . ~/.rvm/scripts/rvm 7 | rvm install 2.1.0 8 | gem install bundler 9 | bundle 10 | bundle exec ruby run.rb 11 | ``` 12 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_config.yml: -------------------------------------------------------------------------------- 1 | name: Your New Jekyll Site 2 | markdown: redcarpet 3 | highlighter: pygments -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ByTravelers.com 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Fork me on GitHub 15 | 16 |
17 |
18 |

ByTravelers.com

19 | Alternative travel information 20 |
21 |
23 |
24 | {{ content }} 25 |
26 |
27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 |

{{ page.title }}

6 | 7 | 8 | 9 | {{ content }} 10 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2000-05-23-third-day-in-salvador.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Third day in Salvador 3 | creation_date: '2000-05-23' 4 | image: photo.gif 5 | author: Chris Dawson (cdawson) 6 | layout: post 7 | --- 8 | 9 | ### Written by: Chris Dawson (cdawson) 10 | 11 | I'm now entering the my third day in Salvador. There is, so far, much 12 | to like. The people are beautiful and they seem to know it, which 13 | makes them doubly so. The view from the beach is fantastic. The city 14 | itself, from what I've seen in two days, is full of deep history 15 | beneath the cobblestones. Before I left Portland I was having second 16 | thoughts about coming here but I know I have made the right decision 17 | now. 18 | 19 | So far I've only really come in contact with people who speak English 20 | well. Aside from my roommate who speak English not at all, that is. 21 | The first person I met was Jussara, the daughter of the woman who is 22 | renting me the room. Jussara is medium height with a short bob for 23 | hair and the typical Brasilian countenance. She is almost too 24 | friendly for me to bear sometimes. Coming from America you grow 25 | suspicious of people who are overly friendly and I've had to catch 26 | myself thinking that there must be a reason that she is so nice to me, 27 | when in fact it is most likely because that is the way she is. 28 | Tonight we were going to head out to go Salsa dancing but because 29 | there is no phone in my apartment there was no way for her to contact 30 | me and I, her, so I assume they went off without me. 31 | 32 | I also met Jandaira, the mother of Jussara. Full of smiles every time 33 | she sees me, but there is little communication between us because of 34 | the language barrier. 35 | 36 | Today I finally met the Brittos, the family that helped me find 37 | Jandaira and Jussara. Rose Britto is the aunt of Louie, a friend of 38 | mine from Portland. She is very kind. I also met her husband today. 39 | He is retired and for now I gues that means he can nap when he wants 40 | to. I also met their daughter Ryan. Ryan and I spent a good part of 41 | the afternoon together. I think Ryan likes the company of someone 42 | like me because she can speak English. She took me to lunch at a 43 | 'Comida a Quilo' joint, of course, called Big Beef. I don't like the 44 | idea of paying for the food I eat by weight since I am not paid by how 45 | heavy I am, but the food was pretty decent. 46 | 47 | After that we went to the Mercado Modelo. This apparently was the 48 | site of a slave trading business. They now sell arts and crafts from 49 | local merchants; lots of talismans and sculpture, busts, almost all in 50 | bright colors to contrast the dominant theme there which was dark 51 | black women in pure white dresses. The building where the Mercado 52 | sits in two stories with a basement. The basement is covered with 53 | water except for concrete slabs placed to act as a walkway. The water 54 | is only a few feet or so deep but is extremely murky; one child behind 55 | us grasping his father's hand tightly worried aloud that there might 56 | be 'tuberão' (sharks). There were definitely sharks on the first and 57 | second floors, kid. 58 | 59 | Afterwards we stopped outside in the back to see the Capoeira 60 | fighters. Capoeira is a different kind of martial art than I have 61 | seen before. Lots of high kicks and spins, but landing a blow was 62 | something that only the lower students did mistakenly. I like the 63 | informal nature of Capoeira; it seems like there is a rhythm you find 64 | with experience but not necessarily something you would get from a 65 | teacher. 66 | 67 | Next we followed the elevator up to Pelourinho, the haunting grounds 68 | of many of the characters from Jorge Amado's novels. All the streets 69 | were pure cobblestone and treacherous. We sat in a cafe outdoors and 70 | sipped limão and coca leite(?) from two straws. A pregnant woman gave 71 | me a cloth bracelet upon which tying around my wrist I was told to 72 | make three wishes. I wished for happiness in my love life in Bahia, 73 | happiness when I start my job and happiness to my family. 74 | 75 | As I write this my body itches. This bed has bed bugs and there are 76 | mosquitos about. I am not sure if it is better that ther are silent 77 | but not one of them made even the slightest buzz the first two nights 78 | I slept here. But if this is roughing it then I really can't 79 | complain. 80 | 81 | I never finished my introductions. The two men I live with are São 82 | Paulo, like the city I think, and Luis. Both are extremely friendly 83 | and talkative, about what I have no idea, but it is nice to hear them 84 | speak to a complete stranger like me without hesitation. I cooked up 85 | some leftovers for dinner tonight and Luis offered me his hot sauce 86 | (pimenta) and some flour type of stuff that I've seen before but don't 87 | know the name of. Then we talked for an hour or so and he gave me a 88 | pen from his company. After that he brought out his television and he 89 | tuned it to the news for me. None of what I am writing here makes any 90 | difference in the grand order of things but I am not sure that is the 91 | point. I am profoundly astonished, when I think about it and see it 92 | in cold black ink here on this paper, at the level of generosity and 93 | kindness shown to me since I have arrived in Salvador. Maybe that is 94 | why, without exception, everyone I have asked so far, loves living in 95 | here in Salvador. I plan to keep asking but I think I know the 96 | answer why. 97 | 98 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-01-12-angrezis-in-bharat.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Angrezis in Bharat 3 | creation_date: '2001-01-12' 4 | image: camera.gif 5 | author: MD 6 | layout: post 7 | --- 8 | 9 | ### Written by: MD 10 | 11 | Translation - "Foreigners in India" 12 | 13 | Well since we last wrote we were heading for India. 14 | 15 | On our way there we stopped in at Chitwan Nat. Park 16 | (Nepal Border) to experience elephant riding while 17 | looking for various species of animal including the 18 | one horned rhino and the tiger in the local jungle. We 19 | were lucky to spot the one horned rhino but no luck on 20 | the tiger front. We also had fun bathing the elephant. 21 | We joined it in the river sitting on its back and 22 | getting soaked in the process by either it spraying us 23 | with its trunk or just dunking us. A great experience. 24 | 25 | Varanasi was our next stop where we enjoyed a dawn 26 | boat ride on the Ganges veiwing the locals daily 27 | ritual of bathing, washing and even dying in the 28 | Ganges. With respect to the latter, before the bodies 29 | are cremated next to the Ganges, they are doused into 30 | the Ganges to purify their soul for afterlife. 31 | Varanasi or Benares as it is known to the locals has 32 | to be seen to be believed for the out and out 33 | polution, be it from carbon monoxide to cowshit!! Cows 34 | are allowed to roam free in Hindu countries which 35 | causes chaos at times with the traffic. I also got to 36 | play cricket with the locals in the narrow alleys of 37 | the old town but had to avoid the brown cowpatts in 38 | the process! It was quite coincidental that the NZ 39 | cricket team was playing India at the same time. 40 | 41 | We then headed to Bandhavgarh Nat Park where we struck 42 | lucky seeing the Bengal tiger in the wild on a number 43 | of occasions. It was pretty awesome to see it in the 44 | flesh so close in its natural environment. Definitely 45 | a highlight in India so far. For the record this park 46 | has the highest density of tigers for any national 47 | park in India, so the odds of getting to see a tiger 48 | are better than average. 49 | 50 | Khajuraho was where Victoria and I got to view the 51 | famous erotic sculptures embedded in the temples of 52 | the village. I will be sure to practice a few new 53 | positions for the honeymoon!! 54 | 55 | Orchha was our next stop which is famous for its 56 | palace and outerlying temples which were built in the 57 | 17 century during the Mughal period. The Mughals 58 | certainly know how to build - massive. We spoilt 59 | ourselves with a night in the palace. I'm definitely 60 | in Victoria's good books for that!! 61 | 62 | In Bharatpur we visited Keoladeo Ghana Natl Park, a 63 | famous migratory birds sanctuary built 300 years ago 64 | by a local Maharaja for his sporting pleasure of 65 | shooting waterfowl. Now, about a third of the park is 66 | flooded which makes a perfect location to see the 67 | endangered Siberian crane along with many herons, 68 | stags, and geese to name just a few, which we did 69 | while riding on bicycles. 70 | 71 | Then another major highlight, in Agra - the Taj Mahal. 72 | This has got to one of the most amazing man made 73 | wonders of the world. The whole building is built out 74 | of solid marble and took 22 years to build yet only 75 | one day to take down the scaffolding! Once again the 76 | Mughals are resonsible for the building of the 77 | mausoleum. Agra is also famous for its Red Fort which 78 | has been the most impressive we've seen thus far, 79 | although I hear the forts in Rajastan are equally 80 | impressive. 81 | 82 | Now we are in New Delhi and have caught up on chores 83 | and spoilt ourselves with a few western comforts. Not 84 | to mention do some shopping. We have also had a lot of 85 | fun riding around in the auto-rickshaws (3 wheeled 2 86 | stroke engine taxis) visiting both New Delhi (British 87 | colonial influence) and Old Delhi (just manic traffic 88 | and bazaars) 89 | 90 | Thanks to those who responded and gave us a run down 91 | of what you have been up to. 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-01-12-cuba-the-good-and-bad.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cuba - the good and bad 3 | creation_date: '2001-01-12' 4 | image: paper.gif 5 | author: MD 6 | layout: post 7 | --- 8 | 9 | ### Written by: MD 10 | 11 | April 1999 12 | 13 | Cuba, what an interesting place??!! 14 | My arrival into Havana wasn't the best, being faced with 15 | corrupt 16 | customs and police trying to set me up with a drug import 17 | charge only 18 | to ask me to bribe them out of it so they could score a few 19 | very 20 | valuable US dollars. Their plan failed thanks to me 21 | verbally abusing 22 | them loudly so the whole airport could hear me. They 23 | realised that 24 | they had a "live one" and thought the whole scam wasn't 25 | worth it and 26 | let me go! After gaining my composure in the taxi on the 27 | way to my 28 | hotel, I found out they had no rooms left and ended up 29 | sleeping in the lounge. "Welcome to Cuba" I thought. 30 | 31 | Bearing in mind all the govt and police are corrupt, you 32 | cannot be touched as a tourist. Cuba i found is very poor 33 | and lacks a decent/modern infrastructure. Despite this the 34 | people are highly educated , friendly, but very desperate 35 | for US dollars - to pay for modern imported goods. The 36 | average doctor's salary is only US 20.00 per month! police 37 | get almost double- plus additional benefits ...bribe money. 38 | Local Cubans have no freedom of speech and if caught 39 | talking or hanging out with tourists without police 40 | approval, they can be arrested on the spot - as happened 41 | with a local who drove me and some friends between Trinidad 42 | and Sancti Spiritus just to get US dollars, only to be 43 | caught and redirected to the police station to be arrested. 44 | We as tourists were let off Scott free. One girl i met in 45 | the main square during a rave (no not a hooker!) was 46 | reluctant to show me how to Salsa due to her being afraid 47 | of being arrested by the cops as a prostitute (and no she 48 | wasn't just using it as an excuse to get away from me!). 49 | 50 | Enough negativity for now, the one thing that keeps you 51 | going is the live bands playing everywhere - rumba, salsa, 52 | jazz, Afro Cuban, etc. I didn't hear one poor band. The 53 | other bonus is the cheap RUM, Rum, Rum -did I say the Rum 54 | was cheap. I must stop that! RUM, RUM, RUM, - salsa, legs, 55 | hips, breasts...stop that! Toking on cigars goes with the 56 | territory and can be used as foreplay, not as Clinton used 57 | them though..only to smoothen out the shots of Neat RUM. To 58 | top it off... Cuban Baseball -it's arguably the best in the 59 | world. These guys have got it right over herer...gorgeous 60 | women (who dance like they're always horney!), baseball 61 | every weekend, and cheap rum and cigars. Shame they haven't 62 | git enough money to house themselves properly or food for 63 | the family. That is the whole irony of the revolution. 64 | Prior, there was a corrupt govt used as a pawn for the US 65 | govt, but at least if you worked hard, you made money and 66 | if you didn't you staved! Immediately after the revolution 67 | of the 1960s, there was a period of equal prosperity and 68 | happiness. But as Castro went doen the road of socialism 69 | towards communism, along came the police state and 70 | corruption and more poverty (not helped of course by the US 71 | Trade Embargo). 72 | 73 | Only now is the Cuban govt earning hard currency by 74 | blatantly ripping off the tourist and heavily subsidising 75 | locals. To give you an example one US dollar = 20 Cuban 76 | pesos. Locals pay 2 pesos while tourists pay USD 2.00. 20 77 | times more and the quality is piss poor. It's only when you 78 | get to the beach resorts or the top hotels where you get 79 | what you pay for (although at astronomical rates) and they 80 | don't allow any local Cubans into these areas unless they 81 | work there. A type of segregation you could say. Besides 82 | they couldn't afford to stay. Racism is running rife in 83 | that black negros are considered bottom of the pile 84 | followed by the Moletos (mixed races). Top is of course 85 | those of Spanish decent. 86 | 87 | Those thinking of travelling independently are in for a 88 | tough time. The only feasible way of affording a night's 89 | accomodation on a backpackers' budget is in a "casa 90 | particular" (private room) in locals homes. These houses 91 | are registered and there is no problem with theft, because 92 | if there was the house would automatically lose there 93 | licence and the culprit would lose their hand! Rather 94 | barbaric but effective. 95 | 96 | Of the places I reccommend... 97 | **Trinidad... is a very pretty colonial town and backs intl 98 | the Play Ancon (nice white sanded Caribbean beach and 99 | excellent for scuba). 100 | **Vinales... has a beautiful backdrop of smoothfaced 101 | limestone mountains to contrast the bright orange soils and 102 | green and brown tobacco leaves 103 | **Havana....check out the old town (slowly being 104 | renovated), have a ride in one of the many 1950s chevy 105 | taxis (that's only if you like smell of petrol fumes), 106 | exclusive Mirimar (the equivalent of Beverley Hills in the 107 | 1950s with huge mansions), Hemmingway History...and of 108 | course the "Tropicana" caberet. 109 | **Santiago de Cuba...learn all about the home of Ron (RUM) 110 | from the Bacardi family museum, visit many secluded 111 | uncrowded beaches, the castillo (castle) del Morro (famous 112 | site of battles between the US and Spanish in thelate 113 | 1800s), Gran Piedro (majestic views of Santiago and 114 | surrounding areas) and the Sierra Maestro mountain range 115 | (great hiking and significant history where the revolution 116 | began with the landing of Castro and his men from Mexico. 117 | 118 | All in all, if you want to get a lot out of Cuba, you must 119 | escape the comfort of your packaged tour, 4-5 star hotels 120 | and guided tours. Plus bring plenty of US dollars - for 121 | both legal and illegal ripoffs! 122 | 123 | Let's finish this on a positove note....bring on the 124 | Cohibas, ron, basball, live music, salsa dancing, sun, 125 | beaches, historic buildings, 1950s chevies, mojitas, cuba 126 | libres, cheap prostitutes ...did I say that...whoops.. only 127 | the Italians and French partake in that kind of activity!! 128 | 129 | Cheers 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-01-12-mexico-belize-guatemala.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mexico/Belize/Guatemala 3 | creation_date: '2001-01-12' 4 | image: phone.gif 5 | author: MD 6 | layout: post 7 | --- 8 | 9 | ### Written by: MD 10 | 11 | Feb/Mar 1999 12 | 13 | Dear All 14 | Well it´s been six weeks on the road throughout Mexico and 15 | Guatemala. 16 | Wow how time flies when you are enjoying the hot temps, 17 | clear skies 18 | and warm ocean. Not to forget the interesting Mayan Ruins 19 | and local 20 | Indian cultures and colours. 21 | 22 | Cervesa (beer) tastes better in hot weather! 23 | 24 | To give a quick rundown of our itinerary: 25 | 26 | 1. Mexico City - lots of parks and musueums, cool Zona Rosa 27 | area 28 | 29 | 2. Tasco - interesting little town famous for its silver 30 | craftsmen and 31 | it´s cheap. Check out page www.armyants.com (plug for Andy) 32 | 33 | 3. Alcapulco - was a beautiful place once upon a time, but 34 | now ruined 35 | by all the high rises. Appreciated the great view of the 36 | harbour at 37 | night and the famous divers (50m high) 38 | 39 | 4. Pie de la Cuesta - this place is bliss. Sun, sand, surf, 40 | dolphins 41 | and whales swimming offshore. What more can I say! 42 | 43 | 5. Oaxaca- pretty colonial town. Interesting mayan ruin at 44 | Monte Alban. 45 | 46 | Chiapas 47 | 6. Tuxtla Guiterrez - capital of Chiapas. Sumidero Canyon 48 | was 49 | impressive (1 km high, 4km long, and tons of Crocs and 50 | birdlife). 51 | 52 | 7. San Cristobal - Pretty town in the Chiapas mountains. 53 | Lots of 54 | traditional Indian clothing in vibrant colours. The 55 | outerlying 56 | villages were interesting to visit to learn about their way 57 | of life. 58 | 59 | 8. Palenque - Mayan Ruin. Quite impressive in the jungle 60 | setting. 61 | Plenty of bird life. Visited Agua Azul (famous river for 62 | its blueness 63 | similar to glacier fed lakes) to get the only day of the 64 | trip that it 65 | poured down! Tropical jungle weather I guess. 66 | 67 | Yucatan 68 | 9. Merida - Got to see the local Carnival. Plenty of 69 | colourful 70 | costumes and dance. At the same time saw President Clinton 71 | and (soon 72 | to be Senator) Hillary Clinton there in the flesh. Also 73 | visited Uxmal 74 | (another less visited mayan ruin..worth seeing) Also 75 | managed to have 76 | my bag slashed without my knowing...but amazingly nothing 77 | was taken! 78 | 79 | 10. Chichen Itza - the most famous mayan ruin in Mexico 80 | (impressive), 81 | full of American tourists on their one/two week holiday in 82 | Cancun. Get 83 | me out of here quick.... 84 | 85 | 11. Playa del Carmen - spent a week to escape the 86 | backpacking mode and 87 | relax on the Caribbean beach again since Pie de la Cuesta. 88 | Celebrated 89 | Tori´s birthday in style (tons of Tequila sunrises, 90 | margheritas, 91 | coronas, dos aquis, etc). Visited Tulum Mayan ruin for the 92 | day...the 93 | beach was the only highlight. 94 | 95 | Belize 96 | 12. (former British Honduras) in one day....drove through 97 | it. Nice to 98 | read English again for less than 24 hours. Creole/Caribbean 99 | Culture. 100 | Would have liked more time to visit 101 | 102 | Guatemala 103 | 13. Tikal - the most impressive Mayan ruin we saw and in 104 | the sticks of 105 | El Peten jungle. Saw all sorts of animals...howler monkeys 106 | louder than 107 | my mother, spider monkeys, tukons, parrots, etc. Definitely 108 | worth the 109 | effort to get there. Caought a dodgey flight from there 110 | across the 111 | jungle to Guatemala City Airport. Heaps of people had 112 | motion sickness! 113 | 114 | 14. Antigua - another pretty colonial town with awesome 115 | Volcano Agua 116 | backdrop. plenty of Gringoes (foreigners) studying Spanish. 117 | 118 | 15. Lake Atitlan - Gorgeous lake with 3 volcanoes 119 | surrounding it. 120 | plenty of sun and relaxation in the treehouse to rechard the 121 | batteries... 122 | 123 | Mexico again 124 | 16. Villahermasa - home of the famous Tabasco Sauce. Have 125 | had plenty 126 | since staying here. Must have worked too well on Tori as 127 | she came done 128 | with an upset stomach! 129 | 130 | Anyway that´s about it for this email 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-01-12-nemaste.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Nemaste 3 | creation_date: '2001-01-12' 4 | image: phone.gif 5 | author: MD 6 | layout: post 7 | --- 8 | 9 | ### Written by: MD 10 | 11 | Oct/Nov 2000 12 | 13 | "NEPAL" 14 | 15 | We spent our first 3 days in Bangkok catching up with a 16 | friend of mine before arriving in Kathmandu. 17 | 18 | Talk about Kathmandu being a definite "gringo" hangout here 19 | in Nepal. There's everything that you could possibly think 20 | of needing, plus more for all your activities, and they are 21 | all for great prices. Kathmandu is a rather hectic place, 22 | but, also very easy to slot into in no time. The main 23 | attraction in Kathmandu is all the temples, but after a 24 | couple of days you have to escape to the mountains for the 25 | fresh air and relaxed pace of life, which we did. 26 | 27 | To get there we used the local transport - always a bit 28 | dodgey, especially given the number of buses leaving the 29 | road and lying in the valleys below!! The most comfortable 30 | way to travel is on the roof rack. You have uninterupted 31 | views and can jump clear if the bus leaves the road!(which 32 | it didn't) 33 | 34 | Our Treking adventure "The Annapurna Curcuit" began in a 35 | village below 36 | 1000mtrs surrounded by terraced rice paddy fields. For the 37 | first 5 days it rained on and off. We walked an average of 38 | 5 hours a day - taking it easy!! Upon reaching the Manang 39 | valley the clouds finally lifted and our views were 40 | spectacular, taking in the Annapurna mountains between 7000- 41 | 8000mtrs. Throughout the trek the villages have guesthouses 42 | where trekkers "crash" for the night with "dal bhat" being 43 | the common meal(made up of rice lentils, soup, curry veg). 44 | 45 | Electricity is only a recent luxury - it has been there for 46 | only 6yrs. Plus, they now have solar showers so trekers can 47 | get a"hot", 48 | mostly luke warm shower!! Our sights during the trek varied 49 | from one place to the next - Majestic waterfalls, hot 50 | springs(to soothe those aching muscles), raging rapids, & 51 | multicoloured buterflies and birds. 52 | You are constantly sharing the trail with locals, cows, 53 | sheep, yaks, and the many donkey convoys which supply goods 54 | to the villages, not to mention the porters who carry 55 | supplies on many occasions over one and a half their 56 | bodyweight!!! 57 | 58 | Before attempting to cross Thorung La(5416mtrs)we spent a 59 | few days 60 | acclimatising to the altitude. This was done in the Manang 61 | valley above 3800mtrs. Otherwise we could have ended up 62 | with altitude sickness, a very common problem when 63 | ascending too quickly(at 5000mtr there is only 50% oxygen 64 | that you have at sea level) 65 | 66 | There is a huge Tibetan influence here, which can be seen 67 | in the type of house - flat roofs, mud bricks etc. The 68 | valley along with the next valley we crossed into(Manang 69 | and the Mustang valley) are both in the rain shadow to the 70 | north of the Annapurna Range so they are very dry and 71 | baron. Not like the rest of our time in the Mountains. 72 | 73 | We had no problems conquering Thorung La(La means Pass) at 74 | 5416mtrs. Yes, metres above sea level!! So from there 75 | onwards it was down hill most of the way. We certainly 76 | enjoyed descending quickly but is was very hard on the 77 | legs!! I was in heaven in a small village where he found a 78 | pub with satelite TV showing the World Cup Rugby!! And to 79 | make it even better they were serving cheap potent apple 80 | cider plus apricot brandy!! 81 | 82 | As we decended further the vegetation changed from very 83 | little to pine forests to tropical forests. Before we 84 | reached Pokhara, the end of the trek, we had one final 85 | climb to get one final look at the amazing views of the 86 | Himalayan Mountains. Well as we had started the hike in the 87 | rain it decided to rain for us on our last day !! 88 | 89 | So after 18 days of treking we made it to Pokhara, a town 90 | beside a lovely lake with a view of the mountains we had 91 | just hiked around. It was heaven to be able to have hot 92 | showers, western food and of course satelite TV for me to 93 | watch the World Cup Rugby!! So I hope that this wasn't 94 | too long a read and we will both look forward to hearing 95 | what you are all up to at the moment!! 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-01-12-south-africa.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: South Africa 3 | creation_date: '2001-01-12' 4 | image: phone.gif 5 | author: MD 6 | layout: post 7 | --- 8 | 9 | ### Written by: MD 10 | 11 | Apr/May 1999 12 | 13 | I got in from South Africa a few days ago after enjoying a 14 | month travelling up the coast from Cape Town to 15 | Johannesburg via Durban and Swaziland. What a great way to 16 | unwind before arriving home. I would reccommend South 17 | Africa to anyone as there is so much to see and do, as I 18 | will explain in my summary below: 19 | 20 | I flew in to Cape Town passing by Table Mountain to 21 | the airport. The first thing I noticed on arrival 22 | was the relaxed pace of life which I had almost forgotten 23 | existed in the Southern Hemisphere. Bliss! 24 | 25 | I spent 10 days in Cape Town (Kaapstad - in Afrikans)which 26 | allowed me to see and do a lot. Some of the highlights 27 | included a drive out to Cape of Good Hope, climbing Table 28 | Mountain, enjoying a Stellenbosch Vineyard tour, visiting 29 | the famous Cape Flats black townships, sipping on a few 30 | sundowners at "Le Med" in Clifton, watching Gary Kirsten's 31 | cricket testimonial at Newlands Cricket Stadium over a 32 | braai (BBQ)under the scoreboard, and also the Super 12 33 | match between Western Stormers and Auckland Blues in a 34 | 48000 one eyed Newlands crowd! I can't get over how 35 | beautiful Cape Town is as a city. It certainly has to rate 36 | in the top 5 I've visited. 37 | 38 | I next headed up the coast along the Garden Route to a 39 | small holiday resort called Knysna where I enjoyed the 40 | outdoors. I spent 2 days mountain biking, kayaking, and 41 | abseiling/rapjumping. Awesome. 42 | 43 | Then I headed to a small seaside village called Kenton-on- 44 | Sea. It was a pretty sleepy retirementholiday destination 45 | but the locals were extremely friendly and knowledgeable 46 | about their country both sport and politic/history. It also 47 | had reasonable surf for boogieboarding. 48 | 49 | After a couple of days I headed to East London for a week 50 | where I caught up with friends of mine who I worked with in 51 | London (UK). While there I pretty much just hung out 52 | catching up and relaxing while occasionally visiting the 53 | beach. 54 | 55 | Durban was next stop but not before going through the 56 | Transkei (Nelson Mandela country). Just beautiful. 57 | 58 | Unfortunately I didn't get to camping out on the wild coast 59 | as I had stayed longer than I had planned in East London. 60 | Still there's always next time. Anyway once in Durban I 61 | caught up with Joanne (my mate Adrian's girlfriend). She 62 | showed me how to party the South African way....heaps of 63 | braais, booze, and friendly hospitality. A great weekend, 64 | but very full on. 65 | 66 | My next stop was the game reserves of Umfolozu & Hluhluwe 67 | in Zululand. I spent 3 days in and around here viewing many 68 | animals including...giraffe, zebra, cape buffalo, water 69 | buffalo, white rhinos, black rhinos, warthogs, elephants, 70 | hippos, but no leopards or lions. Pretty amazing and great 71 | photo opportunities. I also got to visit a local traditional 72 | zulu village. Very interesting culture and crafts. 73 | 74 | My last stop before flying home was Swaziland. Wow what a 75 | wonderful place and very interesting culture. While here I 76 | enjoyed more game reserve viewing, visit to a modern Swazi 77 | village and the memorial of their late king, who has been 78 | very influencial in keeping peace and diplomacy in the 79 | Southern part of Africa for the past 60years. We stayed in 80 | a large game lodge. A great place to wake up to....bird's 81 | chirping, waterbuck feeding from the waterhole in front of 82 | the lodge, hippos belching, etc. A mini paradise. 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-04-05-lava-beds-ate-our-shoes-maui-hi.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Lava Beds Ate Our Shoes; Maui, HI 3 | creation_date: '2001-04-05' 4 | image: book.gif 5 | author: Mark Kashman (mkashman) 6 | layout: post 7 | --- 8 | 9 | ### Written by: Mark Kashman (mkashman) 10 | 11 | Lava Beds Ate Our Shoes 12 | 13 | "Says here just two miles to the deserted black-sand beach," 14 | said Carolyna, my wife and love now doning her sneakers in 15 | place of the recently purchased flip-flops; though they need 16 | be called flip-flopOFFs! Ten bucks doesn't buy a nice pair of 17 | anything. 18 | 19 | To set the scene, we stood on the southern part of Maui, mid 20 | March, at an area called La Perouse Bay. To the east, Mt. 21 | Haleakala rises and peaks out at 10,000+ feet. Hot sun pelts 22 | our northwestern faces challenging its way through our 15 23 | spf. The breeding humpback whales full-body breach or tail 24 | slap about every twenty minutes. It is about midday on a 25 | weekday. And the road that brought us here ends. Only 4x4 26 | trucks and jeeps dare to rove beyond the parking lot. By the 27 | looks of the first few obstacles, I'd say the local auto 28 | parts stores have seen a few people who said 'ta-heck with 29 | it, let's give it a try' - the smell of oil and the echoing 30 | sound of metal upon rock... 31 | 32 | The book's description (a wonderful book called 'Maui 33 | Revealed') reads like a poetic dandelion gently blown on a 34 | fine summer day. It described a small remote beach brimming 35 | with shoreline darkness in an oasis of greenery in the middle 36 | of an expansive lava field. Our eyes read over the parts 37 | about the greenery and beach. Our feet fixated on the part 38 | about the lava, and translated it thus- lava=pumice=porous= 39 | rough=ouch=rubber=gone! So, ok, no open toed shoes, right? 40 | 41 | Right! With flip-flops removed, Carolyna is ready to brave 42 | the trail, known as the King's Highway, with low-top Chuck 43 | Taylors. Me, I sport a similar pair of blue Vans. 44 | 45 | The first part of the trail is pretty easy. It is about a 46 | half mile into it where the true grit falls beneath our feet. 47 | It is both a treasure and a trick to see the King's Highway 48 | lay out in front of us. The trail splits right down the 49 | middle of a jagged, arid landscape full of stories of foot 50 | traffic from the past. We imagine Hawaiian Kings carried upon 51 | wheel-less carriages and servants manipulating the rocky 52 | terrain below. The ocean sounds boom in the distance and the 53 | wind howls. Within the first few hundred yards we figure the 54 | Hawaiian servants would have been using a whole book of 55 | silent expletives by now. 56 | 57 | I couldn't get over the fact that the native Hawaiians wore 58 | no shoes on the King's Highway. Two steps on the crumbly lava 59 | with bare feet would've left me wincing like a baby. Each 60 | step tests the durability of both our shoes, our feet, and 61 | ankles too. The rocks just whittle away at the soles of our 62 | shoes like wood to a swiss army knife. 63 | 64 | One other important aspect the book stresses is how much 65 | water to bring... a lot! It's amazing how lava soaks up the 66 | sun and makes the aura of the Earth breathe fire with an 67 | updraft of air that pulsates the mist of mirage. Phew! So we 68 | drink like fish till our gills burst. Then we sweat, than we 69 | drink more. We are evaporative coolers humming right along. 70 | 71 | After two miles we come upon the turn in the trail we had 72 | read about. "Hang a left and go into the green oasis." So we 73 | do. We don't believe it at first because it looks too real to 74 | be real. But, once off the main highway we actually start to 75 | dodge tree branches. Now, this wouldn't be a strange thing 76 | for the rest of Maui, but here among the rocks stands a mass 77 | of trees defying the rest of the bleak landscape. They appear 78 | so green in contrast, like someone had cranked the chroma 79 | colors on the TV set. 80 | 81 | The path finally wanders its way around and plops us right 82 | onto a pristine black-sand beach. And instantly we are 83 | beckoned into action and rest; I into snorkel gear and 84 | Carolyna to the towel armed with a thick book and sunglasses. 85 | Boom the water is cool. The beach is hot. No one is around 86 | and our feet are free of sneakers, now well worn and slightly 87 | rounded on the bottoms. Yes! This is the destination. This is 88 | the call of the wild. This is where turtles float down below. 89 | And whale sounds permeate the ocean. This is a pretty darn 90 | nice place on a sunny midday weekday. 91 | 92 | And this is how we destined that day in Maui - to seek to 93 | define the road less traveled. Well, that was on this day. 94 | The next day we spent chasing piña coladas with flower- 95 | patterned hats shaded from the sun. The flip-flops flipped 96 | back on and nothing but Aloha all around. 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-08-19-mystic-connecticut.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: mystic, connecticut 3 | creation_date: '2001-08-19' 4 | image: hut.gif 5 | author: jessica 6 | layout: post 7 | --- 8 | 9 | ### Written by: jessica 10 | 11 | WE STAYED AT A WONDERFUL, UNIQUE BED AND BREAKFAST INN LAST 12 | FALL. THIS PLACE TAKES A STEP BACK INTO HISTORY. THE 13 | BUILDING WAS BUILT IN THE 1700'S, AND IS HISTORICALLY 14 | CORRECT IN THE FURNISHINGS. IF ANYONE LOVES REAL ANTIQUES 15 | AND NOT JUST FAKE OR "CUTE CURTAINS" DECORATING, GO THERE. 16 | THE NAME IS RED BROOK INN, MYSTIC 17 | 18 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-08-20-travel-tips-for-the-first-time-to-cuba.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Travel tips for the first time to Cuba 3 | creation_date: '2001-08-20' 4 | image: postcard.gif 5 | author: vedadohabana 6 | layout: post 7 | --- 8 | 9 | ### Written by: vedadohabana 10 | 11 | Travel Tips For Your Cuban Trip.There is a very useful information for the first time to Cuba about Tourist Card, Money matters,Havana Cuba Weather Forecast,Cuban Maps,Timetables for Buses, Bicycling Cuba,Private Accommodation, Swimming with the dolphins in Cuba,Cuban outdoors, Havana John Lennon Park, Cuban Popular Dances,Havana University Spanish Course, and some interactive tours around Santa Clara, Trinidad, Cienfuegos and the San Pasqual floating Hotel, Elguea Mud Hotel.You may take a look at:http://www.geocities.com/vedadohabana/lalala.html 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-10-10-travel-in-italy-after-september-th.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: travel in Italy after September 11th 3 | creation_date: '2001-10-10' 4 | image: book.gif 5 | author: Chris Dawson (cdawson) 6 | layout: post 7 | --- 8 | 9 | ### Written by: Chris Dawson (cdawson) 10 | 11 | Italy is magnificent in the fall. I have never spent time 12 | here and not found it to be incredible, but the weather is 13 | absolutely perfect for fall. Sunny, with a little rain in 14 | the mornings to clean the air. 15 | 16 | I am sure I was not alone in my thinking about getting on 17 | an airplane after September 11th. I definitely gave it 18 | more reflection and thought than I would have given it 19 | before that day. I have read countless pieces via email or 20 | on different web sites about what pilots have said before 21 | take off, and about what passengers have done to those 22 | sitting next to them, both negative and positive. Nothing 23 | out of the ordinary occurred, no tear jerking speeches from 24 | the cockpit, and no suspicious eyes following anyone as far 25 | as I could tell. Things seemed to be back to normal, as 26 | best they could. 27 | 28 | I wonder if this is the way it should be after something 29 | like the attacks. One part of me hopes that this will be a 30 | catalyst for people to review what is going on in the rest 31 | of the world. I worry this will mean that Americans will 32 | stop visiting other parts of the world, people will entrust 33 | their vacations to resorts and Disney and cruise ships. As 34 | an American I feel that Americans are blessed in that we 35 | live in a country rich in resources and full of people with 36 | new ideas about how they want to live their lives, but I 37 | also see the isolationism that we are a part of because of 38 | our geographic location in the world, and because of the 39 | policies of our government in a great many cases. I hope 40 | that despite the terrible things that happened several 41 | weeks ago that Americans, and all people around the world, 42 | choose to learn more about the rest of the world because of 43 | it, instead of closeting themselves more because of fear. 44 | 45 | Today we visited the Sistine Chapel. I missed it the first 46 | time I went to Italy several years ago. I almost did not 47 | take this trip because of the threat of more terrorism. I 48 | am really glad I did. Nothing can describe the amazement 49 | when you stand beneath those works of art, and everyone 50 | should have the opportunity to see that. It truly is a 51 | testament to the power of religion, and devotion. After 52 | some introspection, the issues of today are not so 53 | different as they were hundreds and thousands of years 54 | ago. Religion and a search for power still drive people to 55 | do incredible acts, and also commit terrible atrocities. 56 | 57 | One thing never changes as we walk around the cities of 58 | Italy. We have seen people from all over Europe, and all 59 | over Asia, and people from the Middle East, and all other 60 | parts of the world. As you travel, you notice that their 61 | mannerisms might differ slightly, and their dress might not 62 | be the same as what you see in your home country, but at 63 | their very depths, people are people. We walked around 64 | Milan late at night the day America began bombing, and as 65 | if by fate, we walked by countless groups of Arabs out in 66 | the streets, listening to radios. My heart beat faster, 67 | but why? No one cared who I was. They were only 68 | interested in getting more information about the attacks, 69 | just like I was. And on the train from Florence to Rome 70 | yesterday, we overheard people talking about the "war," and 71 | I have yet to hear someone here speak out in support of 72 | this war, or any war. 73 | 74 | I love to travel. It is a selfish thing in so many ways, 75 | just to expose myself to things that I think are 76 | beautiful. But, travel also exposes you to the rest of the 77 | world, and no matter what politicians want you to think 78 | about the rest of the world, people are people and 79 | individually people do not look to kill or injure other 80 | people. I hope that people can remember this after 81 | September 11th, and continue to remember that we are not so 82 | different from our neighbors around the world. 83 | 84 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-10-17-watch-out-for-borin-the-cab-driver.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: watch out for Borin the Cab Driver 3 | creation_date: '2001-10-17' 4 | image: camera.gif 5 | author: Chris Dawson (cdawson) 6 | layout: post 7 | --- 8 | 9 | ### Written by: Chris Dawson (cdawson) 10 | 11 | I left my new "sobe" (private room) angry and bitter. 12 | After all the time I have put in traveling, I still should 13 | know better than to trust a cab driver to find me lodging. 14 | After a very nice stay in Hotel Lapad, I decided to call 15 | Borin, my cab driver from the airport to Dubrovnik, and 16 | accept his offer to find me something near the city 17 | at "1/10 the price" as he had told me. My first mistake 18 | was that I should have known that there would be a finder's 19 | fee or a trumped up fare to the place, and thought I didn't 20 | see the finders fee I am sure it was there, judging by the 21 | bargains he found for me. The trumped up fare was there, 22 | to be sure, in the form of 80 kuna, or $10. The fare to 23 | the airport was twice this, but took almost 30 minutes, 24 | while this took five. After exhausting myself by climbing 25 | up the stairs to the first sobe he found, and then arguing 26 | over the price for a place that I really had no interest in 27 | staying in, I finally succumbed to a worse deal after the 28 | second sobe shark latched on to me during the feeding. 29 | When I finally dropped my bag down the stairs, and went in 30 | to take a shower, I was almost not surprised to see there 31 | was no shower curtain, and the floor was completely soaked 32 | when I finished my shower. This, despite pointing the head 33 | to the wall the entire time, and turning off the water to 34 | soap up and down. This at a price of 150 kuna, or about 35 | $20, which is low all considered, but the same price I 36 | would have paid for breakfast, a stellar view, and a decent 37 | bathroom at the first joint. 38 | 39 | The walled city of Dubrovnik would have none of this, and 40 | instantly banished all of those thoughts leaving me in 41 | awe. I decided to leave the sobe and get some dinner. I 42 | walked down a few stairs to see the entrance to the city 43 | looming above me. The view from the bridge was stunning to 44 | say the least, as I looked out over the small inlet where 45 | lightly illuminated boats hovered, protected by another arm 46 | of the city. I walked down countless cobblestone streets, 47 | jaw gaping, running my fingers over the limestone walls 48 | which towered sometimes over a hundred feet above me. 49 | 50 | I decided to stop for dinner at the Dubrovnik Terrace. 51 | Almost empty it was, but fun. As I waited on my order, I 52 | watched Wheel of Fortune in Croatian. Unlike the American 53 | version, I didn't know any of the answers. The man waiting 54 | on me, as if to challenge the old world inside the city, 55 | had programmed his phone to ring with the song to Brittni 56 | Spears "Oops, I did it again." American culture pervades 57 | everywhere, unfortunately. I ate a sea bass, which he 58 | promised had been caught the same day. It was good. A 59 | glass of wine was only 12 kuna, which amounted to about 60 | $1.50. 61 | 62 | Today I swam in the blue water of the sea, avoiding sea 63 | urchins and feeling the squish of the sea kelp underneath 64 | my feet on top of the volcanic rock. Dubrovnik is truly 65 | beautiful. 66 | 67 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-10-18-diving-in-dubrovnik.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Diving in Dubrovnik 3 | creation_date: '2001-10-18' 4 | image: star.gif 5 | author: Chris Dawson (cdawson) 6 | layout: post 7 | --- 8 | 9 | ### Written by: Chris Dawson (cdawson) 10 | 11 | I went diving in Dubrovnik this morning. Anton met me at his 12 | shop down the road the pertol station in Lapad. We geared up 13 | and left out to one of the islands a few kilometers from shore. 14 | 15 | The first stop we made was for a cave dive. It was just the 16 | two of us, so Anton dropped his gear into the water after 17 | filling his BCD vest with air, and helped me into my two 18 | wetsuits, one with a hood, and then into my BCD. I dropped 19 | into the water and then he followed. I was glad that he had 20 | suggested the second wetsuit, since the water was clear but 21 | extremely cold, and got colder as we went deeper. 22 | 23 | As we went around the walls near the island, we saw 24 | countless beds of coral, some with orange colored algae, but 25 | most with a dark green. There were sea urchins everywhere. 26 | Most of them had a half shell stuck in their thorns, despite 27 | the fact that there is no way their spines could pierce a 28 | clam shell. I think this is the same phenomenon as teenage 29 | boys who wear "Elevate and decide in the air" basketball 30 | t-shirts. Sort of a ridiculous badge of honor. Their were 31 | even albino sea urchins down there, or perhaps they were 32 | dead and had lost all their purple. 33 | 34 | After trolling around the edge of the island, we came across 35 | a black hole in the wall. I had only about a fourth of a 36 | tank left, but Anton motioned that this was OK, and we 37 | proceeded into it. On the surface he had said that it went 38 | back about 200 meters. It seems now like this was much 39 | exaggerated, maybe my excitement caught up with me. Anton 40 | held an underwater flashlight, and I followed the light more 41 | than I followed him. The "cave" was in reality more of a 42 | crack in the wall, and I slithered through with my tank 43 | bumping against the walls on the side and above me, and 44 | tried to keep up with Anton. As we came around the edge of 45 | the cave his light disappeared several times which was 46 | unconfortable. Finally we arrived at a open area and I could 47 | see the surface of the water as Anton pointed the flashlight 48 | upward. Ascending slowly, we broke the surface. Everything 49 | was black inside the cave without Anton's flashlight. When 50 | he shined it on the roof, a few feet above us, we could see 51 | tiny stalagtites, brownish and gooey. Anton said they looked 52 | like shark's teeth, and I thought this was a pretty 53 | inappropriate observation at that time. We then went back 54 | into the water and he pointed to the entrance, and we could 55 | see the light blue crack from the opposite side. 56 | 57 | As it turned out we descended to about 38 meters. I didn't 58 | have a depth gauge on my regulator, so I had no idea. The 59 | water was so clear and bright that I had thought we hadn't 60 | dropped beneath 15 meters or so. We were under for around 45 61 | minutes, which was a pretty long time for the depth we were 62 | at, although this wasn't our total bottom time. 63 | 64 | After we ascended and rested a bit, Anton said that we would 65 | then visit a bomb dropped during WWII by the Germans, and 66 | then proceed to a wreck and then see another cave. In fact 67 | we saw three German bombs at the bottom. All of them were 68 | completely corroded and you could see that they were empty 69 | inside. Borin the cab driver had told me that some people 70 | here in Dubrovnik would take mines found around the area and 71 | stuff them into fish which would then explode in the water 72 | later. Didn't look like there was much in the way of live 73 | ammunition down there, due in part to the heavy salt water. 74 | But one thing is for sure, war leaves even more than just 75 | death and hatred. 76 | 77 | After we looped around the first German bomb, we descended 78 | to see the sunken ship. The hull had almost completely 79 | settled into the ocean floor so you could only see the top 80 | of it, but many other pieces of the boat remained scattered 81 | about. Anton said it was a tourist boat which had 82 | unfortunately encountered engine problems, and the Serbs had 83 | shot it down with machine guns. Only a few people had died 84 | apparently. It was strange to see such geometric shapes in 85 | the water after seeing the smooth rockiness of the coral in 86 | the earlier dive. Another bomb sat on the floor next to the 87 | wreck. Lots of fish gathered about it as well; wrecks 88 | usually provide shelter similar to natural reefs for the 89 | marine life, and this one was no different. In a few years 90 | the sea will probably have beaten it to a pulp and the ship 91 | will return to the dust. As we went in the direction of the 92 | cave, Anton seemed almost clairvoyant as he found several 93 | little octopus, and a sea eel which had a head the size of a 94 | a coke bottle and probably several feet in length. Maybe 95 | even the sea animals are interested in improving tourism in 96 | Croatia? After he found his friends, I looked and looked, 97 | but nothing ever looked different than grey sand until Anton 98 | pointed his light at something and it jetted off in a cloud 99 | of black ink. 100 | 101 | Finally, we reach the other cave. As a now experienced cave 102 | diver, I had less anxiety in entering this one. This again 103 | was somewhat like a crack in the wall. This cave, however, 104 | opened into the air within some rocky walls going up. "This 105 | is like a little lake," mentioned Anton. We then descended 106 | back into the water, and followed the crack down. After we 107 | reached the boat, Anton informed me that we had reached 28 108 | meters at the lowest depth. Getting back into the boat, the 109 | fillings in my teeth stung a little bit from the pressure 110 | over the two dives. 111 | 112 | These two dives, stretching over a few hours, cost me around 113 | $80, two dives ($58), including equipment rental ($20), the 114 | Croatian diving license good for one year (about 100 Kuna or 115 | $12), and the free boat ride out. Well worth it. Anton can 116 | be reached at 435-737, via email at diver@vdu.hr or 117 | http://diver.vdu.hr/ 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-10-21-mirogoj-cemetery-in-zagreb.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mirogoj Cemetery in Zagreb 3 | creation_date: '2001-10-21' 4 | image: star.gif 5 | author: Chris Dawson (cdawson) 6 | layout: post 7 | --- 8 | 9 | ### Written by: Chris Dawson (cdawson) 10 | 11 | This morning I decided to visit Mirogoj cemetery, in the 12 | north part of Zagreb. I got on the bus at the stop above 13 | the Dolac market. I wasn't sure about where to get off for 14 | the cemetery, but when I saw the countless older women 15 | holding bouquets of flowers, I knew that I could just 16 | follow them off and everything would be alright. I bought 17 | an all day ticket on the bus for 16 kuna after a woman on 18 | the bus politely explained in English that I could buy the 19 | ticket right there. I was worried that I would have to 20 | find a newspaper stand down in Trg Jelaèiæa. 21 | 22 | Anyone who had forgotten flowers in their haste needn't 23 | have worried, for there were plenty of flower stands 24 | dotting the edge of the cemetery as the bus pulled up and 25 | dropped us off. The cemetery is enclosed in by a great 26 | wall with parapets every few dozen meters. The entranceway 27 | to the cemetery is truly amazing, with ivy covered walls 28 | and arched doorways. The entrance to St. Peter should be 29 | so beautiful. 30 | 31 | I sit down after walking for a while in front of the grave 32 | of a one Marieta Pollack. It is a really big tomb, about 33 | ten feet wide and six or seven feet deep. She lived from 34 | 1875 until 1925, so this is one of the older tombs in the 35 | cemetery I imagine. There are a few other names added to 36 | her headstone. None of the names seem to have the same 37 | last name as she did. This was different from the rest of 38 | the tombstones which often had "Obitelj Markovic" 39 | or "Obitelj Balantin" inscribed upon it. From my little 40 | yellow dictionary I soon learned that "obitelj" 41 | means "family." Her headstone has the Star of David on it, 42 | and something in Hebrew which I cannot read, but which I 43 | see on a good number of the stones in this area of the 44 | cemetery. There is an inscription that reads "Što ljubav 45 | spaja smrt ne razdvaja." 46 | 47 | Her headstone seems to be on the edge of the Jewish section 48 | of Mirogoj. Towards the edge of the cemetery I began to 49 | notice more and more German names, last names like Weiss 50 | and first names like Adolf. And, at the same time, more 51 | and more of the tombstones began to replace the long cross 52 | with the Star of David. The tombs are in most other ways 53 | identical to the rest of the ones I saw previously; 54 | typically black marble slabs on top of a black box, which 55 | was set into the ground, and with a matching stone 56 | headpiece sitting perpendicular to the ground. Marieta 57 | Pollack's grave also had a small bench in front of it. 58 | This wasn't typical. Only a few of the graves had a 59 | bench. About half of the benches had a back to them, and 60 | this back always forced the person sitting in the bench to 61 | face the grave, as if to remind the person for what they 62 | were here. Some of the other benches had no backing, as if 63 | to say that they appreciated whatever closeness and company 64 | they could get. I found it interesting that the benches 65 | with the back piece on them almost always were covered in 66 | moss and in greater disrepair than the ones with a back. 67 | 68 | This truly is one of the most beautiful places I have 69 | visited in Croatia. The small paths through the cemetery 70 | cut straight through the graves, dividing them into large 71 | groups of several hundred tombs. I could not tell if these 72 | larger groups had any particular significance. Trees line 73 | the edges of the paths, and since it is early fall when I 74 | am visiting, the leaves, some of which litter the path and 75 | some of which stil cling to the tree branches, contrast 76 | nicely with the grey sky and the gravelly stone under my 77 | feet. The land in the cemetery is uneven, and the paths 78 | roll up and down the ground between the tombs. In most 79 | cases these paths go straight, but around the edges the 80 | paths curve and bend. 81 | 82 | Today is Sunday, and the people here are almost all 83 | elderly, although I am not sure if this is normal. The 84 | footsteps over the concrete paths remind you of this fact; 85 | broken and deliberate footsteps, sometimes you can hear one 86 | foot as it is slowly dragged behind the other. Shhhh-tk. 87 | Shhhh-tk. Some people hover over the graves, holding 88 | flowers. Some dilligently clean the marble slabs with 89 | containers of water, brooms and by simply picking off the 90 | leaves. Some do this alone, while others have come in 91 | groups. As I pass people I try to check the date of the 92 | tombstone. One older man must have buried his wife 93 | recently; her tombstone says 2000. He stands alone in the 94 | long row of graves where he brushes the dirt from her grave. 95 | 96 | As I continue about the cemetery, it seems like many of the 97 | graves followed the style of those around them. In one 98 | section most are black marble, with similar boxy 99 | construction. In other areas the stone is a lighter 100 | color. As I progress back to the entrace, there is more 101 | originality, some graves even add black wrought iron fences 102 | around them. I find it funny that there are several tombs 103 | on the very edge of each divided section which are so 104 | plain, in sharp contrast to the other tombs which are so 105 | careful assembled and planned. These simple tombs must get 106 | more attention from tourists like me than the more 107 | elaborate ones in the center. Then there are the older, 108 | fancier graves which in their day must have been 109 | magnificent, but in their decrepitude remind everyone that 110 | no matter what your legacy in life, death has a way of 111 | limiting your power over the future. 112 | 113 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-11-03-smoking-in-the-hague.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: smoking in the hague 3 | creation_date: '2001-11-03' 4 | image: hut.gif 5 | author: shareena78 6 | layout: post 7 | --- 8 | 9 | ### Written by: shareena78 10 | 11 | The Netherlands is a wonderful place to visit. Steer clear from Amsterdam during the summer time as it is all so touristy and does not resemble what the real part of the Netherlands is all about. Although the country is small, the people are fantastic. I went to school there, and had the opportunity and pleasure to meet many Dutch and foreign students. The Hague is a nice place, very small but has the government buildings, the Peace Palace and many art exhibitions going on constantly. A couple of good places to visit in the Netherlands are Utrecht, Oudewater (where the women were weighed to see if they were witches), Gouda, Leiden and of course Amsterdam. There are many cathedrals and canals of course, but there is so much more to see than that. Check out the Paradiso in Amsterdam as a must see club, the Van Gogh Museum, take a boat ride, try out the boat parties and underground places such as The Dag Maart or the Blauw Aanslaag (The Hague) and also try out the herring (which I didn't do as I don't like fish too well). Especially check out Cremers as the one and best coffee shop in the hague. I travelled and saw quite a lot on my trip to Holland but living there and immersing myself in the culture was the best part of it all. I reccomend Holland as more than a place to visit, it should be place to live and love. 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-12-02-check-out-this-travel-planning-website.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Check out this Travel Planning Website 3 | creation_date: '2001-12-02' 4 | image: paper.gif 5 | author: tadon 6 | layout: post 7 | --- 8 | 9 | ### Written by: tadon 10 | 11 | I used this place and found the information presented and 12 | prices to be much better than the other usual suspects. 13 | 14 | Travel-Ascending.com 15 | 16 | http://www.travel-ascending.com/ 17 | 18 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2001-12-30-bhutan-monsoons-and-miracles.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Bhutan: Monsoons and Miracles' 3 | creation_date: '2001-12-30' 4 | layout: post 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2002-05-07-the-bardo-museum.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: The Bardo Museum 3 | creation_date: '2002-05-07' 4 | layout: post 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2002-07-06-a-day-in-beijing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: A Day in Beijing 3 | creation_date: '2002-07-06' 4 | image: phone.gif 5 | author: Danny Spitler (dispitler) 6 | layout: post 7 | --- 8 | 9 | ### Written by: Danny Spitler (dispitler) 10 | 11 | China Chapters 12 | Volume 2 13 | The Forbidden City 14 | By: Danny Spitler (dispitler@aol.com) 15 | 16 | We arrived at the China World Hotel around noon on 17 | Saturday, China time. We had lost a day crossing the 18 | International Dateline. The hotel was five star in all 19 | respects and could rival any Hyatt Regency that I have ever 20 | stayed in. On a quick visit to the basement level I found 21 | a fully equipped weight room, a 20-meter lap pool, a steam 22 | room, sauna, whirlpool, and a cold plunge. I wouldn't have 23 | any trouble doing my upper body exercises while we were in 24 | Beijing, and from the looks of the schedule my legs were 25 | going to get all the work they needed. 26 | 27 | The hotel provided a private room for our group's "welcome 28 | to China" dinner, and we all headed for bed in an attempt 29 | to get our bodies on China time (15 hours ahead of Mountain 30 | standard). Ten hours later we were standing in Tinanmen 31 | Square. It was Sunday so there were thousands of weekend 32 | Chinese tourists as well as locals joining us in the 33 | square, but it is the largest town square in the world so 34 | there was plenty of room for all of us. We split up for a 35 | while then regrouped for the mandatory group picture with 36 | the Gate of Heavenly Peace in the background. This is the 37 | entrance to the Forbidden City and the place where Mao Ze 38 | Dung stood to proclaim the beginning of the People's 39 | Republic of China on October 1, 1949. You can imagine the 40 | party that they are going to have here in a couple of 41 | months at the 50th anniversary of that event. 42 | 43 | For our group picture a couple of the girls cajoled an 44 | uniformed policemen into joining our group for the 45 | picture. He seemed cordial enough, but as I looked at the 46 | single red star on his shirt and cap, I couldn't help but 47 | wonder if he might have been wielding an automatic weapon 48 | and gunning down students on this very spot several years 49 | ago. 50 | 51 | From the huge square we walked through a walkway under the 52 | main street facing the square and emerged across the street 53 | to enter the Gate of Heavenly Peace and into the Forbidden 54 | City. Our Beijing guide, Jon Jin, purchased our tickets 55 | and we were transferred from modern day China to six 56 | centuries earlier as we began to wander through the huge 57 | city built exclusively for the many emperors who ruled 58 | China for over two milleniums. 59 | 60 | It was hot and humid and there were thousands of other 61 | tourists to contend with, but nothing could detract me from 62 | being amazed with what we were viewing. The Disney 63 | Corporation has had no input into crowd control at this 64 | place, and in order to see the emperor's throne you had to 65 | fight your way through hundreds of other tourists. 66 | Everyone was struggling to get to a small viewing point, 67 | where only a dozen people could stand. Most of our group 68 | didn't attempt it, but I dove headfirst into the melee and 69 | grasp that rarest of feelings..….being one of the tallest 70 | persons in the crowd. After five minutes of squirming 71 | through every opening, no matter how small, I found myself 72 | standing in from of the massive throne. I stayed only long 73 | enough to take a well-earned photo and then started 74 | fighting my way back out of the crowd. I finally broke 75 | free with the feeling that I had just had an intimate 76 | encounter with a small percentage of the Chinese 77 | population. 78 | 79 | We continued to wander from one amazing site to another 80 | listening to Jon Jin provide interesting facts and stories 81 | along the way until we finally arrived at a building 82 | housing some of the emperor's private rooms. We were able 83 | to view the rooms though a glass wall, which was 84 | sufficiently smudged with many days of pollution, 85 | fingerprints and nose prints. I thought about the 86 | potential profits of a Windex concession stand. The ladies 87 | in our group were interested in hearing about the elaborate 88 | robes and the spectacular jewel encrusted crowns, necklaces 89 | and rings worn by the emperor. The males in the group were 90 | more interested in the concubine statistics. According to 91 | Jon Jin the emperor kept a significant number of concubines 92 | on his staff, and when he decided which one he would sleep 93 | with on a given night she would be delivered to him naked, 94 | in order to insure that she was not carrying any weapons. 95 | Then she would have to crawl to his bed on her hands and 96 | knees to make sure that her head was never higher than his 97 | head. This was a major no-no. I think that we can 98 | conclude from this story that sex has not changed much over 99 | the last few centuries. We still take time to remove the 100 | jewelry and there is still groveling involved. We have 101 | just had gender role reversal. 102 | 103 | Prior to exiting the Forbidden City we were ushered into a 104 | gift shop where the People's Republic gave us every 105 | opportunity to contribute filthy, capitalistic, Yankee 106 | dollars to Chinese economic development. Then we were 107 | whisked through some narrow residential streets to a 108 | restaurant that was tucked back off the beaten path. As it 109 | turned out this was one of Chairman Mao's favorite places 110 | to eat. His smiling face adorned the wall of the entryway, 111 | and I assumed that he signed his picture with Chinese 112 | characters which could be loosely interpreted as "Who loves 113 | ya, baby?" 114 | 115 | We packed our hot, sweaty bodies around two large, round 116 | tables and had the first of many sumptuous Chinese lunches 117 | and dinners. I quickly relearned my chopstick skills and 118 | was soon snatching items onto my plate as the dishes rolled 119 | by on the center lazy susan. 120 | 121 | After lunch and a short bus ride to the suburbs we found 122 | ourselves wandering around through the extensive grounds of 123 | the Summer Palace, used by several of the last emperors. 124 | There were many buildings, statues, and gardens along with 125 | a huge lake, which we learned, was dug out by several 126 | thousand peasants. The highlight of hot, crowded afternoon 127 | was when tall Brad (6’ 8”) waded into a large group of 128 | grade school kids on a field trip and let them all pose for 129 | pictures with the giant American. 130 | 131 | We arrive back at the hotel just in time for a quick shower 132 | before reassembling in the lobby for a trip to a downtown 133 | restaurant and a Peking Duck dinner. Dinner was followed 134 | by a request for a special stop on the way back to the 135 | hotel. Jon Jin went to bat for us with the bus driver, and 136 | we all got to buy T-shirts at the Hard Rock Café of 137 | Beijing. 138 | 139 | Next…..The Great Wall 140 | I 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/_posts/2002-10-10-romantic-prague.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Romantic Prague 3 | creation_date: '2002-10-10' 4 | image: camera.gif 5 | author: Danny Spitler (dispitler) 6 | layout: post 7 | --- 8 | 9 | ### Written by: Danny Spitler (dispitler) 10 | 11 | I have been anxious to return to Prague and share it with 12 | Pam ever since my first trip to this beautiful city in 13 | September of 1999. Through an internet web site I had 14 | managed to reserve a room in a small hotel just off the Old 15 | Town Square in the heart of the city. 16 | 17 | I had hoped to be able to get to the hotel from the train 18 | station using the subway system and my two-year-old memory 19 | of the streets of Prague. I found the right subway stop, 20 | but took a wrong turn on one of the streets and discovered 21 | that I was lost. Czech taxi drivers can be pretty 22 | mercenary to tourists, but we were tired from our all night 23 | train ride and ready to unpack, so I hailed a cab and 24 | showed him the address to the hotel, which I was certain 25 | was only a few blocks away. Sure enough, he took us on 26 | creative route, and managed to run up ten dollars on the 27 | meter. I am sure that a direct route would have costs us 28 | half that much. 29 | 30 | The hotel turned out to be charming. It had only been 31 | completed for about six months although it was housed in a 32 | building that dated from the 14th century. Our room was on 33 | the third floor, which had a nice view, but there was no 34 | elevator so we got to know the stairway pretty well over 35 | the next three days. I took Pam by the hand and led her 36 | downstairs and around the corner to show her the most 37 | beautiful town square that I have found in all my travels. 38 | She took a slow 360-degree turn and agreed with my 39 | assessment. 40 | 41 | Upon returning to the hotel I made arrangements for a cab 42 | ride to the Grand Palace. I had the hotel negotiate a set 43 | rate for the short trip across the Vltava River and up the 44 | hill to the entrance of this extensive palace whose first 45 | buildings date back to the 10th century. For the next few 46 | hours we toured through the ancient St. George Basilica and 47 | the Vladislav Assembly Hall where riders on horseback had 48 | ridden into the hall during mid-evil days and where many 49 | historic events in Czech history had taken place. We also 50 | visited the enormous St. Vitus Cathedral, which is one of 51 | the most impressive cathedrals in all of Europe. The 325 52 | steps to the top of the cathedral were tempting, but I had 53 | made that climb two years earlier and we had a long day of 54 | walking yet ahead of us. 55 | 56 | At the walls of the palace you can get a fantastic overview 57 | of the whole city of Prague and there were several members 58 | of a tour group standing at the wall with us and looking 59 | out at the beautiful view. There was also three fairly 60 | well dressed, middle-aged women circulating near all the 61 | tourists. The group's tour guide called for everyone's 62 | attention by announcing, "Ladies and gentlemen, may I have 63 | your attention. Please notice the three ladies standing 64 | here," and he pointed to the three middle-aged 65 | ladies. "These are gypsies," he announced matter-of- 66 | factly, "and they are here to rob you." He then switched 67 | to the Czech language and angrily told the three gypsy 68 | ladies to get away from his tour group. They moved away 69 | giving the tour director looks that could kill and a couple 70 | of hand gestures that most anyone could have interpreted. 71 | Most tour books warn that Prague has some of the most 72 | talented pickpockets in all of Europe. 73 | 74 | We wandered along a narrow street near the back of the 75 | Palace complex called the Golden Lane. It got its name 76 | from the period when goldsmiths used to do their work in 77 | the area, but for some reason, the apartments where they 78 | worked and lived were very small. Later the little rooms 79 | were used as soldiers' barracks. Now they are filled with 80 | retail shops, but I think that anyone over 5' 7" would have 81 | a difficult time as a clerk. 82 | 83 | After leaving the palace we walked through a section of 84 | town called the Lesser Quarter and visited the very ornate 85 | St. Nichols cathedral with its distinctive turquoise dome. 86 | Then we worked our way slowly back toward the Vltava River 87 | for a walk across the famous, old Charles Bridge. The 88 | bridge was built in the 12th century. It is lined with 89 | large statues and there are large mid-evil towers on both 90 | sides of the bridge. It is used only for pedestrian 91 | traffic and, with the Grand Palace and St. Nichols 92 | Cathedral on one side and a view of some of Prague's famous 93 | buildings on the other side, it is certainly one of the 94 | most beautiful and romantic bridges anywhere in the world. 95 | There are usually several artists painting and selling 96 | their wares along the bridge as well as one or two 97 | musicians playing romantic songs in exchange of tips. Like 98 | the Old Town Square the Charles Bridge is a point in the 99 | city that keeps drawing you back. Before our weekend was 100 | over we took many walks across the Charles Bridge, holding 101 | hands and relishing the experience. 102 | 103 | After crossing the bridge our route back to the square took 104 | us through a narrow pedestrian walkway lined with shops. I 105 | remembered that this was the area where I had purchased a 106 | gift for Pam on my visit two and half years earlier. As we 107 | passed the tiny jewelry shop I recognized it immediately. 108 | I also remembered that I had dealt with a very nice female 109 | sales clerk who spoke good English. I asked the girl 110 | behind the counter how long she had worked there and she 111 | said she had been there for at least three years so I was 112 | sure that she was the same one. My purchase back in 1999 113 | had been a gold bracelet filled with red garnet stones. 114 | Pam quickly found a pair of red garnet earrings to give to 115 | her mother, and after some looking we were able to find a 116 | pair of earrings for Pam that just happen to be a perfect 117 | match for her bracelet. My purchase pleased both Pam and 118 | the sales clerk, which just goes to show that on rare 119 | occasions I can make two women happy at the same time. 120 | 121 | We opted for dinner in the small restaurant on the ground 122 | floor of our hotel and ordered some traditional Czech 123 | dishes, which were tasty and filling. By the time we 124 | finished dinner and made the climb to the third floor to 125 | deposit our purchases it was dark and time to walk back to 126 | the Charles Bridge for a night view. On one side of the 127 | bridge you can look up to the Grand Palace and the spires 128 | of St. Vitus Cathedral which are bathed in spotlights. The 129 | dome of St. Nichols is also brightly illuminated. Looking 130 | back to the other side is Prague's city center with its 131 | brightly lit 17th century symphony building, the National 132 | Theater building, and the domes of numerous old 133 | cathedrals. The bright city lights reflect off the waters 134 | of the river below. There are boats cruising the river 135 | with strings of white lights lining their decks. There are 136 | pleasant scents of good food wafting up from the sidewalk 137 | cafes, and usually a street musician playing soft music on 138 | a violin. If you have the tiniest bit of romance in your 139 | soul it will certainly bubble to the surface as you stroll 140 | along the Charles Bridge in the beautiful city of 141 | Prague. 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/css/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000000; 3 | background-color: #CCCC99; 4 | } 5 | 6 | a { 7 | color: #603; 8 | } 9 | 10 | .jumbotron { 11 | background-color: #FFFFCC; 12 | } -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/images/book.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xrd/building-tools-with-github/e38021459158e3c4cca303f2d61945a50922ade7/chapter-6-ruby-and-jekyll/assets/images/book.gif -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/images/camera.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xrd/building-tools-with-github/e38021459158e3c4cca303f2d61945a50922ade7/chapter-6-ruby-and-jekyll/assets/images/camera.gif -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/images/hut.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xrd/building-tools-with-github/e38021459158e3c4cca303f2d61945a50922ade7/chapter-6-ruby-and-jekyll/assets/images/hut.gif -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/images/paper.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xrd/building-tools-with-github/e38021459158e3c4cca303f2d61945a50922ade7/chapter-6-ruby-and-jekyll/assets/images/paper.gif -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/images/phone.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xrd/building-tools-with-github/e38021459158e3c4cca303f2d61945a50922ade7/chapter-6-ruby-and-jekyll/assets/images/phone.gif -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/images/photo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xrd/building-tools-with-github/e38021459158e3c4cca303f2d61945a50922ade7/chapter-6-ruby-and-jekyll/assets/images/photo.gif -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/images/postcard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xrd/building-tools-with-github/e38021459158e3c4cca303f2d61945a50922ade7/chapter-6-ruby-and-jekyll/assets/images/postcard.gif -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/images/star.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xrd/building-tools-with-github/e38021459158e3c4cca303f2d61945a50922ade7/chapter-6-ruby-and-jekyll/assets/images/star.gif -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/assets/images/tower.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xrd/building-tools-with-github/e38021459158e3c4cca303f2d61945a50922ade7/chapter-6-ruby-and-jekyll/assets/images/tower.gif -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 |
6 | {% for post in site.posts %} 7 |

{{ post.title }}

8 | 9 | {{ post.content | strip_html | truncatewords: 40 }} 10 | 11 | Posted on {{ post.date | date_to_string }} 12 | 13 | {% endfor %} 14 |
-------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/run.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require './scraper' 4 | 5 | scraper = Scraper.new() 6 | scraper.run() 7 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/scraper.rb: -------------------------------------------------------------------------------- 1 | require 'mechanize' 2 | require 'vcr' 3 | require 'yaml' 4 | require 'fileutils' 5 | 6 | VCR.configure do |c| 7 | c.cassette_library_dir = 'cached' 8 | c.hook_into :webmock 9 | end 10 | 11 | class Scraper 12 | 13 | attr_accessor :root 14 | attr_accessor :agent 15 | attr_accessor :pages 16 | 17 | def initialize 18 | @root = "http://web.archive.org/web/20030820233527/http://bytravelers.com/journal/entry/" 19 | @agent = Mechanize.new 20 | @pages = [] 21 | end 22 | 23 | def scrape 24 | 100.times do |i| 25 | begin 26 | VCR.use_cassette("bt_#{i}") do 27 | url = "#{@root}#{i}" 28 | @agent.get( url ) do |page| 29 | if page.title.eql? "Read Journal Entries" 30 | pages << page 31 | end 32 | end 33 | end 34 | rescue Exception => e 35 | STDERR.puts "Unable to scrape this file (#{i})" 36 | end 37 | end 38 | end 39 | 40 | def process_title( row ) 41 | row.strip.gsub( /"/, '' ) if row 42 | end 43 | 44 | def process_body( row ) 45 | full = row.text() 46 | all_ps = ( row / "p" ) 47 | first = full.gsub( all_ps.text(), '' ) 48 | first.strip! 49 | body = first + "\n\n" 50 | all_ps.each do |p| 51 | body += p.text().strip() + "\n\n" 52 | end 53 | body 54 | end 55 | 56 | def get_filename( title, date ) 57 | processed_date = DateTime.parse( date ) 58 | processed_title = title.downcase.gsub( /[^a-z]+/, '-' ) 59 | "#{processed_date.strftime('%Y-%m-%d')}-#{processed_title}.md" 60 | end 61 | 62 | def write( rendered, processed ) 63 | Dir.mkdir( "_posts" ) unless File.exists?( "_posts" ) 64 | filename = get_filename( processed['title'], processed['creation_date'] ) 65 | File.open( "_posts/#{filename}", "w+" ) do |f| 66 | f.write rendered 67 | end 68 | end 69 | 70 | def process_creation_date( date ) 71 | tuple = date.split( /last updated on:/ ) 72 | rv = tuple[1].strip if tuple and tuple.length > 1 73 | rv 74 | end 75 | 76 | def render( processed ) 77 | processed['layout'] = 'post' 78 | filtered = processed.reject{ |k,v| k.eql?('body') } 79 | rendered = "#{filtered.to_yaml}---\n\n" + 80 | "### Written by: #{processed['author']}\n\n" + 81 | processed['body'] 82 | rendered 83 | end 84 | 85 | def process_image( title ) 86 | img = ( title / "img" ) 87 | src = img.attr('src').text() 88 | filename = src.split( "/" ).pop 89 | 90 | output = "assets/images/" 91 | FileUtils.mkdir_p output unless File.exists? output 92 | full = File.join( output, filename ) 93 | 94 | if not File.exists? full or not File.size? full 95 | root = "https://web.archive.org" 96 | remote = root + src 97 | # puts "Downloading #{full} from #{remote}" 98 | `curl -L #{remote} -o #{full}` 99 | end 100 | 101 | filename 102 | end 103 | 104 | def get_rows( page ) 105 | page / "table[valign=top] tr" 106 | end 107 | 108 | def run 109 | scrape() 110 | @pages.each do |page| 111 | rows = get_rows( page ) 112 | processed = {} 113 | processed['title'] = process_title( rows[0].text() ) 114 | processed['creation_date'] = process_creation_date( rows[3].text() ) 115 | processed['body'] = process_body( rows[4] ) 116 | processed['image'] = process_image( rows[0] ) 117 | author_text = ( rows[2] / "td font" )[0].text() 118 | processed['author'] = $1.strip if author_text =~ /author:\s+\n\n+(.+)\n\n+/ 119 | rendered = render( processed ) 120 | write( rendered, processed ) 121 | end 122 | end 123 | 124 | end 125 | -------------------------------------------------------------------------------- /chapter-6-ruby-and-jekyll/scraper_spec.rb: -------------------------------------------------------------------------------- 1 | require './scraper' 2 | 3 | describe "#run" do 4 | before :each do 5 | @scraper = Scraper.new 6 | end 7 | 8 | describe "#process_titles" do 9 | it "should correct titles with double quotes" do 10 | str = ' something " with a double quote' 11 | expect( @scraper.process_title( str ) ).to_not match( /"/ ) 12 | end 13 | 14 | it "should strip whitespace from titles" do 15 | str = '\n\n something between newlines \n\n' 16 | expect( @scraper.process_title( str ) ).to_not match( /^\n\n/ ) 17 | end 18 | 19 | it "should not crash if the title is nil" do 20 | expect{ @scraper.process_title( nil ) }.to_not raise_error() 21 | end 22 | end 23 | 24 | describe "#body" do 25 | before( :each ) do 26 | @scraper.scrape() 27 | end 28 | 29 | it "should have a body with Brazil in it" do 30 | found = false 31 | @scraper.pages.each do |p| 32 | rows = @scraper.get_rows( p ) 33 | # puts "Body: #{rows[4].text()}" 34 | found = true if rows[4].text() =~ /salvador/i 35 | end 36 | expect( found ).to eq( true ) 37 | end 38 | end 39 | 40 | describe "#get_filename" do 41 | it "should take 'Cuba - the good and bad' on January 12th, 2001 and get a proper filename" do 42 | input = 'Cuba - the good and bad' 43 | date = "January 12th, 2001" 44 | output = "2001-01-12-cuba-the-good-and-bad.md" 45 | expect( @scraper.get_filename( input, date ) ).to eq( output ) 46 | end 47 | 48 | it "should `Mexico/Belize/Guatemala` and get a proper filename" do 49 | input = "Mexico/Belize/Guatemala" 50 | date = "2001-01-12" 51 | output = "2001-01-12-mexico-belize-guatemala.md" 52 | expect( @scraper.get_filename( input, date ) ).to eq( output ) 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | secrets.xml 9 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.idea/.name: -------------------------------------------------------------------------------- 1 | GhRu2 -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/README.md: -------------------------------------------------------------------------------- 1 | ## Building the app 2 | 3 | First, download the Android SDK and make sure you have Java installed. 4 | 5 | To build a debug app, use this command: 6 | 7 | ``` 8 | JAVA_HOME=~/bin/jdk1.7.0_79 \ 9 | ANDROID_HOME=~/Android/Sdk \ 10 | ./gradlew assembleDebug 11 | ``` 12 | 13 | ## Running Unit Tests 14 | 15 | To run the unit tests, use a GitHub account which: 16 | 17 | * does not have 2-factor auth enabled. 18 | * has a Jekyll repository named `username.github.io` created for the user. 19 | 20 | Then, run this: 21 | 22 | ``` 23 | GITHUB_HELPER_USERNAME=BurningOnUp \ 24 | GITHUB_HELPER_PASSWORD=somethingOrOther \ 25 | JAVA_HOME=~/bin/jdk1.7.0_79 \ 26 | ANDROID_HOME=~/Android/Sdk \ 27 | ./gradlew test 28 | ``` 29 | 30 | This single test proves that our GitHub client Java code makes a new file inside the Jekyll repository 31 | and then views the published post. 32 | 33 | ## Running Espresso Tests 34 | 35 | To run the espresso test, you will need to create a `secrets.xml` file inside `app/src/main/res/values`. 36 | This file should contain the same username and password and look like this: 37 | 38 | ``` 39 | 40 | 41 | BurningOnUp 42 | somethingOrOther 43 | 44 | ``` 45 | 46 | Then, to run the tests, use this command: 47 | 48 | ``` 49 | JAVA_HOME=~/bin/jdk1.7.0_79 \ 50 | ANDROID_HOME=~/Android/Sdk \ 51 | ./gradlew connectedTest 52 | ``` 53 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.example.ghru" 9 | minSdkVersion 21 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(dir: 'libs', include: ['*.jar']) 25 | compile 'com.android.support:appcompat-v7:23.0.1' 26 | compile 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5' 27 | compile( 'commons-codec:commons-codec:1.9' ) 28 | testCompile 'junit:junit:4.12' 29 | testCompile 'com.squareup.okhttp:okhttp:2.5.0' 30 | androidTestCompile 'com.android.support.test:runner:0.4' 31 | androidTestCompile 'com.android.support.test:rules:0.4' 32 | androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1' 33 | } 34 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/22.2.1/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/app/src/androidTest/java/com/example/ghru/MainActivityTest.java: -------------------------------------------------------------------------------- 1 | package com.example.ghru; 2 | 3 | import android.support.test.InstrumentationRegistry; 4 | import android.test.ActivityInstrumentationTestCase2; 5 | import static android.support.test.espresso.Espresso.onView; 6 | import static android.support.test.espresso.action.ViewActions.*; 7 | import static android.support.test.espresso.assertion.ViewAssertions.matches; 8 | import static android.support.test.espresso.matcher.ViewMatchers.*; 9 | 10 | public class MainActivityTest 11 | extends ActivityInstrumentationTestCase2 { 12 | 13 | public MainActivityTest() { 14 | super( MainActivity.class ); 15 | } 16 | 17 | public void testLogin() { 18 | injectInstrumentation( InstrumentationRegistry.getInstrumentation() ); 19 | MainActivity mainActivity = getActivity(); 20 | String username = mainActivity 21 | .getString( R.string.github_helper_username ); 22 | onView( withId( R.id.username ) ) 23 | .perform( typeText( username ) ); 24 | String password = mainActivity 25 | .getString( R.string.github_helper_password ); 26 | onView( withId( R.id.password ) ) 27 | .perform( typeText( password ) ); 28 | onView( withId( R.id.login ) ) 29 | .perform( click() ); 30 | onView( withId( R.id.status ) ) 31 | .check( matches( withText( "Logged into GitHub" ) ) ); 32 | 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/app/src/main/java/com/example/ghru/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.ghru; 2 | 3 | import android.app.Activity; 4 | import android.os.AsyncTask; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | import android.widget.Button; 8 | import android.widget.EditText; 9 | import android.widget.TextView; 10 | import android.view.View; 11 | 12 | import org.eclipse.egit.github.core.User; 13 | import org.eclipse.egit.github.core.service.UserService; 14 | 15 | import java.io.IOException; 16 | 17 | public class MainActivity extends Activity 18 | { 19 | 20 | String username; 21 | String password; 22 | 23 | /** Called when the activity is first created. */ 24 | @Override 25 | public void onCreate(Bundle savedInstanceState) 26 | { 27 | super.onCreate(savedInstanceState); 28 | setContentView( R.layout.main); 29 | 30 | Button login = (Button)findViewById( R.id.login ); 31 | login.setOnClickListener(new View.OnClickListener() { 32 | public void onClick(View v) { 33 | EditText utv = (EditText)findViewById( R.id.username ); 34 | EditText ptv = (EditText)findViewById( R.id.password ); 35 | username = utv.getText().toString(); 36 | password = ptv.getText().toString(); 37 | 38 | new LoginTask().execute(username, password); 39 | } 40 | }); 41 | } 42 | 43 | private void login() { 44 | 45 | setContentView(R.layout.logged_in); 46 | 47 | Button submit = (Button)findViewById( R.id.submit ); 48 | submit.setOnClickListener(new View.OnClickListener() { 49 | public void onClick(View v) { 50 | 51 | EditText post = (EditText) findViewById(R.id.post); 52 | String postContents = post.getText().toString(); 53 | 54 | EditText repo = (EditText) findViewById(R.id.repository); 55 | String repoName = repo.getText().toString(); 56 | 57 | EditText title = (EditText) findViewById(R.id.title); 58 | String titleText = title.getText().toString(); 59 | 60 | doPost(repoName, titleText, postContents); 61 | } 62 | }); 63 | } 64 | 65 | private void loggedIn() { 66 | 67 | setContentView(R.layout.logged_in); 68 | 69 | Button submit = (Button)findViewById( R.id.submit ); 70 | submit.setOnClickListener(new View.OnClickListener() { 71 | public void onClick(View v) { 72 | 73 | EditText post = (EditText) findViewById(R.id.post); 74 | String postContents = post.getText().toString(); 75 | 76 | EditText repo = (EditText) findViewById(R.id.repository); 77 | String repoName = repo.getText().toString(); 78 | 79 | EditText title = (EditText) findViewById(R.id.title); 80 | String titleText = title.getText().toString(); 81 | 82 | doPost(repoName, titleText, postContents); 83 | } 84 | }); 85 | } 86 | 87 | class LoginTask extends AsyncTask { 88 | @Override 89 | protected Boolean doInBackground(String... credentials) { 90 | boolean rv = false; 91 | UserService us = new UserService(); 92 | us.getClient().setCredentials( credentials[0], credentials[1] ); 93 | try { 94 | User user = us.getUser( credentials[0] ); 95 | rv = null != user; 96 | } 97 | catch( IOException ioe ) {} 98 | return rv; 99 | } 100 | 101 | @Override 102 | protected void onPostExecute(Boolean result) { 103 | if( result ) { 104 | loggedIn(); 105 | } 106 | else { 107 | TextView status = (TextView)findViewById( R.id.login_status ); 108 | status.setText( "Invalid login, please check credentials" ); 109 | } 110 | } 111 | } 112 | 113 | private void doPost( String repoName, String title, String post ) { 114 | new PostTask().execute( username, password, repoName, title, post ); 115 | } 116 | 117 | class PostTask extends AsyncTask { 118 | 119 | @Override 120 | protected Boolean doInBackground(String... information) { 121 | String login = information[0]; 122 | String password = information[1]; 123 | String repoName = information[2]; 124 | String titleText = information[3]; 125 | String postContents = information[4]; 126 | 127 | Boolean rv = false; 128 | GitHubHelper ghh = new GitHubHelper(login, password); 129 | try { 130 | rv = ghh.SaveFile(repoName, titleText, postContents, "GhRu Update"); 131 | } catch (IOException ioe) { 132 | Log.d(ioe.getStackTrace().toString(), "GhRu"); 133 | } 134 | return rv; 135 | } 136 | 137 | @Override 138 | protected void onPostExecute(Boolean result) { 139 | TextView status = (TextView) findViewById(R.id.status); 140 | if (result) { 141 | status.setText("Successful jekyll post"); 142 | 143 | EditText post = (EditText) findViewById(R.id.post); 144 | post.setText(""); 145 | 146 | EditText repo = (EditText) findViewById(R.id.repository); 147 | repo.setText(""); 148 | 149 | EditText title = (EditText) findViewById(R.id.title); 150 | title.setText(""); 151 | } else { 152 | status.setText("Post failed."); 153 | } 154 | } 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /chapter-7-android-and-git-data/app/src/main/res/layout/logged_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 14 | 21 | 22 | 28 | 29 | 37 | 38 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /chapter-9-javascript-and-git-data/karma.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | basePath: '', 4 | frameworks: ['jasmine'], 5 | files: [ 6 | 'angular.js', 7 | 'fixtures-*.js', 8 | 'angular-mocks.js', 9 | 'firebase-mock.js', 10 | 'github.js', 11 | '*.js' 12 | ], 13 | reporters: ['progress'], 14 | port: 9876, 15 | colors: true, 16 | logLevel: config.LOG_INFO, 17 | autoWatch: true, 18 | browsers: ['Chrome'], 19 | captureTimeout: 60000, 20 | singleRun: false 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /chapter-9-javascript-and-git-data/node/github-local-login.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | , passport = require('passport') 3 | , util = require('util') 4 | , GitHubStrategy = require('passport-github').Strategy; 5 | 6 | var GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID 7 | var GITHUB_CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET; 8 | 9 | var authTokens = {}; 10 | 11 | // Passport session setup. 12 | // To support persistent login sessions, Passport needs to be able to 13 | // serialize users into and deserialize users out of the session. Typically, 14 | // this will be as simple as storing the user ID when serializing, and finding 15 | // the user by ID when deserializing. However, since this example does not 16 | // have a database of user records, the complete GitHub profile is serialized 17 | // and deserialized. 18 | passport.serializeUser(function(user, done) { 19 | done(null, user); 20 | }); 21 | 22 | passport.deserializeUser(function(obj, done) { 23 | done(null, obj); 24 | }); 25 | 26 | // Use the GitHubStrategy within Passport. 27 | // Strategies in Passport require a `verify` function, which accept 28 | // credentials (in this case, an accessToken, refreshToken, and GitHub 29 | // profile), and invoke a callback with a user object. 30 | passport.use(new GitHubStrategy({ 31 | clientID: GITHUB_CLIENT_ID, 32 | clientSecret: GITHUB_CLIENT_SECRET, 33 | callbackURL: "http://localhost:3000/auth/github/callback" 34 | }, 35 | function(accessToken, refreshToken, profile, done) { 36 | authTokens[profile.id] = accessToken; 37 | // asynchronous verification, for effect... 38 | //process.nextTick(function () { 39 | 40 | // To keep the example simple, the user's GitHub profile is returned to 41 | // represent the logged-in user. In a typical application, you would want 42 | // to associate the GitHub account with a user record in your database, 43 | // and return that user instead. 44 | return done(null, profile); 45 | //}); 46 | } 47 | )); 48 | 49 | var app = express.createServer(); 50 | 51 | // configure Express 52 | app.configure(function() { 53 | app.set('views', __dirname + '/views'); 54 | app.set('view engine', 'ejs'); 55 | app.use(express.logger()); 56 | app.use(express.cookieParser()); 57 | app.use(express.bodyParser()); 58 | app.use(express.methodOverride()); 59 | app.use(express.session({ secret: 'keyboard cat' })); 60 | // Initialize Passport! Also use passport.session() middleware, to support 61 | // persistent login sessions (recommended). 62 | app.use(passport.initialize()); 63 | app.use(passport.session()); 64 | app.use(app.router); 65 | app.use(express.static(__dirname + '/public')); 66 | }); 67 | 68 | app.get( '/token.js', 69 | function(req, res) { 70 | res.send( "var ctAuthToken = '" + req.session.token + "';" ); 71 | } 72 | ); 73 | 74 | app.get('/', function(req, res){ 75 | res.render('index', { user: req.user }); 76 | }); 77 | 78 | app.get('/account', ensureAuthenticated, function(req, res){ 79 | res.render('account', { user: req.user }); 80 | }); 81 | 82 | app.get('/login', function(req, res){ 83 | res.render('login', { user: req.user }); 84 | }); 85 | 86 | // GET /auth/github 87 | // Use passport.authenticate() as route middleware to authenticate the 88 | // request. The first step in GitHub authentication will involve redirecting 89 | // the user to github.com. After authorization, GitHubwill redirect the user 90 | // back to this application at /auth/github/callback 91 | app.get('/auth/github', 92 | passport.authenticate('github'), 93 | function(req, res){ 94 | // The request will be redirected to GitHub for authentication, so this 95 | // function will not be called. 96 | }); 97 | 98 | // GET /auth/github/callback 99 | // Use passport.authenticate() as route middleware to authenticate the 100 | // request. If authentication fails, the user will be redirected back to the 101 | // login page. Otherwise, the primary route function function will be called, 102 | // which, in this example, will redirect the user to the home page. 103 | app.get('/auth/github/callback', 104 | passport.authenticate('github', { failureRedirect: '/login' }), 105 | function(req, res) { 106 | console.log( "auth token here: ", authTokens[req.user.id] ); 107 | req.session.token = authTokens[req.user.id]; 108 | res.redirect('/'); 109 | }); 110 | 111 | app.get('/logout', function(req, res){ 112 | req.logout(); 113 | res.redirect('/'); 114 | }); 115 | 116 | app.listen(3000); 117 | 118 | 119 | // Simple route middleware to ensure user is authenticated. 120 | // Use this route middleware on any resource that needs to be protected. If 121 | // the request is authenticated (typically via a persistent login session), 122 | // the request will proceed. Otherwise, the user will be redirected to the 123 | // login page. 124 | function ensureAuthenticated(req, res, next) { 125 | if (req.isAuthenticated()) { return next(); } 126 | res.redirect('/login') 127 | } 128 | -------------------------------------------------------------------------------- /chapter-9-javascript-and-git-data/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coffeetech", 3 | "description": "karma testing for coffeetech", 4 | "version": "0.0.1", 5 | "homepage": "http://spa.coffeete.ch", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/xrd/building-tools-with-github.git" 9 | }, 10 | "author": "Chris Dawson (https://github.com/xrd/)", 11 | "keywords": [ 12 | "github" 13 | ], 14 | "scripts" : { 15 | "test" : "karma start karma.config.js" 16 | }, 17 | "main": "./gihub-local-login.js", 18 | "dependencies": { 19 | "karma": "~0.12.0", 20 | "karma-jasmine": "~0.2.0", 21 | "karma-chrome-launcher": "0.2.2" 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /chapter-9-javascript-and-git-data/portland.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "information" : [ 4 | "offers gluten free desserts", 5 | "free wifi", 6 | "accepts dogs" 7 | ], 8 | "longitude" : -122.643074, 9 | "latitude" : 45.52292, 10 | "name" : "Very Good Coffee Shop" 11 | }, 12 | { 13 | "latitude" : 45.522181, 14 | "name" : "Very Bad Coffee Shop", 15 | "longitude" : -122.63709 16 | }, 17 | { 18 | "name" : "Mediocre Coffee Shop", 19 | "latitude" : 45.520437, 20 | "longitude" : -122.67846 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /chapter-9-javascript-and-git-data/spec/requestSpec.coffee: -------------------------------------------------------------------------------- 1 | helper = require './spec-helper' 2 | 3 | describe "App", -> 4 | describe "get /", -> 5 | it "responds successfully", -> 6 | helper.withServer (r, done) -> 7 | r.get "/token.json", (err, res, body) -> 8 | expect(res.statusCode).toEqual 200 9 | done() 10 | 11 | # it "has the correct body", -> 12 | # helper.withServer (r, done) -> 13 | # r.get "/", (err, res, body) -> 14 | # expect(body).toEqual "Hello, world!" 15 | # done() 16 | 17 | # describe "post /", -> 18 | # it "has the correct body", -> 19 | # helper.withServer (r, done) -> 20 | # r.post "/", "post body", (err, res, body) -> 21 | # expect(body).toEqual "You posted!" 22 | # done() 23 | -------------------------------------------------------------------------------- /chapter-9-javascript-and-git-data/spec/spec-helper.coffee: -------------------------------------------------------------------------------- 1 | request = require "request" 2 | 3 | class Requester 4 | get: (path, callback) -> 5 | request "http://localhost:3000#{path}", callback 6 | 7 | post: (path, body, callback) -> 8 | request.post {url: "http://localhost:3000#{path}", body: body}, callback 9 | 10 | exports.withServer = (callback) -> 11 | asyncSpecWait() 12 | 13 | {app} = require "../github-local-login" 14 | 15 | stopServer = -> 16 | app.close() 17 | asyncSpecDone() 18 | 19 | app.listen 3000 20 | 21 | callback new Requester, stopServer 22 | --------------------------------------------------------------------------------