summaryrefslogtreecommitdiffstats
path: root/vendor/diff-display
diff options
context:
space:
mode:
authorJohan Sørensen <johan@johansorensen.com>2008-02-03 20:20:49 +0100
committerJohan Sørensen <johan@johansorensen.com>2008-02-03 20:20:49 +0100
commit49a2c203531d114059cde68488f5ef17b07c8ed4 (patch)
tree253ab0c4c310838e04f81f22d5d5acfba3cb6e58 /vendor/diff-display
parentab96ec0f2c159a3b01633a2dd7f12c77f8000e5d (diff)
downloadgitorious-mainline-outdated-49a2c203531d114059cde68488f5ef17b07c8ed4.zip
gitorious-mainline-outdated-49a2c203531d114059cde68488f5ef17b07c8ed4.tar.gz
gitorious-mainline-outdated-49a2c203531d114059cde68488f5ef17b07c8ed4.tar.bz2
Refactored Diff::Display classes
Diffstat (limited to 'vendor/diff-display')
-rw-r--r--vendor/diff-display/History.txt4
-rw-r--r--vendor/diff-display/License.txt (renamed from vendor/diff-display/LICENSE)3
-rw-r--r--vendor/diff-display/Manifest.txt26
-rw-r--r--vendor/diff-display/README1
-rw-r--r--vendor/diff-display/README.txt2
-rw-r--r--vendor/diff-display/Rakefile17
-rw-r--r--vendor/diff-display/config/hoe.rb71
-rw-r--r--vendor/diff-display/config/requirements.rb17
-rw-r--r--vendor/diff-display/doc/.gitignore0
-rw-r--r--vendor/diff-display/lib/diff-display.rb14
-rw-r--r--vendor/diff-display/lib/diff/display/data_structure.rb118
-rw-r--r--vendor/diff-display/lib/diff/display/unified.rb649
-rw-r--r--vendor/diff-display/lib/diff/display/unified/generator.rb218
-rw-r--r--vendor/diff-display/lib/diff/display/version.rb11
-rw-r--r--vendor/diff-display/lib/diff/renderer/base.rb80
-rw-r--r--vendor/diff-display/lib/diff/renderer/diff.rb25
-rwxr-xr-xvendor/diff-display/script/destroy14
-rwxr-xr-xvendor/diff-display/script/generate14
-rwxr-xr-xvendor/diff-display/script/txt2html74
-rw-r--r--vendor/diff-display/setup.rb1585
-rw-r--r--vendor/diff-display/spec/api_spec.rb10
-rw-r--r--vendor/diff-display/spec/data_structure_spec.rb75
-rw-r--r--vendor/diff-display/spec/fixtures/big.diff (renamed from vendor/diff-display/test/diffs/huge_diff)0
-rw-r--r--vendor/diff-display/spec/fixtures/multiple_adds_after_rem.diff (renamed from vendor/diff-display/test/diffs/edgecase1_diff.diff)0
-rw-r--r--vendor/diff-display/spec/fixtures/only_add.diff4
-rw-r--r--vendor/diff-display/spec/fixtures/only_rem.diff4
-rw-r--r--vendor/diff-display/spec/fixtures/simple.diff12
-rw-r--r--vendor/diff-display/spec/generator_spec.rb35
-rw-r--r--vendor/diff-display/spec/renderer/base_spec.rb98
-rw-r--r--vendor/diff-display/spec/renderer/diff_spec.rb9
-rw-r--r--vendor/diff-display/spec/spec.opts1
-rw-r--r--vendor/diff-display/spec/spec_helper.rb20
-rw-r--r--vendor/diff-display/spec/unified_spec.rb21
-rw-r--r--vendor/diff-display/tasks/deployment.rake34
-rw-r--r--vendor/diff-display/tasks/environment.rake7
-rw-r--r--vendor/diff-display/tasks/rspec.rake21
-rw-r--r--vendor/diff-display/tasks/website.rake17
-rw-r--r--vendor/diff-display/test/.tc_diff_display_unified.rb.swpbin12288 -> 0 bytes
-rw-r--r--vendor/diff-display/test/abstract_unit.rb52
-rw-r--r--vendor/diff-display/test/diff_display_unified_test.rb33
-rw-r--r--vendor/diff-display/test/diffs/inline_changes.changes43
-rw-r--r--vendor/diff-display/test/diffs/inline_changes.diff35
-rw-r--r--vendor/diff-display/test/diffs/inline_changes.orig43
-rw-r--r--vendor/diff-display/test/diffs/plain_text.changed7
-rw-r--r--vendor/diff-display/test/diffs/plain_text.diff16
-rw-r--r--vendor/diff-display/test/diffs/plain_text.orig8
-rw-r--r--vendor/diff-display/test/parity_between_diff_and_data_test.rb26
-rw-r--r--vendor/diff-display/website/index.html11
-rw-r--r--vendor/diff-display/website/index.txt39
-rw-r--r--vendor/diff-display/website/javascripts/rounded_corners_lite.inc.js285
-rw-r--r--vendor/diff-display/website/stylesheets/screen.css138
-rw-r--r--vendor/diff-display/website/template.rhtml48
52 files changed, 3180 insertions, 915 deletions
diff --git a/vendor/diff-display/History.txt b/vendor/diff-display/History.txt
new file mode 100644
index 0000000..0ed7358
--- /dev/null
+++ b/vendor/diff-display/History.txt
@@ -0,0 +1,4 @@
+== 0.0.1 2008-01-28
+
+* 1 major enhancement:
+ * Initial release
diff --git a/vendor/diff-display/LICENSE b/vendor/diff-display/License.txt
index 1828d96..169dd23 100644
--- a/vendor/diff-display/LICENSE
+++ b/vendor/diff-display/License.txt
@@ -1,3 +1,4 @@
+Copyright (c) 2008 Johan Sørensen
Copyright (c) 2003 Marcel Molina Jr.
Permission is hereby granted, free of charge, to any person obtaining
@@ -17,4 +18,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/vendor/diff-display/Manifest.txt b/vendor/diff-display/Manifest.txt
new file mode 100644
index 0000000..4964e01
--- /dev/null
+++ b/vendor/diff-display/Manifest.txt
@@ -0,0 +1,26 @@
+History.txt
+License.txt
+Manifest.txt
+README.txt
+Rakefile
+config/hoe.rb
+config/requirements.rb
+lib/diff-display.rb
+lib/diff-display/version.rb
+log/debug.log
+script/destroy
+script/generate
+script/txt2html
+setup.rb
+spec/diff-display_spec.rb
+spec/spec.opts
+spec/spec_helper.rb
+tasks/deployment.rake
+tasks/environment.rake
+tasks/rspec.rake
+tasks/website.rake
+website/index.html
+website/index.txt
+website/javascripts/rounded_corners_lite.inc.js
+website/stylesheets/screen.css
+website/template.rhtml
diff --git a/vendor/diff-display/README b/vendor/diff-display/README
deleted file mode 100644
index f978725..0000000
--- a/vendor/diff-display/README
+++ /dev/null
@@ -1 +0,0 @@
-Marcel Molina Jr. wrote this library probably back in 2004 or so. \ No newline at end of file
diff --git a/vendor/diff-display/README.txt b/vendor/diff-display/README.txt
new file mode 100644
index 0000000..17b43e3
--- /dev/null
+++ b/vendor/diff-display/README.txt
@@ -0,0 +1,2 @@
+Rewrite of an (unreleased) library by Marcel Molina Jr., who wrote this it
+probably back in 2004 or so. \ No newline at end of file
diff --git a/vendor/diff-display/Rakefile b/vendor/diff-display/Rakefile
index a992271..e469154 100644
--- a/vendor/diff-display/Rakefile
+++ b/vendor/diff-display/Rakefile
@@ -1,13 +1,4 @@
-require 'rake'
-require 'rake/testtask'
-require 'rake/rdoctask'
-
-desc 'Default: run unit tests.'
-task :default => :test
-
-desc 'Test the resource_paths plugin.'
-Rake::TestTask.new(:test) do |t|
- t.libs << 'lib'
- t.pattern = 'test/**/*_test.rb'
- t.verbose = true
-end \ No newline at end of file
+require 'config/requirements'
+require 'config/hoe' # setup Hoe + all gem configuration
+
+Dir['tasks/**/*.rake'].each { |rake| load rake } \ No newline at end of file
diff --git a/vendor/diff-display/config/hoe.rb b/vendor/diff-display/config/hoe.rb
new file mode 100644
index 0000000..bf36c45
--- /dev/null
+++ b/vendor/diff-display/config/hoe.rb
@@ -0,0 +1,71 @@
+require 'diff/display/version'
+
+AUTHOR = ['Johan Sørensen', 'Marcel Molina Jr.'] # can also be an array of Authors
+EMAIL = "johan@johansorensen.com"
+DESCRIPTION = "Displays a unified diffs in various (user-definable) ways"
+GEM_NAME = 'diff-display' # what ppl will type to install your gem
+RUBYFORGE_PROJECT = 'diff-display' # The unix name for your project
+HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
+DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
+
+@config_file = "~/.rubyforge/user-config.yml"
+@config = nil
+RUBYFORGE_USERNAME = "unknown"
+def rubyforge_username
+ unless @config
+ begin
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
+ rescue
+ puts <<-EOS
+ERROR: No rubyforge config file found: #{@config_file}
+Run 'rubyforge setup' to prepare your env for access to Rubyforge
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
+ EOS
+ exit
+ end
+ end
+ RUBYFORGE_USERNAME.replace @config["username"]
+end
+
+
+REV = nil
+# UNCOMMENT IF REQUIRED:
+# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
+VERS = Diff::Display::VERSION::STRING + (REV ? ".#{REV}" : "")
+RDOC_OPTS = ['--quiet', '--title', 'diff-display documentation',
+ "--opname", "index.html",
+ "--line-numbers",
+ "--main", "README",
+ "--inline-source"]
+
+class Hoe
+ def extra_deps
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
+ @extra_deps
+ end
+end
+
+# Generate all the Rake tasks
+# Run 'rake -T' to see list of generated tasks (from gem root directory)
+hoe = Hoe.new(GEM_NAME, VERS) do |p|
+ p.author = AUTHOR
+ p.description = DESCRIPTION
+ p.email = EMAIL
+ p.summary = DESCRIPTION
+ p.url = HOMEPATH
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
+ p.test_globs = ["test/**/test_*.rb"]
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
+
+ # == Optional
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
+
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
+
+end
+
+CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
+PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
+hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
+hoe.rsync_args = '-av --delete --ignore-errors' \ No newline at end of file
diff --git a/vendor/diff-display/config/requirements.rb b/vendor/diff-display/config/requirements.rb
new file mode 100644
index 0000000..b6e36b2
--- /dev/null
+++ b/vendor/diff-display/config/requirements.rb
@@ -0,0 +1,17 @@
+require 'fileutils'
+include FileUtils
+
+require 'rubygems'
+%w[rake hoe newgem rubigen].each do |req_gem|
+ begin
+ require req_gem
+ rescue LoadError
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
+ puts "Installation: gem install #{req_gem} -y"
+ exit
+ end
+end
+
+$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
+
+require 'diff-display' \ No newline at end of file
diff --git a/vendor/diff-display/doc/.gitignore b/vendor/diff-display/doc/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vendor/diff-display/doc/.gitignore
diff --git a/vendor/diff-display/lib/diff-display.rb b/vendor/diff-display/lib/diff-display.rb
new file mode 100644
index 0000000..2be63c6
--- /dev/null
+++ b/vendor/diff-display/lib/diff-display.rb
@@ -0,0 +1,14 @@
+$:.unshift File.dirname(__FILE__)
+
+module Diff
+ module Display
+ end
+end
+
+require "diff/display/version"
+require "diff/display/data_structure"
+require "diff/display/unified"
+require "diff/display/unified/generator"
+
+require "diff/renderer/base"
+require "diff/renderer/diff" \ No newline at end of file
diff --git a/vendor/diff-display/lib/diff/display/data_structure.rb b/vendor/diff-display/lib/diff/display/data_structure.rb
new file mode 100644
index 0000000..3ef3c90
--- /dev/null
+++ b/vendor/diff-display/lib/diff/display/data_structure.rb
@@ -0,0 +1,118 @@
+module Diff
+ module Display
+ class Data < Array
+ def initialize
+ super
+ end
+
+ def to_diff
+ diff = ""
+ each do |block|
+ block.each do |line|
+ case line
+ when HeaderLine
+ diff << "#{line}\n"
+ when UnModLine
+ diff << " #{line}\n"
+ when SepLine
+ diff << "\n"
+ when AddLine
+ diff << "+#{line}\n"
+ when RemLine
+ diff << "-#{line}\n"
+ end
+ end
+ end
+ diff.chomp
+ end
+ end
+
+ # Every line from the passed in diff gets transformed into an instance of
+ # one of line Line class's subclasses. One subclass exists for each line
+ # type in a diff. As such there is an AddLine class for added lines, a RemLine
+ # class for removed lines, an UnModLine class for lines which remain unchanged and
+ # a SepLine class which represents all the lines that aren't part of the diff.
+ class Line < String
+ class << self
+ def add(line, line_number)
+ AddLine.new(line, line_number)
+ end
+
+ def rem(line, line_number)
+ RemLine.new(line, line_number)
+ end
+
+ def unmod(line, line_number)
+ UnModLine.new(line, line_number)
+ end
+
+ def header(line)
+ HeaderLine.new(line)
+ end
+ end
+
+ def initialize(line, line_number)
+ super(line)
+ @number = line_number
+ end
+ attr_reader :number
+ end
+
+ class AddLine < Line
+ def initialize(line, line_number)
+ super(line, line_number)
+ end
+ end
+
+ class RemLine < Line
+ def initialize(line, line_number)
+ super(line, line_number)
+ end
+ end
+
+ class UnModLine < Line
+ def initialize(line, line_number)
+ super(line, line_number)
+ end
+ end
+
+ class SepLine < Line
+ def initialize(line = '...')
+ super(line, nil)
+ end
+ end
+
+ class HeaderLine < Line
+ def initialize(line)
+ super(line, nil)
+ end
+ end
+
+ # This class is an array which contains Line objects. Just like Line
+ # classes, several Block classes inherit from Block. If all the lines
+ # in the block are added lines then it is an AddBlock. If all lines
+ # in the block are removed lines then it is a RemBlock. If the lines
+ # in the block are all unmodified then it is an UnMod block. If the
+ # lines in the block are a mixture of added and removed lines then
+ # it is a ModBlock. There are no blocks that contain a mixture of
+ # modified and unmodified lines.
+ class Block < Array
+ class << self
+ def add; AddBlock.new end
+ def rem; RemBlock.new end
+ def mod; ModBlock.new end
+ def unmod; UnModBlock.new end
+ def header; HeaderBlock.new end
+ end
+ end
+
+ #:stopdoc:#
+ class AddBlock < Block; end
+ class RemBlock < Block; end
+ class ModBlock < Block; end
+ class UnModBlock < Block; end
+ class SepBlock < Block; end
+ class HeaderBlock < Block; end
+ #:startdoc:#
+ end
+end \ No newline at end of file
diff --git a/vendor/diff-display/lib/diff/display/unified.rb b/vendor/diff-display/lib/diff/display/unified.rb
index 371030a..b5e0169 100644
--- a/vendor/diff-display/lib/diff/display/unified.rb
+++ b/vendor/diff-display/lib/diff/display/unified.rb
@@ -1,640 +1,15 @@
-module Diff #:nodoc:#
- module Display #:nodoc:#
- # = Diff::Display::Unified
- #
- # Diff::Display::Unified is meant to make dealing with the presentation of
- # diffs easy, customizable and succinct. It breaks a diff up into sections,
- # or blocks, which are defined by the types of lines they contain. If, for
- # example, there is a section where five lines have been added then an
- # AddBlock is created and those five lines are placed into that AddBlock.
- # The design is quite simple: The generated object is made up of Block
- # objects which are themselves made up of Line objects.
- #
- # === Blocks
- #
- # Blocks represent various sections that one finds in a diff.
- # There are five different Block classes:
- #
- # [AddBlock]
- # Contains only instances of AddLine
- #
- # [RemBlock]
- # Contains only instances of RemLine
- #
- # [ModBlock]
- # Contains a set of RemLine objects followed by a set of AddLine
- # objects
- #
- # [UnModBlock]
- # Contains instances of UnModLine which represent sets of context lines
- # that are unchanged in both the old and modified data set that
- # surround Mod, Add or Rem blocks
- #
- # [SepBlock]
- # Contains a single SepLine. SepBlocks are placed between blocks when
- # the distances between one modification set and the next exceeds the
- # number of context buffer surrounding them.
- #
- # === Lines
- #
- # The Line classes are much line the Block classes, just on a smaller
- # scale.
- #
- # There are 4 lines classes:
- #
- # === Example
- #
- # Consider the following before and after on a diff.
- #
- # Before:
- #
- # - class OldName < Array
- # + class NewName < Array
- #
- # - def initialize(boundry)
- # - @boundry = boundry
- # - end
- # -
- # def stay(the, same)
- # + end
- # +
- # + def all_new
- # + @this, @method = *IS_ALL_NEW
- #
- # After:
- #
- # ---------------------------------------- ModBlock
- # 1 [RemLine] class OldName < Array
- # 1 [AddLine] class NewName < Array
- # ----------------------------------------
- #
- # ---------------------------------------- UnModBlock
- # 2 [UnModLine]
- # ----------------------------------------
- #
- # ---------------------------------------- RemBlock
- # 3 [RemLine] def initialize(boundry)
- # 4 [RemLine] @boundry = boundry
- # 5 [RemLine] end
- # 6 [RemLine]
- # ----------------------------------------
- #
- # ---------------------------------------- UnModBlock
- # 7 [UnModLine] def stay(the, same)
- # ----------------------------------------
- #
- # ---------------------------------------- AddBlock
- # 8 [AddLine] end
- # 9 [AddLine]
- # 10 [AddLine] def all_new
- # 11 [AddLine] @this, @method = -IS_ALL_NEW
- # ----------------------------------------
- #
- # Note: That is just a representation of the structure of the generated
- # object. Also note that this example does not include any SepBlocks since
- # the changes in the example diff are all contiguous.
- #
- # Internally the datastructure is quite simple: The Data object has an
- # array of Block objects which themselves have an array of Line
- # objects. Traversing the object on the block level or line level is
- # equally simple so you can focus on what to do for each type of block and
- # line.
- module Unified
- # Every line from the passed in diff gets transformed into an instance of
- # one of line Line class's subclasses. One subclass exists for each line
- # type in a diff. As such there is an AddLine class for added lines, a RemLine
- # class for removed lines, an UnModLine class for lines which remain unchanged and
- # a SepLine class which represents all the lines that aren't part of the diff.
- class Line < String
- def initialize(line, line_number)
- super(line)
- @line_number = line_number
- self
- end
-
- def contains_inline_change?
- @inline
- end
-
- # Returns the line number of the diff line
- def number
- @line_number
- end
-
- def decorate(&block)
- yield self
- end
-
- protected
-
- def inline_add_open; '' end
- def inline_add_close; '' end
- def inline_rem_open; '' end
- def inline_rem_close; '' end
-
- def escape
- self
- end
-
- def expand
- escape.gsub("\t", ' ' * tabwidth).gsub(/ ( +)|^ /) do |match|
- (space + ' ') * (match.size / 2) +
- space * (match.size % 2)
- end
- end
-
- def tabwidth
- 4
- end
-
-
- def space
- ' '
- end
-
- class << self
- def add(line, line_number, inline = false)
- AddLine.new(line, line_number, inline)
- end
-
- def rem(line, line_number, inline = false)
- RemLine.new(line, line_number, inline)
- end
-
- def unmod(line, line_number)
- UnModLine.new(line, line_number)
- end
- end
+module Diff
+ module Display
+ class Unified
+ def initialize(udiff)
+ @data = Diff::Display::Unified::Generator.run(udiff)
+ end
+ attr_reader :data
+
+ def render(renderer, out="")
+ out << renderer.render(data)
+ out
end
-
- class AddLine < Line #:nodoc:#
- def initialize(line, line_number, inline = false)
- #line = inline ? line % [inline_add_open, inline_add_close] : line
- super(line, line_number)
- @inline = inline
- self
- end
- end
-
- class RemLine < Line #:nodoc:#
- def initialize(line, line_number, inline = false)
- #line = inline ? line % [inline_rem_open, inline_rem_close] : line
- super(line, line_number)
- @inline = inline
- self
- end
- end
-
- class UnModLine < Line #:nodoc:#
- def initialize(line, line_number)
- super(line, line_number)
- end
- end
-
- class SepLine < Line #:nodoc:#
- def initialize(line = '...')
- super(line, nil)
- end
- end
-
- # This class is an array which contains Line objects. Just like Line
- # classes, several Block classes inherit from Block. If all the lines
- # in the block are added lines then it is an AddBlock. If all lines
- # in the block are removed lines then it is a RemBlock. If the lines
- # in the block are all unmodified then it is an UnMod block. If the
- # lines in the block are a mixture of added and removed lines then
- # it is a ModBlock. There are no blocks that contain a mixture of
- # modified and unmodified lines.
- class Block < Array
- def initialize
- super
- end
-
- def <<(line_object)
- super(line_object)
- self
- end
-
- def decorate(&block)
- yield self
- end
-
- class << self
- def add; AddBlock.new end
- def rem; RemBlock.new end
- def mod; ModBlock.new end
- def unmod; UnModBlock.new end
- end
- end
-
- #:stopdoc:#
- class AddBlock < Block; end
- class RemBlock < Block; end
- class ModBlock < Block; end
- class UnModBlock < Block; end
- class SepBlock < Block; end
- #:startdoc:#
-
- # A Data object contains the generated diff data structure. It is an
- # array of Block objects which are themselves arrays of Line objects. The
- # Generator class returns a Data instance object after it is done
- # processing the diff.
- class Data < Array
- def initialize
- super
- end
-
- def debug
- demodularize = Proc.new {|obj| obj.class.name[/\w+$/]}
- each do |diff_block|
- print "-" * 40, ' ', demodularize.call(diff_block)
- puts
- puts diff_block.map {|line|
- "%5d" % line.number +
- " [#{demodularize.call(line)}]" +
- line
- }.join("\n")
- puts "-" * 40, ' '
- end
- end
-
- end
-
- # Processes the diff and generates a Data object which contains the
- # resulting data structure.
- #
- # The +run+ class method is fed a diff and returns a Data object. It will
- # accept as its argument a String, an Array or a File object:
- #
- # Diff::Display::Unified::Generator.run(diff)
- #
- class Generator
-
- # Extracts the line number info for a given diff section
- LINE_NUM_RE = /@@ [+-]([0-9]+),([0-9]+) [+-]([0-9]+),([0-9]+) @@/
- LINE_TYPES = {'+' => :add, '-' => :rem, ' ' => :unmod}
-
- class << self
-
- # Runs the generator on a diff and returns a Data object without
- # instantiating a Generator object
- def run(udiff)
- raise ArgumentError, "Object must be enumerable" unless udiff.respond_to?(:each)
- generator = new
- udiff.each {|line| generator.process(line.chomp)}
- generator.data
- end
- end
-
- def initialize
- @buffer = []
- @prev_buffer = []
- @line_type = nil
- @prev_line_type = nil
- @offset_base = 0
- @offset_changed = 0
- @data = Diff::Display::Unified::Data.new
- self
- end
-
- # Operates on a single line from the diff and passes along the
- # collected data to the appropriate method for further processing. The
- # cycle of processing is in general:
- #
- # process --> identify_block --> process_block --> process_line
- #
- def process(line)
- return if is_extra_header_line?(line)
-
- if match = LINE_NUM_RE.match(line)
- identify_block
- add_separator unless @offset_changed.zero?
- @line_type = nil
- @offset_base = match[1].to_i - 1
- @offset_changed = match[3].to_i - 1
- return
- end
-
- new_line_type, line = LINE_TYPES[car(line)], cdr(line)
-
- # Add line to the buffer if it's the same diff line type
- # as the previous line
- #
- # e.g.
- #
- # + This is a new line
- # + As is this one
- # + And yet another one...
- #
- if new_line_type.eql?(@line_type)
- @buffer.push(line)
- else
- # Side by side inline diff
- #
- # e.g.
- #
- # - This line just had to go
- # + This line is on the way in
- #
- if new_line_type.eql?(LINE_TYPES['+']) and @line_type.eql?(LINE_TYPES['-'])
- @prev_buffer = @buffer
- @prev_line_type = @line_type
- else
- identify_block
- end
- @buffer = [line]
- @line_type = new_line_type
- end
- end
-
- # Finishes up with the generation and returns the Data object (could
- # probably use a better name...maybe just #data?)
- def data
- close
- @data
- end
-
- protected
-
- def is_extra_header_line?(line)
- return true if ['++', '--'].include?(line[0,2])
- return true if line =~ /^(new|delete) file mode [0-9]+$/
- return true if line =~ /^diff \-\-git/
- return true if line =~ /^index \w+\.\.\w+ [0-9]+$/
- false
- end
-
- def identify_block
- if @prev_line_type.eql?(LINE_TYPES['-']) and @line_type.eql?(LINE_TYPES['+'])
- process_block(:mod, true, true)
- else
- if LINE_TYPES.values.include?(@line_type)
- process_block(@line_type, true)
- end
- end
-
- @prev_line_type = nil
- end
-
- def process_block(diff_line_type, new = false, old = false)
- push Block.send(diff_line_type)
- # Mod block
- if diff_line_type.eql?(:mod) && @prev_buffer.size && @buffer.size == 1
- process_line(@prev_buffer.first, @buffer.first)
- return
- end
- unroll_prev_buffer if old
- unroll_buffer if new
- end
-
- # TODO Needs a better name...it does process a line (two in fact) but
- # its primary function is to add a Rem and an Add pair which
- # potentially have inline changes
- def process_line(oldline, newline)
- start, ending = get_change_extent(oldline, newline)
-
- # -
- line = inline_diff(oldline, start, ending)
- current_block << Line.rem(line, @offset_base += 1, true)
-
- # +
- line = inline_diff(newline, start, ending)
- current_block << Line.add(line, @offset_changed += 1, true)
- end
-
- # Inserts string formating characters around the section of a string
- # that differs internally from another line so that the Line class
- # can insert the desired formating
- def inline_diff(line, start, ending)
- # line[0, start] +
- # #'%s' + extract_change(line, start, ending) + '%s' +
- # extract_change(line, start, ending) +
- # line[ending, ending.abs]
- line
- end
-
- def add_separator
- push SepBlock.new
- current_block << SepLine.new
- end
-
- def extract_change(line, start, ending)
- line.size > (start - ending) ? line[start...ending] : ''
- end
-
- def car(line)
- line[0,1]
- end
-
- def cdr(line)
- line[1..-1]
- end
-
- # Returns the current Block object
- def current_block
- @data.last
- end
-
- # Adds a Line object onto the current Block object
- def push(line)
- @data.push line
- end
-
- def prev_buffer
- @prev_buffer
- end
-
- def unroll_prev_buffer
- return if @prev_buffer.empty?
- @prev_buffer.each do |line|
- @offset_base += 1
- current_block << Line.send(@prev_line_type, line, @offset_base)
- end
- end
-
- def unroll_buffer
- return if @buffer.empty?
- @buffer.each do |line|
- @offset_changed += 1
- current_block << Line.send(@line_type, line, @offset_changed)
- end
- end
-
- # This method is called once the generator is done with the unified
- # diff. It is a finalizer of sorts. By the time it is called all data
- # has been collected and processed.
- def close
- # certain things could be set now that processing is done
- identify_block
- end
-
- # Determines the extent of differences between two string. Returns
- # an array containing the offset at which changes start, and then
- # negative offset at which the chnages end. If the two strings have
- # neither a common prefix nor a common suffic, [0, 0] is returned.
- def get_change_extent(str1, str2)
- start = 0
- limit = [str1.size, str2.size].sort.first
- while start < limit and str1[start, 1] == str2[start, 1]
- start += 1
- end
- ending = -1
- limit -= start
- while -ending <= limit and str1[ending, 1] == str2[ending, 1]
- ending -= 1
- end
-
- return [start, ending + 1]
- end
- end
-
- # The Renderer class is the single point of entry for the
- # Diff::Display::Unified library. It can be used in two ways. One is to
- # create a new instance which returns a Data object created by the
- # Generator. This object contains the collections of Blocks and Lines
- # which the user can iterate over.
- #
- # data_object = Diff::Display::Unified::Renderer.new(diff)
- #
- # The second way is to call the Renderer's +run+ class method, optionally
- # passing in an instance of a class which inherits from
- # Diff::Display::Unified::Callbacks. This then calls the +render+ method
- # which uses the methods defined in the callback class instance to
- # decorate the diff contents as it unrolls the Data object.
- #
- # Somewhere up above:
- #
- # class MyDiffCallbacks < Diff::Display::Unified::Callbacks
- #
- # def before_addline '<ins>' end
- # def after_addline '</ins>' end
- #
- # end
- #
- # callback_obj = MyDiffCallbacks.new
- #
- # fully_rendered_diff = Diff::Display::Unified::Renderer.run(diff, callback_obj)
- #
- class Renderer
- attr_reader :data
-
- def initialize(diff, callback_object = nil)
- @callbacks = callback_object || Diff::Display::Unified::Callbacks.new
- @data = Diff::Display::Unified::Generator.run(diff)
- end
-
- # XXX The relationship between render and rendered and run is too complicated
- # and nuanced
- def render
- @rendered = @data.inject([]) do |block_data, block|
- block_data << before_method(block)
- # Block must use braces rather than do/end due to precedence rules!
- block_data.concat block.inject([]) { |line_data, line|
- line_data << before_method(line) << escape(line) << after_method(line)
- }
- block_data << after_method(block)
- end
- end
-
- def rendered
- (@rendered ? @rendered : render).join(new_line)
- end
-
- class << self
- def run(diff, callback_object = nil)
- new(diff, callback_object).rendered
- end
- end
-
- def escape(text)
- text
- end
-
- private
-
- def class_name(object)
- object.class.name[/\w+$/].downcase
- end
-
- def before_method(object)
- @callbacks.send('before_' + class_name(object), object)
- end
-
- def after_method(object)
- @callbacks.send('after_' + class_name(object), object)
- end
-
- def new_line
- @callbacks.new_line
- end
-
- end
-
- # Defines a set of callbacks which are triggered at various stages in the
- # Render class as the Data object is being unrolled. This class is meant
- # to be inherited from by classes that define costume behavior by
- # overriding methods to allow for the interpolation of arbitrary values
- # into the diff Data object as it is being rendered.
- #
- # Though this seems like good functionality for a module, being able to
- # define a class that inherits from this makes the interface for
- # customization easier. Suggestions for improvements are much
- # appreciated.
- class Callbacks
-
- #:stopdoc:#
- def before_addblock(block) '' end
- def before_remblock(block) '' end
- def before_modblock(block) '' end
- def before_unmodblock(block) '' end
- def before_sepblock(block) '' end
-
- def after_addblock(block) '' end
- def after_remblock(block) '' end
- def after_modblock(block) '' end
- def after_unmodblock(block) '' end
- def after_sepblock(block) '' end
-
- def before_addline(line) '' end
- def before_remline(line) '' end
- def before_modline(line) '' end
- def before_unmodline(line) '' end
- def before_sepline(line) '' end
-
- def after_addline(line) '' end
- def after_remline(line) '' end
- def after_modline(line) '' end
- def after_unmodline(line) '' end
- def after_sepline(line) '' end
-
- def new_line; "\n" end
- #:startdoc:#
- end
-
- #:stopdoc:#
- class DebugCallbacks
-
- def method_missing(sym, *params)
- sym.id2name
- end
-
- end
- #:startdoc:#
-
- # Renders with HTML as the target output (only effect is escaped lines)
- # callbacks will still need to escape any lines they output
- class HTMLRenderer < Renderer #:nodoc:#
-
- # escapes
- def escape(text)
- #CGI::escapeHTML(text)
- text.gsub('&', '&amp;').
- gsub('<', '&lt;' ).
- gsub('>', '&gt;' ).
- gsub('"', '&#34;')
- end
- end
-
end
end
-end
+end \ No newline at end of file
diff --git a/vendor/diff-display/lib/diff/display/unified/generator.rb b/vendor/diff-display/lib/diff/display/unified/generator.rb
new file mode 100644
index 0000000..9300dfb
--- /dev/null
+++ b/vendor/diff-display/lib/diff/display/unified/generator.rb
@@ -0,0 +1,218 @@
+module Diff::Display
+ # Processes the diff and generates a Data object which contains the
+ # resulting data structure.
+ #
+ # The +run+ class method is fed a diff and returns a Data object. It will
+ # accept as its argument a String, an Array or a File object (or anything
+ # that responds to #each):
+ #
+ # Diff::Display::Unified::Generator.run(diff)
+ #
+ class Unified::Generator
+
+ # Extracts the line number info for a given diff section
+ LINE_NUM_RE = /@@ [+-]([0-9]+)(?:,([0-9]+))? [+-]([0-9]+)(?:,([0-9]+))? @@/
+ LINE_TYPES = {'+' => :add, '-' => :rem, ' ' => :unmod}
+
+ # Runs the generator on a diff and returns a Data object
+ def self.run(udiff)
+ raise ArgumentError, "Object must be enumerable" unless udiff.respond_to?(:each)
+ generator = new
+ udiff.each {|line| generator.process(line.chomp)}
+ generator.data
+ end
+
+ def initialize
+ @buffer = []
+ @prev_buffer = []
+ @line_type = nil
+ @prev_line_type = nil
+ @offset_base = 0
+ @offset_changed = 0
+ @data = Data.new
+ self
+ end
+
+ # Finishes up with the generation and returns the Data object (could
+ # probably use a better name...maybe just #data?)
+ def data
+ close
+ @data
+ end
+
+ # Operates on a single line from the diff and passes along the
+ # collected data to the appropriate method for further processing. The
+ # cycle of processing is in general:
+ #
+ # process --> identify_block --> process_block --> process_line
+ #
+ def process(line)
+ if is_header_line?(line)
+ identify_block
+ push Block.header
+ current_block << Line.header(line)
+ return
+ end
+
+ if line =~ LINE_NUM_RE
+ identify_block
+ push Block.header
+ current_block << Line.header(line)
+ add_separator unless @offset_changed.zero?
+ @line_type = nil
+ @offset_base = $1.to_i - 1
+ @offset_changed = $3.to_i - 1
+ return
+ end
+
+ new_line_type, line = LINE_TYPES[car(line)], cdr(line)
+
+ # Add line to the buffer if it's the same diff line type
+ # as the previous line
+ #
+ # e.g.
+ #
+ # + This is a new line
+ # + As is this one
+ # + And yet another one...
+ #
+ if new_line_type.eql?(@line_type)
+ @buffer.push(line)
+ else
+ # Side by side inline diff
+ #
+ # e.g.
+ #
+ # - This line just had to go
+ # + This line is on the way in
+ #
+ if new_line_type.eql?(LINE_TYPES['+']) and @line_type.eql?(LINE_TYPES['-'])
+ @prev_buffer = @buffer
+ @prev_line_type = @line_type
+ else
+ identify_block
+ end
+ @buffer = [line]
+ @line_type = new_line_type
+ end
+
+ end
+
+ protected
+ def is_header_line?(line)
+ return true if ['++', '--'].include?(line[0,2])
+ return true if line =~ /^(new|delete) file mode [0-9]+$/
+ return true if line =~ /^diff \-\-git/
+ return true if line =~ /^index \w+\.\.\w+ [0-9]+$/
+ false
+ end
+
+ def identify_block
+ if @prev_line_type.eql?(LINE_TYPES['-']) and @line_type.eql?(LINE_TYPES['+'])
+ process_block(:mod, true, true)
+ else
+ if LINE_TYPES.values.include?(@line_type)
+ process_block(@line_type, true)
+ end
+ end
+
+ @prev_line_type = nil
+ end
+
+ def process_block(diff_line_type, new = false, old = false)
+ push Block.send(diff_line_type)
+ # Mod block
+ if diff_line_type.eql?(:mod) && @prev_buffer.size && @buffer.size == 1
+ process_line(@prev_buffer.first, @buffer.first)
+ return
+ end
+ unroll_prev_buffer if old
+ unroll_buffer if new
+ end
+
+ # TODO Needs a better name...it does process a line (two in fact) but
+ # its primary function is to add a Rem and an Add pair which
+ # potentially have inline changes
+ def process_line(oldline, newline)
+ # -
+ current_block << Line.rem(oldline, @offset_base += 1)
+
+ # +
+ current_block << Line.add(newline, @offset_changed += 1)
+ end
+
+ def add_separator
+ push SepBlock.new
+ current_block << SepLine.new
+ end
+
+ def extract_change(line, start, ending)
+ line.size > (start - ending) ? line[start...ending] : ''
+ end
+
+ def car(line)
+ line[0,1]
+ end
+
+ def cdr(line)
+ line[1..-1]
+ end
+
+ # Returns the current Block object
+ def current_block
+ @data.last
+ end
+
+ # Adds a Line object onto the current Block object
+ def push(line)
+ @data.push line
+ end
+
+ def prev_buffer
+ @prev_buffer
+ end
+
+ def unroll_prev_buffer
+ return if @prev_buffer.empty?
+ @prev_buffer.each do |line|
+ @offset_base += 1
+ current_block << Line.send(@prev_line_type, line, @offset_base)
+ end
+ end
+
+ def unroll_buffer
+ return if @buffer.empty?
+ @buffer.each do |line|
+ @offset_changed += 1
+ current_block << Line.send(@line_type, line, @offset_changed)
+ end
+ end
+
+ # This method is called once the generator is done with the unified
+ # diff. It is a finalizer of sorts. By the time it is called all data
+ # has been collected and processed.
+ def close
+ # certain things could be set now that processing is done
+ identify_block
+ end
+
+ # Determines the extent of differences between two string. Returns
+ # an array containing the offset at which changes start, and then
+ # negative offset at which the chnages end. If the two strings have
+ # neither a common prefix nor a common suffic, [0, 0] is returned.
+ def get_change_extent(str1, str2)
+ start = 0
+ limit = [str1.size, str2.size].sort.first
+ while start < limit and str1[start, 1] == str2[start, 1]
+ start += 1
+ end
+ ending = -1
+ limit -= start
+ while -ending <= limit and str1[ending, 1] == str2[ending, 1]
+ ending -= 1
+ end
+
+ return [start, ending + 1]
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/diff-display/lib/diff/display/version.rb b/vendor/diff-display/lib/diff/display/version.rb
new file mode 100644
index 0000000..96915e8
--- /dev/null
+++ b/vendor/diff-display/lib/diff/display/version.rb
@@ -0,0 +1,11 @@
+module Diff
+ module Display #:nodoc:
+ module VERSION #:nodoc:
+ MAJOR = 0
+ MINOR = 0
+ TINY = 1
+
+ STRING = [MAJOR, MINOR, TINY].join('.')
+ end
+ end
+end
diff --git a/vendor/diff-display/lib/diff/renderer/base.rb b/vendor/diff-display/lib/diff/renderer/base.rb
new file mode 100644
index 0000000..b858c11
--- /dev/null
+++ b/vendor/diff-display/lib/diff/renderer/base.rb
@@ -0,0 +1,80 @@
+module Diff
+ module Renderer
+ class Base
+ def render(data)
+ result = []
+ data.each do |block|
+ result << send("before_" + classify(block), block)
+ result << block.map { |line| send(classify(line), line) }
+ result << send("after_" + classify(block), block)
+ end
+ result.compact.join(new_line)
+ end
+
+ def before_headerblock(block)
+ end
+
+ def before_unmodblock(block)
+ end
+
+ def before_modblock(block)
+ end
+
+ def before_remblock(block)
+ end
+
+ def before_addblock(block)
+ end
+
+ def before_sepblock(block)
+ end
+
+ def headerline(line)
+ line
+ end
+
+ def unmodline(line)
+ line
+ end
+
+ def remline(line)
+ line
+ end
+
+ def addline(line)
+ line
+ end
+
+ def sepline(line)
+
+ end
+
+ def after_headerblock(block)
+ end
+
+ def after_unmodblock(block)
+ end
+
+ def after_modblock(block)
+ end
+
+ def after_remblock(block)
+ end
+
+ def after_addblock(block)
+ end
+
+ def after_sepblock(block)
+ end
+
+ def new_line
+ ""
+ end
+
+ protected
+ def classify(object)
+ object.class.name[/\w+$/].downcase
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/diff-display/lib/diff/renderer/diff.rb b/vendor/diff-display/lib/diff/renderer/diff.rb
new file mode 100644
index 0000000..9013930
--- /dev/null
+++ b/vendor/diff-display/lib/diff/renderer/diff.rb
@@ -0,0 +1,25 @@
+module Diff
+ module Renderer
+ class Diff < Base
+ def headerline(line)
+ line
+ end
+
+ def unmodline(line)
+ " #{line}"
+ end
+
+ def remline(line)
+ "-#{line}"
+ end
+
+ def addline(line)
+ "+#{line}"
+ end
+
+ def new_line
+ "\n"
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/diff-display/script/destroy b/vendor/diff-display/script/destroy
new file mode 100755
index 0000000..5fa7e10
--- /dev/null
+++ b/vendor/diff-display/script/destroy
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.join(File.dirname(__FILE__), '..')
+
+begin
+ require 'rubigen'
+rescue LoadError
+ require 'rubygems'
+ require 'rubigen'
+end
+require 'rubigen/scripts/destroy'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
+RubiGen::Scripts::Destroy.new.run(ARGV)
diff --git a/vendor/diff-display/script/generate b/vendor/diff-display/script/generate
new file mode 100755
index 0000000..230a186
--- /dev/null
+++ b/vendor/diff-display/script/generate
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.join(File.dirname(__FILE__), '..')
+
+begin
+ require 'rubigen'
+rescue LoadError
+ require 'rubygems'
+ require 'rubigen'
+end
+require 'rubigen/scripts/generate'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
+RubiGen::Scripts::Generate.new.run(ARGV)
diff --git a/vendor/diff-display/script/txt2html b/vendor/diff-display/script/txt2html
new file mode 100755
index 0000000..42d9b53
--- /dev/null
+++ b/vendor/diff-display/script/txt2html
@@ -0,0 +1,74 @@
+#!/usr/bin/env ruby
+
+require 'rubygems'
+begin
+ require 'newgem'
+rescue LoadError
+ puts "\n\nGenerating the website requires the newgem RubyGem"
+ puts "Install: gem install newgem\n\n"
+ exit(1)
+end
+require 'redcloth'
+require 'syntax/convertors/html'
+require 'erb'
+require File.dirname(__FILE__) + '/../lib/diff-display/version.rb'
+
+version = Diff-display::VERSION::STRING
+download = 'http://rubyforge.org/projects/diff-display'
+
+class Fixnum
+ def ordinal
+ # teens
+ return 'th' if (10..19).include?(self % 100)
+ # others
+ case self % 10
+ when 1: return 'st'
+ when 2: return 'nd'
+ when 3: return 'rd'
+ else return 'th'
+ end
+ end
+end
+
+class Time
+ def pretty
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
+ end
+end
+
+def convert_syntax(syntax, source)
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
+end
+
+if ARGV.length >= 1
+ src, template = ARGV
+ template ||= File.join(File.dirname(__FILE__), '/../website/template.rhtml')
+
+else
+ puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
+ exit!
+end
+
+template = ERB.new(File.open(template).read)
+
+title = nil
+body = nil
+File.open(src) do |fsrc|
+ title_text = fsrc.readline
+ body_text = fsrc.read
+ syntax_items = []
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
+ ident = syntax_items.length
+ element, syntax, source = $1, $2, $3
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
+ "syntax-temp-#{ident}"
+ }
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
+ body = RedCloth.new(body_text).to_html
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
+end
+stat = File.stat(src)
+created = stat.ctime
+modified = stat.mtime
+
+$stdout << template.result(binding)
diff --git a/vendor/diff-display/setup.rb b/vendor/diff-display/setup.rb
new file mode 100644
index 0000000..424a5f3
--- /dev/null
+++ b/vendor/diff-display/setup.rb
@@ -0,0 +1,1585 @@
+#
+# setup.rb
+#
+# Copyright (c) 2000-2005 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+#
+
+unless Enumerable.method_defined?(:map) # Ruby 1.4.6
+ module Enumerable
+ alias map collect
+ end
+end
+
+unless File.respond_to?(:read) # Ruby 1.6
+ def File.read(fname)
+ open(fname) {|f|
+ return f.read
+ }
+ end
+end
+
+unless Errno.const_defined?(:ENOTEMPTY) # Windows?
+ module Errno
+ class ENOTEMPTY
+ # We do not raise this exception, implementation is not needed.
+ end
+ end
+end
+
+def File.binread(fname)
+ open(fname, 'rb') {|f|
+ return f.read
+ }
+end
+
+# for corrupted Windows' stat(2)
+def File.dir?(path)
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
+end
+
+
+class ConfigTable
+
+ include Enumerable
+
+ def initialize(rbconfig)
+ @rbconfig = rbconfig
+ @items = []
+ @table = {}
+ # options
+ @install_prefix = nil
+ @config_opt = nil
+ @verbose = true
+ @no_harm = false
+ end
+
+ attr_accessor :install_prefix
+ attr_accessor :config_opt
+
+ attr_writer :verbose
+
+ def verbose?
+ @verbose
+ end
+
+ attr_writer :no_harm
+
+ def no_harm?
+ @no_harm
+ end
+
+ def [](key)
+ lookup(key).resolve(self)
+ end
+
+ def []=(key, val)
+ lookup(key).set val
+ end
+
+ def names
+ @items.map {|i| i.name }
+ end
+
+ def each(&block)
+ @items.each(&block)
+ end
+
+ def key?(name)
+ @table.key?(name)
+ end
+
+ def lookup(name)
+ @table[name] or setup_rb_error "no such config item: #{name}"
+ end
+
+ def add(item)
+ @items.push item
+ @table[item.name] = item
+ end
+
+ def remove(name)
+ item = lookup(name)
+ @items.delete_if {|i| i.name == name }
+ @table.delete_if {|name, i| i.name == name }
+ item
+ end
+
+ def load_script(path, inst = nil)
+ if File.file?(path)
+ MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
+ end
+ end
+
+ def savefile
+ '.config'
+ end
+
+ def load_savefile
+ begin
+ File.foreach(savefile()) do |line|
+ k, v = *line.split(/=/, 2)
+ self[k] = v.strip
+ end
+ rescue Errno::ENOENT
+ setup_rb_error $!.message + "\n#{File.basename($0)} config first"
+ end
+ end
+
+ def save
+ @items.each {|i| i.value }
+ File.open(savefile(), 'w') {|f|
+ @items.each do |i|
+ f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
+ end
+ }
+ end
+
+ def load_standard_entries
+ standard_entries(@rbconfig).each do |ent|
+ add ent
+ end
+ end
+
+ def standard_entries(rbconfig)
+ c = rbconfig
+
+ rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
+
+ major = c['MAJOR'].to_i
+ minor = c['MINOR'].to_i
+ teeny = c['TEENY'].to_i
+ version = "#{major}.#{minor}"
+
+ # ruby ver. >= 1.4.4?
+ newpath_p = ((major >= 2) or
+ ((major == 1) and
+ ((minor >= 5) or
+ ((minor == 4) and (teeny >= 4)))))
+
+ if c['rubylibdir']
+ # V > 1.6.3
+ libruby = "#{c['prefix']}/lib/ruby"
+ librubyver = c['rubylibdir']
+ librubyverarch = c['archdir']
+ siteruby = c['sitedir']
+ siterubyver = c['sitelibdir']
+ siterubyverarch = c['sitearchdir']
+ elsif newpath_p
+ # 1.4.4 <= V <= 1.6.3
+ libruby = "#{c['prefix']}/lib/ruby"
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+ siteruby = c['sitedir']
+ siterubyver = "$siteruby/#{version}"
+ siterubyverarch = "$siterubyver/#{c['arch']}"
+ else
+ # V < 1.4.4
+ libruby = "#{c['prefix']}/lib/ruby"
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+ siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
+ siterubyver = siteruby
+ siterubyverarch = "$siterubyver/#{c['arch']}"
+ end
+ parameterize = lambda {|path|
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
+ }
+
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
+ else
+ makeprog = 'make'
+ end
+
+ [
+ ExecItem.new('installdirs', 'std/site/home',
+ 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
+ {|val, table|
+ case val
+ when 'std'
+ table['rbdir'] = '$librubyver'
+ table['sodir'] = '$librubyverarch'
+ when 'site'
+ table['rbdir'] = '$siterubyver'
+ table['sodir'] = '$siterubyverarch'
+ when 'home'
+ setup_rb_error '$HOME was not set' unless ENV['HOME']
+ table['prefix'] = ENV['HOME']
+ table['rbdir'] = '$libdir/ruby'
+ table['sodir'] = '$libdir/ruby'
+ end
+ },
+ PathItem.new('prefix', 'path', c['prefix'],
+ 'path prefix of target environment'),
+ PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
+ 'the directory for commands'),
+ PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
+ 'the directory for libraries'),
+ PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
+ 'the directory for shared data'),
+ PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
+ 'the directory for man pages'),
+ PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
+ 'the directory for system configuration files'),
+ PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
+ 'the directory for local state data'),
+ PathItem.new('libruby', 'path', libruby,
+ 'the directory for ruby libraries'),
+ PathItem.new('librubyver', 'path', librubyver,
+ 'the directory for standard ruby libraries'),
+ PathItem.new('librubyverarch', 'path', librubyverarch,
+ 'the directory for standard ruby extensions'),
+ PathItem.new('siteruby', 'path', siteruby,
+ 'the directory for version-independent aux ruby libraries'),
+ PathItem.new('siterubyver', 'path', siterubyver,
+ 'the directory for aux ruby libraries'),
+ PathItem.new('siterubyverarch', 'path', siterubyverarch,
+ 'the directory for aux ruby binaries'),
+ PathItem.new('rbdir', 'path', '$siterubyver',
+ 'the directory for ruby scripts'),
+ PathItem.new('sodir', 'path', '$siterubyverarch',
+ 'the directory for ruby extentions'),
+ PathItem.new('rubypath', 'path', rubypath,
+ 'the path to set to #! line'),
+ ProgramItem.new('rubyprog', 'name', rubypath,
+ 'the ruby program using for installation'),
+ ProgramItem.new('makeprog', 'name', makeprog,
+ 'the make program to compile ruby extentions'),
+ SelectItem.new('shebang', 'all/ruby/never', 'ruby',
+ 'shebang line (#!) editing mode'),
+ BoolItem.new('without-ext', 'yes/no', 'no',
+ 'does not compile/install ruby extentions')
+ ]
+ end
+ private :standard_entries
+
+ def load_multipackage_entries
+ multipackage_entries().each do |ent|
+ add ent
+ end
+ end
+
+ def multipackage_entries
+ [
+ PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
+ 'package names that you want to install'),
+ PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
+ 'package names that you do not want to install')
+ ]
+ end
+ private :multipackage_entries
+
+ ALIASES = {
+ 'std-ruby' => 'librubyver',
+ 'stdruby' => 'librubyver',
+ 'rubylibdir' => 'librubyver',
+ 'archdir' => 'librubyverarch',
+ 'site-ruby-common' => 'siteruby', # For backward compatibility
+ 'site-ruby' => 'siterubyver', # For backward compatibility
+ 'bin-dir' => 'bindir',
+ 'bin-dir' => 'bindir',
+ 'rb-dir' => 'rbdir',
+ 'so-dir' => 'sodir',
+ 'data-dir' => 'datadir',
+ 'ruby-path' => 'rubypath',
+ 'ruby-prog' => 'rubyprog',
+ 'ruby' => 'rubyprog',
+ 'make-prog' => 'makeprog',
+ 'make' => 'makeprog'
+ }
+
+ def fixup
+ ALIASES.each do |ali, name|
+ @table[ali] = @table[name]
+ end
+ @items.freeze
+ @table.freeze
+ @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
+ end
+
+ def parse_opt(opt)
+ m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
+ m.to_a[1,2]
+ end
+
+ def dllext
+ @rbconfig['DLEXT']
+ end
+
+ def value_config?(name)
+ lookup(name).value?
+ end
+
+ class Item
+ def initialize(name, template, default, desc)
+ @name = name.freeze
+ @template = template
+ @value = default
+ @default = default
+ @description = desc
+ end
+
+ attr_reader :name
+ attr_reader :description
+
+ attr_accessor :default
+ alias help_default default
+
+ def help_opt
+ "--#{@name}=#{@template}"
+ end
+
+ def value?
+ true
+ end
+
+ def value
+ @value
+ end
+
+ def resolve(table)
+ @value.gsub(%r<\$([^/]+)>) { table[$1] }
+ end
+
+ def set(val)
+ @value = check(val)
+ end
+
+ private
+
+ def check(val)
+ setup_rb_error "config: --#{name} requires argument" unless val
+ val
+ end
+ end
+
+ class BoolItem < Item
+ def config_type
+ 'bool'
+ end
+
+ def help_opt
+ "--#{@name}"
+ end
+
+ private
+
+ def check(val)
+ return 'yes' unless val
+ case val
+ when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
+ when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
+ else
+ setup_rb_error "config: --#{@name} accepts only yes/no for argument"
+ end
+ end
+ end
+
+ class PathItem < Item
+ def config_type
+ 'path'
+ end
+
+ private
+
+ def check(path)
+ setup_rb_error "config: --#{@name} requires argument" unless path
+ path[0,1] == '$' ? path : File.expand_path(path)
+ end
+ end
+
+ class ProgramItem < Item
+ def config_type
+ 'program'
+ end
+ end
+
+ class SelectItem < Item
+ def initialize(name, selection, default, desc)
+ super
+ @ok = selection.split('/')
+ end
+
+ def config_type
+ 'select'
+ end
+
+ private
+
+ def check(val)
+ unless @ok.include?(val.strip)
+ setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
+ end
+ val.strip
+ end
+ end
+
+ class ExecItem < Item
+ def initialize(name, selection, desc, &block)
+ super name, selection, nil, desc
+ @ok = selection.split('/')
+ @action = block
+ end
+
+ def config_type
+ 'exec'
+ end
+
+ def value?
+ false
+ end
+
+ def resolve(table)
+ setup_rb_error "$#{name()} wrongly used as option value"
+ end
+
+ undef set
+
+ def evaluate(val, table)
+ v = val.strip.downcase
+ unless @ok.include?(v)
+ setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
+ end
+ @action.call v, table
+ end
+ end
+
+ class PackageSelectionItem < Item
+ def initialize(name, template, default, help_default, desc)
+ super name, template, default, desc
+ @help_default = help_default
+ end
+
+ attr_reader :help_default
+
+ def config_type
+ 'package'
+ end
+
+ private
+
+ def check(val)
+ unless File.dir?("packages/#{val}")
+ setup_rb_error "config: no such package: #{val}"
+ end
+ val
+ end
+ end
+
+ class MetaConfigEnvironment
+ def initialize(config, installer)
+ @config = config
+ @installer = installer
+ end
+
+ def config_names
+ @config.names
+ end
+
+ def config?(name)
+ @config.key?(name)
+ end
+
+ def bool_config?(name)
+ @config.lookup(name).config_type == 'bool'
+ end
+
+ def path_config?(name)
+ @config.lookup(name).config_type == 'path'
+ end
+
+ def value_config?(name)
+ @config.lookup(name).config_type != 'exec'
+ end
+
+ def add_config(item)
+ @config.add item
+ end
+
+ def add_bool_config(name, default, desc)
+ @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
+ end
+
+ def add_path_config(name, default, desc)
+ @config.add PathItem.new(name, 'path', default, desc)
+ end
+
+ def set_config_default(name, default)
+ @config.lookup(name).default = default
+ end
+
+ def remove_config(name)
+ @config.remove(name)
+ end
+
+ # For only multipackage
+ def packages
+ raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
+ @installer.packages
+ end
+
+ # For only multipackage
+ def declare_packages(list)
+ raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
+ @installer.packages = list
+ end
+ end
+
+end # class ConfigTable
+
+
+# This module requires: #verbose?, #no_harm?
+module FileOperations
+
+ def mkdir_p(dirname, prefix = nil)
+ dirname = prefix + File.expand_path(dirname) if prefix
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
+ return if no_harm?
+
+ # Does not check '/', it's too abnormal.
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
+ if /\A[a-z]:\z/i =~ dirs[0]
+ disk = dirs.shift
+ dirs[0] = disk + dirs[0]
+ end
+ dirs.each_index do |idx|
+ path = dirs[0..idx].join('')
+ Dir.mkdir path unless File.dir?(path)
+ end
+ end
+
+ def rm_f(path)
+ $stderr.puts "rm -f #{path}" if verbose?
+ return if no_harm?
+ force_remove_file path
+ end
+
+ def rm_rf(path)
+ $stderr.puts "rm -rf #{path}" if verbose?
+ return if no_harm?
+ remove_tree path
+ end
+
+ def remove_tree(path)
+ if File.symlink?(path)
+ remove_file path
+ elsif File.dir?(path)
+ remove_tree0 path
+ else
+ force_remove_file path
+ end
+ end
+
+ def remove_tree0(path)
+ Dir.foreach(path) do |ent|
+ next if ent == '.'
+ next if ent == '..'
+ entpath = "#{path}/#{ent}"
+ if File.symlink?(entpath)
+ remove_file entpath
+ elsif File.dir?(entpath)
+ remove_tree0 entpath
+ else
+ force_remove_file entpath
+ end
+ end
+ begin
+ Dir.rmdir path
+ rescue Errno::ENOTEMPTY
+ # directory may not be empty
+ end
+ end
+
+ def move_file(src, dest)
+ force_remove_file dest
+ begin
+ File.rename src, dest
+ rescue
+ File.open(dest, 'wb') {|f|
+ f.write File.binread(src)
+ }
+ File.chmod File.stat(src).mode, dest
+ File.unlink src
+ end
+ end
+
+ def force_remove_file(path)
+ begin
+ remove_file path
+ rescue
+ end
+ end
+
+ def remove_file(path)
+ File.chmod 0777, path
+ File.unlink path
+ end
+
+ def install(from, dest, mode, prefix = nil)
+ $stderr.puts "install #{from} #{dest}" if verbose?
+ return if no_harm?
+
+ realdest = prefix ? prefix + File.expand_path(dest) : dest
+ realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
+ str = File.binread(from)
+ if diff?(str, realdest)
+ verbose_off {
+ rm_f realdest if File.exist?(realdest)
+ }
+ File.open(realdest, 'wb') {|f|
+ f.write str
+ }
+ File.chmod mode, realdest
+
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
+ if prefix
+ f.puts realdest.sub(prefix, '')
+ else
+ f.puts realdest
+ end
+ }
+ end
+ end
+
+ def diff?(new_content, path)
+ return true unless File.exist?(path)
+ new_content != File.binread(path)
+ end
+
+ def command(*args)
+ $stderr.puts args.join(' ') if verbose?
+ system(*args) or raise RuntimeError,
+ "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
+ end
+
+ def ruby(*args)
+ command config('rubyprog'), *args
+ end
+
+ def make(task = nil)
+ command(*[config('makeprog'), task].compact)
+ end
+
+ def extdir?(dir)
+ File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
+ end
+
+ def files_of(dir)
+ Dir.open(dir) {|d|
+ return d.select {|ent| File.file?("#{dir}/#{ent}") }
+ }
+ end
+
+ DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
+
+ def directories_of(dir)
+ Dir.open(dir) {|d|
+ return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
+ }
+ end
+
+end
+
+
+# This module requires: #srcdir_root, #objdir_root, #relpath
+module HookScriptAPI
+
+ def get_config(key)
+ @config[key]
+ end
+
+ alias config get_config
+
+ # obsolete: use metaconfig to change configuration
+ def set_config(key, val)
+ @config[key] = val
+ end
+
+ #
+ # srcdir/objdir (works only in the package directory)
+ #
+
+ def curr_srcdir
+ "#{srcdir_root()}/#{relpath()}"
+ end
+
+ def curr_objdir
+ "#{objdir_root()}/#{relpath()}"
+ end
+
+ def srcfile(path)
+ "#{curr_srcdir()}/#{path}"
+ end
+
+ def srcexist?(path)
+ File.exist?(srcfile(path))
+ end
+
+ def srcdirectory?(path)
+ File.dir?(srcfile(path))
+ end
+
+ def srcfile?(path)
+ File.file?(srcfile(path))
+ end
+
+ def srcentries(path = '.')
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
+ return d.to_a - %w(. ..)
+ }
+ end
+
+ def srcfiles(path = '.')
+ srcentries(path).select {|fname|
+ File.file?(File.join(curr_srcdir(), path, fname))
+ }
+ end
+
+ def srcdirectories(path = '.')
+ srcentries(path).select {|fname|
+ File.dir?(File.join(curr_srcdir(), path, fname))
+ }
+ end
+
+end
+
+
+class ToplevelInstaller
+
+ Version = '3.4.1'
+ Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
+
+ TASKS = [
+ [ 'all', 'do config, setup, then install' ],
+ [ 'config', 'saves your configurations' ],
+ [ 'show', 'shows current configuration' ],
+ [ 'setup', 'compiles ruby extentions and others' ],
+ [ 'install', 'installs files' ],
+ [ 'test', 'run all tests in test/' ],
+ [ 'clean', "does `make clean' for each extention" ],
+ [ 'distclean',"does `make distclean' for each extention" ]
+ ]
+
+ def ToplevelInstaller.invoke
+ config = ConfigTable.new(load_rbconfig())
+ config.load_standard_entries
+ config.load_multipackage_entries if multipackage?
+ config.fixup
+ klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
+ klass.new(File.dirname($0), config).invoke
+ end
+
+ def ToplevelInstaller.multipackage?
+ File.dir?(File.dirname($0) + '/packages')
+ end
+
+ def ToplevelInstaller.load_rbconfig
+ if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
+ ARGV.delete(arg)
+ load File.expand_path(arg.split(/=/, 2)[1])
+ $".push 'rbconfig.rb'
+ else
+ require 'rbconfig'
+ end
+ ::Config::CONFIG
+ end
+
+ def initialize(ardir_root, config)
+ @ardir = File.expand_path(ardir_root)
+ @config = config
+ # cache
+ @valid_task_re = nil
+ end
+
+ def config(key)
+ @config[key]
+ end
+
+ def inspect
+ "#<#{self.class} #{__id__()}>"
+ end
+
+ def invoke
+ run_metaconfigs
+ case task = parsearg_global()
+ when nil, 'all'
+ parsearg_config
+ init_installers
+ exec_config
+ exec_setup
+ exec_install
+ else
+ case task
+ when 'config', 'test'
+ ;
+ when 'clean', 'distclean'
+ @config.load_savefile if File.exist?(@config.savefile)
+ else
+ @config.load_savefile
+ end
+ __send__ "parsearg_#{task}"
+ init_installers
+ __send__ "exec_#{task}"
+ end
+ end
+
+ def run_metaconfigs
+ @config.load_script "#{@ardir}/metaconfig"
+ end
+
+ def init_installers
+ @installer = Installer.new(@config, @ardir, File.expand_path('.'))
+ end
+
+ #
+ # Hook Script API bases
+ #
+
+ def srcdir_root
+ @ardir
+ end
+
+ def objdir_root
+ '.'
+ end
+
+ def relpath
+ '.'
+ end
+
+ #
+ # Option Parsing
+ #
+
+ def parsearg_global
+ while arg = ARGV.shift
+ case arg
+ when /\A\w+\z/
+ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
+ return arg
+ when '-q', '--quiet'
+ @config.verbose = false
+ when '--verbose'
+ @config.verbose = true
+ when '--help'
+ print_usage $stdout
+ exit 0
+ when '--version'
+ puts "#{File.basename($0)} version #{Version}"
+ exit 0
+ when '--copyright'
+ puts Copyright
+ exit 0
+ else
+ setup_rb_error "unknown global option '#{arg}'"
+ end
+ end
+ nil
+ end
+
+ def valid_task?(t)
+ valid_task_re() =~ t
+ end
+
+ def valid_task_re
+ @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
+ end
+
+ def parsearg_no_options
+ unless ARGV.empty?
+ task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
+ setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
+ end
+ end
+
+ alias parsearg_show parsearg_no_options
+ alias parsearg_setup parsearg_no_options
+ alias parsearg_test parsearg_no_options
+ alias parsearg_clean parsearg_no_options
+ alias parsearg_distclean parsearg_no_options
+
+ def parsearg_config
+ evalopt = []
+ set = []
+ @config.config_opt = []
+ while i = ARGV.shift
+ if /\A--?\z/ =~ i
+ @config.config_opt = ARGV.dup
+ break
+ end
+ name, value = *@config.parse_opt(i)
+ if @config.value_config?(name)
+ @config[name] = value
+ else
+ evalopt.push [name, value]
+ end
+ set.push name
+ end
+ evalopt.each do |name, value|
+ @config.lookup(name).evaluate value, @config
+ end
+ # Check if configuration is valid
+ set.each do |n|
+ @config[n] if @config.value_config?(n)
+ end
+ end
+
+ def parsearg_install
+ @config.no_harm = false
+ @config.install_prefix = ''
+ while a = ARGV.shift
+ case a
+ when '--no-harm'
+ @config.no_harm = true
+ when /\A--prefix=/
+ path = a.split(/=/, 2)[1]
+ path = File.expand_path(path) unless path[0,1] == '/'
+ @config.install_prefix = path
+ else
+ setup_rb_error "install: unknown option #{a}"
+ end
+ end
+ end
+
+ def print_usage(out)
+ out.puts 'Typical Installation Procedure:'
+ out.puts " $ ruby #{File.basename $0} config"
+ out.puts " $ ruby #{File.basename $0} setup"
+ out.puts " # ruby #{File.basename $0} install (may require root privilege)"
+ out.puts
+ out.puts 'Detailed Usage:'
+ out.puts " ruby #{File.basename $0} <global option>"
+ out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
+
+ fmt = " %-24s %s\n"
+ out.puts
+ out.puts 'Global options:'
+ out.printf fmt, '-q,--quiet', 'suppress message outputs'
+ out.printf fmt, ' --verbose', 'output messages verbosely'
+ out.printf fmt, ' --help', 'print this message'
+ out.printf fmt, ' --version', 'print version and quit'
+ out.printf fmt, ' --copyright', 'print copyright and quit'
+ out.puts
+ out.puts 'Tasks:'
+ TASKS.each do |name, desc|
+ out.printf fmt, name, desc
+ end
+
+ fmt = " %-24s %s [%s]\n"
+ out.puts
+ out.puts 'Options for CONFIG or ALL:'
+ @config.each do |item|
+ out.printf fmt, item.help_opt, item.description, item.help_default
+ end
+ out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
+ out.puts
+ out.puts 'Options for INSTALL:'
+ out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
+ out.printf fmt, '--prefix=path', 'install path prefix', ''
+ out.puts
+ end
+
+ #
+ # Task Handlers
+ #
+
+ def exec_config
+ @installer.exec_config
+ @config.save # must be final
+ end
+
+ def exec_setup
+ @installer.exec_setup
+ end
+
+ def exec_install
+ @installer.exec_install
+ end
+
+ def exec_test
+ @installer.exec_test
+ end
+
+ def exec_show
+ @config.each do |i|
+ printf "%-20s %s\n", i.name, i.value if i.value?
+ end
+ end
+
+ def exec_clean
+ @installer.exec_clean
+ end
+
+ def exec_distclean
+ @installer.exec_distclean
+ end
+
+end # class ToplevelInstaller
+
+
+class ToplevelInstallerMulti < ToplevelInstaller
+
+ include FileOperations
+
+ def initialize(ardir_root, config)
+ super
+ @packages = directories_of("#{@ardir}/packages")
+ raise 'no package exists' if @packages.empty?
+ @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
+ end
+
+ def run_metaconfigs
+ @config.load_script "#{@ardir}/metaconfig", self
+ @packages.each do |name|
+ @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
+ end
+ end
+
+ attr_reader :packages
+
+ def packages=(list)
+ raise 'package list is empty' if list.empty?
+ list.each do |name|
+ raise "directory packages/#{name} does not exist"\
+ unless File.dir?("#{@ardir}/packages/#{name}")
+ end
+ @packages = list
+ end
+
+ def init_installers
+ @installers = {}
+ @packages.each do |pack|
+ @installers[pack] = Installer.new(@config,
+ "#{@ardir}/packages/#{pack}",
+ "packages/#{pack}")
+ end
+ with = extract_selection(config('with'))
+ without = extract_selection(config('without'))
+ @selected = @installers.keys.select {|name|
+ (with.empty? or with.include?(name)) \
+ and not without.include?(name)
+ }
+ end
+
+ def extract_selection(list)
+ a = list.split(/,/)
+ a.each do |name|
+ setup_rb_error "no such package: #{name}" unless @installers.key?(name)
+ end
+ a
+ end
+
+ def print_usage(f)
+ super
+ f.puts 'Inluded packages:'
+ f.puts ' ' + @packages.sort.join(' ')
+ f.puts
+ end
+
+ #
+ # Task Handlers
+ #
+
+ def exec_config
+ run_hook 'pre-config'
+ each_selected_installers {|inst| inst.exec_config }
+ run_hook 'post-config'
+ @config.save # must be final
+ end
+
+ def exec_setup
+ run_hook 'pre-setup'
+ each_selected_installers {|inst| inst.exec_setup }
+ run_hook 'post-setup'
+ end
+
+ def exec_install
+ run_hook 'pre-install'
+ each_selected_installers {|inst| inst.exec_install }
+ run_hook 'post-install'
+ end
+
+ def exec_test
+ run_hook 'pre-test'
+ each_selected_installers {|inst| inst.exec_test }
+ run_hook 'post-test'
+ end
+
+ def exec_clean
+ rm_f @config.savefile
+ run_hook 'pre-clean'
+ each_selected_installers {|inst| inst.exec_clean }
+ run_hook 'post-clean'
+ end
+
+ def exec_distclean
+ rm_f @config.savefile
+ run_hook 'pre-distclean'
+ each_selected_installers {|inst| inst.exec_distclean }
+ run_hook 'post-distclean'
+ end
+
+ #
+ # lib
+ #
+
+ def each_selected_installers
+ Dir.mkdir 'packages' unless File.dir?('packages')
+ @selected.each do |pack|
+ $stderr.puts "Processing the package `#{pack}' ..." if verbose?
+ Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
+ Dir.chdir "packages/#{pack}"
+ yield @installers[pack]
+ Dir.chdir '../..'
+ end
+ end
+
+ def run_hook(id)
+ @root_installer.run_hook id
+ end
+
+ # module FileOperations requires this
+ def verbose?
+ @config.verbose?
+ end
+
+ # module FileOperations requires this
+ def no_harm?
+ @config.no_harm?
+ end
+
+end # class ToplevelInstallerMulti
+
+
+class Installer
+
+ FILETYPES = %w( bin lib ext data conf man )
+
+ include FileOperations
+ include HookScriptAPI
+
+ def initialize(config, srcroot, objroot)
+ @config = config
+ @srcdir = File.expand_path(srcroot)
+ @objdir = File.expand_path(objroot)
+ @currdir = '.'
+ end
+
+ def inspect
+ "#<#{self.class} #{File.basename(@srcdir)}>"
+ end
+
+ def noop(rel)
+ end
+
+ #
+ # Hook Script API base methods
+ #
+
+ def srcdir_root
+ @srcdir
+ end
+
+ def objdir_root
+ @objdir
+ end
+
+ def relpath
+ @currdir
+ end
+
+ #
+ # Config Access
+ #
+
+ # module FileOperations requires this
+ def verbose?
+ @config.verbose?
+ end
+
+ # module FileOperations requires this
+ def no_harm?
+ @config.no_harm?
+ end
+
+ def verbose_off
+ begin
+ save, @config.verbose = @config.verbose?, false
+ yield
+ ensure
+ @config.verbose = save
+ end
+ end
+
+ #
+ # TASK config
+ #
+
+ def exec_config
+ exec_task_traverse 'config'
+ end
+
+ alias config_dir_bin noop
+ alias config_dir_lib noop
+
+ def config_dir_ext(rel)
+ extconf if extdir?(curr_srcdir())
+ end
+
+ alias config_dir_data noop
+ alias config_dir_conf noop
+ alias config_dir_man noop
+
+ def extconf
+ ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
+ end
+
+ #
+ # TASK setup
+ #
+
+ def exec_setup
+ exec_task_traverse 'setup'
+ end
+
+ def setup_dir_bin(rel)
+ files_of(curr_srcdir()).each do |fname|
+ update_shebang_line "#{curr_srcdir()}/#{fname}"
+ end
+ end
+
+ alias setup_dir_lib noop
+
+ def setup_dir_ext(rel)
+ make if extdir?(curr_srcdir())
+ end
+
+ alias setup_dir_data noop
+ alias setup_dir_conf noop
+ alias setup_dir_man noop
+
+ def update_shebang_line(path)
+ return if no_harm?
+ return if config('shebang') == 'never'
+ old = Shebang.load(path)
+ if old
+ $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1
+ new = new_shebang(old)
+ return if new.to_s == old.to_s
+ else
+ return unless config('shebang') == 'all'
+ new = Shebang.new(config('rubypath'))
+ end
+ $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
+ open_atomic_writer(path) {|output|
+ File.open(path, 'rb') {|f|
+ f.gets if old # discard
+ output.puts new.to_s
+ output.print f.read
+ }
+ }
+ end
+
+ def new_shebang(old)
+ if /\Aruby/ =~ File.basename(old.cmd)
+ Shebang.new(config('rubypath'), old.args)
+ elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
+ Shebang.new(config('rubypath'), old.args[1..-1])
+ else
+ return old unless config('shebang') == 'all'
+ Shebang.new(config('rubypath'))
+ end
+ end
+
+ def open_atomic_writer(path, &block)
+ tmpfile = File.basename(path) + '.tmp'
+ begin
+ File.open(tmpfile, 'wb', &block)
+ File.rename tmpfile, File.basename(path)
+ ensure
+ File.unlink tmpfile if File.exist?(tmpfile)
+ end
+ end
+
+ class Shebang
+ def Shebang.load(path)
+ line = nil
+ File.open(path) {|f|
+ line = f.gets
+ }
+ return nil unless /\A#!/ =~ line
+ parse(line)
+ end
+
+ def Shebang.parse(line)
+ cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
+ new(cmd, args)
+ end
+
+ def initialize(cmd, args = [])
+ @cmd = cmd
+ @args = args
+ end
+
+ attr_reader :cmd
+ attr_reader :args
+
+ def to_s
+ "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
+ end
+ end
+
+ #
+ # TASK install
+ #
+
+ def exec_install
+ rm_f 'InstalledFiles'
+ exec_task_traverse 'install'
+ end
+
+ def install_dir_bin(rel)
+ install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
+ end
+
+ def install_dir_lib(rel)
+ install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
+ end
+
+ def install_dir_ext(rel)
+ return unless extdir?(curr_srcdir())
+ install_files rubyextentions('.'),
+ "#{config('sodir')}/#{File.dirname(rel)}",
+ 0555
+ end
+
+ def install_dir_data(rel)
+ install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
+ end
+
+ def install_dir_conf(rel)
+ # FIXME: should not remove current config files
+ # (rename previous file to .old/.org)
+ install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
+ end
+
+ def install_dir_man(rel)
+ install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
+ end
+
+ def install_files(list, dest, mode)
+ mkdir_p dest, @config.install_prefix
+ list.each do |fname|
+ install fname, dest, mode, @config.install_prefix
+ end
+ end
+
+ def libfiles
+ glob_reject(%w(*.y *.output), targetfiles())
+ end
+
+ def rubyextentions(dir)
+ ents = glob_select("*.#{@config.dllext}", targetfiles())
+ if ents.empty?
+ setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
+ end
+ ents
+ end
+
+ def targetfiles
+ mapdir(existfiles() - hookfiles())
+ end
+
+ def mapdir(ents)
+ ents.map {|ent|
+ if File.exist?(ent)
+ then ent # objdir
+ else "#{curr_srcdir()}/#{ent}" # srcdir
+ end
+ }
+ end
+
+ # picked up many entries from cvs-1.11.1/src/ignore.c
+ JUNK_FILES = %w(
+ core RCSLOG tags TAGS .make.state
+ .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
+ *~ *.old *.bak *.BAK *.orig *.rej _$* *$
+
+ *.org *.in .*
+ )
+
+ def existfiles
+ glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
+ end
+
+ def hookfiles
+ %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
+ %w( config setup install clean ).map {|t| sprintf(fmt, t) }
+ }.flatten
+ end
+
+ def glob_select(pat, ents)
+ re = globs2re([pat])
+ ents.select {|ent| re =~ ent }
+ end
+
+ def glob_reject(pats, ents)
+ re = globs2re(pats)
+ ents.reject {|ent| re =~ ent }
+ end
+
+ GLOB2REGEX = {
+ '.' => '\.',
+ '$' => '\$',
+ '#' => '\#',
+ '*' => '.*'
+ }
+
+ def globs2re(pats)
+ /\A(?:#{
+ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
+ })\z/
+ end
+
+ #
+ # TASK test
+ #
+
+ TESTDIR = 'test'
+
+ def exec_test
+ unless File.directory?('test')
+ $stderr.puts 'no test in this package' if verbose?
+ return
+ end
+ $stderr.puts 'Running tests...' if verbose?
+ begin
+ require 'test/unit'
+ rescue LoadError
+ setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
+ end
+ runner = Test::Unit::AutoRunner.new(true)
+ runner.to_run << TESTDIR
+ runner.run
+ end
+
+ #
+ # TASK clean
+ #
+
+ def exec_clean
+ exec_task_traverse 'clean'
+ rm_f @config.savefile
+ rm_f 'InstalledFiles'
+ end
+
+ alias clean_dir_bin noop
+ alias clean_dir_lib noop
+ alias clean_dir_data noop
+ alias clean_dir_conf noop
+ alias clean_dir_man noop
+
+ def clean_dir_ext(rel)
+ return unless extdir?(curr_srcdir())
+ make 'clean' if File.file?('Makefile')
+ end
+
+ #
+ # TASK distclean
+ #
+
+ def exec_distclean
+ exec_task_traverse 'distclean'
+ rm_f @config.savefile
+ rm_f 'InstalledFiles'
+ end
+
+ alias distclean_dir_bin noop
+ alias distclean_dir_lib noop
+
+ def distclean_dir_ext(rel)
+ return unless extdir?(curr_srcdir())
+ make 'distclean' if File.file?('Makefile')
+ end
+
+ alias distclean_dir_data noop
+ alias distclean_dir_conf noop
+ alias distclean_dir_man noop
+
+ #
+ # Traversing
+ #
+
+ def exec_task_traverse(task)
+ run_hook "pre-#{task}"
+ FILETYPES.each do |type|
+ if type == 'ext' and config('without-ext') == 'yes'
+ $stderr.puts 'skipping ext/* by user option' if verbose?
+ next
+ end
+ traverse task, type, "#{task}_dir_#{type}"
+ end
+ run_hook "post-#{task}"
+ end
+
+ def traverse(task, rel, mid)
+ dive_into(rel) {
+ run_hook "pre-#{task}"
+ __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
+ directories_of(curr_srcdir()).each do |d|
+ traverse task, "#{rel}/#{d}", mid
+ end
+ run_hook "post-#{task}"
+ }
+ end
+
+ def dive_into(rel)
+ return unless File.dir?("#{@srcdir}/#{rel}")
+
+ dir = File.basename(rel)
+ Dir.mkdir dir unless File.dir?(dir)
+ prevdir = Dir.pwd
+ Dir.chdir dir
+ $stderr.puts '---> ' + rel if verbose?
+ @currdir = rel
+ yield
+ Dir.chdir prevdir
+ $stderr.puts '<--- ' + rel if verbose?
+ @currdir = File.dirname(rel)
+ end
+
+ def run_hook(id)
+ path = [ "#{curr_srcdir()}/#{id}",
+ "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
+ return unless path
+ begin
+ instance_eval File.read(path), path, 1
+ rescue
+ raise if $DEBUG
+ setup_rb_error "hook #{path} failed:\n" + $!.message
+ end
+ end
+
+end # class Installer
+
+
+class SetupError < StandardError; end
+
+def setup_rb_error(msg)
+ raise SetupError, msg
+end
+
+if $0 == __FILE__
+ begin
+ ToplevelInstaller.invoke
+ rescue SetupError
+ raise if $DEBUG
+ $stderr.puts $!.message
+ $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
+ exit 1
+ end
+end
diff --git a/vendor/diff-display/spec/api_spec.rb b/vendor/diff-display/spec/api_spec.rb
new file mode 100644
index 0000000..ed82038
--- /dev/null
+++ b/vendor/diff-display/spec/api_spec.rb
@@ -0,0 +1,10 @@
+require File.dirname(__FILE__) + '/spec_helper.rb'
+
+describe "API acceptance specs" do
+
+ it "has a simple API" do
+ diff = Diff::Display::Unified.new(load_diff("simple"))
+ diff.render(Diff::Renderer::Base.new)
+ end
+
+end \ No newline at end of file
diff --git a/vendor/diff-display/spec/data_structure_spec.rb b/vendor/diff-display/spec/data_structure_spec.rb
new file mode 100644
index 0000000..c9b0c29
--- /dev/null
+++ b/vendor/diff-display/spec/data_structure_spec.rb
@@ -0,0 +1,75 @@
+require File.dirname(__FILE__) + '/spec_helper.rb'
+
+describe "Diff::Display data structures" do
+
+ describe "Data" do
+ it "behaves like an array" do
+ data = Diff::Display::Data.new
+ data << "foo"
+ data.push "bar"
+ data.should == ["foo", "bar"]
+ end
+ end
+
+ describe "Line" do
+ it "initializes with a line number" do
+ line = Diff::Display::Line.new("foo", 12)
+ line.number.should == 12
+ end
+
+ it "has a class method for creating an AddLine" do
+ line = Diff::Display::Line.add("foo", 7)
+ line.should be_instance_of(Diff::Display::AddLine)
+ end
+
+ it "has a class method for creating a RemLine" do
+ line = Diff::Display::Line.rem("foo", 7)
+ line.should be_instance_of(Diff::Display::RemLine)
+ end
+
+ it "has a class method for creating a UnModLine" do
+ line = Diff::Display::Line.unmod("foo", 7)
+ line.should be_instance_of(Diff::Display::UnModLine)
+ end
+
+ it "has a class method for creating a HeaderLine" do
+ line = Diff::Display::Line.header("foo")
+ line.should be_instance_of(Diff::Display::HeaderLine)
+ end
+ end
+
+ describe "Block" do
+ it "behaves like an array" do
+ block = Diff::Display::Block.new
+ block.push 1,2,3
+ block.size.should == 3
+ block.should == [1,2,3]
+ end
+
+ it "has class method for creating an AddBlock" do
+ block = Diff::Display::Block.add
+ block.should be_instance_of(Diff::Display::AddBlock)
+ end
+
+ it "has class method for creating an RemBlock" do
+ block = Diff::Display::Block.rem
+ block.should be_instance_of(Diff::Display::RemBlock)
+ end
+
+ it "has class method for creating an ModBlock" do
+ block = Diff::Display::Block.mod
+ block.should be_instance_of(Diff::Display::ModBlock)
+ end
+
+ it "has class method for creating an UnModBlock" do
+ block = Diff::Display::Block.unmod
+ block.should be_instance_of(Diff::Display::UnModBlock)
+ end
+
+ it "has class method for creating an HeaderBlock" do
+ block = Diff::Display::Block.header
+ block.should be_instance_of(Diff::Display::HeaderBlock)
+ end
+ end
+
+end
diff --git a/vendor/diff-display/test/diffs/huge_diff b/vendor/diff-display/spec/fixtures/big.diff
index b1918e4..b1918e4 100644
--- a/vendor/diff-display/test/diffs/huge_diff
+++ b/vendor/diff-display/spec/fixtures/big.diff
diff --git a/vendor/diff-display/test/diffs/edgecase1_diff.diff b/vendor/diff-display/spec/fixtures/multiple_adds_after_rem.diff
index 07682d2..07682d2 100644
--- a/vendor/diff-display/test/diffs/edgecase1_diff.diff
+++ b/vendor/diff-display/spec/fixtures/multiple_adds_after_rem.diff
diff --git a/vendor/diff-display/spec/fixtures/only_add.diff b/vendor/diff-display/spec/fixtures/only_add.diff
new file mode 100644
index 0000000..b95d705
--- /dev/null
+++ b/vendor/diff-display/spec/fixtures/only_add.diff
@@ -0,0 +1,4 @@
+--- a.txt 2008-02-03 16:28:06.000000000 +0100
++++ b.txt 2008-02-03 16:28:14.000000000 +0100
+@@ -0,0 +1 @@
++foo
diff --git a/vendor/diff-display/spec/fixtures/only_rem.diff b/vendor/diff-display/spec/fixtures/only_rem.diff
new file mode 100644
index 0000000..42c6d8f
--- /dev/null
+++ b/vendor/diff-display/spec/fixtures/only_rem.diff
@@ -0,0 +1,4 @@
+--- b.txt 2008-02-03 16:28:14.000000000 +0100
++++ a.txt 2008-02-03 16:28:06.000000000 +0100
+@@ -1 +0,0 @@
+-foo
diff --git a/vendor/diff-display/spec/fixtures/simple.diff b/vendor/diff-display/spec/fixtures/simple.diff
new file mode 100644
index 0000000..e2b9909
--- /dev/null
+++ b/vendor/diff-display/spec/fixtures/simple.diff
@@ -0,0 +1,12 @@
+diff --git a/History.txt b/History.txt
+index 0ed7358..622c384 100644
+--- a/History.txt
++++ b/History.txt
+@@ -1,4 +1,5 @@
+ == 0.0.1 2008-01-28
+
+-* 1 major enhancement:
+- * Initial release
++* 2 major enhancements:
++ * The Initial release
++ * stuff added \ No newline at end of file
diff --git a/vendor/diff-display/spec/generator_spec.rb b/vendor/diff-display/spec/generator_spec.rb
new file mode 100644
index 0000000..e15b92a
--- /dev/null
+++ b/vendor/diff-display/spec/generator_spec.rb
@@ -0,0 +1,35 @@
+require File.dirname(__FILE__) + '/spec_helper.rb'
+
+describe Diff::Display::Unified::Generator do
+
+ before(:each) do
+ @generator = Diff::Display::Unified::Generator.new
+ end
+
+ it "Generator.run raises if doesn't get a Enumerable object" do
+ proc {
+ Diff::Display::Unified::Generator.run(nil)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "Generator.run processes each line in the diff" do
+ Diff::Display::Unified::Generator.expects(:new).returns(@generator)
+ @generator.expects(:process).with("foo")
+ @generator.expects(:process).with("bar")
+ Diff::Display::Unified::Generator.run("foo\nbar")
+ end
+
+ it "Generator.run returns the data" do
+ Diff::Display::Unified::Generator.expects(:new).returns(@generator)
+ generated = Diff::Display::Unified::Generator.run("foo\nbar")
+ generated.should be_instance_of(Diff::Display::Data)
+ end
+
+ it "the returned that object is in parity with the diff" do
+ %w[simple only_add only_rem multiple_adds_after_rem].each do |diff|
+ data = Diff::Display::Unified::Generator.run(load_diff(diff))
+ data.to_diff.should == load_diff(diff).chomp
+ end
+ end
+
+end
diff --git a/vendor/diff-display/spec/renderer/base_spec.rb b/vendor/diff-display/spec/renderer/base_spec.rb
new file mode 100644
index 0000000..9893d04
--- /dev/null
+++ b/vendor/diff-display/spec/renderer/base_spec.rb
@@ -0,0 +1,98 @@
+require File.dirname(__FILE__) + '/../spec_helper.rb'
+
+describe Diff::Renderer::Base do
+
+ before(:each) do
+ @data = Diff::Display::Unified::Generator.run(load_diff("big"))
+ @base_renderer = Diff::Renderer::Base.new
+ end
+
+ it "classifies a classname" do
+ @base_renderer.send(:classify, Diff::Display::RemBlock.new).should == "remblock"
+ end
+
+ it "calls the before_headerblock" do
+ @base_renderer.expects(:before_headerblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ # it "calls the before_sepblock" do
+ # @base_renderer.expects(:before_sepblock).at_least_once
+ # @base_renderer.render(@data)
+ # end
+
+ it "calls the before_modblock" do
+ @base_renderer.expects(:before_modblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls the before_unmodblock" do
+ @base_renderer.expects(:before_unmodblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls the before_addblock" do
+ @base_renderer.expects(:before_addblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls the before_remblock" do
+ @base_renderer.expects(:before_remblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls headerline" do
+ @base_renderer.expects(:headerline).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls unmodline" do
+ @base_renderer.expects(:unmodline).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls addline" do
+ @base_renderer.expects(:addline).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls remline" do
+ @base_renderer.expects(:remline).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls the after_headerblock" do
+ @base_renderer.expects(:after_headerblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ # it "calls the after_sepblock" do
+ # @base_renderer.expects(:after_sepblock).at_least_once
+ # @base_renderer.render(@data)
+ # end
+
+ it "calls the after_modblock" do
+ @base_renderer.expects(:after_modblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls the after_unmodblock" do
+ @base_renderer.expects(:after_unmodblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls the after_addblock" do
+ @base_renderer.expects(:after_addblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "calls the after_remblock" do
+ @base_renderer.expects(:after_remblock).at_least_once
+ @base_renderer.render(@data)
+ end
+
+ it "renders a basic datastructure" do
+ output = @base_renderer.render(@data)
+ output.should_not == nil
+ end
+end \ No newline at end of file
diff --git a/vendor/diff-display/spec/renderer/diff_spec.rb b/vendor/diff-display/spec/renderer/diff_spec.rb
new file mode 100644
index 0000000..2c7b862
--- /dev/null
+++ b/vendor/diff-display/spec/renderer/diff_spec.rb
@@ -0,0 +1,9 @@
+require File.dirname(__FILE__) + '/../spec_helper.rb'
+
+describe Diff::Renderer::Diff do
+ it "renders a diff back to its original state" do
+ data = Diff::Display::Unified::Generator.run(load_diff("simple"))
+ base_renderer = Diff::Renderer::Diff.new
+ base_renderer.render(data).should == load_diff("simple")
+ end
+end
diff --git a/vendor/diff-display/spec/spec.opts b/vendor/diff-display/spec/spec.opts
new file mode 100644
index 0000000..cf6add7
--- /dev/null
+++ b/vendor/diff-display/spec/spec.opts
@@ -0,0 +1 @@
+--colour \ No newline at end of file
diff --git a/vendor/diff-display/spec/spec_helper.rb b/vendor/diff-display/spec/spec_helper.rb
new file mode 100644
index 0000000..5c91155
--- /dev/null
+++ b/vendor/diff-display/spec/spec_helper.rb
@@ -0,0 +1,20 @@
+begin
+ require 'spec'
+rescue LoadError
+ require 'rubygems'
+ gem 'rspec'
+ require 'spec'
+end
+
+require File.dirname(__FILE__) + "/../lib/diff-display"
+
+module DiffFixtureHelper
+ def load_diff(name)
+ File.read(File.dirname(__FILE__) + "/fixtures/#{name}.diff")
+ end
+end
+
+Spec::Runner.configure do |config|
+ config.mock_with :mocha
+ config.include DiffFixtureHelper
+end \ No newline at end of file
diff --git a/vendor/diff-display/spec/unified_spec.rb b/vendor/diff-display/spec/unified_spec.rb
new file mode 100644
index 0000000..39c5712
--- /dev/null
+++ b/vendor/diff-display/spec/unified_spec.rb
@@ -0,0 +1,21 @@
+require File.dirname(__FILE__) + '/spec_helper.rb'
+
+describe Diff::Display::Unified do
+
+ it "generates its data structure via the Generator" do
+ generator_data = mock("Generator mock")
+ Diff::Display::Unified::Generator.expects(:run).returns(generator_data)
+ diff = Diff::Display::Unified.new(load_diff("simple"))
+ diff.data.should == generator_data
+ end
+
+ it "renders a diff via a callback and renders it to a stringlike object" do
+ diff = Diff::Display::Unified.new(load_diff("simple"))
+ callback = mock()
+ callback.expects(:render).returns("foo")
+ output = ""
+ diff.render(callback, output)
+ output.should == "foo"
+ end
+
+end \ No newline at end of file
diff --git a/vendor/diff-display/tasks/deployment.rake b/vendor/diff-display/tasks/deployment.rake
new file mode 100644
index 0000000..2f43742
--- /dev/null
+++ b/vendor/diff-display/tasks/deployment.rake
@@ -0,0 +1,34 @@
+desc 'Release the website and new gem version'
+task :deploy => [:check_version, :website, :release] do
+ puts "Remember to create SVN tag:"
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
+ puts "Suggested comment:"
+ puts "Tagging release #{CHANGES}"
+end
+
+desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
+task :local_deploy => [:website_generate, :install_gem]
+
+task :check_version do
+ unless ENV['VERSION']
+ puts 'Must pass a VERSION=x.y.z release version'
+ exit
+ end
+ unless ENV['VERSION'] == VERS
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
+ exit
+ end
+end
+
+desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
+task :install_gem_no_doc => [:clean, :package] do
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
+end
+
+namespace :manifest do
+ desc 'Recreate Manifest.txt to include ALL files'
+ task :refresh do
+ `rake check_manifest | patch -p0 > Manifest.txt`
+ end
+end \ No newline at end of file
diff --git a/vendor/diff-display/tasks/environment.rake b/vendor/diff-display/tasks/environment.rake
new file mode 100644
index 0000000..691ed3b
--- /dev/null
+++ b/vendor/diff-display/tasks/environment.rake
@@ -0,0 +1,7 @@
+task :ruby_env do
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
+ "jruby"
+ else
+ "ruby"
+ end unless defined? RUBY_APP
+end
diff --git a/vendor/diff-display/tasks/rspec.rake b/vendor/diff-display/tasks/rspec.rake
new file mode 100644
index 0000000..b256d1c
--- /dev/null
+++ b/vendor/diff-display/tasks/rspec.rake
@@ -0,0 +1,21 @@
+begin
+ require 'spec'
+rescue LoadError
+ require 'rubygems'
+ require 'spec'
+end
+begin
+ require 'spec/rake/spectask'
+rescue LoadError
+ puts <<-EOS
+To use rspec for testing you must install rspec gem:
+ gem install rspec
+EOS
+ exit(0)
+end
+
+desc "Run the specs under spec/models"
+Spec::Rake::SpecTask.new do |t|
+ t.spec_opts = ['--options', "spec/spec.opts"]
+ t.spec_files = FileList['spec/*_spec.rb']
+end
diff --git a/vendor/diff-display/tasks/website.rake b/vendor/diff-display/tasks/website.rake
new file mode 100644
index 0000000..93e03fa
--- /dev/null
+++ b/vendor/diff-display/tasks/website.rake
@@ -0,0 +1,17 @@
+desc 'Generate website files'
+task :website_generate => :ruby_env do
+ (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
+ sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
+ end
+end
+
+desc 'Upload website files to rubyforge'
+task :website_upload do
+ host = "#{rubyforge_username}@rubyforge.org"
+ remote_dir = "/var/www/gforge-projects/#{PATH}/"
+ local_dir = 'website'
+ sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
+end
+
+desc 'Generate and upload website files'
+task :website => [:website_generate, :website_upload, :publish_docs]
diff --git a/vendor/diff-display/test/.tc_diff_display_unified.rb.swp b/vendor/diff-display/test/.tc_diff_display_unified.rb.swp
deleted file mode 100644
index 28b76c5..0000000
--- a/vendor/diff-display/test/.tc_diff_display_unified.rb.swp
+++ /dev/null
Binary files differ
diff --git a/vendor/diff-display/test/abstract_unit.rb b/vendor/diff-display/test/abstract_unit.rb
deleted file mode 100644
index 2129c5d..0000000
--- a/vendor/diff-display/test/abstract_unit.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-require 'test/unit'
-require 'yaml'
-
-$:.unshift(File.dirname(__FILE__) + '/../lib')
-require 'diff/display/unified'
-
-module Kernel
- def load_diffs(*diffs)
- loaded_diffs = Hash.new({})
- diff_path = File.join(File.dirname(__FILE__), 'diffs')
- diffs.each do |diff_name|
- diff = IO.readlines(File.join(diff_path, diff_name.id2name + '.diff'))
- data = Diff::Display::Unified::Generator.run(diff)
- loaded_diffs[diff_name] = {:diff => diff, :data => data}
- end
- loaded_diffs
- end
- alias_method :load_diff, :load_diffs
-
- def load_all_diffs(path = File.join(File.dirname(__FILE__), 'diffs'))
- load_diffs *Dir.glob(path + '/*.diff').map {|d| File.basename(d, '.*').intern}
- end
-
-end
-
-class Array
- def normalize_diff
- diff = delete_if {|elem| %w{++ -- @@}.include?(elem[0,2])}
- diff.map {|elem| elem.gsub(/^./, '').chomp}
- end
-
- def normalize_diff_object
- delete_if {|elem| elem.is_a? Diff::Display::Unified::SepBlock}.flatten
- end
-
- def diff_inline_line_numbers
- numbers = []
- diff = delete_if {|elem| %w{++ -- @@}.include?(elem[0,2])}
- diff.each_with_index do |elem, idx|
- numbers.concat([idx - 1, idx]) if self[idx][0,1].eql?('+') and self[idx - 1][0,1].eql?('-')
- end
- numbers
- end
-
- def data_inline_line_numbers
- numbers = []
- normalize_diff_object.each_with_index do |elem, idx|
- numbers.push idx if elem.contains_inline_change?
- end
- numbers
- end
-end
diff --git a/vendor/diff-display/test/diff_display_unified_test.rb b/vendor/diff-display/test/diff_display_unified_test.rb
deleted file mode 100644
index 40a4f07..0000000
--- a/vendor/diff-display/test/diff_display_unified_test.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require File.dirname(__FILE__) + '/abstract_unit'
-
-class DisplayUnifiedTest < Test::Unit::TestCase
-
- def setup
- @diffs = load_all_diffs
- @diffs_with_inline_changes = load_diffs :inline_changes
- end
-
- def test_parity_of_diffs_and_data_objects
- @diffs.keys.each do |d|
- assert_equal(@diffs[d][:data].normalize_diff_object,
- @diffs[d][:diff].normalize_diff,
- "Data object and diff file for #{d} don't match")
- end
- end
-
- def test_parity_of_inline_changes
- @diffs_with_inline_changes.keys.each do |d|
- assert_equal(@diffs[d][:data].data_inline_line_numbers,
- @diffs[d][:diff].diff_inline_line_numbers,
- "Inline change line numbers don't match up for #{d}")
- end
- end
-
- # def test_edgecase
- # diff = load_diff(:edgecase1_diff)[:edgecase1_diff]
- # assert_equal(diff[:data].normalize_diff_object,
- # diff[:diff].normalize_diff,
- # "Data object and diff file for #{diff} don't match")
- # end
-
-end
diff --git a/vendor/diff-display/test/diffs/inline_changes.changes b/vendor/diff-display/test/diffs/inline_changes.changes
deleted file mode 100644
index a0b50ab..0000000
--- a/vendor/diff-display/test/diffs/inline_changes.changes
+++ /dev/null
@@ -1,43 +0,0 @@
-Tom Copeland is the administrator for RubyForge, which opened in July 2003
-and now hosts over 450 projects. Tom works at Rich Kilmer's red-minded
-company InfoEther.
-
-1. So, give us an idea. How much time do you put into RubyForge?
-
-Hm. Maybe... ninteen hours a day of actual work. So I mull over it
-constantly. And occasionally things arise that take more time, like
-when we got the new hardware, and putting out the Wiki spam fires,
-and so forth.
-
-2. RubyForge has been an incredible contribution to Ruby coders. You are
-so responsive and it's great to have an admin who is directly involved
-with Ruby-Talk and all the various projects. What drives you to work on
-RubyForge? TELL US!! WHY ARE YOU SO BLASTED GOOD??
-
-Thank you! :blushes:
-
-I don't know...it's fun to work on RubyForge, because I see lots of new
-projects. For example, seeing Michael Neumann's postgres-pr project come
-out was neat, because I was able to use it on RubyForge right away. Also,
-I get to chat with lots of Rubyists about various things, and most of the
-folks I talk with are much more savvy than I am, so I'm always learning
-lots about Ruby and system administration and what-have-you. Especially
-the what-have-you.
-
-3. You've added so many excellent components: project wikis, RubyGems
-integration, BitTorrents. Are there any components of RubyForge that
-are bothersome? Anything you regret?
-
-Let's not dwell on the sad things...we must leave them in our
-wake. Instead, let us look ahead to a bright future, with Ruwiki replacing
-UseMod as the default Wiki, with Subversion support, and with RubyForge
-sitting on a 32 CPU Sun E10K behind a T3 pipe all purchased by my lottery
-winnings! Note: some future items may be more likely than others.
-
-4. Will you find a random image on Google to share with us?
-
-Love those McGuffey Readers:
-
-5. Getting anything cool for Christmas?
-
-A 12 passenger bicycle to carry my ever-growing family to and fro.
diff --git a/vendor/diff-display/test/diffs/inline_changes.diff b/vendor/diff-display/test/diffs/inline_changes.diff
deleted file mode 100644
index 2a66106..0000000
--- a/vendor/diff-display/test/diffs/inline_changes.diff
+++ /dev/null
@@ -1,35 +0,0 @@
---- inline_changes.orig 2004-12-24 08:37:18.000000000 +0000
-+++ inline_changes.changes 2004-12-24 10:19:11.000000000 +0000
-@@ -4,7 +4,7 @@
-
- 1. So, give us an idea. How much time do you put into RubyForge?
-
--Hm. Maybe... half an hour a day of actual work. But I mull over it
-+Hm. Maybe... ninteen hours a day of actual work. So I mull over it
- constantly. And occasionally things arise that take more time, like
- when we got the new hardware, and putting out the Wiki spam fires,
- and so forth.
-@@ -16,7 +16,7 @@
-
- Thank you! :blushes:
-
--I don't know... it's fun to work on RubyForge, because I see lots of new
-+I don't know...it's fun to work on RubyForge, because I see lots of new
- projects. For example, seeing Michael Neumann's postgres-pr project come
- out was neat, because I was able to use it on RubyForge right away. Also,
- I get to chat with lots of Rubyists about various things, and most of the
-@@ -28,7 +28,7 @@
- integration, BitTorrents. Are there any components of RubyForge that
- are bothersome? Anything you regret?
-
--Let's not dwell on the sad things... we must leave them in our
-+Let's not dwell on the sad things...we must leave them in our
- wake. Instead, let us look ahead to a bright future, with Ruwiki replacing
- UseMod as the default Wiki, with Subversion support, and with RubyForge
- sitting on a 32 CPU Sun E10K behind a T3 pipe all purchased by my lottery
-@@ -40,4 +40,4 @@
-
- 5. Getting anything cool for Christmas?
-
--A 12 passenger van to contain carry my ever-growing family to and fro.
-+A 12 passenger bicycle to carry my ever-growing family to and fro.
diff --git a/vendor/diff-display/test/diffs/inline_changes.orig b/vendor/diff-display/test/diffs/inline_changes.orig
deleted file mode 100644
index 2985019..0000000
--- a/vendor/diff-display/test/diffs/inline_changes.orig
+++ /dev/null
@@ -1,43 +0,0 @@
-Tom Copeland is the administrator for RubyForge, which opened in July 2003
-and now hosts over 450 projects. Tom works at Rich Kilmer's red-minded
-company InfoEther.
-
-1. So, give us an idea. How much time do you put into RubyForge?
-
-Hm. Maybe... half an hour a day of actual work. But I mull over it
-constantly. And occasionally things arise that take more time, like
-when we got the new hardware, and putting out the Wiki spam fires,
-and so forth.
-
-2. RubyForge has been an incredible contribution to Ruby coders. You are
-so responsive and it's great to have an admin who is directly involved
-with Ruby-Talk and all the various projects. What drives you to work on
-RubyForge? TELL US!! WHY ARE YOU SO BLASTED GOOD??
-
-Thank you! :blushes:
-
-I don't know... it's fun to work on RubyForge, because I see lots of new
-projects. For example, seeing Michael Neumann's postgres-pr project come
-out was neat, because I was able to use it on RubyForge right away. Also,
-I get to chat with lots of Rubyists about various things, and most of the
-folks I talk with are much more savvy than I am, so I'm always learning
-lots about Ruby and system administration and what-have-you. Especially
-the what-have-you.
-
-3. You've added so many excellent components: project wikis, RubyGems
-integration, BitTorrents. Are there any components of RubyForge that
-are bothersome? Anything you regret?
-
-Let's not dwell on the sad things... we must leave them in our
-wake. Instead, let us look ahead to a bright future, with Ruwiki replacing
-UseMod as the default Wiki, with Subversion support, and with RubyForge
-sitting on a 32 CPU Sun E10K behind a T3 pipe all purchased by my lottery
-winnings! Note: some future items may be more likely than others.
-
-4. Will you find a random image on Google to share with us?
-
-Love those McGuffey Readers:
-
-5. Getting anything cool for Christmas?
-
-A 12 passenger van to contain carry my ever-growing family to and fro.
diff --git a/vendor/diff-display/test/diffs/plain_text.changed b/vendor/diff-display/test/diffs/plain_text.changed
deleted file mode 100644
index 175aa26..0000000
--- a/vendor/diff-display/test/diffs/plain_text.changed
+++ /dev/null
@@ -1,7 +0,0 @@
-Following a recent article which corrolated a language's failure with
-the facial hair of its designer, Larry Wall offered this dishearting pic of his
-naked-as-a-baby's butt cheeks. If your resolution is too high to make out the shot,
-then you're missing out on five metric tons of Awesome.
-
-You also might note that Wall's blog is all tricked out with Christmas
-trees and stuff.
diff --git a/vendor/diff-display/test/diffs/plain_text.diff b/vendor/diff-display/test/diffs/plain_text.diff
deleted file mode 100644
index aa2c6de..0000000
--- a/vendor/diff-display/test/diffs/plain_text.diff
+++ /dev/null
@@ -1,16 +0,0 @@
---- plain_text.orig 2004-12-24 08:36:11.000000000 +0000
-+++ plain_text.changed 2004-12-24 08:45:53.000000000 +0000
-@@ -1,8 +1,7 @@
--Following a recent article which corrolated a language's success with
--the facial hair of its designer, Matz offered this spritely pic of his
--Christmas beard. If your resolution is too high to make out the shot,
-+Following a recent article which corrolated a language's failure with
-+the facial hair of its designer, Larry Wall offered this dishearting pic of his
-+naked-as-a-baby's butt cheeks. If your resolution is too high to make out the shot,
- then you're missing out on five metric tons of Awesome.
-
--You also might note that Matz' blog is all tricked out with Christmas
--trees and stuff. See, the smartest man alive is still capable of
--appreciating little animated GIFs.
-+You also might note that Wall's blog is all tricked out with Christmas
-+trees and stuff.
diff --git a/vendor/diff-display/test/diffs/plain_text.orig b/vendor/diff-display/test/diffs/plain_text.orig
deleted file mode 100644
index fbb0e58..0000000
--- a/vendor/diff-display/test/diffs/plain_text.orig
+++ /dev/null
@@ -1,8 +0,0 @@
-Following a recent article which corrolated a language's success with
-the facial hair of its designer, Matz offered this spritely pic of his
-Christmas beard. If your resolution is too high to make out the shot,
-then you're missing out on five metric tons of Awesome.
-
-You also might note that Matz' blog is all tricked out with Christmas
-trees and stuff. See, the smartest man alive is still capable of
-appreciating little animated GIFs.
diff --git a/vendor/diff-display/test/parity_between_diff_and_data_test.rb b/vendor/diff-display/test/parity_between_diff_and_data_test.rb
deleted file mode 100644
index 1eb5037..0000000
--- a/vendor/diff-display/test/parity_between_diff_and_data_test.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require File.dirname(__FILE__) + '/abstract_unit'
-
-class ParityBetweenDiffAndDataTest < Test::Unit::TestCase
-
- def setup
- @diffs = load_all_diffs
- @diffs_with_inline_changes = load_diffs :inline_changes
- end
-
- def test_parity_of_diffs_and_data_objects
- @diffs.keys.each do |d|
- assert_equal(@diffs[d][:data].normalize_diff_object,
- @diffs[d][:diff].normalize_diff,
- "Data object and diff file for #{d} don't match")
- end
- end
-
- def test_parity_of_inline_changes
- @diffs_with_inline_changes.keys.each do |d|
- assert_equal(@diffs[d][:data].data_inline_line_numbers,
- @diffs[d][:diff].diff_inline_line_numbers,
- "Inline change line numbers don't match up for #{d}")
- end
- end
-
-end
diff --git a/vendor/diff-display/website/index.html b/vendor/diff-display/website/index.html
new file mode 100644
index 0000000..fa21304
--- /dev/null
+++ b/vendor/diff-display/website/index.html
@@ -0,0 +1,11 @@
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+ <title>diff-display</title>
+
+ </head>
+ <body id="body">
+ <p>This page has not yet been created for RubyGem <code>diff-display</code></p>
+ <p>To the developer: To generate it, update website/index.txt and run the rake task <code>website</code> to generate this <code>index.html</code> file.</p>
+ </body>
+</html> \ No newline at end of file
diff --git a/vendor/diff-display/website/index.txt b/vendor/diff-display/website/index.txt
new file mode 100644
index 0000000..d15ec42
--- /dev/null
+++ b/vendor/diff-display/website/index.txt
@@ -0,0 +1,39 @@
+h1. diff display
+
+h1. &#x2192; 'diff-display'
+
+
+h2. What
+
+
+h2. Installing
+
+<pre syntax="ruby">sudo gem install diff-display</pre>
+
+h2. The basics
+
+
+h2. Demonstration of usage
+
+
+
+h2. Forum
+
+"http://groups.google.com/group/diff-display":http://groups.google.com/group/diff-display
+
+TODO - create Google Group - diff-display
+
+h2. How to submit patches
+
+Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/ and for section "8b: Submit patch to Google Groups":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups, use the Google Group above.
+
+The trunk repository is <code>svn://rubyforge.org/var/svn/diff-display/trunk</code> for anonymous access.
+
+h2. License
+
+This code is free to use under the terms of the MIT license.
+
+h2. Contact
+
+Comments are welcome. Send an email to "FIXME full name":mailto:FIXME email via the "forum":http://groups.google.com/group/diff-display
+
diff --git a/vendor/diff-display/website/javascripts/rounded_corners_lite.inc.js b/vendor/diff-display/website/javascripts/rounded_corners_lite.inc.js
new file mode 100644
index 0000000..afc3ea3
--- /dev/null
+++ b/vendor/diff-display/website/javascripts/rounded_corners_lite.inc.js
@@ -0,0 +1,285 @@
+
+ /****************************************************************
+ * *
+ * curvyCorners *
+ * ------------ *
+ * *
+ * This script generates rounded corners for your divs. *
+ * *
+ * Version 1.2.9 *
+ * Copyright (c) 2006 Cameron Cooke *
+ * By: Cameron Cooke and Tim Hutchison. *
+ * *
+ * *
+ * Website: http://www.curvycorners.net *
+ * Email: info@totalinfinity.com *
+ * Forum: http://www.curvycorners.net/forum/ *
+ * *
+ * *
+ * This library is free software; you can redistribute *
+ * it and/or modify it under the terms of the GNU *
+ * Lesser General Public License as published by the *
+ * Free Software Foundation; either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will *
+ * be useful, but WITHOUT ANY WARRANTY; without even the *
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A *
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public *
+ * License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser *
+ * General Public License along with this library; *
+ * Inc., 59 Temple Place, Suite 330, Boston, *
+ * MA 02111-1307 USA *
+ * *
+ ****************************************************************/
+
+var isIE = navigator.userAgent.toLowerCase().indexOf("msie") > -1; var isMoz = document.implementation && document.implementation.createDocument; var isSafari = ((navigator.userAgent.toLowerCase().indexOf('safari')!=-1)&&(navigator.userAgent.toLowerCase().indexOf('mac')!=-1))?true:false; function curvyCorners()
+{ if(typeof(arguments[0]) != "object") throw newCurvyError("First parameter of curvyCorners() must be an object."); if(typeof(arguments[1]) != "object" && typeof(arguments[1]) != "string") throw newCurvyError("Second parameter of curvyCorners() must be an object or a class name."); if(typeof(arguments[1]) == "string")
+{ var startIndex = 0; var boxCol = getElementsByClass(arguments[1]);}
+else
+{ var startIndex = 1; var boxCol = arguments;}
+var curvyCornersCol = new Array(); if(arguments[0].validTags)
+var validElements = arguments[0].validTags; else
+var validElements = ["div"]; for(var i = startIndex, j = boxCol.length; i < j; i++)
+{ var currentTag = boxCol[i].tagName.toLowerCase(); if(inArray(validElements, currentTag) !== false)
+{ curvyCornersCol[curvyCornersCol.length] = new curvyObject(arguments[0], boxCol[i]);}
+}
+this.objects = curvyCornersCol; this.applyCornersToAll = function()
+{ for(var x = 0, k = this.objects.length; x < k; x++)
+{ this.objects[x].applyCorners();}
+}
+}
+function curvyObject()
+{ this.box = arguments[1]; this.settings = arguments[0]; this.topContainer = null; this.bottomContainer = null; this.masterCorners = new Array(); this.contentDIV = null; var boxHeight = get_style(this.box, "height", "height"); var boxWidth = get_style(this.box, "width", "width"); var borderWidth = get_style(this.box, "borderTopWidth", "border-top-width"); var borderColour = get_style(this.box, "borderTopColor", "border-top-color"); var boxColour = get_style(this.box, "backgroundColor", "background-color"); var backgroundImage = get_style(this.box, "backgroundImage", "background-image"); var boxPosition = get_style(this.box, "position", "position"); var boxPadding = get_style(this.box, "paddingTop", "padding-top"); this.boxHeight = parseInt(((boxHeight != "" && boxHeight != "auto" && boxHeight.indexOf("%") == -1)? boxHeight.substring(0, boxHeight.indexOf("px")) : this.box.scrollHeight)); this.boxWidth = parseInt(((boxWidth != "" && boxWidth != "auto" && boxWidth.indexOf("%") == -1)? boxWidth.substring(0, boxWidth.indexOf("px")) : this.box.scrollWidth)); this.borderWidth = parseInt(((borderWidth != "" && borderWidth.indexOf("px") !== -1)? borderWidth.slice(0, borderWidth.indexOf("px")) : 0)); this.boxColour = format_colour(boxColour); this.boxPadding = parseInt(((boxPadding != "" && boxPadding.indexOf("px") !== -1)? boxPadding.slice(0, boxPadding.indexOf("px")) : 0)); this.borderColour = format_colour(borderColour); this.borderString = this.borderWidth + "px" + " solid " + this.borderColour; this.backgroundImage = ((backgroundImage != "none")? backgroundImage : ""); this.boxContent = this.box.innerHTML; if(boxPosition != "absolute") this.box.style.position = "relative"; this.box.style.padding = "0px"; if(isIE && boxWidth == "auto" && boxHeight == "auto") this.box.style.width = "100%"; if(this.settings.autoPad == true && this.boxPadding > 0)
+this.box.innerHTML = ""; this.applyCorners = function()
+{ for(var t = 0; t < 2; t++)
+{ switch(t)
+{ case 0:
+if(this.settings.tl || this.settings.tr)
+{ var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var topMaxRadius = Math.max(this.settings.tl ? this.settings.tl.radius : 0, this.settings.tr ? this.settings.tr.radius : 0); newMainContainer.style.height = topMaxRadius + "px"; newMainContainer.style.top = 0 - topMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.topContainer = this.box.appendChild(newMainContainer);}
+break; case 1:
+if(this.settings.bl || this.settings.br)
+{ var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var botMaxRadius = Math.max(this.settings.bl ? this.settings.bl.radius : 0, this.settings.br ? this.settings.br.radius : 0); newMainContainer.style.height = botMaxRadius + "px"; newMainContainer.style.bottom = 0 - botMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.bottomContainer = this.box.appendChild(newMainContainer);}
+break;}
+}
+if(this.topContainer) this.box.style.borderTopWidth = "0px"; if(this.bottomContainer) this.box.style.borderBottomWidth = "0px"; var corners = ["tr", "tl", "br", "bl"]; for(var i in corners)
+{ if(i > -1 < 4)
+{ var cc = corners[i]; if(!this.settings[cc])
+{ if(((cc == "tr" || cc == "tl") && this.topContainer != null) || ((cc == "br" || cc == "bl") && this.bottomContainer != null))
+{ var newCorner = document.createElement("DIV"); newCorner.style.position = "relative"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; if(this.backgroundImage == "")
+newCorner.style.backgroundColor = this.boxColour; else
+newCorner.style.backgroundImage = this.backgroundImage; switch(cc)
+{ case "tl":
+newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.tr.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.left = -this.borderWidth + "px"; break; case "tr":
+newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.tl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; newCorner.style.left = this.borderWidth + "px"; break; case "bl":
+newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.br.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = -this.borderWidth + "px"; newCorner.style.backgroundPosition = "-" + (this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break; case "br":
+newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.bl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = this.borderWidth + "px"
+newCorner.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break;}
+}
+}
+else
+{ if(this.masterCorners[this.settings[cc].radius])
+{ var newCorner = this.masterCorners[this.settings[cc].radius].cloneNode(true);}
+else
+{ var newCorner = document.createElement("DIV"); newCorner.style.height = this.settings[cc].radius + "px"; newCorner.style.width = this.settings[cc].radius + "px"; newCorner.style.position = "absolute"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; var borderRadius = parseInt(this.settings[cc].radius - this.borderWidth); for(var intx = 0, j = this.settings[cc].radius; intx < j; intx++)
+{ if((intx +1) >= borderRadius)
+var y1 = -1; else
+var y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1); if(borderRadius != j)
+{ if((intx) >= borderRadius)
+var y2 = -1; else
+var y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2))); if((intx+1) >= j)
+var y3 = -1; else
+var y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);}
+if((intx) >= j)
+var y4 = -1; else
+var y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2))); if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner, -1, this.settings[cc].radius); if(borderRadius != j)
+{ for(var inty = (y1 + 1); inty < y2; inty++)
+{ if(this.settings.antiAlias)
+{ if(this.backgroundImage != "")
+{ var borderFract = (pixelFraction(intx, inty, borderRadius) * 100); if(borderFract < 30)
+{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, 0, this.settings[cc].radius);}
+else
+{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, -1, this.settings[cc].radius);}
+}
+else
+{ var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, borderRadius)); this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner, 0, this.settings[cc].radius, cc);}
+}
+}
+if(this.settings.antiAlias)
+{ if(y3 >= y2)
+{ if (y2 == -1) y2 = 0; this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner, 0, 0);}
+}
+else
+{ if(y3 >= y1)
+{ this.drawPixel(intx, (y1 + 1), this.borderColour, 100, (y3 - y1), newCorner, 0, 0);}
+}
+var outsideColour = this.borderColour;}
+else
+{ var outsideColour = this.boxColour; var y3 = y1;}
+if(this.settings.antiAlias)
+{ for(var inty = (y3 + 1); inty < y4; inty++)
+{ this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty , j) * 100), 1, newCorner, ((this.borderWidth > 0)? 0 : -1), this.settings[cc].radius);}
+}
+}
+this.masterCorners[this.settings[cc].radius] = newCorner.cloneNode(true);}
+if(cc != "br")
+{ for(var t = 0, k = newCorner.childNodes.length; t < k; t++)
+{ var pixelBar = newCorner.childNodes[t]; var pixelBarTop = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px"))); var pixelBarLeft = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px"))); var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px"))); if(cc == "tl" || cc == "bl"){ pixelBar.style.left = this.settings[cc].radius -pixelBarLeft -1 + "px";}
+if(cc == "tr" || cc == "tl"){ pixelBar.style.top = this.settings[cc].radius -pixelBarHeight -pixelBarTop + "px";}
+switch(cc)
+{ case "tr":
+pixelBar.style.backgroundPosition = "-" + Math.abs((this.boxWidth - this.settings[cc].radius + this.borderWidth) + pixelBarLeft) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "tl":
+pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "bl":
+pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs((this.boxHeight + this.settings[cc].radius + pixelBarTop) -this.borderWidth) + "px"; break;}
+}
+}
+}
+if(newCorner)
+{ switch(cc)
+{ case "tl":
+if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "tr":
+if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "bl":
+if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break; case "br":
+if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break;}
+}
+}
+}
+var radiusDiff = new Array(); radiusDiff["t"] = Math.abs(this.settings.tl.radius - this.settings.tr.radius)
+radiusDiff["b"] = Math.abs(this.settings.bl.radius - this.settings.br.radius); for(z in radiusDiff)
+{ if(z == "t" || z == "b")
+{ if(radiusDiff[z])
+{ var smallerCornerType = ((this.settings[z + "l"].radius < this.settings[z + "r"].radius)? z +"l" : z +"r"); var newFiller = document.createElement("DIV"); newFiller.style.height = radiusDiff[z] + "px"; newFiller.style.width = this.settings[smallerCornerType].radius+ "px"
+newFiller.style.position = "absolute"; newFiller.style.fontSize = "1px"; newFiller.style.overflow = "hidden"; newFiller.style.backgroundColor = this.boxColour; switch(smallerCornerType)
+{ case "tl":
+newFiller.style.bottom = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.topContainer.appendChild(newFiller); break; case "tr":
+newFiller.style.bottom = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.topContainer.appendChild(newFiller); break; case "bl":
+newFiller.style.top = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.bottomContainer.appendChild(newFiller); break; case "br":
+newFiller.style.top = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.bottomContainer.appendChild(newFiller); break;}
+}
+var newFillerBar = document.createElement("DIV"); newFillerBar.style.position = "relative"; newFillerBar.style.fontSize = "1px"; newFillerBar.style.overflow = "hidden"; newFillerBar.style.backgroundColor = this.boxColour; newFillerBar.style.backgroundImage = this.backgroundImage; switch(z)
+{ case "t":
+if(this.topContainer)
+{ if(this.settings.tl.radius && this.settings.tr.radius)
+{ newFillerBar.style.height = topMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.tl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.tr.radius - this.borderWidth + "px"; newFillerBar.style.borderTop = this.borderString; if(this.backgroundImage != "")
+newFillerBar.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; this.topContainer.appendChild(newFillerBar);}
+this.box.style.backgroundPosition = "0px -" + (topMaxRadius - this.borderWidth) + "px";}
+break; case "b":
+if(this.bottomContainer)
+{ if(this.settings.bl.radius && this.settings.br.radius)
+{ newFillerBar.style.height = botMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.bl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.br.radius - this.borderWidth + "px"; newFillerBar.style.borderBottom = this.borderString; if(this.backgroundImage != "")
+newFillerBar.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (topMaxRadius + this.borderWidth)) + "px"; this.bottomContainer.appendChild(newFillerBar);}
+}
+break;}
+}
+}
+if(this.settings.autoPad == true && this.boxPadding > 0)
+{ var contentContainer = document.createElement("DIV"); contentContainer.style.position = "relative"; contentContainer.innerHTML = this.boxContent; contentContainer.className = "autoPadDiv"; var topPadding = Math.abs(topMaxRadius - this.boxPadding); var botPadding = Math.abs(botMaxRadius - this.boxPadding); if(topMaxRadius < this.boxPadding)
+contentContainer.style.paddingTop = topPadding + "px"; if(botMaxRadius < this.boxPadding)
+contentContainer.style.paddingBottom = botMaxRadius + "px"; contentContainer.style.paddingLeft = this.boxPadding + "px"; contentContainer.style.paddingRight = this.boxPadding + "px"; this.contentDIV = this.box.appendChild(contentContainer);}
+}
+this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius)
+{ var pixel = document.createElement("DIV"); pixel.style.height = height + "px"; pixel.style.width = "1px"; pixel.style.position = "absolute"; pixel.style.fontSize = "1px"; pixel.style.overflow = "hidden"; var topMaxRadius = Math.max(this.settings["tr"].radius, this.settings["tl"].radius); if(image == -1 && this.backgroundImage != "")
+{ pixel.style.backgroundImage = this.backgroundImage; pixel.style.backgroundPosition = "-" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + "px -" + ((this.boxHeight + topMaxRadius + inty) -this.borderWidth) + "px";}
+else
+{ pixel.style.backgroundColor = colour;}
+if (transAmount != 100)
+setOpacity(pixel, transAmount); pixel.style.top = inty + "px"; pixel.style.left = intx + "px"; newCorner.appendChild(pixel);}
+}
+function insertAfter(parent, node, referenceNode)
+{ parent.insertBefore(node, referenceNode.nextSibling);}
+function BlendColour(Col1, Col2, Col1Fraction)
+{ var red1 = parseInt(Col1.substr(1,2),16); var green1 = parseInt(Col1.substr(3,2),16); var blue1 = parseInt(Col1.substr(5,2),16); var red2 = parseInt(Col2.substr(1,2),16); var green2 = parseInt(Col2.substr(3,2),16); var blue2 = parseInt(Col2.substr(5,2),16); if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1; var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction))); if(endRed > 255) endRed = 255; if(endRed < 0) endRed = 0; var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction))); if(endGreen > 255) endGreen = 255; if(endGreen < 0) endGreen = 0; var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction))); if(endBlue > 255) endBlue = 255; if(endBlue < 0) endBlue = 0; return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);}
+function IntToHex(strNum)
+{ base = strNum / 16; rem = strNum % 16; base = base - (rem / 16); baseS = MakeHex(base); remS = MakeHex(rem); return baseS + '' + remS;}
+function MakeHex(x)
+{ if((x >= 0) && (x <= 9))
+{ return x;}
+else
+{ switch(x)
+{ case 10: return "A"; case 11: return "B"; case 12: return "C"; case 13: return "D"; case 14: return "E"; case 15: return "F";}
+}
+}
+function pixelFraction(x, y, r)
+{ var pixelfraction = 0; var xvalues = new Array(1); var yvalues = new Array(1); var point = 0; var whatsides = ""; var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2))); if ((intersect >= y) && (intersect < (y+1)))
+{ whatsides = "Left"; xvalues[point] = 0; yvalues[point] = intersect - y; point = point + 1;}
+var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2))); if ((intersect >= x) && (intersect < (x+1)))
+{ whatsides = whatsides + "Top"; xvalues[point] = intersect - x; yvalues[point] = 1; point = point + 1;}
+var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2))); if ((intersect >= y) && (intersect < (y+1)))
+{ whatsides = whatsides + "Right"; xvalues[point] = 1; yvalues[point] = intersect - y; point = point + 1;}
+var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2))); if ((intersect >= x) && (intersect < (x+1)))
+{ whatsides = whatsides + "Bottom"; xvalues[point] = intersect - x; yvalues[point] = 0;}
+switch (whatsides)
+{ case "LeftRight":
+pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2); break; case "TopRight":
+pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2); break; case "TopBottom":
+pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2); break; case "LeftBottom":
+pixelfraction = (yvalues[0]*xvalues[1])/2; break; default:
+pixelfraction = 1;}
+return pixelfraction;}
+function rgb2Hex(rgbColour)
+{ try{ var rgbArray = rgb2Array(rgbColour); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue);}
+catch(e){ alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");}
+return hexColour;}
+function rgb2Array(rgbColour)
+{ var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")")); var rgbArray = rgbValues.split(", "); return rgbArray;}
+function setOpacity(obj, opacity)
+{ opacity = (opacity == 100)?99.999:opacity; if(isSafari && obj.tagName != "IFRAME")
+{ var rgbArray = rgb2Array(obj.style.backgroundColor); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); obj.style.backgroundColor = "rgba(" + red + ", " + green + ", " + blue + ", " + opacity/100 + ")";}
+else if(typeof(obj.style.opacity) != "undefined")
+{ obj.style.opacity = opacity/100;}
+else if(typeof(obj.style.MozOpacity) != "undefined")
+{ obj.style.MozOpacity = opacity/100;}
+else if(typeof(obj.style.filter) != "undefined")
+{ obj.style.filter = "alpha(opacity:" + opacity + ")";}
+else if(typeof(obj.style.KHTMLOpacity) != "undefined")
+{ obj.style.KHTMLOpacity = opacity/100;}
+}
+function inArray(array, value)
+{ for(var i = 0; i < array.length; i++){ if (array[i] === value) return i;}
+return false;}
+function inArrayKey(array, value)
+{ for(key in array){ if(key === value) return true;}
+return false;}
+function addEvent(elm, evType, fn, useCapture) { if (elm.addEventListener) { elm.addEventListener(evType, fn, useCapture); return true;}
+else if (elm.attachEvent) { var r = elm.attachEvent('on' + evType, fn); return r;}
+else { elm['on' + evType] = fn;}
+}
+function removeEvent(obj, evType, fn, useCapture){ if (obj.removeEventListener){ obj.removeEventListener(evType, fn, useCapture); return true;} else if (obj.detachEvent){ var r = obj.detachEvent("on"+evType, fn); return r;} else { alert("Handler could not be removed");}
+}
+function format_colour(colour)
+{ var returnColour = "#ffffff"; if(colour != "" && colour != "transparent")
+{ if(colour.substr(0, 3) == "rgb")
+{ returnColour = rgb2Hex(colour);}
+else if(colour.length == 4)
+{ returnColour = "#" + colour.substring(1, 2) + colour.substring(1, 2) + colour.substring(2, 3) + colour.substring(2, 3) + colour.substring(3, 4) + colour.substring(3, 4);}
+else
+{ returnColour = colour;}
+}
+return returnColour;}
+function get_style(obj, property, propertyNS)
+{ try
+{ if(obj.currentStyle)
+{ var returnVal = eval("obj.currentStyle." + property);}
+else
+{ if(isSafari && obj.style.display == "none")
+{ obj.style.display = ""; var wasHidden = true;}
+var returnVal = document.defaultView.getComputedStyle(obj, '').getPropertyValue(propertyNS); if(isSafari && wasHidden)
+{ obj.style.display = "none";}
+}
+}
+catch(e)
+{ }
+return returnVal;}
+function getElementsByClass(searchClass, node, tag)
+{ var classElements = new Array(); if(node == null)
+node = document; if(tag == null)
+tag = '*'; var els = node.getElementsByTagName(tag); var elsLen = els.length; var pattern = new RegExp("(^|\s)"+searchClass+"(\s|$)"); for (i = 0, j = 0; i < elsLen; i++)
+{ if(pattern.test(els[i].className))
+{ classElements[j] = els[i]; j++;}
+}
+return classElements;}
+function newCurvyError(errorMessage)
+{ return new Error("curvyCorners Error:\n" + errorMessage)
+}
diff --git a/vendor/diff-display/website/stylesheets/screen.css b/vendor/diff-display/website/stylesheets/screen.css
new file mode 100644
index 0000000..2c84cd0
--- /dev/null
+++ b/vendor/diff-display/website/stylesheets/screen.css
@@ -0,0 +1,138 @@
+body {
+ background-color: #E1D1F1;
+ font-family: "Georgia", sans-serif;
+ font-size: 16px;
+ line-height: 1.6em;
+ padding: 1.6em 0 0 0;
+ color: #333;
+}
+h1, h2, h3, h4, h5, h6 {
+ color: #444;
+}
+h1 {
+ font-family: sans-serif;
+ font-weight: normal;
+ font-size: 4em;
+ line-height: 0.8em;
+ letter-spacing: -0.1ex;
+ margin: 5px;
+}
+li {
+ padding: 0;
+ margin: 0;
+ list-style-type: square;
+}
+a {
+ color: #5E5AFF;
+ background-color: #DAC;
+ font-weight: normal;
+ text-decoration: underline;
+}
+blockquote {
+ font-size: 90%;
+ font-style: italic;
+ border-left: 1px solid #111;
+ padding-left: 1em;
+}
+.caps {
+ font-size: 80%;
+}
+
+#main {
+ width: 45em;
+ padding: 0;
+ margin: 0 auto;
+}
+.coda {
+ text-align: right;
+ color: #77f;
+ font-size: smaller;
+}
+
+table {
+ font-size: 90%;
+ line-height: 1.4em;
+ color: #ff8;
+ background-color: #111;
+ padding: 2px 10px 2px 10px;
+ border-style: dashed;
+}
+
+th {
+ color: #fff;
+}
+
+td {
+ padding: 2px 10px 2px 10px;
+}
+
+.success {
+ color: #0CC52B;
+}
+
+.failed {
+ color: #E90A1B;
+}
+
+.unknown {
+ color: #995000;
+}
+pre, code {
+ font-family: monospace;
+ font-size: 90%;
+ line-height: 1.4em;
+ color: #ff8;
+ background-color: #111;
+ padding: 2px 10px 2px 10px;
+}
+.comment { color: #aaa; font-style: italic; }
+.keyword { color: #eff; font-weight: bold; }
+.punct { color: #eee; font-weight: bold; }
+.symbol { color: #0bb; }
+.string { color: #6b4; }
+.ident { color: #ff8; }
+.constant { color: #66f; }
+.regex { color: #ec6; }
+.number { color: #F99; }
+.expr { color: #227; }
+
+#version {
+ float: right;
+ text-align: right;
+ font-family: sans-serif;
+ font-weight: normal;
+ background-color: #B3ABFF;
+ color: #141331;
+ padding: 15px 20px 10px 20px;
+ margin: 0 auto;
+ margin-top: 15px;
+ border: 3px solid #141331;
+}
+
+#version .numbers {
+ display: block;
+ font-size: 4em;
+ line-height: 0.8em;
+ letter-spacing: -0.1ex;
+ margin-bottom: 15px;
+}
+
+#version p {
+ text-decoration: none;
+ color: #141331;
+ background-color: #B3ABFF;
+ margin: 0;
+ padding: 0;
+}
+
+#version a {
+ text-decoration: none;
+ color: #141331;
+ background-color: #B3ABFF;
+}
+
+.clickable {
+ cursor: pointer;
+ cursor: hand;
+}
+
diff --git a/vendor/diff-display/website/template.rhtml b/vendor/diff-display/website/template.rhtml
new file mode 100644
index 0000000..e851735
--- /dev/null
+++ b/vendor/diff-display/website/template.rhtml
@@ -0,0 +1,48 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>
+ <%= title %>
+ </title>
+ <script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
+<style>
+
+</style>
+ <script type="text/javascript">
+ window.onload = function() {
+ settings = {
+ tl: { radius: 10 },
+ tr: { radius: 10 },
+ bl: { radius: 10 },
+ br: { radius: 10 },
+ antiAlias: true,
+ autoPad: true,
+ validTags: ["div"]
+ }
+ var versionBox = new curvyCorners(settings, document.getElementById("version"));
+ versionBox.applyCornersToAll();
+ }
+ </script>
+</head>
+<body>
+<div id="main">
+
+ <h1><%= title %></h1>
+ <div id="version" class="clickable" onclick='document.location = "<%= download %>"; return false'>
+ <p>Get Version</p>
+ <a href="<%= download %>" class="numbers"><%= version %></a>
+ </div>
+ <%= body %>
+ <p class="coda">
+ <a href="FIXME email">FIXME full name</a>, <%= modified.pretty %><br>
+ Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
+ </p>
+</div>
+
+<!-- insert site tracking codes here, like Google Urchin -->
+
+</body>
+</html>