ÿØÿà JFIF    ÿÛ „ ( %!1!%*+...983,7(-.- PK|]$+jirb.rbnu[# # irb.rb - irb main module # $Release Version: 0.9.5 $ # $Revision: 24483 $ # $Date: 2009-08-09 17:44:15 +0900 (Sun, 09 Aug 2009) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "e2mmap" require "irb/init" require "irb/context" require "irb/extend-command" #require "irb/workspace" require "irb/ruby-lex" require "irb/input-method" require "irb/locale" STDOUT.sync = true module IRB @RCS_ID='-$Id: irb.rb 24483 2009-08-09 08:44:15Z shyouhei $-' class Abort < Exception;end # @CONF = {} def IRB.conf @CONF end # IRB version method def IRB.version if v = @CONF[:VERSION] then return v end require "irb/version" rv = @RELEASE_VERSION.sub(/\.0/, "") @CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE) end def IRB.CurrentContext IRB.conf[:MAIN_CONTEXT] end # initialize IRB and start TOP_LEVEL irb def IRB.start(ap_path = nil) $0 = File::basename(ap_path, ".rb") if ap_path IRB.setup(ap_path) if @CONF[:SCRIPT] irb = Irb.new(nil, @CONF[:SCRIPT]) else irb = Irb.new end @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] @CONF[:MAIN_CONTEXT] = irb.context trap("SIGINT") do irb.signal_handle end begin catch(:IRB_EXIT) do irb.eval_input end ensure irb_at_exit end # print "\n" end def IRB.irb_at_exit @CONF[:AT_EXIT].each{|hook| hook.call} end def IRB.irb_exit(irb, ret) throw :IRB_EXIT, ret end def IRB.irb_abort(irb, exception = Abort) if defined? Thread irb.context.thread.raise exception, "abort then interrupt!!" else raise exception, "abort then interrupt!!" end end # # irb interpriter main routine # class Irb def initialize(workspace = nil, input_method = nil, output_method = nil) @context = Context.new(self, workspace, input_method, output_method) @context.main.extend ExtendCommandBundle @signal_status = :IN_IRB @scanner = RubyLex.new @scanner.exception_on_syntax_error = false end attr_reader :context attr_accessor :scanner def eval_input @scanner.set_prompt do |ltype, indent, continue, line_no| if ltype f = @context.prompt_s elsif continue f = @context.prompt_c elsif indent > 0 f = @context.prompt_n else @context.prompt_i f = @context.prompt_i end f = "" unless f if @context.prompting? @context.io.prompt = p = prompt(f, ltype, indent, line_no) else @context.io.prompt = p = "" end if @context.auto_indent_mode unless ltype ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size + indent * 2 - p.size ind += 2 if continue @context.io.prompt = p + " " * ind if ind > 0 end end end @scanner.set_input(@context.io) do signal_status(:IN_INPUT) do if l = @context.io.gets print l if @context.verbose? else if @context.ignore_eof? and @context.io.readable_atfer_eof? l = "\n" if @context.verbose? printf "Use \"exit\" to leave %s\n", @context.ap_name end end end l end end @scanner.each_top_level_statement do |line, line_no| signal_status(:IN_EVAL) do begin line.untaint @context.evaluate(line, line_no) output_value if @context.echo? exc = nil rescue Interrupt => exc rescue SystemExit, SignalException raise rescue Exception => exc end if exc print exc.class, ": ", exc, "\n" if exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ irb_bug = true else irb_bug = false end messages = [] lasts = [] levels = 0 for m in exc.backtrace m = @context.workspace.filter_backtrace(m) unless irb_bug if m if messages.size < @context.back_trace_limit messages.push "\tfrom "+m else lasts.push "\tfrom "+m if lasts.size > @context.back_trace_limit lasts.shift levels += 1 end end end end print messages.join("\n"), "\n" unless lasts.empty? printf "... %d levels...\n", levels if levels > 0 print lasts.join("\n") end print "Maybe IRB bug!!\n" if irb_bug end if $SAFE > 2 abort "Error: irb does not work for $SAFE level higher than 2" end end end end def suspend_name(path = nil, name = nil) @context.irb_path, back_path = path, @context.irb_path if path @context.irb_name, back_name = name, @context.irb_name if name begin yield back_path, back_name ensure @context.irb_path = back_path if path @context.irb_name = back_name if name end end def suspend_workspace(workspace) @context.workspace, back_workspace = workspace, @context.workspace begin yield back_workspace ensure @context.workspace = back_workspace end end def suspend_input_method(input_method) back_io = @context.io @context.instance_eval{@io = input_method} begin yield back_io ensure @context.instance_eval{@io = back_io} end end def suspend_context(context) @context, back_context = context, @context begin yield back_context ensure @context = back_context end end def signal_handle unless @context.ignore_sigint? print "\nabort!!\n" if @context.verbose? exit end case @signal_status when :IN_INPUT print "^C\n" raise RubyLex::TerminateLineInput when :IN_EVAL IRB.irb_abort(self) when :IN_LOAD IRB.irb_abort(self, LoadAbort) when :IN_IRB # ignore else # ignore other cases as well end end def signal_status(status) return yield if @signal_status == :IN_LOAD signal_status_back = @signal_status @signal_status = status begin yield ensure @signal_status = signal_status_back end end def prompt(prompt, ltype, indent, line_no) p = prompt.dup p.gsub!(/%([0-9]+)?([a-zA-Z])/) do case $2 when "N" @context.irb_name when "m" @context.main.to_s when "M" @context.main.inspect when "l" ltype when "i" if $1 format("%" + $1 + "d", indent) else indent.to_s end when "n" if $1 format("%" + $1 + "d", line_no) else line_no.to_s end when "%" "%" end end p end def output_value if @context.inspect? printf @context.return_format, @context.last_value.inspect else printf @context.return_format, @context.last_value end end def inspect ary = [] for iv in instance_variables case iv when "@signal_status" ary.push format("%s=:%s", iv, @signal_status.id2name) when "@context" ary.push format("%s=%s", iv, eval(iv).__to_s__) else ary.push format("%s=%s", iv, eval(iv)) end end format("#<%s: %s>", self.class, ary.join(", ")) end end # Singleton method def @CONF.inspect IRB.version unless self[:VERSION] array = [] for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name} case k when :MAIN_CONTEXT, :__TMP__EHV__ array.push format("CONF[:%s]=...myself...", k.id2name) when :PROMPT s = v.collect{ |kk, vv| ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"} format(":%s=>{%s}", kk.id2name, ss.join(", ")) } array.push format("CONF[:%s]={%s}", k.id2name, s.join(", ")) else array.push format("CONF[:%s]=%s", k.id2name, v.inspect) end end array.join("\n") end end PK|]\ rdoc/usage.rbnu[# = Synopsis # # This library allows command-line tools to encapsulate their usage # as a comment at the top of the main file. Calling RDoc::usage # then displays some or all of that comment, and optionally exits # the program with an exit status. We always look for the comment # in the main program file, so it is safe to call this method # from anywhere in the executing program. # # = Usage # # RDoc::usage( [ exit_status ], [ section, ...]) # RDoc::usage_no_exit( [ section, ...]) # # where: # # exit_status:: # the integer exit code (default zero). RDoc::usage will exit # the calling program with this status. # # section:: # an optional list of section names. If specified, only the # sections with the given names as headings will be output. # For example, this section is named 'Usage', and the next # section is named 'Examples'. The section names are case # insensitive. # # = Examples # # # Comment block describing usage # # with (optional) section headings # # . . . # # require 'rdoc/usage' # # # Display all usage and exit with a status of 0 # # RDoc::usage # # # Display all usage and exit with a status of 99 # # RDoc::usage(99) # # # Display usage in the 'Summary' section only, then # # exit with a status of 99 # # RDoc::usage(99, 'Summary') # # # Display information in the Author and Copyright # # sections, then exit 0. # # RDoc::usage('Author', 'Copyright') # # # Display information in the Author and Copyright # # sections, but don't exit # # RDoc::usage_no_exit('Author', 'Copyright') # # = Author # # Dave Thomas, The Pragmatic Programmers, LLC # # = Copyright # # Copyright (c) 2004 Dave Thomas. # Licensed under the same terms as Ruby # require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_flow' require 'rdoc/ri/ri_formatter' require 'rdoc/ri/ri_options' module RDoc # Display usage information from the comment at the top of # the file. String arguments identify specific sections of the # comment to display. An optional integer first argument # specifies the exit status (defaults to 0) def RDoc.usage(*args) exit_code = 0 if args.size > 0 status = args[0] if status.respond_to?(:to_int) exit_code = status.to_int args.shift end end # display the usage and exit with the given code usage_no_exit(*args) exit(exit_code) end # Display usage def RDoc.usage_no_exit(*args) main_program_file = caller[-1].sub(/:\d+$/, '') comment = File.open(main_program_file) do |file| find_comment(file) end comment = comment.gsub(/^\s*#/, '') markup = SM::SimpleMarkup.new flow_convertor = SM::ToFlow.new flow = markup.convert(comment, flow_convertor) format = "plain" unless args.empty? flow = extract_sections(flow, args) end options = RI::Options.instance if args = ENV["RI"] options.parse(args.split) end formatter = options.formatter.new(options, "") formatter.display_flow(flow) end ###################################################################### private # Find the first comment in the file (that isn't a shebang line) # If the file doesn't start with a comment, report the fact # and return empty string def RDoc.gets(file) if (line = file.gets) && (line =~ /^#!/) # shebang throw :exit, find_comment(file) else line end end def RDoc.find_comment(file) catch(:exit) do # skip leading blank lines 0 while (line = gets(file)) && (line =~ /^\s*$/) comment = [] while line && line =~ /^\s*#/ comment << line line = gets(file) end 0 while line && (line = gets(file)) return no_comment if comment.empty? return comment.join end end ##### # Given an array of flow items and an array of section names, extract those # sections from the flow which have headings corresponding to # a section name in the list. Return them in the order # of names in the +sections+ array. def RDoc.extract_sections(flow, sections) result = [] sections.each do |name| name = name.downcase copy_upto_level = nil flow.each do |item| case item when SM::Flow::H if copy_upto_level && item.level >= copy_upto_level copy_upto_level = nil else if item.text.downcase == name result << item copy_upto_level = item.level end end else if copy_upto_level result << item end end end end if result.empty? puts "Note to developer: requested section(s) [#{sections.join(', ')}] " + "not found" result = flow end result end ##### # Report the fact that no doc comment count be found def RDoc.no_comment $stderr.puts "No usage information available for this program" "" end end if $0 == __FILE__ RDoc::usage(*ARGV) end PK|]w4,,rdoc/markup/test/TestParse.rbnu[require 'test/unit' $:.unshift "../../.." require 'rdoc/markup/simple_markup' include SM class TestParse < Test::Unit::TestCase class MockOutput def start_accepting @res = [] end def end_accepting @res end def accept_paragraph(am, fragment) @res << fragment.to_s end def accept_verbatim(am, fragment) @res << fragment.to_s end def accept_list_start(am, fragment) @res << fragment.to_s end def accept_list_end(am, fragment) @res << fragment.to_s end def accept_list_item(am, fragment) @res << fragment.to_s end def accept_blank_line(am, fragment) @res << fragment.to_s end def accept_heading(am, fragment) @res << fragment.to_s end def accept_rule(am, fragment) @res << fragment.to_s end end def basic_conv(str) sm = SimpleMarkup.new mock = MockOutput.new sm.convert(str, mock) sm.content end def line_types(str, expected) p = SimpleMarkup.new mock = MockOutput.new p.convert(str, mock) assert_equal(expected, p.get_line_types.map{|type| type.to_s[0,1]}.join('')) end def line_groups(str, expected) p = SimpleMarkup.new mock = MockOutput.new block = p.convert(str, mock) if block != expected rows = (0...([expected.size, block.size].max)).collect{|i| [expected[i]||"nil", block[i]||"nil"] } printf "\n\n%35s %35s\n", "Expected", "Got" rows.each {|e,g| printf "%35s %35s\n", e.dump, g.dump } end assert_equal(expected, block) end def test_tabs str = "hello\n dave" assert_equal(str, basic_conv(str)) str = "hello\n\tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = ".\t\t." assert_equal(". .", basic_conv(str)) end def test_whitespace assert_equal("hello", basic_conv("hello")) assert_equal("hello", basic_conv(" hello ")) assert_equal("hello", basic_conv(" \t \t hello\t\t")) assert_equal("1\n 2\n 3", basic_conv("1\n 2\n 3")) assert_equal("1\n 2\n 3", basic_conv(" 1\n 2\n 3")) assert_equal("1\n 2\n 3\n1\n 2", basic_conv("1\n 2\n 3\n1\n 2")) assert_equal("1\n 2\n 3\n1\n 2", basic_conv(" 1\n 2\n 3\n 1\n 2")) assert_equal("1\n 2\n\n 3", basic_conv(" 1\n 2\n\n 3")) end def test_types str = "now is the time" line_types(str, 'P') str = "now is the time\nfor all good men" line_types(str, 'PP') str = "now is the time\n code\nfor all good men" line_types(str, 'PVP') str = "now is the time\n code\n more code\nfor all good men" line_types(str, 'PVVP') str = "now is\n---\nthe time" line_types(str, 'PRP') str = %{\ now is * l1 * l2 the time} line_types(str, 'PLLP') str = %{\ now is * l1 l1+ * l2 the time} line_types(str, 'PLPLP') str = %{\ now is * l1 * l1.1 * l2 the time} line_types(str, 'PLLLP') str = %{\ now is * l1 * l1.1 text code code text * l2 the time} line_types(str, 'PLLPVVBPLP') str = %{\ now is 1. l1 * l1.1 2. l2 the time} line_types(str, 'PLLLP') str = %{\ now is [cat] l1 * l1.1 [dog] l2 the time} line_types(str, 'PLLLP') str = %{\ now is [cat] l1 continuation [dog] l2 the time} line_types(str, 'PLPLP') end def test_groups str = "now is the time" line_groups(str, ["L0: Paragraph\nnow is the time"] ) str = "now is the time\nfor all good men" line_groups(str, ["L0: Paragraph\nnow is the time for all good men"] ) str = %{\ now is the time code _line_ here for all good men} line_groups(str, [ "L0: Paragraph\nnow is the time", "L0: Verbatim\n code _line_ here\n", "L0: Paragraph\nfor all good men" ] ) str = "now is the time\n code\n more code\nfor all good men" line_groups(str, [ "L0: Paragraph\nnow is the time", "L0: Verbatim\n code\n more code\n", "L0: Paragraph\nfor all good men" ] ) str = %{\ now is * l1 * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is * l1 l1+ * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1 l1+", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is * l1 * l1.1 * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is * l1 * l1.1 text code code text * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1 text", "L2: Verbatim\n code\n code\n", "L2: Paragraph\ntext", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is 1. l1 * l1.1 2. l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is [cat] l1 * l1.1 [dog] l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is [cat] l1 continuation [dog] l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1 continuation", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) end def test_verbatim_merge str = %{\ now is code the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n code1\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 code2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n\n code2\n", "L0: Paragraph\nthe time" ]) # Folds multiple blank lines str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n", "L0: Paragraph\nthe time" ]) end def test_list_split str = %{\ now is * l1 1. n1 2. n2 * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L1: ListEnd\n", "L1: ListStart\n", "L1: ListItem\nn1", "L1: ListItem\nn2", "L1: ListEnd\n", "L1: ListStart\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) end def test_headings str = "= heading one" line_groups(str, [ "L0: Heading\nheading one" ]) str = "=== heading three" line_groups(str, [ "L0: Heading\nheading three" ]) str = "text\n === heading three" line_groups(str, [ "L0: Paragraph\ntext", "L0: Verbatim\n === heading three\n" ]) str = "text\n code\n === heading three" line_groups(str, [ "L0: Paragraph\ntext", "L0: Verbatim\n code\n === heading three\n" ]) str = "text\n code\n=== heading three" line_groups(str, [ "L0: Paragraph\ntext", "L0: Verbatim\n code\n", "L0: Heading\nheading three" ]) end end PK|]Z //rdoc/markup/test/AllTests.rbnu[require 'TestParse.rb' require 'TestInline.rb' PK|]=  rdoc/markup/test/TestInline.rbnu[require "test/unit" $:.unshift "../../.." require "rdoc/markup/simple_markup/inline" class TestInline < Test::Unit::TestCase def setup @am = SM::AttributeManager.new @bold_on = @am.changed_attribute_by_name([], [:BOLD]) @bold_off = @am.changed_attribute_by_name([:BOLD], []) @tt_on = @am.changed_attribute_by_name([], [:TT]) @tt_off = @am.changed_attribute_by_name([:TT], []) @em_on = @am.changed_attribute_by_name([], [:EM]) @em_off = @am.changed_attribute_by_name([:EM], []) @bold_em_on = @am.changed_attribute_by_name([], [:BOLD] | [:EM]) @bold_em_off = @am.changed_attribute_by_name([:BOLD] | [:EM], []) @em_then_bold = @am.changed_attribute_by_name([:EM], [:EM] | [:BOLD]) @em_to_bold = @am.changed_attribute_by_name([:EM], [:BOLD]) @am.add_word_pair("{", "}", :WOMBAT) @wombat_on = @am.changed_attribute_by_name([], [:WOMBAT]) @wombat_off = @am.changed_attribute_by_name([:WOMBAT], []) end def crossref(text) [ @am.changed_attribute_by_name([], [:CROSSREF] | [:_SPECIAL_]), SM::Special.new(33, text), @am.changed_attribute_by_name([:CROSSREF] | [:_SPECIAL_], []) ] end def test_special # class names, variable names, file names, or instance variables @am.add_special(/( \b([A-Z]\w+(::\w+)*) | \#\w+[!?=]? | \b\w+([_\/\.]+\w+)+[!?=]? )/x, :CROSSREF) assert_equal(["cat"], @am.flow("cat")) assert_equal(["cat ", crossref("#fred"), " dog"].flatten, @am.flow("cat #fred dog")) assert_equal([crossref("#fred"), " dog"].flatten, @am.flow("#fred dog")) assert_equal(["cat ", crossref("#fred")].flatten, @am.flow("cat #fred")) end def test_basic assert_equal(["cat"], @am.flow("cat")) assert_equal(["cat ", @bold_on, "and", @bold_off, " dog"], @am.flow("cat *and* dog")) assert_equal(["cat ", @bold_on, "AND", @bold_off, " dog"], @am.flow("cat *AND* dog")) assert_equal(["cat ", @em_on, "And", @em_off, " dog"], @am.flow("cat _And_ dog")) assert_equal(["cat *and dog*"], @am.flow("cat *and dog*")) assert_equal(["*cat and* dog"], @am.flow("*cat and* dog")) assert_equal(["cat *and ", @bold_on, "dog", @bold_off], @am.flow("cat *and *dog*")) assert_equal(["cat ", @em_on, "and", @em_off, " dog"], @am.flow("cat _and_ dog")) assert_equal(["cat_and_dog"], @am.flow("cat_and_dog")) assert_equal(["cat ", @tt_on, "and", @tt_off, " dog"], @am.flow("cat +and+ dog")) assert_equal(["cat ", @bold_on, "a_b_c", @bold_off, " dog"], @am.flow("cat *a_b_c* dog")) assert_equal(["cat __ dog"], @am.flow("cat __ dog")) assert_equal(["cat ", @em_on, "_", @em_off, " dog"], @am.flow("cat ___ dog")) end def test_combined assert_equal(["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off], @am.flow("cat _and_ *dog*")) assert_equal(["cat ", @em_on, "a__nd", @em_off, " ", @bold_on, "dog", @bold_off], @am.flow("cat _a__nd_ *dog*")) end def test_html_like assert_equal(["cat ", @tt_on, "dog", @tt_off], @am.flow("cat dog")) assert_equal(["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], @am.flow("cat and dog")) assert_equal([@tt_on, "cat", @tt_off, " ", @em_on, "and ", @em_to_bold, "dog", @bold_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], @am.flow("cat and dog")) assert_equal(["cat ", @bold_em_on, "and", @bold_em_off, " dog"], @am.flow("cat and dog")) end def test_protect assert_equal(['cat \\ dog'], @am.flow('cat \\ dog')) assert_equal(["cat dog"], @am.flow("cat \\dog")) assert_equal(["cat ", @em_on, "and", @em_off, " dog"], @am.flow("cat and \\dog")) assert_equal(["*word* or text"], @am.flow("\\*word* or \\text")) assert_equal(["_cat_", @em_on, "dog", @em_off], @am.flow("\\_cat_dog")) end def test_adding assert_equal(["cat ", @wombat_on, "and", @wombat_off, " dog" ], @am.flow("cat {and} dog")) # assert_equal(["cat {and} dog" ], @am.flow("cat \\{and} dog")) end end PK|]8aU~~$rdoc/markup/simple_markup/to_flow.rbnu[require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/inline' require 'cgi' module SM module Flow P = Struct.new(:body) VERB = Struct.new(:body) RULE = Struct.new(:width) class LIST attr_reader :type, :contents def initialize(type) @type = type @contents = [] end def <<(stuff) @contents << stuff end end LI = Struct.new(:label, :body) H = Struct.new(:level, :text) end class ToFlow LIST_TYPE_TO_HTML = { SM::ListBase::BULLET => [ "" ], SM::ListBase::NUMBER => [ "
    ", "
" ], SM::ListBase::UPPERALPHA => [ "
    ", "
" ], SM::ListBase::LOWERALPHA => [ "
    ", "
" ], SM::ListBase::LABELED => [ "
", "
" ], SM::ListBase::NOTE => [ "", "
" ], } InlineTag = Struct.new(:bit, :on, :off) def initialize init_tags end ## # Set up the standard mapping of attributes to HTML tags # def init_tags @attr_tags = [ InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:TT), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:EM), "", ""), ] end ## # Add a new set of HTML tags for an attribute. We allow # separate start and end tags for flexibility # def add_tag(name, start, stop) @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop) end ## # Given an HTML tag, decorate it with class information # and the like if required. This is a no-op in the base # class, but is overridden in HTML output classes that # implement style sheets def annotate(tag) tag end ## # Here's the client side of the visitor pattern def start_accepting @res = [] @list_stack = [] end def end_accepting @res end def accept_paragraph(am, fragment) @res << Flow::P.new((convert_flow(am.flow(fragment.txt)))) end def accept_verbatim(am, fragment) @res << Flow::VERB.new((convert_flow(am.flow(fragment.txt)))) end def accept_rule(am, fragment) size = fragment.param size = 10 if size > 10 @res << Flow::RULE.new(size) end def accept_list_start(am, fragment) @list_stack.push(@res) list = Flow::LIST.new(fragment.type) @res << list @res = list end def accept_list_end(am, fragment) @res = @list_stack.pop end def accept_list_item(am, fragment) @res << Flow::LI.new(fragment.param, convert_flow(am.flow(fragment.txt))) end def accept_blank_line(am, fragment) # @res << annotate("

") << "\n" end def accept_heading(am, fragment) @res << Flow::H.new(fragment.head_level, convert_flow(am.flow(fragment.txt))) end ####################################################################### private ####################################################################### def on_tags(res, item) attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.on) end end end def off_tags(res, item) attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.off) end end end def convert_flow(flow) res = "" flow.each do |item| case item when String res << convert_string(item) when AttrChanger off_tags(res, item) on_tags(res, item) when Special res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res end # some of these patterns are taken from SmartyPants... def convert_string(item) CGI.escapeHTML(item) end def convert_special(special) handled = false Attribute.each_name_of(special.type) do |name| method_name = "handle_special_#{name}" if self.respond_to? method_name special.text = send(method_name, special) handled = true end end raise "Unhandled special: #{special}" unless handled special.text end end end PK|]sp--$rdoc/markup/simple_markup/to_html.rbnu[require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/inline' require 'cgi' module SM class ToHtml LIST_TYPE_TO_HTML = { ListBase::BULLET => [ "

" ], ListBase::NUMBER => [ "
    ", "
" ], ListBase::UPPERALPHA => [ "
    ", "
" ], ListBase::LOWERALPHA => [ "
    ", "
" ], ListBase::LABELED => [ "
", "
" ], ListBase::NOTE => [ "", "
" ], } InlineTag = Struct.new(:bit, :on, :off) def initialize init_tags end ## # Set up the standard mapping of attributes to HTML tags # def init_tags @attr_tags = [ InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:TT), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:EM), "", ""), ] end ## # Add a new set of HTML tags for an attribute. We allow # separate start and end tags for flexibility # def add_tag(name, start, stop) @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop) end ## # Given an HTML tag, decorate it with class information # and the like if required. This is a no-op in the base # class, but is overridden in HTML output classes that # implement style sheets def annotate(tag) tag end ## # Here's the client side of the visitor pattern def start_accepting @res = "" @in_list_entry = [] end def end_accepting @res end def accept_paragraph(am, fragment) @res << annotate("

") + "\n" @res << wrap(convert_flow(am.flow(fragment.txt))) @res << annotate("

") + "\n" end def accept_verbatim(am, fragment) @res << annotate("
") + "\n"
      @res << CGI.escapeHTML(fragment.txt)
      @res << annotate("
") << "\n" end def accept_rule(am, fragment) size = fragment.param size = 10 if size > 10 @res << "
" end def accept_list_start(am, fragment) @res << html_list_name(fragment.type, true) <<"\n" @in_list_entry.push false end def accept_list_end(am, fragment) if tag = @in_list_entry.pop @res << annotate(tag) << "\n" end @res << html_list_name(fragment.type, false) <<"\n" end def accept_list_item(am, fragment) if tag = @in_list_entry.last @res << annotate(tag) << "\n" end @res << list_item_start(am, fragment) @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n" @in_list_entry[-1] = list_end_for(fragment.type) end def accept_blank_line(am, fragment) # @res << annotate("

") << "\n" end def accept_heading(am, fragment) @res << convert_heading(fragment.head_level, am.flow(fragment.txt)) end # This is a higher speed (if messier) version of wrap def wrap(txt, line_len = 76) res = "" sp = 0 ep = txt.length while sp < ep # scan back for a space p = sp + line_len - 1 if p >= ep p = ep else while p > sp and txt[p] != ?\s p -= 1 end if p <= sp p = sp + line_len while p < ep and txt[p] != ?\s p += 1 end end end res << txt[sp...p] << "\n" sp = p sp += 1 while sp < ep and txt[sp] == ?\s end res end ####################################################################### private ####################################################################### def on_tags(res, item) attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.on) end end end def off_tags(res, item) attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.off) end end end def convert_flow(flow) res = "" flow.each do |item| case item when String res << convert_string(item) when AttrChanger off_tags(res, item) on_tags(res, item) when Special res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res end # some of these patterns are taken from SmartyPants... def convert_string(item) CGI.escapeHTML(item). # convert -- to em-dash, (-- to en-dash) gsub(/---?/, '—'). #gsub(/--/, '–'). # convert ... to elipsis (and make sure .... becomes .) gsub(/\.\.\.\./, '.…').gsub(/\.\.\./, '…'). # convert single closing quote gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1’" }. gsub(%r{\'(?=\W|s\b)}) { "’" }. # convert single opening quote gsub(/'/, '‘'). # convert double closing quote gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1”" }. # convert double opening quote gsub(/'/, '“'). # convert copyright gsub(/\(c\)/, '©'). # convert and registered trademark gsub(/\(r\)/, '®') end def convert_special(special) handled = false Attribute.each_name_of(special.type) do |name| method_name = "handle_special_#{name}" if self.respond_to? method_name special.text = send(method_name, special) handled = true end end raise "Unhandled special: #{special}" unless handled special.text end def convert_heading(level, flow) res = annotate("") + convert_flow(flow) + annotate("\n") end def html_list_name(list_type, is_open_tag) tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}") annotate(tags[ is_open_tag ? 0 : 1]) end def list_item_start(am, fragment) case fragment.type when ListBase::BULLET, ListBase::NUMBER annotate("

  • ") when ListBase::UPPERALPHA annotate("
  • ") when ListBase::LOWERALPHA annotate("
  • ") when ListBase::LABELED annotate("
    ") + convert_flow(am.flow(fragment.param)) + annotate("
    ") + annotate("
    ") when ListBase::NOTE annotate("") + annotate("") + convert_flow(am.flow(fragment.param)) + annotate("") + annotate("") else raise "Invalid list type" end end def list_end_for(fragment_type) case fragment_type when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA "
  • " when ListBase::LABELED "" when ListBase::NOTE "" else raise "Invalid list type" end end end end PK|]Vڹ'rdoc/markup/simple_markup/preprocess.rbnu[module SM ## # Handle common directives that can occur in a block of text: # # : include : filename # class PreProcess def initialize(input_file_name, include_path) @input_file_name = input_file_name @include_path = include_path end # Look for common options in a chunk of text. Options that # we don't handle are passed back to our caller # as |directive, param| def handle(text) text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do prefix = $1 directive = $2.downcase param = $3 case directive when "include" filename = param.split[0] include_file(filename, prefix) else yield(directive, param) end end end ####### private ####### # Include a file, indenting it correctly def include_file(name, indent) if (full_name = find_include_file(name)) content = File.open(full_name) {|f| f.read} # strip leading '#'s, but only if all lines start with them if content =~ /^[^#]/ content.gsub(/^/, indent) else content.gsub(/^#?/, indent) end else $stderr.puts "Couldn't find file to include: '#{name}'" '' end end # Look for the given file in the directory containing the current # file, and then in each of the directories specified in the # RDOC_INCLUDE path def find_include_file(name) to_search = [ File.dirname(@input_file_name) ].concat @include_path to_search.each do |dir| full_name = File.join(dir, name) stat = File.stat(full_name) rescue next return full_name if stat.readable? end nil end end end PK|]""#rdoc/markup/simple_markup/inline.rbnu[module SM # We manage a set of attributes. Each attribute has a symbol name # and a bit value class Attribute SPECIAL = 1 @@name_to_bitmap = { :_SPECIAL_ => SPECIAL } @@next_bitmap = 2 def Attribute.bitmap_for(name) bitmap = @@name_to_bitmap[name] if !bitmap bitmap = @@next_bitmap @@next_bitmap <<= 1 @@name_to_bitmap[name] = bitmap end bitmap end def Attribute.as_string(bitmap) return "none" if bitmap.zero? res = [] @@name_to_bitmap.each do |name, bit| res << name if (bitmap & bit) != 0 end res.join(",") end def Attribute.each_name_of(bitmap) @@name_to_bitmap.each do |name, bit| next if bit == SPECIAL yield name.to_s if (bitmap & bit) != 0 end end end # An AttrChanger records a change in attributes. It contains # a bitmap of the attributes to turn on, and a bitmap of those to # turn off AttrChanger = Struct.new(:turn_on, :turn_off) class AttrChanger def to_s "Attr: +#{Attribute.as_string(@turn_on)}/-#{Attribute.as_string(@turn_on)}" end end # An array of attributes which parallels the characters in a string class AttrSpan def initialize(length) @attrs = Array.new(length, 0) end def set_attrs(start, length, bits) for i in start ... (start+length) @attrs[i] |= bits end end def [](n) @attrs[n] end end ## # Hold details of a special sequence class Special attr_reader :type attr_accessor :text def initialize(type, text) @type, @text = type, text end def ==(o) self.text == o.text && self.type == o.type end def to_s "Special: type=#{type}, text=#{text.dump}" end end class AttributeManager NULL = "\000".freeze ## # We work by substituting non-printing characters in to the # text. For now I'm assuming that I can substitute # a character in the range 0..8 for a 7 bit character # without damaging the encoded string, but this might # be optimistic # A_PROTECT = 004 PROTECT_ATTR = A_PROTECT.chr # This maps delimiters that occur around words (such as # *bold* or +tt+) where the start and end delimiters # and the same. This lets us optimize the regexp MATCHING_WORD_PAIRS = {} # And this is used when the delimiters aren't the same. In this # case the hash maps a pattern to the attribute character WORD_PAIR_MAP = {} # This maps HTML tags to the corresponding attribute char HTML_TAGS = {} # And this maps _special_ sequences to a name. A special sequence # is something like a WikiWord SPECIAL = {} # Return an attribute object with the given turn_on # and turn_off bits set def attribute(turn_on, turn_off) AttrChanger.new(turn_on, turn_off) end def change_attribute(current, new) diff = current ^ new attribute(new & diff, current & diff) end def changed_attribute_by_name(current_set, new_set) current = new = 0 current_set.each {|name| current |= Attribute.bitmap_for(name) } new_set.each {|name| new |= Attribute.bitmap_for(name) } change_attribute(current, new) end def copy_string(start_pos, end_pos) res = @str[start_pos...end_pos] res.gsub!(/\000/, '') res end # Map attributes like textto the sequence \001\002\001\003, # where is a per-attribute specific character def convert_attrs(str, attrs) # first do matching ones tags = MATCHING_WORD_PAIRS.keys.join("") re = "(^|\\W)([#{tags}])([A-Za-z_]+?)\\2(\\W|\$)" # re = "(^|\\W)([#{tags}])(\\S+?)\\2(\\W|\$)" 1 while str.gsub!(Regexp.new(re)) { attr = MATCHING_WORD_PAIRS[$2]; attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr) $1 + NULL*$2.length + $3 + NULL*$2.length + $4 } # then non-matching unless WORD_PAIR_MAP.empty? WORD_PAIR_MAP.each do |regexp, attr| str.gsub!(regexp) { attrs.set_attrs($`.length + $1.length, $2.length, attr) NULL*$1.length + $2 + NULL*$3.length } end end end def convert_html(str, attrs) tags = HTML_TAGS.keys.join("|") re = "<(#{tags})>(.*?)" 1 while str.gsub!(Regexp.new(re, Regexp::IGNORECASE)) { attr = HTML_TAGS[$1.downcase] html_length = $1.length + 2 seq = NULL * html_length attrs.set_attrs($`.length + html_length, $2.length, attr) seq + $2 + seq + NULL } end def convert_specials(str, attrs) unless SPECIAL.empty? SPECIAL.each do |regexp, attr| str.scan(regexp) do attrs.set_attrs($`.length, $&.length, attr | Attribute::SPECIAL) end end end end # A \ in front of a character that would normally be # processed turns off processing. We do this by turning # \< into <#{PROTECT} PROTECTABLE = [ "<" << "\\" ] #" def mask_protected_sequences protect_pattern = Regexp.new("\\\\([#{Regexp.escape(PROTECTABLE.join(''))}])") @str.gsub!(protect_pattern, "\\1#{PROTECT_ATTR}") end def unmask_protected_sequences @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000") end def initialize add_word_pair("*", "*", :BOLD) add_word_pair("_", "_", :EM) add_word_pair("+", "+", :TT) add_html("em", :EM) add_html("i", :EM) add_html("b", :BOLD) add_html("tt", :TT) add_html("code", :TT) add_special(//, :COMMENT) end def add_word_pair(start, stop, name) raise "Word flags may not start '<'" if start[0] == ?< bitmap = Attribute.bitmap_for(name) if start == stop MATCHING_WORD_PAIRS[start] = bitmap else pattern = Regexp.new("(" + Regexp.escape(start) + ")" + # "([A-Za-z]+)" + "(\\S+)" + "(" + Regexp.escape(stop) +")") WORD_PAIR_MAP[pattern] = bitmap end PROTECTABLE << start[0,1] PROTECTABLE.uniq! end def add_html(tag, name) HTML_TAGS[tag.downcase] = Attribute.bitmap_for(name) end def add_special(pattern, name) SPECIAL[pattern] = Attribute.bitmap_for(name) end def flow(str) @str = str puts("Before flow, str='#{@str.dump}'") if $DEBUG mask_protected_sequences @attrs = AttrSpan.new(@str.length) puts("After protecting, str='#{@str.dump}'") if $DEBUG convert_attrs(@str, @attrs) convert_html(@str, @attrs) convert_specials(str, @attrs) unmask_protected_sequences puts("After flow, str='#{@str.dump}'") if $DEBUG return split_into_flow end def display_attributes puts puts @str.tr(NULL, "!") bit = 1 16.times do |bno| line = "" @str.length.times do |i| if (@attrs[i] & bit) == 0 line << " " else if bno.zero? line << "S" else line << ("%d" % (bno+1)) end end end puts(line) unless line =~ /^ *$/ bit <<= 1 end end def split_into_flow display_attributes if $DEBUG res = [] current_attr = 0 str = "" str_len = @str.length # skip leading invisible text i = 0 i += 1 while i < str_len and @str[i].zero? start_pos = i # then scan the string, chunking it on attribute changes while i < str_len new_attr = @attrs[i] if new_attr != current_attr if i > start_pos res << copy_string(start_pos, i) start_pos = i end res << change_attribute(current_attr, new_attr) current_attr = new_attr if (current_attr & Attribute::SPECIAL) != 0 i += 1 while i < str_len and (@attrs[i] & Attribute::SPECIAL) != 0 res << Special.new(current_attr, copy_string(start_pos, i)) start_pos = i next end end # move on, skipping any invisible characters begin i += 1 end while i < str_len and @str[i].zero? end # tidy up trailing text if start_pos < str_len res << copy_string(start_pos, str_len) end # and reset to all attributes off res << change_attribute(current_attr, 0) if current_attr != 0 return res end end end PK|])&rdoc/markup/simple_markup/fragments.rbnu[require 'rdoc/markup/simple_markup/lines.rb' #require 'rdoc/markup/simple_markup/to_flow.rb' module SM ## # A Fragment is a chunk of text, subclassed as a paragraph, a list # entry, or verbatim text class Fragment attr_reader :level, :param, :txt attr_accessor :type def initialize(level, param, type, txt) @level = level @param = param @type = type @txt = "" add_text(txt) if txt end def add_text(txt) @txt << " " if @txt.length > 0 @txt << txt.tr_s("\n ", " ").strip end def to_s "L#@level: #{self.class.name.split('::')[-1]}\n#@txt" end ###### # This is a simple factory system that lets us associate fragement # types (a string) with a subclass of fragment TYPE_MAP = {} def Fragment.type_name(name) TYPE_MAP[name] = self end def Fragment.for(line) klass = TYPE_MAP[line.type] || raise("Unknown line type: '#{line.type.inspect}:' '#{line.text}'") return klass.new(line.level, line.param, line.flag, line.text) end end ## # A paragraph is a fragment which gets wrapped to fit. We remove all # newlines when we're created, and have them put back on output class Paragraph < Fragment type_name Line::PARAGRAPH end class BlankLine < Paragraph type_name Line::BLANK end class Heading < Paragraph type_name Line::HEADING def head_level @param.to_i end end ## # A List is a fragment with some kind of label # class ListBase < Paragraph # List types BULLET = :BULLET NUMBER = :NUMBER UPPERALPHA = :UPPERALPHA LOWERALPHA = :LOWERALPHA LABELED = :LABELED NOTE = :NOTE end class ListItem < ListBase type_name Line::LIST # def label # am = AttributeManager.new(@param) # am.flow # end end class ListStart < ListBase def initialize(level, param, type) super(level, param, type, nil) end end class ListEnd < ListBase def initialize(level, type) super(level, "", type, nil) end end ## # Verbatim code contains lines that don't get wrapped. class Verbatim < Fragment type_name Line::VERBATIM def add_text(txt) @txt << txt.chomp << "\n" end end ## # A horizontal rule class Rule < Fragment type_name Line::RULE end # Collect groups of lines together. Each group # will end up containing a flow of text class LineCollection def initialize @fragments = [] end def add(fragment) @fragments << fragment end def each(&b) @fragments.each(&b) end # For testing def to_a @fragments.map {|fragment| fragment.to_s} end # Factory for different fragment types def fragment_for(*args) Fragment.for(*args) end # tidy up at the end def normalize change_verbatim_blank_lines add_list_start_and_ends add_list_breaks tidy_blank_lines end def to_s @fragments.join("\n----\n") end def accept(am, visitor) visitor.start_accepting @fragments.each do |fragment| case fragment when Verbatim visitor.accept_verbatim(am, fragment) when Rule visitor.accept_rule(am, fragment) when ListStart visitor.accept_list_start(am, fragment) when ListEnd visitor.accept_list_end(am, fragment) when ListItem visitor.accept_list_item(am, fragment) when BlankLine visitor.accept_blank_line(am, fragment) when Heading visitor.accept_heading(am, fragment) when Paragraph visitor.accept_paragraph(am, fragment) end end visitor.end_accepting end ####### private ####### # If you have: # # normal paragraph text. # # this is code # # and more code # # You'll end up with the fragments Paragraph, BlankLine, # Verbatim, BlankLine, Verbatim, BlankLine, etc # # The BlankLine in the middle of the verbatim chunk needs to # be changed to a real verbatim newline, and the two # verbatim blocks merged # # def change_verbatim_blank_lines frag_block = nil blank_count = 0 @fragments.each_with_index do |frag, i| if frag_block.nil? frag_block = frag if Verbatim === frag else case frag when Verbatim blank_count.times { frag_block.add_text("\n") } blank_count = 0 frag_block.add_text(frag.txt) @fragments[i] = nil # remove out current fragment when BlankLine if frag_block blank_count += 1 @fragments[i] = nil end else frag_block = nil blank_count = 0 end end end @fragments.compact! end # List nesting is implicit given the level of # Make it explicit, just to make life a tad # easier for the output processors def add_list_start_and_ends level = 0 res = [] type_stack = [] @fragments.each do |fragment| # $stderr.puts "#{level} : #{fragment.class.name} : #{fragment.level}" new_level = fragment.level while (level < new_level) level += 1 type = fragment.type res << ListStart.new(level, fragment.param, type) if type type_stack.push type # $stderr.puts "Start: #{level}" end while level > new_level type = type_stack.pop res << ListEnd.new(level, type) if type level -= 1 # $stderr.puts "End: #{level}, #{type}" end res << fragment level = fragment.level end level.downto(1) do |i| type = type_stack.pop res << ListEnd.new(i, type) if type end @fragments = res end # now insert start/ends between list entries at the # same level that have different element types def add_list_breaks res = @fragments @fragments = [] list_stack = [] res.each do |fragment| case fragment when ListStart list_stack.push fragment when ListEnd start = list_stack.pop fragment.type = start.type when ListItem l = list_stack.last if fragment.type != l.type @fragments << ListEnd.new(l.level, l.type) start = ListStart.new(l.level, fragment.param, fragment.type) @fragments << start list_stack.pop list_stack.push start end else ; end @fragments << fragment end end # Finally tidy up the blank lines: # * change Blank/ListEnd into ListEnd/Blank # * remove blank lines at the front def tidy_blank_lines (@fragments.size - 1).times do |i| if @fragments[i].kind_of?(BlankLine) and @fragments[i+1].kind_of?(ListEnd) @fragments[i], @fragments[i+1] = @fragments[i+1], @fragments[i] end end # remove leading blanks @fragments.each_with_index do |f, i| break unless f.kind_of? BlankLine @fragments[i] = nil end @fragments.compact! end end end PK|]7^!!%rdoc/markup/simple_markup/to_latex.rbnu[require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/inline' require 'cgi' module SM # Convert SimpleMarkup to basic LaTeX report format class ToLaTeX BS = "\020" # \ OB = "\021" # { CB = "\022" # } DL = "\023" # Dollar BACKSLASH = "#{BS}symbol#{OB}92#{CB}" HAT = "#{BS}symbol#{OB}94#{CB}" BACKQUOTE = "#{BS}symbol#{OB}0#{CB}" TILDE = "#{DL}#{BS}sim#{DL}" LESSTHAN = "#{DL}<#{DL}" GREATERTHAN = "#{DL}>#{DL}" def self.l(str) str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL) end def l(arg) SM::ToLaTeX.l(arg) end LIST_TYPE_TO_LATEX = { ListBase::BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ], ListBase::NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ], ListBase::UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ], ListBase::LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ], ListBase::LABELED => [ l("\\begin{description}"), l("\\end{description}") ], ListBase::NOTE => [ l("\\begin{tabularx}{\\linewidth}{@{} l X @{}}"), l("\\end{tabularx}") ], } InlineTag = Struct.new(:bit, :on, :off) def initialize init_tags @list_depth = 0 @prev_list_types = [] end ## # Set up the standard mapping of attributes to LaTeX # def init_tags @attr_tags = [ InlineTag.new(SM::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")), InlineTag.new(SM::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")), InlineTag.new(SM::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")), ] end ## # Escape a LaTeX string def escape(str) # $stderr.print "FE: ", str s = str. # sub(/\s+$/, ''). gsub(/([_\${}&%#])/, "#{BS}\\1"). gsub(/\\/, BACKSLASH). gsub(/\^/, HAT). gsub(/~/, TILDE). gsub(//, GREATERTHAN). gsub(/,,/, ",{},"). gsub(/\`/, BACKQUOTE) # $stderr.print "-> ", s, "\n" s end ## # Add a new set of LaTeX tags for an attribute. We allow # separate start and end tags for flexibility # def add_tag(name, start, stop) @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop) end ## # Here's the client side of the visitor pattern def start_accepting @res = "" @in_list_entry = [] end def end_accepting @res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$') end def accept_paragraph(am, fragment) @res << wrap(convert_flow(am.flow(fragment.txt))) @res << "\n" end def accept_verbatim(am, fragment) @res << "\n\\begin{code}\n" @res << fragment.txt.sub(/[\n\s]+\Z/, '') @res << "\n\\end{code}\n\n" end def accept_rule(am, fragment) size = fragment.param size = 10 if size > 10 @res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n" end def accept_list_start(am, fragment) @res << list_name(fragment.type, true) <<"\n" @in_list_entry.push false end def accept_list_end(am, fragment) if tag = @in_list_entry.pop @res << tag << "\n" end @res << list_name(fragment.type, false) <<"\n" end def accept_list_item(am, fragment) if tag = @in_list_entry.last @res << tag << "\n" end @res << list_item_start(am, fragment) @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n" @in_list_entry[-1] = list_end_for(fragment.type) end def accept_blank_line(am, fragment) # @res << "\n" end def accept_heading(am, fragment) @res << convert_heading(fragment.head_level, am.flow(fragment.txt)) end # This is a higher speed (if messier) version of wrap def wrap(txt, line_len = 76) res = "" sp = 0 ep = txt.length while sp < ep # scan back for a space p = sp + line_len - 1 if p >= ep p = ep else while p > sp and txt[p] != ?\s p -= 1 end if p <= sp p = sp + line_len while p < ep and txt[p] != ?\s p += 1 end end end res << txt[sp...p] << "\n" sp = p sp += 1 while sp < ep and txt[sp] == ?\s end res end ####################################################################### private ####################################################################### def on_tags(res, item) attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 res << tag.on end end end def off_tags(res, item) attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 res << tag.off end end end def convert_flow(flow) res = "" flow.each do |item| case item when String # $stderr.puts "Converting '#{item}'" res << convert_string(item) when AttrChanger off_tags(res, item) on_tags(res, item) when Special res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res end # some of these patterns are taken from SmartyPants... def convert_string(item) escape(item). # convert ... to elipsis (and make sure .... becomes .) gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}'). # convert single closing quote gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1'" }. gsub(%r{\'(?=\W|s\b)}) { "'" }. # convert single opening quote gsub(/'/, '`'). # convert double closing quote gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}) { "#$1''" }. # convert double opening quote gsub(/"/, "``"). # convert copyright gsub(/\(c\)/, '\copyright{}') end def convert_special(special) handled = false Attribute.each_name_of(special.type) do |name| method_name = "handle_special_#{name}" if self.respond_to? method_name special.text = send(method_name, special) handled = true end end raise "Unhandled special: #{special}" unless handled special.text end def convert_heading(level, flow) res = case level when 1 then "\\chapter{" when 2 then "\\section{" when 3 then "\\subsection{" when 4 then "\\subsubsection{" else "\\paragraph{" end + convert_flow(flow) + "}\n" end def list_name(list_type, is_open_tag) tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}") if tags[2] # enumerate if is_open_tag @list_depth += 1 if @prev_list_types[@list_depth] != tags[2] case @list_depth when 1 roman = "i" when 2 roman = "ii" when 3 roman = "iii" when 4 roman = "iv" else raise("Too deep list: level #{@list_depth}") end @prev_list_types[@list_depth] = tags[2] return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0] end else @list_depth -= 1 end end tags[ is_open_tag ? 0 : 1] end def list_item_start(am, fragment) case fragment.type when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA "\\item " when ListBase::LABELED "\\item[" + convert_flow(am.flow(fragment.param)) + "] " when ListBase::NOTE convert_flow(am.flow(fragment.param)) + " & " else raise "Invalid list type" end end def list_end_for(fragment_type) case fragment_type when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA, ListBase::LABELED "" when ListBase::NOTE "\\\\\n" else raise "Invalid list type" end end end end PK|]k "rdoc/markup/simple_markup/lines.rbnu[########################################################################## # # We store the lines we're working on as objects of class Line. # These contain the text of the line, along with a flag indicating the # line type, and an indentation level module SM class Line INFINITY = 9999 BLANK = :BLANK HEADING = :HEADING LIST = :LIST RULE = :RULE PARAGRAPH = :PARAGRAPH VERBATIM = :VERBATIM # line type attr_accessor :type # The indentation nesting level attr_accessor :level # The contents attr_accessor :text # A prefix or parameter. For LIST lines, this is # the text that introduced the list item (the label) attr_accessor :param # A flag. For list lines, this is the type of the list attr_accessor :flag # the number of leading spaces attr_accessor :leading_spaces # true if this line has been deleted from the list of lines attr_accessor :deleted def initialize(text) @text = text.dup @deleted = false # expand tabs 1 while @text.gsub!(/\t+/) { ' ' * (8*$&.length - $`.length % 8)} && $~ #` # Strip trailing whitespace @text.sub!(/\s+$/, '') # and look for leading whitespace if @text.length > 0 @text =~ /^(\s*)/ @leading_spaces = $1.length else @leading_spaces = INFINITY end end # Return true if this line is blank def isBlank? @text.length.zero? end # stamp a line with a type, a level, a prefix, and a flag def stamp(type, level, param="", flag=nil) @type, @level, @param, @flag = type, level, param, flag end ## # Strip off the leading margin # def strip_leading(size) if @text.size > size @text[0,size] = "" else @text = "" end end def to_s "#@type#@level: #@text" end end ############################################################################### # # A container for all the lines # class Lines include Enumerable attr_reader :lines # for debugging def initialize(lines) @lines = lines rewind end def empty? @lines.size.zero? end def each @lines.each do |line| yield line unless line.deleted end end # def [](index) # @lines[index] # end def rewind @nextline = 0 end def next begin res = @lines[@nextline] @nextline += 1 if @nextline < @lines.size end while res and res.deleted and @nextline < @lines.size res end def unget @nextline -= 1 end def delete(a_line) a_line.deleted = true end def normalize margin = @lines.collect{|l| l.leading_spaces}.min margin = 0 if margin == Line::INFINITY @lines.each {|line| line.strip_leading(margin) } if margin > 0 end def as_text @lines.map {|l| l.text}.join("\n") end def line_types @lines.map {|l| l.type } end end end PK|]v??rdoc/markup/sample/sample.rbnu[# This program illustrates the basic use of the SimpleMarkup # class. It extracts the first comment block from the # simple_markup.rb file and converts it into HTML on # standard output. Run it using # # % ruby sample.rb # # You should be in the sample/ directory when you do this, # as it hardwires the path to the files it needs to require. # This isn't necessary in the code you write once you've # installed the package. # # For a better way of formatting code comment blocks (and more) # see the rdoc package. # $:.unshift "../../.." require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_html' # Extract the comment block from the source file input_string = "" File.foreach("../simple_markup.rb") do |line| break unless line.gsub!(/^\# ?/, '') input_string << line end # Create a markup object markup = SM::SimpleMarkup.new # Attach it to an HTML formatter h = SM::ToHtml.new # And convert out comment block to html. Wrap it a body # tag pair to let browsers view it puts "" puts markup.convert(input_string, h) puts "" PK|]^ rdoc/markup/sample/rdoc2latex.rbnu[#!/usr/local/bin/ruby # Illustration of a script to convert an RDoc-style file to a LaTeX # document require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_latex' p = SM::SimpleMarkup.new h = SM::ToLaTeX.new #puts "\\documentclass{report}" #puts "\\usepackage{tabularx}" #puts "\\usepackage{parskip}" #puts "\\begin{document}" puts p.convert(ARGF.read, h) #puts "\\end{document}" PK|]8TR8R8rdoc/markup/simple_markup.rbnu[# = Introduction # # SimpleMarkup parses plain text documents and attempts to decompose # them into their constituent parts. Some of these parts are high-level: # paragraphs, chunks of verbatim text, list entries and the like. Other # parts happen at the character level: a piece of bold text, a word in # code font. This markup is similar in spirit to that used on WikiWiki # webs, where folks create web pages using a simple set of formatting # rules. # # SimpleMarkup itself does no output formatting: this is left to a # different set of classes. # # SimpleMarkup is extendable at runtime: you can add new markup # elements to be recognised in the documents that SimpleMarkup parses. # # SimpleMarkup is intended to be the basis for a family of tools which # share the common requirement that simple, plain-text should be # rendered in a variety of different output formats and media. It is # envisaged that SimpleMarkup could be the basis for formating RDoc # style comment blocks, Wiki entries, and online FAQs. # # = Basic Formatting # # * SimpleMarkup looks for a document's natural left margin. This is # used as the initial margin for the document. # # * Consecutive lines starting at this margin are considered to be a # paragraph. # # * If a paragraph starts with a "*", "-", or with ".", then it is # taken to be the start of a list. The margin in increased to be the # first non-space following the list start flag. Subsequent lines # should be indented to this new margin until the list ends. For # example: # # * this is a list with three paragraphs in # the first item. This is the first paragraph. # # And this is the second paragraph. # # 1. This is an indented, numbered list. # 2. This is the second item in that list # # This is the third conventional paragraph in the # first list item. # # * This is the second item in the original list # # * You can also construct labeled lists, sometimes called description # or definition lists. Do this by putting the label in square brackets # and indenting the list body: # # [cat] a small furry mammal # that seems to sleep a lot # # [ant] a little insect that is known # to enjoy picnics # # A minor variation on labeled lists uses two colons to separate the # label from the list body: # # cat:: a small furry mammal # that seems to sleep a lot # # ant:: a little insect that is known # to enjoy picnics # # This latter style guarantees that the list bodies' left margins are # aligned: think of them as a two column table. # # * Any line that starts to the right of the current margin is treated # as verbatim text. This is useful for code listings. The example of a # list above is also verbatim text. # # * A line starting with an equals sign (=) is treated as a # heading. Level one headings have one equals sign, level two headings # have two,and so on. # # * A line starting with three or more hyphens (at the current indent) # generates a horizontal rule. THe more hyphens, the thicker the rule # (within reason, and if supported by the output device) # # * You can use markup within text (except verbatim) to change the # appearance of parts of that text. Out of the box, SimpleMarkup # supports word-based and general markup. # # Word-based markup uses flag characters around individual words: # # [\*word*] displays word in a *bold* font # [\_word_] displays word in an _emphasized_ font # [\+word+] displays word in a +code+ font # # General markup affects text between a start delimiter and and end # delimiter. Not surprisingly, these delimiters look like HTML markup. # # [\text...] displays word in a *bold* font # [\text...] displays word in an _emphasized_ font # [\text...] displays word in an _emphasized_ font # [\text...] displays word in a +code+ font # # Unlike conventional Wiki markup, general markup can cross line # boundaries. You can turn off the interpretation of markup by # preceding the first character with a backslash, so \\\bold # text and \\\*bold* produce \bold text and \*bold # respectively. # # = Using SimpleMarkup # # For information on using SimpleMarkup programatically, # see SM::SimpleMarkup. # # Author:: Dave Thomas, dave@pragmaticprogrammer.com # Version:: 0.0 # License:: Ruby license require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/lines.rb' module SM #:nodoc: # == Synopsis # # This code converts input_string, which is in the format # described in markup/simple_markup.rb, to HTML. The conversion # takes place in the +convert+ method, so you can use the same # SimpleMarkup object to convert multiple input strings. # # require 'rdoc/markup/simple_markup' # require 'rdoc/markup/simple_markup/to_html' # # p = SM::SimpleMarkup.new # h = SM::ToHtml.new # # puts p.convert(input_string, h) # # You can extend the SimpleMarkup parser to recognise new markup # sequences, and to add special processing for text that matches a # regular epxression. Here we make WikiWords significant to the parser, # and also make the sequences {word} and \text... signify # strike-through text. When then subclass the HTML output class to deal # with these: # # require 'rdoc/markup/simple_markup' # require 'rdoc/markup/simple_markup/to_html' # # class WikiHtml < SM::ToHtml # def handle_special_WIKIWORD(special) # "" + special.text + "" # end # end # # p = SM::SimpleMarkup.new # p.add_word_pair("{", "}", :STRIKE) # p.add_html("no", :STRIKE) # # p.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # h = WikiHtml.new # h.add_tag(:STRIKE, "", "") # # puts "" + p.convert(ARGF.read, h) + "" # # == Output Formatters # # _missing_ # # class SimpleMarkup SPACE = ?\s # List entries look like: # * text # 1. text # [label] text # label:: text # # Flag it as a list entry, and # work out the indent for subsequent lines SIMPLE_LIST_RE = /^( ( \* (?# bullet) |- (?# bullet) |\d+\. (?# numbered ) |[A-Za-z]\. (?# alphabetically numbered ) ) \s+ )\S/x LABEL_LIST_RE = /^( ( \[.*?\] (?# labeled ) |\S.*:: (?# note ) )(?:\s+|$) )/x ## # take a block of text and use various heuristics to determine # it's structure (paragraphs, lists, and so on). Invoke an # event handler as we identify significant chunks. # def initialize @am = AttributeManager.new @output = nil end ## # Add to the sequences used to add formatting to an individual word # (such as *bold*). Matching entries will generate attibutes # that the output formatters can recognize by their +name+ def add_word_pair(start, stop, name) @am.add_word_pair(start, stop, name) end ## # Add to the sequences recognized as general markup # def add_html(tag, name) @am.add_html(tag, name) end ## # Add to other inline sequences. For example, we could add # WikiWords using something like: # # parser.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # Each wiki word will be presented to the output formatter # via the accept_special method # def add_special(pattern, name) @am.add_special(pattern, name) end # We take a string, split it into lines, work out the type of # each line, and from there deduce groups of lines (for example # all lines in a paragraph). We then invoke the output formatter # using a Visitor to display the result def convert(str, op) @lines = Lines.new(str.split(/\r?\n/).collect { |aLine| Line.new(aLine) }) return "" if @lines.empty? @lines.normalize assign_types_to_lines group = group_lines # call the output formatter to handle the result # group.to_a.each {|i| p i} group.accept(@am, op) end ####### private ####### ## # Look through the text at line indentation. We flag each line as being # Blank, a paragraph, a list element, or verbatim text # def assign_types_to_lines(margin = 0, level = 0) while line = @lines.next if line.isBlank? line.stamp(Line::BLANK, level) next end # if a line contains non-blanks before the margin, then it must belong # to an outer level text = line.text for i in 0...margin if text[i] != SPACE @lines.unget return end end active_line = text[margin..-1] # Rules (horizontal lines) look like # # --- (three or more hyphens) # # The more hyphens, the thicker the rule # if /^(---+)\s*$/ =~ active_line line.stamp(Line::RULE, level, $1.length-2) next end # Then look for list entries. First the ones that have to have # text following them (* xxx, - xxx, and dd. xxx) if SIMPLE_LIST_RE =~ active_line offset = margin + $1.length prefix = $2 prefix_length = prefix.length flag = case prefix when "*","-" then ListBase::BULLET when /^\d/ then ListBase::NUMBER when /^[A-Z]/ then ListBase::UPPERALPHA when /^[a-z]/ then ListBase::LOWERALPHA else raise "Invalid List Type: #{self.inspect}" end line.stamp(Line::LIST, level+1, prefix, flag) text[margin, prefix_length] = " " * prefix_length assign_types_to_lines(offset, level + 1) next end if LABEL_LIST_RE =~ active_line offset = margin + $1.length prefix = $2 prefix_length = prefix.length next if handled_labeled_list(line, level, margin, offset, prefix) end # Headings look like # = Main heading # == Second level # === Third # # Headings reset the level to 0 if active_line[0] == ?= and active_line =~ /^(=+)\s*(.*)/ prefix_length = $1.length prefix_length = 6 if prefix_length > 6 line.stamp(Line::HEADING, 0, prefix_length) line.strip_leading(margin + prefix_length) next end # If the character's a space, then we have verbatim text, # otherwise if active_line[0] == SPACE line.strip_leading(margin) if margin > 0 line.stamp(Line::VERBATIM, level) else line.stamp(Line::PARAGRAPH, level) end end end # Handle labeled list entries, We have a special case # to deal with. Because the labels can be long, they force # the remaining block of text over the to right: # # this is a long label that I wrote:: and here is the # block of text with # a silly margin # # So we allow the special case. If the label is followed # by nothing, and if the following line is indented, then # we take the indent of that line as the new margin # # this is a long label that I wrote:: # here is a more reasonably indented block which # will ab attached to the label. # def handled_labeled_list(line, level, margin, offset, prefix) prefix_length = prefix.length text = line.text flag = nil case prefix when /^\[/ flag = ListBase::LABELED prefix = prefix[1, prefix.length-2] when /:$/ flag = ListBase::NOTE prefix.chop! else raise "Invalid List Type: #{self.inspect}" end # body is on the next line if text.length <= offset original_line = line line = @lines.next return(false) unless line text = line.text for i in 0..margin if text[i] != SPACE @lines.unget return false end end i = margin i += 1 while text[i] == SPACE if i >= text.length @lines.unget return false else offset = i prefix_length = 0 @lines.delete(original_line) end end line.stamp(Line::LIST, level+1, prefix, flag) text[margin, prefix_length] = " " * prefix_length assign_types_to_lines(offset, level + 1) return true end # Return a block consisting of fragments which are # paragraphs, list entries or verbatim text. We merge consecutive # lines of the same type and level together. We are also slightly # tricky with lists: the lines following a list introduction # look like paragraph lines at the next level, and we remap them # into list entries instead def group_lines @lines.rewind inList = false wantedType = wantedLevel = nil block = LineCollection.new group = nil while line = @lines.next if line.level == wantedLevel and line.type == wantedType group.add_text(line.text) else group = block.fragment_for(line) block.add(group) if line.type == Line::LIST wantedType = Line::PARAGRAPH else wantedType = line.type end wantedLevel = line.type == Line::HEADING ? line.param : line.level end end block.normalize block end ## for debugging, we allow access to our line contents as text def content @lines.as_text end public :content ## for debugging, return the list of line types def get_line_types @lines.line_types end public :get_line_types end end PK|]R|K a ardoc/parsers/parse_c.rbnu[# Classes and modules built in to the interpreter. We need # these to define superclasses of user objects require "rdoc/code_objects" require "rdoc/parsers/parserfactory" require "rdoc/options" require "rdoc/rdoc" module RDoc ## # Ruby's built-in classes. KNOWN_CLASSES = { "rb_cObject" => "Object", "rb_cArray" => "Array", "rb_cBignum" => "Bignum", "rb_cClass" => "Class", "rb_cDir" => "Dir", "rb_cData" => "Data", "rb_cFalseClass" => "FalseClass", "rb_cFile" => "File", "rb_cFixnum" => "Fixnum", "rb_cFloat" => "Float", "rb_cHash" => "Hash", "rb_cInteger" => "Integer", "rb_cIO" => "IO", "rb_cModule" => "Module", "rb_cNilClass" => "NilClass", "rb_cNumeric" => "Numeric", "rb_cProc" => "Proc", "rb_cRange" => "Range", "rb_cRegexp" => "Regexp", "rb_cString" => "String", "rb_cSymbol" => "Symbol", "rb_cThread" => "Thread", "rb_cTime" => "Time", "rb_cTrueClass" => "TrueClass", "rb_cStruct" => "Struct", "rb_eException" => "Exception", "rb_eStandardError" => "StandardError", "rb_eSystemExit" => "SystemExit", "rb_eInterrupt" => "Interrupt", "rb_eSignal" => "Signal", "rb_eFatal" => "Fatal", "rb_eArgError" => "ArgError", "rb_eEOFError" => "EOFError", "rb_eIndexError" => "IndexError", "rb_eRangeError" => "RangeError", "rb_eIOError" => "IOError", "rb_eRuntimeError" => "RuntimeError", "rb_eSecurityError" => "SecurityError", "rb_eSystemCallError" => "SystemCallError", "rb_eTypeError" => "TypeError", "rb_eZeroDivError" => "ZeroDivError", "rb_eNotImpError" => "NotImpError", "rb_eNoMemError" => "NoMemError", "rb_eFloatDomainError" => "FloatDomainError", "rb_eScriptError" => "ScriptError", "rb_eNameError" => "NameError", "rb_eSyntaxError" => "SyntaxError", "rb_eLoadError" => "LoadError", "rb_mKernel" => "Kernel", "rb_mComparable" => "Comparable", "rb_mEnumerable" => "Enumerable", "rb_mPrecision" => "Precision", "rb_mErrno" => "Errno", "rb_mFileTest" => "FileTest", "rb_mGC" => "GC", "rb_mMath" => "Math", "rb_mProcess" => "Process" } ## # We attempt to parse C extension files. Basically we look for # the standard patterns that you find in extensions: rb_define_class, # rb_define_method and so on. We also try to find the corresponding # C source for the methods and extract comments, but if we fail # we don't worry too much. # # The comments associated with a Ruby method are extracted from the C # comment block associated with the routine that _implements_ that # method, that is to say the method whose name is given in the # rb_define_method call. For example, you might write: # # /* # * Returns a new array that is a one-dimensional flattening of this # * array (recursively). That is, for every element that is an array, # * extract its elements into the new array. # * # * s = [ 1, 2, 3 ] #=> [1, 2, 3] # * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] # * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] # * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # */ # static VALUE # rb_ary_flatten(ary) # VALUE ary; # { # ary = rb_obj_dup(ary); # rb_ary_flatten_bang(ary); # return ary; # } # # ... # # void # Init_Array() # { # ... # rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0); # # Here RDoc will determine from the rb_define_method line that there's a # method called "flatten" in class Array, and will look for the implementation # in the method rb_ary_flatten. It will then use the comment from that # method in the HTML output. This method must be in the same source file # as the rb_define_method. # # C classes can be diagrammed (see /tc/dl/ruby/ruby/error.c), and RDoc # integrates C and Ruby source into one tree # # The comment blocks may include special directives: # # [Document-class: name] # This comment block is documentation for the given class. Use this # when the Init_xxx method is not named after the class. # # [Document-method: name] # This comment documents the named method. Use when RDoc cannot # automatically find the method from it's declaration # # [call-seq: text up to an empty line] # Because C source doesn't give descriptive names to Ruby-level parameters, # you need to document the calling sequence explicitly # # In addition, RDoc assumes by default that the C method implementing a # Ruby function is in the same source file as the rb_define_method call. # If this isn't the case, add the comment # # rb_define_method(....); // in: filename # # As an example, we might have an extension that defines multiple classes # in its Init_xxx method. We could document them using # # # /* # * Document-class: MyClass # * # * Encapsulate the writing and reading of the configuration # * file. ... # */ # # /* # * Document-method: read_value # * # * call-seq: # * cfg.read_value(key) -> value # * cfg.read_value(key} { |key| } -> value # * # * Return the value corresponding to +key+ from the configuration. # * In the second form, if the key isn't found, invoke the # * block and return its value. # */ # class C_Parser attr_accessor :progress extend ParserFactory parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/) @@known_bodies = {} # prepare to parse a C file def initialize(top_level, file_name, body, options, stats) @known_classes = KNOWN_CLASSES.dup @body = handle_tab_width(handle_ifdefs_in(body)) @options = options @stats = stats @top_level = top_level @classes = Hash.new @file_dir = File.dirname(file_name) @progress = $stderr unless options.quiet end # Extract the classes/modules and methods from a C file # and return the corresponding top-level object def scan remove_commented_out_lines do_classes do_constants do_methods do_includes do_aliases @top_level end ####### private ####### def progress(char) unless @options.quiet @progress.print(char) @progress.flush end end def warn(msg) $stderr.puts $stderr.puts msg $stderr.flush end def remove_private_comments(comment) comment.gsub!(/\/?\*--(.*?)\/?\*\+\+/m, '') comment.sub!(/\/?\*--.*/m, '') end ## # removes lines that are commented out that might otherwise get picked up # when scanning for classes and methods def remove_commented_out_lines @body.gsub!(%r{//.*rb_define_}, '//') end def handle_class_module(var_name, class_mod, class_name, parent, in_module) progress(class_mod[0, 1]) parent_name = @known_classes[parent] || parent if in_module enclosure = @classes[in_module] unless enclosure if enclosure = @known_classes[in_module] handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"), enclosure, nil, nil) enclosure = @classes[in_module] end end unless enclosure warn("Enclosing class/module '#{in_module}' for " + "#{class_mod} #{class_name} not known") return end else enclosure = @top_level end if class_mod == "class" cm = enclosure.add_class(NormalClass, class_name, parent_name) @stats.num_classes += 1 else cm = enclosure.add_module(NormalModule, class_name) @stats.num_modules += 1 end cm.record_location(enclosure.toplevel) find_class_comment(cm.full_name, cm) @classes[var_name] = cm @known_classes[var_name] = cm.full_name end ## # Look for class or module documentation above Init_+class_name+(void), # in a Document-class +class_name+ (or module) comment or above an # rb_define_class (or module). If a comment is supplied above a matching # Init_ and a rb_define_class the Init_ comment is used. # # /* # * This is a comment for Foo # */ # Init_Foo(void) { # VALUE cFoo = rb_define_class("Foo", rb_cObject); # } # # /* # * Document-class: Foo # * This is a comment for Foo # */ # Init_foo(void) { # VALUE cFoo = rb_define_class("Foo", rb_cObject); # } # # /* # * This is a comment for Foo # */ # VALUE cFoo = rb_define_class("Foo", rb_cObject); def find_class_comment(class_name, class_meth) comment = nil if @body =~ %r{((?>/\*.*?\*/\s+)) (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)}xmi comment = $1 elsif @body =~ %r{Document-(class|module):\s#{class_name}\s*?\n((?>.*?\*/))}m comment = $2 else if @body =~ /rb_define_(class|module)/m then class_name = class_name.split("::").last comments = [] @body.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index| comments[index] = chunk if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then comment = comments[index-1] break end end end end class_meth.comment = mangle_comment(comment) if comment end ############################################################ def do_classes @body.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do |var_name, class_name| handle_class_module(var_name, "module", class_name, nil, nil) end # The '.' lets us handle SWIG-generated files @body.scan(/([\w\.]+)\s* = \s*rb_define_class\s* \( \s*"(\w+)", \s*(\w+)\s* \)/mx) do |var_name, class_name, parent| handle_class_module(var_name, "class", class_name, parent, nil) end @body.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do |var_name, class_name, parent| parent = nil if parent == "0" handle_class_module(var_name, "class", class_name, parent, nil) end @body.scan(/(\w+)\s* = \s*rb_define_module_under\s* \( \s*(\w+), \s*"(\w+)" \s*\)/mx) do |var_name, in_module, class_name| handle_class_module(var_name, "module", class_name, nil, in_module) end @body.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s* \( \s*(\w+), \s*"(\w+)", \s*(\w+)\s* \s*\)/mx) do |var_name, in_module, class_name, parent| handle_class_module(var_name, "class", class_name, parent, in_module) end end ########################################################### def do_constants @body.scan(%r{\Wrb_define_ ( variable | readonly_variable | const | global_const | ) \s*\( (?:\s*(\w+),)? \s*"(\w+)", \s*(.*?)\s*\)\s*; }xm) do |type, var_name, const_name, definition| var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel" handle_constants(type, var_name, const_name, definition) end end ############################################################ def do_methods @body.scan(%r{rb_define_ ( singleton_method | method | module_function | private_method ) \s*\(\s*([\w\.]+), \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\) (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))? }xm) do |type, var_name, meth_name, meth_body, param_count, source_file| #" # Ignore top-object and weird struct.c dynamic stuff next if var_name == "ruby_top_self" next if var_name == "nstr" next if var_name == "envtbl" next if var_name == "argf" # it'd be nice to handle this one var_name = "rb_cObject" if var_name == "rb_mKernel" handle_method(type, var_name, meth_name, meth_body, param_count, source_file) end @body.scan(%r{rb_define_attr\( \s*([\w\.]+), \s*"([^"]+)", \s*(\d+), \s*(\d+)\s*\); }xm) do #" |var_name, attr_name, attr_reader, attr_writer| #var_name = "rb_cObject" if var_name == "rb_mKernel" handle_attr(var_name, attr_name, attr_reader.to_i != 0, attr_writer.to_i != 0) end @body.scan(%r{rb_define_global_function\s*\( \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\) (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))? }xm) do #" |meth_name, meth_body, param_count, source_file| handle_method("method", "rb_mKernel", meth_name, meth_body, param_count, source_file) end @body.scan(/define_filetest_function\s*\( \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, \s*(-?\w+)\s*\)/xm) do #" |meth_name, meth_body, param_count| handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count) handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count) end end ############################################################ def do_aliases @body.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do |var_name, new_name, old_name| @stats.num_methods += 1 class_name = @known_classes[var_name] || var_name class_obj = find_class(var_name, class_name) class_obj.add_alias(Alias.new("", old_name, new_name, "")) end end ## # Adds constant comments. By providing some_value: at the start ofthe # comment you can override the C value of the comment to give a friendly # definition. # # /* 300: The perfect score in bowling */ # rb_define_const(cFoo, "PERFECT", INT2FIX(300); # # Will override +INT2FIX(300)+ with the value +300+ in the output RDoc. # Values may include quotes and escaped colons (\:). def handle_constants(type, var_name, const_name, definition) #@stats.num_constants += 1 class_name = @known_classes[var_name] return unless class_name class_obj = find_class(var_name, class_name) unless class_obj warn("Enclosing class/module '#{const_name}' for not known") return end comment = find_const_comment(type, const_name) # In the case of rb_define_const, the definition and comment are in # "/* definition: comment */" form. The literal ':' and '\' characters # can be escaped with a backslash. if type.downcase == 'const' then elements = mangle_comment(comment).split(':') if elements.nil? or elements.empty? then con = Constant.new(const_name, definition, mangle_comment(comment)) else new_definition = elements[0..-2].join(':') if new_definition.empty? then # Default to literal C definition new_definition = definition else new_definition.gsub!("\:", ":") new_definition.gsub!("\\", '\\') end new_definition.sub!(/\A(\s+)/, '') new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}" con = Constant.new(const_name, new_definition, mangle_comment(new_comment)) end else con = Constant.new(const_name, definition, mangle_comment(comment)) end class_obj.add_constant(con) end ## # Finds a comment matching +type+ and +const_name+ either above the # comment or in the matching Document- section. def find_const_comment(type, const_name) if @body =~ %r{((?>^\s*/\*.*?\*/\s+)) rb_define_#{type}\((?:\s*(\w+),)?\s*"#{const_name}"\s*,.*?\)\s*;}xmi $1 elsif @body =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m $1 else '' end end ########################################################### def handle_attr(var_name, attr_name, reader, writer) rw = '' if reader #@stats.num_methods += 1 rw << 'R' end if writer #@stats.num_methods += 1 rw << 'W' end class_name = @known_classes[var_name] return unless class_name class_obj = find_class(var_name, class_name) if class_obj comment = find_attr_comment(attr_name) unless comment.empty? comment = mangle_comment(comment) end att = Attr.new('', attr_name, rw, comment) class_obj.add_attribute(att) end end ########################################################### def find_attr_comment(attr_name) if @body =~ %r{((?>/\*.*?\*/\s+)) rb_define_attr\((?:\s*(\w+),)?\s*"#{attr_name}"\s*,.*?\)\s*;}xmi $1 elsif @body =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m $1 else '' end end ########################################################### def handle_method(type, var_name, meth_name, meth_body, param_count, source_file = nil) progress(".") @stats.num_methods += 1 class_name = @known_classes[var_name] return unless class_name class_obj = find_class(var_name, class_name) if class_obj if meth_name == "initialize" meth_name = "new" type = "singleton_method" end meth_obj = AnyMethod.new("", meth_name) meth_obj.singleton = %w{singleton_method module_function}.include?(type) p_count = (Integer(param_count) rescue -1) if p_count < 0 meth_obj.params = "(...)" elsif p_count == 0 meth_obj.params = "()" else meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")" end if source_file file_name = File.join(@file_dir, source_file) body = (@@known_bodies[source_file] ||= File.read(file_name)) else body = @body end if find_body(meth_body, meth_obj, body) and meth_obj.document_self class_obj.add_method(meth_obj) end end end ############################################################ # Find the C code corresponding to a Ruby method def find_body(meth_name, meth_obj, body, quiet = false) case body when %r{((?>/\*.*?\*/\s*))(?:static\s+)?VALUE\s+#{meth_name} \s*(\(.*?\)).*?^}xm comment, params = $1, $2 body_text = $& remove_private_comments(comment) if comment # see if we can find the whole body re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}' if Regexp.new(re, Regexp::MULTILINE).match(body) body_text = $& end # The comment block may have been overridden with a # 'Document-method' block. This happens in the interpreter # when multiple methods are vectored through to the same # C method but those methods are logically distinct (for # example Kernel.hash and Kernel.object_id share the same # implementation override_comment = find_override_comment(meth_obj.name) comment = override_comment if override_comment find_modifiers(comment, meth_obj) if comment # meth_obj.params = params meth_obj.start_collecting_tokens meth_obj.add_token(RubyToken::Token.new(1,1).set_text(body_text)) meth_obj.comment = mangle_comment(comment) when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m comment = $1 find_body($2, meth_obj, body, true) find_modifiers(comment, meth_obj) meth_obj.comment = mangle_comment(comment) + meth_obj.comment when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m unless find_body($1, meth_obj, body, true) warn "No definition for #{meth_name}" unless quiet return false end else # No body, but might still have an override comment comment = find_override_comment(meth_obj.name) if comment find_modifiers(comment, meth_obj) meth_obj.comment = mangle_comment(comment) else warn "No definition for #{meth_name}" unless quiet return false end end true end ## # If the comment block contains a section that looks like: # # call-seq: # Array.new # Array.new(10) # # use it for the parameters. def find_modifiers(comment, meth_obj) if comment.sub!(/:nodoc:\s*^\s*\*?\s*$/m, '') or comment.sub!(/\A\/\*\s*:nodoc:\s*\*\/\Z/, '') meth_obj.document_self = false end if comment.sub!(/call-seq:(.*?)^\s*\*?\s*$/m, '') or comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '') seq = $1 seq.gsub!(/^\s*\*\s*/, '') meth_obj.call_seq = seq end end ############################################################ def find_override_comment(meth_name) name = Regexp.escape(meth_name) if @body =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m $1 end end ## # Look for includes of the form: # # rb_include_module(rb_cArray, rb_mEnumerable); def do_includes @body.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m| if cls = @classes[c] m = @known_classes[m] || m cls.add_include(Include.new(m, "")) end end end ## # Remove the /*'s and leading asterisks from C comments def mangle_comment(comment) comment.sub!(%r{/\*+}) { " " * $&.length } comment.sub!(%r{\*+/}) { " " * $&.length } comment.gsub!(/^[ \t]*\*/m) { " " * $&.length } comment end def find_class(raw_name, name) unless @classes[raw_name] if raw_name =~ /^rb_m/ @classes[raw_name] = @top_level.add_module(NormalModule, name) else @classes[raw_name] = @top_level.add_class(NormalClass, name, nil) end end @classes[raw_name] end def handle_tab_width(body) if /\t/ =~ body tab_width = Options.instance.tab_width body.split(/\n/).map do |line| 1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #` line end .join("\n") else body end end ## # Removes #ifdefs that would otherwise confuse us def handle_ifdefs_in(body) body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m) { $1 } end end end PK|]T??rdoc/parsers/parse_rb.rbnu[#!/usr/local/bin/ruby # Parse a Ruby source file, building a set of objects # representing the modules, classes, methods, # requires, and includes we find (these classes # are defined in code_objects.rb). # This file contains stuff stolen outright from: # # rtags.rb - # ruby-lex.rb - ruby lexcal analizer # ruby-token.rb - ruby tokens # by Keiju ISHITSUKA (Nippon Rational Inc.) # require "e2mmap" require "irb/slex" require "rdoc/code_objects" require "rdoc/tokenstream" require "rdoc/markup/simple_markup/preprocess" require "rdoc/parsers/parserfactory" $TOKEN_DEBUG = $DEBUG # Definitions of all tokens involved in the lexical analysis module RubyToken EXPR_BEG = :EXPR_BEG EXPR_MID = :EXPR_MID EXPR_END = :EXPR_END EXPR_ARG = :EXPR_ARG EXPR_FNAME = :EXPR_FNAME EXPR_DOT = :EXPR_DOT EXPR_CLASS = :EXPR_CLASS class Token NO_TEXT = "??".freeze attr :text def initialize(line_no, char_no) @line_no = line_no @char_no = char_no @text = NO_TEXT end # Because we're used in contexts that expect to return a token, # we set the text string and then return ourselves def set_text(text) @text = text self end attr_reader :line_no, :char_no, :text end class TkNode < Token attr :node end class TkId < Token def initialize(line_no, char_no, name) super(line_no, char_no) @name = name end attr :name end class TkKW < TkId end class TkVal < Token def initialize(line_no, char_no, value = nil) super(line_no, char_no) set_text(value) end end class TkOp < Token def name self.class.op_name end end class TkOPASGN < TkOp def initialize(line_no, char_no, op) super(line_no, char_no) op = TkReading2Token[op] unless op.kind_of?(Symbol) @op = op end attr :op end class TkUnknownChar < Token def initialize(line_no, char_no, id) super(line_no, char_no) @name = char_no.chr end attr :name end class TkError < Token end def set_token_position(line, char) @prev_line_no = line @prev_char_no = char end def Token(token, value = nil) tk = nil case token when String, Symbol source = token.kind_of?(String) ? TkReading2Token : TkSymbol2Token if (tk = source[token]).nil? IRB.fail TkReading2TokenNoKey, token end tk = Token(tk[0], value) else tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty? token.new(@prev_line_no, @prev_char_no) else token.new(@prev_line_no, @prev_char_no, value) end end tk end TokenDefinitions = [ [:TkCLASS, TkKW, "class", EXPR_CLASS], [:TkMODULE, TkKW, "module", EXPR_BEG], [:TkDEF, TkKW, "def", EXPR_FNAME], [:TkUNDEF, TkKW, "undef", EXPR_FNAME], [:TkBEGIN, TkKW, "begin", EXPR_BEG], [:TkRESCUE, TkKW, "rescue", EXPR_MID], [:TkENSURE, TkKW, "ensure", EXPR_BEG], [:TkEND, TkKW, "end", EXPR_END], [:TkIF, TkKW, "if", EXPR_BEG, :TkIF_MOD], [:TkUNLESS, TkKW, "unless", EXPR_BEG, :TkUNLESS_MOD], [:TkTHEN, TkKW, "then", EXPR_BEG], [:TkELSIF, TkKW, "elsif", EXPR_BEG], [:TkELSE, TkKW, "else", EXPR_BEG], [:TkCASE, TkKW, "case", EXPR_BEG], [:TkWHEN, TkKW, "when", EXPR_BEG], [:TkWHILE, TkKW, "while", EXPR_BEG, :TkWHILE_MOD], [:TkUNTIL, TkKW, "until", EXPR_BEG, :TkUNTIL_MOD], [:TkFOR, TkKW, "for", EXPR_BEG], [:TkBREAK, TkKW, "break", EXPR_END], [:TkNEXT, TkKW, "next", EXPR_END], [:TkREDO, TkKW, "redo", EXPR_END], [:TkRETRY, TkKW, "retry", EXPR_END], [:TkIN, TkKW, "in", EXPR_BEG], [:TkDO, TkKW, "do", EXPR_BEG], [:TkRETURN, TkKW, "return", EXPR_MID], [:TkYIELD, TkKW, "yield", EXPR_END], [:TkSUPER, TkKW, "super", EXPR_END], [:TkSELF, TkKW, "self", EXPR_END], [:TkNIL, TkKW, "nil", EXPR_END], [:TkTRUE, TkKW, "true", EXPR_END], [:TkFALSE, TkKW, "false", EXPR_END], [:TkAND, TkKW, "and", EXPR_BEG], [:TkOR, TkKW, "or", EXPR_BEG], [:TkNOT, TkKW, "not", EXPR_BEG], [:TkIF_MOD, TkKW], [:TkUNLESS_MOD, TkKW], [:TkWHILE_MOD, TkKW], [:TkUNTIL_MOD, TkKW], [:TkALIAS, TkKW, "alias", EXPR_FNAME], [:TkDEFINED, TkKW, "defined?", EXPR_END], [:TklBEGIN, TkKW, "BEGIN", EXPR_END], [:TklEND, TkKW, "END", EXPR_END], [:Tk__LINE__, TkKW, "__LINE__", EXPR_END], [:Tk__FILE__, TkKW, "__FILE__", EXPR_END], [:TkIDENTIFIER, TkId], [:TkFID, TkId], [:TkGVAR, TkId], [:TkIVAR, TkId], [:TkCONSTANT, TkId], [:TkINTEGER, TkVal], [:TkFLOAT, TkVal], [:TkSTRING, TkVal], [:TkXSTRING, TkVal], [:TkREGEXP, TkVal], [:TkCOMMENT, TkVal], [:TkDSTRING, TkNode], [:TkDXSTRING, TkNode], [:TkDREGEXP, TkNode], [:TkNTH_REF, TkId], [:TkBACK_REF, TkId], [:TkUPLUS, TkOp, "+@"], [:TkUMINUS, TkOp, "-@"], [:TkPOW, TkOp, "**"], [:TkCMP, TkOp, "<=>"], [:TkEQ, TkOp, "=="], [:TkEQQ, TkOp, "==="], [:TkNEQ, TkOp, "!="], [:TkGEQ, TkOp, ">="], [:TkLEQ, TkOp, "<="], [:TkANDOP, TkOp, "&&"], [:TkOROP, TkOp, "||"], [:TkMATCH, TkOp, "=~"], [:TkNMATCH, TkOp, "!~"], [:TkDOT2, TkOp, ".."], [:TkDOT3, TkOp, "..."], [:TkAREF, TkOp, "[]"], [:TkASET, TkOp, "[]="], [:TkLSHFT, TkOp, "<<"], [:TkRSHFT, TkOp, ">>"], [:TkCOLON2, TkOp], [:TkCOLON3, TkOp], # [:OPASGN, TkOp], # +=, -= etc. # [:TkASSOC, TkOp, "=>"], [:TkQUESTION, TkOp, "?"], #? [:TkCOLON, TkOp, ":"], #: [:TkfLPAREN], # func( # [:TkfLBRACK], # func[ # [:TkfLBRACE], # func{ # [:TkSTAR], # *arg [:TkAMPER], # &arg # [:TkSYMBOL, TkId], # :SYMBOL [:TkSYMBEG, TkId], [:TkGT, TkOp, ">"], [:TkLT, TkOp, "<"], [:TkPLUS, TkOp, "+"], [:TkMINUS, TkOp, "-"], [:TkMULT, TkOp, "*"], [:TkDIV, TkOp, "/"], [:TkMOD, TkOp, "%"], [:TkBITOR, TkOp, "|"], [:TkBITXOR, TkOp, "^"], [:TkBITAND, TkOp, "&"], [:TkBITNOT, TkOp, "~"], [:TkNOTOP, TkOp, "!"], [:TkBACKQUOTE, TkOp, "`"], [:TkASSIGN, Token, "="], [:TkDOT, Token, "."], [:TkLPAREN, Token, "("], #(exp) [:TkLBRACK, Token, "["], #[arry] [:TkLBRACE, Token, "{"], #{hash} [:TkRPAREN, Token, ")"], [:TkRBRACK, Token, "]"], [:TkRBRACE, Token, "}"], [:TkCOMMA, Token, ","], [:TkSEMICOLON, Token, ";"], [:TkRD_COMMENT], [:TkSPACE], [:TkNL], [:TkEND_OF_SCRIPT], [:TkBACKSLASH, TkUnknownChar, "\\"], [:TkAT, TkUnknownChar, "@"], [:TkDOLLAR, TkUnknownChar, "\$"], #" ] # {reading => token_class} # {reading => [token_class, *opt]} TkReading2Token = {} TkSymbol2Token = {} def RubyToken.def_token(token_n, super_token = Token, reading = nil, *opts) token_n = token_n.id2name unless token_n.kind_of?(String) if RubyToken.const_defined?(token_n) IRB.fail AlreadyDefinedToken, token_n end token_c = Class.new super_token RubyToken.const_set token_n, token_c # token_c.inspect if reading if TkReading2Token[reading] IRB.fail TkReading2TokenDuplicateError, token_n, reading end if opts.empty? TkReading2Token[reading] = [token_c] else TkReading2Token[reading] = [token_c].concat(opts) end end TkSymbol2Token[token_n.intern] = token_c if token_c <= TkOp token_c.class_eval %{ def self.op_name; "#{reading}"; end } end end for defs in TokenDefinitions def_token(*defs) end NEWLINE_TOKEN = TkNL.new(0,0) NEWLINE_TOKEN.set_text("\n") end # Lexical analyzer for Ruby source class RubyLex ###################################################################### # # Read an input stream character by character. We allow for unlimited # ungetting of characters just read. # # We simplify the implementation greatly by reading the entire input # into a buffer initially, and then simply traversing it using # pointers. # # We also have to allow for the here document diversion. This # little gem comes about when the lexer encounters a here # document. At this point we effectively need to split the input # stream into two parts: one to read the body of the here document, # the other to read the rest of the input line where the here # document was initially encountered. For example, we might have # # do_something(<<-A, <<-B) # stuff # for # A # stuff # for # B # # When the lexer encounters the <= @size ch = @content[@offset, 1] @offset += 1 @hwm = @offset if @hwm < @offset if @newline_pending @line_num += 1 @last_newline = @offset - 1 @newline_pending = false end if ch == "\n" @newline_pending = true end ch end def getc_already_read getc end def ungetc(ch) raise "unget past beginning of file" if @offset <= 0 @offset -= 1 if @content[@offset] == ?\n @newline_pending = false end end def get_read res = @content[@read_back_offset...@offset] @read_back_offset = @offset res end def peek(at) pos = @offset + at if pos >= @size nil else @content[pos, 1] end end def peek_equal(str) @content[@offset, str.length] == str end def divert_read_from(reserve) @content[@offset, 0] = reserve @size = @content.size end end # end of nested class BufferedReader extend Exception2MessageMapper def_exception(:AlreadyDefinedToken, "Already defined token(%s)") def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')") def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')") def_exception(:TkReading2TokenDuplicateError, "key duplicate(token_n='%s', key='%s')") def_exception(:SyntaxError, "%s") include RubyToken include IRB attr_reader :continue attr_reader :lex_state def RubyLex.debug? false end def initialize(content) lex_init @reader = BufferedReader.new(content) @exp_line_no = @line_no = 1 @base_char_no = 0 @indent = 0 @ltype = nil @quoted = nil @lex_state = EXPR_BEG @space_seen = false @continue = false @line = "" @skip_space = false @read_auto_clean_up = false @exception_on_syntax_error = true end attr :skip_space, true attr :read_auto_clean_up, true attr :exception_on_syntax_error, true attr :indent # io functions def line_no @reader.line_num end def char_no @reader.column end def get_read @reader.get_read end def getc @reader.getc end def getc_of_rests @reader.getc_already_read end def gets c = getc or return l = "" begin l.concat c unless c == "\r" break if c == "\n" end while c = getc l end def ungetc(c = nil) @reader.ungetc(c) end def peek_equal?(str) @reader.peek_equal(str) end def peek(i = 0) @reader.peek(i) end def lex until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) && !@continue or tk.nil?) end line = get_read if line == "" and tk.kind_of?(TkEND_OF_SCRIPT) || tk.nil? nil else line end end def token set_token_position(line_no, char_no) begin begin tk = @OP.match(self) @space_seen = tk.kind_of?(TkSPACE) rescue SyntaxError abort if @exception_on_syntax_error tk = TkError.new(line_no, char_no) end end while @skip_space and tk.kind_of?(TkSPACE) if @read_auto_clean_up get_read end # throw :eof unless tk p tk if $DEBUG tk end ENINDENT_CLAUSE = [ "case", "class", "def", "do", "for", "if", "module", "unless", "until", "while", "begin" #, "when" ] DEINDENT_CLAUSE = ["end" #, "when" ] PERCENT_LTYPE = { "q" => "\'", "Q" => "\"", "x" => "\`", "r" => "/", "w" => "]" } PERCENT_PAREN = { "{" => "}", "[" => "]", "<" => ">", "(" => ")" } Ltype2Token = { "\'" => TkSTRING, "\"" => TkSTRING, "\`" => TkXSTRING, "/" => TkREGEXP, "]" => TkDSTRING } Ltype2Token.default = TkSTRING DLtype2Token = { "\"" => TkDSTRING, "\`" => TkDXSTRING, "/" => TkDREGEXP, } def lex_init() @OP = SLex.new @OP.def_rules("\0", "\004", "\032") do |chars, io| Token(TkEND_OF_SCRIPT).set_text(chars) end @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |chars, io| @space_seen = TRUE while (ch = getc) =~ /[ \t\f\r\13]/ chars << ch end ungetc Token(TkSPACE).set_text(chars) end @OP.def_rule("#") do |op, io| identify_comment end @OP.def_rule("=begin", proc{@prev_char_no == 0 && peek(0) =~ /\s/}) do |op, io| str = op @ltype = "=" begin line = "" begin ch = getc line << ch end until ch == "\n" str << line end until line =~ /^=end/ ungetc @ltype = nil if str =~ /\A=begin\s+rdoc/i str.sub!(/\A=begin.*\n/, '') str.sub!(/^=end.*/m, '') Token(TkCOMMENT).set_text(str) else Token(TkRD_COMMENT)#.set_text(str) end end @OP.def_rule("\n") do print "\\n\n" if RubyLex.debug? case @lex_state when EXPR_BEG, EXPR_FNAME, EXPR_DOT @continue = TRUE else @continue = FALSE @lex_state = EXPR_BEG end Token(TkNL).set_text("\n") end @OP.def_rules("*", "**", "!", "!=", "!~", "=", "==", "===", "=~", "<=>", "<", "<=", ">", ">=", ">>") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end @OP.def_rules("<<") do |op, io| tk = nil if @lex_state != EXPR_END && @lex_state != EXPR_CLASS && (@lex_state != EXPR_ARG || @space_seen) c = peek(0) if /[-\w_\"\'\`]/ =~ c tk = identify_here_document end end if !tk @lex_state = EXPR_BEG tk = Token(op).set_text(op) end tk end @OP.def_rules("'", '"') do |op, io| identify_string(op) end @OP.def_rules("`") do |op, io| if @lex_state == EXPR_FNAME Token(op).set_text(op) else identify_string(op) end end @OP.def_rules('?') do |op, io| if @lex_state == EXPR_END @lex_state = EXPR_BEG Token(TkQUESTION).set_text(op) else ch = getc if @lex_state == EXPR_ARG && ch !~ /\s/ ungetc @lex_state = EXPR_BEG; Token(TkQUESTION).set_text(op) else str = op str << ch if (ch == '\\') #' str << read_escape end @lex_state = EXPR_END Token(TkINTEGER).set_text(str) end end end @OP.def_rules("&", "&&", "|", "||") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end @OP.def_rules("+=", "-=", "*=", "**=", "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do |op, io| @lex_state = EXPR_BEG op =~ /^(.*)=$/ Token(TkOPASGN, $1).set_text(op) end @OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do |op, io| Token(TkUPLUS).set_text(op) end @OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) do |op, io| Token(TkUMINUS).set_text(op) end @OP.def_rules("+", "-") do |op, io| catch(:RET) do if @lex_state == EXPR_ARG if @space_seen and peek(0) =~ /[0-9]/ throw :RET, identify_number(op) else @lex_state = EXPR_BEG end elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/ throw :RET, identify_number(op) else @lex_state = EXPR_BEG end Token(op).set_text(op) end end @OP.def_rule(".") do @lex_state = EXPR_BEG if peek(0) =~ /[0-9]/ ungetc identify_number("") else # for obj.if @lex_state = EXPR_DOT Token(TkDOT).set_text(".") end end @OP.def_rules("..", "...") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end lex_int2 end def lex_int2 @OP.def_rules("]", "}", ")") do |op, io| @lex_state = EXPR_END @indent -= 1 Token(op).set_text(op) end @OP.def_rule(":") do if @lex_state == EXPR_END || peek(0) =~ /\s/ @lex_state = EXPR_BEG tk = Token(TkCOLON) else @lex_state = EXPR_FNAME; tk = Token(TkSYMBEG) end tk.set_text(":") end @OP.def_rule("::") do # p @lex_state.id2name, @space_seen if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen @lex_state = EXPR_BEG tk = Token(TkCOLON3) else @lex_state = EXPR_DOT tk = Token(TkCOLON2) end tk.set_text("::") end @OP.def_rule("/") do |op, io| if @lex_state == EXPR_BEG || @lex_state == EXPR_MID identify_string(op) elsif peek(0) == '=' getc @lex_state = EXPR_BEG Token(TkOPASGN, :/).set_text("/=") #") elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ identify_string(op) else @lex_state = EXPR_BEG Token("/").set_text(op) end end @OP.def_rules("^") do @lex_state = EXPR_BEG Token("^").set_text("^") end # @OP.def_rules("^=") do # @lex_state = EXPR_BEG # Token(TkOPASGN, :^) # end @OP.def_rules(",", ";") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end @OP.def_rule("~") do @lex_state = EXPR_BEG Token("~").set_text("~") end @OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) do @lex_state = EXPR_BEG Token("~").set_text("~@") end @OP.def_rule("(") do @indent += 1 if @lex_state == EXPR_BEG || @lex_state == EXPR_MID @lex_state = EXPR_BEG tk = Token(TkfLPAREN) else @lex_state = EXPR_BEG tk = Token(TkLPAREN) end tk.set_text("(") end @OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) do Token("[]").set_text("[]") end @OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) do Token("[]=").set_text("[]=") end @OP.def_rule("[") do @indent += 1 if @lex_state == EXPR_FNAME t = Token(TkfLBRACK) else if @lex_state == EXPR_BEG || @lex_state == EXPR_MID t = Token(TkLBRACK) elsif @lex_state == EXPR_ARG && @space_seen t = Token(TkLBRACK) else t = Token(TkfLBRACK) end @lex_state = EXPR_BEG end t.set_text("[") end @OP.def_rule("{") do @indent += 1 if @lex_state != EXPR_END && @lex_state != EXPR_ARG t = Token(TkLBRACE) else t = Token(TkfLBRACE) end @lex_state = EXPR_BEG t.set_text("{") end @OP.def_rule('\\') do #' if getc == "\n" @space_seen = true @continue = true Token(TkSPACE).set_text("\\\n") else ungetc Token("\\").set_text("\\") #" end end @OP.def_rule('%') do |op, io| if @lex_state == EXPR_BEG || @lex_state == EXPR_MID identify_quotation('%') elsif peek(0) == '=' getc Token(TkOPASGN, "%").set_text("%=") elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ identify_quotation('%') else @lex_state = EXPR_BEG Token("%").set_text("%") end end @OP.def_rule('$') do #' identify_gvar end @OP.def_rule('@') do if peek(0) =~ /[@\w_]/ ungetc identify_identifier else Token("@").set_text("@") end end # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do # |op, io| # @indent += 1 # @lex_state = EXPR_FNAME # # @lex_state = EXPR_END # # until @rests[0] == "\n" or @rests[0] == ";" # # rests.shift # # end # end @OP.def_rule("__END__", proc{@prev_char_no == 0 && peek(0) =~ /[\r\n]/}) do throw :eof end @OP.def_rule("") do |op, io| printf "MATCH: start %s: %s\n", op, io.inspect if RubyLex.debug? if peek(0) =~ /[0-9]/ t = identify_number("") elsif peek(0) =~ /[\w_]/ t = identify_identifier end printf "MATCH: end %s: %s\n", op, io.inspect if RubyLex.debug? t end p @OP if RubyLex.debug? end def identify_gvar @lex_state = EXPR_END str = "$" tk = case ch = getc when /[~_*$?!@\/\\;,=:<>".]/ #" str << ch Token(TkGVAR, str) when "-" str << "-" << getc Token(TkGVAR, str) when "&", "`", "'", "+" str << ch Token(TkBACK_REF, str) when /[1-9]/ str << ch while (ch = getc) =~ /[0-9]/ str << ch end ungetc Token(TkNTH_REF) when /\w/ ungetc ungetc return identify_identifier else ungetc Token("$") end tk.set_text(str) end def identify_identifier token = "" token.concat getc if peek(0) =~ /[$@]/ token.concat getc if peek(0) == "@" while (ch = getc) =~ /\w|_/ print ":", ch, ":" if RubyLex.debug? token.concat ch end ungetc if ch == "!" or ch == "?" token.concat getc end # fix token # $stderr.puts "identifier - #{token}, state = #@lex_state" case token when /^\$/ return Token(TkGVAR, token).set_text(token) when /^\@/ @lex_state = EXPR_END return Token(TkIVAR, token).set_text(token) end if @lex_state != EXPR_DOT print token, "\n" if RubyLex.debug? token_c, *trans = TkReading2Token[token] if token_c # reserved word? if (@lex_state != EXPR_BEG && @lex_state != EXPR_FNAME && trans[1]) # modifiers token_c = TkSymbol2Token[trans[1]] @lex_state = trans[0] else if @lex_state != EXPR_FNAME if ENINDENT_CLAUSE.include?(token) @indent += 1 elsif DEINDENT_CLAUSE.include?(token) @indent -= 1 end @lex_state = trans[0] else @lex_state = EXPR_END end end return Token(token_c, token).set_text(token) end end if @lex_state == EXPR_FNAME @lex_state = EXPR_END if peek(0) == '=' token.concat getc end elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_END end if token[0, 1] =~ /[A-Z]/ return Token(TkCONSTANT, token).set_text(token) elsif token[token.size - 1, 1] =~ /[!?]/ return Token(TkFID, token).set_text(token) else return Token(TkIDENTIFIER, token).set_text(token) end end def identify_here_document ch = getc if ch == "-" ch = getc indent = true end if /['"`]/ =~ ch # ' lt = ch quoted = "" while (c = getc) && c != lt quoted.concat c end else lt = '"' quoted = ch.dup while (c = getc) && c =~ /\w/ quoted.concat c end ungetc end ltback, @ltype = @ltype, lt reserve = "" while ch = getc reserve << ch if ch == "\\" #" ch = getc reserve << ch elsif ch == "\n" break end end str = "" while (l = gets) l.chomp! l.strip! if indent break if l == quoted str << l.chomp << "\n" end @reader.divert_read_from(reserve) @ltype = ltback @lex_state = EXPR_END Token(Ltype2Token[lt], str).set_text(str.dump) end def identify_quotation(initial_char) ch = getc if lt = PERCENT_LTYPE[ch] initial_char += ch ch = getc elsif ch =~ /\W/ lt = "\"" else RubyLex.fail SyntaxError, "unknown type of %string ('#{ch}')" end # if ch !~ /\W/ # ungetc # next # end #@ltype = lt @quoted = ch unless @quoted = PERCENT_PAREN[ch] identify_string(lt, @quoted, ch, initial_char) end def identify_number(start) str = start.dup if start == "+" or start == "-" or start == "" start = getc str << start end @lex_state = EXPR_END if start == "0" if peek(0) == "x" ch = getc str << ch match = /[0-9a-f_]/ else match = /[0-7_]/ end while ch = getc if ch !~ match ungetc break else str << ch end end return Token(TkINTEGER).set_text(str) end type = TkINTEGER allow_point = TRUE allow_e = TRUE while ch = getc case ch when /[0-9_]/ str << ch when allow_point && "." type = TkFLOAT if peek(0) !~ /[0-9]/ ungetc break end str << ch allow_point = false when allow_e && "e", allow_e && "E" str << ch type = TkFLOAT if peek(0) =~ /[+-]/ str << getc end allow_e = false allow_point = false else ungetc break end end Token(type).set_text(str) end def identify_string(ltype, quoted = ltype, opener=nil, initial_char = nil) @ltype = ltype @quoted = quoted subtype = nil str = "" str << initial_char if initial_char str << (opener||quoted) nest = 0 begin while ch = getc str << ch if @quoted == ch if nest == 0 break else nest -= 1 end elsif opener == ch nest += 1 elsif @ltype != "'" && @ltype != "]" and ch == "#" ch = getc if ch == "{" subtype = true str << ch << skip_inner_expression else ungetc(ch) end elsif ch == '\\' #' str << read_escape end end if @ltype == "/" if peek(0) =~ /i|o|n|e|s/ str << getc end end if subtype Token(DLtype2Token[ltype], str) else Token(Ltype2Token[ltype], str) end.set_text(str) ensure @ltype = nil @quoted = nil @lex_state = EXPR_END end end def skip_inner_expression res = "" nest = 0 while (ch = getc) res << ch if ch == '}' break if nest.zero? nest -= 1 elsif ch == '{' nest += 1 end end res end def identify_comment @ltype = "#" comment = "#" while ch = getc if ch == "\\" ch = getc if ch == "\n" ch = " " else comment << "\\" end else if ch == "\n" @ltype = nil ungetc break end end comment << ch end return Token(TkCOMMENT).set_text(comment) end def read_escape res = "" case ch = getc when /[0-7]/ ungetc ch 3.times do case ch = getc when /[0-7]/ when nil break else ungetc break end res << ch end when "x" res << ch 2.times do case ch = getc when /[0-9a-fA-F]/ when nil break else ungetc break end res << ch end when "M" res << ch if (ch = getc) != '-' ungetc else res << ch if (ch = getc) == "\\" #" res << ch res << read_escape else res << ch end end when "C", "c" #, "^" res << ch if ch == "C" and (ch = getc) != "-" ungetc else res << ch if (ch = getc) == "\\" #" res << ch res << read_escape else res << ch end end else res << ch end res end end # Extract code elements from a source file, returning a TopLevel # object containing the constituent file elements. # # This file is based on rtags module RDoc GENERAL_MODIFIERS = [ 'nodoc' ].freeze CLASS_MODIFIERS = GENERAL_MODIFIERS ATTR_MODIFIERS = GENERAL_MODIFIERS CONSTANT_MODIFIERS = GENERAL_MODIFIERS METHOD_MODIFIERS = GENERAL_MODIFIERS + [ 'arg', 'args', 'yield', 'yields', 'notnew', 'not-new', 'not_new', 'doc' ] class RubyParser include RubyToken include TokenStream extend ParserFactory parse_files_matching(/\.rbw?$/) def initialize(top_level, file_name, content, options, stats) @options = options @stats = stats @size = 0 @token_listeners = nil @input_file_name = file_name @scanner = RubyLex.new(content) @scanner.exception_on_syntax_error = false @top_level = top_level @progress = $stderr unless options.quiet end def scan @tokens = [] @unget_read = [] @read = [] catch(:eof) do catch(:enddoc) do begin parse_toplevel_statements(@top_level) rescue Exception => e $stderr.puts "\n\n" $stderr.puts "RDoc failure in #@input_file_name at or around " + "line #{@scanner.line_no} column #{@scanner.char_no}" $stderr.puts $stderr.puts "Before reporting this, could you check that the file" $stderr.puts "you're documenting compiles cleanly--RDoc is not a" $stderr.puts "full Ruby parser, and gets confused easily if fed" $stderr.puts "invalid programs." $stderr.puts $stderr.puts "The internal error was:\n\n" e.set_backtrace(e.backtrace[0,4]) raise end end end @top_level end private def make_message(msg) prefix = "\n" + @input_file_name + ":" if @scanner prefix << "#{@scanner.line_no}:#{@scanner.char_no}: " end return prefix + msg end def warn(msg) return if @options.quiet msg = make_message msg $stderr.puts msg end def error(msg) msg = make_message msg $stderr.puts msg exit(1) end def progress(char) unless @options.quiet @progress.print(char) @progress.flush end end def add_token_listener(obj) @token_listeners ||= [] @token_listeners << obj end def remove_token_listener(obj) @token_listeners.delete(obj) end def get_tk tk = nil if @tokens.empty? tk = @scanner.token @read.push @scanner.get_read puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG else @read.push @unget_read.shift tk = @tokens.shift puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG end if tk.kind_of?(TkSYMBEG) set_token_position(tk.line_no, tk.char_no) tk1 = get_tk if tk1.kind_of?(TkId) || tk1.kind_of?(TkOp) tk = Token(TkSYMBOL).set_text(":" + tk1.name) # remove the identifier we just read (we're about to # replace it with a symbol) @token_listeners.each do |obj| obj.pop_token end if @token_listeners else warn("':' not followed by identifier or operator") tk = tk1 end end # inform any listeners of our shiny new token @token_listeners.each do |obj| obj.add_token(tk) end if @token_listeners tk end def peek_tk unget_tk(tk = get_tk) tk end def unget_tk(tk) @tokens.unshift tk @unget_read.unshift @read.pop # Remove this token from any listeners @token_listeners.each do |obj| obj.pop_token end if @token_listeners end def skip_tkspace(skip_nl = true) tokens = [] while ((tk = get_tk).kind_of?(TkSPACE) || (skip_nl && tk.kind_of?(TkNL))) tokens.push tk end unget_tk(tk) tokens end def get_tkread read = @read.join("") @read = [] read end def peek_read @read.join('') end NORMAL = "::" SINGLE = "<<" # Look for the first comment in a file that isn't # a shebang line. def collect_first_comment skip_tkspace res = '' first_line = true tk = get_tk while tk.kind_of?(TkCOMMENT) if first_line && /\A#!/ =~ tk.text skip_tkspace tk = get_tk elsif first_line && /\A#\s*-\*-/ =~ tk.text first_line = false skip_tkspace tk = get_tk else first_line = false res << tk.text << "\n" tk = get_tk if tk.kind_of? TkNL skip_tkspace(false) tk = get_tk end end end unget_tk(tk) res end def parse_toplevel_statements(container) comment = collect_first_comment look_for_directives_in(container, comment) container.comment = comment unless comment.empty? parse_statements(container, NORMAL, nil, comment) end def parse_statements(container, single=NORMAL, current_method=nil, comment='') nest = 1 save_visibility = container.visibility # if container.kind_of?(TopLevel) # else # comment = '' # end non_comment_seen = true while tk = get_tk keep_comment = false non_comment_seen = true unless tk.kind_of?(TkCOMMENT) case tk when TkNL skip_tkspace(true) # Skip blanks and newlines tk = get_tk if tk.kind_of?(TkCOMMENT) if non_comment_seen comment = '' non_comment_seen = false end while tk.kind_of?(TkCOMMENT) comment << tk.text << "\n" tk = get_tk # this is the newline skip_tkspace(false) # leading spaces tk = get_tk end unless comment.empty? look_for_directives_in(container, comment) if container.done_documenting container.ongoing_visibility = save_visibility # return end end keep_comment = true else non_comment_seen = true end unget_tk(tk) keep_comment = true when TkCLASS if container.document_children parse_class(container, single, tk, comment) else nest += 1 end when TkMODULE if container.document_children parse_module(container, single, tk, comment) else nest += 1 end when TkDEF if container.document_self parse_method(container, single, tk, comment) else nest += 1 end when TkCONSTANT if container.document_self parse_constant(container, single, tk, comment) end when TkALIAS if container.document_self parse_alias(container, single, tk, comment) end when TkYIELD if current_method.nil? warn("Warning: yield outside of method") if container.document_self else parse_yield(container, single, tk, current_method) end # Until and While can have a 'do', which shouldn't increas # the nesting. We can't solve the general case, but we can # handle most occurrences by ignoring a do at the end of a line when TkUNTIL, TkWHILE nest += 1 puts "FOUND #{tk.class} in #{container.name}, nest = #{nest}, " + "line #{tk.line_no}" if $DEBUG skip_optional_do_after_expression # 'for' is trickier when TkFOR nest += 1 puts "FOUND #{tk.class} in #{container.name}, nest = #{nest}, " + "line #{tk.line_no}" if $DEBUG skip_for_variable skip_optional_do_after_expression when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN nest += 1 puts "Found #{tk.class} in #{container.name}, nest = #{nest}, " + "line #{tk.line_no}" if $DEBUG when TkIDENTIFIER if nest == 1 and current_method.nil? case tk.name when "private", "protected", "public", "private_class_method", "public_class_method" parse_visibility(container, single, tk) keep_comment = true when "attr" parse_attr(container, single, tk, comment) when /^attr_(reader|writer|accessor)$/, @options.extra_accessors parse_attr_accessor(container, single, tk, comment) when "alias_method" if container.document_self parse_alias(container, single, tk, comment) end end end case tk.name when "require" parse_require(container, comment) when "include" parse_include(container, comment) end when TkEND nest -= 1 puts "Found 'end' in #{container.name}, nest = #{nest}, line #{tk.line_no}" if $DEBUG puts "Method = #{current_method.name}" if $DEBUG and current_method if nest == 0 read_documentation_modifiers(container, CLASS_MODIFIERS) container.ongoing_visibility = save_visibility return end end comment = '' unless keep_comment begin get_tkread skip_tkspace(false) end while peek_tk == TkNL end end def parse_class(container, single, tk, comment, &block) progress("c") @stats.num_classes += 1 container, name_t = get_class_or_module(container) case name_t when TkCONSTANT name = name_t.name superclass = "Object" if peek_tk.kind_of?(TkLT) get_tk skip_tkspace(true) superclass = get_class_specification superclass = "" if superclass.empty? end if single == SINGLE cls_type = SingleClass else cls_type = NormalClass end cls = container.add_class(cls_type, name, superclass) read_documentation_modifiers(cls, CLASS_MODIFIERS) cls.record_location(@top_level) parse_statements(cls) cls.comment = comment when TkLSHFT case name = get_class_specification when "self", container.name parse_statements(container, SINGLE, &block) else other = TopLevel.find_class_named(name) unless other # other = @top_level.add_class(NormalClass, name, nil) # other.record_location(@top_level) # other.comment = comment other = NormalClass.new("Dummy", nil) end read_documentation_modifiers(other, CLASS_MODIFIERS) parse_statements(other, SINGLE, &block) end else warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}") end end def parse_module(container, single, tk, comment) progress("m") @stats.num_modules += 1 container, name_t = get_class_or_module(container) # skip_tkspace name = name_t.name mod = container.add_module(NormalModule, name) mod.record_location(@top_level) read_documentation_modifiers(mod, CLASS_MODIFIERS) parse_statements(mod) mod.comment = comment end # Look for the name of a class of module (optionally with a leading :: or # with :: separated named) and return the ultimate name and container def get_class_or_module(container) skip_tkspace name_t = get_tk # class ::A -> A is in the top level if name_t.kind_of?(TkCOLON2) name_t = get_tk container = @top_level end skip_tkspace(false) while peek_tk.kind_of?(TkCOLON2) prev_container = container container = container.find_module_named(name_t.name) if !container # warn("Couldn't find module #{name_t.name}") container = prev_container.add_module(NormalModule, name_t.name) end get_tk name_t = get_tk end skip_tkspace(false) return [container, name_t] end def parse_constant(container, single, tk, comment) name = tk.name skip_tkspace(false) eq_tk = get_tk unless eq_tk.kind_of?(TkASSIGN) unget_tk(eq_tk) return end nest = 0 get_tkread tk = get_tk if tk.kind_of? TkGT unget_tk(tk) unget_tk(eq_tk) return end loop do puts("Param: #{tk}, #{@scanner.continue} " + "#{@scanner.lex_state} #{nest}") if $DEBUG case tk when TkSEMICOLON break when TkLPAREN, TkfLPAREN nest += 1 when TkRPAREN nest -= 1 when TkCOMMENT if nest <= 0 && @scanner.lex_state == EXPR_END unget_tk(tk) break end when TkNL if (@scanner.lex_state == EXPR_END and nest <= 0) || !@scanner.continue unget_tk(tk) break end end tk = get_tk end res = get_tkread.tr("\n", " ").strip res = "" if res == ";" con = Constant.new(name, res, comment) read_documentation_modifiers(con, CONSTANT_MODIFIERS) if con.document_self container.add_constant(con) end end def parse_method(container, single, tk, comment) progress(".") @stats.num_methods += 1 line_no = tk.line_no column = tk.char_no start_collecting_tokens add_token(tk) add_token_listener(self) @scanner.instance_eval{@lex_state = EXPR_FNAME} skip_tkspace(false) name_t = get_tk back_tk = skip_tkspace meth = nil added_container = false dot = get_tk if dot.kind_of?(TkDOT) or dot.kind_of?(TkCOLON2) @scanner.instance_eval{@lex_state = EXPR_FNAME} skip_tkspace name_t2 = get_tk case name_t when TkSELF name = name_t2.name when TkCONSTANT name = name_t2.name prev_container = container container = container.find_module_named(name_t.name) if !container added_container = true obj = name_t.name.split("::").inject(Object) do |state, item| state.const_get(item) end rescue nil type = obj.class == Class ? NormalClass : NormalModule if not [Class, Module].include?(obj.class) warn("Couldn't find #{name_t.name}. Assuming it's a module") end if type == NormalClass then container = prev_container.add_class(type, name_t.name, obj.superclass.name) else container = prev_container.add_module(type, name_t.name) end end else # warn("Unexpected token '#{name_t2.inspect}'") # break skip_method(container) return end meth = AnyMethod.new(get_tkread, name) meth.singleton = true else unget_tk dot back_tk.reverse_each do |tk| unget_tk tk end name = name_t.name meth = AnyMethod.new(get_tkread, name) meth.singleton = (single == SINGLE) end remove_token_listener(self) meth.start_collecting_tokens indent = TkSPACE.new(1,1) indent.set_text(" " * column) meth.add_tokens([TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}"), NEWLINE_TOKEN, indent]) meth.add_tokens(@token_stream) add_token_listener(meth) @scanner.instance_eval{@continue = false} parse_method_parameters(meth) if meth.document_self container.add_method(meth) elsif added_container container.document_self = false end # Having now read the method parameters and documentation modifiers, we # now know whether we have to rename #initialize to ::new if name == "initialize" && !meth.singleton if meth.dont_rename_initialize meth.visibility = :protected else meth.singleton = true meth.name = "new" meth.visibility = :public end end parse_statements(container, single, meth) remove_token_listener(meth) # Look for a 'call-seq' in the comment, and override the # normal parameter stuff if comment.sub!(/:?call-seq:(.*?)^\s*\#?\s*$/m, '') seq = $1 seq.gsub!(/^\s*\#\s*/, '') meth.call_seq = seq end meth.comment = comment end def skip_method(container) meth = AnyMethod.new("", "anon") parse_method_parameters(meth) parse_statements(container, false, meth) end # Capture the method's parameters. Along the way, # look for a comment containing # # # yields: .... # # and add this as the block_params for the method def parse_method_parameters(method) res = parse_method_or_yield_parameters(method) res = "(" + res + ")" unless res[0] == ?( method.params = res unless method.params if method.block_params.nil? skip_tkspace(false) read_documentation_modifiers(method, METHOD_MODIFIERS) end end def parse_method_or_yield_parameters(method=nil, modifiers=METHOD_MODIFIERS) skip_tkspace(false) tk = get_tk # Little hack going on here. In the statement # f = 2*(1+yield) # We see the RPAREN as the next token, so we need # to exit early. This still won't catch all cases # (such as "a = yield + 1" end_token = case tk when TkLPAREN, TkfLPAREN TkRPAREN when TkRPAREN return "" else TkNL end nest = 0 loop do puts("Param: #{tk.inspect}, #{@scanner.continue} " + "#{@scanner.lex_state} #{nest}") if $DEBUG case tk when TkSEMICOLON break when TkLBRACE nest += 1 when TkRBRACE # we might have a.each {|i| yield i } unget_tk(tk) if nest.zero? nest -= 1 break if nest <= 0 when TkLPAREN, TkfLPAREN nest += 1 when end_token if end_token == TkRPAREN nest -= 1 break if @scanner.lex_state == EXPR_END and nest <= 0 else break unless @scanner.continue end when method && method.block_params.nil? && TkCOMMENT unget_tk(tk) read_documentation_modifiers(method, modifiers) end tk = get_tk end res = get_tkread.tr("\n", " ").strip res = "" if res == ";" res end # skip the var [in] part of a 'for' statement def skip_for_variable skip_tkspace(false) tk = get_tk skip_tkspace(false) tk = get_tk unget_tk(tk) unless tk.kind_of?(TkIN) end # while, until, and for have an optional def skip_optional_do_after_expression skip_tkspace(false) tk = get_tk case tk when TkLPAREN, TkfLPAREN end_token = TkRPAREN else end_token = TkNL end nest = 0 @scanner.instance_eval{@continue = false} loop do puts("\nWhile: #{tk}, #{@scanner.continue} " + "#{@scanner.lex_state} #{nest}") if $DEBUG case tk when TkSEMICOLON break when TkLPAREN, TkfLPAREN nest += 1 when TkDO break if nest.zero? when end_token if end_token == TkRPAREN nest -= 1 break if @scanner.lex_state == EXPR_END and nest.zero? else break unless @scanner.continue end end tk = get_tk end skip_tkspace(false) if peek_tk.kind_of? TkDO get_tk end end # Return a superclass, which can be either a constant # of an expression def get_class_specification tk = get_tk return "self" if tk.kind_of?(TkSELF) res = "" while tk.kind_of?(TkCOLON2) || tk.kind_of?(TkCOLON3) || tk.kind_of?(TkCONSTANT) res += tk.text tk = get_tk end unget_tk(tk) skip_tkspace(false) get_tkread # empty out read buffer tk = get_tk case tk when TkNL, TkCOMMENT, TkSEMICOLON unget_tk(tk) return res end res += parse_call_parameters(tk) res end def parse_call_parameters(tk) end_token = case tk when TkLPAREN, TkfLPAREN TkRPAREN when TkRPAREN return "" else TkNL end nest = 0 loop do puts("Call param: #{tk}, #{@scanner.continue} " + "#{@scanner.lex_state} #{nest}") if $DEBUG case tk when TkSEMICOLON break when TkLPAREN, TkfLPAREN nest += 1 when end_token if end_token == TkRPAREN nest -= 1 break if @scanner.lex_state == EXPR_END and nest <= 0 else break unless @scanner.continue end when TkCOMMENT unget_tk(tk) break end tk = get_tk end res = get_tkread.tr("\n", " ").strip res = "" if res == ";" res end # Parse a constant, which might be qualified by # one or more class or module names def get_constant res = "" skip_tkspace(false) tk = get_tk while tk.kind_of?(TkCOLON2) || tk.kind_of?(TkCOLON3) || tk.kind_of?(TkCONSTANT) res += tk.text tk = get_tk end # if res.empty? # warn("Unexpected token #{tk} in constant") # end unget_tk(tk) res end # Get a constant that may be surrounded by parens def get_constant_with_optional_parens skip_tkspace(false) nest = 0 while (tk = peek_tk).kind_of?(TkLPAREN) || tk.kind_of?(TkfLPAREN) get_tk skip_tkspace(true) nest += 1 end name = get_constant while nest > 0 skip_tkspace(true) tk = get_tk nest -= 1 if tk.kind_of?(TkRPAREN) end name end # Directives are modifier comments that can appear after class, module, # or method names. For example # # def fred # :yields: a, b # # or # # class SM # :nodoc: # # we return the directive name and any parameters as a two element array def read_directive(allowed) tk = get_tk puts "directive: #{tk.inspect}" if $DEBUG result = nil if tk.kind_of?(TkCOMMENT) if tk.text =~ /\s*:?(\w+):\s*(.*)/ directive = $1.downcase if allowed.include?(directive) result = [directive, $2] end end else unget_tk(tk) end result end def read_documentation_modifiers(context, allow) dir = read_directive(allow) case dir[0] when "notnew", "not_new", "not-new" context.dont_rename_initialize = true when "nodoc" context.document_self = false if dir[1].downcase == "all" context.document_children = false end when "doc" context.document_self = true context.force_documentation = true when "yield", "yields" unless context.params.nil? context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc end context.block_params = dir[1] when "arg", "args" context.params = dir[1] end if dir end # Look for directives in a normal comment block: # # #-- - don't display comment from this point forward # # # This routine modifies it's parameter def look_for_directives_in(context, comment) preprocess = SM::PreProcess.new(@input_file_name, @options.rdoc_include) preprocess.handle(comment) do |directive, param| case directive when "stopdoc" context.stop_doc "" when "startdoc" context.start_doc context.force_documentation = true "" when "enddoc" #context.done_documenting = true #"" throw :enddoc when "main" options = Options.instance options.main_page = param "" when "title" options = Options.instance options.title = param "" when "section" context.set_current_section(param, comment) comment.replace("") # 1.8 doesn't support #clear break else warn "Unrecognized directive '#{directive}'" break end end remove_private_comments(comment) end def remove_private_comments(comment) comment.gsub!(/^#--.*?^#\+\+/m, '') comment.sub!(/^#--.*/m, '') end def get_symbol_or_name tk = get_tk case tk when TkSYMBOL tk.text.sub(/^:/, '') when TkId, TkOp tk.name when TkSTRING tk.text else raise "Name or symbol expected (got #{tk})" end end def parse_alias(context, single, tk, comment) skip_tkspace if (peek_tk.kind_of? TkLPAREN) get_tk skip_tkspace end new_name = get_symbol_or_name @scanner.instance_eval{@lex_state = EXPR_FNAME} skip_tkspace if (peek_tk.kind_of? TkCOMMA) get_tk skip_tkspace end old_name = get_symbol_or_name al = Alias.new(get_tkread, old_name, new_name, comment) read_documentation_modifiers(al, ATTR_MODIFIERS) if al.document_self context.add_alias(al) end end def parse_yield_parameters parse_method_or_yield_parameters end def parse_yield(context, single, tk, method) if method.block_params.nil? get_tkread @scanner.instance_eval{@continue = false} method.block_params = parse_yield_parameters end end def parse_require(context, comment) skip_tkspace_comment tk = get_tk if tk.kind_of? TkLPAREN skip_tkspace_comment tk = get_tk end name = nil case tk when TkSTRING name = tk.text # when TkCONSTANT, TkIDENTIFIER, TkIVAR, TkGVAR # name = tk.name when TkDSTRING warn "Skipping require of dynamic string: #{tk.text}" # else # warn "'require' used as variable" end if name context.add_require(Require.new(name, comment)) else unget_tk(tk) end end def parse_include(context, comment) loop do skip_tkspace_comment name = get_constant_with_optional_parens unless name.empty? context.add_include(Include.new(name, comment)) end return unless peek_tk.kind_of?(TkCOMMA) get_tk end end def get_bool skip_tkspace tk = get_tk case tk when TkTRUE true when TkFALSE, TkNIL false else unget_tk tk true end end def parse_attr(context, single, tk, comment) args = parse_symbol_arg(1) if args.size > 0 name = args[0] rw = "R" skip_tkspace(false) tk = get_tk if tk.kind_of? TkCOMMA rw = "RW" if get_bool else unget_tk tk end att = Attr.new(get_tkread, name, rw, comment) read_documentation_modifiers(att, ATTR_MODIFIERS) if att.document_self context.add_attribute(att) end else warn("'attr' ignored - looks like a variable") end end def parse_visibility(container, single, tk) singleton = (single == SINGLE) vis = case tk.name when "private" then :private when "protected" then :protected when "public" then :public when "private_class_method" singleton = true :private when "public_class_method" singleton = true :public else raise "Invalid visibility: #{tk.name}" end skip_tkspace_comment(false) case peek_tk # Ryan Davis suggested the extension to ignore modifiers, because he # often writes # # protected unless $TESTING # when TkNL, TkUNLESS_MOD, TkIF_MOD # error("Missing argument") if singleton container.ongoing_visibility = vis else args = parse_symbol_arg container.set_visibility_for(args, vis, singleton) end end def parse_attr_accessor(context, single, tk, comment) args = parse_symbol_arg read = get_tkread rw = "?" # If nodoc is given, don't document any of them tmp = CodeObject.new read_documentation_modifiers(tmp, ATTR_MODIFIERS) return unless tmp.document_self case tk.name when "attr_reader" then rw = "R" when "attr_writer" then rw = "W" when "attr_accessor" then rw = "RW" else rw = @options.extra_accessor_flags[tk.name] end for name in args att = Attr.new(get_tkread, name, rw, comment) context.add_attribute(att) end end def skip_tkspace_comment(skip_nl = true) loop do skip_tkspace(skip_nl) return unless peek_tk.kind_of? TkCOMMENT get_tk end end def parse_symbol_arg(no = nil) args = [] skip_tkspace_comment case tk = get_tk when TkLPAREN loop do skip_tkspace_comment if tk1 = parse_symbol_in_arg args.push tk1 break if no and args.size >= no end skip_tkspace_comment case tk2 = get_tk when TkRPAREN break when TkCOMMA else warn("unexpected token: '#{tk2.inspect}'") if $DEBUG break end end else unget_tk tk if tk = parse_symbol_in_arg args.push tk return args if no and args.size >= no end loop do # skip_tkspace_comment(false) skip_tkspace(false) tk1 = get_tk unless tk1.kind_of?(TkCOMMA) unget_tk tk1 break end skip_tkspace_comment if tk = parse_symbol_in_arg args.push tk break if no and args.size >= no end end end args end def parse_symbol_in_arg case tk = get_tk when TkSYMBOL tk.text.sub(/^:/, '') when TkSTRING eval @read[-1] else warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG nil end end end end PK|]8Ye\''rdoc/parsers/parse_simple.rbnu[# Parse a non-source file. We basically take the whole thing # as one big comment. If the first character in the file # is '#', we strip leading pound signs. require "rdoc/code_objects" require "rdoc/markup/simple_markup/preprocess" module RDoc # See rdoc/parsers/parse_c.rb class SimpleParser # prepare to parse a plain file def initialize(top_level, file_name, body, options, stats) preprocess = SM::PreProcess.new(file_name, options.rdoc_include) preprocess.handle(body) do |directive, param| $stderr.puts "Unrecognized directive '#{directive}' in #{file_name}" end @body = body @options = options @top_level = top_level end # Extract the file contents and attach them to the toplevel as a # comment def scan # @body.gsub(/^(\s\n)+/, '') @top_level.comment = remove_private_comments(@body) @top_level end def remove_private_comments(comment) comment.gsub(/^--.*?^\+\+/m, '').sub(/^--.*/m, '') end end end PK|] kU rdoc/parsers/parserfactory.rbnu[require "rdoc/parsers/parse_simple" module RDoc # A parser is simple a class that implements # # #initialize(file_name, body, options) # # and # # #scan # # The initialize method takes a file name to be used, the body of the # file, and an RDoc::Options object. The scan method is then called # to return an appropriately parsed TopLevel code object. # # The ParseFactory is used to redirect to the correct parser given a filename # extension. This magic works because individual parsers have to register # themselves with us as they are loaded in. The do this using the following # incantation # # # require "rdoc/parsers/parsefactory" # # module RDoc # # class XyzParser # extend ParseFactory <<<< # parse_files_matching /\.xyz$/ <<<< # # def initialize(file_name, body, options) # ... # end # # def scan # ... # end # end # end # # Just to make life interesting, if we suspect a plain text file, we # also look for a shebang line just in case it's a potential # shell script module ParserFactory @@parsers = [] Parsers = Struct.new(:regexp, :parser) # Record the fact that a particular class parses files that # match a given extension def parse_files_matching(regexp) @@parsers.unshift Parsers.new(regexp, self) end # Return a parser that can handle a particular extension def ParserFactory.can_parse(file_name) @@parsers.find {|p| p.regexp.match(file_name) } end # Alias an extension to another extension. After this call, # files ending "new_ext" will be parsed using the same parser # as "old_ext" def ParserFactory.alias_extension(old_ext, new_ext) parser = ParserFactory.can_parse("xxx.#{old_ext}") return false unless parser @@parsers.unshift Parsers.new(Regexp.new("\\.#{new_ext}$"), parser.parser) true end # Find the correct parser for a particular file name. Return a # SimpleParser for ones that we don't know def ParserFactory.parser_for(top_level, file_name, body, options, stats) # If no extension, look for shebang if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)} shebang = $1 case shebang when %r{env\s+ruby}, %r{/ruby} file_name = "dummy.rb" end end parser_description = can_parse(file_name) if parser_description parser = parser_description.parser else parser = SimpleParser end parser.new(top_level, file_name, body, options, stats) end end end PK|]Grdoc/parsers/parse_f95.rbnu[#= parse_f95.rb - Fortran95 Parser # #== Overview # #"parse_f95.rb" parses Fortran95 files with suffixes "f90", "F90", "f95" #and "F95". Fortran95 files are expected to be conformed to Fortran95 #standards. # #== Rules # #Fundamental rules are same as that of the Ruby parser. #But comment markers are '!' not '#'. # #=== Correspondence between RDoc documentation and Fortran95 programs # #"parse_f95.rb" parses main programs, modules, subroutines, functions, #derived-types, public variables, public constants, #defined operators and defined assignments. #These components are described in items of RDoc documentation, as follows. # #Files :: Files (same as Ruby) #Classes :: Modules #Methods :: Subroutines, functions, variables, constants, derived-types, defined operators, defined assignments #Required files :: Files in which imported modules, external subroutines and external functions are defined. #Included Modules :: List of imported modules #Attributes :: List of derived-types, List of imported modules all of whose components are published again # #Components listed in 'Methods' (subroutines, functions, ...) #defined in modules are described in the item of 'Classes'. #On the other hand, components defined in main programs or #as external procedures are described in the item of 'Files'. # #=== Components parsed by default # #By default, documentation on public components (subroutines, functions, #variables, constants, derived-types, defined operators, #defined assignments) are generated. #With "--all" option, documentation on all components #are generated (almost same as the Ruby parser). # #=== Information parsed automatically # #The following information is automatically parsed. # #* Types of arguments #* Types of variables and constants #* Types of variables in the derived types, and initial values #* NAMELISTs and types of variables in them, and initial values # #Aliases by interface statement are described in the item of 'Methods'. # #Components which are imported from other modules and published again #are described in the item of 'Methods'. # #=== Format of comment blocks # #Comment blocks should be written as follows. #Comment blocks are considered to be ended when the line without '!' #appears. #The indentation is not necessary. # # ! (Top of file) # ! # ! Comment blocks for the files. # ! # !-- # ! The comment described in the part enclosed by # ! "!--" and "!++" is ignored. # !++ # ! # module hogehoge # ! # ! Comment blocks for the modules (or the programs). # ! # # private # # logical :: a ! a private variable # real, public :: b ! a public variable # integer, parameter :: c = 0 ! a public constant # # public :: c # public :: MULTI_ARRAY # public :: hoge, foo # # type MULTI_ARRAY # ! # ! Comment blocks for the derived-types. # ! # real, pointer :: var(:) =>null() ! Comments block for the variables. # integer :: num = 0 # end type MULTI_ARRAY # # contains # # subroutine hoge( in, & ! Comment blocks between continuation lines are ignored. # & out ) # ! # ! Comment blocks for the subroutines or functions # ! # character(*),intent(in):: in ! Comment blocks for the arguments. # character(*),intent(out),allocatable,target :: in # ! Comment blocks can be # ! written under Fortran statements. # # character(32) :: file ! This comment parsed as a variable in below NAMELIST. # integer :: id # # namelist /varinfo_nml/ file, id # ! # ! Comment blocks for the NAMELISTs. # ! Information about variables are described above. # ! # # .... # # end subroutine hoge # # integer function foo( in ) # ! # ! This part is considered as comment block. # # ! Comment blocks under blank lines are ignored. # ! # integer, intent(in):: inA ! This part is considered as comment block. # # ! This part is ignored. # # end function foo # # subroutine hide( in, & # & out ) !:nodoc: # ! # ! If "!:nodoc:" is described at end-of-line in subroutine # ! statement as above, the subroutine is ignored. # ! This assignment can be used to modules, subroutines, # ! functions, variables, constants, derived-types, # ! defined operators, defined assignments, # ! list of imported modules ("use" statement). # ! # # .... # # end subroutine hide # # end module hogehoge # require "rdoc/code_objects" module RDoc class Token NO_TEXT = "??".freeze def initialize(line_no, char_no) @line_no = line_no @char_no = char_no @text = NO_TEXT end # Because we're used in contexts that expect to return a token, # we set the text string and then return ourselves def set_text(text) @text = text self end attr_reader :line_no, :char_no, :text end # See rdoc/parsers/parse_f95.rb class Fortran95parser extend ParserFactory parse_files_matching(/\.((f|F)9(0|5)|F)$/) @@external_aliases = [] @@public_methods = [] # "false":: Comments are below source code # "true" :: Comments are upper source code COMMENTS_ARE_UPPER = false # Internal alias message INTERNAL_ALIAS_MES = "Alias for" # External alias message EXTERNAL_ALIAS_MES = "The entity is" # prepare to parse a Fortran 95 file def initialize(top_level, file_name, body, options, stats) @body = body @stats = stats @file_name = file_name @options = options @top_level = top_level @progress = $stderr unless options.quiet end # define code constructs def scan # remove private comment remaining_code = remove_private_comments(@body) # continuation lines are united to one line remaining_code = united_to_one_line(remaining_code) # semicolons are replaced to line feed remaining_code = semicolon_to_linefeed(remaining_code) # collect comment for file entity whole_comment, remaining_code = collect_first_comment(remaining_code) @top_level.comment = whole_comment # String "remaining_code" is converted to Array "remaining_lines" remaining_lines = remaining_code.split("\n") # "module" or "program" parts are parsed (new) # level_depth = 0 block_searching_flag = nil block_searching_lines = [] pre_comment = [] module_program_trailing = "" module_program_name = "" other_block_level_depth = 0 other_block_searching_flag = nil remaining_lines.collect!{|line| if !block_searching_flag && !other_block_searching_flag if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i block_searching_flag = :module block_searching_lines << line module_program_name = $1 module_program_trailing = find_comments($2) next false elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || line =~ /^\s*?\w/ && !block_start?(line) block_searching_flag = :program block_searching_lines << line module_program_name = $1 || "" module_program_trailing = find_comments($2) next false elsif block_start?(line) other_block_searching_flag = true next line elsif line =~ /^\s*?!\s?(.*)/ pre_comment << line next line else pre_comment = [] next line end elsif other_block_searching_flag other_block_level_depth += 1 if block_start?(line) other_block_level_depth -= 1 if block_end?(line) if other_block_level_depth < 0 other_block_level_depth = 0 other_block_searching_flag = nil end next line end block_searching_lines << line level_depth += 1 if block_start?(line) level_depth -= 1 if block_end?(line) if level_depth >= 0 next false end # "module_program_code" is formatted. # ":nodoc:" flag is checked. # module_program_code = block_searching_lines.join("\n") module_program_code = remove_empty_head_lines(module_program_code) if module_program_trailing =~ /^:nodoc:/ # next loop to search next block level_depth = 0 block_searching_flag = false block_searching_lines = [] pre_comment = [] next false end # NormalClass is created, and added to @top_level # if block_searching_flag == :module module_name = module_program_name module_code = module_program_code module_trailing = module_program_trailing progress "m" @stats.num_modules += 1 f9x_module = @top_level.add_module NormalClass, module_name f9x_module.record_location @top_level f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + "\n" + module_trailing : module_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, '')) f9x_module.comment = f9x_comment parse_program_or_module(f9x_module, module_code) TopLevel.all_files.each do |name, toplevel| if toplevel.include_includes?(module_name, @options.ignore_case) if !toplevel.include_requires?(@file_name, @options.ignore_case) toplevel.add_require(Require.new(@file_name, "")) end end toplevel.each_classmodule{|m| if m.include_includes?(module_name, @options.ignore_case) if !m.include_requires?(@file_name, @options.ignore_case) m.add_require(Require.new(@file_name, "")) end end } end elsif block_searching_flag == :program program_name = module_program_name program_code = module_program_code program_trailing = module_program_trailing progress "p" program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + "\n" + program_trailing : program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, '')) program_comment = "\n\n= Program #{program_name}\n\n" \ + program_comment @top_level.comment << program_comment parse_program_or_module(@top_level, program_code, :private) end # next loop to search next block level_depth = 0 block_searching_flag = false block_searching_lines = [] pre_comment = [] next false } remaining_lines.delete_if{ |line| line == false } # External subprograms and functions are parsed # parse_program_or_module(@top_level, remaining_lines.join("\n"), :public, true) @top_level end # End of scan private def parse_program_or_module(container, code, visibility=:public, external=nil) return unless container return unless code remaining_lines = code.split("\n") remaining_code = "#{code}" # # Parse variables before "contains" in module # level_depth = 0 before_contains_lines = [] before_contains_code = nil before_contains_flag = nil remaining_lines.each{ |line| if !before_contains_flag if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i before_contains_flag = true end else break if line =~ /^\s*?contains\s*?(!.*?)?$/i level_depth += 1 if block_start?(line) level_depth -= 1 if block_end?(line) break if level_depth < 0 before_contains_lines << line end } before_contains_code = before_contains_lines.join("\n") if before_contains_code before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "") before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") end # # Parse global "use" # use_check_code = "#{before_contains_code}" cascaded_modules_list = [] while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i use_check_code = $~.pre_match use_check_code << $~.post_match used_mod_name = $1.strip.chomp used_list = $2 || "" used_trailing = $3 || "" next if used_trailing =~ /!:nodoc:/ if !container.include_includes?(used_mod_name, @options.ignore_case) progress "." container.add_include Include.new(used_mod_name, "") end if ! (used_list =~ /\,\s*?only\s*?:/i ) cascaded_modules_list << "\#" + used_mod_name end end # # Parse public and private, and store information. # This information is used when "add_method" and # "set_visibility_for" are called. # visibility_default, visibility_info = parse_visibility(remaining_lines.join("\n"), visibility, container) @@public_methods.concat visibility_info if visibility_default == :public if !cascaded_modules_list.empty? cascaded_modules = Attr.new("Cascaded Modules", "Imported modules all of whose components are published again", "", cascaded_modules_list.join(", ")) container.add_attribute(cascaded_modules) end end # # Check rename elements # use_check_code = "#{before_contains_code}" while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i use_check_code = $~.pre_match use_check_code << $~.post_match used_mod_name = $1.strip.chomp used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '') used_elements.split(",").each{ |used| if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used local = $1 org = $2 @@public_methods.collect!{ |pub_meth| if local == pub_meth["name"] || local.upcase == pub_meth["name"].upcase && @options.ignore_case pub_meth["name"] = org pub_meth["local_name"] = local end pub_meth } end } end # # Parse private "use" # use_check_code = remaining_lines.join("\n") while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i use_check_code = $~.pre_match use_check_code << $~.post_match used_mod_name = $1.strip.chomp used_trailing = $3 || "" next if used_trailing =~ /!:nodoc:/ if !container.include_includes?(used_mod_name, @options.ignore_case) progress "." container.add_include Include.new(used_mod_name, "") end end container.each_includes{ |inc| TopLevel.all_files.each do |name, toplevel| indicated_mod = toplevel.find_symbol(inc.name, nil, @options.ignore_case) if indicated_mod indicated_name = indicated_mod.parent.file_relative_name if !container.include_requires?(indicated_name, @options.ignore_case) container.add_require(Require.new(indicated_name, "")) end break end end } # # Parse derived-types definitions # derived_types_comment = "" remaining_code = remaining_lines.join("\n") while remaining_code =~ /^\s*? type[\s\,]+(public|private)?\s*?(::)?\s*? (\w+)\s*?(!.*?)?$ (.*?) ^\s*?end\s+type.*?$ /imx remaining_code = $~.pre_match remaining_code << $~.post_match typename = $3.chomp.strip type_elements = $5 || "" type_code = remove_empty_head_lines($&) type_trailing = find_comments($4) next if type_trailing =~ /^:nodoc:/ type_visibility = $1 type_comment = COMMENTS_ARE_UPPER ? find_comments($~.pre_match) + "\n" + type_trailing : type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, '')) type_element_visibility_public = true type_code.split("\n").each{ |line| if /^\s*?private\s*?$/ =~ line type_element_visibility_public = nil break end } if type_code args_comment = "" type_args_info = nil if @options.show_all args_comment = find_arguments(nil, type_code, true) else type_public_args_list = [] type_args_info = definition_info(type_code) type_args_info.each{ |arg| arg_is_public = type_element_visibility_public arg_is_public = true if arg.include_attr?("public") arg_is_public = nil if arg.include_attr?("private") type_public_args_list << arg.varname if arg_is_public } args_comment = find_arguments(type_public_args_list, type_code) end type = AnyMethod.new("type #{typename}", typename) type.singleton = false type.params = "" type.comment = " Derived Type :: \n" type.comment << args_comment if args_comment type.comment << type_comment if type_comment progress "t" @stats.num_methods += 1 container.add_method type set_visibility(container, typename, visibility_default, @@public_methods) if type_visibility type_visibility.gsub!(/\s/,'') type_visibility.gsub!(/\,/,'') type_visibility.gsub!(/:/,'') type_visibility.downcase! if type_visibility == "public" container.set_visibility_for([typename], :public) elsif type_visibility == "private" container.set_visibility_for([typename], :private) end end check_public_methods(type, container.name) if @options.show_all derived_types_comment << ", " unless derived_types_comment.empty? derived_types_comment << typename else if type.visibility == :public derived_types_comment << ", " unless derived_types_comment.empty? derived_types_comment << typename end end end if !derived_types_comment.empty? derived_types_table = Attr.new("Derived Types", "Derived_Types", "", derived_types_comment) container.add_attribute(derived_types_table) end # # move interface scope # interface_code = "" while remaining_code =~ /^\s*? interface( \s+\w+ | \s+operator\s*?\(.*?\) | \s+assignment\s*?\(\s*?=\s*?\) )?\s*?$ (.*?) ^\s*?end\s+interface.*?$ /imx interface_code << remove_empty_head_lines($&) + "\n" remaining_code = $~.pre_match remaining_code << $~.post_match end # # Parse global constants or variables in modules # const_var_defs = definition_info(before_contains_code) const_var_defs.each{|defitem| next if defitem.nodoc const_or_var_type = "Variable" const_or_var_progress = "v" if defitem.include_attr?("parameter") const_or_var_type = "Constant" const_or_var_progress = "c" end const_or_var = AnyMethod.new(const_or_var_type, defitem.varname) const_or_var.singleton = false const_or_var.params = "" self_comment = find_arguments([defitem.varname], before_contains_code) const_or_var.comment = "" + const_or_var_type + " :: \n" const_or_var.comment << self_comment if self_comment progress const_or_var_progress @stats.num_methods += 1 container.add_method const_or_var set_visibility(container, defitem.varname, visibility_default, @@public_methods) if defitem.include_attr?("public") container.set_visibility_for([defitem.varname], :public) elsif defitem.include_attr?("private") container.set_visibility_for([defitem.varname], :private) end check_public_methods(const_or_var, container.name) } if const_var_defs remaining_lines = remaining_code.split("\n") # "subroutine" or "function" parts are parsed (new) # level_depth = 0 block_searching_flag = nil block_searching_lines = [] pre_comment = [] procedure_trailing = "" procedure_name = "" procedure_params = "" procedure_prefix = "" procedure_result_arg = "" procedure_type = "" contains_lines = [] contains_flag = nil remaining_lines.collect!{|line| if !block_searching_flag # subroutine if line =~ /^\s*? (recursive|pure|elemental)?\s*? subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ /ix block_searching_flag = :subroutine block_searching_lines << line procedure_name = $2.chomp.strip procedure_params = $3 || "" procedure_prefix = $1 || "" procedure_trailing = $4 || "!" next false # function elsif line =~ /^\s*? (recursive|pure|elemental)?\s*? ( character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | type\s*?\([\w\s]+?\)\s+ | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | double\s+precision\s+ | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ )? function\s+(\w+)\s*? (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ /ix block_searching_flag = :function block_searching_lines << line procedure_prefix = $1 || "" procedure_type = $2 ? $2.chomp.strip : nil procedure_name = $8.chomp.strip procedure_params = $9 || "" procedure_result_arg = $11 ? $11.chomp.strip : procedure_name procedure_trailing = $12 || "!" next false elsif line =~ /^\s*?!\s?(.*)/ pre_comment << line next line else pre_comment = [] next line end end contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/ block_searching_lines << line contains_lines << line if contains_flag level_depth += 1 if block_start?(line) level_depth -= 1 if block_end?(line) if level_depth >= 0 next false end # "procedure_code" is formatted. # ":nodoc:" flag is checked. # procedure_code = block_searching_lines.join("\n") procedure_code = remove_empty_head_lines(procedure_code) if procedure_trailing =~ /^!:nodoc:/ # next loop to search next block level_depth = 0 block_searching_flag = nil block_searching_lines = [] pre_comment = [] procedure_trailing = "" procedure_name = "" procedure_params = "" procedure_prefix = "" procedure_result_arg = "" procedure_type = "" contains_lines = [] contains_flag = nil next false end # AnyMethod is created, and added to container # subroutine_function = nil if block_searching_flag == :subroutine subroutine_prefix = procedure_prefix subroutine_name = procedure_name subroutine_params = procedure_params subroutine_trailing = procedure_trailing subroutine_code = procedure_code subroutine_comment = COMMENTS_ARE_UPPER ? pre_comment.join("\n") + "\n" + subroutine_trailing : subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '') subroutine = AnyMethod.new("subroutine", subroutine_name) parse_subprogram(subroutine, subroutine_params, subroutine_comment, subroutine_code, before_contains_code, nil, subroutine_prefix) progress "s" @stats.num_methods += 1 container.add_method subroutine subroutine_function = subroutine elsif block_searching_flag == :function function_prefix = procedure_prefix function_type = procedure_type function_name = procedure_name function_params_org = procedure_params function_result_arg = procedure_result_arg function_trailing = procedure_trailing function_code_org = procedure_code function_comment = COMMENTS_ARE_UPPER ? pre_comment.join("\n") + "\n" + function_trailing : function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '') function_code = "#{function_code_org}" if function_type function_code << "\n" + function_type + " :: " + function_result_arg end function_params = function_params_org.sub(/^\(/, "\(#{function_result_arg}, ") function = AnyMethod.new("function", function_name) parse_subprogram(function, function_params, function_comment, function_code, before_contains_code, true, function_prefix) # Specific modification due to function function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ") function.params << " result(" + function_result_arg + ")" function.start_collecting_tokens function.add_token Token.new(1,1).set_text(function_code_org) progress "f" @stats.num_methods += 1 container.add_method function subroutine_function = function end # The visibility of procedure is specified # set_visibility(container, procedure_name, visibility_default, @@public_methods) # The alias for this procedure from external modules # check_external_aliases(procedure_name, subroutine_function.params, subroutine_function.comment, subroutine_function) if external check_public_methods(subroutine_function, container.name) # contains_lines are parsed as private procedures if contains_flag parse_program_or_module(container, contains_lines.join("\n"), :private) end # next loop to search next block level_depth = 0 block_searching_flag = nil block_searching_lines = [] pre_comment = [] procedure_trailing = "" procedure_name = "" procedure_params = "" procedure_prefix = "" procedure_result_arg = "" contains_lines = [] contains_flag = nil next false } # End of remaining_lines.collect!{|line| # Array remains_lines is converted to String remains_code again # remaining_code = remaining_lines.join("\n") # # Parse interface # interface_scope = false generic_name = "" interface_code.split("\n").each{ |line| if /^\s*? interface( \s+\w+| \s+operator\s*?\(.*?\)| \s+assignment\s*?\(\s*?=\s*?\) )? \s*?(!.*?)?$ /ix =~ line generic_name = $1 ? $1.strip.chomp : nil interface_trailing = $2 || "!" interface_scope = true interface_scope = false if interface_trailing =~ /!:nodoc:/ # if generic_name =~ /operator\s*?\((.*?)\)/i # operator_name = $1 # if operator_name && !operator_name.empty? # generic_name = "#{operator_name}" # end # end # if generic_name =~ /assignment\s*?\((.*?)\)/i # assignment_name = $1 # if assignment_name && !assignment_name.empty? # generic_name = "#{assignment_name}" # end # end end if /^\s*?end\s+interface/i =~ line interface_scope = false generic_name = nil end # internal alias if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line procedures = $1.strip.chomp procedures_trailing = $2 || "!" next if procedures_trailing =~ /!:nodoc:/ procedures.split(",").each{ |proc| proc.strip! proc.chomp! next if generic_name == proc || !generic_name old_meth = container.find_symbol(proc, nil, @options.ignore_case) next if !old_meth nolink = old_meth.visibility == :private ? true : nil nolink = nil if @options.show_all new_meth = initialize_external_method(generic_name, proc, old_meth.params, nil, old_meth.comment, old_meth.clone.token_stream[0].text, true, nolink) new_meth.singleton = old_meth.singleton progress "i" @stats.num_methods += 1 container.add_method new_meth set_visibility(container, generic_name, visibility_default, @@public_methods) check_public_methods(new_meth, container.name) } end # external aliases if interface_scope # subroutine proc = nil params = nil procedures_trailing = nil if line =~ /^\s*? (recursive|pure|elemental)?\s*? subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ /ix proc = $2.chomp.strip generic_name = proc unless generic_name params = $3 || "" procedures_trailing = $4 || "!" # function elsif line =~ /^\s*? (recursive|pure|elemental)?\s*? ( character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | type\s*?\([\w\s]+?\)\s+ | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | double\s+precision\s+ | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ )? function\s+(\w+)\s*? (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ /ix proc = $8.chomp.strip generic_name = proc unless generic_name params = $9 || "" procedures_trailing = $12 || "!" else next end next if procedures_trailing =~ /!:nodoc:/ indicated_method = nil indicated_file = nil TopLevel.all_files.each do |name, toplevel| indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case) indicated_file = name break if indicated_method end if indicated_method external_method = initialize_external_method(generic_name, proc, indicated_method.params, indicated_file, indicated_method.comment) progress "e" @stats.num_methods += 1 container.add_method external_method set_visibility(container, generic_name, visibility_default, @@public_methods) if !container.include_requires?(indicated_file, @options.ignore_case) container.add_require(Require.new(indicated_file, "")) end check_public_methods(external_method, container.name) else @@external_aliases << { "new_name" => generic_name, "old_name" => proc, "file_or_module" => container, "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default } end end } if interface_code # End of interface_code.split("\n").each ... # # Already imported methods are removed from @@public_methods. # Remainders are assumed to be imported from other modules. # @@public_methods.delete_if{ |method| method["entity_is_discovered"]} @@public_methods.each{ |pub_meth| next unless pub_meth["file_or_module"].name == container.name pub_meth["used_modules"].each{ |used_mod| TopLevel.all_classes_and_modules.each{ |modules| if modules.name == used_mod || modules.name.upcase == used_mod.upcase && @options.ignore_case modules.method_list.each{ |meth| if meth.name == pub_meth["name"] || meth.name.upcase == pub_meth["name"].upcase && @options.ignore_case new_meth = initialize_public_method(meth, modules.name) if pub_meth["local_name"] new_meth.name = pub_meth["local_name"] end progress "e" @stats.num_methods += 1 container.add_method new_meth end } end } } } container end # End of parse_program_or_module # # Parse arguments, comment, code of subroutine and function. # Return AnyMethod object. # def parse_subprogram(subprogram, params, comment, code, before_contains=nil, function=nil, prefix=nil) subprogram.singleton = false prefix = "" if !prefix arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params args_comment, params_opt = find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""), nil, nil, true) params_opt = "( " + params_opt + " ) " if params_opt subprogram.params = params_opt || "" namelist_comment = find_namelists(code, before_contains) block_comment = find_comments comment if function subprogram.comment = " Function :: #{prefix}\n" else subprogram.comment = " Subroutine :: #{prefix}\n" end subprogram.comment << args_comment if args_comment subprogram.comment << block_comment if block_comment subprogram.comment << namelist_comment if namelist_comment # For output source code subprogram.start_collecting_tokens subprogram.add_token Token.new(1,1).set_text(code) subprogram end # # Collect comment for file entity # def collect_first_comment(body) comment = "" not_comment = "" comment_start = false comment_end = false body.split("\n").each{ |line| if comment_end not_comment << line not_comment << "\n" elsif /^\s*?!\s?(.*)$/i =~ line comment_start = true comment << $1 comment << "\n" elsif /^\s*?$/i =~ line comment_end = true if comment_start && COMMENTS_ARE_UPPER else comment_end = true not_comment << line not_comment << "\n" end } return comment, not_comment end # Return comments of definitions of arguments # # If "all" argument is true, information of all arguments are returned. # If "modified_params" is true, list of arguments are decorated, # for example, optional arguments are parenthetic as "[arg]". # def find_arguments(args, text, all=nil, indent=nil, modified_params=nil) return unless args || all indent = "" unless indent args = ["all"] if all params = "" if modified_params comma = "" return unless text args_rdocforms = "\n" remaining_lines = "#{text}" definitions = definition_info(remaining_lines) args.each{ |arg| arg.strip! arg.chomp! definitions.each { |defitem| if arg == defitem.varname.strip.chomp || all args_rdocforms << <<-"EOF" #{indent}#{defitem.varname.chomp.strip}#{defitem.arraysuffix} #{defitem.inivalue} :: #{indent} #{defitem.types.chomp.strip} EOF if !defitem.comment.chomp.strip.empty? comment = "" defitem.comment.split("\n").each{ |line| comment << " " + line + "\n" } args_rdocforms << <<-"EOF" #{indent} :: #{indent} #{indent} #{comment.chomp.strip} EOF end if modified_params if defitem.include_attr?("optional") params << "#{comma}[#{arg}]" else params << "#{comma}#{arg}" end comma = ", " end end } } if modified_params return args_rdocforms, params else return args_rdocforms end end # Return comments of definitions of namelists # def find_namelists(text, before_contains=nil) return nil if !text result = "" lines = "#{text}" before_contains = "" if !before_contains while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i lines = $~.post_match nml_comment = COMMENTS_ARE_UPPER ? find_comments($~.pre_match) : find_comments($~.post_match) nml_name = $1 nml_args = $2.split(",") result << "\n\n=== NAMELIST " + nml_name + "\n\n" result << nml_comment + "\n" if nml_comment if lines.split("\n")[0] =~ /^\//i lines = "namelist " + lines end result << find_arguments(nml_args, "#{text}" + "\n" + before_contains) end return result end # # Comments just after module or subprogram, or arguments are # returned. If "COMMENTS_ARE_UPPER" is true, comments just before # modules or subprograms are returned # def find_comments text return "" unless text lines = text.split("\n") lines.reverse! if COMMENTS_ARE_UPPER comment_block = Array.new lines.each do |line| break if line =~ /^\s*?\w/ || line =~ /^\s*?$/ if COMMENTS_ARE_UPPER comment_block.unshift line.sub(/^\s*?!\s?/,"") else comment_block.push line.sub(/^\s*?!\s?/,"") end end nice_lines = comment_block.join("\n").split "\n\s*?\n" nice_lines[0] ||= "" nice_lines.shift end def progress(char) unless @options.quiet @progress.print(char) @progress.flush end end # # Create method for internal alias # def initialize_public_method(method, parent) return if !method || !parent new_meth = AnyMethod.new("External Alias for module", method.name) new_meth.singleton = method.singleton new_meth.params = method.params.clone new_meth.comment = remove_trailing_alias(method.comment.clone) new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}" return new_meth end # # Create method for external alias # # If argument "internal" is true, file is ignored. # def initialize_external_method(new, old, params, file, comment, token=nil, internal=nil, nolink=nil) return nil unless new || old if internal external_alias_header = "#{INTERNAL_ALIAS_MES} " external_alias_text = external_alias_header + old elsif file external_alias_header = "#{EXTERNAL_ALIAS_MES} " external_alias_text = external_alias_header + file + "#" + old else return nil end external_meth = AnyMethod.new(external_alias_text, new) external_meth.singleton = false external_meth.params = params external_comment = remove_trailing_alias(comment) + "\n\n" if comment external_meth.comment = external_comment || "" if nolink && token external_meth.start_collecting_tokens external_meth.add_token Token.new(1,1).set_text(token) else external_meth.comment << external_alias_text end return external_meth end # # Parse visibility # def parse_visibility(code, default, container) result = [] visibility_default = default || :public used_modules = [] container.includes.each{|i| used_modules << i.name} if container remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") remaining_code.split("\n").each{ |line| if /^\s*?private\s*?$/ =~ line visibility_default = :private break end } if remaining_code remaining_code.split("\n").each{ |line| if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line methods = $2.sub(/!.*$/, '') methods.split(",").each{ |meth| meth.sub!(/!.*$/, '') meth.gsub!(/:/, '') result << { "name" => meth.chomp.strip, "visibility" => :private, "used_modules" => used_modules.clone, "file_or_module" => container, "entity_is_discovered" => nil, "local_name" => nil } } elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line methods = $2.sub(/!.*$/, '') methods.split(",").each{ |meth| meth.sub!(/!.*$/, '') meth.gsub!(/:/, '') result << { "name" => meth.chomp.strip, "visibility" => :public, "used_modules" => used_modules.clone, "file_or_module" => container, "entity_is_discovered" => nil, "local_name" => nil } } end } if remaining_code if container result.each{ |vis_info| vis_info["parent"] = container.name } end return visibility_default, result end # # Set visibility # # "subname" element of "visibility_info" is deleted. # def set_visibility(container, subname, visibility_default, visibility_info) return unless container || subname || visibility_default || visibility_info not_found = true visibility_info.collect!{ |info| if info["name"] == subname || @options.ignore_case && info["name"].upcase == subname.upcase if info["file_or_module"].name == container.name container.set_visibility_for([subname], info["visibility"]) info["entity_is_discovered"] = true not_found = false end end info } if not_found return container.set_visibility_for([subname], visibility_default) else return container end end # # Find visibility # def find_visibility(container, subname, visibility_info) return nil if !subname || !visibility_info visibility_info.each{ |info| if info["name"] == subname || @options.ignore_case && info["name"].upcase == subname.upcase if info["parent"] == container.name return info["visibility"] end end } return nil end # # Check external aliases # def check_external_aliases(subname, params, comment, test=nil) @@external_aliases.each{ |alias_item| if subname == alias_item["old_name"] || subname.upcase == alias_item["old_name"].upcase && @options.ignore_case new_meth = initialize_external_method(alias_item["new_name"], subname, params, @file_name, comment) new_meth.visibility = alias_item["visibility"] progress "e" @stats.num_methods += 1 alias_item["file_or_module"].add_method(new_meth) if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case) alias_item["file_or_module"].add_require(Require.new(@file_name, "")) end end } end # # Check public_methods # def check_public_methods(method, parent) return if !method || !parent @@public_methods.each{ |alias_item| parent_is_used_module = nil alias_item["used_modules"].each{ |used_module| if used_module == parent || used_module.upcase == parent.upcase && @options.ignore_case parent_is_used_module = true end } next if !parent_is_used_module if method.name == alias_item["name"] || method.name.upcase == alias_item["name"].upcase && @options.ignore_case new_meth = initialize_public_method(method, parent) if alias_item["local_name"] new_meth.name = alias_item["local_name"] end progress "e" @stats.num_methods += 1 alias_item["file_or_module"].add_method new_meth end } end # # Continuous lines are united. # # Comments in continuous lines are removed. # def united_to_one_line(f90src) return "" unless f90src lines = f90src.split("\n") previous_continuing = false now_continuing = false body = "" lines.each{ |line| words = line.split("") next if words.empty? && previous_continuing commentout = false brank_flag = true ; brank_char = "" squote = false ; dquote = false ignore = false words.collect! { |char| if previous_continuing && brank_flag now_continuing = true ignore = true case char when "!" ; break when " " ; brank_char << char ; next "" when "&" brank_flag = false now_continuing = false next "" else brank_flag = false now_continuing = false ignore = false next brank_char + char end end ignore = false if now_continuing next "" elsif !(squote) && !(dquote) && !(commentout) case char when "!" ; commentout = true ; next char when "\""; dquote = true ; next char when "\'"; squote = true ; next char when "&" ; now_continuing = true ; next "" else next char end elsif commentout next char elsif squote case char when "\'"; squote = false ; next char else next char end elsif dquote case char when "\""; dquote = false ; next char else next char end end } if !ignore && !previous_continuing || !brank_flag if previous_continuing body << words.join("") else body << "\n" + words.join("") end end previous_continuing = now_continuing ? true : nil now_continuing = nil } return body end # # Continuous line checker # def continuous_line?(line) continuous = false if /&\s*?(!.*)?$/ =~ line continuous = true if comment_out?($~.pre_match) continuous = false end end return continuous end # # Comment out checker # def comment_out?(line) return nil unless line commentout = false squote = false ; dquote = false line.split("").each { |char| if !(squote) && !(dquote) case char when "!" ; commentout = true ; break when "\""; dquote = true when "\'"; squote = true else next end elsif squote case char when "\'"; squote = false else next end elsif dquote case char when "\""; dquote = false else next end end } return commentout end # # Semicolons are replaced to line feed. # def semicolon_to_linefeed(text) return "" unless text lines = text.split("\n") lines.collect!{ |line| words = line.split("") commentout = false squote = false ; dquote = false words.collect! { |char| if !(squote) && !(dquote) && !(commentout) case char when "!" ; commentout = true ; next char when "\""; dquote = true ; next char when "\'"; squote = true ; next char when ";" ; "\n" else next char end elsif commentout next char elsif squote case char when "\'"; squote = false ; next char else next char end elsif dquote case char when "\""; dquote = false ; next char else next char end end } words.join("") } return lines.join("\n") end # # Which "line" is start of block (module, program, block data, # subroutine, function) statement ? # def block_start?(line) return nil if !line if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i || line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i || line =~ \ /^\s*? (recursive|pure|elemental)?\s*? subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ /ix || line =~ \ /^\s*? (recursive|pure|elemental)?\s*? ( character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | type\s*?\([\w\s]+?\)\s+ | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | double\s+precision\s+ | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ )? function\s+(\w+)\s*? (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ /ix return true end return nil end # # Which "line" is end of block (module, program, block data, # subroutine, function) statement ? # def block_end?(line) return nil if !line if line =~ /^\s*?end\s*?(!.*?)?$/i || line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i || line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i || line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i || line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i || line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i return true end return nil end # # Remove "Alias for" in end of comments # def remove_trailing_alias(text) return "" if !text lines = text.split("\n").reverse comment_block = Array.new checked = false lines.each do |line| if !checked if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line || /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line checked = true next end end comment_block.unshift line end nice_lines = comment_block.join("\n") nice_lines ||= "" return nice_lines end # Empty lines in header are removed def remove_empty_head_lines(text) return "" unless text lines = text.split("\n") header = true lines.delete_if{ |line| header = false if /\S/ =~ line header && /^\s*?$/ =~ line } lines.join("\n") end # header marker "=", "==", ... are removed def remove_header_marker(text) return text.gsub(/^\s?(=+)/, '\1') end def remove_private_comments(body) body.gsub!(/^\s*!--\s*?$.*?^\s*!\+\+\s*?$/m, '') return body end # # Information of arguments of subroutines and functions in Fortran95 # class Fortran95Definition # Name of variable # attr_reader :varname # Types of variable # attr_reader :types # Initial Value # attr_reader :inivalue # Suffix of array # attr_reader :arraysuffix # Comments # attr_accessor :comment # Flag of non documentation # attr_accessor :nodoc def initialize(varname, types, inivalue, arraysuffix, comment, nodoc=false) @varname = varname @types = types @inivalue = inivalue @arraysuffix = arraysuffix @comment = comment @nodoc = nodoc end def to_s return <<-EOF EOF end # # If attr is included, true is returned # def include_attr?(attr) return if !attr @types.split(",").each{ |type| return true if type.strip.chomp.upcase == attr.strip.chomp.upcase } return nil end end # End of Fortran95Definition # # Parse string argument "text", and Return Array of # Fortran95Definition object # def definition_info(text) return nil unless text lines = "#{text}" defs = Array.new comment = "" trailing_comment = "" under_comment_valid = false lines.split("\n").each{ |line| if /^\s*?!\s?(.*)/ =~ line if COMMENTS_ARE_UPPER comment << remove_header_marker($1) comment << "\n" elsif defs[-1] && under_comment_valid defs[-1].comment << "\n" defs[-1].comment << remove_header_marker($1) end next elsif /^\s*?$/ =~ line comment = "" under_comment_valid = false next end type = "" characters = "" if line =~ /^\s*? ( character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* | type\s*?\([\w\s]+?\)[\s\,]* | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* | double\s+precision[\s\,]* | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* ) (.*?::)? (.+)$ /ix characters = $8 type = $1 type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7 else under_comment_valid = false next end squote = false ; dquote = false ; bracket = 0 iniflag = false; commentflag = false varname = "" ; arraysuffix = "" ; inivalue = "" start_pos = defs.size characters.split("").each { |char| if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag) case char when "!" ; commentflag = true when "(" ; bracket += 1 ; arraysuffix = char when "\""; dquote = true when "\'"; squote = true when "=" ; iniflag = true ; inivalue << char when "," defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) varname = "" ; arraysuffix = "" ; inivalue = "" under_comment_valid = true when " " ; next else ; varname << char end elsif commentflag comment << remove_header_marker(char) trailing_comment << remove_header_marker(char) elsif iniflag if dquote case char when "\"" ; dquote = false ; inivalue << char else ; inivalue << char end elsif squote case char when "\'" ; squote = false ; inivalue << char else ; inivalue << char end elsif bracket > 0 case char when "(" ; bracket += 1 ; inivalue << char when ")" ; bracket -= 1 ; inivalue << char else ; inivalue << char end else case char when "," defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) varname = "" ; arraysuffix = "" ; inivalue = "" iniflag = false under_comment_valid = true when "(" ; bracket += 1 ; inivalue << char when "\""; dquote = true ; inivalue << char when "\'"; squote = true ; inivalue << char when "!" ; commentflag = true else ; inivalue << char end end elsif !(squote) && !(dquote) && bracket > 0 case char when "(" ; bracket += 1 ; arraysuffix << char when ")" ; bracket -= 1 ; arraysuffix << char else ; arraysuffix << char end elsif squote case char when "\'"; squote = false ; inivalue << char else ; inivalue << char end elsif dquote case char when "\""; dquote = false ; inivalue << char else ; inivalue << char end end } defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) if trailing_comment =~ /^:nodoc:/ defs[start_pos..-1].collect!{ |defitem| defitem.nodoc = true } end varname = "" ; arraysuffix = "" ; inivalue = "" comment = "" under_comment_valid = true trailing_comment = "" } return defs end end # class Fortran95parser end # module RDoc PK|]9O99rdoc/ri/ri_formatter.rbnu[module RI class TextFormatter attr_reader :indent def initialize(options, indent) @options = options @width = options.width @indent = indent end ###################################################################### def draw_line(label=nil) len = @width len -= (label.size+1) if label print "-"*len if label print(" ") bold_print(label) end puts end ###################################################################### def wrap(txt, prefix=@indent, linelen=@width) return unless txt && !txt.empty? work = conv_markup(txt) textLen = linelen - prefix.length patt = Regexp.new("^(.{0,#{textLen}})[ \n]") next_prefix = prefix.tr("^ ", " ") res = [] while work.length > textLen if work =~ patt res << $1 work.slice!(0, $&.length) else res << work.slice!(0, textLen) end end res << work if work.length.nonzero? puts(prefix + res.join("\n" + next_prefix)) end ###################################################################### def blankline puts end ###################################################################### # called when we want to ensure a nbew 'wrap' starts on a newline # Only needed for HtmlFormatter, because the rest do their # own line breaking def break_to_newline end ###################################################################### def bold_print(txt) print txt end ###################################################################### def raw_print_line(txt) puts txt end ###################################################################### # convert HTML entities back to ASCII def conv_html(txt) txt. gsub(/>/, '>'). gsub(/</, '<'). gsub(/"/, '"'). gsub(/&/, '&') end # convert markup into display form def conv_markup(txt) txt. gsub(%r{(.*?)}) { "+#$1+" } . gsub(%r{(.*?)}) { "+#$1+" } . gsub(%r{(.*?)}) { "*#$1*" } . gsub(%r{(.*?)}) { "_#$1_" } end ###################################################################### def display_list(list) case list.type when SM::ListBase::BULLET prefixer = proc { |ignored| @indent + "* " } when SM::ListBase::NUMBER, SM::ListBase::UPPERALPHA, SM::ListBase::LOWERALPHA start = case list.type when SM::ListBase::NUMBER then 1 when SM::ListBase::UPPERALPHA then 'A' when SM::ListBase::LOWERALPHA then 'a' end prefixer = proc do |ignored| res = @indent + "#{start}.".ljust(4) start = start.succ res end when SM::ListBase::LABELED prefixer = proc do |li| li.label end when SM::ListBase::NOTE longest = 0 list.contents.each do |item| if item.kind_of?(SM::Flow::LI) && item.label.length > longest longest = item.label.length end end prefixer = proc do |li| @indent + li.label.ljust(longest+1) end else fail "unknown list type" end list.contents.each do |item| if item.kind_of? SM::Flow::LI prefix = prefixer.call(item) display_flow_item(item, prefix) else display_flow_item(item) end end end ###################################################################### def display_flow_item(item, prefix=@indent) case item when SM::Flow::P, SM::Flow::LI wrap(conv_html(item.body), prefix) blankline when SM::Flow::LIST display_list(item) when SM::Flow::VERB display_verbatim_flow_item(item, @indent) when SM::Flow::H display_heading(conv_html(item.text), item.level, @indent) when SM::Flow::RULE draw_line else fail "Unknown flow element: #{item.class}" end end ###################################################################### def display_verbatim_flow_item(item, prefix=@indent) item.body.split(/\n/).each do |line| print @indent, conv_html(line), "\n" end blankline end ###################################################################### def display_heading(text, level, indent) text = strip_attributes(text) case level when 1 ul = "=" * text.length puts puts text.upcase puts ul # puts when 2 ul = "-" * text.length puts puts text puts ul # puts else print indent, text, "\n" end end def display_flow(flow) flow.each do |f| display_flow_item(f) end end def strip_attributes(txt) tokens = txt.split(%r{()}) text = [] attributes = 0 tokens.each do |tok| case tok when %r{^$}, %r{^<(\w+)>$} ; else text << tok end end text.join end end ###################################################################### # Handle text with attributes. We're a base class: there are # different presentation classes (one, for example, uses overstrikes # to handle bold and underlining, while another using ANSI escape # sequences class AttributeFormatter < TextFormatter BOLD = 1 ITALIC = 2 CODE = 4 ATTR_MAP = { "b" => BOLD, "code" => CODE, "em" => ITALIC, "i" => ITALIC, "tt" => CODE } # TODO: struct? class AttrChar attr_reader :char attr_reader :attr def initialize(char, attr) @char = char @attr = attr end end class AttributeString attr_reader :txt def initialize @txt = [] @optr = 0 end def <<(char) @txt << char end def empty? @optr >= @txt.length end # accept non space, then all following spaces def next_word start = @optr len = @txt.length while @optr < len && @txt[@optr].char != " " @optr += 1 end while @optr < len && @txt[@optr].char == " " @optr += 1 end @txt[start...@optr] end end ###################################################################### # overrides base class. Looks for ... etc sequences # and generates an array of AttrChars. This array is then used # as the basis for the split def wrap(txt, prefix=@indent, linelen=@width) return unless txt && !txt.empty? txt = add_attributes_to(txt) next_prefix = prefix.tr("^ ", " ") linelen -= prefix.size line = [] until txt.empty? word = txt.next_word if word.size + line.size > linelen write_attribute_text(prefix, line) prefix = next_prefix line = [] end line.concat(word) end write_attribute_text(prefix, line) if line.length > 0 end protected # overridden in specific formatters def write_attribute_text(prefix, line) print prefix line.each do |achar| print achar.char end puts end # again, overridden def bold_print(txt) print txt end private def add_attributes_to(txt) tokens = txt.split(%r{()}) text = AttributeString.new attributes = 0 tokens.each do |tok| case tok when %r{^$} then attributes &= ~(ATTR_MAP[$1]||0) when %r{^<(\w+)>$} then attributes |= (ATTR_MAP[$1]||0) else tok.split(//).each {|ch| text << AttrChar.new(ch, attributes)} end end text end end ################################################## # This formatter generates overstrike-style formatting, which # works with pagers such as man and less. class OverstrikeFormatter < AttributeFormatter BS = "\C-h" def write_attribute_text(prefix, line) print prefix line.each do |achar| attr = achar.attr if (attr & (ITALIC+CODE)) != 0 print "_", BS end if (attr & BOLD) != 0 print achar.char, BS end print achar.char end puts end # draw a string in bold def bold_print(text) text.split(//).each do |ch| print ch, BS, ch end end end ################################################## # This formatter uses ANSI escape sequences # to colorize stuff # works with pages such as man and less. class AnsiFormatter < AttributeFormatter def initialize(*args) print "\033[0m" super end def write_attribute_text(prefix, line) print prefix curr_attr = 0 line.each do |achar| attr = achar.attr if achar.attr != curr_attr update_attributes(achar.attr) curr_attr = achar.attr end print achar.char end update_attributes(0) unless curr_attr.zero? puts end def bold_print(txt) print "\033[1m#{txt}\033[m" end HEADINGS = { 1 => [ "\033[1;32m", "\033[m" ] , 2 => ["\033[4;32m", "\033[m" ], 3 => ["\033[32m", "\033[m" ] } def display_heading(text, level, indent) level = 3 if level > 3 heading = HEADINGS[level] print indent print heading[0] print strip_attributes(text) puts heading[1] end private ATTR_MAP = { BOLD => "1", ITALIC => "33", CODE => "36" } def update_attributes(attr) str = "\033[" for quality in [ BOLD, ITALIC, CODE] unless (attr & quality).zero? str << ATTR_MAP[quality] end end print str, "m" end end ################################################## # This formatter uses HTML. class HtmlFormatter < AttributeFormatter def initialize(*args) super end def write_attribute_text(prefix, line) curr_attr = 0 line.each do |achar| attr = achar.attr if achar.attr != curr_attr update_attributes(curr_attr, achar.attr) curr_attr = achar.attr end print(escape(achar.char)) end update_attributes(curr_attr, 0) unless curr_attr.zero? end def draw_line(label=nil) if label != nil bold_print(label) end puts("
    ") end def bold_print(txt) tag("b") { txt } end def blankline() puts("

    ") end def break_to_newline puts("
    ") end def display_heading(text, level, indent) level = 4 if level > 4 tag("h#{level}") { text } puts end ###################################################################### def display_list(list) case list.type when SM::ListBase::BULLET list_type = "ul" prefixer = proc { |ignored| "

  • " } when SM::ListBase::NUMBER, SM::ListBase::UPPERALPHA, SM::ListBase::LOWERALPHA list_type = "ol" prefixer = proc { |ignored| "
  • " } when SM::ListBase::LABELED list_type = "dl" prefixer = proc do |li| "
    " + escape(li.label) + "
    " end when SM::ListBase::NOTE list_type = "table" prefixer = proc do |li| %{#{li.label.gsub(/ /, ' ')}} end else fail "unknown list type" end print "<#{list_type}>" list.contents.each do |item| if item.kind_of? SM::Flow::LI prefix = prefixer.call(item) print prefix display_flow_item(item, prefix) else display_flow_item(item) end end print "" end def display_verbatim_flow_item(item, prefix=@indent) print("
    ")
            puts item.body
            puts("
    ") end private ATTR_MAP = { BOLD => "b>", ITALIC => "i>", CODE => "tt>" } def update_attributes(current, wanted) str = "" # first turn off unwanted ones off = current & ~wanted for quality in [ BOLD, ITALIC, CODE] if (off & quality) > 0 str << "") print(yield) print("") end def escape(str) str. gsub(/&/n, '&'). gsub(/\"/n, '"'). gsub(/>/n, '>'). gsub(/ AnsiFormatter, "bs" => OverstrikeFormatter, "html" => HtmlFormatter, "plain" => TextFormatter, "simple" => SimpleFormatter, } def TextFormatter.list FORMATTERS.keys.sort.join(", ") end def TextFormatter.for(name) FORMATTERS[name.downcase] end end end PK|] rdoc/ri/ri_descriptions.rbnu[require 'yaml' require 'rdoc/markup/simple_markup/fragments' # Descriptions are created by RDoc (in ri_generator) and # written out in serialized form into the documentation # tree. ri then reads these to generate the documentation module RI class NamedThing attr_reader :name def initialize(name) @name = name end def <=>(other) @name <=> other.name end def hash @name.hash end def eql?(other) @name.eql?(other) end end # Alias = Struct.new(:old_name, :new_name) class AliasName < NamedThing end class Attribute < NamedThing attr_reader :rw, :comment def initialize(name, rw, comment) super(name) @rw = rw @comment = comment end end class Constant < NamedThing attr_reader :value, :comment def initialize(name, value, comment) super(name) @value = value @comment = comment end end class IncludedModule < NamedThing end class MethodSummary < NamedThing def initialize(name="") super end end class Description attr_accessor :name attr_accessor :full_name attr_accessor :comment def serialize self.to_yaml end def Description.deserialize(from) YAML.load(from) end def <=>(other) @name <=> other.name end end class ModuleDescription < Description attr_accessor :class_methods attr_accessor :instance_methods attr_accessor :attributes attr_accessor :constants attr_accessor :includes # merge in another class desscription into this one def merge_in(old) merge(@class_methods, old.class_methods) merge(@instance_methods, old.instance_methods) merge(@attributes, old.attributes) merge(@constants, old.constants) merge(@includes, old.includes) if @comment.nil? || @comment.empty? @comment = old.comment else unless old.comment.nil? or old.comment.empty? then @comment << SM::Flow::RULE.new @comment.concat old.comment end end end def display_name "Module" end # the 'ClassDescription' subclass overrides this # to format up the name of a parent def superclass_string nil end private def merge(into, from) names = {} into.each {|i| names[i.name] = i } from.each {|i| names[i.name] = i } into.replace(names.keys.sort.map {|n| names[n]}) end end class ClassDescription < ModuleDescription attr_accessor :superclass def display_name "Class" end def superclass_string if @superclass && @superclass != "Object" @superclass else nil end end end class MethodDescription < Description attr_accessor :is_class_method attr_accessor :visibility attr_accessor :block_params attr_accessor :is_singleton attr_accessor :aliases attr_accessor :is_alias_for attr_accessor :params end end PK|] 988rdoc/ri/ri_cache.rbnu[module RI class ClassEntry attr_reader :name attr_reader :path_names def initialize(path_name, name, in_class) @path_names = [ path_name ] @name = name @in_class = in_class @class_methods = [] @instance_methods = [] @inferior_classes = [] end # We found this class in more tha one place, so add # in the name from there. def add_path(path) @path_names << path end # read in our methods and any classes # and modules in our namespace. Methods are # stored in files called name-c|i.yaml, # where the 'name' portion is the external # form of the method name and the c|i is a class|instance # flag def load_from(dir) Dir.foreach(dir) do |name| next if name =~ /^\./ # convert from external to internal form, and # extract the instance/class flag if name =~ /^(.*?)-(c|i).yaml$/ external_name = $1 is_class_method = $2 == "c" internal_name = RiWriter.external_to_internal(external_name) list = is_class_method ? @class_methods : @instance_methods path = File.join(dir, name) list << MethodEntry.new(path, internal_name, is_class_method, self) else full_name = File.join(dir, name) if File.directory?(full_name) inf_class = @inferior_classes.find {|c| c.name == name } if inf_class inf_class.add_path(full_name) else inf_class = ClassEntry.new(full_name, name, self) @inferior_classes << inf_class end inf_class.load_from(full_name) end end end end # Return a list of any classes or modules that we contain # that match a given string def contained_modules_matching(name) @inferior_classes.find_all {|c| c.name[name]} end def classes_and_modules @inferior_classes end # Return an exact match to a particular name def contained_class_named(name) @inferior_classes.find {|c| c.name == name} end # return the list of local methods matching name # We're split into two because we need distinct behavior # when called from the _toplevel_ def methods_matching(name, is_class_method) local_methods_matching(name, is_class_method) end # Find methods matching 'name' in ourselves and in # any classes we contain def recursively_find_methods_matching(name, is_class_method) res = local_methods_matching(name, is_class_method) @inferior_classes.each do |c| res.concat(c.recursively_find_methods_matching(name, is_class_method)) end res end # Return our full name def full_name res = @in_class.full_name res << "::" unless res.empty? res << @name end # Return a list of all out method names def all_method_names res = @class_methods.map {|m| m.full_name } @instance_methods.each {|m| res << m.full_name} res end private # Return a list of all our methods matching a given string. # Is +is_class_methods+ if 'nil', we don't care if the method # is a class method or not, otherwise we only return # those methods that match def local_methods_matching(name, is_class_method) list = case is_class_method when nil then @class_methods + @instance_methods when true then @class_methods when false then @instance_methods else fail "Unknown is_class_method: #{is_class_method.inspect}" end list.find_all {|m| m.name; m.name[name]} end end # A TopLevelEntry is like a class entry, but when asked to search # for methods searches all classes, not just itself class TopLevelEntry < ClassEntry def methods_matching(name, is_class_method) res = recursively_find_methods_matching(name, is_class_method) end def full_name "" end def module_named(name) end end class MethodEntry attr_reader :name attr_reader :path_name def initialize(path_name, name, is_class_method, in_class) @path_name = path_name @name = name @is_class_method = is_class_method @in_class = in_class end def full_name res = @in_class.full_name unless res.empty? if @is_class_method res << "::" else res << "#" end end res << @name end end # We represent everything know about all 'ri' files # accessible to this program class RiCache attr_reader :toplevel def initialize(dirs) # At the top level we have a dummy module holding the # overall namespace @toplevel = TopLevelEntry.new('', '::', nil) dirs.each do |dir| @toplevel.load_from(dir) end end end end PK|]`\lrdoc/ri/ri_display.rbnu[require 'rdoc/ri/ri_util' require 'rdoc/ri/ri_formatter' require 'rdoc/ri/ri_options' # This is a kind of 'flag' module. If you want to write your # own 'ri' display module (perhaps because you'r writing # an IDE or somesuch beast), you simply write a class # which implements the various 'display' methods in 'DefaultDisplay', # and include the 'RiDisplay' module in that class. # # To access your class from the command line, you can do # # ruby -r ../ri .... # # If folks _really_ want to do this from the command line, # I'll build an option in module RiDisplay @@display_class = nil def RiDisplay.append_features(display_class) @@display_class = display_class end def RiDisplay.new(*args) @@display_class.new(*args) end end ###################################################################### # # A paging display module. Uses the ri_formatter class to do the # actual presentation # class DefaultDisplay include RiDisplay def initialize(options) @options = options @formatter = @options.formatter.new(@options, " ") end ###################################################################### def display_usage page do RI::Options::OptionList.usage(short_form=true) end end ###################################################################### def display_method_info(method) page do @formatter.draw_line(method.full_name) display_params(method) @formatter.draw_line display_flow(method.comment) if method.aliases && !method.aliases.empty? @formatter.blankline aka = "(also known as " aka << method.aliases.map {|a| a.name }.join(", ") aka << ")" @formatter.wrap(aka) end end end ###################################################################### def display_class_info(klass, ri_reader) page do superclass = klass.superclass_string if superclass superclass = " < " + superclass else superclass = "" end @formatter.draw_line(klass.display_name + ": " + klass.full_name + superclass) display_flow(klass.comment) @formatter.draw_line unless klass.includes.empty? @formatter.blankline @formatter.display_heading("Includes:", 2, "") incs = [] klass.includes.each do |inc| inc_desc = ri_reader.find_class_by_name(inc.name) if inc_desc str = inc.name + "(" str << inc_desc.instance_methods.map{|m| m.name}.join(", ") str << ")" incs << str else incs << inc.name end end @formatter.wrap(incs.sort.join(', ')) end unless klass.constants.empty? @formatter.blankline @formatter.display_heading("Constants:", 2, "") len = 0 klass.constants.each { |c| len = c.name.length if c.name.length > len } len += 2 klass.constants.each do |c| @formatter.wrap(c.value, @formatter.indent+((c.name+":").ljust(len))) end end unless klass.class_methods.empty? @formatter.blankline @formatter.display_heading("Class methods:", 2, "") @formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', ')) end unless klass.instance_methods.empty? @formatter.blankline @formatter.display_heading("Instance methods:", 2, "") @formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', ')) end unless klass.attributes.empty? @formatter.blankline @formatter.wrap("Attributes:", "") @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', ')) end end end ###################################################################### # Display a list of method names def display_method_list(methods) page do puts "More than one method matched your request. You can refine" puts "your search by asking for information on one of:\n\n" @formatter.wrap(methods.map {|m| m.full_name} .join(", ")) end end ###################################################################### def display_class_list(namespaces) page do puts "More than one class or module matched your request. You can refine" puts "your search by asking for information on one of:\n\n" @formatter.wrap(namespaces.map {|m| m.full_name}.join(", ")) end end ###################################################################### def list_known_classes(classes) if classes.empty? warn_no_database else page do @formatter.draw_line("Known classes and modules") @formatter.blankline @formatter.wrap(classes.sort.join(", ")) end end end ###################################################################### def list_known_names(names) if names.empty? warn_no_database else page do names.each {|n| @formatter.raw_print_line(n)} end end end ###################################################################### private ###################################################################### def page return yield unless pager = setup_pager begin save_stdout = STDOUT.clone STDOUT.reopen(pager) yield ensure STDOUT.reopen(save_stdout) save_stdout.close pager.close end end ###################################################################### def setup_pager unless @options.use_stdout for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq return IO.popen(pager, "w") rescue nil end @options.use_stdout = true nil end end ###################################################################### def display_params(method) params = method.params if params[0,1] == "(" if method.is_singleton params = method.full_name + params else params = method.name + params end end params.split(/\n/).each do |p| @formatter.wrap(p) @formatter.break_to_newline end end ###################################################################### def display_flow(flow) if !flow || flow.empty? @formatter.wrap("(no description...)") else @formatter.display_flow(flow) end end ###################################################################### def warn_no_database puts "Before using ri, you need to generate documentation" puts "using 'rdoc' with the --ri option" end end # class RiDisplay PK|]>ꞗ rdoc/ri/ri_paths.rbnu[module RI # Encapsulate all the strangeness to do with finding out # where to find RDoc files # # We basically deal with three directories: # # 1. The 'system' documentation directory, which holds # the documentation distributed with Ruby, and which # is managed by the Ruby install process # 2. The 'site' directory, which contains site-wide # documentation added locally. # 3. The 'user' documentation directory, stored under the # user's own home directory. # # There's contention about all this, but for now: # # system:: $datadir/ri//system/... # site:: $datadir/ri//site/... # user:: ~/.rdoc module Paths #:stopdoc: require 'rbconfig' DOC_DIR = "doc/rdoc" version = Config::CONFIG['ruby_version'] base = File.join(Config::CONFIG['datadir'], "ri", version) SYSDIR = File.join(base, "system") SITEDIR = File.join(base, "site") homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH'] if homedir HOMEDIR = File.join(homedir, ".rdoc") else HOMEDIR = nil end # This is the search path for 'ri' PATH = [ SYSDIR, SITEDIR, HOMEDIR ].find_all {|p| p && File.directory?(p)} begin require 'rubygems' # HACK dup'd from Gem.latest_partials and friends all_paths = [] all_paths = Gem.path.map do |dir| Dir[File.join(dir, 'doc', '*', 'ri')] end.flatten ri_paths = {} all_paths.each do |dir| base = File.basename File.dirname(dir) if base =~ /(.*)-((\d+\.)*\d+)/ then name, version = $1, $2 ver = Gem::Version.new version if ri_paths[name].nil? or ver > ri_paths[name][0] then ri_paths[name] = [ver, dir] end end end GEMDIRS = ri_paths.map { |k,v| v.last }.sort GEMDIRS.each { |dir| RI::Paths::PATH << dir } rescue LoadError GEMDIRS = nil end # Returns the selected documentation directories as an Array, or PATH if no # overriding directories were given. def self.path(use_system, use_site, use_home, use_gems, *extra_dirs) path = raw_path(use_system, use_site, use_home, use_gems, *extra_dirs) return path.select { |directory| File.directory? directory } end # Returns the selected documentation directories including nonexistent # directories. Used to print out what paths were searched if no ri was # found. def self.raw_path(use_system, use_site, use_home, use_gems, *extra_dirs) return PATH unless use_system or use_site or use_home or use_gems or not extra_dirs.empty? path = [] path << extra_dirs unless extra_dirs.empty? path << RI::Paths::SYSDIR if use_system path << RI::Paths::SITEDIR if use_site path << RI::Paths::HOMEDIR if use_home path << RI::Paths::GEMDIRS if use_gems return path.flatten.compact end end end PK|]O7rdoc/ri/ri_driver.rbnu[require 'rdoc/ri/ri_paths' require 'rdoc/usage' require 'rdoc/ri/ri_cache' require 'rdoc/ri/ri_util' require 'rdoc/ri/ri_reader' require 'rdoc/ri/ri_formatter' require 'rdoc/ri/ri_options' ###################################################################### class RiDriver def initialize @options = RI::Options.instance args = ARGV if ENV["RI"] args = ENV["RI"].split.concat(ARGV) end @options.parse(args) path = @options.path report_missing_documentation @options.raw_path if path.empty? @ri_reader = RI::RiReader.new(RI::RiCache.new(path)) @display = @options.displayer end # Couldn't find documentation in +path+, so tell the user what to do def report_missing_documentation(path) STDERR.puts "No ri documentation found in:" path.each do |d| STDERR.puts " #{d}" end STDERR.puts "\nWas rdoc run to create documentation?\n\n" RDoc::usage("Installing Documentation") end ###################################################################### # If the list of matching methods contains exactly one entry, or # if it contains an entry that exactly matches the requested method, # then display that entry, otherwise display the list of # matching method names def report_method_stuff(requested_method_name, methods) if methods.size == 1 method = @ri_reader.get_method(methods[0]) @display.display_method_info(method) else entries = methods.find_all {|m| m.name == requested_method_name} if entries.size == 1 method = @ri_reader.get_method(entries[0]) @display.display_method_info(method) else @display.display_method_list(methods) end end end ###################################################################### def report_class_stuff(namespaces) if namespaces.size == 1 klass = @ri_reader.get_class(namespaces[0]) @display.display_class_info(klass, @ri_reader) else # entries = namespaces.find_all {|m| m.full_name == requested_class_name} # if entries.size == 1 # klass = @ri_reader.get_class(entries[0]) # @display.display_class_info(klass, @ri_reader) # else @display.display_class_list(namespaces) # end end end ###################################################################### def get_info_for(arg) desc = NameDescriptor.new(arg) namespaces = @ri_reader.top_level_namespace for class_name in desc.class_names namespaces = @ri_reader.lookup_namespace_in(class_name, namespaces) if namespaces.empty? raise RiError.new("Nothing known about #{arg}") end end # at this point, if we have multiple possible namespaces, but one # is an exact match for our requested class, prune down to just it full_class_name = desc.full_class_name entries = namespaces.find_all {|m| m.full_name == full_class_name} namespaces = entries if entries.size == 1 if desc.method_name.nil? report_class_stuff(namespaces) else methods = @ri_reader.find_methods(desc.method_name, desc.is_class_method, namespaces) if methods.empty? raise RiError.new("Nothing known about #{arg}") else report_method_stuff(desc.method_name, methods) end end end ###################################################################### def process_args if @options.list_classes classes = @ri_reader.full_class_names @display.list_known_classes(classes) elsif @options.list_names names = @ri_reader.all_names @display.list_known_names(names) else if ARGV.size.zero? @display.display_usage else begin ARGV.each do |arg| get_info_for(arg) end rescue RiError => e STDERR.puts(e.message) exit(1) end end end end end # class RiDriver PK|] <*rdoc/ri/ri_reader.rbnu[require 'rdoc/ri/ri_descriptions' require 'rdoc/ri/ri_writer' require 'rdoc/markup/simple_markup/to_flow' module RI class RiReader def initialize(ri_cache) @cache = ri_cache end def top_level_namespace [ @cache.toplevel ] end def lookup_namespace_in(target, namespaces) result = [] for n in namespaces result.concat(n.contained_modules_matching(target)) end result end def find_class_by_name(full_name) names = full_name.split(/::/) ns = @cache.toplevel for name in names ns = ns.contained_class_named(name) return nil if ns.nil? end get_class(ns) end def find_methods(name, is_class_method, namespaces) result = [] namespaces.each do |ns| result.concat ns.methods_matching(name, is_class_method) end result end # return the MethodDescription for a given MethodEntry # by deserializing the YAML def get_method(method_entry) path = method_entry.path_name File.open(path) { |f| RI::Description.deserialize(f) } end # Return a class description def get_class(class_entry) result = nil for path in class_entry.path_names path = RiWriter.class_desc_path(path, class_entry) desc = File.open(path) {|f| RI::Description.deserialize(f) } if result result.merge_in(desc) else result = desc end end result end # return the names of all classes and modules def full_class_names res = [] find_classes_in(res, @cache.toplevel) end # return a list of all classes, modules, and methods def all_names res = [] find_names_in(res, @cache.toplevel) end # ---- private # ---- def find_classes_in(res, klass) classes = klass.classes_and_modules for c in classes res << c.full_name find_classes_in(res, c) end res end def find_names_in(res, klass) classes = klass.classes_and_modules for c in classes res << c.full_name res.concat c.all_method_names find_names_in(res, c) end res end end end PK|]|Qi"i"rdoc/ri/ri_options.rbnu[# We handle the parsing of options, and subsequently as a singleton # object to be queried for option values module RI require 'rdoc/ri/ri_paths' require 'rdoc/ri/ri_display' VERSION_STRING = "ri v1.0.1 - 20041108" class Options require 'singleton' require 'getoptlong' include Singleton # No not use a pager. Writable, because ri sets it if it # can't find a pager attr_accessor :use_stdout # should we just display a class list and exit attr_reader :list_classes # should we display a list of all names attr_reader :list_names # The width of the output line attr_reader :width # the formatting we apply to the output attr_reader :formatter # the directory we search for original documentation attr_reader :doc_dir module OptionList OPTION_LIST = [ [ "--help", "-h", nil, "you're looking at it" ], [ "--classes", "-c", nil, "Display the names of classes and modules we\n" + "know about"], [ "--doc-dir", "-d", "", "A directory to search for documentation. If not\n" + "specified, we search the standard rdoc/ri directories.\n" + "May be repeated."], [ "--system", nil, nil, "Include documentation from Ruby's standard library:\n " + RI::Paths::SYSDIR ], [ "--site", nil, nil, "Include documentation from libraries installed in site_lib:\n " + RI::Paths::SITEDIR ], [ "--home", nil, nil, "Include documentation stored in ~/.rdoc:\n " + (RI::Paths::HOMEDIR || "No ~/.rdoc found") ], [ "--gems", nil, nil, "Include documentation from RubyGems:\n" + (RI::Paths::GEMDIRS ? Gem.path.map { |dir| " #{dir}/doc/*/ri" }.join("\n") : "No Rubygems ri found.") ], [ "--format", "-f", "", "Format to use when displaying output:\n" + " " + RI::TextFormatter.list + "\n" + "Use 'bs' (backspace) with most pager programs.\n" + "To use ANSI, either also use the -T option, or\n" + "tell your pager to allow control characters\n" + "(for example using the -R option to less)"], [ "--list-names", "-l", nil, "List all the names known to RDoc, one per line" ], [ "--no-pager", "-T", nil, "Send output directly to stdout." ], [ "--width", "-w", "output width", "Set the width of the output" ], [ "--version", "-v", nil, "Display the version of ri" ], ] def OptionList.options OPTION_LIST.map do |long, short, arg,| option = [] option << long option << short unless short.nil? option << (arg ? GetoptLong::REQUIRED_ARGUMENT : GetoptLong::NO_ARGUMENT) option end end def OptionList.strip_output(text) text =~ /^\s+/ leading_spaces = $& text.gsub!(/^#{leading_spaces}/, '') $stdout.puts text end # Show an error and exit def OptionList.error(msg) $stderr.puts $stderr.puts msg name = File.basename $PROGRAM_NAME $stderr.puts "\nFor help on options, try '#{name} --help'\n\n" exit 1 end # Show usage and exit def OptionList.usage(short_form=false) puts puts(RI::VERSION_STRING) puts name = File.basename($0) directories = [ RI::Paths::SYSDIR, RI::Paths::SITEDIR, RI::Paths::HOMEDIR ] if RI::Paths::GEMDIRS then Gem.path.each do |dir| directories << "#{dir}/doc/*/ri" end end directories = directories.join("\n ") OptionList.strip_output(<<-EOT) Usage: #{name} [options] [names...] Display information on Ruby classes, modules, and methods. Give the names of classes or methods to see their documentation. Partial names may be given: if the names match more than one entity, a list will be shown, otherwise details on that entity will be displayed. Nested classes and modules can be specified using the normal Name::Name notation, and instance methods can be distinguished from class methods using "." (or "#") instead of "::". For example: #{name} File #{name} File.new #{name} F.n #{name} zip Note that shell quoting may be required for method names containing punctuation: #{name} 'Array.[]' #{name} compact\\! By default ri searches for documentation in the following directories: #{directories} Specifying the --system, --site, --home, --gems or --doc-dir options will limit ri to searching only the specified directories. EOT if short_form puts "For help on options, type '#{name} -h'" puts "For a list of classes I know about, type '#{name} -c'" else puts "Options:\n\n" OPTION_LIST.each do|long, short, arg, desc| opt = '' opt << (short ? sprintf("%15s", "#{long}, #{short}") : sprintf("%15s", long)) if arg opt << " " << arg end print opt desc = desc.split("\n") if opt.size < 17 print " "*(18-opt.size) puts desc.shift else puts end desc.each do |line| puts(" "*18 + line) end puts end puts "Options may also be passed in the 'RI' environment variable" exit 0 end end end # Show the version and exit def show_version puts VERSION_STRING exit(0) end def initialize @use_stdout = !STDOUT.tty? @width = 72 @formatter = RI::TextFormatter.for("plain") @list_classes = false @list_names = false # By default all paths are used. If any of these are true, only those # directories are used. @use_system = false @use_site = false @use_home = false @use_gems = false @doc_dirs = [] end # Parse command line options. def parse(args) old_argv = ARGV.dup ARGV.replace(args) begin go = GetoptLong.new(*OptionList.options) go.quiet = true go.each do |opt, arg| case opt when "--help" then OptionList.usage when "--version" then show_version when "--list-names" then @list_names = true when "--no-pager" then @use_stdout = true when "--classes" then @list_classes = true when "--system" then @use_system = true when "--site" then @use_site = true when "--home" then @use_home = true when "--gems" then @use_gems = true when "--doc-dir" if File.directory?(arg) @doc_dirs << arg else $stderr.puts "Invalid directory: #{arg}" exit 1 end when "--format" @formatter = RI::TextFormatter.for(arg) unless @formatter $stderr.print "Invalid formatter (should be one of " $stderr.puts RI::TextFormatter.list + ")" exit 1 end when "--width" begin @width = Integer(arg) rescue $stderr.puts "Invalid width: '#{arg}'" exit 1 end end end rescue GetoptLong::InvalidOption, GetoptLong::MissingArgument => error OptionList.error(error.message) end end # Return the selected documentation directories. def path RI::Paths.path(@use_system, @use_site, @use_home, @use_gems, *@doc_dirs) end def raw_path RI::Paths.raw_path(@use_system, @use_site, @use_home, @use_gems, *@doc_dirs) end # Return an instance of the displayer (the thing that actually writes # the information). This allows us to load in new displayer classes # at runtime (for example to help with IDE integration) def displayer ::RiDisplay.new(self) end end end PK|]/rdoc/ri/ri_writer.rbnu[require 'fileutils' module RI class RiWriter def RiWriter.class_desc_path(dir, class_desc) File.join(dir, "cdesc-" + class_desc.name + ".yaml") end # Convert a name from internal form (containing punctuation) # to an external form (where punctuation is replaced # by %xx) def RiWriter.internal_to_external(name) name.gsub(/\W/) { sprintf("%%%02x", $&[0]) } end # And the reverse operation def RiWriter.external_to_internal(name) name.gsub(/%([0-9a-f]{2,2})/) { $1.to_i(16).chr } end def initialize(base_dir) @base_dir = base_dir end def remove_class(class_desc) FileUtils.rm_rf(path_to_dir(class_desc.full_name)) end def add_class(class_desc) dir = path_to_dir(class_desc.full_name) FileUtils.mkdir_p(dir) class_file_name = RiWriter.class_desc_path(dir, class_desc) File.open(class_file_name, "w") do |f| f.write(class_desc.serialize) end end def add_method(class_desc, method_desc) dir = path_to_dir(class_desc.full_name) file_name = RiWriter.internal_to_external(method_desc.name) meth_file_name = File.join(dir, file_name) if method_desc.is_singleton meth_file_name += "-c.yaml" else meth_file_name += "-i.yaml" end File.open(meth_file_name, "w") do |f| f.write(method_desc.serialize) end end private def path_to_dir(class_name) File.join(@base_dir, *class_name.split('::')) end end end PK|]sbbrdoc/ri/ri_util.rbnu[###################################################################### class RiError < Exception; end # # Break argument into its constituent class or module names, an # optional method type, and a method name class NameDescriptor attr_reader :class_names attr_reader :method_name # true and false have the obvious meaning. nil means we don't care attr_reader :is_class_method # arg may be # 1. a class or module name (optionally qualified with other class # or module names (Kernel, File::Stat etc) # 2. a method name # 3. a method name qualified by a optionally fully qualified class # or module name # # We're fairly casual about delimiters: folks can say Kernel::puts, # Kernel.puts, or Kernel\#puts for example. There's one exception: # if you say IO::read, we look for a class method, but if you # say IO.read, we look for an instance method def initialize(arg) @class_names = [] separator = nil tokens = arg.split(/(\.|::|#)/) # Skip leading '::', '#' or '.', but remember it might # be a method name qualifier separator = tokens.shift if tokens[0] =~ /^(\.|::|#)/ # Skip leading '::', but remember we potentially have an inst # leading stuff must be class names while tokens[0] =~ /^[A-Z]/ @class_names << tokens.shift unless tokens.empty? separator = tokens.shift break unless separator == "::" end end # Now must have a single token, the method name, or an empty # array unless tokens.empty? @method_name = tokens.shift # We may now have a trailing !, ?, or = to roll into # the method name if !tokens.empty? && tokens[0] =~ /^[!?=]$/ @method_name << tokens.shift end if @method_name =~ /::|\.|#/ or !tokens.empty? raise RiError.new("Bad argument: #{arg}") end if separator && separator != '.' @is_class_method = separator == "::" end end end # Return the full class name (with '::' between the components) # or "" if there's no class name def full_class_name @class_names.join("::") end end PK|]%#H#Hrdoc/code_objects.rbnu[# We represent the various high-level code constructs that appear # in Ruby programs: classes, modules, methods, and so on. require 'rdoc/tokenstream' module RDoc # We contain the common stuff for contexts (which are containers) # and other elements (methods, attributes and so on) # class CodeObject attr_accessor :parent # We are the model of the code, but we know that at some point # we will be worked on by viewers. By implementing the Viewable # protocol, viewers can associated themselves with these objects. attr_accessor :viewer # are we done documenting (ie, did we come across a :enddoc:)? attr_accessor :done_documenting # Which section are we in attr_accessor :section # do we document ourselves? attr_reader :document_self def document_self=(val) @document_self = val if !val remove_methods_etc end end # set and cleared by :startdoc: and :enddoc:, this is used to toggle # the capturing of documentation def start_doc @document_self = true @document_children = true end def stop_doc @document_self = false @document_children = false end # do we document ourselves and our children attr_reader :document_children def document_children=(val) @document_children = val if !val remove_classes_and_modules end end # Do we _force_ documentation, even is we wouldn't normally show the entity attr_accessor :force_documentation # Default callbacks to nothing, but this is overridden for classes # and modules def remove_classes_and_modules end def remove_methods_etc end def initialize @document_self = true @document_children = true @force_documentation = false @done_documenting = false end # Access the code object's comment attr_reader :comment # Update the comment, but don't overwrite a real comment # with an empty one def comment=(comment) @comment = comment unless comment.empty? end # There's a wee trick we pull. Comment blocks can have directives that # override the stuff we extract during the parse. So, we have a special # class method, attr_overridable, that lets code objects list # those directives. Wehn a comment is assigned, we then extract # out any matching directives and update our object def CodeObject.attr_overridable(name, *aliases) @overridables ||= {} attr_accessor name aliases.unshift name aliases.each do |directive_name| @overridables[directive_name.to_s] = name end end end # A Context is something that can hold modules, classes, methods, # attributes, aliases, requires, and includes. Classes, modules, and # files are all Contexts. class Context < CodeObject attr_reader :name, :method_list, :attributes, :aliases, :constants attr_reader :requires, :includes, :in_files, :visibility attr_reader :sections class Section attr_reader :title, :comment, :sequence @@sequence = "SEC00000" def initialize(title, comment) @title = title @@sequence.succ! @sequence = @@sequence.dup set_comment(comment) end private # Set the comment for this section from the original comment block # If the first line contains :section:, strip it and use the rest. Otherwise # remove lines up to the line containing :section:, and look for # those lines again at the end and remove them. This lets us write # # # --------------------- # # :SECTION: The title # # The body # # --------------------- def set_comment(comment) return unless comment if comment =~ /^.*?:section:.*$/ start = $` rest = $' if start.empty? @comment = rest else @comment = rest.sub(/#{start.chomp}\Z/, '') end else @comment = comment end @comment = nil if @comment.empty? end end def initialize super() @in_files = [] @name ||= "unknown" @comment ||= "" @parent = nil @visibility = :public @current_section = Section.new(nil, nil) @sections = [ @current_section ] initialize_methods_etc initialize_classes_and_modules end # map the class hash to an array externally def classes @classes.values end # map the module hash to an array externally def modules @modules.values end # Change the default visibility for new methods def ongoing_visibility=(vis) @visibility = vis end # Given an array +methods+ of method names, set the # visibility of the corresponding AnyMethod object def set_visibility_for(methods, vis, singleton=false) count = 0 @method_list.each do |m| if methods.include?(m.name) && m.singleton == singleton m.visibility = vis count += 1 end end return if count == methods.size || singleton # perhaps we need to look at attributes @attributes.each do |a| if methods.include?(a.name) a.visibility = vis count += 1 end end end # Record the file that we happen to find it in def record_location(toplevel) @in_files << toplevel unless @in_files.include?(toplevel) end # Return true if at least part of this thing was defined in +file+ def defined_in?(file) @in_files.include?(file) end def add_class(class_type, name, superclass) add_class_or_module(@classes, class_type, name, superclass) end def add_module(class_type, name) add_class_or_module(@modules, class_type, name, nil) end def add_method(a_method) puts "Adding #@visibility method #{a_method.name} to #@name" if $DEBUG a_method.visibility = @visibility add_to(@method_list, a_method) end def add_attribute(an_attribute) add_to(@attributes, an_attribute) end def add_alias(an_alias) meth = find_instance_method_named(an_alias.old_name) if meth new_meth = AnyMethod.new(an_alias.text, an_alias.new_name) new_meth.is_alias_for = meth new_meth.singleton = meth.singleton new_meth.params = meth.params new_meth.comment = "Alias for \##{meth.name}" meth.add_alias(new_meth) add_method(new_meth) else add_to(@aliases, an_alias) end end def add_include(an_include) add_to(@includes, an_include) end def add_constant(const) add_to(@constants, const) end # Requires always get added to the top-level (file) context def add_require(a_require) if self.kind_of? TopLevel add_to(@requires, a_require) else parent.add_require(a_require) end end def add_class_or_module(collection, class_type, name, superclass=nil) cls = collection[name] if cls puts "Reusing class/module #{name}" if $DEBUG else cls = class_type.new(name, superclass) puts "Adding class/module #{name} to #@name" if $DEBUG # collection[name] = cls if @document_self && !@done_documenting collection[name] = cls if !@done_documenting cls.parent = self cls.section = @current_section end cls end def add_to(array, thing) array << thing if @document_self && !@done_documenting thing.parent = self thing.section = @current_section end # If a class's documentation is turned off after we've started # collecting methods etc., we need to remove the ones # we have def remove_methods_etc initialize_methods_etc end def initialize_methods_etc @method_list = [] @attributes = [] @aliases = [] @requires = [] @includes = [] @constants = [] end # and remove classes and modules when we see a :nodoc: all def remove_classes_and_modules initialize_classes_and_modules end def initialize_classes_and_modules @classes = {} @modules = {} end # Find a named module def find_module_named(name) return self if self.name == name res = @modules[name] || @classes[name] return res if res find_enclosing_module_named(name) end # find a module at a higher scope def find_enclosing_module_named(name) parent && parent.find_module_named(name) end # Iterate over all the classes and modules in # this object def each_classmodule @modules.each_value {|m| yield m} @classes.each_value {|c| yield c} end def each_method @method_list.each {|m| yield m} end def each_attribute @attributes.each {|a| yield a} end def each_constant @constants.each {|c| yield c} end # Return the toplevel that owns us def toplevel return @toplevel if defined? @toplevel @toplevel = self @toplevel = @toplevel.parent until TopLevel === @toplevel @toplevel end # allow us to sort modules by name def <=>(other) name <=> other.name end # Look up the given symbol. If method is non-nil, then # we assume the symbol references a module that # contains that method def find_symbol(symbol, method=nil) result = nil case symbol when /^::(.*)/ result = toplevel.find_symbol($1) when /::/ modules = symbol.split(/::/) unless modules.empty? module_name = modules.shift result = find_module_named(module_name) if result modules.each do |module_name| result = result.find_module_named(module_name) break unless result end end end else # if a method is specified, then we're definitely looking for # a module, otherwise it could be any symbol if method result = find_module_named(symbol) else result = find_local_symbol(symbol) if result.nil? if symbol =~ /^[A-Z]/ result = parent while result && result.name != symbol result = result.parent end end end end end if result && method if !result.respond_to?(:find_local_symbol) p result.name p method fail end result = result.find_local_symbol(method) end result end def find_local_symbol(symbol) res = find_method_named(symbol) || find_constant_named(symbol) || find_attribute_named(symbol) || find_module_named(symbol) end # Handle sections def set_current_section(title, comment) @current_section = Section.new(title, comment) @sections << @current_section end private # Find a named method, or return nil def find_method_named(name) @method_list.find {|meth| meth.name == name} end # Find a named instance method, or return nil def find_instance_method_named(name) @method_list.find {|meth| meth.name == name && !meth.singleton} end # Find a named constant, or return nil def find_constant_named(name) @constants.find {|m| m.name == name} end # Find a named attribute, or return nil def find_attribute_named(name) @attributes.find {|m| m.name == name} end end # A TopLevel context is a source file class TopLevel < Context attr_accessor :file_stat attr_accessor :file_relative_name attr_accessor :file_absolute_name attr_accessor :diagram @@all_classes = {} @@all_modules = {} def TopLevel::reset @@all_classes = {} @@all_modules = {} end def initialize(file_name) super() @name = "TopLevel" @file_relative_name = file_name @file_absolute_name = file_name @file_stat = File.stat(file_name) @diagram = nil end def full_name nil end # Adding a class or module to a TopLevel is special, as we only # want one copy of a particular top-level class. For example, # if both file A and file B implement class C, we only want one # ClassModule object for C. This code arranges to share # classes and modules between files. def add_class_or_module(collection, class_type, name, superclass) cls = collection[name] if cls puts "Reusing class/module #{name}" if $DEBUG else if class_type == NormalModule all = @@all_modules else all = @@all_classes end cls = all[name] if !cls cls = class_type.new(name, superclass) all[name] = cls unless @done_documenting end puts "Adding class/module #{name} to #@name" if $DEBUG collection[name] = cls unless @done_documenting cls.parent = self end cls end def TopLevel.all_classes_and_modules @@all_classes.values + @@all_modules.values end def TopLevel.find_class_named(name) @@all_classes.each_value do |c| res = c.find_class_named(name) return res if res end nil end def find_local_symbol(symbol) find_class_or_module_named(symbol) || super end def find_class_or_module_named(symbol) @@all_classes.each_value {|c| return c if c.name == symbol} @@all_modules.each_value {|m| return m if m.name == symbol} nil end # Find a named module def find_module_named(name) find_class_or_module_named(name) || find_enclosing_module_named(name) end end # ClassModule is the base class for objects representing either a # class or a module. class ClassModule < Context attr_reader :superclass attr_accessor :diagram def initialize(name, superclass = nil) @name = name @diagram = nil @superclass = superclass @comment = "" super() end # Return the fully qualified name of this class or module def full_name if @parent && @parent.full_name @parent.full_name + "::" + @name else @name end end def http_url(prefix) path = full_name.split("::") File.join(prefix, *path) + ".html" end # Return +true+ if this object represents a module def is_module? false end # to_s is simply for debugging def to_s res = self.class.name + ": " + @name res << @comment.to_s res << super res end def find_class_named(name) return self if full_name == name @classes.each_value {|c| return c if c.find_class_named(name) } nil end end # Anonymous classes class AnonClass < ClassModule end # Normal classes class NormalClass < ClassModule end # Singleton classes class SingleClass < ClassModule end # Module class NormalModule < ClassModule def is_module? true end end # AnyMethod is the base class for objects representing methods class AnyMethod < CodeObject attr_accessor :name attr_accessor :visibility attr_accessor :block_params attr_accessor :dont_rename_initialize attr_accessor :singleton attr_reader :aliases # list of other names for this method attr_accessor :is_alias_for # or a method we're aliasing attr_overridable :params, :param, :parameters, :parameter attr_accessor :call_seq include TokenStream def initialize(text, name) super() @text = text @name = name @token_stream = nil @visibility = :public @dont_rename_initialize = false @block_params = nil @aliases = [] @is_alias_for = nil @comment = "" @call_seq = nil end def <=>(other) @name <=> other.name end def to_s res = self.class.name + ": " + @name + " (" + @text + ")\n" res << @comment.to_s res end def param_seq p = params.gsub(/\s*\#.*/, '') p = p.tr("\n", " ").squeeze(" ") p = "(" + p + ")" unless p[0] == ?( if (block = block_params) # If this method has explicit block parameters, remove any # explicit &block $stderr.puts p p.sub!(/,?\s*&\w+/) $stderr.puts p block.gsub!(/\s*\#.*/, '') block = block.tr("\n", " ").squeeze(" ") if block[0] == ?( block.sub!(/^\(/, '').sub!(/\)/, '') end p << " {|#{block}| ...}" end p end def add_alias(method) @aliases << method end end # Represent an alias, which is an old_name/ new_name pair associated # with a particular context class Alias < CodeObject attr_accessor :text, :old_name, :new_name, :comment def initialize(text, old_name, new_name, comment) super() @text = text @old_name = old_name @new_name = new_name self.comment = comment end def to_s "alias: #{self.old_name} -> #{self.new_name}\n#{self.comment}" end end # Represent a constant class Constant < CodeObject attr_accessor :name, :value def initialize(name, value, comment) super() @name = name @value = value self.comment = comment end end # Represent attributes class Attr < CodeObject attr_accessor :text, :name, :rw, :visibility def initialize(text, name, rw, comment) super() @text = text @name = name @rw = rw @visibility = :public self.comment = comment end def to_s "attr: #{self.name} #{self.rw}\n#{self.comment}" end def <=>(other) self.name <=> other.name end end # a required file class Require < CodeObject attr_accessor :name def initialize(name, comment) super() @name = name.gsub(/'|"/, "") #' self.comment = comment end end # an included module class Include < CodeObject attr_accessor :name def initialize(name, comment) super() @name = name self.comment = comment end end end PK|]Lف//rdoc/diagram.rbnu[# A wonderful hack by to draw package diagrams using the dot package. # Originally written by Jah, team Enticla. # # You must have the V1.7 or later in your path # http://www.research.att.com/sw/tools/graphviz/ require "rdoc/dot/dot" require 'rdoc/options' module RDoc # Draw a set of diagrams representing the modules and classes in the # system. We draw one diagram for each file, and one for each toplevel # class or module. This means there will be overlap. However, it also # means that you'll get better context for objects. # # To use, simply # # d = Diagram.new(info) # pass in collection of top level infos # d.draw # # The results will be written to the +dot+ subdirectory. The process # also sets the +diagram+ attribute in each object it graphs to # the name of the file containing the image. This can be used # by output generators to insert images. class Diagram FONT = "Arial" DOT_PATH = "dot" # Pass in the set of top level objects. The method also creates # the subdirectory to hold the images def initialize(info, options) @info = info @options = options @counter = 0 File.makedirs(DOT_PATH) @diagram_cache = {} end # Draw the diagrams. We traverse the files, drawing a diagram for # each. We also traverse each top-level class and module in that # file drawing a diagram for these too. def draw unless @options.quiet $stderr.print "Diagrams: " $stderr.flush end @info.each_with_index do |i, file_count| @done_modules = {} @local_names = find_names(i) @global_names = [] @global_graph = graph = DOT::DOTDigraph.new('name' => 'TopLevel', 'fontname' => FONT, 'fontsize' => '8', 'bgcolor' => 'lightcyan1', 'compound' => 'true') # it's a little hack %) i'm too lazy to create a separate class # for default node graph << DOT::DOTNode.new('name' => 'node', 'fontname' => FONT, 'color' => 'black', 'fontsize' => 8) i.modules.each do |mod| draw_module(mod, graph, true, i.file_relative_name) end add_classes(i, graph, i.file_relative_name) i.diagram = convert_to_png("f_#{file_count}", graph) # now go through and document each top level class and # module independently i.modules.each_with_index do |mod, count| @done_modules = {} @local_names = find_names(mod) @global_names = [] @global_graph = graph = DOT::DOTDigraph.new('name' => 'TopLevel', 'fontname' => FONT, 'fontsize' => '8', 'bgcolor' => 'lightcyan1', 'compound' => 'true') graph << DOT::DOTNode.new('name' => 'node', 'fontname' => FONT, 'color' => 'black', 'fontsize' => 8) draw_module(mod, graph, true) mod.diagram = convert_to_png("m_#{file_count}_#{count}", graph) end end $stderr.puts unless @options.quiet end ####### private ####### def find_names(mod) return [mod.full_name] + mod.classes.collect{|cl| cl.full_name} + mod.modules.collect{|m| find_names(m)}.flatten end def find_full_name(name, mod) full_name = name.dup return full_name if @local_names.include?(full_name) mod_path = mod.full_name.split('::')[0..-2] unless mod_path.nil? until mod_path.empty? full_name = mod_path.pop + '::' + full_name return full_name if @local_names.include?(full_name) end end return name end def draw_module(mod, graph, toplevel = false, file = nil) return if @done_modules[mod.full_name] and not toplevel @counter += 1 url = mod.http_url("classes") m = DOT::DOTSubgraph.new('name' => "cluster_#{mod.full_name.gsub( /:/,'_' )}", 'label' => mod.name, 'fontname' => FONT, 'color' => 'blue', 'style' => 'filled', 'URL' => %{"#{url}"}, 'fillcolor' => toplevel ? 'palegreen1' : 'palegreen3') @done_modules[mod.full_name] = m add_classes(mod, m, file) graph << m unless mod.includes.empty? mod.includes.each do |m| m_full_name = find_full_name(m.name, mod) if @local_names.include?(m_full_name) @global_graph << DOT::DOTEdge.new('from' => "#{m_full_name.gsub( /:/,'_' )}", 'to' => "#{mod.full_name.gsub( /:/,'_' )}", 'ltail' => "cluster_#{m_full_name.gsub( /:/,'_' )}", 'lhead' => "cluster_#{mod.full_name.gsub( /:/,'_' )}") else unless @global_names.include?(m_full_name) path = m_full_name.split("::") url = File.join('classes', *path) + ".html" @global_graph << DOT::DOTNode.new('name' => "#{m_full_name.gsub( /:/,'_' )}", 'shape' => 'box', 'label' => "#{m_full_name}", 'URL' => %{"#{url}"}) @global_names << m_full_name end @global_graph << DOT::DOTEdge.new('from' => "#{m_full_name.gsub( /:/,'_' )}", 'to' => "#{mod.full_name.gsub( /:/,'_' )}", 'lhead' => "cluster_#{mod.full_name.gsub( /:/,'_' )}") end end end end def add_classes(container, graph, file = nil ) use_fileboxes = Options.instance.fileboxes files = {} # create dummy node (needed if empty and for module includes) if container.full_name graph << DOT::DOTNode.new('name' => "#{container.full_name.gsub( /:/,'_' )}", 'label' => "", 'width' => (container.classes.empty? and container.modules.empty?) ? '0.75' : '0.01', 'height' => '0.01', 'shape' => 'plaintext') end container.classes.each_with_index do |cl, cl_index| last_file = cl.in_files[-1].file_relative_name if use_fileboxes && !files.include?(last_file) @counter += 1 files[last_file] = DOT::DOTSubgraph.new('name' => "cluster_#{@counter}", 'label' => "#{last_file}", 'fontname' => FONT, 'color'=> last_file == file ? 'red' : 'black') end next if cl.name == 'Object' || cl.name[0,2] == "<<" url = cl.http_url("classes") label = cl.name.dup if use_fileboxes && cl.in_files.length > 1 label << '\n[' + cl.in_files.collect {|i| i.file_relative_name }.sort.join( '\n' ) + ']' end attrs = { 'name' => "#{cl.full_name.gsub( /:/, '_' )}", 'fontcolor' => 'black', 'style'=>'filled', 'color'=>'palegoldenrod', 'label' => label, 'shape' => 'ellipse', 'URL' => %{"#{url}"} } c = DOT::DOTNode.new(attrs) if use_fileboxes files[last_file].push c else graph << c end end if use_fileboxes files.each_value do |val| graph << val end end unless container.classes.empty? container.classes.each_with_index do |cl, cl_index| cl.includes.each do |m| m_full_name = find_full_name(m.name, cl) if @local_names.include?(m_full_name) @global_graph << DOT::DOTEdge.new('from' => "#{m_full_name.gsub( /:/,'_' )}", 'to' => "#{cl.full_name.gsub( /:/,'_' )}", 'ltail' => "cluster_#{m_full_name.gsub( /:/,'_' )}") else unless @global_names.include?(m_full_name) path = m_full_name.split("::") url = File.join('classes', *path) + ".html" @global_graph << DOT::DOTNode.new('name' => "#{m_full_name.gsub( /:/,'_' )}", 'shape' => 'box', 'label' => "#{m_full_name}", 'URL' => %{"#{url}"}) @global_names << m_full_name end @global_graph << DOT::DOTEdge.new('from' => "#{m_full_name.gsub( /:/,'_' )}", 'to' => "#{cl.full_name.gsub( /:/, '_')}") end end sclass = cl.superclass next if sclass.nil? || sclass == 'Object' sclass_full_name = find_full_name(sclass,cl) unless @local_names.include?(sclass_full_name) or @global_names.include?(sclass_full_name) path = sclass_full_name.split("::") url = File.join('classes', *path) + ".html" @global_graph << DOT::DOTNode.new( 'name' => "#{sclass_full_name.gsub( /:/, '_' )}", 'label' => sclass_full_name, 'URL' => %{"#{url}"}) @global_names << sclass_full_name end @global_graph << DOT::DOTEdge.new('from' => "#{sclass_full_name.gsub( /:/,'_' )}", 'to' => "#{cl.full_name.gsub( /:/, '_')}") end end container.modules.each do |submod| draw_module(submod, graph) end end def convert_to_png(file_base, graph) str = graph.to_s return @diagram_cache[str] if @diagram_cache[str] op_type = Options.instance.image_format dotfile = File.join(DOT_PATH, file_base) src = dotfile + ".dot" dot = dotfile + "." + op_type unless @options.quiet $stderr.print "." $stderr.flush end File.open(src, 'w+' ) do |f| f << str << "\n" end system "dot", "-T#{op_type}", src, "-o", dot # Now construct the imagemap wrapper around # that png ret = wrap_in_image_map(src, dot) @diagram_cache[str] = ret return ret end # Extract the client-side image map from dot, and use it # to generate the imagemap proper. Return the whole # .. combination, suitable for inclusion on # the page def wrap_in_image_map(src, dot) res = %{\n} dot_map = `dot -Tismap #{src}` dot_map.each do |area| unless area =~ /^rectangle \((\d+),(\d+)\) \((\d+),(\d+)\) ([\/\w.]+)\s*(.*)/ $stderr.puts "Unexpected output from dot:\n#{area}" return nil end xs, ys = [$1.to_i, $3.to_i], [$2.to_i, $4.to_i] url, area_name = $5, $6 res << %{ #{area_name}\n} end res << "\n" # map_file = src.sub(/.dot/, '.map') # system("dot -Timap #{src} -o #{map_file}") res << %{#{dot}} return res end end end PK|]@K{{rdoc/dot/dot.rbnu[module DOT # these glogal vars are used to make nice graph source $tab = ' ' $tab2 = $tab * 2 # if we don't like 4 spaces, we can change it any time def change_tab( t ) $tab = t $tab2 = t * 2 end # options for node declaration NODE_OPTS = [ 'bgcolor', 'color', 'fontcolor', 'fontname', 'fontsize', 'height', 'width', 'label', 'layer', 'rank', 'shape', 'shapefile', 'style', 'URL', ] # options for edge declaration EDGE_OPTS = [ 'color', 'decorate', 'dir', 'fontcolor', 'fontname', 'fontsize', 'id', 'label', 'layer', 'lhead', 'ltail', 'minlen', 'style', 'weight' ] # options for graph declaration GRAPH_OPTS = [ 'bgcolor', 'center', 'clusterrank', 'color', 'compound', 'concentrate', 'fillcolor', 'fontcolor', 'fontname', 'fontsize', 'label', 'layerseq', 'margin', 'mclimit', 'nodesep', 'nslimit', 'ordering', 'orientation', 'page', 'rank', 'rankdir', 'ranksep', 'ratio', 'size', 'style', 'URL' ] # a root class for any element in dot notation class DOTSimpleElement attr_accessor :name def initialize( params = {} ) @label = params['name'] ? params['name'] : '' end def to_s @name end end # an element that has options ( node, edge or graph ) class DOTElement < DOTSimpleElement #attr_reader :parent attr_accessor :name, :options def initialize( params = {}, option_list = [] ) super( params ) @name = params['name'] ? params['name'] : nil @parent = params['parent'] ? params['parent'] : nil @options = {} option_list.each{ |i| @options[i] = params[i] if params[i] } @options['label'] ||= @name if @name != 'node' end def each_option @options.each{ |i| yield i } end def each_option_pair @options.each_pair{ |key, val| yield key, val } end #def parent=( thing ) # @parent.delete( self ) if defined?( @parent ) and @parent # @parent = thing #end end # this is used when we build nodes that have shape=record # ports don't have options :) class DOTPort < DOTSimpleElement attr_accessor :label def initialize( params = {} ) super( params ) @name = params['label'] ? params['label'] : '' end def to_s ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}" end end # node element class DOTNode < DOTElement def initialize( params = {}, option_list = NODE_OPTS ) super( params, option_list ) @ports = params['ports'] ? params['ports'] : [] end def each_port @ports.each{ |i| yield i } end def << ( thing ) @ports << thing end def push ( thing ) @ports.push( thing ) end def pop @ports.pop end def to_s( t = '' ) label = @options['shape'] != 'record' && @ports.length == 0 ? @options['label'] ? t + $tab + "label = \"#{@options['label']}\"\n" : '' : t + $tab + 'label = "' + " \\\n" + t + $tab2 + "#{@options['label']}| \\\n" + @ports.collect{ |i| t + $tab2 + i.to_s }.join( "| \\\n" ) + " \\\n" + t + $tab + '"' + "\n" t + "#{@name} [\n" + @options.to_a.collect{ |i| i[1] && i[0] != 'label' ? t + $tab + "#{i[0]} = #{i[1]}" : nil }.compact.join( ",\n" ) + ( label != '' ? ",\n" : "\n" ) + label + t + "]\n" end end # subgraph element is the same to graph, but has another header in dot # notation class DOTSubgraph < DOTElement def initialize( params = {}, option_list = GRAPH_OPTS ) super( params, option_list ) @nodes = params['nodes'] ? params['nodes'] : [] @dot_string = 'subgraph' end def each_node @nodes.each{ |i| yield i } end def << ( thing ) @nodes << thing end def push( thing ) @nodes.push( thing ) end def pop @nodes.pop end def to_s( t = '' ) hdr = t + "#{@dot_string} #{@name} {\n" options = @options.to_a.collect{ |name, val| val && name != 'label' ? t + $tab + "#{name} = #{val}" : name ? t + $tab + "#{name} = \"#{val}\"" : nil }.compact.join( "\n" ) + "\n" nodes = @nodes.collect{ |i| i.to_s( t + $tab ) }.join( "\n" ) + "\n" hdr + options + nodes + t + "}\n" end end # this is graph class DOTDigraph < DOTSubgraph def initialize( params = {}, option_list = GRAPH_OPTS ) super( params, option_list ) @dot_string = 'digraph' end end # this is edge class DOTEdge < DOTElement attr_accessor :from, :to def initialize( params = {}, option_list = EDGE_OPTS ) super( params, option_list ) @from = params['from'] ? params['from'] : nil @to = params['to'] ? params['to'] : nil end def to_s( t = '' ) t + "#{@from} -> #{to} [\n" + @options.to_a.collect{ |i| i[1] && i[0] != 'label' ? t + $tab + "#{i[0]} = #{i[1]}" : i[1] ? t + $tab + "#{i[0]} = \"#{i[1]}\"" : nil }.compact.join( "\n" ) + "\n" + t + "]\n" end end end PK|]%l@@rdoc/template.rbnu[# Cheap-n-cheerful HTML page template system. You create a # template containing: # # * variable names between percent signs (%fred%) # * blocks of repeating stuff: # # START:key # ... stuff # END:key # # You feed the code a hash. For simple variables, the values # are resolved directly from the hash. For blocks, the hash entry # corresponding to +key+ will be an array of hashes. The block will # be generated once for each entry. Blocks can be nested arbitrarily # deeply. # # The template may also contain # # IF:key # ... stuff # ENDIF:key # # _stuff_ will only be included in the output if the corresponding # key is set in the value hash. # # Usage: Given a set of templates T1, T2, etc # # values = { "name" => "Dave", state => "TX" } # # t = TemplatePage.new(T1, T2, T3) # File.open(name, "w") {|f| t.write_html_on(f, values)} # or # res = '' # t.write_html_on(res, values) # # class TemplatePage ########## # A context holds a stack of key/value pairs (like a symbol # table). When asked to resolve a key, it first searches the top of # the stack, then the next level, and so on until it finds a match # (or runs out of entries) class Context def initialize @stack = [] end def push(hash) @stack.push(hash) end def pop @stack.pop end # Find a scalar value, throwing an exception if not found. This # method is used when substituting the %xxx% constructs def find_scalar(key) @stack.reverse_each do |level| if val = level[key] return val unless val.kind_of? Array end end raise "Template error: can't find variable '#{key}'" end # Lookup any key in the stack of hashes def lookup(key) @stack.reverse_each do |level| val = level[key] return val if val end nil end end ######### # Simple class to read lines out of a string class LineReader # we're initialized with an array of lines def initialize(lines) @lines = lines end # read the next line def read @lines.shift end # Return a list of lines up to the line that matches # a pattern. That last line is discarded. def read_up_to(pattern) res = [] while line = read if pattern.match(line) return LineReader.new(res) else res << line end end raise "Missing end tag in template: #{pattern.source}" end # Return a copy of ourselves that can be modified without # affecting us def dup LineReader.new(@lines.dup) end end # +templates+ is an array of strings containing the templates. # We start at the first, and substitute in subsequent ones # where the string !INCLUDE! occurs. For example, # we could have the overall page template containing # # #

    Master

    # !INCLUDE! # # # and substitute subpages in to it by passing [master, sub_page]. # This gives us a cheap way of framing pages def initialize(*templates) result = "!INCLUDE!" templates.each do |content| result.sub!(/!INCLUDE!/, content) end @lines = LineReader.new(result.split($/)) end # Render the templates into HTML, storing the result on +op+ # using the method <<. The value_hash contains # key/value pairs used to drive the substitution (as described above) def write_html_on(op, value_hash) @context = Context.new op << substitute_into(@lines, value_hash).tr("\000", '\\') end # Substitute a set of key/value pairs into the given template. # Keys with scalar values have them substituted directly into # the page. Those with array values invoke substitute_array # (below), which examples a block of the template once for each # row in the array. # # This routine also copes with the IF:_key_ directive, # removing chunks of the template if the corresponding key # does not appear in the hash, and the START: directive, which # loops its contents for each value in an array def substitute_into(lines, values) @context.push(values) skip_to = nil result = [] while line = lines.read case line when /^IF:(\w+)/ lines.read_up_to(/^ENDIF:#$1/) unless @context.lookup($1) when /^IFNOT:(\w+)/ lines.read_up_to(/^ENDIF:#$1/) if @context.lookup($1) when /^ENDIF:/ ; when /^START:(\w+)/ tag = $1 body = lines.read_up_to(/^END:#{tag}/) inner_values = @context.lookup(tag) raise "unknown tag: #{tag}" unless inner_values raise "not array: #{tag}" unless inner_values.kind_of?(Array) inner_values.each do |vals| result << substitute_into(body.dup, vals) end else result << expand_line(line.dup) end end @context.pop result.join("\n") end # Given an individual line, we look for %xxx% constructs and # HREF:ref:name: constructs, substituting for each. def expand_line(line) # Generate a cross reference if a reference is given, # otherwise just fill in the name part line.gsub!(/HREF:(\w+?):(\w+?):/) { ref = @context.lookup($1) name = @context.find_scalar($2) if ref and !ref.kind_of?(Array) "#{name}" else name end } # Substitute in values for %xxx% constructs. This is made complex # because the replacement string may contain characters that are # meaningful to the regexp (like \1) line = line.gsub(/%([a-zA-Z]\w*)%/) { val = @context.find_scalar($1) val.tr('\\', "\000") } line rescue Exception => e $stderr.puts "Error in template: #{e}" $stderr.puts "Original line: #{line}" exit end end PK|]!! rdoc/rdoc.rbnu[# See README. # VERSION_STRING = %{RDoc V1.0.1 - 20041108} require 'rdoc/parsers/parse_rb.rb' require 'rdoc/parsers/parse_c.rb' require 'rdoc/parsers/parse_f95.rb' require 'rdoc/parsers/parse_simple.rb' require 'rdoc/options' require 'rdoc/diagram' require 'find' require 'ftools' require 'time' # We put rdoc stuff in the RDoc module to avoid namespace # clutter. # # ToDo: This isn't universally true. # # :include: README module RDoc # Name of the dotfile that contains the description of files to be # processed in the current directory DOT_DOC_FILENAME = ".document" # Simple stats collector class Stats attr_accessor :num_files, :num_classes, :num_modules, :num_methods def initialize @num_files = @num_classes = @num_modules = @num_methods = 0 @start = Time.now end def print puts "Files: #@num_files" puts "Classes: #@num_classes" puts "Modules: #@num_modules" puts "Methods: #@num_methods" puts "Elapsed: " + sprintf("%0.3fs", Time.now - @start) end end # Exception thrown by any rdoc error. Only the #message part is # of use externally. class RDocError < Exception end # Encapsulate the production of rdoc documentation. Basically # you can use this as you would invoke rdoc from the command # line: # # rdoc = RDoc::RDoc.new # rdoc.document(args) # # where _args_ is an array of strings, each corresponding to # an argument you'd give rdoc on the command line. See rdoc/rdoc.rb # for details. class RDoc ## # This is the list of output generators that we # support Generator = Struct.new(:file_name, :class_name, :key) GENERATORS = {} $:.collect {|d| File::expand_path(d) }.find_all {|d| File::directory?("#{d}/rdoc/generators") }.each {|dir| Dir::entries("#{dir}/rdoc/generators").each {|gen| next unless /(\w+)_generator.rb$/ =~ gen type = $1 unless GENERATORS.has_key? type GENERATORS[type] = Generator.new("rdoc/generators/#{gen}", "#{type.upcase}Generator".intern, type) end } } ####### private ####### ## # Report an error message and exit def error(msg) raise RDocError.new(msg) end ## # Create an output dir if it doesn't exist. If it does # exist, but doesn't contain the flag file created.rid # then we refuse to use it, as we may clobber some # manually generated documentation def setup_output_dir(op_dir, force) flag_file = output_flag_file(op_dir) if File.exist?(op_dir) unless File.directory?(op_dir) error "'#{op_dir}' exists, and is not a directory" end begin created = File.read(flag_file) rescue SystemCallError error "\nDirectory #{op_dir} already exists, but it looks like it\n" + "isn't an RDoc directory. Because RDoc doesn't want to risk\n" + "destroying any of your existing files, you'll need to\n" + "specify a different output directory name (using the\n" + "--op option).\n\n" else last = (Time.parse(created) unless force rescue nil) end else File.makedirs(op_dir) end last end # Update the flag file in an output directory. def update_output_dir(op_dir, time) File.open(output_flag_file(op_dir), "w") {|f| f.puts time.rfc2822 } end # Return the path name of the flag file in an output directory. def output_flag_file(op_dir) File.join(op_dir, "created.rid") end # The .document file contains a list of file and directory name # patterns, representing candidates for documentation. It may # also contain comments (starting with '#') def parse_dot_doc_file(in_dir, filename, options) # read and strip comments patterns = File.read(filename).gsub(/#.*/, '') result = [] patterns.split.each do |patt| candidates = Dir.glob(File.join(in_dir, patt)) result.concat(normalized_file_list(options, candidates)) end result end # Given a list of files and directories, create a list # of all the Ruby files they contain. # # If +force_doc+ is true, we always add the given files. # If false, only add files that we guarantee we can parse # It is true when looking at files given on the command line, # false when recursing through subdirectories. # # The effect of this is that if you want a file with a non- # standard extension parsed, you must name it explicity. # def normalized_file_list(options, relative_files, force_doc = false, exclude_pattern=nil) file_list = [] relative_files.each do |rel_file_name| next if exclude_pattern && exclude_pattern =~ rel_file_name stat = File.stat(rel_file_name) case type = stat.ftype when "file" next if @last_created and stat.mtime < @last_created file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name) when "directory" next if rel_file_name == "CVS" || rel_file_name == ".svn" dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME) if File.file?(dot_doc) file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options)) else file_list.concat(list_files_in_directory(rel_file_name, options)) end else raise RDocError.new("I can't deal with a #{type} #{rel_file_name}") end end file_list end # Return a list of the files to be processed in # a directory. We know that this directory doesn't have # a .document file, so we're looking for real files. However # we may well contain subdirectories which must # be tested for .document files def list_files_in_directory(dir, options) normalized_file_list(options, Dir.glob(File.join(dir, "*")), false, options.exclude) end # Parse each file on the command line, recursively entering # directories def parse_files(options) file_info = [] files = options.files files = ["."] if files.empty? file_list = normalized_file_list(options, files, true) file_list.each do |fn| $stderr.printf("\n%35s: ", File.basename(fn)) unless options.quiet content = File.open(fn, "r") {|f| f.read} top_level = TopLevel.new(fn) parser = ParserFactory.parser_for(top_level, fn, content, options, @stats) file_info << parser.scan @stats.num_files += 1 end file_info end public ################################################################### # # Format up one or more files according to the given arguments. # For simplicity, _argv_ is an array of strings, equivalent to the # strings that would be passed on the command line. (This isn't a # coincidence, as we _do_ pass in ARGV when running # interactively). For a list of options, see rdoc/rdoc.rb. By # default, output will be stored in a directory called +doc+ below # the current directory, so make sure you're somewhere writable # before invoking. # # Throws: RDocError on error def document(argv) TopLevel::reset @stats = Stats.new options = Options.instance options.parse(argv, GENERATORS) @last_created = nil unless options.all_one_file @last_created = setup_output_dir(options.op_dir, options.force_update) end start_time = Time.now file_info = parse_files(options) if file_info.empty? $stderr.puts "\nNo newer files." unless options.quiet else gen = options.generator $stderr.puts "\nGenerating #{gen.key.upcase}..." unless options.quiet require gen.file_name gen_class = Generators.const_get(gen.class_name) gen = gen_class.for(options) pwd = Dir.pwd Dir.chdir(options.op_dir) unless options.all_one_file begin Diagram.new(file_info, options).draw if options.diagram gen.generate(file_info) update_output_dir(".", start_time) ensure Dir.chdir(pwd) end end unless options.quiet puts @stats.print end end end end PK|]%`CC)rdoc/generators/template/html/old_html.rbnu[module RDoc # This is how you define the HTML that RDoc generates. Simply create # a file in rdoc/generators/html_templates that creates the # module RDoc::Page and populate it as described below. Then invoke # rdoc using the --template option, and # your template will be used. # # The constants defining pages use a simple templating system: # # * The templating system is passed a hash. Keys in the hash correspond # to tags on this page. The tag %abc% is looked up in the hash, # and is replaced by the corresponding hash value. # # * Some tags are optional. You can detect this using IF/ENDIF # # IF: title # The value of title is %title% # ENDIF: title # # * Some entries in the hash have values that are arrays, where each # entry in the array is itself a hash. These are used to generate # lists using the START: construct. For example, given a hash # containing # # { 'people' => [ { 'name' => 'Fred', 'age' => '12' }, # { 'name' => 'Mary', 'age' => '21' } ] # # You could generate a simple table using # # # START:people # # END:people #
    %name%%age%
    # # These lists can be nested to an arbitrary depth # # * the construct HREF:url:name: generates %name% # if +url+ is defined in the hash, or %name% otherwise. # # # Your file must contain the following constants # # [*FONTS*] a list of fonts to be used # [*STYLE*] a CSS section (without the START:entries %name%
    END:entries } CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = %{ %title% <body bgcolor="white"> Sorry, RDoc currently only generates HTML using frames. </body> } ###################################################################### # # The following is used for the -1 option # CONTENTS_XML = %{ IF:description %description% ENDIF:description IF:requires

    Requires:

      START:requires IF:aref
    • %name%
    • ENDIF:aref IFNOT:aref
    • %name%
    • ENDIF:aref END:requires
    ENDIF:requires IF:attributes

    Attributes

    START:attributes END:attributes
    %name%%rw%%a_desc%
    ENDIF:attributes IF:includes

    Includes

      START:includes IF:aref
    • %name%
    • ENDIF:aref IFNOT:aref
    • %name%
    • ENDIF:aref END:includes
    ENDIF:includes IF:method_list

    Methods

    START:method_list IF:methods START:methods

    %type% %category% method: %name%%params%

    IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode
    %sourcecode%
    
    ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } end end require 'rdoc/generators/template/html/one_page_html' PK|]aV""&rdoc/generators/template/html/hefss.rbnu[module RDoc module Page FONTS = "Verdana, Arial, Helvetica, sans-serif" STYLE = %{ body,p { font-family: Verdana, Arial, Helvetica, sans-serif; color: #000040; background: #BBBBBB; } td { font-family: Verdana, Arial, Helvetica, sans-serif; color: #000040; } .attr-rw { font-size: small; color: #444488 } .title-row {color: #eeeeff; background: #BBBBDD; } .big-title-font { color: white; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: large; height: 50px} .small-title-font { color: purple; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: small; } .aqua { color: purple } .method-name, attr-name { font-family: monospace; font-weight: bold; } .tablesubtitle { width: 100%; margin-top: 1ex; margin-bottom: .5ex; padding: 5px 0px 5px 20px; font-size: large; color: purple; background: #BBBBCC; } .tablesubsubtitle { width: 100%; margin-top: 1ex; margin-bottom: .5ex; padding: 5px 0px 5px 20px; font-size: medium; color: white; background: #BBBBCC; } .name-list { font-family: monospace; margin-left: 40px; margin-bottom: 2ex; line-height: 140%; } .description { margin-left: 40px; margin-bottom: 2ex; line-height: 140%; } .methodtitle { font-size: medium; text_decoration: none; padding: 3px 3px 3px 20px; color: #0000AA; } .column-title { font-size: medium; font-weight: bold; text_decoration: none; padding: 3px 3px 3px 20px; color: #3333CC; } .variable-name { font-family: monospace; font-size: medium; text_decoration: none; padding: 3px 3px 3px 20px; color: #0000AA; } .row-name { font-size: medium; font-weight: medium; font-family: monospace; text_decoration: none; padding: 3px 3px 3px 20px; } .paramsig { font-size: small; } .srcbut { float: right } } ############################################################################ BODY = %{ %title% !INCLUDE! IF:diagram
    %diagram%
    ENDIF:diagram IF:description
    %description%
    ENDIF:description IF:requires
    Required files

    START:requires HREF:aref:name: END:requires ENDIF:requires
    IF:methods
    Subroutines and Functions

    START:methods HREF:aref:name:, END:methods
    ENDIF:methods IF:attributes
    Arguments

    START:attributes IF:rw ENDIF:rw IFNOT:rw ENDIF:rw END:attributes
     [%rw%] %name% %a_desc%
    ENDIF:attributes IF:classlist
    Modules

    %classlist%
    ENDIF:classlist !INCLUDE! } ############################################################################### FILE_PAGE = <<_FILE_PAGE_
    File
    %short_name%
    Path: %full_path% IF:cvsurl  (CVS) ENDIF:cvsurl
    Modified: %dtm_modified%

    _FILE_PAGE_ ################################################################### CLASS_PAGE = %{
    %classmod%
    %full_name%
    IF:parent ENDIF:parent
    In: START:infiles HREF:full_path_url:full_path: IF:cvsurl  (CVS) ENDIF:cvsurl END:infiles
    Parent: IF:par_url ENDIF:par_url %parent% IF:par_url ENDIF:par_url

    } ################################################################### METHOD_LIST = %{ IF:includes
    Uses

    START:includes HREF:aref:name: END:includes
    ENDIF:includes IF:method_list START:method_list IF:methods
    %type% %category% methods
    START:methods
    %name%%params% IF:codeurl src ENDIF:codeurl
    IF:m_desc
    %m_desc%
    ENDIF:m_desc END:methods ENDIF:methods END:method_list ENDIF:method_list } =begin =end ########################## Source code ########################## SRC_PAGE = %{ %title%
    %code%
    } ########################## Index ################################ FR_INDEX_BODY = %{ !INCLUDE! } FILE_INDEX = %{ START:entries %name%
    END:entries } CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = %{ %title% <body bgcolor="#BBBBBB"> Click <a href="html/index.html">here</a> for a non-frames version of this page. </body> } # and a blank page to use as a target BLANK = %{ } def write_extra_pages template = TemplatePage.new(BLANK) File.open("blank.html", "w") { |f| template.write_html_on(f, {}) } end end end PK|](g%O#O#'rdoc/generators/template/html/kilmer.rbnu[module RDoc module Page FONTS = "Verdana, Arial, Helvetica, sans-serif" STYLE = %{ body,td,p { font-family: %fonts%; color: #000040; } .attr-rw { font-size: xx-small; color: #444488 } .title-row { background-color: #CCCCFF; color: #000010; } .big-title-font { color: black; font-weight: bold; font-family: %fonts%; font-size: large; height: 60px; padding: 10px 3px 10px 3px; } .small-title-font { color: black; font-family: %fonts%; font-size:10; } .aqua { color: black } .method-name, .attr-name { font-family: font-family: %fonts%; font-weight: bold; font-size: small; margin-left: 20px; color: #000033; } .tablesubtitle, .tablesubsubtitle { width: 100%; margin-top: 1ex; margin-bottom: .5ex; padding: 5px 0px 5px 3px; font-size: large; color: black; background-color: #CCCCFF; border: thin; } .name-list { margin-left: 5px; margin-bottom: 2ex; line-height: 105%; } .description { margin-left: 5px; margin-bottom: 2ex; line-height: 105%; font-size: small; } .methodtitle { font-size: small; font-weight: bold; text-decoration: none; color: #000033; background-color: white; } .srclink { font-size: small; font-weight: bold; text-decoration: none; color: #0000DD; background-color: white; } .paramsig { font-size: small; } .srcbut { float: right } } ############################################################################ BODY = %{ %title% !INCLUDE! IF:diagram
    %diagram%
    ENDIF:diagram IF:description
    %description%
    ENDIF:description IF:requires
    Required files

    START:requires HREF:aref:name: END:requires ENDIF:requires
    IF:methods
    Methods

    START:methods HREF:aref:name:, END:methods
    ENDIF:methods START:sections
    IF:sectitle

    %sectitle%

    IF:seccomment
    %seccomment%
    ENDIF:seccomment ENDIF:sectitle IF:attributes
    Attributes

    START:attributes IF:rw ENDIF:rw IFNOT:rw ENDIF:rw END:attributes
     [%rw%] %name% %a_desc%
    ENDIF:attributes IF:classlist
    Classes and Modules

    %classlist%
    ENDIF:classlist !INCLUDE! END:sections } ############################################################################### FILE_PAGE = <<_FILE_PAGE_
    File
    %short_name%
    Path: %full_path% IF:cvsurl  (CVS) ENDIF:cvsurl
    Modified: %dtm_modified%

    _FILE_PAGE_ ################################################################### CLASS_PAGE = %{
    %classmod%
    %full_name%
    IF:parent ENDIF:parent
    In: START:infiles HREF:full_path_url:full_path: IF:cvsurl  (CVS) ENDIF:cvsurl END:infiles
    Parent: IF:par_url ENDIF:par_url %parent% IF:par_url ENDIF:par_url

    } ################################################################### METHOD_LIST = %{ IF:includes
    Included modules

    START:includes HREF:aref:name: END:includes
    ENDIF:includes IF:method_list START:method_list IF:methods
    %type% %category% methods
    START:methods
    IF:callseq %callseq% ENDIF:callseq IFNOT:callseq %name%%params% ENDIF:callseq IF:codeurl src ENDIF:codeurl
    IF:m_desc
    %m_desc%
    ENDIF:m_desc IF:aka
    This method is also aliased as START:aka %name% END:aka
    ENDIF:aka IF:sourcecode
    %sourcecode%
    
    ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } =begin =end ########################## Source code ########################## SRC_PAGE = %{ %title%
    %code%
    } ########################## Index ################################ FR_INDEX_BODY = %{ !INCLUDE! } FILE_INDEX = %{ START:entries %name%
    END:entries } CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = %{ %title% IF:inline_source ENDIF:inline_source IFNOT:inline_source ENDIF:inline_source <body bgcolor="white"> Click <a href="html/index.html">here</a> for a non-frames version of this page. </body> } # and a blank page to use as a target BLANK = %{ } def write_extra_pages template = TemplatePage.new(BLANK) File.open("blank.html", "w") { |f| template.write_html_on(f, {}) } end end end PK|]d8f?f?%rdoc/generators/template/html/html.rbnu[# # = CSS2 RDoc HTML template # # This is a template for RDoc that uses XHTML 1.0 Transitional and dictates a # bit more of the appearance of the output to cascading stylesheets than the # default. It was designed for clean inline code display, and uses DHTMl to # toggle the visbility of each method's source with each click on the '[source]' # link. # # == Authors # # * Michael Granger # # Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved. # # This work is licensed under the Creative Commons Attribution License. To view # a copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or # send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California # 94305, USA. # module RDoc module Page FONTS = "Verdana,Arial,Helvetica,sans-serif" STYLE = %{ body { font-family: Verdana,Arial,Helvetica,sans-serif; font-size: 90%; margin: 0; margin-left: 40px; padding: 0; background: white; } h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; } h1 { font-size: 150%; } h2,h3,h4 { margin-top: 1em; } a { background: #eef; color: #039; text-decoration: none; } a:hover { background: #039; color: #eef; } /* Override the base stylesheet's Anchor inside a table cell */ td > a { background: transparent; color: #039; text-decoration: none; } /* and inside a section title */ .section-title > a { background: transparent; color: #eee; text-decoration: none; } /* === Structural elements =================================== */ div#index { margin: 0; margin-left: -40px; padding: 0; font-size: 90%; } div#index a { margin-left: 0.7em; } div#index .section-bar { margin-left: 0px; padding-left: 0.7em; background: #ccc; font-size: small; } div#classHeader, div#fileHeader { width: auto; color: white; padding: 0.5em 1.5em 0.5em 1.5em; margin: 0; margin-left: -40px; border-bottom: 3px solid #006; } div#classHeader a, div#fileHeader a { background: inherit; color: white; } div#classHeader td, div#fileHeader td { background: inherit; color: white; } div#fileHeader { background: #057; } div#classHeader { background: #048; } .class-name-in-header { font-size: 180%; font-weight: bold; } div#bodyContent { padding: 0 1.5em 0 1.5em; } div#description { padding: 0.5em 1.5em; background: #efefef; border: 1px dotted #999; } div#description h1,h2,h3,h4,h5,h6 { color: #125;; background: transparent; } div#validator-badges { text-align: center; } div#validator-badges img { border: 0; } div#copyright { color: #333; background: #efefef; font: 0.75em sans-serif; margin-top: 5em; margin-bottom: 0; padding: 0.5em 2em; } /* === Classes =================================== */ table.header-table { color: white; font-size: small; } .type-note { font-size: small; color: #DEDEDE; } .xxsection-bar { background: #eee; color: #333; padding: 3px; } .section-bar { color: #333; border-bottom: 1px solid #999; margin-left: -20px; } .section-title { background: #79a; color: #eee; padding: 3px; margin-top: 2em; margin-left: -30px; border: 1px solid #999; } .top-aligned-row { vertical-align: top } .bottom-aligned-row { vertical-align: bottom } /* --- Context section classes ----------------------- */ .context-row { } .context-item-name { font-family: monospace; font-weight: bold; color: black; } .context-item-value { font-size: small; color: #448; } .context-item-desc { color: #333; padding-left: 2em; } /* --- Method classes -------------------------- */ .method-detail { background: #efefef; padding: 0; margin-top: 0.5em; margin-bottom: 1em; border: 1px dotted #ccc; } .method-heading { color: black; background: #ccc; border-bottom: 1px solid #666; padding: 0.2em 0.5em 0 0.5em; } .method-signature { color: black; background: inherit; } .method-name { font-weight: bold; } .method-args { font-style: italic; } .method-description { padding: 0 0.5em 0 0.5em; } /* --- Source code sections -------------------- */ a.source-toggle { font-size: 90%; } div.method-source-code { background: #262626; color: #ffdead; margin: 1em; padding: 0.5em; border: 1px dashed #999; overflow: hidden; } div.method-source-code pre { color: #ffdead; overflow: hidden; } /* --- Ruby keyword styles --------------------- */ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; } .ruby-constant { color: #7fffd4; background: transparent; } .ruby-keyword { color: #00ffff; background: transparent; } .ruby-ivar { color: #eedd82; background: transparent; } .ruby-operator { color: #00ffee; background: transparent; } .ruby-identifier { color: #ffdead; background: transparent; } .ruby-node { color: #ffa07a; background: transparent; } .ruby-comment { color: #b22222; font-weight: bold; background: transparent; } .ruby-regexp { color: #ffa07a; background: transparent; } .ruby-value { color: #7fffd4; background: transparent; } } ##################################################################### ### H E A D E R T E M P L A T E ##################################################################### XHTML_PREAMBLE = %{ } HEADER = XHTML_PREAMBLE + %{ %title% } ##################################################################### ### C O N T E X T C O N T E N T T E M P L A T E ##################################################################### CONTEXT_CONTENT = %{ } ##################################################################### ### F O O T E R T E M P L A T E ##################################################################### FOOTER = %{ } ##################################################################### ### F I L E P A G E H E A D E R T E M P L A T E ##################################################################### FILE_PAGE = %{

    %short_name%

    Path: %full_path% IF:cvsurl  (CVS) ENDIF:cvsurl
    Last Update: %dtm_modified%
    } ##################################################################### ### C L A S S P A G E H E A D E R T E M P L A T E ##################################################################### CLASS_PAGE = %{
    IF:parent ENDIF:parent
    %classmod% %full_name%
    In: START:infiles IF:full_path_url ENDIF:full_path_url %full_path% IF:full_path_url ENDIF:full_path_url IF:cvsurl  (CVS) ENDIF:cvsurl
    END:infiles
    Parent: IF:par_url ENDIF:par_url %parent% IF:par_url ENDIF:par_url
    } ##################################################################### ### M E T H O D L I S T T E M P L A T E ##################################################################### METHOD_LIST = %{
    IF:diagram
    %diagram%
    ENDIF:diagram IF:description
    %description%
    ENDIF:description IF:requires

    Required files

    START:requires HREF:aref:name:   END:requires
    ENDIF:requires IF:toc

    Contents

    ENDIF:toc
    IF:methods

    Methods

    START:methods HREF:aref:name:   END:methods
    ENDIF:methods
    IF:includes

    Included Modules

    START:includes HREF:aref:name: END:includes
    ENDIF:includes START:sections
    IF:sectitle

    %sectitle%

    IF:seccomment
    %seccomment%
    ENDIF:seccomment ENDIF:sectitle IF:classlist

    Classes and Modules

    %classlist%
    ENDIF:classlist IF:constants

    Constants

    START:constants IF:desc ENDIF:desc END:constants
    %name% = %value%  %desc%
    ENDIF:constants IF:aliases

    External Aliases

    START:aliases IF:desc ENDIF:desc END:aliases
    %old_name% -> %new_name%
      %desc%
    ENDIF:aliases IF:attributes

    Attributes

    START:attributes IF:rw ENDIF:rw IFNOT:rw ENDIF:rw END:attributes
    %name% [%rw%]   %a_desc%
    ENDIF:attributes IF:method_list
    START:method_list IF:methods

    %type% %category% methods

    START:methods
    IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode

    [Source]

    %sourcecode%
    
    ENDIF:sourcecode
    END:methods ENDIF:methods END:method_list
    ENDIF:method_list END:sections } ##################################################################### ### B O D Y T E M P L A T E ##################################################################### BODY = HEADER + %{ !INCLUDE!
    } + METHOD_LIST + %{
    } + FOOTER ##################################################################### ### S O U R C E C O D E T E M P L A T E ##################################################################### SRC_PAGE = XHTML_PREAMBLE + %{ %title%
    %code%
    } ##################################################################### ### I N D E X F I L E T E M P L A T E S ##################################################################### FR_INDEX_BODY = %{ !INCLUDE! } FILE_INDEX = XHTML_PREAMBLE + %{ %list_title%

    %list_title%

    START:entries %name%
    END:entries
    } CLASS_INDEX = FILE_INDEX METHOD_INDEX = FILE_INDEX INDEX = %{ %title% } end # module Page end # class RDoc require 'rdoc/generators/template/html/one_page_html' PK|].S͇.rdoc/generators/template/html/one_page_html.rbnu[module RDoc module Page ###################################################################### # # The following is used for the -1 option # CONTENTS_XML = %{ IF:description %description% ENDIF:description IF:requires

    Requires:

      START:requires IF:aref
    • %name%
    • ENDIF:aref IFNOT:aref
    • %name%
    • ENDIF:aref END:requires
    ENDIF:requires IF:attributes

    Attributes

    START:attributes END:attributes
    %name%%rw%%a_desc%
    ENDIF:attributes IF:includes

    Includes

      START:includes IF:aref
    • %name%
    • ENDIF:aref IFNOT:aref
    • %name%
    • ENDIF:aref END:includes
    ENDIF:includes IF:method_list

    Methods

    START:method_list IF:methods START:methods

    %type% %category% method: IF:callseq %callseq% ENDIF:callseq IFNOT:callseq %name%%params%

    ENDIF:callseq IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode
    %sourcecode%
    
    ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } ######################################################################## ONE_PAGE = %{ %title% START:files

    File: %short_name%

    Path:%full_path%
    Modified:%dtm_modified%
    } + CONTENTS_XML + %{ END:files IF:classes

    Classes

    START:classes IF:parent

    %classmod% %full_name% < HREF:par_url:parent:

    ENDIF:parent IFNOT:parent

    %classmod% %full_name%

    ENDIF:parent IF:infiles (in files START:infiles HREF:full_path_url:full_path: END:infiles ) ENDIF:infiles } + CONTENTS_XML + %{ END:classes ENDIF:classes } end end PK|]%6ww#rdoc/generators/template/xml/xml.rbnu[module RDoc module Page CONTENTS_XML = %{ IF:description %description% ENDIF:description IF:requires START:requires END:requires ENDIF:requires IF:attributes START:attributes IF:rw %rw% ENDIF:rw %a_desc% END:attributes ENDIF:attributes IF:includes START:includes END:includes ENDIF:includes IF:method_list START:method_list IF:methods START:methods %params% IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode %sourcecode% ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } ######################################################################## ONE_PAGE = %{ START:files %full_path% %dtm_modified% } + CONTENTS_XML + %{ END:files START:classes <%classmod% name="%full_name%" id="%full_name%"> IF:infiles START:infiles HREF:full_path_url:full_path: END:infiles ENDIF:infiles IF:parent HREF:par_url:parent: ENDIF:parent } + CONTENTS_XML + %{ END:classes } end end PK|]Og  #rdoc/generators/template/xml/rdf.rbnu[module RDoc module Page CONTENTS_RDF = %{ IF:description %description% ENDIF:description IF:requires START:requires END:requires ENDIF:requires IF:attributes START:attributes IF:rw %rw% ENDIF:rw %a_desc% END:attributes ENDIF:attributes IF:includes START:includes END:includes ENDIF:includes IF:method_list START:method_list IF:methods START:methods %params% IF:m_desc %m_desc% ENDIF:m_desc IF:sourcecode %sourcecode% ENDIF:sourcecode END:methods ENDIF:methods END:method_list ENDIF:method_list } ######################################################################## ONE_PAGE = %{ START:files %full_path% %dtm_modified% } + CONTENTS_RDF + %{ END:files START:classes <%classmod% rd:name="%full_name%" rd:id="%full_name%"> IF:infiles START:infiles END:infiles ENDIF:infiles IF:parent HREF:par_url:parent: ENDIF:parent } + CONTENTS_RDF + %{ END:classes } end end PK|]#rdoc/generators/template/chm/chm.rbnu[module RDoc module Page require "rdoc/generators/template/html/html" # This is a nasty little hack, but hhc doesn't support the /, '') SRC_PAGE.sub!(/<\?xml.*\?>/, '') HPP_FILE = %{ [OPTIONS] Auto Index = Yes Compatibility=1.1 or later Compiled file=%opname%.chm Contents file=contents.hhc Full-text search=Yes Index file=index.hhk Language=0x409 English(United States) Title=%title% [FILES] START:all_html_files %html_file_name% END:all_html_files } CONTENTS = %{
      START:contents
    • IF:methods
        START:methods
      • END:methods
      ENDIF:methods
    • END:contents
    } CHM_INDEX = %{
      START:index
    • END:index
    } end end PK|]>4__rdoc/generators/ri_generator.rbnu[# We're responsible for generating all the HTML files # from the object tree defined in code_objects.rb. We # generate: # # [files] an html file for each input file given. These # input files appear as objects of class # TopLevel # # [classes] an html file for each class or module encountered. # These classes are not grouped by file: if a file # contains four classes, we'll generate an html # file for the file itself, and four html files # for the individual classes. # # [indices] we generate three indices for files, classes, # and methods. These are displayed in a browser # like window with three index panes across the # top and the selected description below # # Method descriptions appear in whatever entity (file, class, # or module) that contains them. # # We generate files in a structure below a specified subdirectory, # normally +doc+. # # opdir # | # |___ files # | |__ per file summaries # | # |___ classes # |__ per class/module descriptions # # HTML is generated using the Template class. # require 'ftools' require 'rdoc/options' require 'rdoc/template' require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_flow' require 'cgi' require 'rdoc/ri/ri_cache' require 'rdoc/ri/ri_reader' require 'rdoc/ri/ri_writer' require 'rdoc/ri/ri_descriptions' module Generators class RIGenerator # Generators may need to return specific subclasses depending # on the options they are passed. Because of this # we create them using a factory def RIGenerator.for(options) new(options) end class <\s*)[^\#]/ content = comment else content = comment.gsub(/^\s*(#+)/) { $1.tr('#',' ') } end @markup.convert(content, @to_flow) end # By default we replace existing classes with the # same name. If the --merge option was given, we instead # merge this definition into an existing class. We add # our methods, aliases, etc to that class, but do not # change the class's description. def update_or_replace(cls_desc) old_cls = nil if @options.merge rdr = RI::RiReader.new(RI::RiCache.new(@options.op_dir)) namespace = rdr.top_level_namespace namespace = rdr.lookup_namespace_in(cls_desc.name, namespace) if namespace.empty? $stderr.puts "You asked me to merge this source into existing " $stderr.puts "documentation. This file references a class or " $stderr.puts "module called #{cls_desc.name} which I don't" $stderr.puts "have existing documentation for." $stderr.puts $stderr.puts "Perhaps you need to generate its documentation first" exit 1 else old_cls = namespace[0] end end if old_cls.nil? # no merge: simply overwrite @ri_writer.remove_class(cls_desc) @ri_writer.add_class(cls_desc) else # existing class: merge in old_desc = rdr.get_class(old_cls) old_desc.merge_in(cls_desc) @ri_writer.add_class(old_desc) end end end end PK|]&5L L rdoc/generators/chm_generator.rbnu[require 'rdoc/generators/html_generator' module Generators class CHMGenerator < HTMLGenerator HHC_PATH = "c:/Program Files/HTML Help Workshop/hhc.exe" # Standard generator factory def CHMGenerator.for(options) CHMGenerator.new(options) end def initialize(*args) super @op_name = @options.op_name || "rdoc" check_for_html_help_workshop end def check_for_html_help_workshop stat = File.stat(HHC_PATH) rescue $stderr << "\n.chm output generation requires that Microsoft's Html Help\n" << "Workshop is installed. RDoc looks for it in:\n\n " << HHC_PATH << "\n\nYou can download a copy for free from:\n\n" << " http://msdn.microsoft.com/library/default.asp?" << "url=/library/en-us/htmlhelp/html/hwMicrosoftHTMLHelpDownloads.asp\n\n" exit 99 end # Generate the html as normal, then wrap it # in a help project def generate(info) super @project_name = @op_name + ".hhp" create_help_project end # The project contains the project file, a table of contents # and an index def create_help_project create_project_file create_contents_and_index compile_project end # The project file links together all the various # files that go to make up the help. def create_project_file template = TemplatePage.new(RDoc::Page::HPP_FILE) values = { "title" => @options.title, "opname" => @op_name } files = [] @files.each do |f| files << { "html_file_name" => f.path } end values['all_html_files'] = files File.open(@project_name, "w") do |f| template.write_html_on(f, values) end end # The contents is a list of all files and modules. # For each we include as sub-entries the list # of methods they contain. As we build the contents # we also build an index file def create_contents_and_index contents = [] index = [] (@files+@classes).sort.each do |entry| content_entry = { "c_name" => entry.name, "ref" => entry.path } index << { "name" => entry.name, "aref" => entry.path } internals = [] methods = entry.build_method_summary_list(entry.path) content_entry["methods"] = methods unless methods.empty? contents << content_entry index.concat methods end values = { "contents" => contents } template = TemplatePage.new(RDoc::Page::CONTENTS) File.open("contents.hhc", "w") do |f| template.write_html_on(f, values) end values = { "index" => index } template = TemplatePage.new(RDoc::Page::CHM_INDEX) File.open("index.hhk", "w") do |f| template.write_html_on(f, values) end end # Invoke the windows help compiler to compiler the project def compile_project system(HHC_PATH, @project_name) end end end PK|]M)Męę!rdoc/generators/html_generator.rbnu[# We're responsible for generating all the HTML files # from the object tree defined in code_objects.rb. We # generate: # # [files] an html file for each input file given. These # input files appear as objects of class # TopLevel # # [classes] an html file for each class or module encountered. # These classes are not grouped by file: if a file # contains four classes, we'll generate an html # file for the file itself, and four html files # for the individual classes. # # [indices] we generate three indices for files, classes, # and methods. These are displayed in a browser # like window with three index panes across the # top and the selected description below # # Method descriptions appear in whatever entity (file, class, # or module) that contains them. # # We generate files in a structure below a specified subdirectory, # normally +doc+. # # opdir # | # |___ files # | |__ per file summaries # | # |___ classes # |__ per class/module descriptions # # HTML is generated using the Template class. # require 'ftools' require 'rdoc/options' require 'rdoc/template' require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_html' require 'cgi' module Generators # Name of sub-direcories that hold file and class/module descriptions FILE_DIR = "files" CLASS_DIR = "classes" CSS_NAME = "rdoc-style.css" ## # Build a hash of all items that can be cross-referenced. # This is used when we output required and included names: # if the names appear in this hash, we can generate # an html cross reference to the appropriate description. # We also use this when parsing comment blocks: any decorated # words matching an entry in this list are hyperlinked. class AllReferences @@refs = {} def AllReferences::reset @@refs = {} end def AllReferences.add(name, html_class) @@refs[name] = html_class end def AllReferences.[](name) @@refs[name] end def AllReferences.keys @@refs.keys end end ## # Subclass of the SM::ToHtml class that supports looking # up words in the AllReferences list. Those that are # found (like AllReferences in this comment) will # be hyperlinked class HyperlinkHtml < SM::ToHtml # We need to record the html path of our caller so we can generate # correct relative paths for any hyperlinks that we find def initialize(from_path, context) super() @from_path = from_path @parent_name = context.parent_name @parent_name += "::" if @parent_name @context = context end # We're invoked when any text matches the CROSSREF pattern # (defined in MarkUp). If we fine the corresponding reference, # generate a hyperlink. If the name we're looking for contains # no punctuation, we look for it up the module/class chain. For # example, HyperlinkHtml is found, even without the Generators:: # prefix, because we look for it in module Generators first. def handle_special_CROSSREF(special) name = special.text if name[0,1] == '#' lookup = name[1..-1] name = lookup unless Options.instance.show_hash else lookup = name end # Find class, module, or method in class or module. if /([A-Z]\w*)[.\#](\w+[!?=]?)/ =~ lookup container = $1 method = $2 ref = @context.find_symbol(container, method) elsif /([A-Za-z]\w*)[.\#](\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?)/ =~ lookup container = $1 method = $2 ref = @context.find_symbol(container, method) else ref = @context.find_symbol(lookup) end if ref and ref.document_self "#{name}" else name end end # Generate a hyperlink for url, labeled with text. Handle the # special cases for img: and link: described under handle_special_HYPEDLINK def gen_url(url, text) if url =~ /([A-Za-z]+):(.*)/ type = $1 path = $2 else type = "http" path = url url = "http://#{url}" end if type == "link" if path[0,1] == '#' # is this meaningful? url = path else url = HTMLGenerator.gen_url(@from_path, path) end end if (type == "http" || type == "link") && url =~ /\.(gif|png|jpg|jpeg|bmp)$/ "" else "#{text.sub(%r{^#{type}:/*}, '')}" end end # And we're invoked with a potential external hyperlink mailto: # just gets inserted. http: links are checked to see if they # reference an image. If so, that image gets inserted using an # tag. Otherwise a conventional is used. We also # support a special type of hyperlink, link:, which is a reference # to a local file whose path is relative to the --op directory. def handle_special_HYPERLINK(special) url = special.text gen_url(url, url) end # HEre's a hypedlink where the label is different to the URL #

    /, '') res.sub!(/<\/p>$/, '') end res end # Qualify a stylesheet URL; if if +css_name+ does not begin with '/' or # 'http[s]://', prepend a prefix relative to +path+. Otherwise, return it # unmodified. def style_url(path, css_name=nil) # $stderr.puts "style_url( #{path.inspect}, #{css_name.inspect} )" css_name ||= CSS_NAME if %r{^(https?:/)?/} =~ css_name return css_name else return HTMLGenerator.gen_url(path, css_name) end end # Build a webcvs URL with the given 'url' argument. URLs with a '%s' in them # get the file's path sprintfed into them; otherwise they're just catenated # together. def cvs_url(url, full_path) if /%s/ =~ url return sprintf( url, full_path ) else return url + full_path end end end ##################################################################### # # A Context is built by the parser to represent a container: contexts # hold classes, modules, methods, require lists and include lists. # ClassModule and TopLevel are the context objects we process here # class ContextUser include MarkUp attr_reader :context def initialize(context, options) @context = context @options = options end # convenience method to build a hyperlink def href(link, cls, name) %{#{name}} #" end # return a reference to outselves to be used as an href= # the form depends on whether we're all in one file # or in multiple files def as_href(from_path) if @options.all_one_file "#" + path else HTMLGenerator.gen_url(from_path, path) end end # Create a list of HtmlMethod objects for each method # in the corresponding context object. If the @options.show_all # variable is set (corresponding to the --all option, # we include all methods, otherwise just the public ones. def collect_methods list = @context.method_list unless @options.show_all list = list.find_all {|m| m.visibility == :public || m.visibility == :protected || m.force_documentation } end @methods = list.collect {|m| HtmlMethod.new(m, self, @options) } end # Build a summary list of all the methods in this context def build_method_summary_list(path_prefix="") collect_methods unless @methods meths = @methods.sort res = [] meths.each do |meth| res << { "name" => CGI.escapeHTML(meth.name), "aref" => "#{path_prefix}\##{meth.aref}" } end res end # Build a list of aliases for which we couldn't find a # corresponding method def build_alias_summary_list(section) values = [] @context.aliases.each do |al| next unless al.section == section res = { 'old_name' => al.old_name, 'new_name' => al.new_name, } if al.comment && !al.comment.empty? res['desc'] = markup(al.comment, true) end values << res end values end # Build a list of constants def build_constants_summary_list(section) values = [] @context.constants.each do |co| next unless co.section == section res = { 'name' => co.name, 'value' => CGI.escapeHTML(co.value) } res['desc'] = markup(co.comment, true) if co.comment && !co.comment.empty? values << res end values end def build_requires_list(context) potentially_referenced_list(context.requires) {|fn| [fn + ".rb"] } end def build_include_list(context) potentially_referenced_list(context.includes) end # Build a list from an array of Htmlxxx items. Look up each # in the AllReferences hash: if we find a corresponding entry, # we generate a hyperlink to it, otherwise just output the name. # However, some names potentially need massaging. For example, # you may require a Ruby file without the .rb extension, # but the file names we know about may have it. To deal with # this, we pass in a block which performs the massaging, # returning an array of alternative names to match def potentially_referenced_list(array) res = [] array.each do |i| ref = AllReferences[i.name] # if !ref # container = @context.parent # while !ref && container # name = container.name + "::" + i.name # ref = AllReferences[name] # container = container.parent # end # end ref = @context.find_symbol(i.name) ref = ref.viewer if ref if !ref && block_given? possibles = yield(i.name) while !ref and !possibles.empty? ref = AllReferences[possibles.shift] end end h_name = CGI.escapeHTML(i.name) if ref and ref.document_self path = url(ref.path) res << { "name" => h_name, "aref" => path } else res << { "name" => h_name } end end res end # Build an array of arrays of method details. The outer array has up # to six entries, public, private, and protected for both class # methods, the other for instance methods. The inner arrays contain # a hash for each method def build_method_detail_list(section) outer = [] methods = @methods.sort for singleton in [true, false] for vis in [ :public, :protected, :private ] res = [] methods.each do |m| if m.section == section and m.document_self and m.visibility == vis and m.singleton == singleton row = {} if m.call_seq row["callseq"] = m.call_seq.gsub(/->/, '→') else row["name"] = CGI.escapeHTML(m.name) row["params"] = m.params end desc = m.description.strip row["m_desc"] = desc unless desc.empty? row["aref"] = m.aref row["visibility"] = m.visibility.to_s alias_names = [] m.aliases.each do |other| if other.viewer # won't be if the alias is private alias_names << { 'name' => other.name, 'aref' => other.viewer.as_href(path) } end end unless alias_names.empty? row["aka"] = alias_names end if @options.inline_source code = m.source_code row["sourcecode"] = code if code else code = m.src_url if code row["codeurl"] = code row["imgurl"] = m.img_url end end res << row end end if res.size > 0 outer << { "type" => vis.to_s.capitalize, "category" => singleton ? "Class" : "Instance", "methods" => res } end end end outer end # Build the structured list of classes and modules contained # in this context. def build_class_list(level, from, section, infile=nil) res = "" prefix = "  ::" * level; from.modules.sort.each do |mod| next unless mod.section == section next if infile && !mod.defined_in?(infile) if mod.document_self res << prefix << "Module " << href(url(mod.viewer.path), "link", mod.full_name) << "
    \n" << build_class_list(level + 1, mod, section, infile) end end from.classes.sort.each do |cls| next unless cls.section == section next if infile && !cls.defined_in?(infile) if cls.document_self res << prefix << "Class " << href(url(cls.viewer.path), "link", cls.full_name) << "
    \n" << build_class_list(level + 1, cls, section, infile) end end res end def url(target) HTMLGenerator.gen_url(path, target) end def aref_to(target) if @options.all_one_file "#" + target else url(target) end end def document_self @context.document_self end def diagram_reference(diagram) res = diagram.gsub(/((?:src|href)=")(.*?)"/) { $1 + url($2) + '"' } res end # Find a symbol in ourselves or our parent def find_symbol(symbol, method=nil) res = @context.find_symbol(symbol, method) if res res = res.viewer end res end # create table of contents if we contain sections def add_table_of_sections toc = [] @context.sections.each do |section| if section.title toc << { 'secname' => section.title, 'href' => section.sequence } end end @values['toc'] = toc unless toc.empty? end end ##################################################################### # # Wrap a ClassModule context class HtmlClass < ContextUser attr_reader :path def initialize(context, html_file, prefix, options) super(context, options) @html_file = html_file @is_module = context.is_module? @values = {} context.viewer = self if options.all_one_file @path = context.full_name else @path = http_url(context.full_name, prefix) end collect_methods AllReferences.add(name, self) end # return the relative file name to store this class in, # which is also its url def http_url(full_name, prefix) path = full_name.dup if path['<<'] path.gsub!(/<<\s*(\w*)/) { "from-#$1" } end File.join(prefix, path.split("::")) + ".html" end def name @context.full_name end def parent_name @context.parent.full_name end def index_name name end def write_on(f) value_hash template = TemplatePage.new(RDoc::Page::BODY, RDoc::Page::CLASS_PAGE, RDoc::Page::METHOD_LIST) template.write_html_on(f, @values) end def value_hash class_attribute_values add_table_of_sections @values["charset"] = @options.charset @values["style_url"] = style_url(path, @options.css) d = markup(@context.comment) @values["description"] = d unless d.empty? ml = build_method_summary_list @values["methods"] = ml unless ml.empty? il = build_include_list(@context) @values["includes"] = il unless il.empty? @values["sections"] = @context.sections.map do |section| secdata = { "sectitle" => section.title, "secsequence" => section.sequence, "seccomment" => markup(section.comment) } al = build_alias_summary_list(section) secdata["aliases"] = al unless al.empty? co = build_constants_summary_list(section) secdata["constants"] = co unless co.empty? al = build_attribute_list(section) secdata["attributes"] = al unless al.empty? cl = build_class_list(0, @context, section) secdata["classlist"] = cl unless cl.empty? mdl = build_method_detail_list(section) secdata["method_list"] = mdl unless mdl.empty? secdata end @values end def build_attribute_list(section) atts = @context.attributes.sort res = [] atts.each do |att| next unless att.section == section if att.visibility == :public || att.visibility == :protected || @options.show_all entry = { "name" => CGI.escapeHTML(att.name), "rw" => att.rw, "a_desc" => markup(att.comment, true) } unless att.visibility == :public || att.visibility == :protected entry["rw"] << "-" end res << entry end end res end def class_attribute_values h_name = CGI.escapeHTML(name) @values["classmod"] = @is_module ? "Module" : "Class" @values["title"] = "#{@values['classmod']}: #{h_name}" c = @context c = c.parent while c and !c.diagram if c && c.diagram @values["diagram"] = diagram_reference(c.diagram) end @values["full_name"] = h_name parent_class = @context.superclass if parent_class @values["parent"] = CGI.escapeHTML(parent_class) if parent_name lookup = parent_name + "::" + parent_class else lookup = parent_class end parent_url = AllReferences[lookup] || AllReferences[parent_class] if parent_url and parent_url.document_self @values["par_url"] = aref_to(parent_url.path) end end files = [] @context.in_files.each do |f| res = {} full_path = CGI.escapeHTML(f.file_absolute_name) res["full_path"] = full_path res["full_path_url"] = aref_to(f.viewer.path) if f.document_self if @options.webcvs res["cvsurl"] = cvs_url( @options.webcvs, full_path ) end files << res end @values['infiles'] = files end def <=>(other) self.name <=> other.name end end ##################################################################### # # Handles the mapping of a file's information to HTML. In reality, # a file corresponds to a +TopLevel+ object, containing modules, # classes, and top-level methods. In theory it _could_ contain # attributes and aliases, but we ignore these for now. class HtmlFile < ContextUser attr_reader :path attr_reader :name def initialize(context, options, file_dir) super(context, options) @values = {} if options.all_one_file @path = filename_to_label else @path = http_url(file_dir) end @name = @context.file_relative_name collect_methods AllReferences.add(name, self) context.viewer = self end def http_url(file_dir) File.join(file_dir, @context.file_relative_name.tr('.', '_')) + ".html" end def filename_to_label @context.file_relative_name.gsub(/%|\/|\?|\#/) {|s| '%' + ("%x" % s[0]) } end def index_name name end def parent_name nil end def value_hash file_attribute_values add_table_of_sections @values["charset"] = @options.charset @values["href"] = path @values["style_url"] = style_url(path, @options.css) if @context.comment d = markup(@context.comment) @values["description"] = d if d.size > 0 end ml = build_method_summary_list @values["methods"] = ml unless ml.empty? il = build_include_list(@context) @values["includes"] = il unless il.empty? rl = build_requires_list(@context) @values["requires"] = rl unless rl.empty? if @options.promiscuous file_context = nil else file_context = @context end @values["sections"] = @context.sections.map do |section| secdata = { "sectitle" => section.title, "secsequence" => section.sequence, "seccomment" => markup(section.comment) } cl = build_class_list(0, @context, section, file_context) @values["classlist"] = cl unless cl.empty? mdl = build_method_detail_list(section) secdata["method_list"] = mdl unless mdl.empty? al = build_alias_summary_list(section) secdata["aliases"] = al unless al.empty? co = build_constants_summary_list(section) @values["constants"] = co unless co.empty? secdata end @values end def write_on(f) value_hash template = TemplatePage.new(RDoc::Page::BODY, RDoc::Page::FILE_PAGE, RDoc::Page::METHOD_LIST) template.write_html_on(f, @values) end def file_attribute_values full_path = @context.file_absolute_name short_name = File.basename(full_path) @values["title"] = CGI.escapeHTML("File: #{short_name}") if @context.diagram @values["diagram"] = diagram_reference(@context.diagram) end @values["short_name"] = CGI.escapeHTML(short_name) @values["full_path"] = CGI.escapeHTML(full_path) @values["dtm_modified"] = @context.file_stat.mtime.to_s if @options.webcvs @values["cvsurl"] = cvs_url( @options.webcvs, @values["full_path"] ) end end def <=>(other) self.name <=> other.name end end ##################################################################### class HtmlMethod include MarkUp attr_reader :context attr_reader :src_url attr_reader :img_url attr_reader :source_code @@seq = "M000000" @@all_methods = [] def HtmlMethod::reset @@all_methods = [] end def initialize(context, html_class, options) @context = context @html_class = html_class @options = options @@seq = @@seq.succ @seq = @@seq @@all_methods << self context.viewer = self if (ts = @context.token_stream) @source_code = markup_code(ts) unless @options.inline_source @src_url = create_source_code_file(@source_code) @img_url = HTMLGenerator.gen_url(path, 'source.png') end end AllReferences.add(name, self) end # return a reference to outselves to be used as an href= # the form depends on whether we're all in one file # or in multiple files def as_href(from_path) if @options.all_one_file "#" + path else HTMLGenerator.gen_url(from_path, path) end end def name @context.name end def section @context.section end def index_name "#{@context.name} (#{@html_class.name})" end def parent_name if @context.parent.parent @context.parent.parent.full_name else nil end end def aref @seq end def path if @options.all_one_file aref else @html_class.path + "#" + aref end end def description markup(@context.comment) end def visibility @context.visibility end def singleton @context.singleton end def call_seq cs = @context.call_seq if cs cs.gsub(/\n/, "
    \n") else nil end end def params # params coming from a call-seq in 'C' will start with the # method name p = @context.params if p !~ /^\w/ p = @context.params.gsub(/\s*\#.*/, '') p = p.tr("\n", " ").squeeze(" ") p = "(" + p + ")" unless p[0] == ?( if (block = @context.block_params) # If this method has explicit block parameters, remove any # explicit &block p.sub!(/,?\s*&\w+/, '') block.gsub!(/\s*\#.*/, '') block = block.tr("\n", " ").squeeze(" ") if block[0] == ?( block.sub!(/^\(/, '').sub!(/\)/, '') end p << " {|#{block.strip}| ...}" end end CGI.escapeHTML(p) end def create_source_code_file(code_body) meth_path = @html_class.path.sub(/\.html$/, '.src') File.makedirs(meth_path) file_path = File.join(meth_path, @seq) + ".html" template = TemplatePage.new(RDoc::Page::SRC_PAGE) File.open(file_path, "w") do |f| values = { 'title' => CGI.escapeHTML(index_name), 'code' => code_body, 'style_url' => style_url(file_path, @options.css), 'charset' => @options.charset } template.write_html_on(f, values) end HTMLGenerator.gen_url(path, file_path) end def HtmlMethod.all_methods @@all_methods end def <=>(other) @context <=> other.context end ## # Given a sequence of source tokens, mark up the source code # to make it look purty. def markup_code(tokens) src = "" tokens.each do |t| next unless t # p t.class # style = STYLE_MAP[t.class] style = case t when RubyToken::TkCONSTANT then "ruby-constant" when RubyToken::TkKW then "ruby-keyword kw" when RubyToken::TkIVAR then "ruby-ivar" when RubyToken::TkOp then "ruby-operator" when RubyToken::TkId then "ruby-identifier" when RubyToken::TkNode then "ruby-node" when RubyToken::TkCOMMENT then "ruby-comment cmt" when RubyToken::TkREGEXP then "ruby-regexp re" when RubyToken::TkSTRING then "ruby-value str" when RubyToken::TkVal then "ruby-value" else nil end text = CGI.escapeHTML(t.text) if style src << "#{text}" else src << text end end add_line_numbers(src) if Options.instance.include_line_numbers src end # we rely on the fact that the first line of a source code # listing has # # File xxxxx, line dddd def add_line_numbers(src) if src =~ /\A.*, line (\d+)/ first = $1.to_i - 1 last = first + src.count("\n") size = last.to_s.length real_fmt = "%#{size}d: " fmt = " " * (size+2) src.gsub!(/^/) do res = sprintf(fmt, first) first += 1 fmt = real_fmt res end end end def document_self @context.document_self end def aliases @context.aliases end def find_symbol(symbol, method=nil) res = @context.parent.find_symbol(symbol, method) if res res = res.viewer end res end end ##################################################################### class HTMLGenerator include MarkUp ## # convert a target url to one that is relative to a given # path def HTMLGenerator.gen_url(path, target) from = File.dirname(path) to, to_file = File.split(target) from = from.split("/") to = to.split("/") while from.size > 0 and to.size > 0 and from[0] == to[0] from.shift to.shift end from.fill("..") from.concat(to) from << to_file File.join(*from) end # Generators may need to return specific subclasses depending # on the options they are passed. Because of this # we create them using a factory def HTMLGenerator.for(options) AllReferences::reset HtmlMethod::reset if options.all_one_file HTMLGeneratorInOne.new(options) else HTMLGenerator.new(options) end end class < RDoc::Page::FONTS } template.write_html_on(f, values) end end end ## # See the comments at the top for a description of the # directory structure def gen_sub_directories File.makedirs(FILE_DIR, CLASS_DIR) rescue $stderr.puts $!.message exit 1 end ## # Generate: # # * a list of HtmlFile objects for each TopLevel object. # * a list of HtmlClass objects for each first level # class or module in the TopLevel objects # * a complete list of all hyperlinkable terms (file, # class, module, and method names) def build_indices @toplevels.each do |toplevel| @files << HtmlFile.new(toplevel, @options, FILE_DIR) end RDoc::TopLevel.all_classes_and_modules.each do |cls| build_class_list(cls, @files[0], CLASS_DIR) end end def build_class_list(from, html_file, class_dir) @classes << HtmlClass.new(from, html_file, class_dir, @options) from.each_classmodule do |mod| build_class_list(mod, html_file, class_dir) end end ## # Generate all the HTML # def generate_html # the individual descriptions for files and classes gen_into(@files) gen_into(@classes) # and the index files gen_file_index gen_class_index gen_method_index gen_main_index # this method is defined in the template file write_extra_pages if defined? write_extra_pages end def gen_into(list) list.each do |item| if item.document_self op_file = item.path File.makedirs(File.dirname(op_file)) File.open(op_file, "w") { |file| item.write_on(file) } end end end def gen_file_index gen_an_index(@files, 'Files', RDoc::Page::FILE_INDEX, "fr_file_index.html") end def gen_class_index gen_an_index(@classes, 'Classes', RDoc::Page::CLASS_INDEX, "fr_class_index.html") end def gen_method_index gen_an_index(HtmlMethod.all_methods, 'Methods', RDoc::Page::METHOD_INDEX, "fr_method_index.html") end def gen_an_index(collection, title, template, filename) template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template) res = [] collection.sort.each do |f| if f.document_self res << { "href" => f.path, "name" => f.index_name } end end values = { "entries" => res, 'list_title' => CGI.escapeHTML(title), 'index_url' => main_url, 'charset' => @options.charset, 'style_url' => style_url('', @options.css), } File.open(filename, "w") do |f| template.write_html_on(f, values) end end # The main index page is mostly a template frameset, but includes # the initial page. If the --main option was given, # we use this as our main page, otherwise we use the # first file specified on the command line. def gen_main_index template = TemplatePage.new(RDoc::Page::INDEX) File.open("index.html", "w") do |f| values = { "initial_page" => main_url, 'title' => CGI.escapeHTML(@options.title), 'charset' => @options.charset } if @options.inline_source values['inline_source'] = true end template.write_html_on(f, values) end end # return the url of the main page def main_url main_page = @options.main_page ref = nil if main_page ref = AllReferences[main_page] if ref ref = ref.path else $stderr.puts "Could not find main page #{main_page}" end end unless ref for file in @files if file.document_self ref = file.path break end end end unless ref $stderr.puts "Couldn't find anything to document" $stderr.puts "Perhaps you've used :stopdoc: in all classes" exit(1) end ref end end ###################################################################### class HTMLGeneratorInOne < HTMLGenerator def initialize(*args) super end ## # Build the initial indices and output objects # based on an array of TopLevel objects containing # the extracted information. def generate(info) @toplevels = info @files = [] @classes = [] @hyperlinks = {} build_indices generate_xml end ## # Generate: # # * a list of HtmlFile objects for each TopLevel object. # * a list of HtmlClass objects for each first level # class or module in the TopLevel objects # * a complete list of all hyperlinkable terms (file, # class, module, and method names) def build_indices @toplevels.each do |toplevel| @files << HtmlFile.new(toplevel, @options, FILE_DIR) end RDoc::TopLevel.all_classes_and_modules.each do |cls| build_class_list(cls, @files[0], CLASS_DIR) end end def build_class_list(from, html_file, class_dir) @classes << HtmlClass.new(from, html_file, class_dir, @options) from.each_classmodule do |mod| build_class_list(mod, html_file, class_dir) end end ## # Generate all the HTML. For the one-file case, we generate # all the information in to one big hash # def generate_xml values = { 'charset' => @options.charset, 'files' => gen_into(@files), 'classes' => gen_into(@classes), 'title' => CGI.escapeHTML(@options.title), } # this method is defined in the template file write_extra_pages if defined? write_extra_pages template = TemplatePage.new(RDoc::Page::ONE_PAGE) if @options.op_name opfile = File.open(@options.op_name, "w") else opfile = $stdout end template.write_html_on(opfile, values) end def gen_into(list) res = [] list.each do |item| res << item.value_hash end res end def gen_file_index gen_an_index(@files, 'Files') end def gen_class_index gen_an_index(@classes, 'Classes') end def gen_method_index gen_an_index(HtmlMethod.all_methods, 'Methods') end def gen_an_index(collection, title) res = [] collection.sort.each do |f| if f.document_self res << { "href" => f.path, "name" => f.index_name } end end return { "entries" => res, 'list_title' => title, 'index_url' => main_url, } end end end PK|]^.s  rdoc/generators/xml_generator.rbnu[ require 'ftools' require 'rdoc/options' require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_html' require 'rdoc/generators/html_generator' module Generators # Generate XML output as one big file class XMLGenerator < HTMLGenerator # Standard generator factory def XMLGenerator.for(options) XMLGenerator.new(options) end def initialize(*args) super end ## # Build the initial indices and output objects # based on an array of TopLevel objects containing # the extracted information. def generate(info) @info = info @files = [] @classes = [] @hyperlinks = {} build_indices generate_xml end ## # Generate: # # * a list of HtmlFile objects for each TopLevel object. # * a list of HtmlClass objects for each first level # class or module in the TopLevel objects # * a complete list of all hyperlinkable terms (file, # class, module, and method names) def build_indices @info.each do |toplevel| @files << HtmlFile.new(toplevel, @options, FILE_DIR) end RDoc::TopLevel.all_classes_and_modules.each do |cls| build_class_list(cls, @files[0], CLASS_DIR) end end def build_class_list(from, html_file, class_dir) @classes << HtmlClass.new(from, html_file, class_dir, @options) from.each_classmodule do |mod| build_class_list(mod, html_file, class_dir) end end ## # Generate all the HTML. For the one-file case, we generate # all the information in to one big hash # def generate_xml values = { 'charset' => @options.charset, 'files' => gen_into(@files), 'classes' => gen_into(@classes) } # this method is defined in the template file write_extra_pages if defined? write_extra_pages template = TemplatePage.new(RDoc::Page::ONE_PAGE) if @options.op_name opfile = File.open(@options.op_name, "w") else opfile = $stdout end template.write_html_on(opfile, values) end def gen_into(list) res = [] list.each do |item| res << item.value_hash end res end def gen_file_index gen_an_index(@files, 'Files') end def gen_class_index gen_an_index(@classes, 'Classes') end def gen_method_index gen_an_index(HtmlMethod.all_methods, 'Methods') end def gen_an_index(collection, title) res = [] collection.sort.each do |f| if f.document_self res << { "href" => f.path, "name" => f.index_name } end end return { "entries" => res, 'list_title' => title, 'index_url' => main_url, } end end end PK|];gDDrdoc/options.rbnu[# We handle the parsing of options, and subsequently as a singleton # object to be queried for option values require "rdoc/ri/ri_paths" class Options require 'singleton' require 'getoptlong' include Singleton # files matching this pattern will be excluded attr_accessor :exclude # the name of the output directory attr_accessor :op_dir # the name to use for the output attr_reader :op_name # include private and protected methods in the # output attr_accessor :show_all # name of the file, class or module to display in # the initial index page (if not specified # the first file we encounter is used) attr_accessor :main_page # merge into classes of the name name when generating ri attr_reader :merge # Don't display progress as we process the files attr_reader :quiet # description of the output generator (set with the -fmt # option attr_accessor :generator # and the list of files to be processed attr_reader :files # array of directories to search for files to satisfy an :include: attr_reader :rdoc_include # title to be used out the output #attr_writer :title # template to be used when generating output attr_reader :template # should diagrams be drawn attr_reader :diagram # should we draw fileboxes in diagrams attr_reader :fileboxes # include the '#' at the front of hyperlinked instance method names attr_reader :show_hash # image format for diagrams attr_reader :image_format # character-set attr_reader :charset # should source code be included inline, or displayed in a popup attr_reader :inline_source # should the output be placed into a single file attr_reader :all_one_file # the number of columns in a tab attr_reader :tab_width # include line numbers in the source listings attr_reader :include_line_numbers # pattern for additional attr_... style methods attr_reader :extra_accessors attr_reader :extra_accessor_flags # URL of stylesheet attr_reader :css # URL of web cvs frontend attr_reader :webcvs # Are we promiscuous about showing module contents across # multiple files attr_reader :promiscuous # scan newer sources than the flag file if true. attr_reader :force_update module OptionList OPTION_LIST = [ [ "--accessor", "-A", "accessorname[,..]", "comma separated list of additional class methods\n" + "that should be treated like 'attr_reader' and\n" + "friends. Option may be repeated. Each accessorname\n" + "may have '=text' appended, in which case that text\n" + "appears where the r/w/rw appears for normal accessors."], [ "--all", "-a", nil, "include all methods (not just public)\nin the output" ], [ "--charset", "-c", "charset", "specifies HTML character-set" ], [ "--debug", "-D", nil, "displays lots on internal stuff" ], [ "--diagram", "-d", nil, "Generate diagrams showing modules and classes.\n" + "You need dot V1.8.6 or later to use the --diagram\n" + "option correctly. Dot is available from\n"+ "http://www.research.att.com/sw/tools/graphviz/" ], [ "--exclude", "-x", "pattern", "do not process files or directories matching\n" + "pattern. Files given explicitly on the command\n" + "line will never be excluded." ], [ "--extension", "-E", "new=old", "Treat files ending with .new as if they ended with\n" + ".old. Using '-E cgi=rb' will cause xxx.cgi to be\n" + "parsed as a Ruby file"], [ "--fileboxes", "-F", nil, "classes are put in boxes which represents\n" + "files, where these classes reside. Classes\n" + "shared between more than one file are\n" + "shown with list of files that sharing them.\n" + "Silently discarded if --diagram is not given\n" + "Experimental." ], [ "--force-update", "-U", nil, "forces to scan all sources even if newer than\n" + "the flag file." ], [ "--fmt", "-f", "format name", "set the output formatter (see below)" ], [ "--help", "-h", nil, "you're looking at it" ], [ "--help-output", "-O", nil, "explain the various output options" ], [ "--image-format", "-I", "gif/png/jpg/jpeg", "Sets output image format for diagrams. Can\n" + "be png, gif, jpeg, jpg. If this option is\n" + "omitted, png is used. Requires --diagram." ], [ "--include", "-i", "dir[,dir...]", "set (or add to) the list of directories\n" + "to be searched when satisfying :include:\n" + "requests. Can be used more than once." ], [ "--inline-source", "-S", nil, "Show method source code inline, rather\n" + "than via a popup link" ], [ "--line-numbers", "-N", nil, "Include line numbers in the source code" ], [ "--main", "-m", "name", "'name' will be the initial page displayed" ], [ "--merge", "-M", nil, "when creating ri output, merge processed classes\n" + "into previously documented classes of the name name"], [ "--one-file", "-1", nil, "put all the output into a single file" ], [ "--op", "-o", "dir", "set the output directory" ], [ "--opname", "-n", "name", "Set the 'name' of the output. Has no\n" + "effect for HTML." ], [ "--promiscuous", "-p", nil, "When documenting a file that contains a module\n" + "or class also defined in other files, show\n" + "all stuff for that module/class in each files\n" + "page. By default, only show stuff defined in\n" + "that particular file." ], [ "--quiet", "-q", nil, "don't show progress as we parse" ], [ "--ri", "-r", nil, "generate output for use by 'ri.' The files are\n" + "stored in the '.rdoc' directory under your home\n"+ "directory unless overridden by a subsequent\n" + "--op parameter, so no special privileges are needed." ], [ "--ri-site", "-R", nil, "generate output for use by 'ri.' The files are\n" + "stored in a site-wide directory, making them accessible\n"+ "to others, so special privileges are needed." ], [ "--ri-system", "-Y", nil, "generate output for use by 'ri.' The files are\n" + "stored in a system-level directory, making them accessible\n"+ "to others, so special privileges are needed. This option\n"+ "is intended to be used during Ruby installations" ], [ "--show-hash", "-H", nil, "A name of the form #name in a comment\n" + "is a possible hyperlink to an instance\n" + "method name. When displayed, the '#' is\n" + "removed unless this option is specified" ], [ "--style", "-s", "stylesheet url", "specifies the URL of a separate stylesheet." ], [ "--tab-width", "-w", "n", "Set the width of tab characters (default 8)"], [ "--template", "-T", "template name", "Set the template used when generating output" ], [ "--title", "-t", "text", "Set 'txt' as the title for the output" ], [ "--version", "-v", nil, "display RDoc's version" ], [ "--webcvs", "-W", "url", "Specify a URL for linking to a web frontend\n" + "to CVS. If the URL contains a '\%s', the\n" + "name of the current file will be substituted;\n" + "if the URL doesn't contain a '\%s', the\n" + "filename will be appended to it." ], ] def OptionList.options OPTION_LIST.map do |long, short, arg,| [ long, short, arg ? GetoptLong::REQUIRED_ARGUMENT : GetoptLong::NO_ARGUMENT ] end end def OptionList.strip_output(text) text =~ /^\s+/ leading_spaces = $& text.gsub!(/^#{leading_spaces}/, '') $stdout.puts text end # Show an error and exit def OptionList.error(msg) $stderr.puts $stderr.puts msg $stderr.puts "\nFor help on options, try 'rdoc --help'\n\n" exit 1 end # Show usage and exit def OptionList.usage(generator_names) puts puts(VERSION_STRING) puts name = File.basename($0) OptionList.strip_output(<<-EOT) Usage: #{name} [options] [names...] Files are parsed, and the information they contain collected, before any output is produced. This allows cross references between all files to be resolved. If a name is a directory, it is traversed. If no names are specified, all Ruby files in the current directory (and subdirectories) are processed. Options: EOT OPTION_LIST.each do |long, short, arg, desc| opt = sprintf("%20s", "#{long}, #{short}") oparg = sprintf("%-7s", arg) print "#{opt} #{oparg}" desc = desc.split("\n") if arg.nil? || arg.length < 7 puts desc.shift else puts end desc.each do |line| puts(" "*28 + line) end puts end puts "\nAvailable output formatters: " + generator_names.sort.join(', ') + "\n\n" puts "For information on where the output goes, use\n\n" puts " rdoc --help-output\n\n" exit 0 end def OptionList.help_output OptionList.strip_output(<<-EOT) How RDoc generates output depends on the output formatter being used, and on the options you give. - HTML output is normally produced into a number of separate files (one per class, module, and file, along with various indices). These files will appear in the directory given by the --op option (doc/ by default). - XML output by default is written to standard output. If a --opname option is given, the output will instead be written to a file with that name in the output directory. - .chm files (Windows help files) are written in the --op directory. If an --opname parameter is present, that name is used, otherwise the file will be called rdoc.chm. For information on other RDoc options, use "rdoc --help". EOT exit 0 end end # Parse command line options. We're passed a hash containing # output generators, keyed by the generator name def parse(argv, generators) old_argv = ARGV.dup begin ARGV.replace(argv) @op_dir = "doc" @op_name = nil @show_all = false @main_page = nil @marge = false @exclude = [] @quiet = false @generator_name = 'html' @generator = generators[@generator_name] @rdoc_include = [] @title = nil @template = nil @diagram = false @fileboxes = false @show_hash = false @image_format = 'png' @inline_source = false @all_one_file = false @tab_width = 8 @include_line_numbers = false @extra_accessor_flags = {} @promiscuous = false @force_update = false @css = nil @webcvs = nil @charset = case $KCODE when /^S/i 'Shift_JIS' when /^E/i 'EUC-JP' else 'iso-8859-1' end accessors = [] go = GetoptLong.new(*OptionList.options) go.quiet = true go.each do |opt, arg| case opt when "--all" then @show_all = true when "--charset" then @charset = arg when "--debug" then $DEBUG = true when "--exclude" then @exclude << Regexp.new(arg) when "--inline-source" then @inline_source = true when "--line-numbers" then @include_line_numbers = true when "--main" then @main_page = arg when "--merge" then @merge = true when "--one-file" then @all_one_file = @inline_source = true when "--op" then @op_dir = arg when "--opname" then @op_name = arg when "--promiscuous" then @promiscuous = true when "--quiet" then @quiet = true when "--show-hash" then @show_hash = true when "--style" then @css = arg when "--template" then @template = arg when "--title" then @title = arg when "--webcvs" then @webcvs = arg when "--accessor" arg.split(/,/).each do |accessor| if accessor =~ /^(\w+)(=(.*))?$/ accessors << $1 @extra_accessor_flags[$1] = $3 end end when "--diagram" check_diagram @diagram = true when "--fileboxes" @fileboxes = true if @diagram when "--fmt" @generator_name = arg.downcase setup_generator(generators) when "--help" OptionList.usage(generators.keys) when "--help-output" OptionList.help_output when "--image-format" if ['gif', 'png', 'jpeg', 'jpg'].include?(arg) @image_format = arg else raise GetoptLong::InvalidOption.new("unknown image format: #{arg}") end when "--include" @rdoc_include.concat arg.split(/\s*,\s*/) when "--ri", "--ri-site", "--ri-system" @generator_name = "ri" @op_dir = case opt when "--ri" then RI::Paths::HOMEDIR when "--ri-site" then RI::Paths::SITEDIR when "--ri-system" then RI::Paths::SYSDIR else fail opt end setup_generator(generators) when "--tab-width" begin @tab_width = Integer(arg) rescue $stderr.puts "Invalid tab width: '#{arg}'" exit 1 end when "--extension" new, old = arg.split(/=/, 2) OptionList.error("Invalid parameter to '-E'") unless new && old unless RDoc::ParserFactory.alias_extension(old, new) OptionList.error("Unknown extension .#{old} to -E") end when "--force-update" @force_update = true when "--version" puts VERSION_STRING exit end end @files = ARGV.dup @rdoc_include << "." if @rdoc_include.empty? if @exclude.empty? @exclude = nil else @exclude = Regexp.new(@exclude.join("|")) end check_files # If no template was specified, use the default # template for the output formatter @template ||= @generator_name # Generate a regexp from the accessors unless accessors.empty? re = '^(' + accessors.map{|a| Regexp.quote(a)}.join('|') + ')$' @extra_accessors = Regexp.new(re) end rescue GetoptLong::InvalidOption, GetoptLong::MissingArgument => error OptionList.error(error.message) ensure ARGV.replace(old_argv) end end def title @title ||= "RDoc Documentation" end # Set the title, but only if not already set. This means that a title set from # the command line trumps one set in a source file def title=(string) @title ||= string end private # Set up an output generator for the format in @generator_name def setup_generator(generators) @generator = generators[@generator_name] if !@generator OptionList.error("Invalid output formatter") end if @generator_name == "xml" @all_one_file = true @inline_source = true end end # Check that the right version of 'dot' is available. # Unfortuately this doesn't work correctly under Windows NT, # so we'll bypass the test under Windows def check_diagram return if RUBY_PLATFORM =~ /mswin|cygwin|mingw|bccwin/ ok = false ver = nil IO.popen("dot -V 2>&1") do |io| ver = io.read if ver =~ /dot.+version(?:\s+gviz)?\s+(\d+)\.(\d+)/ ok = ($1.to_i > 1) || ($1.to_i == 1 && $2.to_i >= 8) end end unless ok if ver =~ /^dot.+version/ $stderr.puts "Warning: You may need dot V1.8.6 or later to use\n", "the --diagram option correctly. You have:\n\n ", ver, "\nDiagrams might have strange background colors.\n\n" else $stderr.puts "You need the 'dot' program to produce diagrams.", "(see http://www.research.att.com/sw/tools/graphviz/)\n\n" exit end # exit end end # Check that the files on the command line exist def check_files @files.each do |f| stat = File.stat f rescue error("File not found: #{f}") error("File '#{f}' not readable") unless stat.readable? end end def error(str) $stderr.puts str exit(1) end end PK|]%Ȅrdoc/tokenstream.rbnu[# A TokenStream is a list of tokens, gathered during the parse # of some entity (say a method). Entities populate these streams # by being registered with the lexer. Any class can collect tokens # by including TokenStream. From the outside, you use such an object # by calling the start_collecting_tokens method, followed by calls # to add_token and pop_token module TokenStream def token_stream @token_stream end def start_collecting_tokens @token_stream = [] end def add_token(tk) @token_stream << tk end def add_tokens(tks) tks.each {|tk| add_token(tk)} end def pop_token @token_stream.pop end end PK|]BDD thwait.rbnu[# # thwait.rb - thread synchronization class # $Release Version: 0.9 $ # $Revision: 1.3 $ # $Date: 1998/06/26 03:19:34 $ # by Keiju ISHITSUKA(Nihpon Rational Software Co.,Ltd.) # # -- # feature: # provides synchronization for multiple threads. # # class methods: # * ThreadsWait.all_waits(thread1,...) # waits until all of specified threads are terminated. # if a block is supplied for the method, evaluates it for # each thread termination. # * th = ThreadsWait.new(thread1,...) # creates synchronization object, specifying thread(s) to wait. # # methods: # * th.threads # list threads to be synchronized # * th.empty? # is there any thread to be synchronized. # * th.finished? # is there already terminated thread. # * th.join(thread1,...) # wait for specified thread(s). # * th.join_nowait(threa1,...) # specifies thread(s) to wait. non-blocking. # * th.next_wait # waits until any of specified threads is terminated. # * th.all_waits # waits until all of specified threads are terminated. # if a block is supplied for the method, evaluates it for # each thread termination. # require "thread.rb" require "e2mmap.rb" # # This class watches for termination of multiple threads. Basic functionality # (wait until specified threads have terminated) can be accessed through the # class method ThreadsWait::all_waits. Finer control can be gained using # instance methods. # # Example: # # ThreadsWait.all_wait(thr1, thr2, ...) do |t| # STDERR.puts "Thread #{t} has terminated." # end # class ThreadsWait RCS_ID='-$Id: thwait.rb,v 1.3 1998/06/26 03:19:34 keiju Exp keiju $-' Exception2MessageMapper.extend_to(binding) def_exception("ErrNoWaitingThread", "No threads for waiting.") def_exception("ErrNoFinishedThread", "No finished threads.") # # Waits until all specified threads have terminated. If a block is provided, # it is executed for each thread termination. # def ThreadsWait.all_waits(*threads) # :yield: thread tw = ThreadsWait.new(*threads) if block_given? tw.all_waits do |th| yield th end else tw.all_waits end end # # Creates a ThreadsWait object, specifying the threads to wait on. # Non-blocking. # def initialize(*threads) @threads = [] @wait_queue = Queue.new join_nowait(*threads) unless threads.empty? end # Returns the array of threads in the wait queue. attr :threads # # Returns +true+ if there are no threads to be synchronized. # def empty? @threads.empty? end # # Returns +true+ if any thread has terminated. # def finished? !@wait_queue.empty? end # # Waits for specified threads to terminate, and returns when one of # the threads terminated. # def join(*threads) join_nowait(*threads) next_wait end # # Specifies the threads that this object will wait for, but does not actually # wait. # def join_nowait(*threads) threads.flatten! @threads.concat threads for th in threads Thread.start(th) do |t| begin t.join ensure @wait_queue.push t end end end end # # Waits until any of the specified threads has terminated, and returns the one # that does. # # If there is no thread to wait, raises +ErrNoWaitingThread+. If +nonblock+ # is true, and there is no terminated thread, raises +ErrNoFinishedThread+. # def next_wait(nonblock = nil) ThreadsWait.fail ErrNoWaitingThread if @threads.empty? begin @threads.delete(th = @wait_queue.pop(nonblock)) th rescue ThreadError ThreadsWait.fail ErrNoFinishedThread end end # # Waits until all of the specified threads are terminated. If a block is # supplied for the method, it is executed for each thread termination. # # Raises exceptions in the same manner as +next_wait+. # def all_waits until @threads.empty? th = next_wait yield th if block_given? end end end ThWait = ThreadsWait # Documentation comments: # - Source of documentation is evenly split between Nutshell, existing # comments, and my own rephrasing. # - I'm not particularly confident that the comments are all exactly correct. # - The history, etc., up the top appears in the RDoc output. Perhaps it would # be better to direct that not to appear, and put something else there # instead. PK|]VCmathn.rbnu[# # mathn.rb - # $Release Version: 0.5 $ # $Revision: 1.1.1.1.4.1 $ # $Date: 1998/01/16 12:36:05 $ # by Keiju ISHITSUKA(SHL Japan Inc.) # # -- # # # require "complex.rb" require "rational.rb" require "matrix.rb" class Integer def gcd2(int) a = self.abs b = int.abs a, b = b, a if a < b pd_a = a.prime_division pd_b = b.prime_division gcd = 1 for pair in pd_a as = pd_b.assoc(pair[0]) if as gcd *= as[0] ** [as[1], pair[1]].min end end return gcd end def Integer.from_prime_division(pd) value = 1 for prime, index in pd value *= prime**index end value end def prime_division raise ZeroDivisionError if self == 0 ps = Prime.new value = self pv = [] for prime in ps count = 0 while (value1, mod = value.divmod(prime) mod) == 0 value = value1 count += 1 end if count != 0 pv.push [prime, count] end break if prime * prime >= value end if value > 1 pv.push [value, 1] end return pv end end class Prime include Enumerable def initialize @seed = 1 @primes = [] @counts = [] end def succ i = -1 size = @primes.size while i < size if i == -1 @seed += 1 i += 1 else while @seed > @counts[i] @counts[i] += @primes[i] end if @seed != @counts[i] i += 1 else i = -1 end end end @primes.push @seed @counts.push @seed + @seed return @seed end alias next succ def each loop do yield succ end end end class Fixnum alias / quo end class Bignum alias / quo end class Rational Unify = true def inspect format "%s/%s", numerator.inspect, denominator.inspect end alias power! ** def ** (other) if other.kind_of?(Rational) other2 = other if self < 0 return Complex.new!(self, 0) ** other elsif other == 0 return Rational(1,1) elsif self == 0 return Rational(0,1) elsif self == 1 return Rational(1,1) end npd = numerator.prime_division dpd = denominator.prime_division if other < 0 other = -other npd, dpd = dpd, npd end for elm in npd elm[1] = elm[1] * other if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 return Float(self) ** other2 end elm[1] = elm[1].to_i end for elm in dpd elm[1] = elm[1] * other if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 return Float(self) ** other2 end elm[1] = elm[1].to_i end num = Integer.from_prime_division(npd) den = Integer.from_prime_division(dpd) Rational(num,den) elsif other.kind_of?(Integer) if other > 0 num = numerator ** other den = denominator ** other elsif other < 0 num = denominator ** -other den = numerator ** -other elsif other == 0 num = 1 den = 1 end Rational.new!(num, den) elsif other.kind_of?(Float) Float(self) ** other else x , y = other.coerce(self) x ** y end end def power2(other) if other.kind_of?(Rational) if self < 0 return Complex(self, 0) ** other elsif other == 0 return Rational(1,1) elsif self == 0 return Rational(0,1) elsif self == 1 return Rational(1,1) end dem = nil x = self.denominator.to_f.to_i neard = self.denominator.to_f ** (1.0/other.denominator.to_f) loop do if (neard**other.denominator == self.denominator) dem = neaed break end end nearn = self.numerator.to_f ** (1.0/other.denominator.to_f) Rational(num,den) elsif other.kind_of?(Integer) if other > 0 num = numerator ** other den = denominator ** other elsif other < 0 num = denominator ** -other den = numerator ** -other elsif other == 0 num = 1 den = 1 end Rational.new!(num, den) elsif other.kind_of?(Float) Float(self) ** other else x , y = other.coerce(self) x ** y end end end module Math def sqrt(a) if a.kind_of?(Complex) abs = sqrt(a.real*a.real + a.image*a.image) # if not abs.kind_of?(Rational) # return a**Rational(1,2) # end x = sqrt((a.real + abs)/Rational(2)) y = sqrt((-a.real + abs)/Rational(2)) # if !(x.kind_of?(Rational) and y.kind_of?(Rational)) # return a**Rational(1,2) # end if a.image >= 0 Complex(x, y) else Complex(x, -y) end elsif a >= 0 rsqrt(a) else Complex(0,rsqrt(-a)) end end def rsqrt(a) if a.kind_of?(Float) sqrt!(a) elsif a.kind_of?(Rational) rsqrt(a.numerator)/rsqrt(a.denominator) else src = a max = 2 ** 32 byte_a = [src & 0xffffffff] # ruby's bug while (src >= max) and (src >>= 32) byte_a.unshift src & 0xffffffff end answer = 0 main = 0 side = 0 for elm in byte_a main = (main << 32) + elm side <<= 16 if answer != 0 if main * 4 < side * side applo = main.div(side) else applo = ((sqrt!(side * side + 4 * main) - side)/2.0).to_i + 1 end else applo = sqrt!(main).to_i + 1 end while (x = (side + applo) * applo) > main applo -= 1 end main -= x answer = (answer << 16) + applo side += applo * 2 end if main == 0 answer else sqrt!(a) end end end module_function :sqrt module_function :rsqrt end class Complex Unify = true end PK|];N-- yaml/error.rbnu[# # Error messages and exception class # module YAML # # Error messages # ERROR_NO_HEADER_NODE = "With UseHeader=false, the node Array or Hash must have elements" ERROR_NEED_HEADER = "With UseHeader=false, the node must be an Array or Hash" ERROR_BAD_EXPLICIT = "Unsupported explicit transfer: '%s'" ERROR_MANY_EXPLICIT = "More than one explicit transfer" ERROR_MANY_IMPLICIT = "More than one implicit request" ERROR_NO_ANCHOR = "No anchor for alias '%s'" ERROR_BAD_ANCHOR = "Invalid anchor: %s" ERROR_MANY_ANCHOR = "More than one anchor" ERROR_ANCHOR_ALIAS = "Can't define both an anchor and an alias" ERROR_BAD_ALIAS = "Invalid alias: %s" ERROR_MANY_ALIAS = "More than one alias" ERROR_ZERO_INDENT = "Can't use zero as an indentation width" ERROR_UNSUPPORTED_VERSION = "This release of YAML.rb does not support YAML version %s" ERROR_UNSUPPORTED_ENCODING = "Attempt to use unsupported encoding: %s" # # YAML Error classes # class Error < StandardError; end class ParseError < Error; end class TypeError < StandardError; end end PK|]7O O yaml/tag.rbnu[# -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4 # $Id: tag.rb 16084 2008-04-19 11:45:39Z knu $ # # = yaml/tag.rb: methods for associating a taguri to a class. # # Author:: why the lucky stiff # module YAML # A dictionary of taguris which map to # Ruby classes. @@tagged_classes = {} # # Associates a taguri _tag_ with a Ruby class _cls_. The taguri is used to give types # to classes when loading YAML. Taguris are of the form: # # tag:authorityName,date:specific # # The +authorityName+ is a domain name or email address. The +date+ is the date the type # was issued in YYYY or YYYY-MM or YYYY-MM-DD format. The +specific+ is a name for # the type being added. # # For example, built-in YAML types have 'yaml.org' as the +authorityName+ and '2002' as the # +date+. The +specific+ is simply the name of the type: # # tag:yaml.org,2002:int # tag:yaml.org,2002:float # tag:yaml.org,2002:timestamp # # The domain must be owned by you on the +date+ declared. If you don't own any domains on the # date you declare the type, you can simply use an e-mail address. # # tag:why@ruby-lang.org,2004:notes/personal # def YAML.tag_class( tag, cls ) if @@tagged_classes.has_key? tag warn "class #{ @@tagged_classes[tag] } held ownership of the #{ tag } tag" end @@tagged_classes[tag] = cls end # Returns the complete dictionary of taguris, paired with classes. The key for # the dictionary is the full taguri. The value for each key is the class constant # associated to that taguri. # # YAML.tagged_classes["tag:yaml.org,2002:int"] => Integer # def YAML.tagged_classes @@tagged_classes end end class Module # :stopdoc: # Adds a taguri _tag_ to a class, used when dumping or loading the class # in YAML. See YAML::tag_class for detailed information on typing and # taguris. def yaml_as( tag, sc = true ) verbose, $VERBOSE = $VERBOSE, nil class_eval <<-"end;", __FILE__, __LINE__+1 attr_writer :taguri def taguri if respond_to? :to_yaml_type YAML::tagurize( to_yaml_type[1..-1] ) else return @taguri if defined?(@taguri) and @taguri tag = #{ tag.dump } if self.class.yaml_tag_subclasses? and self.class != YAML::tagged_classes[tag] tag = "\#{ tag }:\#{ self.class.yaml_tag_class_name }" end tag end end def self.yaml_tag_subclasses?; #{ sc ? 'true' : 'false' }; end end; YAML::tag_class tag, self ensure $VERBOSE = verbose end # Transforms the subclass name into a name suitable for display # in a subclassed tag. def yaml_tag_class_name self.name end # Transforms the subclass name found in the tag into a Ruby # constant name. def yaml_tag_read_class( name ) name end end PK|]C00 yaml/ypath.rbnu[# # YAML::YPath # module YAML class YPath attr_accessor :segments, :predicates, :flags def initialize( str ) @segments = [] @predicates = [] @flags = nil while str =~ /^\/?(\/|[^\/\[]+)(?:\[([^\]]+)\])?/ @segments.push $1 @predicates.push $2 str = $' end unless str.to_s.empty? @segments += str.split( "/" ) end if @segments.length == 0 @segments.push "." end end def YPath.each_path( str ) # # Find choices # paths = [] str = "(#{ str })" while str.sub!( /\(([^()]+)\)/, "\n#{ paths.length }\n" ) paths.push $1.split( '|' ) end # # Construct all possible paths # all = [ str ] ( paths.length - 1 ).downto( 0 ) do |i| all = all.collect do |a| paths[i].collect do |p| a.gsub( /\n#{ i }\n/, p ) end end.flatten.uniq end all.collect do |path| yield YPath.new( path ) end end end end PK|] 8O4 yaml/dbm.rbnu[require 'yaml' require 'dbm' # # YAML + DBM = YDBM # - Same interface as DBM class # module YAML class DBM < ::DBM VERSION = "0.1" def []( key ) fetch( key ) end def []=( key, val ) store( key, val ) end def fetch( keystr, ifnone = nil ) begin val = super( keystr ) return YAML::load( val ) if String === val rescue IndexError end if block_given? yield keystr else ifnone end end def index( keystr ) super( keystr.to_yaml ) end def values_at( *keys ) keys.collect { |k| fetch( k ) } end def delete( key ) v = super( key ) if String === v v = YAML::load( v ) end v end def delete_if del_keys = keys.dup del_keys.delete_if { |k| yield( k, fetch( k ) ) == false } del_keys.each { |k| delete( k ) } self end def reject hsh = self.to_hash hsh.reject { |k,v| yield k, v } end def each_pair keys.each { |k| yield k, fetch( k ) } self end def each_value super { |v| yield YAML::load( v ) } self end def values super.collect { |v| YAML::load( v ) } end def has_value?( val ) each_value { |v| return true if v == val } return false end def invert h = {} keys.each { |k| h[ self.fetch( k ) ] = k } h end def replace( hsh ) clear update( hsh ) end def shift a = super a[1] = YAML::load( a[1] ) if a a end def select( *keys ) if block_given? self.keys.collect { |k| v = self[k]; [k, v] if yield k, v }.compact else values_at( *keys ) end end def store( key, val ) super( key, val.to_yaml ) val end def update( hsh ) hsh.keys.each do |k| self.store( k, hsh.fetch( k ) ) end self end def to_a a = [] keys.each { |k| a.push [ k, self.fetch( k ) ] } a end def to_hash h = {} keys.each { |k| h[ k ] = self.fetch( k ) } h end alias :each :each_pair end end PK|]tyaml/yamlnode.rbnu[# # YAML::YamlNode class # require 'yaml/basenode' module YAML # # YAML Generic Model container # class YamlNode include BaseNode attr_accessor :kind, :type_id, :value, :anchor def initialize( t, v ) @type_id = t if Hash === v @kind = 'map' @value = {} v.each { |k,v| @value[ k.transform ] = [ k, v ] } elsif Array === v @kind = 'seq' @value = v elsif String === v @kind = 'scalar' @value = v end end # # Transform this node fully into a native type # def transform t = nil if @value.is_a? Hash t = {} @value.each { |k,v| t[ k ] = v[1].transform } elsif @value.is_a? Array t = [] @value.each { |v| t.push v.transform } else t = @value end YAML.transfer_method( @type_id, t ) end end end PK|]Uyyyaml/baseemitter.rbnu[# # BaseEmitter # require 'yaml/constants' require 'yaml/encoding' require 'yaml/error' module YAML module BaseEmitter def options( opt = nil ) if opt @options[opt] || YAML::DEFAULTS[opt] else @options end end def options=( opt ) @options = opt end # # Emit binary data # def binary_base64( value ) self << "!binary " self.node_text( [value].pack("m"), '|' ) end # # Emit plain, normal flowing text # def node_text( value, block = nil ) @seq_map = false valx = value.dup unless block block = if options(:UseBlock) '|' elsif not options(:UseFold) and valx =~ /\n[ \t]/ and not valx =~ /#{YAML::ESCAPE_CHAR}/ '|' else '>' end indt = $&.to_i if block =~ /\d+/ if valx =~ /(\A\n*[ \t#]|^---\s+)/ indt = options(:Indent) unless indt.to_i > 0 block += indt.to_s end block += if valx =~ /\n\Z\n/ "+" elsif valx =~ /\Z\n/ "" else "-" end end block += "\n" if block[0] == ?" esc_skip = ( "\t\n" unless valx =~ /^[ \t]/ ) || "" valx = fold( YAML::escape( valx, esc_skip ) + "\"" ).chomp self << '"' + indent_text( valx, indt, false ) else if block[0] == ?> valx = fold( valx ) end #p [block, indt] self << block + indent_text( valx, indt ) end end # # Emit a simple, unqouted string # def simple( value ) @seq_map = false self << value.to_s end # # Emit double-quoted string # def double( value ) "\"#{YAML.escape( value )}\"" end # # Emit single-quoted string # def single( value ) "'#{value}'" end # # Write a text block with the current indent # def indent_text( text, mod, first_line = true ) return "" if text.to_s.empty? spacing = indent( mod ) text = text.gsub( /\A([^\n])/, "#{ spacing }\\1" ) if first_line return text.gsub( /\n^([^\n])/, "\n#{spacing}\\1" ) end # # Write a current indent # def indent( mod = nil ) #p [ self.id, level, mod, :INDENT ] if level <= 0 mod ||= 0 else mod ||= options(:Indent) mod += ( level - 1 ) * options(:Indent) end return " " * mod end # # Add indent to the buffer # def indent! self << indent end # # Folding paragraphs within a column # def fold( value ) value.gsub( /(^[ \t]+.*$)|(\S.{0,#{options(:BestWidth) - 1}})(?:[ \t]+|(\n+(?=[ \t]|\Z))|$)/ ) do $1 || $2 + ( $3 || "\n" ) end end # # Quick mapping # def map( type, &e ) val = Mapping.new e.call( val ) self << "#{type} " if type.length.nonzero? # # Empty hashes # if val.length.zero? self << "{}" @seq_map = false else # FIXME # if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero? # @headless = 1 # end defkey = @options.delete( :DefaultKey ) if defkey seq_map_shortcut self << "= : " defkey.to_yaml( :Emitter => self ) end # # Emit the key and value # val.each { |v| seq_map_shortcut if v[0].is_complex_yaml? self << "? " end v[0].to_yaml( :Emitter => self ) if v[0].is_complex_yaml? self << "\n" indent! end self << ": " v[1].to_yaml( :Emitter => self ) } end end def seq_map_shortcut # FIXME: seq_map needs to work with the new anchoring system # if @seq_map # @anchor_extras[@buffer.length - 1] = "\n" + indent # @seq_map = false # else self << "\n" indent! # end end # # Quick sequence # def seq( type, &e ) @seq_map = false val = Sequence.new e.call( val ) self << "#{type} " if type.length.nonzero? # # Empty arrays # if val.length.zero? self << "[]" else # FIXME # if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero? # @headless = 1 # end # # Emit the key and value # val.each { |v| self << "\n" indent! self << "- " @seq_map = true if v.class == Hash v.to_yaml( :Emitter => self ) } end end end # # Emitter helper classes # class Mapping < Array def add( k, v ) push [k, v] end end class Sequence < Array def add( v ) push v end end end PK|]uo]]yaml/encoding.rbnu[# # Handle Unicode-to-Internal conversion # module YAML # # Escape the string, condensing common escapes # def YAML.escape( value, skip = "" ) value.gsub( /\\/, "\\\\\\" ). gsub( /"/, "\\\"" ). gsub( /([\x00-\x1f])/ ) do skip[$&] || ESCAPES[ $&.unpack("C")[0] ] end end # # Unescape the condenses escapes # def YAML.unescape( value ) value.gsub( /\\(?:([nevfbart\\])|0?x([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/ ) { if $3 ["#$3".hex ].pack('U*') elsif $2 [$2].pack( "H2" ) else UNESCAPES[$1] end } end end PK|]k"u((yaml/loader.rbnu[# # YAML::Loader class # .. type handling .. # module YAML class Loader TRANSFER_DOMAINS = { 'yaml.org,2002' => {}, 'ruby.yaml.org,2002' => {} } PRIVATE_TYPES = {} IMPLICIT_TYPES = [ 'null', 'bool', 'time', 'int', 'float' ] end end PK|]! yaml/store.rbnu[# # YAML::Store # require 'yaml' require 'pstore' class YAML::Store < PStore def initialize( *o ) @opt = YAML::DEFAULTS.dup if String === o.first super(o.shift) end if o.last.is_a? Hash @opt.update(o.pop) end end def dump(table) @table.to_yaml(@opt) end def load(content) table = YAML::load(content) if table == false {} else table end end def marshal_dump_supports_canonical_option? false end EMPTY_MARSHAL_DATA = {}.to_yaml EMPTY_MARSHAL_CHECKSUM = Digest::MD5.digest(EMPTY_MARSHAL_DATA) def empty_marshal_data EMPTY_MARSHAL_DATA end def empty_marshal_checksum EMPTY_MARSHAL_CHECKSUM end end PK|]]yaml/constants.rbnu[# # Constants used throughout the library # module YAML # # Constants # VERSION = '0.60' SUPPORTED_YAML_VERSIONS = ['1.0'] # # Parser tokens # WORD_CHAR = 'A-Za-z0-9' PRINTABLE_CHAR = '-_A-Za-z0-9!?/()$\'". ' NOT_PLAIN_CHAR = '\x7f\x0-\x1f\x80-\x9f' ESCAPE_CHAR = '[\\x00-\\x09\\x0b-\\x1f]' INDICATOR_CHAR = '*&!|\\\\^@%{}[]=' SPACE_INDICATORS = '-#:,?' RESTRICTED_INDICATORS = '#:,}]' DNS_COMP_RE = "\\w(?:[-\\w]*\\w)?" DNS_NAME_RE = "(?:(?:#{DNS_COMP_RE}\\.)+#{DNS_COMP_RE}|#{DNS_COMP_RE})" ESCAPES = %w{\x00 \x01 \x02 \x03 \x04 \x05 \x06 \a \x08 \t \n \v \f \r \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 \x1a \e \x1c \x1d \x1e \x1f } UNESCAPES = { 'a' => "\x07", 'b' => "\x08", 't' => "\x09", 'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c", 'r' => "\x0d", 'e' => "\x1b", '\\' => '\\', } # # Default settings # DEFAULTS = { :Indent => 2, :UseHeader => false, :UseVersion => false, :Version => '1.0', :SortKeys => false, :AnchorFormat => 'id%03d', :ExplicitTypes => false, :WidthType => 'absolute', :BestWidth => 80, :UseBlock => false, :UseFold => false, :Encoding => :None } end PK|] yaml/syck.rbnu[# # YAML::Syck module # .. glues syck and yaml.rb together .. # require 'syck' require 'yaml/basenode' module YAML module Syck # # Mixin BaseNode functionality # class Node include YAML::BaseNode end end end PK|]3vyaml/stream.rbnu[module YAML # # YAML::Stream -- for emitting many documents # class Stream attr_accessor :documents, :options def initialize( opts = {} ) @options = opts @documents = [] end def []( i ) @documents[ i ] end def add( doc ) @documents << doc end def edit( doc_num, doc ) @documents[ doc_num ] = doc end def emit( io = nil ) # opts = @options.dup # opts[:UseHeader] = true if @documents.length > 1 out = YAML.emitter out.reset( io || io2 = StringIO.new ) @documents.each { |v| v.to_yaml( out ) } io || ( io2.rewind; io2.read ) end end end PK|]Ryaml/basenode.rbnu[# # YAML::BaseNode class # require 'yaml/ypath' module YAML # # YAML Generic Model container # module BaseNode # # Search for YPath entry and return # qualified nodes. # def select( ypath_str ) matches = match_path( ypath_str ) # # Create a new generic view of the elements selected # if matches result = [] matches.each { |m| result.push m.last } YAML.transfer( 'seq', result ) end end # # Search for YPath entry and return # transformed nodes. # def select!( ypath_str ) matches = match_path( ypath_str ) # # Create a new generic view of the elements selected # if matches result = [] matches.each { |m| result.push m.last.transform } result end end # # Search for YPath entry and return a list of # qualified paths. # def search( ypath_str ) matches = match_path( ypath_str ) if matches matches.collect { |m| path = [] m.each_index { |i| path.push m[i] if ( i % 2 ).zero? } "/" + path.compact.join( "/" ) } end end def at( seg ) if Hash === @value self[seg] elsif Array === @value and seg =~ /\A\d+\Z/ and @value[seg.to_i] @value[seg.to_i] end end # # YPath search returning a complete depth array # def match_path( ypath_str ) depth = 0 matches = [] YPath.each_path( ypath_str ) do |ypath| seg = match_segment( ypath, 0 ) matches += seg if seg end matches.uniq end # # Search a node for a single YPath segment # def match_segment( ypath, depth ) deep_nodes = [] seg = ypath.segments[ depth ] if seg == "/" unless String === @value idx = -1 @value.collect { |v| idx += 1 if Hash === @value match_init = [v[0].transform, v[1]] match_deep = v[1].match_segment( ypath, depth ) else match_init = [idx, v] match_deep = v.match_segment( ypath, depth ) end if match_deep match_deep.each { |m| deep_nodes.push( match_init + m ) } end } end depth += 1 seg = ypath.segments[ depth ] end match_nodes = case seg when "." [[nil, self]] when ".." [["..", nil]] when "*" if @value.is_a? Enumerable idx = -1 @value.collect { |h| idx += 1 if Hash === @value [h[0].transform, h[1]] else [idx, h] end } end else if seg =~ /^"(.*)"$/ seg = $1 elsif seg =~ /^'(.*)'$/ seg = $1 end if ( v = at( seg ) ) [[ seg, v ]] end end return deep_nodes unless match_nodes pred = ypath.predicates[ depth ] if pred case pred when /^\.=/ pred = $' # ' match_nodes.reject! { |n| n.last.value != pred } else match_nodes.reject! { |n| n.last.at( pred ).nil? } end end return match_nodes + deep_nodes unless ypath.segments.length > depth + 1 #puts "DEPTH: #{depth + 1}" deep_nodes = [] match_nodes.each { |n| if n[1].is_a? BaseNode match_deep = n[1].match_segment( ypath, depth + 1 ) if match_deep match_deep.each { |m| deep_nodes.push( n + m ) } end else deep_nodes = [] end } deep_nodes = nil if deep_nodes.length == 0 deep_nodes end # # We want the node to act like as Hash # if it is. # def []( *key ) if Hash === @value v = @value.detect { |k,| k.transform == key.first } v[1] if v elsif Array === @value @value.[]( *key ) end end def children if Hash === @value @value.values.collect { |c| c[1] } elsif Array === @value @value end end def children_with_index if Hash === @value @value.keys.collect { |i| [self[i], i] } elsif Array === @value i = -1; @value.collect { |v| i += 1; [v, i] } end end def emit transform.to_yaml end end end PK|]b\1 yaml/types.rbnu[# -*- mode: ruby; ruby-indent-level: 4 -*- vim: sw=4 # # Classes required by the full core typeset # module YAML # # Default private type # class PrivateType def self.tag_subclasses?; false; end verbose, $VERBOSE = $VERBOSE, nil def initialize( type, val ) @type_id = type; @value = val @value.taguri = "x-private:#{ @type_id }" end def to_yaml( opts = {} ) @value.to_yaml( opts ) end ensure $VERBOSE = verbose end # # Default domain type # class DomainType def self.tag_subclasses?; false; end verbose, $VERBOSE = $VERBOSE, nil def initialize( domain, type, val ) @domain = domain; @type_id = type; @value = val @value.taguri = "tag:#{ @domain }:#{ @type_id }" end def to_yaml( opts = {} ) @value.to_yaml( opts ) end ensure $VERBOSE = verbose end # # Unresolved objects # class Object def self.tag_subclasses?; false; end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.map( "tag:ruby.yaml.org,2002:object:#{ @class }", to_yaml_style ) do |map| @ivars.each do |k,v| map.add( k, v ) end end end end end # # YAML Hash class to support comments and defaults # class SpecialHash < ::Hash attr_accessor :default def inspect self.default.to_s end def to_s self.default.to_s end def update( h ) if YAML::SpecialHash === h @default = h.default if h.default end super( h ) end def to_yaml( opts = {} ) opts[:DefaultKey] = self.default super( opts ) end end # # Builtin collection: !omap # class Omap < ::Array yaml_as "tag:yaml.org,2002:omap" def yaml_initialize( tag, val ) if Array === val val.each do |v| if Hash === v concat( v.to_a ) # Convert the map to a sequence else raise YAML::Error, "Invalid !omap entry: " + val.inspect end end else raise YAML::Error, "Invalid !omap: " + val.inspect end self end def self.[]( *vals ) o = Omap.new 0.step( vals.length - 1, 2 ) do |i| o[vals[i]] = vals[i+1] end o end def []( k ) self.assoc( k ).to_a[1] end def []=( k, *rest ) val, set = rest.reverse if ( tmp = self.assoc( k ) ) and not set tmp[1] = val else self << [ k, val ] end val end def has_key?( k ) self.assoc( k ) ? true : false end def is_complex_yaml? true end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.seq( taguri, to_yaml_style ) do |seq| self.each do |v| seq.add( Hash[ *v ] ) end end end end end # # Builtin collection: !pairs # class Pairs < ::Array yaml_as "tag:yaml.org,2002:pairs" def yaml_initialize( tag, val ) if Array === val val.each do |v| if Hash === v concat( v.to_a ) # Convert the map to a sequence else raise YAML::Error, "Invalid !pairs entry: " + val.inspect end end else raise YAML::Error, "Invalid !pairs: " + val.inspect end self end def self.[]( *vals ) p = Pairs.new 0.step( vals.length - 1, 2 ) { |i| p[vals[i]] = vals[i+1] } p end def []( k ) self.assoc( k ).to_a end def []=( k, val ) self << [ k, val ] val end def has_key?( k ) self.assoc( k ) ? true : false end def is_complex_yaml? true end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.seq( taguri, to_yaml_style ) do |seq| self.each do |v| seq.add( Hash[ *v ] ) end end end end end # # Builtin collection: !set # class Set < ::Hash yaml_as "tag:yaml.org,2002:set" end end PK|]g\22yaml/rubytypes.rbnu[# -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4 require 'date' class Class def to_yaml( opts = {} ) raise TypeError, "can't dump anonymous class %s" % self.class end end class Object yaml_as "tag:ruby.yaml.org,2002:object" def to_yaml_style; end def to_yaml_properties; instance_variables.sort; end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.map( taguri, to_yaml_style ) do |map| to_yaml_properties.each do |m| map.add( m[1..-1], instance_variable_get( m ) ) end end end end end class Hash yaml_as "tag:ruby.yaml.org,2002:hash" yaml_as "tag:yaml.org,2002:map" def yaml_initialize( tag, val ) if Array === val update Hash.[]( *val ) # Convert the map to a sequence elsif Hash === val update val else raise YAML::TypeError, "Invalid map explicitly tagged #{ tag }: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.map( taguri, to_yaml_style ) do |map| each do |k, v| map.add( k, v ) end end end end end class Struct yaml_as "tag:ruby.yaml.org,2002:struct" def self.yaml_tag_class_name; self.name.gsub( "Struct::", "" ); end def self.yaml_tag_read_class( name ); "Struct::#{ name }"; end def self.yaml_new( klass, tag, val ) if Hash === val struct_type = nil # # Use existing Struct if it exists # props = {} val.delete_if { |k,v| props[k] = v if k =~ /^@/ } begin struct_name, struct_type = YAML.read_type_class( tag, Struct ) rescue NameError end if not struct_type struct_def = [ tag.split( ':', 4 ).last ] struct_type = Struct.new( *struct_def.concat( val.keys.collect { |k| k.intern } ) ) end # # Set the Struct properties # st = YAML::object_maker( struct_type, {} ) st.members.each do |m| st.send( "#{m}=", val[m] ) end props.each do |k,v| st.instance_variable_set(k, v) end st else raise YAML::TypeError, "Invalid Ruby Struct: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| # # Basic struct is passed as a YAML map # out.map( taguri, to_yaml_style ) do |map| self.members.each do |m| map.add( m, self[m] ) end self.to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end end end end class Array yaml_as "tag:ruby.yaml.org,2002:array" yaml_as "tag:yaml.org,2002:seq" def yaml_initialize( tag, val ); concat( val.to_a ); end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.seq( taguri, to_yaml_style ) do |seq| each do |x| seq.add( x ) end end end end end class Exception yaml_as "tag:ruby.yaml.org,2002:exception" def Exception.yaml_new( klass, tag, val ) o = YAML.object_maker( klass, { 'mesg' => val.delete( 'message' ) } ) val.each_pair do |k,v| o.instance_variable_set("@#{k}", v) end o end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.map( taguri, to_yaml_style ) do |map| map.add( 'message', message ) to_yaml_properties.each do |m| map.add( m[1..-1], instance_variable_get( m ) ) end end end end end class String yaml_as "tag:ruby.yaml.org,2002:string" yaml_as "tag:yaml.org,2002:binary" yaml_as "tag:yaml.org,2002:str" def is_complex_yaml? to_yaml_style or not to_yaml_properties.empty? or self =~ /\n.+/ end def is_binary_data? ( self.count( "^ -~", "^\r\n" ).fdiv(self.size) > 0.3 || self.index( "\x00" ) ) unless empty? end def String.yaml_new( klass, tag, val ) val = val.unpack("m")[0] if tag == "tag:yaml.org,2002:binary" val = { 'str' => val } if String === val if Hash === val s = klass.allocate # Thank you, NaHi String.instance_method(:initialize). bind(s). call( val.delete( 'str' ) ) val.each { |k,v| s.instance_variable_set( k, v ) } s else raise YAML::TypeError, "Invalid String: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( is_complex_yaml? ? self : nil, opts ) do |out| if is_binary_data? out.scalar( "tag:yaml.org,2002:binary", [self].pack("m"), :literal ) elsif to_yaml_properties.empty? out.scalar( taguri, self, self =~ /^:/ ? :quote2 : to_yaml_style ) else out.map( taguri, to_yaml_style ) do |map| map.add( 'str', "#{self}" ) to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end end end end end class Symbol yaml_as "tag:ruby.yaml.org,2002:symbol" yaml_as "tag:ruby.yaml.org,2002:sym" def Symbol.yaml_new( klass, tag, val ) if String === val val = YAML::load( val ) if val =~ /\A(["']).*\1\z/ val.intern else raise YAML::TypeError, "Invalid Symbol: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( "tag:yaml.org,2002:str", self.inspect, :plain ) end end end class Range yaml_as "tag:ruby.yaml.org,2002:range" def Range.yaml_new( klass, tag, val ) inr = %r'(\w+|[+-]?\d+(?:\.\d+)?(?:e[+-]\d+)?|"(?:[^\\"]|\\.)*")' opts = {} if String === val and val =~ /^#{inr}(\.{2,3})#{inr}$/o r1, rdots, r2 = $1, $2, $3 opts = { 'begin' => YAML.load( "--- #{r1}" ), 'end' => YAML.load( "--- #{r2}" ), 'excl' => rdots.length == 3 } val = {} elsif Hash === val opts['begin'] = val.delete('begin') opts['end'] = val.delete('end') opts['excl'] = val.delete('excl') end if Hash === opts r = YAML::object_maker( klass, {} ) # Thank you, NaHi Range.instance_method(:initialize). bind(r). call( opts['begin'], opts['end'], opts['excl'] ) val.each { |k,v| r.instance_variable_set( k, v ) } r else raise YAML::TypeError, "Invalid Range: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| # if self.begin.is_complex_yaml? or self.begin.respond_to? :to_str or # self.end.is_complex_yaml? or self.end.respond_to? :to_str or # not to_yaml_properties.empty? out.map( taguri, to_yaml_style ) do |map| map.add( 'begin', self.begin ) map.add( 'end', self.end ) map.add( 'excl', self.exclude_end? ) to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end # else # out.scalar( taguri ) do |sc| # sc.embed( self.begin ) # sc.concat( self.exclude_end? ? "..." : ".." ) # sc.embed( self.end ) # end # end end end end class Regexp yaml_as "tag:ruby.yaml.org,2002:regexp" def Regexp.yaml_new( klass, tag, val ) if String === val and val =~ /^\/(.*)\/([mix]*)$/ val = { 'regexp' => $1, 'mods' => $2 } end if Hash === val mods = nil unless val['mods'].to_s.empty? mods = 0x00 mods |= Regexp::EXTENDED if val['mods'].include?( 'x' ) mods |= Regexp::IGNORECASE if val['mods'].include?( 'i' ) mods |= Regexp::MULTILINE if val['mods'].include?( 'm' ) end val.delete( 'mods' ) r = YAML::object_maker( klass, {} ) Regexp.instance_method(:initialize). bind(r). call( val.delete( 'regexp' ), mods ) val.each { |k,v| r.instance_variable_set( k, v ) } r else raise YAML::TypeError, "Invalid Regular expression: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| if to_yaml_properties.empty? out.scalar( taguri, self.inspect, :plain ) else out.map( taguri, to_yaml_style ) do |map| src = self.inspect if src =~ /\A\/(.*)\/([a-z]*)\Z/ map.add( 'regexp', $1 ) map.add( 'mods', $2 ) else raise YAML::TypeError, "Invalid Regular expression: " + src end to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end end end end end class Time yaml_as "tag:ruby.yaml.org,2002:time" yaml_as "tag:yaml.org,2002:timestamp" def Time.yaml_new( klass, tag, val ) if Hash === val t = val.delete( 'at' ) val.each { |k,v| t.instance_variable_set( k, v ) } t else raise YAML::TypeError, "Invalid Time: " + val.inspect end end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| tz = "Z" # from the tidy Tobias Peters Thanks! unless self.utc? utc_same_instant = self.dup.utc utc_same_writing = Time.utc(year,month,day,hour,min,sec,usec) difference_to_utc = utc_same_writing - utc_same_instant if (difference_to_utc < 0) difference_sign = '-' absolute_difference = -difference_to_utc else difference_sign = '+' absolute_difference = difference_to_utc end difference_minutes = (absolute_difference/60).round tz = "%s%02d:%02d" % [ difference_sign, difference_minutes / 60, difference_minutes % 60] end standard = self.strftime( "%Y-%m-%d %H:%M:%S" ) standard += ".%06d" % [usec] if usec.nonzero? standard += " %s" % [tz] if to_yaml_properties.empty? out.scalar( taguri, standard, :plain ) else out.map( taguri, to_yaml_style ) do |map| map.add( 'at', standard ) to_yaml_properties.each do |m| map.add( m, instance_variable_get( m ) ) end end end end end end class Date yaml_as "tag:yaml.org,2002:timestamp#ymd" def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.scalar( "tag:yaml.org,2002:timestamp", self.to_s, :plain ) end end end class Integer yaml_as "tag:yaml.org,2002:int" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( "tag:yaml.org,2002:int", self.to_s, :plain ) end end end class Float yaml_as "tag:yaml.org,2002:float" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| str = self.to_s if str == "Infinity" str = ".Inf" elsif str == "-Infinity" str = "-.Inf" elsif str == "NaN" str = ".NaN" end out.scalar( "tag:yaml.org,2002:float", str, :plain ) end end end class TrueClass yaml_as "tag:yaml.org,2002:bool#yes" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( taguri, "true", :plain ) end end end class FalseClass yaml_as "tag:yaml.org,2002:bool#no" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( taguri, "false", :plain ) end end end class NilClass yaml_as "tag:yaml.org,2002:null" def to_yaml( opts = {} ) YAML::quick_emit( nil, opts ) do |out| out.scalar( taguri, "", :plain ) end end end PK|]׏yaml/stringio.rbnu[# # Limited StringIO if no core lib is available # begin require 'stringio' rescue LoadError # StringIO based on code by MoonWolf class StringIO def initialize(string="") @string=string @pos=0 @eof=(string.size==0) end def pos @pos end def eof @eof end alias eof? eof def readline(rs=$/) if @eof raise EOFError else if p = @string[@pos..-1]=~rs line = @string[@pos,p+1] else line = @string[@pos..-1] end @pos+=line.size @eof =true if @pos==@string.size $_ = line end end def rewind seek(0,0) end def seek(offset,whence) case whence when 0 @pos=offset when 1 @pos+=offset when 2 @pos=@string.size+offset end @eof=(@pos>=@string.size) 0 end end # # Class method for creating streams # def YAML.make_stream( io ) if String === io io = StringIO.new( io ) elsif not IO === io raise YAML::Error, "YAML stream must be an IO or String object." end if YAML::unicode def io.readline YAML.utf_to_internal( readline( @ln_sep ), @utf_encoding ) end def io.check_unicode @utf_encoding = YAML.sniff_encoding( read( 4 ) ) @ln_sep = YAML.enc_separator( @utf_encoding ) seek( -4, IO::SEEK_CUR ) end def io.utf_encoding @utf_encoding end io.check_unicode else def io.utf_encoding :None end end io end end PK|]uSɂ;; getoptlong.rbnu[# # GetoptLong for Ruby # # Copyright (C) 1998, 1999, 2000 Motoyuki Kasahara. # # You may redistribute and/or modify this library under the same license # terms as Ruby. # # See GetoptLong for documentation. # # Additional documents and the latest version of `getoptlong.rb' can be # found at http://www.sra.co.jp/people/m-kasahr/ruby/getoptlong/ # The GetoptLong class allows you to parse command line options similarly to # the GNU getopt_long() C library call. Note, however, that GetoptLong is a # pure Ruby implementation. # # GetoptLong allows for POSIX-style options like --file as well # as single letter options like -f # # The empty option -- (two minus symbols) is used to end option # processing. This can be particularly important if options have optional # arguments. # # Here is a simple example of usage: # # # == Synopsis # # # # hello: greets user, demonstrates command line parsing # # # # == Usage # # # # hello [OPTION] ... DIR # # # # -h, --help: # # show help # # # # --repeat x, -n x: # # repeat x times # # # # --name [name]: # # greet user by name, if name not supplied default is John # # # # DIR: The directory in which to issue the greeting. # # require 'getoptlong' # require 'rdoc/usage' # # opts = GetoptLong.new( # [ '--help', '-h', GetoptLong::NO_ARGUMENT ], # [ '--repeat', '-n', GetoptLong::REQUIRED_ARGUMENT ], # [ '--name', GetoptLong::OPTIONAL_ARGUMENT ] # ) # # dir = nil # name = nil # repetitions = 1 # opts.each do |opt, arg| # case opt # when '--help' # RDoc::usage # when '--repeat' # repetitions = arg.to_i # when '--name' # if arg == '' # name = 'John' # else # name = arg # end # end # end # # if ARGV.length != 1 # puts "Missing dir argument (try --help)" # exit 0 # end # # dir = ARGV.shift # # Dir.chdir(dir) # for i in (1..repetitions) # print "Hello" # if name # print ", #{name}" # end # puts # end # # Example command line: # # hello -n 6 --name -- /tmp # class GetoptLong # # Orderings. # ORDERINGS = [REQUIRE_ORDER = 0, PERMUTE = 1, RETURN_IN_ORDER = 2] # # Argument flags. # ARGUMENT_FLAGS = [NO_ARGUMENT = 0, REQUIRED_ARGUMENT = 1, OPTIONAL_ARGUMENT = 2] # # Status codes. # STATUS_YET, STATUS_STARTED, STATUS_TERMINATED = 0, 1, 2 # # Error types. # class Error < StandardError; end class AmbigousOption < Error; end class NeedlessArgument < Error; end class MissingArgument < Error; end class InvalidOption < Error; end # # Set up option processing. # # The options to support are passed to new() as an array of arrays. # Each sub-array contains any number of String option names which carry # the same meaning, and one of the following flags: # # GetoptLong::NO_ARGUMENT :: Option does not take an argument. # # GetoptLong::REQUIRED_ARGUMENT :: Option always takes an argument. # # GetoptLong::OPTIONAL_ARGUMENT :: Option may or may not take an argument. # # The first option name is considered to be the preferred (canonical) name. # Other than that, the elements of each sub-array can be in any order. # def initialize(*arguments) # # Current ordering. # if ENV.include?('POSIXLY_CORRECT') @ordering = REQUIRE_ORDER else @ordering = PERMUTE end # # Hash table of option names. # Keys of the table are option names, and their values are canonical # names of the options. # @canonical_names = Hash.new # # Hash table of argument flags. # Keys of the table are option names, and their values are argument # flags of the options. # @argument_flags = Hash.new # # Whether error messages are output to $deferr. # @quiet = FALSE # # Status code. # @status = STATUS_YET # # Error code. # @error = nil # # Error message. # @error_message = nil # # Rest of catenated short options. # @rest_singles = '' # # List of non-option-arguments. # Append them to ARGV when option processing is terminated. # @non_option_arguments = Array.new if 0 < arguments.length set_options(*arguments) end end # # Set the handling of the ordering of options and arguments. # A RuntimeError is raised if option processing has already started. # # The supplied value must be a member of GetoptLong::ORDERINGS. It alters # the processing of options as follows: # # REQUIRE_ORDER : # # Options are required to occur before non-options. # # Processing of options ends as soon as a word is encountered that has not # been preceded by an appropriate option flag. # # For example, if -a and -b are options which do not take arguments, # parsing command line arguments of '-a one -b two' would result in # 'one', '-b', 'two' being left in ARGV, and only ('-a', '') being # processed as an option/arg pair. # # This is the default ordering, if the environment variable # POSIXLY_CORRECT is set. (This is for compatibility with GNU getopt_long.) # # PERMUTE : # # Options can occur anywhere in the command line parsed. This is the # default behavior. # # Every sequence of words which can be interpreted as an option (with or # without argument) is treated as an option; non-option words are skipped. # # For example, if -a does not require an argument and -b optionally takes # an argument, parsing '-a one -b two three' would result in ('-a','') and # ('-b', 'two') being processed as option/arg pairs, and 'one','three' # being left in ARGV. # # If the ordering is set to PERMUTE but the environment variable # POSIXLY_CORRECT is set, REQUIRE_ORDER is used instead. This is for # compatibility with GNU getopt_long. # # RETURN_IN_ORDER : # # All words on the command line are processed as options. Words not # preceded by a short or long option flag are passed as arguments # with an option of '' (empty string). # # For example, if -a requires an argument but -b does not, a command line # of '-a one -b two three' would result in option/arg pairs of ('-a', 'one') # ('-b', ''), ('', 'two'), ('', 'three') being processed. # def ordering=(ordering) # # The method is failed if option processing has already started. # if @status != STATUS_YET set_error(ArgumentError, "argument error") raise RuntimeError, "invoke ordering=, but option processing has already started" end # # Check ordering. # if !ORDERINGS.include?(ordering) raise ArgumentError, "invalid ordering `#{ordering}'" end if ordering == PERMUTE && ENV.include?('POSIXLY_CORRECT') @ordering = REQUIRE_ORDER else @ordering = ordering end end # # Return ordering. # attr_reader :ordering # # Set options. Takes the same argument as GetoptLong.new. # # Raises a RuntimeError if option processing has already started. # def set_options(*arguments) # # The method is failed if option processing has already started. # if @status != STATUS_YET raise RuntimeError, "invoke set_options, but option processing has already started" end # # Clear tables of option names and argument flags. # @canonical_names.clear @argument_flags.clear arguments.each do |arg| # # Each argument must be an Array. # if !arg.is_a?(Array) raise ArgumentError, "the option list contains non-Array argument" end # # Find an argument flag and it set to `argument_flag'. # argument_flag = nil arg.each do |i| if ARGUMENT_FLAGS.include?(i) if argument_flag != nil raise ArgumentError, "too many argument-flags" end argument_flag = i end end raise ArgumentError, "no argument-flag" if argument_flag == nil canonical_name = nil arg.each do |i| # # Check an option name. # next if i == argument_flag begin if !i.is_a?(String) || i !~ /^-([^-]|-.+)$/ raise ArgumentError, "an invalid option `#{i}'" end if (@canonical_names.include?(i)) raise ArgumentError, "option redefined `#{i}'" end rescue @canonical_names.clear @argument_flags.clear raise end # # Register the option (`i') to the `@canonical_names' and # `@canonical_names' Hashes. # if canonical_name == nil canonical_name = i end @canonical_names[i] = canonical_name @argument_flags[i] = argument_flag end raise ArgumentError, "no option name" if canonical_name == nil end return self end # # Set/Unset `quiet' mode. # attr_writer :quiet # # Return the flag of `quiet' mode. # attr_reader :quiet # # `quiet?' is an alias of `quiet'. # alias quiet? quiet # # Explicitly terminate option processing. # def terminate return nil if @status == STATUS_TERMINATED raise RuntimeError, "an error has occured" if @error != nil @status = STATUS_TERMINATED @non_option_arguments.reverse_each do |argument| ARGV.unshift(argument) end @canonical_names = nil @argument_flags = nil @rest_singles = nil @non_option_arguments = nil return self end # # Returns true if option processing has terminated, false otherwise. # def terminated? return @status == STATUS_TERMINATED end # # Set an error (protected). # def set_error(type, message) $deferr.print("#{$0}: #{message}\n") if !@quiet @error = type @error_message = message @canonical_names = nil @argument_flags = nil @rest_singles = nil @non_option_arguments = nil raise type, message end protected :set_error # # Examine whether an option processing is failed. # attr_reader :error # # `error?' is an alias of `error'. # alias error? error # Return the appropriate error message in POSIX-defined format. # If no error has occurred, returns nil. # def error_message return @error_message end # # Get next option name and its argument, as an Array of two elements. # # The option name is always converted to the first (preferred) # name given in the original options to GetoptLong.new. # # Example: ['--option', 'value'] # # Returns nil if the processing is complete (as determined by # STATUS_TERMINATED). # def get option_name, option_argument = nil, '' # # Check status. # return nil if @error != nil case @status when STATUS_YET @status = STATUS_STARTED when STATUS_TERMINATED return nil end # # Get next option argument. # if 0 < @rest_singles.length argument = '-' + @rest_singles elsif (ARGV.length == 0) terminate return nil elsif @ordering == PERMUTE while 0 < ARGV.length && ARGV[0] !~ /^-./ @non_option_arguments.push(ARGV.shift) end if ARGV.length == 0 terminate return nil end argument = ARGV.shift elsif @ordering == REQUIRE_ORDER if (ARGV[0] !~ /^-./) terminate return nil end argument = ARGV.shift else argument = ARGV.shift end # # Check the special argument `--'. # `--' indicates the end of the option list. # if argument == '--' && @rest_singles.length == 0 terminate return nil end # # Check for long and short options. # if argument =~ /^(--[^=]+)/ && @rest_singles.length == 0 # # This is a long style option, which start with `--'. # pattern = $1 if @canonical_names.include?(pattern) option_name = pattern else # # The option `option_name' is not registered in `@canonical_names'. # It may be an abbreviated. # match_count = 0 @canonical_names.each_key do |key| if key.index(pattern) == 0 option_name = key match_count += 1 end end if 2 <= match_count set_error(AmbigousOption, "option `#{argument}' is ambiguous") elsif match_count == 0 set_error(InvalidOption, "unrecognized option `#{argument}'") end end # # Check an argument to the option. # if @argument_flags[option_name] == REQUIRED_ARGUMENT if argument =~ /=(.*)$/ option_argument = $1 elsif 0 < ARGV.length option_argument = ARGV.shift else set_error(MissingArgument, "option `#{argument}' requires an argument") end elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT if argument =~ /=(.*)$/ option_argument = $1 elsif 0 < ARGV.length && ARGV[0] !~ /^-./ option_argument = ARGV.shift else option_argument = '' end elsif argument =~ /=(.*)$/ set_error(NeedlessArgument, "option `#{option_name}' doesn't allow an argument") end elsif argument =~ /^(-(.))(.*)/ # # This is a short style option, which start with `-' (not `--'). # Short options may be catenated (e.g. `-l -g' is equivalent to # `-lg'). # option_name, ch, @rest_singles = $1, $2, $3 if @canonical_names.include?(option_name) # # The option `option_name' is found in `@canonical_names'. # Check its argument. # if @argument_flags[option_name] == REQUIRED_ARGUMENT if 0 < @rest_singles.length option_argument = @rest_singles @rest_singles = '' elsif 0 < ARGV.length option_argument = ARGV.shift else # 1003.2 specifies the format of this message. set_error(MissingArgument, "option requires an argument -- #{ch}") end elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT if 0 < @rest_singles.length option_argument = @rest_singles @rest_singles = '' elsif 0 < ARGV.length && ARGV[0] !~ /^-./ option_argument = ARGV.shift else option_argument = '' end end else # # This is an invalid option. # 1003.2 specifies the format of this message. # if ENV.include?('POSIXLY_CORRECT') set_error(InvalidOption, "illegal option -- #{ch}") else set_error(InvalidOption, "invalid option -- #{ch}") end end else # # This is a non-option argument. # Only RETURN_IN_ORDER falled into here. # return '', argument end return @canonical_names[option_name], option_argument end # # `get_option' is an alias of `get'. # alias get_option get # Iterator version of `get'. # # The block is called repeatedly with two arguments: # The first is the option name. # The second is the argument which followed it (if any). # Example: ('--opt', 'value') # # The option name is always converted to the first (preferred) # name given in the original options to GetoptLong.new. # def each loop do option_name, option_argument = get_option break if option_name == nil yield option_name, option_argument end end # # `each_option' is an alias of `each'. # alias each_option each end PK|]a ? fileutils.rbnu[# # = fileutils.rb # # Copyright (c) 2000-2006 Minero Aoki # # This program is free software. # You can distribute/modify this program under the same terms of ruby. # # == module FileUtils # # Namespace for several file utility methods for copying, moving, removing, etc. # # === Module Functions # # cd(dir, options) # cd(dir, options) {|dir| .... } # pwd() # mkdir(dir, options) # mkdir(list, options) # mkdir_p(dir, options) # mkdir_p(list, options) # rmdir(dir, options) # rmdir(list, options) # ln(old, new, options) # ln(list, destdir, options) # ln_s(old, new, options) # ln_s(list, destdir, options) # ln_sf(src, dest, options) # cp(src, dest, options) # cp(list, dir, options) # cp_r(src, dest, options) # cp_r(list, dir, options) # mv(src, dest, options) # mv(list, dir, options) # rm(list, options) # rm_r(list, options) # rm_rf(list, options) # install(src, dest, mode = , options) # chmod(mode, list, options) # chmod_R(mode, list, options) # chown(user, group, list, options) # chown_R(user, group, list, options) # touch(list, options) # # The options parameter is a hash of options, taken from the list # :force, :noop, :preserve, and :verbose. # :noop means that no changes are made. The other two are obvious. # Each method documents the options that it honours. # # All methods that have the concept of a "source" file or directory can take # either one file or a list of files in that argument. See the method # documentation for examples. # # There are some `low level' methods, which do not accept any option: # # copy_entry(src, dest, preserve = false, dereference = false) # copy_file(src, dest, preserve = false, dereference = true) # copy_stream(srcstream, deststream) # remove_entry(path, force = false) # remove_entry_secure(path, force = false) # remove_file(path, force = false) # compare_file(path_a, path_b) # compare_stream(stream_a, stream_b) # uptodate?(file, cmp_list) # # == module FileUtils::Verbose # # This module has all methods of FileUtils module, but it outputs messages # before acting. This equates to passing the :verbose flag to methods # in FileUtils. # # == module FileUtils::NoWrite # # This module has all methods of FileUtils module, but never changes # files/directories. This equates to passing the :noop flag to methods # in FileUtils. # # == module FileUtils::DryRun # # This module has all methods of FileUtils module, but never changes # files/directories. This equates to passing the :noop and # :verbose flags to methods in FileUtils. # module FileUtils def self.private_module_function(name) #:nodoc: module_function name private_class_method name end # This hash table holds command options. OPT_TABLE = {} #:nodoc: internal use only # # Options: (none) # # Returns the name of the current directory. # def pwd Dir.pwd end module_function :pwd alias getwd pwd module_function :getwd # # Options: verbose # # Changes the current directory to the directory +dir+. # # If this method is called with block, resumes to the old # working directory after the block execution finished. # # FileUtils.cd('/', :verbose => true) # chdir and report it # def cd(dir, options = {}, &block) # :yield: dir fu_check_options options, OPT_TABLE['cd'] fu_output_message "cd #{dir}" if options[:verbose] Dir.chdir(dir, &block) fu_output_message 'cd -' if options[:verbose] and block end module_function :cd alias chdir cd module_function :chdir OPT_TABLE['cd'] = OPT_TABLE['chdir'] = [:verbose] # # Options: (none) # # Returns true if +newer+ is newer than all +old_list+. # Non-existent files are older than any file. # # FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \ # system 'make hello.o' # def uptodate?(new, old_list, options = nil) raise ArgumentError, 'uptodate? does not accept any option' if options return false unless File.exist?(new) new_time = File.mtime(new) old_list.each do |old| if File.exist?(old) return false unless new_time > File.mtime(old) end end true end module_function :uptodate? # # Options: mode noop verbose # # Creates one or more directories. # # FileUtils.mkdir 'test' # FileUtils.mkdir %w( tmp data ) # FileUtils.mkdir 'notexist', :noop => true # Does not really create. # FileUtils.mkdir 'tmp', :mode => 0700 # def mkdir(list, options = {}) fu_check_options options, OPT_TABLE['mkdir'] list = fu_list(list) fu_output_message "mkdir #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose] return if options[:noop] list.each do |dir| fu_mkdir dir, options[:mode] end end module_function :mkdir OPT_TABLE['mkdir'] = [:mode, :noop, :verbose] # # Options: mode noop verbose # # Creates a directory and all its parent directories. # For example, # # FileUtils.mkdir_p '/usr/local/lib/ruby' # # causes to make following directories, if it does not exist. # * /usr # * /usr/local # * /usr/local/lib # * /usr/local/lib/ruby # # You can pass several directories at a time in a list. # def mkdir_p(list, options = {}) fu_check_options options, OPT_TABLE['mkdir_p'] list = fu_list(list) fu_output_message "mkdir -p #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose] return *list if options[:noop] list.map {|path| path.sub(%r, '') }.each do |path| # optimize for the most common case begin fu_mkdir path, options[:mode] next rescue SystemCallError next if File.directory?(path) end stack = [] until path == stack.last # dirname("/")=="/", dirname("C:/")=="C:/" stack.push path path = File.dirname(path) end stack.reverse_each do |path| begin fu_mkdir path, options[:mode] rescue SystemCallError => err raise unless File.directory?(path) end end end return *list end module_function :mkdir_p alias mkpath mkdir_p alias makedirs mkdir_p module_function :mkpath module_function :makedirs OPT_TABLE['mkdir_p'] = OPT_TABLE['mkpath'] = OPT_TABLE['makedirs'] = [:mode, :noop, :verbose] def fu_mkdir(path, mode) #:nodoc: path = path.sub(%r, '') if mode Dir.mkdir path, mode File.chmod mode, path else Dir.mkdir path end end private_module_function :fu_mkdir # # Options: noop, verbose # # Removes one or more directories. # # FileUtils.rmdir 'somedir' # FileUtils.rmdir %w(somedir anydir otherdir) # # Does not really remove directory; outputs message. # FileUtils.rmdir 'somedir', :verbose => true, :noop => true # def rmdir(list, options = {}) fu_check_options options, OPT_TABLE['rmdir'] list = fu_list(list) fu_output_message "rmdir #{list.join ' '}" if options[:verbose] return if options[:noop] list.each do |dir| Dir.rmdir dir.sub(%r, '') end end module_function :rmdir OPT_TABLE['rmdir'] = [:noop, :verbose] # # Options: force noop verbose # # ln(old, new, options = {}) # # Creates a hard link +new+ which points to +old+. # If +new+ already exists and it is a directory, creates a link +new/old+. # If +new+ already exists and it is not a directory, raises Errno::EEXIST. # But if :force option is set, overwrite +new+. # # FileUtils.ln 'gcc', 'cc', :verbose => true # FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs' # # ln(list, destdir, options = {}) # # Creates several hard links in a directory, with each one pointing to the # item in +list+. If +destdir+ is not a directory, raises Errno::ENOTDIR. # # include FileUtils # cd '/sbin' # FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked. # def ln(src, dest, options = {}) fu_check_options options, OPT_TABLE['ln'] fu_output_message "ln#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose] return if options[:noop] fu_each_src_dest0(src, dest) do |s,d| remove_file d, true if options[:force] File.link s, d end end module_function :ln alias link ln module_function :link OPT_TABLE['ln'] = OPT_TABLE['link'] = [:force, :noop, :verbose] # # Options: force noop verbose # # ln_s(old, new, options = {}) # # Creates a symbolic link +new+ which points to +old+. If +new+ already # exists and it is a directory, creates a symbolic link +new/old+. If +new+ # already exists and it is not a directory, raises Errno::EEXIST. But if # :force option is set, overwrite +new+. # # FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby' # FileUtils.ln_s 'verylongsourcefilename.c', 'c', :force => true # # ln_s(list, destdir, options = {}) # # Creates several symbolic links in a directory, with each one pointing to the # item in +list+. If +destdir+ is not a directory, raises Errno::ENOTDIR. # # If +destdir+ is not a directory, raises Errno::ENOTDIR. # # FileUtils.ln_s Dir.glob('bin/*.rb'), '/home/aamine/bin' # def ln_s(src, dest, options = {}) fu_check_options options, OPT_TABLE['ln_s'] fu_output_message "ln -s#{options[:force] ? 'f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose] return if options[:noop] fu_each_src_dest0(src, dest) do |s,d| remove_file d, true if options[:force] File.symlink s, d end end module_function :ln_s alias symlink ln_s module_function :symlink OPT_TABLE['ln_s'] = OPT_TABLE['symlink'] = [:force, :noop, :verbose] # # Options: noop verbose # # Same as # #ln_s(src, dest, :force) # def ln_sf(src, dest, options = {}) fu_check_options options, OPT_TABLE['ln_sf'] options = options.dup options[:force] = true ln_s src, dest, options end module_function :ln_sf OPT_TABLE['ln_sf'] = [:noop, :verbose] # # Options: preserve noop verbose # # Copies a file content +src+ to +dest+. If +dest+ is a directory, # copies +src+ to +dest/src+. # # If +src+ is a list of files, then +dest+ must be a directory. # # FileUtils.cp 'eval.c', 'eval.c.org' # FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6' # FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', :verbose => true # FileUtils.cp 'symlink', 'dest' # copy content, "dest" is not a symlink # def cp(src, dest, options = {}) fu_check_options options, OPT_TABLE['cp'] fu_output_message "cp#{options[:preserve] ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose] return if options[:noop] fu_each_src_dest(src, dest) do |s, d| copy_file s, d, options[:preserve] end end module_function :cp alias copy cp module_function :copy OPT_TABLE['cp'] = OPT_TABLE['copy'] = [:preserve, :noop, :verbose] # # Options: preserve noop verbose dereference_root remove_destination # # Copies +src+ to +dest+. If +src+ is a directory, this method copies # all its contents recursively. If +dest+ is a directory, copies # +src+ to +dest/src+. # # +src+ can be a list of files. # # # Installing ruby library "mylib" under the site_ruby # FileUtils.rm_r site_ruby + '/mylib', :force # FileUtils.cp_r 'lib/', site_ruby + '/mylib' # # # Examples of copying several files to target directory. # FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail' # FileUtils.cp_r Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true # # # If you want to copy all contents of a directory instead of the # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y, # # use following code. # FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes src/dest, # # but this doesn't. # def cp_r(src, dest, options = {}) fu_check_options options, OPT_TABLE['cp_r'] fu_output_message "cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose] return if options[:noop] options = options.dup options[:dereference_root] = true unless options.key?(:dereference_root) fu_each_src_dest(src, dest) do |s, d| copy_entry s, d, options[:preserve], options[:dereference_root], options[:remove_destination] end end module_function :cp_r OPT_TABLE['cp_r'] = [:preserve, :noop, :verbose, :dereference_root, :remove_destination] # # Copies a file system entry +src+ to +dest+. # If +src+ is a directory, this method copies its contents recursively. # This method preserves file types, c.f. symlink, directory... # (FIFO, device files and etc. are not supported yet) # # Both of +src+ and +dest+ must be a path name. # +src+ must exist, +dest+ must not exist. # # If +preserve+ is true, this method preserves owner, group, permissions # and modified time. # # If +dereference_root+ is true, this method dereference tree root. # # If +remove_destination+ is true, this method removes each destination file before copy. # def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) Entry_.new(src, nil, dereference_root).traverse do |ent| destent = Entry_.new(dest, ent.rel, false) File.unlink destent.path if remove_destination && File.file?(destent.path) ent.copy destent.path ent.copy_metadata destent.path if preserve end end module_function :copy_entry # # Copies file contents of +src+ to +dest+. # Both of +src+ and +dest+ must be a path name. # def copy_file(src, dest, preserve = false, dereference = true) ent = Entry_.new(src, nil, dereference) ent.copy_file dest ent.copy_metadata dest if preserve end module_function :copy_file # # Copies stream +src+ to +dest+. # +src+ must respond to #read(n) and # +dest+ must respond to #write(str). # def copy_stream(src, dest) fu_copy_stream0 src, dest, fu_stream_blksize(src, dest) end module_function :copy_stream # # Options: force noop verbose # # Moves file(s) +src+ to +dest+. If +file+ and +dest+ exist on the different # disk partition, the file is copied instead. # # FileUtils.mv 'badname.rb', 'goodname.rb' # FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', :force => true # no error # # FileUtils.mv %w(junk.txt dust.txt), '/home/aamine/.trash/' # FileUtils.mv Dir.glob('test*.rb'), 'test', :noop => true, :verbose => true # def mv(src, dest, options = {}) fu_check_options options, OPT_TABLE['mv'] fu_output_message "mv#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose] return if options[:noop] fu_each_src_dest(src, dest) do |s, d| destent = Entry_.new(d, nil, true) begin if destent.exist? if destent.directory? raise Errno::EEXIST, dest else destent.remove_file if rename_cannot_overwrite_file? end end begin File.rename s, d rescue Errno::EXDEV copy_entry s, d, true if options[:secure] remove_entry_secure s, options[:force] else remove_entry s, options[:force] end end rescue SystemCallError raise unless options[:force] end end end module_function :mv alias move mv module_function :move OPT_TABLE['mv'] = OPT_TABLE['move'] = [:force, :noop, :verbose, :secure] def rename_cannot_overwrite_file? #:nodoc: /djgpp|cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM end private_module_function :rename_cannot_overwrite_file? # # Options: force noop verbose # # Remove file(s) specified in +list+. This method cannot remove directories. # All StandardErrors are ignored when the :force option is set. # # FileUtils.rm %w( junk.txt dust.txt ) # FileUtils.rm Dir.glob('*.so') # FileUtils.rm 'NotExistFile', :force => true # never raises exception # def rm(list, options = {}) fu_check_options options, OPT_TABLE['rm'] list = fu_list(list) fu_output_message "rm#{options[:force] ? ' -f' : ''} #{list.join ' '}" if options[:verbose] return if options[:noop] list.each do |path| remove_file path, options[:force] end end module_function :rm alias remove rm module_function :remove OPT_TABLE['rm'] = OPT_TABLE['remove'] = [:force, :noop, :verbose] # # Options: noop verbose # # Equivalent to # # #rm(list, :force => true) # def rm_f(list, options = {}) fu_check_options options, OPT_TABLE['rm_f'] options = options.dup options[:force] = true rm list, options end module_function :rm_f alias safe_unlink rm_f module_function :safe_unlink OPT_TABLE['rm_f'] = OPT_TABLE['safe_unlink'] = [:noop, :verbose] # # Options: force noop verbose secure # # remove files +list+[0] +list+[1]... If +list+[n] is a directory, # removes its all contents recursively. This method ignores # StandardError when :force option is set. # # FileUtils.rm_r Dir.glob('/tmp/*') # FileUtils.rm_r '/', :force => true # :-) # # WARNING: This method causes local vulnerability # if one of parent directories or removing directory tree are world # writable (including /tmp, whose permission is 1777), and the current # process has strong privilege such as Unix super user (root), and the # system has symbolic link. For secure removing, read the documentation # of #remove_entry_secure carefully, and set :secure option to true. # Default is :secure=>false. # # NOTE: This method calls #remove_entry_secure if :secure option is set. # See also #remove_entry_secure. # def rm_r(list, options = {}) fu_check_options options, OPT_TABLE['rm_r'] # options[:secure] = true unless options.key?(:secure) list = fu_list(list) fu_output_message "rm -r#{options[:force] ? 'f' : ''} #{list.join ' '}" if options[:verbose] return if options[:noop] list.each do |path| if options[:secure] remove_entry_secure path, options[:force] else remove_entry path, options[:force] end end end module_function :rm_r OPT_TABLE['rm_r'] = [:force, :noop, :verbose, :secure] # # Options: noop verbose secure # # Equivalent to # # #rm_r(list, :force => true) # # WARNING: This method causes local vulnerability. # Read the documentation of #rm_r first. # def rm_rf(list, options = {}) fu_check_options options, OPT_TABLE['rm_rf'] options = options.dup options[:force] = true rm_r list, options end module_function :rm_rf alias rmtree rm_rf module_function :rmtree OPT_TABLE['rm_rf'] = OPT_TABLE['rmtree'] = [:noop, :verbose, :secure] # # This method removes a file system entry +path+. +path+ shall be a # regular file, a directory, or something. If +path+ is a directory, # remove it recursively. This method is required to avoid TOCTTOU # (time-of-check-to-time-of-use) local security vulnerability of #rm_r. # #rm_r causes security hole when: # # * Parent directory is world writable (including /tmp). # * Removing directory tree includes world writable directory. # * The system has symbolic link. # # To avoid this security hole, this method applies special preprocess. # If +path+ is a directory, this method chown(2) and chmod(2) all # removing directories. This requires the current process is the # owner of the removing whole directory tree, or is the super user (root). # # WARNING: You must ensure that *ALL* parent directories cannot be # moved by other untrusted users. For example, parent directories # should not be owned by untrusted users, and should not be world # writable except when the sticky bit set. # # WARNING: Only the owner of the removing directory tree, or Unix super # user (root) should invoke this method. Otherwise this method does not # work. # # For details of this security vulnerability, see Perl's case: # # http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448 # http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452 # # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100]. # def remove_entry_secure(path, force = false) unless fu_have_symlink? remove_entry path, force return end fullpath = File.expand_path(path) st = File.lstat(fullpath) unless st.directory? File.unlink fullpath return end # is a directory. parent_st = File.stat(File.dirname(fullpath)) unless fu_world_writable?(parent_st) remove_entry path, force return end unless parent_st.sticky? raise ArgumentError, "parent directory is world writable, FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})" end # freeze tree root euid = Process.euid File.open(fullpath + '/.') {|f| unless fu_stat_identical_entry?(st, f.stat) # symlink (TOC-to-TOU attack?) File.unlink fullpath return end f.chown euid, -1 f.chmod 0700 unless fu_stat_identical_entry?(st, File.lstat(fullpath)) # TOC-to-TOU attack? File.unlink fullpath return end } # ---- tree root is frozen ---- root = Entry_.new(path) root.preorder_traverse do |ent| if ent.directory? ent.chown euid, -1 ent.chmod 0700 end end root.postorder_traverse do |ent| begin ent.remove rescue raise unless force end end rescue raise unless force end module_function :remove_entry_secure def fu_world_writable?(st) (st.mode & 0002) != 0 end private_module_function :fu_world_writable? def fu_have_symlink? #:nodoc File.symlink nil, nil rescue NotImplementedError return false rescue return true end private_module_function :fu_have_symlink? def fu_stat_identical_entry?(a, b) #:nodoc: a.dev == b.dev and a.ino == b.ino end private_module_function :fu_stat_identical_entry? # # This method removes a file system entry +path+. # +path+ might be a regular file, a directory, or something. # If +path+ is a directory, remove it recursively. # # See also #remove_entry_secure. # def remove_entry(path, force = false) Entry_.new(path).postorder_traverse do |ent| begin ent.remove rescue raise unless force end end rescue raise unless force end module_function :remove_entry # # Removes a file +path+. # This method ignores StandardError if +force+ is true. # def remove_file(path, force = false) Entry_.new(path).remove_file rescue raise unless force end module_function :remove_file # # Removes a directory +dir+ and its contents recursively. # This method ignores StandardError if +force+ is true. # def remove_dir(path, force = false) remove_entry path, force # FIXME?? check if it is a directory end module_function :remove_dir # # Returns true if the contents of a file A and a file B are identical. # # FileUtils.compare_file('somefile', 'somefile') #=> true # FileUtils.compare_file('/bin/cp', '/bin/mv') #=> maybe false # def compare_file(a, b) return false unless File.size(a) == File.size(b) File.open(a, 'rb') {|fa| File.open(b, 'rb') {|fb| return compare_stream(fa, fb) } } end module_function :compare_file alias identical? compare_file alias cmp compare_file module_function :identical? module_function :cmp # # Returns true if the contents of a stream +a+ and +b+ are identical. # def compare_stream(a, b) bsize = fu_stream_blksize(a, b) sa = sb = nil while sa == sb sa = a.read(bsize) sb = b.read(bsize) unless sa and sb if sa.nil? and sb.nil? return true end end end false end module_function :compare_stream # # Options: mode preserve noop verbose # # If +src+ is not same as +dest+, copies it and changes the permission # mode to +mode+. If +dest+ is a directory, destination is +dest+/+src+. # This method removes destination before copy. # # FileUtils.install 'ruby', '/usr/local/bin/ruby', :mode => 0755, :verbose => true # FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', :verbose => true # def install(src, dest, options = {}) fu_check_options options, OPT_TABLE['install'] fu_output_message "install -c#{options[:preserve] && ' -p'}#{options[:mode] ? (' -m 0%o' % options[:mode]) : ''} #{[src,dest].flatten.join ' '}" if options[:verbose] return if options[:noop] fu_each_src_dest(src, dest) do |s, d| unless File.exist?(d) and compare_file(s, d) remove_file d, true st = File.stat(s) if options[:preserve] copy_file s, d File.utime st.atime, st.mtime, d if options[:preserve] File.chmod options[:mode], d if options[:mode] end end end module_function :install OPT_TABLE['install'] = [:mode, :preserve, :noop, :verbose] # # Options: noop verbose # # Changes permission bits on the named files (in +list+) to the bit pattern # represented by +mode+. # # FileUtils.chmod 0755, 'somecommand' # FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb) # FileUtils.chmod 0755, '/usr/bin/ruby', :verbose => true # def chmod(mode, list, options = {}) fu_check_options options, OPT_TABLE['chmod'] list = fu_list(list) fu_output_message sprintf('chmod %o %s', mode, list.join(' ')) if options[:verbose] return if options[:noop] list.each do |path| Entry_.new(path).chmod mode end end module_function :chmod OPT_TABLE['chmod'] = [:noop, :verbose] # # Options: noop verbose force # # Changes permission bits on the named files (in +list+) # to the bit pattern represented by +mode+. # # FileUtils.chmod_R 0700, "/tmp/app.#{$$}" # def chmod_R(mode, list, options = {}) fu_check_options options, OPT_TABLE['chmod_R'] list = fu_list(list) fu_output_message sprintf('chmod -R%s %o %s', (options[:force] ? 'f' : ''), mode, list.join(' ')) if options[:verbose] return if options[:noop] list.each do |root| Entry_.new(root).traverse do |ent| begin ent.chmod mode rescue raise unless options[:force] end end end end module_function :chmod_R OPT_TABLE['chmod_R'] = [:noop, :verbose, :force] # # Options: noop verbose # # Changes owner and group on the named files (in +list+) # to the user +user+ and the group +group+. +user+ and +group+ # may be an ID (Integer/String) or a name (String). # If +user+ or +group+ is nil, this method does not change # the attribute. # # FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby' # FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true # def chown(user, group, list, options = {}) fu_check_options options, OPT_TABLE['chown'] list = fu_list(list) fu_output_message sprintf('chown %s%s', [user,group].compact.join(':') + ' ', list.join(' ')) if options[:verbose] return if options[:noop] uid = fu_get_uid(user) gid = fu_get_gid(group) list.each do |path| Entry_.new(path).chown uid, gid end end module_function :chown OPT_TABLE['chown'] = [:noop, :verbose] # # Options: noop verbose force # # Changes owner and group on the named files (in +list+) # to the user +user+ and the group +group+ recursively. # +user+ and +group+ may be an ID (Integer/String) or # a name (String). If +user+ or +group+ is nil, this # method does not change the attribute. # # FileUtils.chown_R 'www', 'www', '/var/www/htdocs' # FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', :verbose => true # def chown_R(user, group, list, options = {}) fu_check_options options, OPT_TABLE['chown_R'] list = fu_list(list) fu_output_message sprintf('chown -R%s %s%s', (options[:force] ? 'f' : ''), [user,group].compact.join(':') + ' ', list.join(' ')) if options[:verbose] return if options[:noop] uid = fu_get_uid(user) gid = fu_get_gid(group) return unless uid or gid list.each do |root| Entry_.new(root).traverse do |ent| begin ent.chown uid, gid rescue raise unless options[:force] end end end end module_function :chown_R OPT_TABLE['chown_R'] = [:noop, :verbose, :force] begin require 'etc' def fu_get_uid(user) #:nodoc: return nil unless user user = user.to_s if /\A\d+\z/ =~ user then user.to_i else Etc.getpwnam(user).uid end end private_module_function :fu_get_uid def fu_get_gid(group) #:nodoc: return nil unless group group = group.to_s if /\A\d+\z/ =~ group then group.to_i else Etc.getgrnam(group).gid end end private_module_function :fu_get_gid rescue LoadError # need Win32 support??? def fu_get_uid(user) #:nodoc: user # FIXME end private_module_function :fu_get_uid def fu_get_gid(group) #:nodoc: group # FIXME end private_module_function :fu_get_gid end # # Options: noop verbose # # Updates modification time (mtime) and access time (atime) of file(s) in # +list+. Files are created if they don't exist. # # FileUtils.touch 'timestamp' # FileUtils.touch Dir.glob('*.c'); system 'make' # def touch(list, options = {}) fu_check_options options, OPT_TABLE['touch'] list = fu_list(list) created = nocreate = options[:nocreate] t = options[:mtime] if options[:verbose] fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}" end return if options[:noop] list.each do |path| created = nocreate begin File.utime(t, t, path) rescue Errno::ENOENT raise if created File.open(path, 'a') { ; } created = true retry if t end end end module_function :touch OPT_TABLE['touch'] = [:noop, :verbose, :mtime, :nocreate] private module StreamUtils_ private def fu_windows? /mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM end def fu_copy_stream0(src, dest, blksize) #:nodoc: # FIXME: readpartial? while s = src.read(blksize) dest.write s end end def fu_stream_blksize(*streams) streams.each do |s| next unless s.respond_to?(:stat) size = fu_blksize(s.stat) return size if size end fu_default_blksize() end def fu_blksize(st) s = st.blksize return nil unless s return nil if s == 0 s end def fu_default_blksize 1024 end end include StreamUtils_ extend StreamUtils_ class Entry_ #:nodoc: internal use only include StreamUtils_ def initialize(a, b = nil, deref = false) @prefix = @rel = @path = nil if b @prefix = a @rel = b else @path = a end @deref = deref @stat = nil @lstat = nil end def inspect "\#<#{self.class} #{path()}>" end def path if @path @path.to_str else join(@prefix, @rel) end end def prefix @prefix || @path end def rel @rel end def dereference? @deref end def exist? lstat! ? true : false end def file? s = lstat! s and s.file? end def directory? s = lstat! s and s.directory? end def symlink? s = lstat! s and s.symlink? end def chardev? s = lstat! s and s.chardev? end def blockdev? s = lstat! s and s.blockdev? end def socket? s = lstat! s and s.socket? end def pipe? s = lstat! s and s.pipe? end S_IF_DOOR = 0xD000 def door? s = lstat! s and (s.mode & 0xF000 == S_IF_DOOR) end def entries Dir.entries(path())\ .reject {|n| n == '.' or n == '..' }\ .map {|n| Entry_.new(prefix(), join(rel(), n.untaint)) } end def stat return @stat if @stat if lstat() and lstat().symlink? @stat = File.stat(path()) else @stat = lstat() end @stat end def stat! return @stat if @stat if lstat! and lstat!.symlink? @stat = File.stat(path()) else @stat = lstat! end @stat rescue SystemCallError nil end def lstat if dereference? @lstat ||= File.stat(path()) else @lstat ||= File.lstat(path()) end end def lstat! lstat() rescue SystemCallError nil end def chmod(mode) if symlink? File.lchmod mode, path() if have_lchmod? else File.chmod mode, path() end end def chown(uid, gid) if symlink? File.lchown uid, gid, path() if have_lchown? else File.chown uid, gid, path() end end def copy(dest) case when file? copy_file dest when directory? begin Dir.mkdir dest rescue raise unless File.directory?(dest) end when symlink? File.symlink File.readlink(path()), dest when chardev? raise "cannot handle device file" unless File.respond_to?(:mknod) mknod dest, ?c, 0666, lstat().rdev when blockdev? raise "cannot handle device file" unless File.respond_to?(:mknod) mknod dest, ?b, 0666, lstat().rdev when socket? raise "cannot handle socket" unless File.respond_to?(:mknod) mknod dest, nil, lstat().mode, 0 when pipe? raise "cannot handle FIFO" unless File.respond_to?(:mkfifo) mkfifo dest, 0666 when door? raise "cannot handle door: #{path()}" else raise "unknown file type: #{path()}" end end def copy_file(dest) st = stat() File.open(path(), 'rb') {|r| File.open(dest, 'wb', st.mode) {|w| fu_copy_stream0 r, w, (fu_blksize(st) || fu_default_blksize()) } } end def copy_metadata(path) st = lstat() File.utime st.atime, st.mtime, path begin File.chown st.uid, st.gid, path rescue Errno::EPERM # clear setuid/setgid File.chmod st.mode & 01777, path else File.chmod st.mode, path end end def remove if directory? remove_dir1 else remove_file end end def remove_dir1 platform_support { Dir.rmdir path().sub(%r, '') } end def remove_file platform_support { File.unlink path } end def platform_support return yield unless fu_windows? first_time_p = true begin yield rescue Errno::ENOENT raise rescue => err if first_time_p first_time_p = false begin File.chmod 0700, path() # Windows does not have symlink retry rescue SystemCallError end end raise err end end def preorder_traverse stack = [self] while ent = stack.pop yield ent stack.concat ent.entries.reverse if ent.directory? end end alias traverse preorder_traverse def postorder_traverse if directory? entries().each do |ent| ent.postorder_traverse do |e| yield e end end end yield self end private $fileutils_rb_have_lchmod = nil def have_lchmod? # This is not MT-safe, but it does not matter. if $fileutils_rb_have_lchmod == nil $fileutils_rb_have_lchmod = check_have_lchmod? end $fileutils_rb_have_lchmod end def check_have_lchmod? return false unless File.respond_to?(:lchmod) File.lchmod 0 return true rescue NotImplementedError return false end $fileutils_rb_have_lchown = nil def have_lchown? # This is not MT-safe, but it does not matter. if $fileutils_rb_have_lchown == nil $fileutils_rb_have_lchown = check_have_lchown? end $fileutils_rb_have_lchown end def check_have_lchown? return false unless File.respond_to?(:lchown) File.lchown nil, nil return true rescue NotImplementedError return false end def join(dir, base) return dir.to_str if not base or base == '.' return base.to_str if not dir or dir == '.' File.join(dir, base) end end # class Entry_ def fu_list(arg) #:nodoc: [arg].flatten.map {|path| path.to_str } end private_module_function :fu_list def fu_each_src_dest(src, dest) #:nodoc: fu_each_src_dest0(src, dest) do |s, d| raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s, d) yield s, d end end private_module_function :fu_each_src_dest def fu_each_src_dest0(src, dest) #:nodoc: if src.is_a?(Array) src.each do |s| s = s.to_str yield s, File.join(dest, File.basename(s)) end else src = src.to_str if File.directory?(dest) yield src, File.join(dest, File.basename(src)) else yield src, dest.to_str end end end private_module_function :fu_each_src_dest0 def fu_same?(a, b) #:nodoc: if fu_have_st_ino? st1 = File.stat(a) st2 = File.stat(b) st1.dev == st2.dev and st1.ino == st2.ino else File.expand_path(a) == File.expand_path(b) end rescue Errno::ENOENT return false end private_module_function :fu_same? def fu_have_st_ino? #:nodoc: not fu_windows? end private_module_function :fu_have_st_ino? def fu_check_options(options, optdecl) #:nodoc: h = options.dup optdecl.each do |opt| h.delete opt end raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty? end private_module_function :fu_check_options def fu_update_option(args, new) #:nodoc: if args.last.is_a?(Hash) args[-1] = args.last.dup.update(new) else args.push new end args end private_module_function :fu_update_option @fileutils_output = $stderr @fileutils_label = '' def fu_output_message(msg) #:nodoc: @fileutils_output ||= $stderr @fileutils_label ||= '' @fileutils_output.puts @fileutils_label + msg end private_module_function :fu_output_message # # Returns an Array of method names which have any options. # # p FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...] # def FileUtils.commands OPT_TABLE.keys end # # Returns an Array of option names. # # p FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"] # def FileUtils.options OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s } end # # Returns true if the method +mid+ have an option +opt+. # # p FileUtils.have_option?(:cp, :noop) #=> true # p FileUtils.have_option?(:rm, :force) #=> true # p FileUtils.have_option?(:rm, :perserve) #=> false # def FileUtils.have_option?(mid, opt) li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}" li.include?(opt) end # # Returns an Array of option names of the method +mid+. # # p FileUtils.options(:rm) #=> ["noop", "verbose", "force"] # def FileUtils.options_of(mid) OPT_TABLE[mid.to_s].map {|sym| sym.to_s } end # # Returns an Array of method names which have the option +opt+. # # p FileUtils.collect_method(:preserve) #=> ["cp", "cp_r", "copy", "install"] # def FileUtils.collect_method(opt) OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) } end METHODS = singleton_methods() - %w( private_module_function commands options have_option? options_of collect_method ) # # This module has all methods of FileUtils module, but it outputs messages # before acting. This equates to passing the :verbose flag to # methods in FileUtils. # module Verbose include FileUtils @fileutils_output = $stderr @fileutils_label = '' ::FileUtils.collect_method(:verbose).each do |name| module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args) super(*fu_update_option(args, :verbose => true)) end private :#{name} EOS end extend self class << self ::FileUtils::METHODS.each do |m| public m end end end # # This module has all methods of FileUtils module, but never changes # files/directories. This equates to passing the :noop flag # to methods in FileUtils. # module NoWrite include FileUtils @fileutils_output = $stderr @fileutils_label = '' ::FileUtils.collect_method(:noop).each do |name| module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args) super(*fu_update_option(args, :noop => true)) end private :#{name} EOS end extend self class << self ::FileUtils::METHODS.each do |m| public m end end end # # This module has all methods of FileUtils module, but never changes # files/directories, with printing message before acting. # This equates to passing the :noop and :verbose flag # to methods in FileUtils. # module DryRun include FileUtils @fileutils_output = $stderr @fileutils_label = '' ::FileUtils.collect_method(:noop).each do |name| module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{name}(*args) super(*fu_update_option(args, :noop => true, :verbose => true)) end private :#{name} EOS end extend self class << self ::FileUtils::METHODS.each do |m| public m end end end end PK|]??pp.rbnu[# == Pretty-printer for Ruby objects. # # = Which seems better? # # non-pretty-printed output by #p is: # #, @group_queue=#], []]>, @buffer=[], @newline="\n", @group_stack=[#], @buffer_width=0, @indent=0, @maxwidth=79, @output_width=2, @output=#> # # pretty-printed output by #pp is: # #, # @group_queue= # #], # []]>, # @group_stack= # [#], # @indent=0, # @maxwidth=79, # @newline="\n", # @output=#, # @output_width=2> # # I like the latter. If you do too, this library is for you. # # = Usage # # pp(obj) # # output +obj+ to +$>+ in pretty printed format. # # It returns +nil+. # # = Output Customization # To define your customized pretty printing function for your classes, # redefine a method #pretty_print(+pp+) in the class. # It takes an argument +pp+ which is an instance of the class PP. # The method should use PP#text, PP#breakable, PP#nest, PP#group and # PP#pp to print the object. # # = Author # Tanaka Akira require 'prettyprint' module Kernel # returns a pretty printed object as a string. def pretty_inspect PP.pp(self, '') end private # prints arguments in pretty form. # # pp returns nil. def pp(*objs) # :doc: objs.each {|obj| PP.pp(obj) } nil end module_function :pp end class PP < PrettyPrint # Outputs +obj+ to +out+ in pretty printed format of # +width+ columns in width. # # If +out+ is omitted, +$>+ is assumed. # If +width+ is omitted, 79 is assumed. # # PP.pp returns +out+. def PP.pp(obj, out=$>, width=79) q = PP.new(out, width) q.guard_inspect_key {q.pp obj} q.flush #$pp = q out << "\n" end # Outputs +obj+ to +out+ like PP.pp but with no indent and # newline. # # PP.singleline_pp returns +out+. def PP.singleline_pp(obj, out=$>) q = SingleLine.new(out) q.guard_inspect_key {q.pp obj} q.flush out end # :stopdoc: def PP.mcall(obj, mod, meth, *args, &block) mod.instance_method(meth).bind(obj).call(*args, &block) end # :startdoc: @sharing_detection = false class << self # Returns the sharing detection flag as a boolean value. # It is false by default. attr_accessor :sharing_detection end module PPMethods InspectKey = :__inspect_key__ def guard_inspect_key if Thread.current[InspectKey] == nil Thread.current[InspectKey] = [] end save = Thread.current[InspectKey] begin Thread.current[InspectKey] = [] yield ensure Thread.current[InspectKey] = save end end # Adds +obj+ to the pretty printing buffer # using Object#pretty_print or Object#pretty_print_cycle. # # Object#pretty_print_cycle is used when +obj+ is already # printed, a.k.a the object reference chain has a cycle. def pp(obj) id = obj.__id__ if Thread.current[InspectKey].include? id group {obj.pretty_print_cycle self} return end begin Thread.current[InspectKey] << id group {obj.pretty_print self} ensure Thread.current[InspectKey].pop unless PP.sharing_detection end end # A convenience method which is same as follows: # # group(1, '#<' + obj.class.name, '>') { ... } def object_group(obj, &block) # :yield: group(1, '#<' + obj.class.name, '>', &block) end def object_address_group(obj, &block) id = "%x" % (obj.__id__ * 2) id.sub!(/\Af(?=[[:xdigit:]]{2}+\z)/, '') if id.sub!(/\A\.\./, '') group(1, "\#<#{obj.class}:0x#{id}", '>', &block) end # A convenience method which is same as follows: # # text ',' # breakable def comma_breakable text ',' breakable end # Adds a separated list. # The list is separated by comma with breakable space, by default. # # #seplist iterates the +list+ using +iter_method+. # It yields each object to the block given for #seplist. # The procedure +separator_proc+ is called between each yields. # # If the iteration is zero times, +separator_proc+ is not called at all. # # If +separator_proc+ is nil or not given, # +lambda { comma_breakable }+ is used. # If +iter_method+ is not given, :each is used. # # For example, following 3 code fragments has similar effect. # # q.seplist([1,2,3]) {|v| xxx v } # # q.seplist([1,2,3], lambda { comma_breakable }, :each) {|v| xxx v } # # xxx 1 # q.comma_breakable # xxx 2 # q.comma_breakable # xxx 3 def seplist(list, sep=nil, iter_method=:each) # :yield: element sep ||= lambda { comma_breakable } first = true list.__send__(iter_method) {|*v| if first first = false else sep.call end yield(*v) } end def pp_object(obj) object_address_group(obj) { seplist(obj.pretty_print_instance_variables, lambda { text ',' }) {|v| breakable v = v.to_s if Symbol === v text v text '=' group(1) { breakable '' pp(obj.instance_eval(v)) } } } end def pp_hash(obj) group(1, '{', '}') { seplist(obj, nil, :each_pair) {|k, v| group { pp k text '=>' group(1) { breakable '' pp v } } } } end end include PPMethods class SingleLine < PrettyPrint::SingleLine include PPMethods end module ObjectMixin # 1. specific pretty_print # 2. specific inspect # 3. specific to_s if instance variable is empty # 4. generic pretty_print # A default pretty printing method for general objects. # It calls #pretty_print_instance_variables to list instance variables. # # If +self+ has a customized (redefined) #inspect method, # the result of self.inspect is used but it obviously has no # line break hints. # # This module provides predefined #pretty_print methods for some of # the most commonly used built-in classes for convenience. def pretty_print(q) if /\(Kernel\)#/ !~ Object.instance_method(:method).bind(self).call(:inspect).inspect q.text self.inspect elsif /\(Kernel\)#/ !~ Object.instance_method(:method).bind(self).call(:to_s).inspect && instance_variables.empty? q.text self.to_s else q.pp_object(self) end end # A default pretty printing method for general objects that are # detected as part of a cycle. def pretty_print_cycle(q) q.object_address_group(self) { q.breakable q.text '...' } end # Returns a sorted array of instance variable names. # # This method should return an array of names of instance variables as symbols or strings as: # +[:@a, :@b]+. def pretty_print_instance_variables instance_variables.sort end # Is #inspect implementation using #pretty_print. # If you implement #pretty_print, it can be used as follows. # # alias inspect pretty_print_inspect # # However, doing this requires that every class that #inspect is called on # implement #pretty_print, or a RuntimeError will be raised. def pretty_print_inspect if /\(PP::ObjectMixin\)#/ =~ Object.instance_method(:method).bind(self).call(:pretty_print).inspect raise "pretty_print is not overridden for #{self.class}" end PP.singleline_pp(self, '') end end end class Array def pretty_print(q) q.group(1, '[', ']') { q.seplist(self) {|v| q.pp v } } end def pretty_print_cycle(q) q.text(empty? ? '[]' : '[...]') end end class Hash def pretty_print(q) q.pp_hash self end def pretty_print_cycle(q) q.text(empty? ? '{}' : '{...}') end end class << ENV def pretty_print(q) q.pp_hash self end end class Struct def pretty_print(q) q.group(1, '#') { q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member| q.breakable q.text member.to_s q.text '=' q.group(1) { q.breakable '' q.pp self[member] } } } end def pretty_print_cycle(q) q.text sprintf("#", PP.mcall(self, Kernel, :class).name) end end class Range def pretty_print(q) q.pp self.begin q.breakable '' q.text(self.exclude_end? ? '...' : '..') q.breakable '' q.pp self.end end end class File class Stat def pretty_print(q) require 'etc.so' q.object_group(self) { q.breakable q.text sprintf("dev=0x%x", self.dev); q.comma_breakable q.text "ino="; q.pp self.ino; q.comma_breakable q.group { m = self.mode q.text sprintf("mode=0%o", m) q.breakable q.text sprintf("(%s %c%c%c%c%c%c%c%c%c)", self.ftype, (m & 0400 == 0 ? ?- : ?r), (m & 0200 == 0 ? ?- : ?w), (m & 0100 == 0 ? (m & 04000 == 0 ? ?- : ?S) : (m & 04000 == 0 ? ?x : ?s)), (m & 0040 == 0 ? ?- : ?r), (m & 0020 == 0 ? ?- : ?w), (m & 0010 == 0 ? (m & 02000 == 0 ? ?- : ?S) : (m & 02000 == 0 ? ?x : ?s)), (m & 0004 == 0 ? ?- : ?r), (m & 0002 == 0 ? ?- : ?w), (m & 0001 == 0 ? (m & 01000 == 0 ? ?- : ?T) : (m & 01000 == 0 ? ?x : ?t))) } q.comma_breakable q.text "nlink="; q.pp self.nlink; q.comma_breakable q.group { q.text "uid="; q.pp self.uid begin pw = Etc.getpwuid(self.uid) rescue ArgumentError end if pw q.breakable; q.text "(#{pw.name})" end } q.comma_breakable q.group { q.text "gid="; q.pp self.gid begin gr = Etc.getgrgid(self.gid) rescue ArgumentError end if gr q.breakable; q.text "(#{gr.name})" end } q.comma_breakable q.group { q.text sprintf("rdev=0x%x", self.rdev) q.breakable q.text sprintf('(%d, %d)', self.rdev_major, self.rdev_minor) } q.comma_breakable q.text "size="; q.pp self.size; q.comma_breakable q.text "blksize="; q.pp self.blksize; q.comma_breakable q.text "blocks="; q.pp self.blocks; q.comma_breakable q.group { t = self.atime q.text "atime="; q.pp t q.breakable; q.text "(#{t.tv_sec})" } q.comma_breakable q.group { t = self.mtime q.text "mtime="; q.pp t q.breakable; q.text "(#{t.tv_sec})" } q.comma_breakable q.group { t = self.ctime q.text "ctime="; q.pp t q.breakable; q.text "(#{t.tv_sec})" } } end end end class MatchData def pretty_print(q) q.object_group(self) { q.breakable q.seplist(1..self.size, lambda { q.breakable }) {|i| q.pp self[i-1] } } end end class Object include PP::ObjectMixin end [Numeric, Symbol, FalseClass, TrueClass, NilClass, Module].each {|c| c.class_eval { def pretty_print_cycle(q) q.text inspect end } } [Numeric, FalseClass, TrueClass, Module].each {|c| c.class_eval { def pretty_print(q) q.text inspect end } } # :enddoc: if __FILE__ == $0 require 'test/unit' class PPTest < Test::Unit::TestCase def test_list0123_12 assert_equal("[0, 1, 2, 3]\n", PP.pp([0,1,2,3], '', 12)) end def test_list0123_11 assert_equal("[0,\n 1,\n 2,\n 3]\n", PP.pp([0,1,2,3], '', 11)) end OverriddenStruct = Struct.new("OverriddenStruct", :members, :class) def test_struct_override_members # [ruby-core:7865] a = OverriddenStruct.new(1,2) assert_equal("#\n", PP.pp(a, '')) end def test_redefined_method o = "" def o.method end assert_equal(%(""\n), PP.pp(o, "")) end end class HasInspect def initialize(a) @a = a end def inspect return "" end end class HasPrettyPrint def initialize(a) @a = a end def pretty_print(q) q.text "" end end class HasBoth def initialize(a) @a = a end def inspect return "" end def pretty_print(q) q.text "" end end class PrettyPrintInspect < HasPrettyPrint alias inspect pretty_print_inspect end class PrettyPrintInspectWithoutPrettyPrint alias inspect pretty_print_inspect end class PPInspectTest < Test::Unit::TestCase def test_hasinspect a = HasInspect.new(1) assert_equal("\n", PP.pp(a, '')) end def test_hasprettyprint a = HasPrettyPrint.new(1) assert_equal("\n", PP.pp(a, '')) end def test_hasboth a = HasBoth.new(1) assert_equal("\n", PP.pp(a, '')) end def test_pretty_print_inspect a = PrettyPrintInspect.new(1) assert_equal("", a.inspect) a = PrettyPrintInspectWithoutPrettyPrint.new assert_raise(RuntimeError) { a.inspect } end def test_proc a = proc {1} assert_equal("#{a.inspect}\n", PP.pp(a, '')) end def test_to_s_with_iv a = Object.new def a.to_s() "aaa" end a.instance_eval { @a = nil } result = PP.pp(a, '') assert_equal("#{a.inspect}\n", result) assert_match(/\A#\n\z/m, result) a = 1.0 a.instance_eval { @a = nil } result = PP.pp(a, '') assert_equal("#{a.inspect}\n", result) end def test_to_s_without_iv a = Object.new def a.to_s() "aaa" end result = PP.pp(a, '') assert_equal("#{a.inspect}\n", result) assert_equal("aaa\n", result) end end class PPCycleTest < Test::Unit::TestCase def test_array a = [] a << a assert_equal("[[...]]\n", PP.pp(a, '')) assert_equal("#{a.inspect}\n", PP.pp(a, '')) end def test_hash a = {} a[0] = a assert_equal("{0=>{...}}\n", PP.pp(a, '')) assert_equal("#{a.inspect}\n", PP.pp(a, '')) end S = Struct.new("S", :a, :b) def test_struct a = S.new(1,2) a.b = a assert_equal("#>\n", PP.pp(a, '')) assert_equal("#{a.inspect}\n", PP.pp(a, '')) end def test_object a = Object.new a.instance_eval {@a = a} assert_equal(a.inspect + "\n", PP.pp(a, '')) end def test_anonymous a = Class.new.new assert_equal(a.inspect + "\n", PP.pp(a, '')) end def test_withinspect a = [] a << HasInspect.new(a) assert_equal("[]\n", PP.pp(a, '')) assert_equal("#{a.inspect}\n", PP.pp(a, '')) end def test_share_nil begin PP.sharing_detection = true a = [nil, nil] assert_equal("[nil, nil]\n", PP.pp(a, '')) ensure PP.sharing_detection = false end end end class PPSingleLineTest < Test::Unit::TestCase def test_hash assert_equal("{1=>1}", PP.singleline_pp({ 1 => 1}, '')) # [ruby-core:02699] assert_equal("[1#{', 1'*99}]", PP.singleline_pp([1]*100, '')) end end end PK|]z openssl/bn.rbnu[=begin = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for BN = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id: bn.rb 31657 2011-05-20 22:25:35Z shyouhei $ =end ## # Should we care what if somebody require this file directly? #require 'openssl' module OpenSSL class BN include Comparable end # BN end # OpenSSL ## # Add double dispatch to Integer # class Integer def to_bn OpenSSL::BN::new(self.to_s(16), 16) end end # Integer PK|]8openssl/ssl-internal.rbnu[=begin = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL = Info 'OpenSSL for Ruby 2' project Copyright (C) 2001 GOTOU YUUZOU All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ =end require "openssl/buffering" require "fcntl" module OpenSSL module SSL class SSLContext DEFAULT_PARAMS = { :ssl_version => "SSLv23", :verify_mode => OpenSSL::SSL::VERIFY_PEER, :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", :options => OpenSSL::SSL::OP_ALL, } DEFAULT_CERT_STORE = OpenSSL::X509::Store.new DEFAULT_CERT_STORE.set_default_paths if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL) DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL end def set_params(params={}) params = DEFAULT_PARAMS.merge(params) # ssl_version need to be set at first. self.ssl_version = params.delete(:ssl_version) params.each{|name, value| self.__send__("#{name}=", value) } if self.verify_mode != OpenSSL::SSL::VERIFY_NONE unless self.ca_file or self.ca_path or self.cert_store self.cert_store = DEFAULT_CERT_STORE end end return params end end module SocketForwarder def addr to_io.addr end def peeraddr to_io.peeraddr end def setsockopt(level, optname, optval) to_io.setsockopt(level, optname, optval) end def getsockopt(level, optname) to_io.getsockopt(level, optname) end def fcntl(*args) to_io.fcntl(*args) end def closed? to_io.closed? end def do_not_reverse_lookup=(flag) to_io.do_not_reverse_lookup = flag end end module Nonblock def initialize(*args) flag = File::NONBLOCK flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL) @io.fcntl(Fcntl::F_SETFL, flag) super end end def verify_certificate_identity(cert, hostname) should_verify_common_name = true cert.extensions.each{|ext| next if ext.oid != "subjectAltName" id, ostr = OpenSSL::ASN1.decode(ext.to_der).value sequence = OpenSSL::ASN1.decode(ostr.value) sequence.value.each{|san| case san.tag when 2 # dNSName in GeneralName (RFC5280) should_verify_common_name = false reg = Regexp.escape(san.value).gsub(/\\\*/, "[^.]+") return true if /\A#{reg}\z/i =~ hostname when 7 # iPAddress in GeneralName (RFC5280) should_verify_common_name = false # follows GENERAL_NAME_print() in x509v3/v3_alt.c if san.value.size == 4 return true if san.value.unpack('C*').join('.') == hostname elsif san.value.size == 16 return true if san.value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname end end } } if should_verify_common_name cert.subject.to_a.each{|oid, value| if oid == "CN" reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+") return true if /\A#{reg}\z/i =~ hostname end } end return false end module_function :verify_certificate_identity class SSLSocket include Buffering include SocketForwarder include Nonblock def post_connection_check(hostname) unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname) raise SSLError, "hostname was not match with the server certificate" end return true end def session SSL::Session.new(self) rescue SSL::Session::SessionError nil end end class SSLServer include SocketForwarder attr_accessor :start_immediately def initialize(svr, ctx) @svr = svr @ctx = ctx unless ctx.session_id_context session_id = OpenSSL::Digest::MD5.hexdigest($0) @ctx.session_id_context = session_id end @start_immediately = true end def to_io @svr end def listen(backlog=5) @svr.listen(backlog) end def shutdown(how=Socket::SHUT_RDWR) @svr.shutdown(how) end def accept sock = @svr.accept begin ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) ssl.sync_close = true ssl.accept if @start_immediately ssl rescue SSLError => ex sock.close raise ex end end def close @svr.close end end end end PK|]` openssl/cipher.rbnu[=begin = $RCSfile$ -- Ruby-space predefined Cipher subclasses = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id: cipher.rb 12496 2007-06-08 15:02:04Z technorama $ =end ## # Should we care what if somebody require this file directly? #require 'openssl' module OpenSSL class Cipher %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name| klass = Class.new(Cipher){ define_method(:initialize){|*args| cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" } super(cipher_name) } } const_set(name, klass) } %w(128 192 256).each{|keylen| klass = Class.new(Cipher){ define_method(:initialize){|mode| mode ||= "CBC" cipher_name = "AES-#{keylen}-#{mode}" super(cipher_name) } } const_set("AES#{keylen}", klass) } # Generate, set, and return a random key. # You must call cipher.encrypt or cipher.decrypt before calling this method. def random_key str = OpenSSL::Random.random_bytes(self.key_len) self.key = str return str end # Generate, set, and return a random iv. # You must call cipher.encrypt or cipher.decrypt before calling this method. def random_iv str = OpenSSL::Random.random_bytes(self.iv_len) self.iv = str return str end # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. class Cipher < Cipher # add warning end end # Cipher end # OpenSSL PK|])sopenssl/ssl.rbnu[require 'openssl' PK|]  openssl/x509-internal.rbnu[=begin = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id$ =end module OpenSSL module X509 class ExtensionFactory def create_extension(*arg) if arg.size > 1 create_ext(*arg) else send("create_ext_from_"+arg[0].class.name.downcase, arg[0]) end end def create_ext_from_array(ary) raise ExtensionError, "unexpected array form" if ary.size > 3 create_ext(ary[0], ary[1], ary[2]) end def create_ext_from_string(str) # "oid = critical, value" oid, value = str.split(/=/, 2) oid.strip! value.strip! create_ext(oid, value) end def create_ext_from_hash(hash) create_ext(hash["oid"], hash["value"], hash["critical"]) end end class Extension def to_s # "oid = critical, value" str = self.oid str << " = " str << "critical, " if self.critical? str << self.value.gsub(/\n/, ", ") end def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false} {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?} end def to_a [ self.oid, self.value, self.critical? ] end end class Name module RFC2253DN Special = ',=+<>#;' HexChar = /[0-9a-fA-F]/ HexPair = /#{HexChar}#{HexChar}/ HexString = /#{HexPair}+/ Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/ StringChar = /[^#{Special}\\"]/ QuoteChar = /[^\\"]/ AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/ AttributeValue = / (?!["#])((?:#{StringChar}|#{Pair})*)| \#(#{HexString})| "((?:#{QuoteChar}|#{Pair})*)" /x TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/ module_function def expand_pair(str) return nil unless str return str.gsub(Pair){ pair = $& case pair.size when 2 then pair[1,1] when 3 then Integer("0x#{pair[1,2]}").chr else raise OpenSSL::X509::NameError, "invalid pair: #{str}" end } end def expand_hexstring(str) return nil unless str der = str.gsub(HexPair){$&.to_i(16).chr } a1 = OpenSSL::ASN1.decode(der) return a1.value, a1.tag end def expand_value(str1, str2, str3) value = expand_pair(str1) value, tag = expand_hexstring(str2) unless value value = expand_pair(str3) unless value return value, tag end def scan(dn) str = dn ary = [] while true if md = TypeAndValue.match(str) matched = md.to_s remain = md.post_match type = md[1] value, tag = expand_value(md[2], md[3], md[4]) rescue nil if value type_and_value = [type, value] type_and_value.push(tag) if tag ary.unshift(type_and_value) if remain.length > 2 && remain[0] == ?, str = remain[1..-1] next elsif remain.length > 2 && remain[0] == ?+ raise OpenSSL::X509::NameError, "multi-valued RDN is not supported: #{dn}" elsif remain.empty? break end end end msg_dn = dn[0, dn.length - str.length] + " =>" + str raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}" end return ary end end class < All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id: buffering.rb 28004 2010-05-24 23:58:49Z shyouhei $ =end module OpenSSL module Buffering include Enumerable attr_accessor :sync BLOCK_SIZE = 1024*16 def initialize(*args) @eof = false @rbuffer = "" @sync = @io.sync end # # for reading. # private def fill_rbuff begin @rbuffer << self.sysread(BLOCK_SIZE) rescue Errno::EAGAIN retry rescue EOFError @eof = true end end def consume_rbuff(size=nil) if @rbuffer.empty? nil else size = @rbuffer.size unless size ret = @rbuffer[0, size] @rbuffer[0, size] = "" ret end end public def read(size=nil, buf=nil) if size == 0 if buf buf.clear else buf = "" end return @eof ? nil : buf end until @eof break if size && size <= @rbuffer.size fill_rbuff end ret = consume_rbuff(size) || "" if buf buf.replace(ret) ret = buf end (size && ret.empty?) ? nil : ret end def readpartial(maxlen, buf=nil) if maxlen == 0 if buf buf.clear else buf = "" end return @eof ? nil : buf end if @rbuffer.empty? begin return sysread(maxlen, buf) rescue Errno::EAGAIN retry end end ret = consume_rbuff(maxlen) if buf buf.replace(ret) ret = buf end raise EOFError if ret.empty? ret end def gets(eol=$/) idx = @rbuffer.index(eol) until @eof break if idx fill_rbuff idx = @rbuffer.index(eol) end if eol.is_a?(Regexp) size = idx ? idx+$&.size : nil else size = idx ? idx+eol.size : nil end consume_rbuff(size) end def each(eol=$/) while line = self.gets(eol) yield line end end alias each_line each def readlines(eol=$/) ary = [] while line = self.gets(eol) ary << line end ary end def readline(eol=$/) raise EOFError if eof? gets(eol) end def getc c = read(1) c ? c[0] : nil end def each_byte while c = getc yield(c) end end def readchar raise EOFError if eof? getc end def ungetc(c) @rbuffer[0,0] = c.chr end def eof? fill_rbuff if !@eof && @rbuffer.empty? @eof && @rbuffer.empty? end alias eof eof? # # for writing. # private def do_write(s) @wbuffer = "" unless defined? @wbuffer @wbuffer << s @sync ||= false if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/) remain = idx ? idx + $/.size : @wbuffer.length nwritten = 0 while remain > 0 str = @wbuffer[nwritten,remain] begin nwrote = syswrite(str) rescue Errno::EAGAIN retry end remain -= nwrote nwritten += nwrote end @wbuffer[0,nwritten] = "" end end public def write(s) do_write(s) s.length end def << (s) do_write(s) self end def puts(*args) s = "" if args.empty? s << "\n" end args.each{|arg| s << arg.to_s if $/ && /\n\z/ !~ s s << "\n" end } do_write(s) nil end def print(*args) s = "" args.each{ |arg| s << arg.to_s } do_write(s) nil end def printf(s, *args) do_write(s % args) nil end def flush osync = @sync @sync = true do_write "" @sync = osync end def close flush rescue nil sysclose end end end PK|]E=LLopenssl/config.rbnu[=begin = Ruby-space definitions that completes C-space funcs for Config = Info Copyright (C) 2010 Hiroshi Nakamura = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) =end ## # Should we care what if somebody require this file directly? #require 'openssl' require 'stringio' module OpenSSL class Config include Enumerable class << self def parse(str) c = new() parse_config(StringIO.new(str)).each do |section, hash| c[section] = hash end c end alias load new def parse_config(io) begin parse_config_lines(io) rescue ConfigError => e e.message.replace("error in line #{io.lineno}: " + e.message) raise end end def get_key_string(data, section, key) # :nodoc: if v = data[section] && data[section][key] return v elsif section == 'ENV' if v = ENV[key] return v end end if v = data['default'] && data['default'][key] return v end end private def parse_config_lines(io) section = 'default' data = {section => {}} while definition = get_definition(io) definition = clear_comments(definition) next if definition.empty? if definition[0] == ?[ if /\[([^\]]*)\]/ =~ definition section = $1.strip data[section] ||= {} else raise ConfigError, "missing close square bracket" end else if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition if $2 section = $1 key = $2 else key = $1 end value = unescape_value(data, section, $3) (data[section] ||= {})[key] = value.strip else raise ConfigError, "missing equal sign" end end end data end # escape with backslash QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/ # escape with backslash and doubled dq QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/ # escaped char map ESCAPE_MAP = { "r" => "\r", "n" => "\n", "b" => "\b", "t" => "\t", } def unescape_value(data, section, value) scanned = [] while m = value.match(/['"\\$]/) scanned << m.pre_match c = m[0] value = m.post_match case c when "'" if m = value.match(QUOTE_REGEXP_SQ) scanned << m[1].gsub(/\\(.)/, '\\1') value = m.post_match else break end when '"' if m = value.match(QUOTE_REGEXP_DQ) scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1') value = m.post_match else break end when "\\" c = value.slice!(0, 1) scanned << (ESCAPE_MAP[c] || c) when "$" ref, value = extract_reference(value) refsec = section if ref.index('::') refsec, ref = ref.split('::', 2) end if v = get_key_string(data, refsec, ref) scanned << v else raise ConfigError, "variable has no value" end else raise 'must not reaced' end end scanned << value scanned.join end def extract_reference(value) rest = '' if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/) value = m[1] || m[2] rest = m.post_match elsif [?(, ?{].include?(value[0]) raise ConfigError, "no close brace" end if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/) return m[0], m.post_match + rest else raise end end def clear_comments(line) # FCOMMENT if m = line.match(/\A([\t\n\f ]*);.*\z/) return m[1] end # COMMENT scanned = [] while m = line.match(/[#'"\\]/) scanned << m.pre_match c = m[0] line = m.post_match case c when '#' line = nil break when "'", '"' regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ scanned << c if m = line.match(regexp) scanned << m[0] line = m.post_match else scanned << line line = nil break end when "\\" scanned << c scanned << line.slice!(0, 1) else raise 'must not reaced' end end scanned << line scanned.join end def get_definition(io) if line = get_line(io) while /[^\\]\\\z/ =~ line if extra = get_line(io) line += extra else break end end return line.strip end end def get_line(io) if line = io.gets line.gsub(/[\r\n]*/, '') end end end def initialize(filename = nil) @data = {} if filename File.open(filename.to_s) do |file| Config.parse_config(file).each do |section, hash| self[section] = hash end end end end def get_value(section, key) if section.nil? raise TypeError.new('nil not allowed') end section = 'default' if section.empty? get_key_string(section, key) end def value(arg1, arg2 = nil) warn('Config#value is deprecated; use Config#get_value') if arg2.nil? section, key = 'default', arg1 else section, key = arg1, arg2 end section ||= 'default' section = 'default' if section.empty? get_key_string(section, key) end def add_value(section, key, value) check_modify (@data[section] ||= {})[key] = value end def [](section) @data[section] || {} end def section(name) warn('Config#section is deprecated; use Config#[]') @data[name] || {} end def []=(section, pairs) check_modify @data[section] ||= {} pairs.each do |key, value| self.add_value(section, key, value) end end def sections @data.keys end def to_s ary = [] @data.keys.sort.each do |section| ary << "[ #{section} ]\n" @data[section].keys.each do |key| ary << "#{key}=#{@data[section][key]}\n" end ary << "\n" end ary.join end def each @data.each do |section, hash| hash.each do |key, value| yield(section, key, value) end end end def inspect "#<#{self.class.name} sections=#{sections.inspect}>" end protected def data @data end private def initialize_copy(other) @data = other.data.dup end def check_modify raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen? end def get_key_string(section, key) Config.get_key_string(@data, section, key) end end end PK|]=fopenssl/digest.rbnu[=begin = $RCSfile$ -- Ruby-space predefined Digest subclasses = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id: digest.rb 28004 2010-05-24 23:58:49Z shyouhei $ =end ## # Should we care what if somebody require this file directly? #require 'openssl' module OpenSSL class Digest alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1) if OPENSSL_VERSION_NUMBER > 0x00908000 alg += %w(SHA224 SHA256 SHA384 SHA512) end def self.digest(name, data) super(data, name) end alg.each{|name| klass = Class.new(Digest){ define_method(:initialize){|*data| if data.length > 1 raise ArgumentError, "wrong number of arguments (#{data.length} for 1)" end super(name, data.first) } } singleton = (class << klass; self; end) singleton.class_eval{ define_method(:digest){|data| Digest.digest(name, data) } define_method(:hexdigest){|data| Digest.hexdigest(name, data) } } const_set(name, klass) } # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. class Digest < Digest def initialize(*args) # add warning super(*args) end end end # Digest end # OpenSSL PK|] tmpdir.rbnu[# # tmpdir - retrieve temporary directory path # # $Id: tmpdir.rb 21776 2009-01-26 02:12:10Z shyouhei $ # require 'fileutils' class Dir @@systmpdir = '/tmp' begin require 'Win32API' CSIDL_LOCAL_APPDATA = 0x001c max_pathlen = 260 windir = "\0"*(max_pathlen+1) begin getdir = Win32API.new('shell32', 'SHGetFolderPath', 'LLLLP', 'L') raise RuntimeError if getdir.call(0, CSIDL_LOCAL_APPDATA, 0, 0, windir) != 0 windir = File.expand_path(windir.rstrip) rescue RuntimeError begin getdir = Win32API.new('kernel32', 'GetSystemWindowsDirectory', 'PL', 'L') rescue RuntimeError getdir = Win32API.new('kernel32', 'GetWindowsDirectory', 'PL', 'L') end len = getdir.call(windir, windir.size) windir = File.expand_path(windir[0, len]) end temp = File.join(windir.untaint, 'temp') @@systmpdir = temp if File.directory?(temp) and File.writable?(temp) rescue LoadError end ## # Returns the operating system's temporary file path. def Dir::tmpdir tmp = '.' if $SAFE > 0 tmp = @@systmpdir else for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], ENV['USERPROFILE'], @@systmpdir, '/tmp'] if dir and File.directory?(dir) and File.writable?(dir) tmp = dir break end end File.expand_path(tmp) end end # Dir.mktmpdir creates a temporary directory. # # The directory is created with 0700 permission. # # The prefix and suffix of the name of the directory is specified by # the optional first argument, prefix_suffix. # - If it is not specified or nil, "d" is used as the prefix and no suffix is used. # - If it is a string, it is used as the prefix and no suffix is used. # - If it is an array, first element is used as the prefix and second element is used as a suffix. # # Dir.mktmpdir {|dir| dir is ".../d..." } # Dir.mktmpdir("foo") {|dir| dir is ".../foo..." } # Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" } # # The directory is created under Dir.tmpdir or # the optional second argument tmpdir if non-nil value is given. # # Dir.mktmpdir {|dir| dir is "#{Dir.tmpdir}/d..." } # Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." } # # If a block is given, # it is yielded with the path of the directory. # The directory and its contents are removed # using FileUtils.remove_entry_secure before Dir.mktmpdir returns. # The value of the block is returned. # # Dir.mktmpdir {|dir| # # use the directory... # open("#{dir}/foo", "w") { ... } # } # # If a block is not given, # The path of the directory is returned. # In this case, Dir.mktmpdir doesn't remove the directory. # # dir = Dir.mktmpdir # begin # # use the directory... # open("#{dir}/foo", "w") { ... } # ensure # # remove the directory. # FileUtils.remove_entry_secure dir # end # def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil) case prefix_suffix when nil prefix = "d" suffix = "" when String prefix = prefix_suffix suffix = "" when Array prefix = prefix_suffix[0] suffix = prefix_suffix[1] else raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}" end tmpdir ||= Dir.tmpdir t = Time.now.strftime("%Y%m%d") n = nil begin path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}" path << "-#{n}" if n path << suffix Dir.mkdir(path, 0700) rescue Errno::EEXIST n ||= 0 n += 1 retry end if block_given? begin yield path ensure FileUtils.remove_entry_secure path end else path end end end PK|]qc finalize.rbnu[#-- # finalizer.rb - # $Release Version: 0.3$ # $Revision: 1.4 $ # $Date: 1998/02/27 05:34:33 $ # by Keiju ISHITSUKA #++ # # Usage: # # add dependency R_method(obj, dependant) # add(obj, dependant, method = :finalize, *opt) # add_dependency(obj, dependant, method = :finalize, *opt) # # delete dependency R_method(obj, dependant) # delete(obj_or_id, dependant, method = :finalize) # delete_dependency(obj_or_id, dependant, method = :finalize) # # delete dependency R_*(obj, dependant) # delete_all_dependency(obj_or_id, dependant) # # delete dependency R_method(*, dependant) # delete_by_dependant(dependant, method = :finalize) # # delete dependency R_*(*, dependant) # delete_all_by_dependant(dependant) # # delete all dependency R_*(*, *) # delete_all # # finalize the dependant connected by dependency R_method(obj, dependtant). # finalize(obj_or_id, dependant, method = :finalize) # finalize_dependency(obj_or_id, dependant, method = :finalize) # # finalize all dependants connected by dependency R_*(obj, dependtant). # finalize_all_dependency(obj_or_id, dependant) # # finalize the dependant connected by dependency R_method(*, dependtant). # finalize_by_dependant(dependant, method = :finalize) # # finalize all dependants connected by dependency R_*(*, dependant). # finalize_all_by_dependant(dependant) # # finalize all dependency registered to the Finalizer. # finalize_all # # stop invoking Finalizer on GC. # safe{..} # module Finalizer RCS_ID='-$Id: finalize.rb,v 1.4 1998/02/27 05:34:33 keiju Exp keiju $-' class < [[dependant, method, *opt], ...], ...} # add dependency R_method(obj, dependant) def add_dependency(obj, dependant, method = :finalize, *opt) ObjectSpace.call_finalizer(obj) method = method.intern unless method.kind_of?(Integer) assoc = [dependant, method].concat(opt) if dep = @dependency[obj.object_id] dep.push assoc else @dependency[obj.object_id] = [assoc] end end alias add add_dependency # delete dependency R_method(obj, dependant) def delete_dependency(id, dependant, method = :finalize) id = id.object_id unless id.kind_of?(Integer) method = method.intern unless method.kind_of?(Integer) for assoc in @dependency[id] assoc.delete_if do |d, m, *o| d == dependant && m == method end @dependency.delete(id) if assoc.empty? end end alias delete delete_dependency # delete dependency R_*(obj, dependant) def delete_all_dependency(id, dependant) id = id.object_id unless id.kind_of?(Integer) method = method.intern unless method.kind_of?(Integer) for assoc in @dependency[id] assoc.delete_if do |d, m, *o| d == dependant end @dependency.delete(id) if assoc.empty? end end # delete dependency R_method(*, dependant) def delete_by_dependant(dependant, method = :finalize) method = method.intern unless method.kind_of?(Integer) for id in @dependency.keys delete(id, dependant, method) end end # delete dependency R_*(*, dependant) def delete_all_by_dependant(dependant) for id in @dependency.keys delete_all_dependency(id, dependant) end end # finalize the depandant connected by dependency R_method(obj, dependtant) def finalize_dependency(id, dependant, method = :finalize) id = id.object_id unless id.kind_of?(Integer) method = method.intern unless method.kind_of?(Integer) for assocs in @dependency[id] assocs.delete_if do |d, m, *o| d.send(m, id, *o) if ret = d == dependant && m == method ret end @dependency.delete(id) if assoc.empty? end end alias finalize finalize_dependency # finalize all dependants connected by dependency R_*(obj, dependtant) def finalize_all_dependency(id, dependant) id = id.object_id unless id.kind_of?(Integer) method = method.intern unless method.kind_of?(Integer) for assoc in @dependency[id] assoc.delete_if do |d, m, *o| d.send(m, id, *o) if ret = d == dependant end @dependency.delete(id) if assoc.empty? end end # finalize the dependant connected by dependency R_method(*, dependtant) def finalize_by_dependant(dependant, method = :finalize) method = method.intern unless method.kind_of?(Integer) for id in @dependency.keys finalize(id, dependant, method) end end # finalize all dependants connected by dependency R_*(*, dependtant) def finalize_all_by_dependant(dependant) for id in @dependency.keys finalize_all_dependency(id, dependant) end end # finalize all dependants registered to the Finalizer. def finalize_all for id, assocs in @dependency for dependant, method, *opt in assocs dependant.send(method, id, *opt) end assocs.clear end end # method to call finalize_* safely. def safe old_status = Thread.critical Thread.critical = true ObjectSpace.remove_finalizer(@proc) begin yield ensure ObjectSpace.add_finalizer(@proc) Thread.critical = old_status end end private # registering function to ObjectSpace#add_finalizer def final_of(id) if assocs = @dependency.delete(id) for dependant, method, *opt in assocs dependant.send(method, id, *opt) end end end end @dependency = Hash.new @proc = proc{|id| final_of(id)} ObjectSpace.add_finalizer(@proc) end PK|]v%&& e2mmap.rbnu[# # e2mmap.rb - for ruby 1.1 # $Release Version: 2.0$ # $Revision: 1.10 $ # $Date: 1999/02/17 12:33:17 $ # by Keiju ISHITSUKA # # -- # Usage: # # U1) # class Foo # extend Exception2MessageMapper # def_e2message ExistingExceptionClass, "message..." # def_exception :NewExceptionClass, "message..."[, superclass] # ... # end # # U2) # module Error # extend Exception2MessageMapper # def_e2meggage ExistingExceptionClass, "message..." # def_exception :NewExceptionClass, "message..."[, superclass] # ... # end # class Foo # include Error # ... # end # # foo = Foo.new # foo.Fail .... # # U3) # module Error # extend Exception2MessageMapper # def_e2message ExistingExceptionClass, "message..." # def_exception :NewExceptionClass, "message..."[, superclass] # ... # end # class Foo # extend Exception2MessageMapper # include Error # ... # end # # Foo.Fail NewExceptionClass, arg... # Foo.Fail ExistingExceptionClass, arg... # # fail "Use Ruby 1.1" if VERSION < "1.1" module Exception2MessageMapper @RCS_ID='-$Id: e2mmap.rb,v 1.10 1999/02/17 12:33:17 keiju Exp keiju $-' E2MM = Exception2MessageMapper def E2MM.extend_object(cl) super cl.bind(self) unless cl == E2MM end # backward compatibility def E2MM.extend_to(b) c = eval("self", b) c.extend(self) end def bind(cl) self.module_eval %[ def Raise(err = nil, *rest) Exception2MessageMapper.Raise(self.class, err, *rest) end alias Fail Raise def self.included(mod) mod.extend Exception2MessageMapper end ] end # Fail(err, *rest) # err: exception # rest: message arguments # def Raise(err = nil, *rest) E2MM.Raise(self, err, *rest) end alias Fail Raise # backward compatibility alias fail! fail def fail(err = nil, *rest) begin E2MM.Fail(self, err, *rest) rescue E2MM::ErrNotRegisteredException super end end class << self public :fail end # def_e2message(c, m) # c: exception # m: message_form # define exception c with message m. # def def_e2message(c, m) E2MM.def_e2message(self, c, m) end # def_exception(n, m, s) # n: exception_name # m: message_form # s: superclass(default: StandardError) # define exception named ``c'' with message m. # def def_exception(n, m, s = StandardError) E2MM.def_exception(self, n, m, s) end # # Private definitions. # # {[class, exp] => message, ...} @MessageMap = {} # E2MM.def_exception(k, e, m) # k: class to define exception under. # e: exception # m: message_form # define exception c with message m. # def E2MM.def_e2message(k, c, m) E2MM.instance_eval{@MessageMap[[k, c]] = m} c end # E2MM.def_exception(k, n, m, s) # k: class to define exception under. # n: exception_name # m: message_form # s: superclass(default: StandardError) # define exception named ``c'' with message m. # def E2MM.def_exception(k, n, m, s = StandardError) n = n.id2name if n.kind_of?(Fixnum) e = Class.new(s) E2MM.instance_eval{@MessageMap[[k, e]] = m} k.const_set(n, e) end # Fail(klass, err, *rest) # klass: class to define exception under. # err: exception # rest: message arguments # def E2MM.Raise(klass = E2MM, err = nil, *rest) if form = e2mm_message(klass, err) $! = err.new(sprintf(form, *rest)) $@ = caller(1) if $@.nil? #p $@ #p __FILE__ $@.shift if $@[0] =~ /^#{Regexp.quote(__FILE__)}:/ raise else E2MM.Fail E2MM, ErrNotRegisteredException, err.inspect end end class < # # This program is free software. # You can distribute/modify this program under the same terms of Ruby. # # == Utilities to replace common UNIX commands in Makefiles etc # # == SYNOPSIS # # ruby -run -e cp -- [OPTION] SOURCE DEST # ruby -run -e ln -- [OPTION] TARGET LINK_NAME # ruby -run -e mv -- [OPTION] SOURCE DEST # ruby -run -e rm -- [OPTION] FILE # ruby -run -e mkdir -- [OPTION] DIRS # ruby -run -e rmdir -- [OPTION] DIRS # ruby -run -e install -- [OPTION] SOURCE DEST # ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE # ruby -run -e touch -- [OPTION] FILE # ruby -run -e help [COMMAND] require "fileutils" require "optparse" module FileUtils # @fileutils_label = "" @fileutils_output = $stdout end def setup(options = "") ARGV.map! do |x| case x when /^-/ x.delete "^-#{options}v" when /[*?\[{]/ Dir[x] else x end end ARGV.flatten! ARGV.delete_if{|x| x == "-"} opt_hash = {} OptionParser.new do |o| options.scan(/.:?/) do |s| o.on("-" + s.tr(":", " ")) do |val| opt_hash[s.delete(":").intern] = val end end o.on("-v") do opt_hash[:verbose] = true end o.parse! end yield ARGV, opt_hash end ## # Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY # # ruby -run -e cp -- [OPTION] SOURCE DEST # # -p preserve file attributes if possible # -r copy recursively # -v verbose # def cp setup("pr") do |argv, options| cmd = "cp" cmd += "_r" if options.delete :r options[:preserve] = true if options.delete :p dest = argv.pop argv = argv[0] if argv.size == 1 FileUtils.send cmd, argv, dest, options end end ## # Create a link to the specified TARGET with LINK_NAME. # # ruby -run -e ln -- [OPTION] TARGET LINK_NAME # # -s make symbolic links instead of hard links # -f remove existing destination files # -v verbose # def ln setup("sf") do |argv, options| cmd = "ln" cmd += "_s" if options.delete :s options[:force] = true if options.delete :f dest = argv.pop argv = argv[0] if argv.size == 1 FileUtils.send cmd, argv, dest, options end end ## # Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. # # ruby -run -e mv -- [OPTION] SOURCE DEST # # -v verbose # def mv setup do |argv, options| dest = argv.pop argv = argv[0] if argv.size == 1 FileUtils.mv argv, dest, options end end ## # Remove the FILE # # ruby -run -e rm -- [OPTION] FILE # # -f ignore nonexistent files # -r remove the contents of directories recursively # -v verbose # def rm setup("fr") do |argv, options| cmd = "rm" cmd += "_r" if options.delete :r options[:force] = true if options.delete :f FileUtils.send cmd, argv, options end end ## # Create the DIR, if they do not already exist. # # ruby -run -e mkdir -- [OPTION] DIR # # -p no error if existing, make parent directories as needed # -v verbose # def mkdir setup("p") do |argv, options| cmd = "mkdir" cmd += "_p" if options.delete :p FileUtils.send cmd, argv, options end end ## # Remove the DIR. # # ruby -run -e rmdir -- [OPTION] DIR # # -v verbose # def rmdir setup do |argv, options| FileUtils.rmdir argv, options end end ## # Copy SOURCE to DEST. # # ruby -run -e install -- [OPTION] SOURCE DEST # # -p apply access/modification times of SOURCE files to # corresponding destination files # -m set permission mode (as in chmod), instead of 0755 # -v verbose # def install setup("pm:") do |argv, options| options[:mode] = (mode = options.delete :m) ? mode.oct : 0755 options[:preserve] = true if options.delete :p dest = argv.pop argv = argv[0] if argv.size == 1 FileUtils.install argv, dest, options end end ## # Change the mode of each FILE to OCTAL-MODE. # # ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE # # -v verbose # def chmod setup do |argv, options| mode = argv.shift.oct FileUtils.chmod mode, argv, options end end ## # Update the access and modification times of each FILE to the current time. # # ruby -run -e touch -- [OPTION] FILE # # -v verbose # def touch setup do |argv, options| FileUtils.touch argv, options end end ## # Display help message. # # ruby -run -e help [COMMAND] # def help setup do |argv,| all = argv.empty? open(__FILE__) do |me| while me.gets("##\n") if help = me.gets("\n\n") if all or argv.delete help[/-e \w+/].sub(/-e /, "") print help.gsub(/^# ?/, "") end end end end end end PK|]Gio/nonblock.rbnu[require "fcntl" class IO def nonblock? (fcntl(Fcntl::F_GETFL) & File::NONBLOCK) != 0 end def nonblock=(nb) f = fcntl(Fcntl::F_GETFL) if nb f |= File::NONBLOCK else f &= ~File::NONBLOCK end fcntl(Fcntl::F_SETFL, f) end def nonblock(nb = true) nb, self.nonblock = nonblock?, nb yield ensure self.nonblock = nb end end if defined?(Fcntl::F_GETFL) PK|]?JJJ mutex_m.rbnu[#-- # mutex_m.rb - # $Release Version: 3.0$ # $Revision: 1.7 $ # $Date: 1998/02/27 04:28:57 $ # Original from mutex.rb # by Keiju ISHITSUKA(keiju@ishitsuka.com) # modified by matz # patched by akira yamada #++ # # == Usage # # Extend an object and use it like a Mutex object: # # require "mutex_m.rb" # obj = Object.new # obj.extend Mutex_m # # ... # # Or, include Mutex_m in a class to have its instances behave like a Mutex # object: # # class Foo # include Mutex_m # # ... # end # # obj = Foo.new module Mutex_m def Mutex_m.define_aliases(cl) cl.module_eval %q{ alias locked? mu_locked? alias lock mu_lock alias unlock mu_unlock alias try_lock mu_try_lock alias synchronize mu_synchronize } end def Mutex_m.append_features(cl) super define_aliases(cl) unless cl.instance_of?(Module) end def Mutex_m.extend_object(obj) super obj.mu_extended end def mu_extended unless (defined? locked? and defined? lock and defined? unlock and defined? try_lock and defined? synchronize) Mutex_m.define_aliases(class< e x.raise e else x.raise exception, "execution expired" if x.alive? end } yield sec # return true rescue exception => e rej = /\A#{Regexp.quote(__FILE__)}:#{__LINE__-4}\z/o (bt = e.backtrace).reject! {|m| rej =~ m} level = -caller(CALLER_OFFSET).size while THIS_FILE =~ bt[level] bt.delete_at(level) level += 1 end raise if klass # if exception class is specified, it # would be expected outside. raise Error, e.message, e.backtrace ensure if y and y.alive? y.kill y.join # make sure y is dead. end end end module_function :timeout end ## # Identical to: # # Timeout::timeout(n, e, &block). # # Defined for backwards compatibility with earlier versions of timeout.rb, see # Timeout#timeout. def timeout(n, e = nil, &block) # :nodoc: Timeout::timeout(n, e, &block) end ## # Another name for Timeout::Error, defined for backwards compatibility with # earlier versions of timeout.rb. TimeoutError = Timeout::Error # :nodoc: if __FILE__ == $0 p timeout(5) { 45 } p timeout(5, TimeoutError) { 45 } p timeout(nil) { 54 } p timeout(0) { 54 } p timeout(5) { loop { p 10 sleep 1 } } end PK|]8hh thread.rbnu[unless defined? Thread fail "Thread not available for this ruby interpreter" end require 'thread.so' PK|]xCRRscanf.rbnu[# scanf for Ruby # # $Revision: 21682 $ # $Id: scanf.rb 21682 2009-01-20 03:23:46Z shyouhei $ # $Author: shyouhei $ # $Date: 2009-01-20 12:23:46 +0900 (Tue, 20 Jan 2009) $ # # A product of the Austin Ruby Codefest (Austin, Texas, August 2002) =begin =scanf for Ruby ==Description scanf for Ruby is an implementation of the C function scanf(3), modified as necessary for Ruby compatibility. The methods provided are String#scanf, IO#scanf, and Kernel#scanf. Kernel#scanf is a wrapper around STDIN.scanf. IO#scanf can be used on any IO stream, including file handles and sockets. scanf can be called either with or without a block. scanf for Ruby scans an input string or stream according to a format, as described below ("Conversions"), and returns an array of matches between the format and the input. The format is defined in a string, and is similar (though not identical) to the formats used in Kernel#printf and Kernel#sprintf. The format may contain conversion specifiers, which tell scanf what form (type) each particular matched substring should be converted to (e.g., decimal integer, floating point number, literal string, etc.) The matches and conversions take place from left to right, and the conversions themselves are returned as an array. The format string may also contain characters other than those in the conversion specifiers. White space (blanks, tabs, or newlines) in the format string matches any amount of white space, including none, in the input. Everything else matches only itself. Scanning stops, and scanf returns, when any input character fails to match the specifications in the format string, or when input is exhausted, or when everything in the format string has been matched. All matches found up to the stopping point are returned in the return array (or yielded to the block, if a block was given). ==Basic usage require 'scanf.rb' # String#scanf and IO#scanf take a single argument (a format string) array = aString.scanf("%d%s") array = anIO.scanf("%d%s") # Kernel#scanf reads from STDIN array = scanf("%d%s") ==Block usage When called with a block, scanf keeps scanning the input, cycling back to the beginning of the format string, and yields a new array of conversions to the block every time the format string is matched (including partial matches, but not including complete failures). The actual return value of scanf when called with a block is an array containing the results of all the executions of the block. str = "123 abc 456 def 789 ghi" str.scanf("%d%s") { |num,str| [ num * 2, str.upcase ] } # => [[246, "ABC"], [912, "DEF"], [1578, "GHI"]] ==Conversions The single argument to scanf is a format string, which generally includes one or more conversion specifiers. Conversion specifiers begin with the percent character ('%') and include information about what scanf should next scan for (string, decimal number, single character, etc.). There may be an optional maximum field width, expressed as a decimal integer, between the % and the conversion. If no width is given, a default of `infinity' is used (with the exception of the %c specifier; see below). Otherwise, given a field width of n for a given conversion, at most n characters are scanned in processing that conversion. Before conversion begins, most conversions skip white space in the input string; this white space is not counted against the field width. The following conversions are available. (See the files EXAMPLES and tests/scanftests.rb for examples.) [%] Matches a literal `%'. That is, `%%' in the format string matches a single input `%' character. No conversion is done, and the resulting '%' is not included in the return array. [d] Matches an optionally signed decimal integer. [u] Same as d. [i] Matches an optionally signed integer. The integer is read in base 16 if it begins with `0x' or `0X', in base 8 if it begins with `0', and in base 10 other- wise. Only characters that correspond to the base are recognized. [o] Matches an optionally signed octal integer. [x,X] Matches an optionally signed hexadecimal integer, [f,g,e,E] Matches an optionally signed floating-point number. [s] Matches a sequence of non-white-space character. The input string stops at white space or at the maximum field width, whichever occurs first. [c] Matches a single character, or a sequence of n characters if a field width of n is specified. The usual skip of leading white space is suppressed. To skip white space first, use an explicit space in the format. [[] Matches a nonempty sequence of characters from the specified set of accepted characters. The usual skip of leading white space is suppressed. This bracketed sub-expression is interpreted exactly like a character class in a Ruby regular expression. (In fact, it is placed as-is in a regular expression.) The matching against the input string ends with the appearance of a character not in (or, with a circumflex, in) the set, or when the field width runs out, whichever comes first. ===Assignment suppression To require that a particular match occur, but without including the result in the return array, place the assignment suppression flag, which is the star character ('*'), immediately after the leading '%' of a format specifier (just before the field width, if any). ==Examples See the files EXAMPLES and tests/scanftests.rb. ==scanf for Ruby compared with scanf in C scanf for Ruby is based on the C function scanf(3), but with modifications, dictated mainly by the underlying differences between the languages. ===Unimplemented flags and specifiers * The only flag implemented in scanf for Ruby is '*' (ignore upcoming conversion). Many of the flags available in C versions of scanf(4) have to do with the type of upcoming pointer arguments, and are literally meaningless in Ruby. * The n specifier (store number of characters consumed so far in next pointer) is not implemented. * The p specifier (match a pointer value) is not implemented. ===Altered specifiers [o,u,x,X] In scanf for Ruby, all of these specifiers scan for an optionally signed integer, rather than for an unsigned integer like their C counterparts. ===Return values scanf for Ruby returns an array of successful conversions, whereas scanf(3) returns the number of conversions successfully completed. (See below for more details on scanf for Ruby's return values.) ==Return values Without a block, scanf returns an array containing all the conversions it has found. If none are found, scanf will return an empty array. An unsuccesful match is never ignored, but rather always signals the end of the scanning operation. If the first unsuccessful match takes place after one or more successful matches have already taken place, the returned array will contain the results of those successful matches. With a block scanf returns a 'map'-like array of transformations from the block -- that is, an array reflecting what the block did with each yielded result from the iterative scanf operation. (See "Block usage", above.) ==Test suite scanf for Ruby includes a suite of unit tests (requiring the TestUnit package), which can be run with the command ruby tests/scanftests.rb or the command make test. ==Current limitations and bugs When using IO#scanf under Windows, make sure you open your files in binary mode: File.open("filename", "rb") so that scanf can keep track of characters correctly. Support for character classes is reasonably complete (since it essentially piggy-backs on Ruby's regular expression handling of character classes), but users are advised that character class testing has not been exhaustive, and that they should exercise some caution in using any of the more complex and/or arcane character class idioms. ==Technical notes ===Rationale behind scanf for Ruby The impetus for a scanf implementation in Ruby comes chiefly from the fact that existing pattern matching operations, such as Regexp#match and String#scan, return all results as strings, which have to be converted to integers or floats explicitly in cases where what's ultimately wanted are integer or float values. ===Design of scanf for Ruby scanf for Ruby is essentially a -to- converter. When scanf is called, a FormatString object is generated from the format string ("%d%s...") argument. The FormatString object breaks the format string down into atoms ("%d", "%5f", "blah", etc.), and from each atom it creates a FormatSpecifier object, which it saves. Each FormatSpecifier has a regular expression fragment and a "handler" associated with it. For example, the regular expression fragment associated with the format "%d" is "([-+]?\d+)", and the handler associated with it is a wrapper around String#to_i. scanf itself calls FormatString#match, passing in the input string. FormatString#match iterates through its FormatSpecifiers; for each one, it matches the corresponding regular expression fragment against the string. If there's a match, it sends the matched string to the handler associated with the FormatSpecifier. Thus, to follow up the "%d" example: if "123" occurs in the input string when a FormatSpecifier consisting of "%d" is reached, the "123" will be matched against "([-+]?\d+)", and the matched string will be rendered into an integer by a call to to_i. The rendered match is then saved to an accumulator array, and the input string is reduced to the post-match substring. Thus the string is "eaten" from the left as the FormatSpecifiers are applied in sequence. (This is done to a duplicate string; the original string is not altered.) As soon as a regular expression fragment fails to match the string, or when the FormatString object runs out of FormatSpecifiers, scanning stops and results accumulated so far are returned in an array. ==License and copyright Copyright:: (c) 2002-2003 David Alan Black License:: Distributed on the same licensing terms as Ruby itself ==Warranty disclaimer This software is provided "as is" and without any express or implied warranties, including, without limitation, the implied warranties of merchantibility and fitness for a particular purpose. ==Credits and acknowledgements scanf for Ruby was developed as the major activity of the Austin Ruby Codefest (Austin, Texas, August 2002). Principal author:: David Alan Black (mailto:dblack@superlink.net) Co-author:: Hal Fulton (mailto:hal9000@hypermetrics.com) Project contributors:: Nolan Darilek, Jason Johnston Thanks to Hal Fulton for hosting the Codefest. Thanks to Matz for suggestions about the class design. Thanks to Gavin Sinclair for some feedback on the documentation. The text for parts of this document, especially the Description and Conversions sections, above, were adapted from the Linux Programmer's Manual manpage for scanf(3), dated 1995-11-01. ==Bugs and bug reports scanf for Ruby is based on something of an amalgam of C scanf implementations and documentation, rather than on a single canonical description. Suggestions for features and behaviors which appear in other scanfs, and would be meaningful in Ruby, are welcome, as are reports of suspicious behaviors and/or bugs. (Please see "Credits and acknowledgements", above, for email addresses.) =end module Scanf class FormatSpecifier attr_reader :re_string, :matched_string, :conversion, :matched private def skip; /^\s*%\*/.match(@spec_string); end def extract_float(s); s.to_f if s &&! skip; end def extract_decimal(s); s.to_i if s &&! skip; end def extract_hex(s); s.hex if s &&! skip; end def extract_octal(s); s.oct if s &&! skip; end def extract_integer(s); Integer(s) if s &&! skip; end def extract_plain(s); s unless skip; end def nil_proc(s); nil; end public def to_s @spec_string end def count_space? /(?:\A|\S)%\*?\d*c|\[/.match(@spec_string) end def initialize(str) @spec_string = str h = '[A-Fa-f0-9]' @re_string, @handler = case @spec_string # %[[:...:]] when /%\*?(\[\[:[a-z]+:\]\])/ [ "(#{$1}+)", :extract_plain ] # %5[[:...:]] when /%\*?(\d+)(\[\[:[a-z]+:\]\])/ [ "(#{$2}{1,#{$1}})", :extract_plain ] # %[...] when /%\*?\[([^\]]*)\]/ yes = $1 if /^\^/.match(yes) then no = yes[1..-1] else no = '^' + yes end [ "([#{yes}]+)(?=[#{no}]|\\z)", :extract_plain ] # %5[...] when /%\*?(\d+)\[([^\]]*)\]/ yes = $2 w = $1 [ "([#{yes}]{1,#{w}})", :extract_plain ] # %i when /%\*?i/ [ "([-+]?(?:(?:0[0-7]+)|(?:0[Xx]#{h}+)|(?:[1-9]\\d*)))", :extract_integer ] # %5i when /%\*?(\d+)i/ n = $1.to_i s = "(" if n > 1 then s += "[1-9]\\d{1,#{n-1}}|" end if n > 1 then s += "0[0-7]{1,#{n-1}}|" end if n > 2 then s += "[-+]0[0-7]{1,#{n-2}}|" end if n > 2 then s += "[-+][1-9]\\d{1,#{n-2}}|" end if n > 2 then s += "0[Xx]#{h}{1,#{n-2}}|" end if n > 3 then s += "[-+]0[Xx]#{h}{1,#{n-3}}|" end s += "\\d" s += ")" [ s, :extract_integer ] # %d, %u when /%\*?[du]/ [ '([-+]?\d+)', :extract_decimal ] # %5d, %5u when /%\*?(\d+)[du]/ n = $1.to_i s = "(" if n > 1 then s += "[-+]\\d{1,#{n-1}}|" end s += "\\d{1,#{$1}})" [ s, :extract_decimal ] # %x when /%\*?[Xx]/ [ "([-+]?(?:0[Xx])?#{h}+)", :extract_hex ] # %5x when /%\*?(\d+)[Xx]/ n = $1.to_i s = "(" if n > 3 then s += "[-+]0[Xx]#{h}{1,#{n-3}}|" end if n > 2 then s += "0[Xx]#{h}{1,#{n-2}}|" end if n > 1 then s += "[-+]#{h}{1,#{n-1}}|" end s += "#{h}{1,#{n}}" s += ")" [ s, :extract_hex ] # %o when /%\*?o/ [ '([-+]?[0-7]+)', :extract_octal ] # %5o when /%\*?(\d+)o/ [ "([-+][0-7]{1,#{$1.to_i-1}}|[0-7]{1,#{$1}})", :extract_octal ] # %f when /%\*?f/ [ '([-+]?((\d+(?>(?=[^\d.]|$)))|(\d*(\.(\d*([eE][-+]?\d+)?)))))', :extract_float ] # %5f when /%\*?(\d+)f/ [ "(\\S{1,#{$1}})", :extract_float ] # %5s when /%\*?(\d+)s/ [ "(\\S{1,#{$1}})", :extract_plain ] # %s when /%\*?s/ [ '(\S+)', :extract_plain ] # %c when /\s%\*?c/ [ "\\s*(.)", :extract_plain ] # %c when /%\*?c/ [ "(.)", :extract_plain ] # %5c (whitespace issues are handled by the count_*_space? methods) when /%\*?(\d+)c/ [ "(.{1,#{$1}})", :extract_plain ] # %% when /%%/ [ '(\s*%)', :nil_proc ] # literal characters else [ "(#{Regexp.escape(@spec_string)})", :nil_proc ] end @re_string = '\A' + @re_string end def to_re Regexp.new(@re_string,Regexp::MULTILINE) end def match(str) @matched = false s = str.dup s.sub!(/\A\s+/,'') unless count_space? res = to_re.match(s) if res @conversion = send(@handler, res[1]) @matched_string = @conversion.to_s @matched = true end res end def letter /%\*?\d*([a-z\[])/.match(@spec_string).to_a[1] end def width w = /%\*?(\d+)/.match(@spec_string).to_a[1] w && w.to_i end def mid_match? return false unless @matched cc_no_width = letter == '[' &&! width c_or_cc_width = (letter == 'c' || letter == '[') && width width_left = c_or_cc_width && (matched_string.size < width) return width_left || cc_no_width end end class FormatString attr_reader :string_left, :last_spec_tried, :last_match_tried, :matched_count, :space SPECIFIERS = 'diuXxofeEgsc' REGEX = / # possible space, followed by... (?:\s* # percent sign, followed by... % # another percent sign, or... (?:%| # optional assignment suppression flag \*? # optional maximum field width \d* # named character class, ... (?:\[\[:\w+:\]\]| # traditional character class, or... \[[^\]]*\]| # specifier letter. [#{SPECIFIERS}])))| # or miscellaneous characters [^%\s]+/ix def initialize(str) @specs = [] @i = 1 s = str.to_s return unless /\S/.match(s) @space = true if /\s\z/.match(s) @specs.replace s.scan(REGEX).map {|spec| FormatSpecifier.new(spec) } end def to_s @specs.join('') end def prune(n=matched_count) n.times { @specs.shift } end def spec_count @specs.size end def last_spec @i == spec_count - 1 end def match(str) accum = [] @string_left = str @matched_count = 0 @specs.each_with_index do |spec,@i| @last_spec_tried = spec @last_match_tried = spec.match(@string_left) break unless @last_match_tried @matched_count += 1 accum << spec.conversion @string_left = @last_match_tried.post_match break if @string_left.empty? end return accum.compact end end end class IO # The trick here is doing a match where you grab one *line* # of input at a time. The linebreak may or may not occur # at the boundary where the string matches a format specifier. # And if it does, some rule about whitespace may or may not # be in effect... # # That's why this is much more elaborate than the string # version. # # For each line: # Match succeeds (non-emptily) # and the last attempted spec/string sub-match succeeded: # # could the last spec keep matching? # yes: save interim results and continue (next line) # # The last attempted spec/string did not match: # # are we on the next-to-last spec in the string? # yes: # is fmt_string.string_left all spaces? # yes: does current spec care about input space? # yes: fatal failure # no: save interim results and continue # no: continue [this state could be analyzed further] # # def scanf(str,&b) return block_scanf(str,&b) if b return [] unless str.size > 0 start_position = pos rescue 0 matched_so_far = 0 source_buffer = "" result_buffer = [] final_result = [] fstr = Scanf::FormatString.new(str) loop do if eof || (tty? &&! fstr.match(source_buffer)) final_result.concat(result_buffer) break end source_buffer << gets current_match = fstr.match(source_buffer) spec = fstr.last_spec_tried if spec.matched if spec.mid_match? result_buffer.replace(current_match) next end elsif (fstr.matched_count == fstr.spec_count - 1) if /\A\s*\z/.match(fstr.string_left) break if spec.count_space? result_buffer.replace(current_match) next end end final_result.concat(current_match) matched_so_far += source_buffer.size source_buffer.replace(fstr.string_left) matched_so_far -= source_buffer.size break if fstr.last_spec fstr.prune end seek(start_position + matched_so_far, IO::SEEK_SET) rescue Errno::ESPIPE soak_up_spaces if fstr.last_spec && fstr.space return final_result end private def soak_up_spaces c = getc ungetc(c) if c until eof ||! c || /\S/.match(c.chr) c = getc end ungetc(c) if (c && /\S/.match(c.chr)) end def block_scanf(str) final = [] # Sub-ideal, since another FS gets created in scanf. # But used here to determine the number of specifiers. fstr = Scanf::FormatString.new(str) last_spec = fstr.last_spec begin current = scanf(str) break if current.empty? final.push(yield(current)) end until eof || fstr.last_spec_tried == last_spec return final end end class String def scanf(fstr,&b) if b block_scanf(fstr,&b) else fs = if fstr.is_a? Scanf::FormatString fstr else Scanf::FormatString.new(fstr) end fs.match(self) end end def block_scanf(fstr,&b) fs = Scanf::FormatString.new(fstr) str = self.dup final = [] begin current = str.scanf(fs) final.push(yield(current)) unless current.empty? str = fs.string_left end until current.empty? || str.empty? return final end end module Kernel private def scanf(fs,&b) STDIN.scanf(fs,&b) end end PK|]ojVmd5.rbnu[# just for compatibility; requiring "md5" is obsoleted # # $RoughId: md5.rb,v 1.4 2001/07/13 15:38:27 knu Exp $ # $Id: md5.rb 12007 2007-03-06 10:09:51Z knu $ require 'digest/md5' class MD5 < Digest::MD5 class << self alias orig_new new def new(str = nil) if str orig_new.update(str) else orig_new end end def md5(*args) new(*args) end end end PK|]'66resolv-replace.rbnu[require 'socket' require 'resolv' class << IPSocket alias original_resolv_getaddress getaddress def getaddress(host) begin return Resolv.getaddress(host).to_s rescue Resolv::ResolvError raise SocketError, "Hostname not known: #{host}" end end end class TCPSocket alias original_resolv_initialize initialize def initialize(host, serv, *rest) rest[0] = IPSocket.getaddress(rest[0]) unless rest.empty? original_resolv_initialize(IPSocket.getaddress(host), serv, *rest) end end class UDPSocket alias original_resolv_bind bind def bind(host, port) host = IPSocket.getaddress(host) if host != "" original_resolv_bind(host, port) end alias original_resolv_connect connect def connect(host, port) original_resolv_connect(IPSocket.getaddress(host), port) end alias original_resolv_send send def send(mesg, flags, *rest) if rest.length == 2 host, port = rest begin addrs = Resolv.getaddresses(host) rescue Resolv::ResolvError raise SocketError, "Hostname not known: #{host}" end err = nil addrs[0...-1].each {|addr| begin return original_resolv_send(mesg, flags, addr, port) rescue SystemCallError end } original_resolv_send(mesg, flags, addrs[-1], port) else original_resolv_send(mesg, flags, *rest) end end end class SOCKSSocket alias original_resolv_initialize initialize def initialize(host, serv) original_resolv_initialize(IPSocket.getaddress(host), port) end end if defined? SOCKSSocket PK|]f*=ll matrix.rbnu[#!/usr/local/bin/ruby #-- # matrix.rb - # $Release Version: 1.0$ # $Revision: 1.11 $ # $Date: 1999/10/06 11:01:53 $ # Original Version from Smalltalk-80 version # on July 23, 1985 at 8:37:17 am # by Keiju ISHITSUKA #++ # # = matrix.rb # # An implementation of Matrix and Vector classes. # # Author:: Keiju ISHITSUKA # Documentation:: Gavin Sinclair (sourced from Ruby in a Nutshell (Matsumoto, O'Reilly)) # # See classes Matrix and Vector for documentation. # require "e2mmap.rb" module ExceptionForMatrix # :nodoc: extend Exception2MessageMapper def_e2message(TypeError, "wrong argument type %s (expected %s)") def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)") def_exception("ErrDimensionMismatch", "\#{self.name} dimension mismatch") def_exception("ErrNotRegular", "Not Regular Matrix") def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined") end # # The +Matrix+ class represents a mathematical matrix, and provides methods for creating # special-case matrices (zero, identity, diagonal, singular, vector), operating on them # arithmetically and algebraically, and determining their mathematical properties (trace, rank, # inverse, determinant). # # Note that although matrices should theoretically be rectangular, this is not # enforced by the class. # # Also note that the determinant of integer matrices may be incorrectly calculated unless you # also require 'mathn'. This may be fixed in the future. # # == Method Catalogue # # To create a matrix: # * Matrix[*rows] # * Matrix.[](*rows) # * Matrix.rows(rows, copy = true) # * Matrix.columns(columns) # * Matrix.diagonal(*values) # * Matrix.scalar(n, value) # * Matrix.scalar(n, value) # * Matrix.identity(n) # * Matrix.unit(n) # * Matrix.I(n) # * Matrix.zero(n) # * Matrix.row_vector(row) # * Matrix.column_vector(column) # # To access Matrix elements/columns/rows/submatrices/properties: # * [](i, j) # * #row_size # * #column_size # * #row(i) # * #column(j) # * #collect # * #map # * #minor(*param) # # Properties of a matrix: # * #regular? # * #singular? # * #square? # # Matrix arithmetic: # * *(m) # * +(m) # * -(m) # * #/(m) # * #inverse # * #inv # * ** # # Matrix functions: # * #determinant # * #det # * #rank # * #trace # * #tr # * #transpose # * #t # # Conversion to other data types: # * #coerce(other) # * #row_vectors # * #column_vectors # * #to_a # # String representations: # * #to_s # * #inspect # class Matrix @RCS_ID='-$Id: matrix.rb,v 1.11 1999/10/06 11:01:53 keiju Exp keiju $-' # extend Exception2MessageMapper include ExceptionForMatrix # instance creations private_class_method :new # # Creates a matrix where each argument is a row. # Matrix[ [25, 93], [-1, 66] ] # => 25 93 # -1 66 # def Matrix.[](*rows) new(:init_rows, rows, false) end # # Creates a matrix where +rows+ is an array of arrays, each of which is a row # to the matrix. If the optional argument +copy+ is false, use the given # arrays as the internal structure of the matrix without copying. # Matrix.rows([[25, 93], [-1, 66]]) # => 25 93 # -1 66 def Matrix.rows(rows, copy = true) new(:init_rows, rows, copy) end # # Creates a matrix using +columns+ as an array of column vectors. # Matrix.columns([[25, 93], [-1, 66]]) # => 25 -1 # 93 66 # # def Matrix.columns(columns) rows = (0 .. columns[0].size - 1).collect { |i| (0 .. columns.size - 1).collect { |j| columns[j][i] } } Matrix.rows(rows, false) end # # Creates a matrix where the diagonal elements are composed of +values+. # Matrix.diagonal(9, 5, -3) # => 9 0 0 # 0 5 0 # 0 0 -3 # def Matrix.diagonal(*values) size = values.size rows = (0 .. size - 1).collect { |j| row = Array.new(size).fill(0, 0, size) row[j] = values[j] row } rows(rows, false) end # # Creates an +n+ by +n+ diagonal matrix where each diagonal element is # +value+. # Matrix.scalar(2, 5) # => 5 0 # 0 5 # def Matrix.scalar(n, value) Matrix.diagonal(*Array.new(n).fill(value, 0, n)) end # # Creates an +n+ by +n+ identity matrix. # Matrix.identity(2) # => 1 0 # 0 1 # def Matrix.identity(n) Matrix.scalar(n, 1) end class << Matrix alias unit identity alias I identity end # # Creates an +n+ by +n+ zero matrix. # Matrix.zero(2) # => 0 0 # 0 0 # def Matrix.zero(n) Matrix.scalar(n, 0) end # # Creates a single-row matrix where the values of that row are as given in # +row+. # Matrix.row_vector([4,5,6]) # => 4 5 6 # def Matrix.row_vector(row) case row when Vector Matrix.rows([row.to_a], false) when Array Matrix.rows([row.dup], false) else Matrix.rows([[row]], false) end end # # Creates a single-column matrix where the values of that column are as given # in +column+. # Matrix.column_vector([4,5,6]) # => 4 # 5 # 6 # def Matrix.column_vector(column) case column when Vector Matrix.columns([column.to_a]) when Array Matrix.columns([column]) else Matrix.columns([[column]]) end end # # This method is used by the other methods that create matrices, and is of no # use to general users. # def initialize(init_method, *argv) self.send(init_method, *argv) end def init_rows(rows, copy) if copy @rows = rows.collect{|row| row.dup} else @rows = rows end self end private :init_rows # # Returns element (+i+,+j+) of the matrix. That is: row +i+, column +j+. # def [](i, j) @rows[i][j] end # # Returns the number of rows. # def row_size @rows.size end # # Returns the number of columns. Note that it is possible to construct a # matrix with uneven columns (e.g. Matrix[ [1,2,3], [4,5] ]), but this is # mathematically unsound. This method uses the first row to determine the # result. # def column_size @rows[0].size end # # Returns row vector number +i+ of the matrix as a Vector (starting at 0 like # an array). When a block is given, the elements of that vector are iterated. # def row(i) # :yield: e if block_given? for e in @rows[i] yield e end else Vector.elements(@rows[i]) end end # # Returns column vector number +j+ of the matrix as a Vector (starting at 0 # like an array). When a block is given, the elements of that vector are # iterated. # def column(j) # :yield: e if block_given? 0.upto(row_size - 1) do |i| yield @rows[i][j] end else col = (0 .. row_size - 1).collect { |i| @rows[i][j] } Vector.elements(col, false) end end # # Returns a matrix that is the result of iteration of the given block over all # elements of the matrix. # Matrix[ [1,2], [3,4] ].collect { |i| i**2 } # => 1 4 # 9 16 # def collect # :yield: e rows = @rows.collect{|row| row.collect{|e| yield e}} Matrix.rows(rows, false) end alias map collect # # Returns a section of the matrix. The parameters are either: # * start_row, nrows, start_col, ncols; OR # * col_range, row_range # # Matrix.diagonal(9, 5, -3).minor(0..1, 0..2) # => 9 0 0 # 0 5 0 # def minor(*param) case param.size when 2 from_row = param[0].first size_row = param[0].end - from_row size_row += 1 unless param[0].exclude_end? from_col = param[1].first size_col = param[1].end - from_col size_col += 1 unless param[1].exclude_end? when 4 from_row = param[0] size_row = param[1] from_col = param[2] size_col = param[3] else Matrix.Raise ArgumentError, param.inspect end rows = @rows[from_row, size_row].collect{ |row| row[from_col, size_col] } Matrix.rows(rows, false) end #-- # TESTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Returns +true+ if this is a regular matrix. # def regular? square? and rank == column_size end # # Returns +true+ is this is a singular (i.e. non-regular) matrix. # def singular? not regular? end # # Returns +true+ is this is a square matrix. See note in column_size about this # being unreliable, though. # def square? column_size == row_size end #-- # OBJECT METHODS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Returns +true+ if and only if the two matrices contain equal elements. # def ==(other) return false unless Matrix === other other.compare_by_row_vectors(@rows) end alias eql? == # # Not really intended for general consumption. # def compare_by_row_vectors(rows) return false unless @rows.size == rows.size 0.upto(@rows.size - 1) do |i| return false unless @rows[i] == rows[i] end true end # # Returns a clone of the matrix, so that the contents of each do not reference # identical objects. # def clone Matrix.rows(@rows) end # # Returns a hash-code for the matrix. # def hash value = 0 for row in @rows for e in row value ^= e.hash end end return value end #-- # ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Matrix multiplication. # Matrix[[2,4], [6,8]] * Matrix.identity(2) # => 2 4 # 6 8 # def *(m) # m is matrix or vector or number case(m) when Numeric rows = @rows.collect { |row| row.collect { |e| e * m } } return Matrix.rows(rows, false) when Vector m = Matrix.column_vector(m) r = self * m return r.column(0) when Matrix Matrix.Raise ErrDimensionMismatch if column_size != m.row_size rows = (0 .. row_size - 1).collect { |i| (0 .. m.column_size - 1).collect { |j| vij = 0 0.upto(column_size - 1) do |k| vij += self[i, k] * m[k, j] end vij } } return Matrix.rows(rows, false) else x, y = m.coerce(self) return x * y end end # # Matrix addition. # Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]] # => 6 0 # -4 12 # def +(m) case m when Numeric Matrix.Raise ErrOperationNotDefined, "+" when Vector m = Matrix.column_vector(m) when Matrix else x, y = m.coerce(self) return x + y end Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size rows = (0 .. row_size - 1).collect { |i| (0 .. column_size - 1).collect { |j| self[i, j] + m[i, j] } } Matrix.rows(rows, false) end # # Matrix subtraction. # Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]] # => -8 2 # 8 1 # def -(m) case m when Numeric Matrix.Raise ErrOperationNotDefined, "-" when Vector m = Matrix.column_vector(m) when Matrix else x, y = m.coerce(self) return x - y end Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size rows = (0 .. row_size - 1).collect { |i| (0 .. column_size - 1).collect { |j| self[i, j] - m[i, j] } } Matrix.rows(rows, false) end # # Matrix division (multiplication by the inverse). # Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]] # => -7 1 # -3 -6 # def /(other) case other when Numeric rows = @rows.collect { |row| row.collect { |e| e / other } } return Matrix.rows(rows, false) when Matrix return self * other.inverse else x, y = other.coerce(self) rerurn x / y end end # # Returns the inverse of the matrix. # Matrix[[1, 2], [2, 1]].inverse # => -1 1 # 0 -1 # def inverse Matrix.Raise ErrDimensionMismatch unless square? Matrix.I(row_size).inverse_from(self) end alias inv inverse # # Not for public consumption? # def inverse_from(src) size = row_size - 1 a = src.to_a for k in 0..size i = k akk = a[k][k].abs for j in (k+1)..size v = a[j][k].abs if v > akk i = j akk = v end end Matrix.Raise ErrNotRegular if akk == 0 if i != k a[i], a[k] = a[k], a[i] @rows[i], @rows[k] = @rows[k], @rows[i] end akk = a[k][k] for i in 0 .. size next if i == k q = a[i][k] / akk a[i][k] = 0 (k + 1).upto(size) do |j| a[i][j] -= a[k][j] * q end 0.upto(size) do |j| @rows[i][j] -= @rows[k][j] * q end end (k + 1).upto(size) do |j| a[k][j] /= akk end 0.upto(size) do |j| @rows[k][j] /= akk end end self end #alias reciprocal inverse # # Matrix exponentiation. Defined for integer powers only. Equivalent to # multiplying the matrix by itself N times. # Matrix[[7,6], [3,9]] ** 2 # => 67 96 # 48 99 # def ** (other) if other.kind_of?(Integer) x = self if other <= 0 x = self.inverse return Matrix.identity(self.column_size) if other == 0 other = -other end z = x n = other - 1 while n != 0 while (div, mod = n.divmod(2) mod == 0) x = x * x n = div end z *= x n -= 1 end z elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational) Matrix.Raise ErrOperationNotDefined, "**" else Matrix.Raise ErrOperationNotDefined, "**" end end #-- # MATRIX FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Returns the determinant of the matrix. If the matrix is not square, the # result is 0. # Matrix[[7,6], [3,9]].determinant # => 63 # def determinant return 0 unless square? size = row_size - 1 a = to_a det = 1 k = 0 begin if (akk = a[k][k]) == 0 i = k begin return 0 if (i += 1) > size end while a[i][k] == 0 a[i], a[k] = a[k], a[i] akk = a[k][k] det *= -1 end (k + 1).upto(size) do |i| q = a[i][k] / akk (k + 1).upto(size) do |j| a[i][j] -= a[k][j] * q end end det *= akk end while (k += 1) <= size det end alias det determinant # # Returns the rank of the matrix. Beware that using Float values, with their # usual lack of precision, can affect the value returned by this method. Use # Rational values instead if this is important to you. # Matrix[[7,6], [3,9]].rank # => 2 # def rank if column_size > row_size a = transpose.to_a a_column_size = row_size a_row_size = column_size else a = to_a a_column_size = column_size a_row_size = row_size end rank = 0 k = 0 begin if (akk = a[k][k]) == 0 i = k exists = true begin if (i += 1) > a_column_size - 1 exists = false break end end while a[i][k] == 0 if exists a[i], a[k] = a[k], a[i] akk = a[k][k] else i = k exists = true begin if (i += 1) > a_row_size - 1 exists = false break end end while a[k][i] == 0 if exists k.upto(a_column_size - 1) do |j| a[j][k], a[j][i] = a[j][i], a[j][k] end akk = a[k][k] else next end end end (k + 1).upto(a_row_size - 1) do |i| q = a[i][k] / akk (k + 1).upto(a_column_size - 1) do |j| a[i][j] -= a[k][j] * q end end rank += 1 end while (k += 1) <= a_column_size - 1 return rank end # # Returns the trace (sum of diagonal elements) of the matrix. # Matrix[[7,6], [3,9]].trace # => 16 # def trace tr = 0 0.upto(column_size - 1) do |i| tr += @rows[i][i] end tr end alias tr trace # # Returns the transpose of the matrix. # Matrix[[1,2], [3,4], [5,6]] # => 1 2 # 3 4 # 5 6 # Matrix[[1,2], [3,4], [5,6]].transpose # => 1 3 5 # 2 4 6 # def transpose Matrix.columns(@rows) end alias t transpose #-- # CONVERTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # FIXME: describe #coerce. # def coerce(other) case other when Numeric return Scalar.new(other), self else raise TypeError, "#{self.class} can't be coerced into #{other.class}" end end # # Returns an array of the row vectors of the matrix. See Vector. # def row_vectors rows = (0 .. row_size - 1).collect { |i| row(i) } rows end # # Returns an array of the column vectors of the matrix. See Vector. # def column_vectors columns = (0 .. column_size - 1).collect { |i| column(i) } columns end # # Returns an array of arrays that describe the rows of the matrix. # def to_a @rows.collect{|row| row.collect{|e| e}} end #-- # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Overrides Object#to_s # def to_s "Matrix[" + @rows.collect{ |row| "[" + row.collect{|e| e.to_s}.join(", ") + "]" }.join(", ")+"]" end # # Overrides Object#inspect # def inspect "Matrix"+@rows.inspect end # Private CLASS class Scalar < Numeric # :nodoc: include ExceptionForMatrix def initialize(value) @value = value end # ARITHMETIC def +(other) case other when Numeric Scalar.new(@value + other) when Vector, Matrix Scalar.Raise WrongArgType, other.class, "Numeric or Scalar" when Scalar Scalar.new(@value + other.value) else x, y = other.coerce(self) x + y end end def -(other) case other when Numeric Scalar.new(@value - other) when Vector, Matrix Scalar.Raise WrongArgType, other.class, "Numeric or Scalar" when Scalar Scalar.new(@value - other.value) else x, y = other.coerce(self) x - y end end def *(other) case other when Numeric Scalar.new(@value * other) when Vector, Matrix other.collect{|e| @value * e} else x, y = other.coerce(self) x * y end end def / (other) case other when Numeric Scalar.new(@value / other) when Vector Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix" when Matrix self * _M.inverse else x, y = other.coerce(self) x / y end end def ** (other) case other when Numeric Scalar.new(@value ** other) when Vector Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix" when Matrix other.powered_by(self) else x, y = other.coerce(self) x ** y end end end end # # The +Vector+ class represents a mathematical vector, which is useful in its own right, and # also constitutes a row or column of a Matrix. # # == Method Catalogue # # To create a Vector: # * Vector.[](*array) # * Vector.elements(array, copy = true) # # To access elements: # * [](i) # # To enumerate the elements: # * #each2(v) # * #collect2(v) # # Vector arithmetic: # * *(x) "is matrix or number" # * +(v) # * -(v) # # Vector functions: # * #inner_product(v) # * #collect # * #map # * #map2(v) # * #r # * #size # # Conversion to other data types: # * #covector # * #to_a # * #coerce(other) # # String representations: # * #to_s # * #inspect # class Vector include ExceptionForMatrix #INSTANCE CREATION private_class_method :new # # Creates a Vector from a list of elements. # Vector[7, 4, ...] # def Vector.[](*array) new(:init_elements, array, copy = false) end # # Creates a vector from an Array. The optional second argument specifies # whether the array itself or a copy is used internally. # def Vector.elements(array, copy = true) new(:init_elements, array, copy) end # # For internal use. # def initialize(method, array, copy) self.send(method, array, copy) end # # For internal use. # def init_elements(array, copy) if copy @elements = array.dup else @elements = array end end # ACCESSING # # Returns element number +i+ (starting at zero) of the vector. # def [](i) @elements[i] end # # Returns the number of elements in the vector. # def size @elements.size end #-- # ENUMERATIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Iterate over the elements of this vector and +v+ in conjunction. # def each2(v) # :yield: e1, e2 Vector.Raise ErrDimensionMismatch if size != v.size 0.upto(size - 1) do |i| yield @elements[i], v[i] end end # # Collects (as in Enumerable#collect) over the elements of this vector and +v+ # in conjunction. # def collect2(v) # :yield: e1, e2 Vector.Raise ErrDimensionMismatch if size != v.size (0 .. size - 1).collect do |i| yield @elements[i], v[i] end end #-- # COMPARING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Returns +true+ iff the two vectors have the same elements in the same order. # def ==(other) return false unless Vector === other other.compare_by(@elements) end alias eql? == # # For internal use. # def compare_by(elements) @elements == elements end # # Return a copy of the vector. # def clone Vector.elements(@elements) end # # Return a hash-code for the vector. # def hash @elements.hash end #-- # ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Multiplies the vector by +x+, where +x+ is a number or another vector. # def *(x) case x when Numeric els = @elements.collect{|e| e * x} Vector.elements(els, false) when Matrix Matrix.column_vector(self) * x else s, x = x.coerce(self) s * x end end # # Vector addition. # def +(v) case v when Vector Vector.Raise ErrDimensionMismatch if size != v.size els = collect2(v) { |v1, v2| v1 + v2 } Vector.elements(els, false) when Matrix Matrix.column_vector(self) + v else s, x = v.coerce(self) s + x end end # # Vector subtraction. # def -(v) case v when Vector Vector.Raise ErrDimensionMismatch if size != v.size els = collect2(v) { |v1, v2| v1 - v2 } Vector.elements(els, false) when Matrix Matrix.column_vector(self) - v else s, x = v.coerce(self) s - x end end #-- # VECTOR FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Returns the inner product of this vector with the other. # Vector[4,7].inner_product Vector[10,1] => 47 # def inner_product(v) Vector.Raise ErrDimensionMismatch if size != v.size p = 0 each2(v) { |v1, v2| p += v1 * v2 } p end # # Like Array#collect. # def collect # :yield: e els = @elements.collect { |v| yield v } Vector.elements(els, false) end alias map collect # # Like Vector#collect2, but returns a Vector instead of an Array. # def map2(v) # :yield: e1, e2 els = collect2(v) { |v1, v2| yield v1, v2 } Vector.elements(els, false) end # # Returns the modulus (Pythagorean distance) of the vector. # Vector[5,8,2].r => 9.643650761 # def r v = 0 for e in @elements v += e*e end return Math.sqrt(v) end #-- # CONVERTING #++ # # Creates a single-row matrix from this vector. # def covector Matrix.row_vector(self) end # # Returns the elements of the vector in an array. # def to_a @elements.dup end # # FIXME: describe Vector#coerce. # def coerce(other) case other when Numeric return Scalar.new(other), self else raise TypeError, "#{self.class} can't be coerced into #{other.class}" end end #-- # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #++ # # Overrides Object#to_s # def to_s "Vector[" + @elements.join(", ") + "]" end # # Overrides Object#inspect # def inspect str = "Vector"+@elements.inspect end end # Documentation comments: # - Matrix#coerce and Vector#coerce need to be documented PK|])oŝx86_64-linux/dlconfig.hnu[#ifndef DLCONFIG_H #define DLCONFIG_H #define MAX_ARG 0 #define MAX_CALLBACK 10 #define CALLBACK_TYPES 8 #define USE_DLSTACK #define WITH_TYPE_CHAR #define WITH_TYPE_SHORT #define WITH_TYPE_LONG #define WITH_TYPE_DOUBLE #define WITH_TYPE_FLOAT #define WITH_TYPE_INT #if !defined(HAVE_DLFCN_H) # define HAVE_DLFCN_H #endif #if !defined(HAVE_DLERROR) # define HAVE_DLERROR #endif #endif /* DLCONFIG_H */ PK|] (h@h@x86_64-linux/pty.sonuȯELF>@(9@8 @@%@% h-h- h- Xp -- - @@888$$ % % % Std % % % Ptd###ddQtdRtdh-h- h- GNUf:mlôow u؀<@  <>?BE|qXuU$ J&>  ,z Z_UU) s96rk|v~e, kDF"PP11 .1 "1 \ 0!__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_internrb_ivar_getrb_warnrb_yieldrb_thread_killrb_funcallrb_detach_processrb_f_exec__snprintf_chkrb_exc_new2rb_last_statusrb_iv_set__stack_chk_failrb_waitpidrb_cFilerb_obj_allocrb_io_closefreeruby_xmallocopenptyrb_thread_currentforkreadrb_io_mode_flagsfdopenruby_strduprb_ary_new2rb_ary_storerb_thread_createrb_thread_schedulerb_block_given_prb_gcrb_eRuntimeErrorrb_raisegetenvrb_str_new2rb_ensuregetuidgetpwuidsetsidioctlwritedup2seteuidrb_protectsleep_exitrb_sys_failInit_ptyrb_define_modulerb_define_module_functionrb_define_class_underrb_define_methodlibruby.so.1.8libutil.so.1libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.4GLIBC_2.3.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64 ui 3 ui 3ii ?ti Iui 3h- p- `x- x- / / / /  / ./ 1/ 4/ :0  0 (0 00 80 @0 H0  P0  X0  `0  h0  p0 x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  1 !1 "1 #1 $ 1 %(1 &01 '81 (@1 )H1 *P1 +X1 ,`1 -h1 /p1 0x1 21 31 41 51 61 71 81 91 ;HH HtH5 % hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D%  D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D%  D% D% D% D% D% D% D% D% DH= H H9tH Ht H= H5 H)HHH?HHtH HtfD=U u+UH=z Ht H= d- ]wSHH=QlH[H@S1HH=zH[DS1HH=ZPH[ff.SHHH=H{1H13{[@Hw?UHcILSHպHdH%(H$1HHVH߾H= XHZH5=HH HHH=< ȐJ/M;,Vsm`L59#9?+.^{uR8> `] OqzPl>RbH]w#/4eލ6zH)l~{Q-idVlO;)n04 Et}"zT^MKERy#'ם}UbatozV4TBhVv1_Dqw vIYTJ#-Zz9:_B| ĎcE /* Define number of parens for which we record the beginnings and ends. This affects how much space the `struct re_registers' type takes up. */ #ifndef RE_NREGS #define RE_NREGS 10 #endif #define BYTEWIDTH 8 #define RE_REG_MAX ((1<`@`@8 @ ##h<xO ##00888$$ Std Ptd<<<QtdRtd##p8p8GNU \) _g\m @ !  B2"?? A`@?x`?@0(~@ ????~~ ?@ 0 D$ "/ !"#$%&(+-./0126:=AEIMORTUVWX[_bdfijlortvxyz{}~     !"#%&')+-.0123468:=>?@ACDEFGHIJKLMNOPQRSTVXYZ[]_`bdfhjlmnoqrtvxz{|}~   "#&),048;=?@ABCEIMPUZ]begijlnruxz{|}~ , ,r'fr'f ,! , ,r'fr'fr'fr'f) ,+ ,+ ,r'f- ,BWQr'f- ,r'f/ ,r'fr'fr'f9 ,; ,< , ,r'fW/ ,< ,r'fE}> ,r'f , ,> ,r'f@ ,r'f~ , ,@ ,r'fr'fB , , ,r'fr'f , ,r'famiFK ,K ,M , ,r'fM ,r'fN , , ,r'fr'f , ,r'fr'f ,r'f , ,r'f ,r'f ,r'f ,r'f ,r'f , , , ,r'f#A(t-a- ,- ,/ ,r'f. ,(0 ,xMBr'f ,1 ,r'f ,1 , ,3 , ,2 ,cu:" ,5 ,5 ,i ,m ,m , < ,? ,? ,A ,A ,2QC ,ƒaaÃŃŃǃǃML ,'SO ,O ,Q ,Q ,S ,S ,U ,U ,V ,Ճm ,o ,o ,p ,^ ,LO8p ,_ ,r ,a ,` ,s ,t ,c ,b ,u ,w , , , , , , , , , , ,CE쏐 , , , ,#\ , , , , , ,U믔 , ,ܠ , , , , , , , , , , , , , ,;s͝Ř ,͝Ř , ,Ô ,Ô ,ܠŔ ,?a_ϔ ,є ,є ,Ӕ ,Ӕ ,Ք ,Ք ,ה ,ה ,ٔ , , , , , , , , , , , , , , , , , , , , , , ,NB , , , , , , , ,! ,# ," ,'(% ,$ ,)*PG' ,+-eFe%x26=<\99;;==??AIIKKMMYY ,[Z ,]]_` ,` , , , , , , , , , , , , , , ,kmz_ȍmo$ ,_ȍ& ,_ȍ»y' ,( ,_ȍ) ,+ ,y{{|Ӊ_ȍ|Ӌ_ȍӁ(NS4 ,6 ,7 ,9 ,9 ,; ,µ{q; ,= ,= ,> ,ӋӘ_ȍӛ_ȍZlG_ȍT ,_ȍV ,_ȍV ,_ȍF ,X ,_ȍX ,_ȍG ,H ,Z ,_ȍZ ,_ȍI ,J ,] ,\ ,K ,_ ,.lG_ȍӪ_ȍӭ_ȍ_ȍg ,_ȍg ,_ȍi ,i ,k ,k ,,_ȍޡ_ȍ_ȍv ,_ȍ_ȍw ,x ,_ȍ_ȍ({ ,y ,z ,_ȍ5_ȍ 9{ ,| ,_ȍ,{ ,} ,,{ , ,.{ , ,/{ ,1{ ,1{ ,;r'f  ,_ȍ=r'f_ȍr'f_ȍ%$_ȍ , ,?r'f ,@r'f_ȍ ,_ȍ , ,Ar'f ,8{ , ,Cr'f ,Br'f , ,:{ , , ,Kr'fLr'f_ȍ_ȍ ,Mr'f_ȍ ,Or'f_ȍ ,Or'f_ȍ ,Qr'f_ȍ ,_ȍ ,_ȍK{ ,lk_ȍ_ȍM{ ,O{ ,O{ ,Q{ ,Q{ ,R{ ,[r'f]r'f_ȍ\r'f ,^r'f ,_ȍ_ȍ ,_r'f`r'fh ,_ȍ ,_ȍ ,`r'fk ,br'fj ,_ȍ , ,br'fm ,dr'f , ,| ,q ,ˮו ,lr'fٕ ,lr'f ϵؕ ,_ȍڕ ,_ȍnr'fɑ ,nr'fڕ ,_ȍ\]xʑ ,ܕ ,_ȍqr'fpr'fz ,ʑ ,ܕ ,`ȍ̑ ,ޕ ,`ȍ| ,ǤV̑ ,ޕ ,`ȍ ,`ȍ} ,~ ,`ȍ`ȍ ,󅧭 ,}r'f ,}r'f `ȍ~r'fd , ,`ȍr'f`ȍr'f ,`ȍr'fr'fr'fr'fr'f ,r'fqX , ,r'fr'f , ,r'fr'f `ȍ , `ȍ ,r'f , , , , , , , ,r'fr'f , , , ,r'fr'f , , m{tf A'aZ, F"dSQW ))h y -)@<)K)Z)   i)@ x) ) ))@)   | )kn # ) 4 )@E )H :V )9 9g *8*@7x ,*~;*}7J*} @]   &Y*@| , $h*{ 7H6w*z*zYj*@y6*x{5*w*w 5*@v 4*u*t*t% +@st@##<M^+ro$$6@++qGj+qXiz3#W h y `$P GK*`k#;\##$=## ##)# (LD*]nz#$$ /@ @#Qb)s:K     +$.?P9ar  @  `$"3D Ufw ($,$U$ >#J#!2CTev    & 7 H Y j {       @    `% 6  G X i `"z   4 F`  Xj:+@p | `;#8 `  `0BT f`x `$ `$, >`P##" ""! $ 3!5 bt f!o`F w!nW !n#h y !@m   `!l!k `(j(:L ##4E^`p!k!@j&@!i\!hm"h~!"@gV2"fC"egxT"ee"@d &v"c "b`"b"@a"`"_(9J[0!3"_ `("@^"]l#\ #\}1#@[B#ZU!4S#YF@#d#Y]#u#@X- 2> 2O 1` 1D!0 /L+#-#W[+#V0&>O?&#Vz`n#@U`N&q]&@#T'#S8l& /I{&Z& .k&@&#S#@R&$Q&$P&@0$P &A$@OR$N,c$M .q 0t$M$@L - - , ,!+!+&'$K'@= 'N$J$J_/'>'*$@Ip$HM'@Y)\' )$Gk'(z'+$'C`$P'@'# $G1 %@F''B%E' :S/%D'@'' d@%DuQ%@C&$H+b%Bs%A&%%A%@@%8#''%?(@ 3%>(%>(%@=.(=(@L([(j(y(@+$((0A((@%<R%;c(t    (($ 5 (@)F __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizestd_gc_ndxstd_gc_bufshiftjis_cp932shiftjis_x0212cp932inveuc_to_utf8_2bytesx0212_to_utf8_2byteseuc_to_utf8_1byteeuc_to_utf8_2bytes_msscore_table_A0score_table_F0__stack_chk_failx0212_shiftjisutf8_to_euc_2bytesutf8_to_euc_3bytesutf8_to_euc_2bytes_932utf8_to_euc_3bytes_932utf8_to_euc_3bytes_msutf8_to_euc_2bytes_msz_prev2z_prev1normalization_tablemime_lastchar2mime_lastchar1mimeout_buf_countmimeout_bufmime_patternmime_encodemime_encode_methodmimeout_preserve_spaceinput_code_liststderrfwriteexitstrcmprb_str_resizerb_string_valuefind_inputcode_byfunc__fprintf_chkmallocfreeperrorrealloccheck_bommime_priority_funchex_getcnkf_split_optionsrb_str_newInit_nkfrb_define_modulerb_define_module_functionrb_define_aliasrb_singleton_classrb_define_constrb_str_new2x0212_shiftjis_A2x0212_shiftjis_B0x0212_shiftjis_B1x0212_shiftjis_B2x0212_shiftjis_B3x0212_shiftjis_B4x0212_shiftjis_B5x0212_shiftjis_B7x0212_shiftjis_B8x0212_shiftjis_B9x0212_shiftjis_BAx0212_shiftjis_BBx0212_shiftjis_BCx0212_shiftjis_BDx0212_shiftjis_BEx0212_shiftjis_BFx0212_shiftjis_C0x0212_shiftjis_C1x0212_shiftjis_C2x0212_shiftjis_C3x0212_shiftjis_C4x0212_shiftjis_C5x0212_shiftjis_C6x0212_shiftjis_C7x0212_shiftjis_C8x0212_shiftjis_C9x0212_shiftjis_CAx0212_shiftjis_CBx0212_shiftjis_CCx0212_shiftjis_CDx0212_shiftjis_CEx0212_shiftjis_CFx0212_shiftjis_D0x0212_shiftjis_D1x0212_shiftjis_D2x0212_shiftjis_D3x0212_shiftjis_D4x0212_shiftjis_D5x0212_shiftjis_D7x0212_shiftjis_D8x0212_shiftjis_D9x0212_shiftjis_DCx0212_shiftjis_DDx0212_shiftjis_DEx0212_shiftjis_DFx0212_shiftjis_E0x0212_shiftjis_E1x0212_shiftjis_E2x0212_shiftjis_E3x0212_shiftjis_E4x0212_shiftjis_E5x0212_shiftjis_E6x0212_shiftjis_E7x0212_shiftjis_E8x0212_shiftjis_E9x0212_shiftjis_EAx0212_shiftjis_EBx0212_shiftjis_ECx0212_shiftjis_F3x0212_shiftjis_F4utf8_to_euc_E2_932utf8_to_euc_E3_932utf8_to_euc_E4utf8_to_euc_E5utf8_to_euc_E6utf8_to_euc_E7utf8_to_euc_E8utf8_to_euc_E9utf8_to_euc_EF_msutf8_to_euc_E2_msutf8_to_euc_E3utf8_to_euc_E2utf8_to_euc_EFutf8_to_euc_C2_932utf8_to_euc_C3_932utf8_to_euc_C4utf8_to_euc_C5utf8_to_euc_C7utf8_to_euc_CButf8_to_euc_CEutf8_to_euc_CFutf8_to_euc_D0utf8_to_euc_D1utf8_to_euc_C2_msutf8_to_euc_C3utf8_to_euc_C2utf8_to_euc_EFA4utf8_to_euc_EFA7utf8_to_euc_EFA8utf8_to_euc_EFBCutf8_to_euc_EFBD_msutf8_to_euc_EFBEutf8_to_euc_EFBFutf8_to_euc_EFBDutf8_to_euc_E980utf8_to_euc_E981utf8_to_euc_E982utf8_to_euc_E983utf8_to_euc_E984utf8_to_euc_E985utf8_to_euc_E986utf8_to_euc_E987utf8_to_euc_E988utf8_to_euc_E989utf8_to_euc_E98Autf8_to_euc_E98Butf8_to_euc_E98Cutf8_to_euc_E98Dutf8_to_euc_E98Eutf8_to_euc_E98Futf8_to_euc_E990utf8_to_euc_E991utf8_to_euc_E992utf8_to_euc_E995utf8_to_euc_E996utf8_to_euc_E997utf8_to_euc_E998utf8_to_euc_E999utf8_to_euc_E99Autf8_to_euc_E99Butf8_to_euc_E99Cutf8_to_euc_E99Dutf8_to_euc_E99Eutf8_to_euc_E99Futf8_to_euc_E9A0utf8_to_euc_E9A1utf8_to_euc_E9A2utf8_to_euc_E9A3utf8_to_euc_E9A4utf8_to_euc_E9A5utf8_to_euc_E9A6utf8_to_euc_E9A7utf8_to_euc_E9A8utf8_to_euc_E9A9utf8_to_euc_E9AAutf8_to_euc_E9AButf8_to_euc_E9ACutf8_to_euc_E9ADutf8_to_euc_E9AEutf8_to_euc_E9AFutf8_to_euc_E9B0utf8_to_euc_E9B1utf8_to_euc_E9B3utf8_to_euc_E9B4utf8_to_euc_E9B5utf8_to_euc_E9B6utf8_to_euc_E9B7utf8_to_euc_E9B8utf8_to_euc_E9B9utf8_to_euc_E9BAutf8_to_euc_E9BButf8_to_euc_E9BCutf8_to_euc_E9BDutf8_to_euc_E9BEutf8_to_euc_E880utf8_to_euc_E881utf8_to_euc_E882utf8_to_euc_E883utf8_to_euc_E884utf8_to_euc_E885utf8_to_euc_E886utf8_to_euc_E887utf8_to_euc_E888utf8_to_euc_E889utf8_to_euc_E88Autf8_to_euc_E88Butf8_to_euc_E88Cutf8_to_euc_E88Dutf8_to_euc_E88Eutf8_to_euc_E88Futf8_to_euc_E890utf8_to_euc_E891utf8_to_euc_E892utf8_to_euc_E893utf8_to_euc_E894utf8_to_euc_E895utf8_to_euc_E896utf8_to_euc_E897utf8_to_euc_E898utf8_to_euc_E899utf8_to_euc_E89Autf8_to_euc_E89Butf8_to_euc_E89Cutf8_to_euc_E89Dutf8_to_euc_E89Eutf8_to_euc_E89Futf8_to_euc_E8A0utf8_to_euc_E8A1utf8_to_euc_E8A2utf8_to_euc_E8A3utf8_to_euc_E8A4utf8_to_euc_E8A5utf8_to_euc_E8A6utf8_to_euc_E8A7utf8_to_euc_E8A8utf8_to_euc_E8A9utf8_to_euc_E8AAutf8_to_euc_E8AButf8_to_euc_E8ACutf8_to_euc_E8ADutf8_to_euc_E8AEutf8_to_euc_E8B0utf8_to_euc_E8B1utf8_to_euc_E8B2utf8_to_euc_E8B3utf8_to_euc_E8B4utf8_to_euc_E8B5utf8_to_euc_E8B6utf8_to_euc_E8B7utf8_to_euc_E8B8utf8_to_euc_E8B9utf8_to_euc_E8BAutf8_to_euc_E8BButf8_to_euc_E8BCutf8_to_euc_E8BDutf8_to_euc_E8BEutf8_to_euc_E8BFutf8_to_euc_E780utf8_to_euc_E781utf8_to_euc_E782utf8_to_euc_E783utf8_to_euc_E784utf8_to_euc_E785utf8_to_euc_E786utf8_to_euc_E787utf8_to_euc_E788utf8_to_euc_E789utf8_to_euc_E78Autf8_to_euc_E78Butf8_to_euc_E78Cutf8_to_euc_E78Dutf8_to_euc_E78Eutf8_to_euc_E78Futf8_to_euc_E790utf8_to_euc_E791utf8_to_euc_E792utf8_to_euc_E793utf8_to_euc_E794utf8_to_euc_E795utf8_to_euc_E796utf8_to_euc_E797utf8_to_euc_E798utf8_to_euc_E799utf8_to_euc_E79Autf8_to_euc_E79Butf8_to_euc_E79Cutf8_to_euc_E79Dutf8_to_euc_E79Eutf8_to_euc_E79Futf8_to_euc_E7A0utf8_to_euc_E7A1utf8_to_euc_E7A2utf8_to_euc_E7A3utf8_to_euc_E7A4utf8_to_euc_E7A5utf8_to_euc_E7A6utf8_to_euc_E7A7utf8_to_euc_E7A8utf8_to_euc_E7A9utf8_to_euc_E7AAutf8_to_euc_E7AButf8_to_euc_E7ACutf8_to_euc_E7ADutf8_to_euc_E7AEutf8_to_euc_E7AFutf8_to_euc_E7B0utf8_to_euc_E7B1utf8_to_euc_E7B2utf8_to_euc_E7B3utf8_to_euc_E7B4utf8_to_euc_E7B5utf8_to_euc_E7B6utf8_to_euc_E7B7utf8_to_euc_E7B8utf8_to_euc_E7B9utf8_to_euc_E7BAutf8_to_euc_E7BCutf8_to_euc_E7BDutf8_to_euc_E7BEutf8_to_euc_E7BFutf8_to_euc_E680utf8_to_euc_E681utf8_to_euc_E682utf8_to_euc_E683utf8_to_euc_E684utf8_to_euc_E685utf8_to_euc_E686utf8_to_euc_E687utf8_to_euc_E688utf8_to_euc_E689utf8_to_euc_E68Autf8_to_euc_E68Butf8_to_euc_E68Cutf8_to_euc_E68Dutf8_to_euc_E68Eutf8_to_euc_E68Futf8_to_euc_E690utf8_to_euc_E691utf8_to_euc_E692utf8_to_euc_E693utf8_to_euc_E694utf8_to_euc_E695utf8_to_euc_E696utf8_to_euc_E697utf8_to_euc_E698utf8_to_euc_E699utf8_to_euc_E69Autf8_to_euc_E69Butf8_to_euc_E69Cutf8_to_euc_E69Dutf8_to_euc_E69Eutf8_to_euc_E69Futf8_to_euc_E6A0utf8_to_euc_E6A1utf8_to_euc_E6A2utf8_to_euc_E6A3utf8_to_euc_E6A4utf8_to_euc_E6A5utf8_to_euc_E6A6utf8_to_euc_E6A7utf8_to_euc_E6A8utf8_to_euc_E6A9utf8_to_euc_E6AAutf8_to_euc_E6AButf8_to_euc_E6ACutf8_to_euc_E6ADutf8_to_euc_E6AEutf8_to_euc_E6AFutf8_to_euc_E6B0utf8_to_euc_E6B1utf8_to_euc_E6B2utf8_to_euc_E6B3utf8_to_euc_E6B4utf8_to_euc_E6B5utf8_to_euc_E6B6utf8_to_euc_E6B7utf8_to_euc_E6B8utf8_to_euc_E6B9utf8_to_euc_E6BAutf8_to_euc_E6BButf8_to_euc_E6BCutf8_to_euc_E6BDutf8_to_euc_E6BEutf8_to_euc_E6BFutf8_to_euc_E580utf8_to_euc_E581utf8_to_euc_E582utf8_to_euc_E583utf8_to_euc_E584utf8_to_euc_E585utf8_to_euc_E586utf8_to_euc_E587utf8_to_euc_E588utf8_to_euc_E589utf8_to_euc_E58Autf8_to_euc_E58Butf8_to_euc_E58Cutf8_to_euc_E58Dutf8_to_euc_E58Eutf8_to_euc_E58Futf8_to_euc_E590utf8_to_euc_E591utf8_to_euc_E592utf8_to_euc_E593utf8_to_euc_E594utf8_to_euc_E595utf8_to_euc_E596utf8_to_euc_E597utf8_to_euc_E598utf8_to_euc_E599utf8_to_euc_E59Autf8_to_euc_E59Butf8_to_euc_E59Cutf8_to_euc_E59Dutf8_to_euc_E59Eutf8_to_euc_E59Futf8_to_euc_E5A0utf8_to_euc_E5A1utf8_to_euc_E5A2utf8_to_euc_E5A3utf8_to_euc_E5A4utf8_to_euc_E5A5utf8_to_euc_E5A6utf8_to_euc_E5A7utf8_to_euc_E5A8utf8_to_euc_E5A9utf8_to_euc_E5AAutf8_to_euc_E5AButf8_to_euc_E5ACutf8_to_euc_E5ADutf8_to_euc_E5AEutf8_to_euc_E5AFutf8_to_euc_E5B0utf8_to_euc_E5B1utf8_to_euc_E5B2utf8_to_euc_E5B3utf8_to_euc_E5B4utf8_to_euc_E5B5utf8_to_euc_E5B6utf8_to_euc_E5B7utf8_to_euc_E5B8utf8_to_euc_E5B9utf8_to_euc_E5BAutf8_to_euc_E5BButf8_to_euc_E5BCutf8_to_euc_E5BDutf8_to_euc_E5BEutf8_to_euc_E5BFutf8_to_euc_E4B8utf8_to_euc_E4B9utf8_to_euc_E4BAutf8_to_euc_E4BButf8_to_euc_E4BCutf8_to_euc_E4BDutf8_to_euc_E4BEutf8_to_euc_E4BFutf8_to_euc_E380_932utf8_to_euc_E381utf8_to_euc_E382_932utf8_to_euc_E383utf8_to_euc_E388utf8_to_euc_E38Autf8_to_euc_E38Cutf8_to_euc_E38Dutf8_to_euc_E38Eutf8_to_euc_E38Futf8_to_euc_E380utf8_to_euc_E382utf8_to_euc_E280_932utf8_to_euc_E284utf8_to_euc_E285utf8_to_euc_E286utf8_to_euc_E287utf8_to_euc_E288_932utf8_to_euc_E289utf8_to_euc_E28Autf8_to_euc_E28Cutf8_to_euc_E291utf8_to_euc_E294utf8_to_euc_E295utf8_to_euc_E296utf8_to_euc_E297utf8_to_euc_E298utf8_to_euc_E299utf8_to_euc_E280_msutf8_to_euc_E288utf8_to_euc_E280euc_to_utf8_8FA2euc_to_utf8_8FA6euc_to_utf8_8FA7euc_to_utf8_8FA9euc_to_utf8_8FAAeuc_to_utf8_8FABeuc_to_utf8_8FB0euc_to_utf8_8FB1euc_to_utf8_8FB2euc_to_utf8_8FB3euc_to_utf8_8FB4euc_to_utf8_8FB5euc_to_utf8_8FB6euc_to_utf8_8FB7euc_to_utf8_8FB8euc_to_utf8_8FB9euc_to_utf8_8FBAeuc_to_utf8_8FBBeuc_to_utf8_8FBCeuc_to_utf8_8FBDeuc_to_utf8_8FBEeuc_to_utf8_8FBFeuc_to_utf8_8FC0euc_to_utf8_8FC1euc_to_utf8_8FC2euc_to_utf8_8FC3euc_to_utf8_8FC4euc_to_utf8_8FC5euc_to_utf8_8FC6euc_to_utf8_8FC7euc_to_utf8_8FC8euc_to_utf8_8FC9euc_to_utf8_8FCAeuc_to_utf8_8FCBeuc_to_utf8_8FCCeuc_to_utf8_8FCDeuc_to_utf8_8FCEeuc_to_utf8_8FCFeuc_to_utf8_8FD0euc_to_utf8_8FD1euc_to_utf8_8FD2euc_to_utf8_8FD3euc_to_utf8_8FD4euc_to_utf8_8FD5euc_to_utf8_8FD6euc_to_utf8_8FD7euc_to_utf8_8FD8euc_to_utf8_8FD9euc_to_utf8_8FDAeuc_to_utf8_8FDBeuc_to_utf8_8FDCeuc_to_utf8_8FDDeuc_to_utf8_8FDEeuc_to_utf8_8FDFeuc_to_utf8_8FE0euc_to_utf8_8FE1euc_to_utf8_8FE2euc_to_utf8_8FE3euc_to_utf8_8FE4euc_to_utf8_8FE5euc_to_utf8_8FE6euc_to_utf8_8FE7euc_to_utf8_8FE8euc_to_utf8_8FE9euc_to_utf8_8FEAeuc_to_utf8_8FEBeuc_to_utf8_8FECeuc_to_utf8_8FEDeuc_to_utf8_8FF3euc_to_utf8_8FF4euc_to_utf8_A1_mseuc_to_utf8_A2_mseuc_to_utf8_A3euc_to_utf8_A4euc_to_utf8_A5euc_to_utf8_A6euc_to_utf8_A7euc_to_utf8_A8euc_to_utf8_A9euc_to_utf8_AAeuc_to_utf8_ABeuc_to_utf8_ACeuc_to_utf8_ADeuc_to_utf8_AEeuc_to_utf8_AFeuc_to_utf8_B0euc_to_utf8_B1euc_to_utf8_B2euc_to_utf8_B3euc_to_utf8_B4euc_to_utf8_B5euc_to_utf8_B6euc_to_utf8_B7euc_to_utf8_B8euc_to_utf8_B9euc_to_utf8_BAeuc_to_utf8_BBeuc_to_utf8_BCeuc_to_utf8_BDeuc_to_utf8_BEeuc_to_utf8_BFeuc_to_utf8_C0euc_to_utf8_C1euc_to_utf8_C2euc_to_utf8_C3euc_to_utf8_C4euc_to_utf8_C5euc_to_utf8_C6euc_to_utf8_C7euc_to_utf8_C8euc_to_utf8_C9euc_to_utf8_CAeuc_to_utf8_CBeuc_to_utf8_CCeuc_to_utf8_CDeuc_to_utf8_CEeuc_to_utf8_CFeuc_to_utf8_D0euc_to_utf8_D1euc_to_utf8_D2euc_to_utf8_D3euc_to_utf8_D4euc_to_utf8_D5euc_to_utf8_D6euc_to_utf8_D7euc_to_utf8_D8euc_to_utf8_D9euc_to_utf8_DAeuc_to_utf8_DBeuc_to_utf8_DCeuc_to_utf8_DDeuc_to_utf8_DEeuc_to_utf8_DFeuc_to_utf8_E0euc_to_utf8_E1euc_to_utf8_E2euc_to_utf8_E3euc_to_utf8_E4euc_to_utf8_E5euc_to_utf8_E6euc_to_utf8_E7euc_to_utf8_E8euc_to_utf8_E9euc_to_utf8_EAeuc_to_utf8_EBeuc_to_utf8_ECeuc_to_utf8_EDeuc_to_utf8_EEeuc_to_utf8_EFeuc_to_utf8_F0euc_to_utf8_F1euc_to_utf8_F2euc_to_utf8_F3euc_to_utf8_F4euc_to_utf8_F5euc_to_utf8_F9euc_to_utf8_FAeuc_to_utf8_FBeuc_to_utf8_FC_mseuc_to_utf8_A1euc_to_utf8_A2euc_to_utf8_FClibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.3.4GLIBC_2.4GLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64+ti +ii +ui +#####H##؇##߉####### #(#0#)8#@#.H#P#X#`# h#p#x# ##$#(#+#-##8#=#A##I#$#i#Q#T#]#`#r##  #(#0#8#@# H#P#uX#&`#zh#p#x##D##L##T##c##[##k##v######&# #2(#0#8#@#܇H#P#X#`#h#p#x#######$$0$0B8$0B`$^h$jp$yx$$$$$Ɖ$щ$ $@$ $@$P=$ $@$ $@$P=$!$!$!$! $!($!0$!8$ @$!H$`$͆$0L$$ˆ$0J$$H$`H$0B$r0$@$h$P$ $@$ $@$ $@$ $@$#8##@#%H#&P#'X#)`#+p#/x#0#1#5#6#9#:#=#>#A#C#D#E#F#G#H#I#J#K#L#M#N #O(#P0#Q8#R@#SH#UP#VX#X`#Yp#Zx#[#]#m#n#p#q#|#}#~##########P#X##~##`###h###p###x########8#i#iP#X###8#P#X#B`#H#H`#Hh#J#Jh#Jx#P#Px#P#`#`#`#f0#f#f#i8#i#i#n@#n#n#qH#q#q#P#CX#CP#@#########9###### # # # ######## #(#0#8#@#!H#"P#$h#(p#*x#,#-#.#2#3#4#7#8#<#############$ #%(#'0#*8#,@#0H#1X#2`#7h#:p#>x#A#F#K#U#V#W#Z#]############ #(#0#8#@#H#P#X#`#h#p#x#### ######B#D#G#I#N#R#X#[#`#b#j#l #q(#r0#w@#~H#P#X#`#h#p#x##################### #(#0#8#@#H#P#X#`#h#p#x#####################  # (#0#8#@#%H#'P#*X#/`#1h#7p#8x#<#=#?#L#Q#W#Z#_############ #(#0#8#@#H#P#X#`#h#p#x##################### #(#0#8#@#H#P#X#`#h#p#x##########3#6#<#=#D#E#L#M#Q#R#X#^ #_(#c0#d8#h@#kH#lP#oX#r`#th#vp#xx#y#z#{#######\#^#_#a#c#e#f#i#j#l#r#t #w(#x0#z8#{@#H#P#X#`#h#p#x##########T#W#`#b#d#g#h#k##3#3##:#:#@#@#V#V #] #](#d(#d0#e0#e8#h8#h#-#5#p################### # # #H#H#H#`#`#`#h#h#h#p#p#p#x#x#x##### # # #####o#s#u#y##8#@#H#P#X#`#h#p#x##################### #(#0#8#@#H# P# X#`#h#p#x#####(#)#.#0#6#H#J#O#S#Y#\#a#c#f#g#n#s#u #xP#X####################### #  # (#(#0#0#8#!8#!@#"@#"H#$H#$P#&P#&X#+X#+`#,`#,h#2h#2p#4p#4x#9x#9#;#;#C#C#E#E#K#K#M#M#T#T#U#U#k#k#m#m#o#o#t#t#v#v#y#y#z#z#{#{#|#|#}#}###### # #(#(#0#0#8#8#@#@#H#H#P#P#X#X#`#`#h#h#p# p# x#!x#!#"#"#&#&#)#)#+#+#-#-#.#.#/#/#4#4#8#8#;#;#?#?#B#B#G#G#I#I#N#N#O#O#S#S#Y#Y#\#\#a#a #b #b(#e(#e0#g0#g8#j8#j@#m@#mH#pH#pP#sP#sX#uX#u`#w`#w#|#|#####;######F###v#[# #?(#0#8#}@#H#P#X#@`#h#(p#x#^##A# #######5######$ $($0$8$@$H$P$TX$`$ h$ p$ x$ $ $$$$$$$$$HH#HtH5#%#hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhh%#D%#D% #D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%#D%}#D%u#D%m#DH=#H#H9tH~#Ht H=a#H5Z#H)HHH?HHtH%#HtfD=%#u+UH= #Ht H="9d#]wH#HctJH>#<øf#D ##$LcDVO@McMIM)L5#MGCEE? f.G~ v?w w7π,@Et$[G w :11fwfDVMcHL@LHL)LO#LE@DEDAM2EkkD?aND)ǁ1)1@HDFL@McLHL)LL_#E@Eu=D?aD)ǁ~fDAEDAE.91HcH!A…5"AD " "ED "A9& V"A9D"G "8`DD"E < $" DH `HHЃ!AE=E /?5:"fAɀ "f.tjEtv1?wHH߃]EЃ߃AvcBЃ w "!t"Fރ5wH HӃ t tf"ATUStjL%"A<$"tJuED-H HcЀ<uH <SH"A$([]A\Dt{%"H~"t# !tt[]A\fHq"LR"DP^@H_H HcA$4<A+[]A\%"!M߃]wMH5ɋHc ^P&#v=< >u;H}& DH"H13@uHs}"t1ۉ[]A\@H ތ[]H<A\4%:"f.H5y HcA$[4]A\A@H HcHA$4[<]A\ADu+\ 1[ ]1A\%"fD 10H|H|@tu/@~M~EZ~`~m~6z %/" ~O&/ ~O)/@ %"FуLDGуLD"H"t %t&!tYtuy0uqt%DF߃RvxtuH"H eH9t H IH9u;01N̓vPtFˉ!C$u3 ~.1t@ǃ$$f!tWff.F=w vmG׃veG v]HnA9"/"A.LA"fDD@H9 D9ANANI9u%U"D."@ff.%"fD%"fDAWAVAUATUHSHHL-"L%"dH%(HD$81AAljD$&t.HL$8dH3 %(DHH[]A\A]A^A_HAՉD$#tHAHAՉD$߃XHD$AE1HD$0DvEGIGHI II HDAՉHD$OBI"I9u="FDE)A\$E1H-@"I&IIAfDQEH-"E1DA<,I*D9#AGMcFl=Tf "^"aE~HE1H-z"$< t,."%"ID9#~$A<,i"A,< u1H-5"DDmEH-"AD$HHL(fHH9!<]wTE1~A<,I""D9#DmPl"AE߃] ~#H-"E1DA<,I"D9#""8H-H"EH-9"oH&HAD$Fl%<qE1~#A<,I""D9#lf.AWAVAUATUSHH5"H EHX"HP f.9HBuH"Hcɋ="-"L%"H\"1A$~H+"   п $"H]""HD$A$~,H "Hc  wH&HH҃9}ML-"HcA|@ w7I&Is'Lc"D8"E9<$~ CIA$- „uLs""B"< 1DIDBA$JЀ v"L=-L8 132HHH9""$"H=]ULuoHvL="H""cH='ULuyS"L""#^H=TLuYHL"Hq"""H5TLAuF"L H=}TLHLH"wH5XTL H5MTLѲq H5SL躲Z H5,TL裲C H5TL茲 H5 TLu H5SL^"L"-"H5SL!H5SL H5SLH5eSLܱH5TSLűH5CSL讱H53SL藱HL#"H|"b"H5RLVH5RL?H5RL(H5RLH5RLH5RLtcH5RLаtPH5RL轰tH5RL誰 ,"L"""L"""L"-""La""H5QL4H5QLH5QLͯH5uQL趯H5kQL蟯H5`QL舯tqH5\QLut^H5XQLbtH5RQLOH`Lw"H4"b""H L?"H""iHL"H""?HL"H""H5PL膮t&H5PLstH5}PL`u4" LH5KPL;uQH-8"LH5@PLtH56PLu>" L_"fH5OL׭udH-"LDH5OL赭t&H5OL袭tH5OL菭uH"L0"H5}OL`u[H-]"L("H5OL4tH5OL!uE"L"H53OLukHLH"XH56OLɬt&H5*OL趬tH5 OL裬ub)"LD"H5NLttH5NLauiHL)"HJ"H5NL.tLH5NL"L"tH5DNA@΃7|$H DH tDt:DVDNAw@A 0H LH".@t["=U"HT$Ht$D$L D$2"uD$1t DNAwL$HDDH uH3LH"D$114 DNA Xk DǍD0ЍqHt$Hu=A@WHڲLH";HtLH"%HLH|"Hl"Lb"L"L"L"/"H+L"H"H5cKLu*HL"H""UH53KLƨtH5'KL賨uH(LH"H5KL芨u HLR"Hs"H5JLWu H̷L"H@"LH5J$LH"H ""rfufDHc"5"S9}H"H "[5"H="5"HceH"%"HPHc"H[H" y"HH|$Ht$)HD$HHHxHH91H9փ@lcr@ rq@r_@>HqH9^sQDBADB AjHH9H9V7PHqH9QDBA>vDBA v zHfDr@vE Hqw[H9tn$QDBA>vDBA vHÀ~1HHHf.HfDQt1%Qt1DH9w fDmA?vvLƀv!Jq;LFL9htA8t1Qs1@ HfDHNLff.H "u'Hcp";f"}0P_"H`"Hl"HfDf.x(~P ? у?%<lj % ~?% øf.u 1A8D@1A/vAVAAUIATMUSV~AED A$1[]A\A]A^f.H|$ t$w`u"1H1t⍇@H KHH IHcH>Gt$v\%=u&iD$ 1 ƉD$kHL$ LD$Ut$|$ @@2fD't$1NсaDt$1N?vDt$1p/vf.t$1NсDtkt$1^t$1N?=ft#t$1`vfD1 USH̿"H_"Ã$(u_="tV"wHH/"}"ƒBq"f"(T" fDB"H[]ÐH6","HH[]f="t)"uH""ƒ@u."ݾ"$˾"f.HM"fUSH"tT"u: u5"HX" t H1[]fD 1tHމ[]%" t+ ttH1[]%"=" uH[]" H[] 1H"nN"t %4"@b"P%T"H]""St"[D"H#" "%@<[ff.fHt?Hx"HHufDH8HHtH;z(uHf.1DH="H9=:"t8HHtH8$"u H"H "HDHQ"H B"H@H81Lf.u "u$9="t="Htݽ"uH56"ؽ"t ?HGIG&H"I9A(t H@11HsOA5H"DSHHcH>F?HcGPWt9}8LCHK SsH舧CC[~%=t㍆@ HcGGPWt["tH GHG[f.F?w HcGSPWt[H[HcGGPWt[fHH9CSswHcGGPWt[ff.SGHta~/uF>F|[u `"tH GHG[D~‰%=t_>< -"HcGGPWt[@F>vF|vH[HcCHKPSHSts{HCC[HcCHKPSHSts{跛K CC[HcWHHBGr舤CC["* HcCCPSt[ff.Gte~3t~ui_]HcGGPWt@uC+`"t!H GHGfDcf._]w5HHcGIPWt{AAAAHfD%=t_]1%uHcGGPWDff.fH(|$ t$dH%(HD$1uD%="P"HD$dH3%(pH(tZff=D$!]1G߃]%K" @πٳ"|$@π˳"vfDHT$Ht$ i|$ u|$%=/%D$ -=Ww "H"H "|$@π8"" "|$@π "f" "t<z"۲"|$ f11jft$HL$HT$车t:D$ u"|$"0ff{t$|$HL$HT$ 託뭁]ALk^)H ,"!~+D$ЉT$ ff=u6|$ uD$T$ ʀы|$@πֱ"ϔff.@H|$ t$u,%=""Htt$nEff=F^iG^]HL$HT$ " 4"|$ tNwCL$HQH @HHcHH)HHO"BЅtT$ ׉D$D"|$H7"@"|$DHT$Ht$ 1|$ |$%=%D$ -=Ww³"H["Hv"@΀"}DV" @΀"HD11JfHL$HT$ " ǣ'|$ "|$"]AL1iҼ|$ )у>D@D$R"|$H"ff..";$"AVAUATUSt&P%"H"[]A\A]A^fN"H="DAH"QBCD%"f.AHg"HAă ~=p"2H9"à ~A?="ÑIH1AE1H"à B 3 Et^=uIcAD< tL< tHDH"t0IcAT$HcIDLH)If;HH"I9uA]L~|fʯ"[H]A\A]A^f=I""aH "H"H5"H"H"Ht1H"H"H=3躐[]A\A]A^f.ЉÃt݃_trC߃]=ty?=y"D%"Hc"t=u =R"ή"QH/"]f.=!" E?@D%"H"Ã3~H߫"Hͫ"à ~H"QH"H"H"H"="Hi"AŃ ~=p",H9" ~"BA@PAZ:AL$@wZS?AA@<AZAU@~ZpD ==خ"Lݮ"AD_AD"C A=tRDɃ?DWAAD"AD C =t!Ѓ?A=i" C^"P%P"AA@= "." *IcA\A\$E9~ELAvHc蟍HIAD%8"="uH"H Ѓ _H"H"t p gHH T"E {H"M 1"QSЃ SSXЃ vHXɃv H1ۃwXD%?"^IHAE1H"à ~  tvE=uIcAD< < DHO"IcAT$HcIDLH)I;HH"I9u uIcA\A\$E9~ELAvHc袋HIA%Ѓt  H"E&H"H cЃ H|"t   HR"H D"E H D "@K1҃SH DAL$A/1A+>AUA/1A+ƒ>S/1҃+ƒ>yH"E6 p/1+@ƃ>qH L"AU@DApEЃt tȃ tH"ESAL$E#fLH=,襉H"Ey.EI#fAWE1AVAAUAATUSHL%"Lf.E1HH;t,HC Hk8HtDHЋUЅuMuI@EtMt "tTA~5H[]A\A]A^A_AD$I8AD$AD$ I<$uH[]A\A]A^A_Iw(H[]A\A]A^A_@SH"=~E==Hv"=HމX"H޿[%I"uLHC"H2"==THމ "H1"@Hމ[%"@H"=4Hމɣ"H޿[%"fH"=Hމ"H޿[%"fHމ}"H1[%q"fHg"HV"N,"HH9z"<H1"H1""HH9B"H޿ޢ"Hע"=Hމ"H޿" fDH"u[H"z5h"$H՜H9"H1U"H1J"Hމ="*Hމ-" "HH9a"3H޿"/=ޥ"UH+H9,"tVH޿̡"H"=-Hމ"H޿""T [f.Hw"=HމY"H޿K"=fDH5!*fH5 f.Hމ"Hމ""[@"[@D "EHH9"tH޿"1҉E|"D1x"AŃ1X"Aă1="AŃADD =v"DfЉŃ(w/1"D$d$1Ɠ" D$="݉|$ D "E="}Hf" @Dމ"H="D$ x|$  =Y=" HUۖ"H,"@;-fD=D-"ED%"E1"Ã?="* -|"L-"A%AD=EY"E%AD?1?"="J ."AD-_AAu‰H"HH9t]H"Hޑ"H5ߟ=ؐ"H"H"H5"u*H"H3H"HeH^"Hg"D"E-"Hq"1f.1X"ljD$ AD$ DD t"6"1|$ Dr"E ɔ"-Ŕ" -6"1" ( G1"H"t  1ǻ ҿ 1j"=ؒ"wH"H8Ht HfDp 9r HLH8H:uH8\{="D =v"."@"H"=DA=8"AŁ \$ "H4"H8uHHx t J 9H HLH8H8uX=Ƒ"Éa"H?"f.="08-v"1"1 q" W@Hю"HHÎ"HH"H"H"H"XH"H]H"HHP"Hi"Hb"H3"2H7L h"H"="G1%"=" -1"Ã:@ (‘"11)"$1"1"H"f="="t "HH΍"p"H\uH9=ɏ"1f1A"3"4="t  "HuHS""O=V"DE=A"A ܋\$D E="A ݋\$D 1"Ã$)1n"@v AbȺ$I )Ѝ))HHcD$PZ41J"1"uB"11=3"=("1 H5I11"€ ?q="ý=11"1Q"HR"11"="C"h11g"1(Z"=p"1"Ã@DIO P1"$1"(1"1"H"81 s"Ht"H$ HHƒ߃A7PЃ +Ã=H,"?#1ЉË"P%A\H""Aiڃ߃BC6"B1ЉËʍ"P%A\H""A?DHY"H9Ћ"=P"t D"H-H"0"X"H"""1"1L"=b"HJH+"H=3 9"+"=h"H"H "HIH81lH"0"Ho"͊"HQ"H""HH=?HD${ HSEE1AHl$IA1"BDPHA7C9IAN<+A? wABD+HD"1"J4H"H"}J<kHt` ߃="BHw"H@H9t]Hd"HU"H5V=O"H "H"H52"u*H"HH"HHՆ"Hކ"܊"A*H5"DIcDXEFEDGLLHI1McHtRItEK8Nu2 H:LuHcH9uD9u D9tHIA몹A1H]J"AEL$Hu1H"L9u(HF1="H"H-"H9DV"E-"11 (0"P(H""^"O(H"">"D(H}"ۇ"-\"-:"H"L-\"J J"9"7"t!HAT5u"D%"1`+ "t`=u ?+t=t߃AvHЃ w)JÉ "AD1""u"JADHq"H: d" b"H9H F"H5G=@"H"H2"H "H5"u*H"HH"HH "Hȃ"H=13"E1E1AfH"D%"AD=HwH9IIQ"QHJH9}=΅"t1-f""1HH9H>"XHHt$~H|$g"*fHD$="HPH@HO"="u=""\"M" B"uH" :u H@ H=Hָt׹H=1Hָt H= HָtH=lHָ sH=rHHHHAWAVIAUAHATIUHSH҉D9HADxAōPA v<v7@wHAAč@AL$ vv AT$wjA]9T$ HAԋT$ Ač@Ѓ AL$vD߃Aw4A wFD w[ H[]A\A]A^A_HDADHDAHDA@Auq1ۃwA]AD$wA7D DwAWD fH U"HV"H%dH E"HF"H:dATUSHdH%(H$1taH_1111I.fD<'Hc<t*Huԅt@Hc41uօ1H$dH3<%(H[]A\Ð<\t,t8<"tdHcʃ 1zfe@<'t<"t`< tjHcʉ Cf5@1(RfDHcH聞6@HcL[ 1aH(Ht$H$H|$aHD$Hx1aHێ" "aH$1HPH@t@ Hˎ"Hc"Mb=B}""HPH"HD$H@H"w"u=ׁ"|" HE"HcN"HHHPu&HtH$uHt HH H(SH=aHH5lHHAaH߹HbH5O&aHH7H5; aH/H5/H`HaHH5H`HߺH5SaHߺH5?aHߺH5+aHߺH5aHߺ H5aHߺ H5`Hߺ H5`Hߺ H5`HߺH5`HߺH5s`H5hH`H=ao_H5rHHm`H=VQ_H5PHHO`H=J3_HH5F[H0`HH0123456789ABCDEF>"<&ic=ISO-2022-JPX-ISO2022JP-CP932CP50220CP50221CP50222ISO-2022-JP-1ISO-2022-JP-3SHIFT_JISWINDOWS-31JCSWINDOWS31JMS932EUCJPEUC-JPCP51932EUC-JP-MSEUCJP-MSEUCJPMSEUC-JP-ASCIIEUCJP-ASCIISHIFT_JISX0213SHIFT_JIS-2004EUC-JISX0213EUC-JIS-2004UTF-8UTF-8NUTF-8-BOMUTF8-MACUTF-8-MACUTF-16UTF-16BEUTF-16BE-BOMUTF-16LEUTF-16LE-BOMUTF-32UTF-32BEUTF-32BE-BOMUTF-32LEUTF-32LE-BOMoc=cap-inputurl-inputnumchar-inputno-outputdebugno-cp932cp932invx0212no-cp932extno-best-fit-charsfb-skipfb-htmlfb-xmlfb-javafb-perlfb-subcharfb-subchar=ms-ucs-maputf8mac-inputprefix=%s can't malloccan't reallocShift_JISNKFnkfguess1guess2guessAUTOEUCSJISBINARYNOCONVUTF8UTF16UTF32UNKNOWN2.0.8 (2008-11-08)2.0.8NKF_VERSION2008-11-08NKF_RELEASE_DATE=?EUC-JP?B?=?SHIFT_JIS?B?=?ISO-8859-1?Q?=?ISO-8859-1?B?=?ISO-2022-JP?B?=?ISO-2022-JP?Q?=?UTF-8?B?=?UTF-8?Q?=?US-ASCII?Q?base64jMBeuceuc-inputfjjmhelpmacsLmmimejMmime-inputmsdossLwsjissjis-inputunixeLuversionwindowsh1katakanah2katakana-hiraganah3utf8utf16w16utf8-inputWutf16-inputW16nkf internal module connection failure. dhpP8x`8 șzȘpH0x`ܷ\4ܶTԼ/"9"B"I"Q"["k"q"z"}"!#/#:#@#[#`#{#~#t$~$w%~%9&@&Y&~&B'P'r'~'A(~(TO~O%t~t !!()))*+++2222<<FF ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/BBQBBQBQQ  @,.:;?!'`^_-/\|`'""()[]{}<>+-=<>$%#&*@%Q%T%W%Z%]%t%,%.%0%2%4%6%8%:%<%>%@%B%E%G%I%P%S%V%Y%\!!!#!V!W!"!&%r%!%#%%%'%)%c%e%g%C!<%"%$%&%(%*%+%-%/%1%3%5%7%9%;%=%?%A%D%F%H%J%K%L%M%N%O%R%U%X%[%^%_%`%a%b%d%f%h%i%j%k%l%m%o%s!+!,LMNOPQRSVWXYZbj|CDPX^npru|}~BIK@ABCDEFGHIJKJFHGACDE@e^_]`\xyz{sqtvoegihjklm]_`adbcfYZ[\MNOQRTSVWUJKL@ABEHFIGdcfgw{}~porqasvwutzxyhiklmnCP`Ustuvwxyz{|}~!"#$%&'(L"C)*+,-h"c_ix!;.-|P?t)H/RTcn'#,)>_XHWcta#0;fmu|15X[en{23@GP^4*5/Dh6Bdhg789Nauwx|/7>[*a:k38;J<=P^tuydm~>Bg?p0,@3=MId(IDdt&Au|Bx+!%C8:DDRW[^mpE!5I9FX~GLHYj}I'56JU8W`jc!+GCKOYKLfn|kp1ex&+-MJSic|tuN3=oq.OJfjptn%y+.-2BPYP;Q;R:CSr]UbimTUVWeXihYZl;[ah'\]Tr.^^_"7AQtFHQ`abcdSHTjz$0e5Kf9gChiYjkblmnG(&)/0*+o@G?`^Qp\R[Tzo3?IPbjkqrsho,t.u1v216wx]yzQ{mM|[fj%{z}V~\]^_`abcdefghijklmnopqrstuvwxyz{|}~@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@ABCDEFGHIJK@ABCDEFGHIʁUVWTUVWXYZ[\]ʁ@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~;AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBCCCCCCDDDDDDEEEEEEEEEEEEEEEEEEEEEEEEFGGGGGGGHHHHHHIIIIIIIIIIIIIIIIJKKKKKLLLLLLLMMMNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOPPRRRRRRRRRSSSSSSSSSTTTTTTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUVVWWWWWWXXYYYYYYYYZZZZZZ`aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbccccccddddddeeeeeeeeeeeeeeeeeeeeeeeefggggggghhhhhhhiiiiiiiiiiiiiiijjkkkkklllllllmmmnnnnnnnnoooooooooooooooooooooooooooooopprrrrrrrrrssssssssstttttttuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvwwwwwwwxxyyyyyyyyyzzzzzzq!r!L"1!Co!@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_.!a#b#c#d#e#f#g#h#i#j#k#l#m#n#o#p#q#r#s#t#u#v#w#x#y#z#P!C!Q!A!!"#$%&'()*+,-./0123456789:;<=>?.!a#b#c#d#e#f#g#h#i#j#k#l#m#n#o#p#q#r#s#t#u#v#w#x#y#z#P!C!Q!7!"#$%&'()*+,-./0123456789:;<=>?*!*t!p!s!u!)J!K!v!\!$!]!%!?!0#1#2#3#4#5#6#7#8#9#'!(!c!a!d!)!w!A#B#C#D#E#F#G#H#I#J#K#L#M#N#O#P#Q#R#S#T#U#V#W#X#Y#Z#N!@!O!0!2!478=DGHNOSUVWXZ[^`bceijkmopswxy}rE6NXYZ[\|s]^}sTc_~s`abc?@ABCDns7cZlmposEpsFGHIJKLrssstspNqsusvsMNxswsOPQRSzsTU{sysVW#$gshs%$E&'()]8*js+,-./0MAks1234ls56789:;!I<=ms>+2qrsTsP5UsVsWs~u9XstT`[LcBYs[sZsu\sv]sw^sxyz_s{|}`s~asbs!csdsesfs"\Fs]^_`aGsHsIsbcLsJs?9s@ABCDsIIOJK;skBm:?sL#$%)s(s&'(\7)*+,-.-s/.s/s0*s12tr30saD44s55s3s67zrnowrl}rp~rq%s$srs&s-1!s"stt99Lvu#swxyz2K+s{'s|},s~!"^prqr>Fnrmr]*2_yrxr`au1bcdvrursr{3rr2<)2efghijc9km|r{r;DYjr7HorkrlrZ1KDLPF[\<=>?crar-C@ABCDpKEFGZNHerIPJKLfrMgrRNOQSTUVhrWirX%&ZrVrWrSrYr'Urb3(LO)XrTrRrQr*+,-\r./_r01^r]r23456II[rs0`r7br89:o3Mr71;drArnDropq8BrqErrFrGrKr*;stdBuvLrIrHrJrwx_7yz{PrOrNr|30}~!"#$R9rSTUVWXYZ>0[\:r+J8r];rrab?rcnK-;dz:/Aefg@rhiCrjklm!32:1r0r%L:;<3r4r2r5rbK=>?6r{5@ABCDEFGHIJK%O|L7rMNOPQ{|}~!""r#$%&'()*+#r,$r-.%r/&r'r(r0)r*r+r,r12-r.r5]/r345678xd459oqbcq?defpqgqqhrqsqijkb9{lmtquqnvqwqopxqqr1Hzqs&I{qyq}qtu|qv~qwx!ryz|9VWlqXYmqZ[\]<3^_nq`a^qL]q_qM\qKNOPbqQRSaqTdqC6cqUeqfqhqgqiqkqjqUq789Wq:;35Vq<={A38>Yq?@ABCDMBZqEF-FGHI[qJ`q}G%LBX1n6o6&sCNqp6'(o2Mq)*Kq+Lq,JqXq-./0OqPq1QqRq23Tq4Sq56Y=s3OGGqHq{|}ZCkF~!"Iq#$hi;q=qjklq@qAqoCqB6pqrstuvP-q_LQR.q\MB1A;S/qn20qTUV1qWXY3q4qZ6q2q[5q\][4^7q8q_`abcdefg9q:qD)q(qE*qFGtHLf)?H25IJKL+qM,q,R;]SH{0N;0Ot;0K~>wI$q:;<%q=&q>'q?@ABC*yp+,{pjB[3\3zp-./i42801j423?E`N4567\88|p9}p~p!q#q"qGJ:D":`9g=s\?tspvwrpBMh4RH\Fxy|?NNu[7z{|vp}up(~!KK,F"#$%&P1'wptpQIjMxp)XgpYZhp[ip\]jp^_`abZ4cdefjkpghikllp#Gmnnp;2oqppppqr$1A6B[ps3Yp]pC^pH0_p`pDEFd>GHapIJG5KdpcpbpqkL\JMNOepfpPQRSTUVW-Np.KpLpMpOp/u01vD@2wL34E@56PpsHQpSsLL7RpSp8TpW39VpY?:Wp;$7<=>Xp\p?Zp@A{<~!p#nN9p@pBpAp?pCpDp$%zA&b2'()Ep8L*FpGp+*O,1[HptIpJp}?g4:Mm28=[85pr4ps;6p3p(;s:p-juVRvw?8pwxy%NqF+1zc@6<{7J|@1mNkM;p}EE`abcy64N(7dbB!g&p,3o?eV3(pf)p'pd7g]:c>hi#1YNjkl+p.nm*pno.p,p-pp/p0plN1p2pqI@;HKBSxomI{oyo_9zoB8TUVWXEJ}o!p~o"pY!1X?|=Y4#pfG%pZ"1$pDD[MN+F|o&N18\][M^_lIDEtoFGHIuoe:JvowoKIKLMNOPKAQR$0jo4G056ho7loko89:;nomooo.F<=po>?@AqosoBroCgLYo.A"Zo#DJ[o+3$%&<1W4qV4\o]o^o_o'()`o*X4U3^96H+boao,-.co\1/0fo1eodo2go39D}~!Wo|{GoiIojklmU4HozLnoToJopMoqKorLostNouvwxPoyzQoRoUoSoVoXoTU?oV@oWXYZ[Ao>o=o\]^b>*F?@:oABCDE9o-EF2o3o6oGH8oIJ@6K;o5oLM4oOPNQRS$%&'()y3*+,0o-?:yA.JD/01234;35;6.o/oCD-o7891o:}nhijiFUEklmWDn,oopqCC(or)ostuvw-7x+oyz{|}08~!*o"a>#ST,;UV{nm?WXYn?!o#oZ[\]{>^"o$o_`S6aEIbcb<#O~nx:?Ode&ofg%o'o23456789:;<=wn>/K?@ABCDEFGHI{=JKLzn_JMT1NOFIrCx5P|nQ]9Rd6F=ijklmn[9opqrstuvHKw89:;<=>?@_FC3AgnBCdnfnDEFGbnHIJKLOoenMNOPkNQRZ8STUVWonVnWn!"#PHS:aqrRnPnstuQnvwxyTnSnzz>Un{|}~STUSFDn6=`<[GqCVr?An@ABCEFDGH"EIJCnKBnLMNOPQRj0~!"#$Y9|:O-%&'(>n)*l+47;n?VJ@imAkmBCjm`2DvFlmwG3EEmmR=FomGHBL~mqmrmIIDJI?cm--EDm]Gmd^_`a4mPQRS?m+,zl}D!m%m"m~l-#m./0$m1+m&m2345X@(m67*m'm89:;<=-m3=,m>?@.mtuvwsltlYMx'Fxlyz{vlwlyl|}~!"#)m|l$%}l{l&'()*^el_`abcmlkldhlefgjlhiilllw5plW@qljklY8nlolm)Onpq7Dr)ArlsulclKL6DM[1NOPQdlRSTq<Uv?VWXY-BZ[\gl]oflV@FO<_lGR3H`lIvAalblkIh/5J@ASlTlVl#BBUlf4XlWlYlC[l]l^lDEl2Ll(OBDEO,-q;Kl.1B/\l(A0xFPI213Ol?;r;4^>eG5-8NlMljI6A<7RE89:g;<=QlRlX9Pl>?:ll?l#$%@lBl&'(-3gDiIb:W9)OI_2NHElS4U@DlIlyCcLGlHl.5JlcG_B*+qH=EFlGK/lf&Fg1lh-Ki2l3lj4lklm5lnorZFpq]>6lstuvwk9.P7lxyz{8l?I9l|Al}+Cbc.lde0l&lW>;XYNZZ'l[(l\2=)l*l]^+l,l-l_`avkDEFGHIzkwkNykxkJKL{k1$lRn8STU%lVfEKZ1b0%F89ik?:hkfFmk;bklknk,8jkV9okXMrkuksk5I@ApkB`6Ctk[k%Yk&LC'()A@R4Zk[?*JN+,-@O.\kgk5D/fk0ckkkdk`k|D_k]k1!Mp;2ak^k345ekt=A86zB7oPkpQkOkqX8@Mro;'GstTku@@BCvw6MxWkl8y?@SkXkm8UkVkzRk{b@IF|}/C]2~!"pH#C5$4DWFkXYIkZJk[\]>:BBHk^[>>I_`aGkbcl;S1dNkX7en;fm;MOMkLk'AM5CO:3\>ghijklKkmn@8{D>kCDEW7V?Ak$FF@kGH17IJ?kwB-5BkCkKY>LMm7NDkO,KPQ_@Rv5uLJASEkTG?pCZ>UV7kQ3456788k9k:kr29(?;k:;<=>@UhjmjV#JojnjWXYl3+KpjZ[\]^_|jrj`sjabctjujdefgyjzjhixjjD[:vNajbjuAEFGHI"NJKLcj5MdjejMdJfjN@:#NOkjPQRljX>jjSTgMgjij=@~?8OjVj67^B\jXj5BWj9Zj:;<Qj=>[j]j?@oHYj^j`jS8TjA0ABC_jl7#Ij$Hj%0=&'()T9'^*+JjQ=,-93.Kj/R10W>Lj12U9Mja03=I4Njj?5UjRjoC67SjPj^6hi$jjdklm8jjpqr@j?jsotuvwxBjAjZiFjyz{|Cj}~DjEj!Gj"+jR/j2j1jSTU)jV,j=jWXYZ[\6j]^_`ab4jc5jd:j;je*3fB59jg'j89:;<=>?@;MABCDEFG&jH%jIJ.jKLM(jN0jOfM3j*jPQ+,-f@9Oxi.yi!j*?{i/~i0viui1"j23\2|i#j}i456zi3Dwi7hGfi*KgiqrdiseijimitkiuvwiicixyXCzti*L{|}~ri!si"#$%nipi&'qi()*oi_`aVibWiX<YiACV7B3cd\ief?3gaih]i`iij:Hkl^i_iHIZHbi}Blinhiopk2mc2RiSiLMNi=;NOPQROiBGSTUPiQi[iVUiXiWXYZTi[\]^6f78HiW8T59:Ji]Q;<=>u5:N?s6Ki@ABCDLiEnCFGMiHIJzFK:0""i#$CiIA>i@i%&'()?i1]"]*+Ei,-.Di/0vMI<#i>6BCDEF$iGyI}hHVhIJKLMNO|hPOO"FsIQ+iR1iSTUV2iWC<-.Qh/012NJ"Lyhxhthuh6134whqh5678UD9:;vh~0<)=>"B?CJ@xmhy_Cnhz{VMch83|ih}lh,L~ohhhkh!"#)K!O$%&'sh(*+zh,rhh\hWhiU>/=jk,ehujhsAvwfhO^hPQUMRS*NTUVWxCXYZk3[\rIdh!F]^10_]h`YhrASh[h`ha,Gbc*0dXheahxIfgEDh:FFIhGFh(KLh`0HI@hJKNhMhkGTh_hM~3bhPhNUhnM6Gh{?78F5]6Bh9:;[2<T>EhZ:=QEJh?nJ@AhZ2V8)IKh?hAHhBCRhDCh#$%.h&6h=h7h'5h(vg)*3h+,/h-./P41hh20h|G3LiM9hOh45&hstu)hvpAU7wxA1(hyS9>cz{|qA_}:h;hY2~.28h!"]^PLwgX2}3{g_`}gabT7#h,h-hd+0efghi4hq0+hjkl*hm%h$hn"h!hcCo{B'hpqr#4NOq1rgjN]BPDI~gQW2|gzgqgRogSpgTc?@)320ABCDkgngNGED?FV2G'KHI]7\6JmgKj2LMYg{|}~zD!"#$%[gZg]g&\g^g'`g(_gO4)agbgcg*1:INeg'?+p1fggg,-hg.mMgNgnOgPg=6*ZQge@RgKgVW22Eg@gXUAgYZBg!B[\DgCgFg]^_GgHg`C?ai2IgWN+)g*g?@Ap<B(gCx9'g+gD2D"J#A\Bi;(<6H@FO.LwfT@)*+,S5zf-./|f01{f2}f3&C>G41D56#g_0tf@CtXGu[Bvwxyvfz{rfufpfsf&K|U8}0qf}~xf!yf"#9F$;6%&&g=G'jgfifhf%HkyF>O)HlkfS>*IlfjfmN4nT8h;nHop*8CKqofmfN9O9i0h:rsYGbcYfXfZf;@[f\f9J]fdoA^fef_fg~Nbfhaf`f0Dicf&?dfef8OffTM7OM9NfTHf?Ife4@ABM4CJfKfD]KcMEFG%0f2feM1f4f3fSM&5f'~H()*6f+,9f-8f7f./:f270"AA512>f;fe[6lH./0mAPNo=ne]1He2~@DeIeKeyDNe4Je56TJK478KL9^0:Me}N;<=>Lerstuvw5exyz7e{4e|}Q73B9enA~!Fe\BeC?e=0JL^_*=>8HA%e+e`a&eP7b.e2ek7cd-eefg6ehiJ9mM<03ejk5k0el1em}E/e,e(3d@n(8op8eq*5!eKsLH9~dLMN$efL0:[\])eqdsd:rd;<=R8>8A?ud@AB|ECtdDEvdF5JlAG9wdGHNHIydzd{dJ|de;}dO7j5N6)7cd,-4Jh?0L.dd3N/tGFA4GM=0@01idgded!42Q>jdhdfdnd3mdldkd45od678pd:@9ZdWdstVdR@Yd[dvwxXdu_d\dyz{|}~]dFd!"^d`d#$ad%&'(FJbd)*+bLGd\]^_`HdabcMddeBdURIdCdLdfgRdhJ4OdijPdkQdTdlmnopSdvHqrUd|NmJa@;dHOHI?dSJJ[CK:d}@?@"HA>dBC$HDEFG%&&d.I'&HyEZ6%d#d(5H~c^C{EzE)v:8d*+(d,*d-.-d/.d0+d,d12)d'd3!dsc"dvcsh5uc$dtcP>txcyc+Ezcu^3vZ?dIw|cxyzhB{|}~!wc"{c}c{:#$v3bcacdec^cefc)NfgcghchtTjcickclci5NmcopO>ncocW=8FpcYjk(ClmqcKLScMO3NUcj7Of5PVcu6WcQ|@)5*+,Cc-.xD/DcG@0-L1#IEcFcUC2GN3HcGc4567o<89Jcp0:;Mc<=>KcT2N7LcF9(=d;tuvw=cx)=yJ2CIz>c{kH|}~EA!Ac"BciG#A??caC$%@c&N>'(\0)IcX6=O5A4cabR2wD!Jcdefghij5ckz56clm8cn9co)Gp:cqr;cY<%c=CA>'c&c(c?@ABCDhbEFjb*c)cGTHIJ(efghijk2NE9l'8#Hmbmobn=:NOPfbQRSgb&8U:TibUVWVEV:N5XYZ$KKG[\WE\9<^b=_b>?@`bAab7LbbBCDpLcbENCFjGk6GH;Cdb:6IJP@KLMeb+,Sb-.RbTb/012Vb3Ub4MJ56V=FN78Wb97F:XbYb]b[b\b;ZbeCpqrIbstuvwxyJbMbz{|}g?~DF!NbSK"Kb#Lb$%&'(Qb)*PbObZJ>@b[?b>b}H\G4)8]^_`abcFbdCb??2LeBbDbEbfAbghijklGbHbm/Dc4noI3bVGJ_KN1KW1LM4bN6bO5bpEP9@9]7bALQ8bF4WH9bR:bS;bT\LUVUL>DWjAX=bYb=%b5Q&b*E6'3D9'b(b78)b);+b9*b,b-b:;?@ABCDEFGiH.b/bis0b1b2bH.;$%EN&'(tarasa)#*b4~L+JJva,ua-waxa./|ayaza{a}a012~a3!b4"b#b/HPE$brG4Icaadefghhaifajgaklmnopqrstiakalamaunavwjaxypaz{oa|}~!qa"PQPaRaRBISI>YaTXaUVZa&?NVaTa@aVHAaBa;[0<v>GaDamFCa=>?@AB&5P,a+a-a~.a0a/ay9!2a1a"#E4S??l`@o`j8M1q`Ap?n`\NBt`$tCDEr`u`FGHg`s`IJ<:v`w`"#e5$f`}M%0N&'()vB*h`+,-./012345j`VNW6|HJG6k`m`a`Q2hi]`j9;klAD_`mnopqrd`n7IHc`~`xyzi`{|}~=8!MNO<8PQ(NL6&2RSTUj6VWXYZ[\]^a4_`ahN^`bcd``efg8v9b;9R`S`:;?@AC=BCW`DV`EFGHX`IM3Z`JY`K\`[`L"#$%I`&'()K`H`*+TLJ`L`,DN-.P`/0O`vC-G1%8N`23M`41M2M567Q`n1r86=`?`>`stu@`Q8A`vwi6x@A}9yC`D`B`zm<HF96{|F`,CE`}~5ObG!T:5`4`f6`ghi7`j8`k>59`:`l$8mnHHo<`pu>;`q.`MNOP/`RJGH0`WGQRS-DTUV1`g2Wm5XFLY6LZ424O[RK\*J]^_`7@2`abCFcd#83`e>zG?@A#`$`BCD%`EFG&`^DH(`'`I)`*`J_!QHl_Q<"z@bcdefa_ghik1d_2Jc_jk5LG>lmnop3AqF>uNX^_(1YZ[\]^`____]_`X_#Kab_IJK'Of?j1V_LMNOPU_QRSY_:C\_W_TU[_VWZ_@EY0.789:;gF?@T_BCP2DEtE%3FGd5^_<_?_!B_";_j9(G9^#$tM=_A_uB%@_+_&io'E_()I_(_'_-_c!@$_defgh0_i1_jklmB4nop6_5_7_qrst:_uvwCE4_xy8_zs^C4TUVWi7X/_YZ*_x@[\c3]^a=3__`,_,D)_YDL_&_%_._aby5:IA?<Bw9CDE3Ot^"_i1fAFGHIyGA4zNJKL!LRDSMN{^}^OP2AQR!_y^23q^4k^GL56f^7"<~^89:j3h^m^n^lBZB;v^<=|^z^)E#_w^>?@x^`^~Kc^.H'o^;8(`=e^)/NB9r^*n0p^+d^,-j^.l^/OMg^.E0i^1\^qrst+LuZ^^^vwxyzP8{E>9C|}~T^!"/M#W^P^rES^$Y^%&QO>=^B=L7<^R^m=:8a^i[^t5OEjV^_^/021k92X^,BO^Q^A9lmb^n]^opU^dMUH^B^?^VWTNE^XYJ=G^L^ZqEJ^[\D^]^8C_K^`@^F^aM^|0C^N^bc0M7^HI2^J8^KLM^NsEBFNO63U1P>^QA^RCNST.Nt>u@=6^4^MI>?@1^3^A:1B@92O=3bICDaM$3;?5^E+,-NM0^./0/^1v@,^2lM6F&^ED345L1?9)^789'=.^-^(^+^:h3;*^IG<76vu]z]wt@qGgHxyz{|w]}!K~y]$^!"^"{]#"KHGc5%E$mC%%^&'(#^YBv])K1*n]k]`Mijk@DlYFl]t]s]#7mn-2op;:m]o]qrWKtBwK|]s}]tO2u(J}L!^#x]~]h1uDA=a5XYZFH[.<\]h]@4^x1_`rFg]>9SCi]6q]j]abcABb5r]defgh7h%5p]CDEa]FGHa;I1LJb]c]$5Kd]Lf]e]MNOPQRe?ST9IJ1UVEHWLT45#5X]6Y]7lJhKGFZ]fH8{H9SL[]:;<=]]\]>_]?^]@ABH]"J]I]#XK^=l]rN2s7C?]t?4A]uv@]B]wC]xD]_;5@!:pIybJDOz{u;|P:rN}E]F]`;~!G]]^sM0]_`a^\bcd3]4]ef51g6]g7!<U6h$2ijkl_Mmn8]7]:]=5oV6>4pj\%]$]KMLNO*]&OPQR-]{6ST)]+]JUV'H.]WXYZ2]/][\IC78|\9:;<z\i8y\=!]>X[?@A{\}\~\B,]C(]m[DEF']G&]#]HIJm\&'r\v\()66*+,-./L5t\0!5KFs\1u\23I4o\5q\6`3rs[\tb\h\uHn\uvi\l\f\wtC8Ix\\yd\@>zOLx\k\{|"8#2_3S\}~!A>p\"w\y\?AG5\B\A\oF@\jFHIJKLMD\7\NH6:\]=OPQ`G<\K64\6\3\RS0OZ39\TPOv[&\X05x[67:L}["?GDs[89%\:;<z?/\q3!81\z[0\)\{[-\.\?\=>NF?$\@;\A=\XD~4{2\|ILw[}4}~[~!"@K#!\#\$'\y[%*C&'oE+\|[(\("\)*+,-9?,\./3@01*\=4234BNkl[l_Gmnt[g[40i[o<9pqk[rj[f[q[s?>tumTh8|Mvwh[xtD#3-:y`[p[a3n[r[znE\[e7K7mEXYZ[F0Z[][_[M6,7I<4K5\]^b[_y:qK7;c[0I`abcdeo[f32d[ghiju[e[FNDJFI1r@J4@*7KLY[M;9|3ON[[t3a[PQRST^[Us@K3,:VJ3O:W9HB:;AJ"IU[pG?K;4?w@@=@SDA.MBQ[P[CR[O[DW[M[K[S[I[ElCFxLF[D[C[)*O@+,mK-SN./gK0L2^;HOF[u?E[@[O8123L[J[4M2H[N[T[5675[x8[yzy?{{MI0`:;[NE~9[+B:[r>]L<[=[hM!B[":9#UG?[lE^ZbZ$O5%GG&A[>>DHG:rPnon7-M~J~Ip,[qs:?D-[/Or>Ks+D.[|4tu/[0[ZL$LvK\K%;2[k<vQK4[7[6[y4`5w3[_zZ`a![^Fb|Zcdef#[l=$[gKMxGh%['[i([jkl)[J6H199*[+[q=bAm?XR>A=AXBKG6sZwZK2tZvZMNOuZPk=QHCE0xZRSTUyZVW*DXqNC;YkJZ[=K\"[{Z]~Z}Z^1jZ~;89hZ23iZ48?57gZ6/;89:;qZmZC"3nZoZUH@ABaIJ7rZD2@E=>GHIRCJLCFu79`Zv+::>wx_Z;>y@L*:z{W0N@|}fZ~!1@G1"#$%U=&fKr:'()*<>+'@,-.eZcZdZ0/BkC&[UZeSZVZ9NTZfg{@WZh2BiXZjkz4lZZYZm[Z\Z{4|F6Cl5];aA\=00n]Zopqr"2aZstVLZMZW8J]UF@XLIX:eHCHYZME[ANOZP<\PZ]60^T6M@_`IQZB;GC`[;7?abcRZ}Jw1\;dJN8KCZLFZARIM_5NOEZDZTGGZ56IZHZPQ:46;XFRSI7t?JZ0@(E_IKZTU5Z569Z789:;<=7Z>?8ZpY@AB;Z:ZCDxYZ@Z?ZAZ~2G69HI|J/@JM'Z!#Z$Z"#$%`A&'("Z?Y)*&Z!Z+Z,Z'E.Z+,$;)Z-.<5//Z0(Z3Z2Z11Z24Z36Zq>4b7lm}Ynop5;zYyYqr2Gst5Fuvw1E{Yxy|YoIzEG#;q@PK{I3%Z~Y|}~]@YwYZ[\]^&E_`abcdeftY`KguYhivYNL"@jklYGH;BsYIJmYKjYqYLSYMNOPQnYrYRSBHkETUkYVoYH7Wq:XcY57BiY6dY7fY8AIsD9gY:;<,MHM94=>.0eY?bY@Ax4BCg1DhYEFIMWY%]A&'x<\Y(8>VY[Y)SG*+UY!7,-]3.]Y+NN:5CZY/\@059d?f1!hF1G"#$};LY[\X;MYD0]^HY_`)Dabcs546KY'0deC:f6?ghirDjTHQY^ADYQ4C>YEY@YGYCYBYoGRAYRGr5H3Vg3!?IYNYJYW}7XOY";i9YZ&==Y;50Y7Y6>1YDGEFGH^M3Y4Y8YjE5Y39^@FY4HrBIJdH-ZzJKqDLMuKN;Y!2jCOPj=(Y3456p@=nbHj<7M:)Y89:GB;'J<qB=,Y>*Y-Y+Y?.Y@1JA70B^IcHC/YD2Y5>xX$%&'yXzXjJ|X{X?=.@f2|2(}X)?0L@~X*Cl!Ya7+"Y,-o@./#Y0$Y:5%Y&Y'YWBM81aL2X?XU0<=>?@3XABCr6&0DE64@;XFCXBXGHGXIJHXKLMNFXIXAXEX#$p>/XWF%&'()*GO+X+,1X-{9.K@/0T0*X(X1ZA2|W4;FB=X3[A8X45X6X5f<9X?@AVWV;:K;K~1[WBiCCDXWEFGw2HIJK-XZWLM0GNYWOWWPz9]W}1,@IWHWB7TBNWLW)KW'Ne8*+y=MWLE>=,@FQWPW-.OWRWf8/20SW|I[=13TWyH456AF'D>70EUW+5r;WstuWw@WvExAWBWyCWz4W3W{DWA7|}'I~L:7I&DKIEW!4>F1"FW#$GW%rL&`H'(JW[J\1W.O]^_2W@J5W!P1P`0'W&W"WZ(W)W[*W-W+W,W.Wd1nD/Wz7v26G0W{FB#D-91>_H2>CDx=lDyJ9E.9\IyVEFGYEB:HIK8JmDKLC0n=/9GMMNOlVkVjV}IsV42ZKmV35oVkK6nV789:pV(HqV>JrV;<=>?@A34?J/GtVuV,944vV88DM)Mv4xV$T;[IAH%cVu4&fV'()!D*eVdVgVkD+,c?.U;J@-SB"5/"D0hViVo>9K1vwZVx`4[Vzy]V\V^V{|_Vn@#=}d=cA~)98:*9p5!`V9:J8aV&LCGbV+9"#,4'CR6dQVePVOVfghE:VWVhijklmSVnoRVpqTVUVrtsXVtufNYVVVPQRSWKVHVJVrMUIV<TV?VXYZ[\s?]LV^7:_MVNV`abcBCr?VGVFVEVAV@VDVGHIJxJFKLMNO2V4V9:;=5V<=F.6e26V;V9V>wJvJ?@A;gE8VT=7V)*+)V,t4*V-+V./0,2123;Ad44-V(LRB5Y367/V1V_48.V0V3VI6{Uo5|U~6OF02S;}U"V!V}6~U8Ewxy0BKEHrUsUS0:BR?itU3F.>/>uUm@j0>klvUwUm`LnxUopqF6rs"=tuvyUzU\<,?tFT?xH"G[\dH2XbUFMYZI=RU:PUQU;<R;SU=&9TU>z;8BUUVUZ;'9?RL(5I8WUX3@XU9BABYU#VZU[U\U^UCDEF./0r4IUHUJU13456n>7MU\D8E1KU2NU9OUG2?U!"#;<>Uy7$LUEUBU%&'dCAU(CUDU)*+,FUGU-kl^Gmno;U2Ipqrstuvwxyz{|}9:;(U90H8?+@Q0,U-U*U@ABCD81/4E)UEL1IFGHIJ(0Ky0Q;"U!G^HQL%G()+U*+85,EM-/L,V#U.&U/EB08KJE1234'U56eK7J:8*>rb1sq4`FtJwTUAvT@7tu[KuTeEyTvxTwxyz{T{zT||1|T)>~T%C}}T~3J!"w=[E#$!U%&'%9iT_`QJjTabF2kTcdeSTU[TVZTWh9X\T^T]TY`TZUTbT[\aT_T]N;Q?TAcT<@m0dG^[DeTdTfTgThT;<-6PT=>?@ABCDhJEF}AFDG9RTHIJKOKLSTXTMN/JWTQTTTVTP&:=J]N-t2JT./01:AMTcE2IEdE9HMDI:34IT567v16EKTGTP?8OT9N=:YK2Fz{x7OB|}ATDT!"DBET#FT$%&HTiD'(.4)!ta1sJ*l>HE+f:NT,1Tj?T@T>TkBT8Glmh0VI~CTnopqrs}>tu9?,T/TA:#9@63TA%:B3CCD0TZDEFGHIJKLMNOPQRS4T{S#$`J}S%!T~S&"T'#Tw7(`1$T)&T%T*+(T,ZE-./01)T50_:234=756OC78*T+T-T9:;sSqSoSrSjtSklmpquSnovSwSxSEQr|?=1@ABCD9AEYSFZSGz3HIJKLaSMo4NdS`ScSOPQR.JSUF8H*2C+E2,-./012RSTS(>313WS^24bS5|>^S6\S7]S8_S9:;<=vwNSLSx'Tyz{|}~!QS"#KS$OS%MS&L;PS'(SSXSVSUS)=SfgGS1AhISi"9?S}CjklmnopCSWXY3SZdL[\<77S8S]^_5S;S`ab2ScdASFSBSeEF41G6:0?HIJKL)SbE*SM"0NO4S#M'>P:SQR9S0SSTUCB%0JI"S|R9wR}RH::;<&S=w0/S'S(S%>iK>?-S,S@/EA.SB+SCDrR!"tR#vR$%5p:BO&kRiRuR'pR()*+,xR#SzR-.~R/0!S{R12>S3i:134yR567%Sv0$S8`R$OoprJqhDb8p9rhRs]FtlRuvwx~L!9yMGE~8ef/7gRc6JKg]HhifRj^4aRbRdRklmneR[5a?-JcR_Rc8W2;TRXtK5:Z5'MPA?H}\RZRD2fB8a8CR>H87DR\H4BnB(6nF1C9nG:NKFRj@;<=57GR>?HR,1u0m4@(BQ5qMKR72AJRB*6{hLwF|qJ2R23R}~!5R7R6R"#8R=2LK$|:9R%&YA'(">)6:R3)*+,[H-./;R0R$Ih6e0345?Fe&RVKf)RgJ-Rp*@*RP6q+R+4rstuvw.7.Rx/Ryz0R1R[<{8^LMND3O`7|Q-NPQxQ}QzQRyQSTUVWONXy8C2tNYZ[\u=XEe9"R#R]^eN+O%R_`az8bc$Rd/3fDmQ>'B?o:nQoQ0AlQqQ@6KABCd9DpQEFGu7^:mGHtQrQI{Ij>{Qd3uQsQOAJKLwQvQaE01O?cQ2,JZ@"4)4dQfQ:734eQ56sN7i=8=HLJgQ9xMhQiQ~E:;jQ<)@~:t7kQI;o9=~(@YQZ=!ZQ|C?N`E"#$%&ER'[Q%tE6(\Q^K)*h=|B^QdF1_Q+`Q.3,-.aQ'6/LFz1P=!HbQCQDQpqbF_1GQ}:rFQF:sHQnfIQAKJQKQLQi>tL<u'4vOQwMQ=LNQZIPQQQRQ_ExVQTQUQSQc:WQjLdNyz{XQ|}:Qt0e58;7<={C$6h@w8fn9Qm~Fn4A@QAQ,Hx8;OBQ&6?)Q@'QANABC(Q*QDEQ0,QF+QGHJHzPwxy|Pz{5K|}~f7!"#$1;wH{P%&'()*+,E:CM-.~P#Q}PD:}=/0197_`apPbcqPuPN0defPJtPghisPwPjkvPdDlmnor7pqrxPstuE<&BeDv6yP65IJKfPoPLRAMD8N\GOG`PnP]EQcPv8RSu8aPTUVWZ<iPXoJMCePq7YbPjPdPQNkPAOZ[\]^f6p7v6787%Bd289:;S=<=>YP?^P\P@WP/BZP]P[PA]JXPB.?CsK_P`P$=mPDEPG6IhPpJ62FGlPH|}&4~!TPLP"#cN$x;%MP&RP'()UP*NP+,!6M0-."6A2%UyKnIt8//?7N012345XJfgQD"CJPhijkL0cD;=4:$MlNBm?2nIPo>MEPGPn:HP$Up_qPPrstSPQPuB2;JKPvwxyOPs8z{H;Rk4STUDPK0VW`8l4zI2HY5XYZ[\q2gPAE]lGFP^`PCB?PUIg@EF8!@PBPGHIeBaNJ0JAP>2KD6LgCMNo7CP$G/OPQ55,P-P;N=MhA/Pv;sF=2P>1_8^8f0>?KOJO3:!0@3P4P5P4K6Pr8g0rK|5}5~5bD+P5245e6p8iL&V678pM}F9:;%40;e><2$TI?M"P/1%n3#P$@BRV5:Jg>&>N'(BJ)$P*fC+,-%Pz6.&P]40Cg<'P(PU-c-S-T-P-Q-R-V-@-N-C-H-I-_-o-n-m-F-J-A-D-B-L-K-E-M-G-O-e-f-g-h-i-j-k-l-@%A%B%C%D%E%F%G%H%I%J%K%L%M%N%O%P%Q%R%S%T%U%V%W%X%Y%Z%[%\%]%^%_%`%a%b%c%d%e%f%g%h%i%j%k%l%m%n%o%p%q%r%s%t%u%v%&!%?%`$a$b$c$d$e$f$g$h$i$j$k$l$m$n$o$p$q$r$s$+!,!5!6!!%"%#%$%%%&%'%(%)%*%+%,%-%.%/%0%1%2%3%4%5%6%7%8%9%:%;%<%=%>%?%!$"$#$$$%$&$'$($)$*$+$,$-$.$/$0$1$2$3$4$5$6$7$8$9$:$;$<$=$>$?$@$A$B$C$D$E$F$G$H$I$J$K$L$M$N$O$P$Q$R$S$T$U$V$W$X$Y$Z$[$\$]$^$_$!!"!#!7!9!:!;!R!S!T!U!V!W!X!Y!Z![!)"."L!M!`-a-!!"!#!7!9!:!;!R!S!T!U!V!W!X!Y!Z![!)"."L!M!A!`-a-j!i!v"u"t"z!y!!"~!{!}!|!~"#"""%"$"'"&"@(6(!(,("(-(#(.($(/(&(1(%(0('(<(7(2()(>(9(4(((8(=(3(*(:(?(5(+(;(!-"-#-$-%-&-'-(-)-*-+-,---.-/-0-1-2-3-4-^">"?"<"="]"y-b"b!a"e!f!c"d"O"_"P"`":";"t-e"g"g!x-\"B!J"K"A"@"i"j"s-h!h"f"O"_"P"`":";"t-]!e"g"g!x-\"B!J"K"A"@"i"j"s-h!h"f"M"N"+","*"-"5-6-7-8-9-:-;-<-=->-stuvwxyz{|n!b-d-or">!=!F!G!H!I!w"x"E!D!s"l!m!(">!=!=!B!F!G!H!I!w"x"E!D!s"l!m!("~>!=!=!B!F!G!H!I!w"x"E!D!s"l!m!("1!b'c'd'e'f'g'h'i'j'k'l'm'n'o'p'q'W'rstuvwxyz{|}~''BCDEFGHIJKLMN!'"'#'$'%'&'(')'*'+','-'.'/'0'1'2'3'4'5'6'7'8'9':';'<'='>'?'@'A'Q'R'S'T'U'V'X'Y'Z'['\']'^'_'`'a'P&Q&xR&S&T&U&V&W&X&uzwy|89abcdgilv!&"&#&$&%&&&'&(&)&*&+&,&-&.&/&0&1&2&3&4&5&6&7&8&ejqrst{A&B&C&D&E&F&G&H&I&J&K&L&M&N&O&0/2653&&CCUUggppmmoonn9I(HMMOONNJ+KWWVV-MYY[[ZZ\\]]__^^aa``/Olliiffkkhhjjqqttsuuwwvv''%%((++,,//--00"B77668855::;;==<>>$DGGEEFFDE&FHHIIGJJLLKK)AAAAAAACEEEEIIIIDNOOOOO_!OUUUUYTsaaaaaaaceeeeiiiidnooooo`!ouuuuyty"!$*#)!.2143@?BAPRQTXS_!,cbedr0N"!$*#)A.2143@?BACPRQTXS`!LcbedrPs!q!r!\|x!/!cac"L"-R1!k!^!23-!L&y"&!$!1od"Bq!r!p\Cx!/!mlL"n4k!^!-!y"1kDBq!r!po!Cx!/!mlL"n4k!^!-!y"1kDabcdefghijklmnopqrstuvwxyz{|}~"!b!c!d!e!f!g!h!i!12!!!pNPQS$STYWX[\S]_` aNe;fef)hkjjmm(puvv0yz}}b !"v#$%ސ&'();MQ*+,ٚr-ўp!q!r!s!t!u!v!w!x!y!`!a! "&*+/12479:<=?ACDEFGSUVWXZ]^himnopqsuz}|~Ýǝɝʝԝ՝֝םڝޝߝ z{|ƞȞ˞՞ߞ "#&'()*1567=ACDEIJNOPSTVX[]^_cij\khnpruw{ /0234:DGJQRSVWYZbcefjl˜ŘȘ̘"&'+123459:;<@AFGHMNTXY[\^_` !"#(13ACJNOUWXZ[cgjnsvwx{}ėŗǗɗʗ̗͗ΗЗїԗחؗٗݗޗۗ   #&~ƕȕɕ˕Еѕҕӕٕڕݕޕߕ"$%&,13789:<=ARTVWXant{|~ʖҖ]ؖږݖޖߖz}ēœƓǓɓʓ˓͓̓ӓٓܓޓߓ ./1234;?=CEHJLUY\_achkmnoqrxy’ÒŒƒǒȒ˒̒͒ΒВӒՒגْؒܒݒߒ !$%')*3467GHIPQRUWXZ^degijmopqstv‘Ñőӑԑבّڑޑ #$%&(./035689:<>@BCFGJMNOQXY\]`aeghinopuvwxy{|}ĐŐǐȐՐאِؐܐݐߐҐ  %"#')./14679:<=CGHOSWYZ[adgmtyz{CGOQRSTUX]^eƏʏˏ͏ЏҏӏՏ ()/*,-347?CDL[]bfglpty̐Ð#&'136789=@AKMNOT[\]^abilmopqyz{ÎĎǎώюԎ܎ !#%'(,-.4567:@AŌƌɌˌό֌Ռٌ݌ eilnōƍǍȍʍ΍эԍՍ׍ٍ  !"ÊƊȊɊʊъӊԊՊ׊݊ߊ  -07EGIKOQSTWX[]Ycdfhimsuv{~{|}ԉՉ։׉؉ "$&+,/57=>@CEGIMNSVWX\]aeguvwyz{~:@BEFIORWZ[\abcknpsuz(./129:<=>@CEMX]adeoqr{ȇɇʇ·Շևهڇ܇߇ (-.025 !')68:<=@BFRSVWXY]`abcdilouvwzÆņц҆Ն׆چ܆熈 !#܄2 "#$%'*+/346?FOPQRSVY\]^_`abdkoyz{}…Džʅ˅΅؅څ߅}ǃɃσЃуԃ݃S /9EGHJMOQRVXYZ\`degjpstvx|}„DŽȄ̄τӄKNOQV\`cgmt{}ƂЂՂڂ T!",-.037:<=BCDGMNQUVWpx  $',05:@D`dfmquȀ̀πҀԀՀ׀؀}}}}}}}}}}}}}}}}}}~}}}}}}}}}}}~~~~~~~ ~'~(~,~-~/~3~6~?~D~E~G~N~P~R~X~_~a~b~e~k~n~o~s~x~~~~~~~~~~~~~~<;=>?CDGORS[\]acdefma|c|g|i|m|n|p|r|y|||}||||||||||||||||||||||||||||||||}}} }}}}}}}}#}&}*}-}1}<}=}>}@}A}G}H}M}Q}S}W}Y}Z}\}]}e}g}j}p}x}z}{}}}}}}}}}}}}}}}1{4{={?{@{A{G{N{U{`{d{f{i{j{m{o{r{s{w{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{||||| | | ||||| |%|&|(|,|1|3|4|6|9|:|F|J|U|Q|R|S|Y|Z|[|\|]|^|yyyyyyyyyzzz z z zzzzz!z'z+z-z/z0z4z5z8z9z:zDzEzGzHzLzUzVzYz\z]z_z`zezgzjzmzuzxz~zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz{{{#{'{){*{+{-{.{/{0{xxxxxxxxxxxxxxxxxxxxxyxxxxxy yyyyyy y%y'y)y-y1y4y5y;y=y?yDyEyFyJyKyOyQyTyXy[y\ygyiykyryyy{y|y~yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyydwgwjwlwpwrwswtwzw}wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwxx x xxxx!x"x#x-x.x0x5x7xCxDxGxHxLxNxRx\x^x`xaxcxdxhxjxnxzx~xxxxxxxxxxxxxxxxx:vwBwEwFwJwMwNwOwRwVwWw\w^w_w`wbwuuu u!u$u'u)u*u/u6u9u=u>u?u@uCuGuHuNuPuRuWu^u_uauouquyuzu{u|u}u~uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvv v vvvvvvvvvvv#v%v&v)v-v2v3v5v8v9vstttt tttt$t&t(t)t*t+t,t-t.t/t0t1t9t@tCtDtFtGtKtMtQtRtWt]tbtftgthtktmtntqtrtttttttttttttttttttttttttttttttttttttttttttttttttttturssss s ssssss"s$s's(s,s1s2s5s:s;s=sCsMsPsRsVsXs]s^s_s`sfsgsiskslsnsosqswsys|ssssssssssssssssssssssssssssssssssssssssssssssssssshqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrr rrrrrr$r+r/r4r8r9rArBrCrErNrOrPrSrUrVrZr\r^r`rcrhrkrnrorqrwrxr{r|rrrrrrrrrrrrrrrrrrrrrrrrrrrooooooooopppp pp p#p/p4p7p9pj?jEjFjIjJjNjPjQjRjUjVj[jdjgjjjqjsj~jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkk kkkkkkk$k(k+k,k/k5k6k;k?kFkJkMkRkVkXk]k`kgkkknkpkuk}khhhhhhhhhhhhhhhhhhhhi i iiiiii1i3i5i8i;iBiEiIiNiWi[icidieifihiiilipiqirizi{iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiijjjjjjjj j$j(j0j2jfglgngtgvg{gggggggggggggggggggggggggggggggggggRhhhhh(h'h,h-h/h0h1h3h;h?hDhEhJhLhUhWhXh[hkhnhohphqhrhuhyhzh{h|hhhhhhhhhhhhhhhhhhhhhf!f"f#f$f&f)f*f+f,f.f0f1f3f9f7f@fEfFfJfLfQfNfWfXfYf[f\f`faffjfkflf~fsfuffwfxfyf{ff|ffffffffffffffffffffffffffffffffffgggggg g"g3g>gEgGgHgLgTgUg]gddddddddddddddddddddeee e eeeeeeeee"e&e)e.e1e:e^K^P^I^Q^V^X^[^\^^^h^j^k^l^m^n^p^^^^^^^^^^^^^^^^^^^^^^^^^^^________!_"_#_$_(_+_,_._0_4_6_;_=_?_@_D_E_G_M_P_T_X_[_`_c_d_g_m\p\t\u\z\{\|\}\\\\\\\\\\\\\\\\\\\\\\\\\\]] ]]+]#]$]&]']1]4]9]=]?]B]C]F]H]U]Q]Y]J]_]`]a]b]d]j]m]p]y]z]~]]]]]]]]]]]]]]]]]]]]]]]]]]]]]ZZZZZZZZZZZZZ[[[[4[[[[![%[-[8[A[K[L[R[V[^[h[n[o[|[}[~[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ \\\\#\&\)\+\,\.\0\2\5\6\Y\Z\\\b\c\g\h\i\oYrYuYvYyY{Y|YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYZZ Z ZZZZZ#Z$Z'Z(Z*Z-Z0ZDZEZGZHZLZPZUZ^ZcZeZgZmZwZzZ{Z~ZZZZZZZZZZZZZZZZZZZZZ X XXXX X&X'X-X2X9X?XIXLXMXOXPXUX_XaXdXgXhXxX|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXYY Y YYYYAY!Y#Y$Y(Y/Y0Y3Y5Y6Y?YCYFYRYSYYY[Y]Y^Y_YaYcYkYmYVVWWW W WWWWWW W"W#W$W%W)W*W,W.W/W3W4W=W>W?WEWFWLWMWRWbWeWgWhWkWmWnWoWpWqWsWtWuWwWyWzW{W|W~WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWXXX XWUUUUUUUUUVV V VVVVVVV,V0V3V5V7V9V;VSBSLSKSYS[SaScSeSlSmSrSyS~SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSTTT!T'T(T*T/T1T4T5TCTDTGTMTOT^TbTdTfTgTiTkTmTnTtTTQQQQQQQQQQQQQQQRRRRRRRR"R(R1R2R5RO@OBOHOIOKOLOROTOVOXO_OcOjOlOnOqOwOxOyOzO}O~OOOO   !%+/)57:><DHFQMUYW[]a_ecmqksoiuwz~|  " $0*.(469=;CGEPLTXVZ\`^dblpjrnhtxvy}{&2A?JRf'138B@IKSg    RSTUVWXYZ[\^_^"!!בޑ :@ABCD;</XiYdtQq]^dQPYrozĝƝϝٝӝuy}a̞ΞϞОԞܞޞݞv!,>JRTc_`afgljwrv"#%'()*./2DCOMNQXtʛƛϛћқԛ:   .%$!0G2F>Z`gvx *&#DA?>FHqtsĘØƘ !$ ,.=>BIEPKQRLUߙۙݙؙљ+7EB@C>UM[W_bedikjϚњӚԚޚߚ]_frlΖ˖ɖ͖Mܖ Ֆ$*09=>DFHBI\`dfhRkqy|z×Ɨȗ˗ܗOz 8$!7=FOKkop"#:5;\`|nV֓דؓÓݓГȓ6+5!:ARD[`b^j)puw}Z|~ʕoÕ͕̕Օԕ֕ܕ!(./BLOKw\^OPQRI>VX^hovr}Hbې20JVXceisrɑˑБ֑ߑۑ,^WEIdH?KPZϒD.GILPHYd`*cUvr|ƎŎȎˎێ  &3;9EB>LIFNW\bcdڏ!  '659_lot}:A?HLNPUblxz|bȌڌ  N͌gmqsύڍ֍̍ۍˍߍ B504Jfdmjotw~ډ܉݉ %6A[RFH|mlbĊ͊Šڊފۊ  3&+>(ALONIV[ZkScjˇЇ֖ćLJƇ ҇"!169';DBRY^bk~u}rÈĈԈ؈و݈ C%*+AD;68L`^AKUmꅇw~ɅυЅՅ݅܅  "0?MUNT_gqĆƆɆ#Ԇކ߆ۆ 4?7;%)`_xLNtWhnY5421@9PE/+#|su΃؃  " 8m*SQqneft_Ɂ́сف؁ȁځ߁ )+83@YX]Z_dbhjk.qwx~߂҂ނ܂ قELMNPQUTX_`higxqܘ !(?;JFRXZ_bhsrpvy}Qۀـ݀Āڀր )#/K}}} }E}K}.}2}?}5}F}s}V}N}r}h}n}O}c}}}[}}}}}}}}}}}}=~}}}}}}}}}}}}}~ ~#~!~~1~~ ~ ~"~F~f~;~5~9~C~7~2~:~g~]~V~^~Y~Z~y~j~i~|~{~~}}~~~~~~~~~~~~~8:z{{M{ {L{E{u{e{t{g{p{q{l{n{{{{{{{{{{]{{{{{{{{{{||{{`||||{{| |{#|'|*||7|+|=|L|C|T|O|@|P|X|_|d|V|e|l|u||||||||||||||||||||||;|||||}xxxxyyyy,y+y@y`yWy_yZyUySyzyyyyyKyyyyyyyyyyyz zzz zzy1z;z>z7zCzWzIzazbzizpzyz}zzzzzzzzzzzzzzzzzzzzzzzzzzz{{ {{3{{{{5{({6{P{rvvvxv|vvvvvvvvvvvvvvvvvvvvvvvv/vwww)w$ww%w&ww7w8wGwZwhwkw[weww~wywwwwwwwwwwwwwwwwwwwww xx&y x*yExxtxx|xxxxxxxxxxxxxxxxttttttttttuuu uu uuuu&u,usNsOs؞Wsjshspsxsus{szsssssssssttot%ts2t:tUt?t_tYtAt\titptctjtvt~ttttttts>oonozoxooooo[oomoo|oXoooofoooooooooooooooo p popppopptoppp0p>p2pQpcppppppppppppp qpqqeqUqqfqbqLqVqlqqqqqqqqqqqqqqqqqqqlllllmM6m+m=m8mm5m3mm mcmmdmZmymYmmmommn nmmmmmmmmmmmmmmmmm-nnn.nnrn_n>n#nkn+nvnMnnCn:nNn$nnn8nnnnnnnnnnnnnnnnnAooLpnnn?on1on2onjjjjjjjjjjjjjjkjkk1k8k7kv9kGkCkIkPkYkTk[k_kakxkykkkkkkkkkkkkkkkkkkkkkkkkkkllll$l#l^lUlbljllllll~lhlslllllllllllllhhh6iiihh%ihhh(i*ii#i!ihyiwi\ixikiTi~ini9iti=iYi0iai^i]iijiiiiiiiii[iiiii.jiiiiiiijji kiiijijiji jjj#jjDj jrj6jxjGjbjYjfjHj8j"jjjjjjjfffff?ffffffggg&g'g8.g?g6gAg8g7gFg^g`gYgcgdggpgg|gjggggggggggggggggggggggjhFh)h@hMh2hNhh+hYhchwhhhhhhhhhjhthhhhih~hihih"i&ih ihddddddddd ddbdd,eddddedeee$e#e+e4e5e7e6e8eKuHeVeUeMeXe^e]erexeeeeeeeeeeeeeeeeeerg ffesg5f6f4ffOfDfIfAf^f]fdfgfhf_fbfpfffffffffffffb!b*b.b0b2b3bAbNb^bcb[b`bhb|bbb~bbbbbbbbbbbbbdbbbbbbbb cbb'cccbbPc>cMcdOcccccvcccccckciccccccccccd4ddd&d6ded(ddgdodvdNd*edddddd````````````_````Maaa``a``a!a`` aaGa>a(a'aJa?a[C[E[@[Q[U[Z[[[e[i[p[s[u[x[ez[[[[[[[[[[[[[[[[[[[\\\ \\ \"\(\8\9\A\F\N\S\W W WWWWUW&W7W8WNW;W@WOWiWWWaWWWWWWWWWWWWWW XWW XXXrX!XbXKXpXkRX=XyXXXXXXXXXXXXXXXXXXXXXXXXXXY YYYh%Y,Y-Y2Y8Y>YzUYPYNYZYXYbY`YgYlYiYTTTTTTTTUUTTTTT9U@UcULU.U\UEUVUWU8U3U]UUUTUU{U~UUUU|UUUUUUUUUUUUVUVUUVUNVPVq4V6V2V8VkVdV/VlVjVVVVVVVVVVVVVVVVVVVVVVVWVW WRRRRRRRRRRRRRRRSS8u SSSSS#S/S1S3S8S@SFSESNISMSQ^SiSnSY{SwSSSSSSSSSS|ٖSfqSSSST=T@T,T-T|}o8/UQO*QRS[}^`ac gggnm6s7s1uPyՈJĖYNYON?P|^Y[^ccdfJii mnq(uzIɄ! e} ~ab2kltmmeg<ma}=jqNuSP]koͅ-)RTe\Nghtt+osT*gE]{\[JnфzY|l wR"Y!q_rw'a iZZQ T}TfvY]rnMQh}}bxd!jY_[ksv}2Q(gٞvbgR$\;b~|OU` }S_NQY:r6Α%_wSy_}3VgS aalRvllp2x+~ހ *JҒlONNPVRJWY=^__?bfgghQ!}~2 T,SP\SXd4ggrfwFzRlkXL^TY,gQvidxTWY'fgkTiU^ggR]hNOSb+glďOm~Nbanyym_UblNirR;TtVXanbqnY||}e^NuOuQ@Xc^s^ _g&N=[s|PXVvx%Rw{OP YGr{}ԏMOR)Z_OWUcik+u܈BzRXUa bfk?|#POSFT1XIY[\\)]^bgc>ee g;gz9Suf_񃘀<__buF{lNlHrrsTuA~,酩{Ƒiq=cifjuvxC*SQS&TY^|_`Ibybbekluvxy}w^ۘ j8|P>\_gk5t wY?\NY_oyby[q+sqt^_{cdq|CN^KNWV`o }3]bdwgl>m6t4xFZuO^bcWeogvLr̀)M PWZhsidqrXjyw)/OeRZSbgl}v{|6f or~ciFv-0ؕPR TX\admwzS\?S__myrcwy{krhajQz4iJ\[IpxVo\`felZAQTf HYQMNQXpzcKbi~wuWS`iߎ]lN<\_Sьy^esNeQ-ؑlXdduenv{iѓnT_dMDxQkX)YU\^m~u[pOko0uNQT5XWXY`\_e\g!n{v߃M%x:xR^WtY`PZQQQRUTXXXWY[\]`b-dqgChhhvmonmopqS_uwyI{T{R{|q}0R^3^^_5_k__acfgnoRr:u:wt9xv܊󍚒wRWcvglsÌs%mXiiuZXhciCO,og&}T?ipojWX,[,}*r T㑴NNO\PuPCRHT$X[^^^^_`b:cch@lxy z}GDSFOTjY1]zh7rH=j9NXSVfWbceNkm[npwz{}=ƀˆ[VX>_efjk7uNJ$Pw0W_e`zf`luznE{\uzQ{Ąyz6Z@w-NN[_bUXY`Sbg5Ui@ę(SOX[\/^_ `Ka4bfln΀Ԃ.۞ۛNS'Y,{Ln'pSSDU[Xbbblo"t8o8QSJ~z9nΌxwMRU8o6qhQyU~|LVQX\cffZiruuyVyy| }D}4;a PuRSS PUXOY=r[d\S``\cc?ccdef]iioqNuvz|}}aIXlňpmPXaozd[N,p]u/fQ6RRY_'`b?eteftfhhcknrruv|VXˊRYez-^`befgwMzM|>~ d_xRbcBdb-z{v} INHQCS`S[\\]&bGbdh4hlEmmg\oNq}qez{}b ikqT~wrߘU;\8OOOU Z[[_Na/ceKfhixmm3uuw^yy3}は:2ݑNNRuXX \u=\N ŏcm%{ϊbVS9TW%^c4lpaw|pBT^tĚ]i]pegۖncIgiŃR SGSSTFU1UVhYYrtux:y 3ꁔPl_X+z[NSW1YZ[`nouꌟ[{rPga\J~Q\hcfenq>y}ʎndžPR:\Sg|p5rLȑ+[1_`;NS[Kb1gkrs.zkRQSjT[c9j}VShT[bdd-gkіv֛LcvRf NPSq\`dce_hqs#u{~یxefkNN:OO:RSSUVXYYYP[M\^+^_`c/e\[eeegbk{klEsIyy|}+}󁖉^ifnj܌̖okNd(fggzV{"}/\h9{SQ7RTUQWW}YT[][[]]]x^^^^_R`Labbc;efCffmg!hhi_l*mim/nn2uvlx?z|}}^}}T*RLaʐuq?xMؚ;[RRSTXboj_KQ;RJTV@zw`ҞDs opu_`ri)j}rr.sxoxy} wҎcuzUxCQSS{^&_nnssC}7PNN PS|TVYd[]^'_8bEegVnr|N7ǖgNN OHSIT>T/Z__`hjZtxw^NɛN|OOPPIQlQRRRSSTczltazq|hp~QhlRT͎fSAyOPRDQSU-WsWQYb__u`vagaac:dleofBhnfu=z|L}}K~kJ͆cfΏ蛇RbdoAhP kzlTotzP}@#gN9P&PeP|Q8RcRUWXZ^aabrcOOPGQzqQQTS!SSSUX\7_J_/`P`m`cYeKjlrrwNWZNQ-\fmi@\fuisPh|PRGW]&e#k=k4tyyK{}̃_9яёT]N6PS:Srsw悯ƙșҙwQa^UzzvP[G2NjQ\H\_j0^kl}luHyc[z}_w̎kSkWl"ooEotuv wz{!|}6f̊Qeӗ(8N+T\]sLv?@ABCDEFGHIJKLMNO00000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0W0X0Y0Z0[0\0]0^0_0`0a0b0c0d0e0f0g0h0i0j0k0l0m0n0o0p0q0r0s0t0u0v0w0x0y0z0{0|0}0~0000000000000000000000!"#$%&'()*+,-./0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ%%%%%%%; 0!!!!0" """""*")"'"("!!"" ""#""a"R"j"k""=""5"+","+!0 o&m&j& ! %%%%%%%%; 0!!!!0" """""*")"'"("!!"" ""#""a"R"j"k""=""5"+","+!0 o&m&j& ! %000 000@>?00000N0000  <^%"\& %      00;=[]0 0 0 0 0 00000 `"f"g""4"B&@&2 3 ! &&%%%%000 000@>> ?00000N0000  <0 \& %      00;=[]0 0 0 0 0 00000 "`"f"g""4"B&@&2 3 ! &&%%%%;O4./124T5 646H789:T:t:$;0;D=h?@B0tF\GGTHtJN DN QLtTUUV V V4VHXXZZ Z [@]4^ed $h k k k 4l d  $4 Tl 4 t đ  , @ $` $  @  Ĭl$$D8dLzRx $+FJ w?:*3$"D,p\/.p/1H f B ,224T3nBRD C(D0H(A ABB3E\ O  5JE,<P5FFE  CBK l6JED6P66 h7 ED0 AH \T9FBA C(F0z (A ABBN ` (C ABBH T (A ABBF PH:OLAC  ABI P ABE ^ CBM A CBJ ;>(FBE H(D0D8DP 8C0A(B BBBA   0 FAA G  AABB  l H0 `EGNU#H؇߉).  $(+-8=AI$iQT]`r  u&zDLTc[kv&2܇y+++++++ , P ##o`U 7, $((pY o0ooo# 0@P`p BB?0B0B^jyƉщ @ @P= @ @P=!!!!!!! !͆0Lˆ0JH`H0BrP @ @ @ @GA$3a1P GA$3p1067 GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY NGA+GLIBCXX_ASSERTIONSnkf.so-1.8.7-16.el8.x86_64.debug7zXZִF!t/-}]?Eh=ڊ2NĊ_9ĴIy _3YRfB)U:NX[4F|4}I}|=δS\?Ұ^F*h jϕ+#/#]݂hW(+MNCU$ 5$&EUo-Jr;vr:G@xxLpH9O~Q#**O{xPilz8?b57I 1揱GXFuV^.7p-Tpe@J({Yf;8 >*gxX1Wj F>KmmEt6uBˇmZ߹ASH7ڌcה_PWiYj}#Vairs/C 0+ 4%y=6G=ԨSMUsF E۳\20L|m:ԢZ*P Xv\7Б,y.Άɱ`{݄+,)Vaw2lx T0u[\d sm7*Gο4|l<,T%ĀJ.c`h՝fzu FG+i Ѯz~uq]ɴSh~qLپnłÓ%z3z5g0Onߌ̜*dAĿ F %ɸ~<4@y9a[.&u}i|v`"Y'6w8vݹxlXYpF1Vyi57IGy"@J@YpnQKyDŌ-OmtNSZk^5pNQpwcΨNz+ԫ Ŷu0?t45vG^zpU2q" *f;u(S#ĕ] 𞕙]T=W+M~,q5 j-#e.cT&b]9[eu.U P"l=2/ZQ Z5sgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``T( ?0UU7,8o@Eo00@TppY^B(((hPPcppnpw``}   / <<8  ###5 #0# $$ $ dH@("h( 1PK|])x86_64-linux/util.hnu[/********************************************************************** util.h - $Author: shyouhei $ $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ created at: Thu Mar 9 11:55:53 JST 1995 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef UTIL_H #define UTIL_H #ifndef _ #ifdef __cplusplus # ifndef HAVE_PROTOTYPES # define HAVE_PROTOTYPES 1 # endif # ifndef HAVE_STDARG_PROTOTYPES # define HAVE_STDARG_PROTOTYPES 1 # endif #endif #ifdef HAVE_PROTOTYPES # define _(args) args #else # define _(args) () #endif #ifdef HAVE_STDARG_PROTOTYPES # define __(args) args #else # define __(args) () #endif #endif #define scan_oct ruby_scan_oct unsigned long scan_oct _((const char*, int, int*)); #define scan_hex ruby_scan_hex unsigned long scan_hex _((const char*, int, int*)); #if defined(MSDOS) || defined(__CYGWIN32__) || defined(_WIN32) void ruby_add_suffix(); #endif void ruby_qsort _((void*, const int, const int, int (*)(), void*)); #define qsort(b,n,s,c,d) ruby_qsort(b,n,s,c,d) void ruby_setenv _((const char*, const char*)); void ruby_unsetenv _((const char*)); #undef setenv #undef unsetenv #define setenv(name,val) ruby_setenv(name,val) #define unsetenv(name,val) ruby_unsetenv(name); char *ruby_strdup _((const char*)); #undef strdup #define strdup(s) ruby_strdup(s) char *ruby_getcwd _((void)); #define my_getcwd() ruby_getcwd() double ruby_strtod _((const char*, char **)); #undef strtod #define strtod(s,e) ruby_strtod(s,e) #endif /* UTIL_H */ PK|]..x86_64-linux/io/wait.sonuȯELF> @'@8 @      00888$$xxx Stdxxx Ptd\\\44QtdRtd  ppGNU%cQ 0L6`y^I`"BE|qXMV  z Ug&, F"    @__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_io_taint_checkrb_io_check_closedrb_io_check_readablerb_scan_argsrb_time_intervalfeofrb_read_pendingfileno__fdelt_chkrb_thread_selectioctl__stack_chk_failrb_sys_failrb_int2inumInit_waitrb_cIOrb_define_methodlibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.15GLIBC_2.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64ui ii    @           ( 0 8 @ H P  X  `  h  p x    HH9 HtH5B %C hhhhhhhhqhah Qh Ah 1h !h hh%= D%5 D%- D%% D% D% D%  D% D% D% D% D% D% D% D% D% DH= H H9tH Ht H= H5 H)HHH?HHtH HtfD=M u+UH= Ht H=> Id% ]wAWAVAUIATIUHSHdH%(H$1HXHHtLHL$H`1E1 H|$HtLl$ HD$ HT$(H+H?1҅t1H$dH34%(HH[]A\A]A^A_DHD$ HL|$0T$ LAƉHIcDA~MLA ?)ѺH1H T01xSHH;HHT$T1Iu$D$IO 1f.SHdH%(HD$1"HXH6HH;HH1҅tHL$dH3 %(HuYH[@HpuUaL'U%jUK<'+* A|oSą&";/)/XU1c 0 -B]hp oO++K/=1Tk44$[y9&=ٯ0 G굙<kW\ '^k: *yylͲo [͋0:gɖ$>{dT܂7u9X@..ɭjE]7(7> ܳ3: G!$\#yLDU?ܨ9m:GO'Tnu#b*ghH޾|d~=hslΚ)7sKEhdoNy W*&y7, 3rFY@s$ϦA@t̄06%Qaa8C+)<"kEL(l _0ZOSbMCEw- 0@|Y!lEώ g*~A (հVP 8SD ̕D ًΈ=(EPM u鉘4}ЀhJp訉ӮjOt,[K5D 'Je(])c˅e,9(kueY>^ushs]5`lǸ6@hzf1k[X96H$GٻҐ#L[DܕngYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( X08o2Eo@TXX^Bh c n w p}@@ 2MM\\4xx     0 (   ` H "(#dl&+PK|]a7`bbx86_64-linux/gdbm.sonuȯELF>@Z@8 @`J`J @M@M @M  XMXM XM @@888$$@J@J@J Std@J@J@J Ptd8?8?8?QtdRtd@M@M @M GNU]0*9cB@$BDBE| VqXt 3K([+ UEe}Y>AuzNc)Z, 5ksF"jQ Q  6nQ __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_check_typerb_eRuntimeErrorrb_raisegdbm_firstkeyrb_str_newfreegdbm_fetchrb_string_valuegdbm_nextkeyrb_hash_newrb_hash_asetrb_ary_newrb_assoc_newrb_ary_pushmemcmpgdbm_existsrb_iteraterb_internrb_funcallrb_hash_delete_ifrb_yieldrb_ary_new2rb_block_given_prb_warnrb_eArgErrorgdbm_closerb_scan_argsrb_fix2intrb_num2intrb_check_safe_objgdbm_opengdbm_errno_locationrb_sys_failruby_xmallocgdbm_strerror__stack_chk_failrb_data_object_allocrb_ensuregdbm_setoptrb_securerb_error_frozengdbm_syncgdbm_reorganizegdbm_deleterb_protectrb_jump_taggdbm_store__errno_locationrb_eIndexErrorInit_gdbmrb_cObjectrb_define_classrb_eStandardErrorrb_eExceptionrb_mEnumerablerb_include_modulerb_define_alloc_funcrb_define_singleton_methodrb_define_methodrb_define_constgdbm_versionrb_str_new2libruby.so.1.8libgdbm.so.6libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64 ui ii ui @M HM PPM PM O O O O O !O *O +O 0O 4O 5O 6O 9O :P  P (P 0P 8P @P HP  PP  XP  `P  hP  pP xP P P P P P P P P P P P P P P P P  Q "Q #Q $Q % Q &(Q '0Q (8Q )@Q ,HQ -PQ .XQ /`Q 1hQ 2pQ 3xQ 7Q 8Q :Q ;Q <Q =Q >Q ?Q @Q AHH: HtH5: %: hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5%7 D%7 D%}7 D%u7 D%m7 D%e7 D%]7 D%U7 D%M7 D%E7 D%=7 D%57 D%-7 D%%7 D%7 D%7 D% 7 D%7 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%6 D%}6 D%u6 D%m6 D%e6 D%]6 D%U6 D%M6 D%E6 D%=6 D%56 D%-6 D%%6 D%6 D%6 D% 6 D%6 D%5 D%5 D%5 D%5 DH=5 H5 H9tH3 Ht H=5 H55 H)HHH?HHtH3 HtfD=m5 u+UH=3 Ht H=0 dE5 ]wS"HnHC HtHx[HD[fPXH5 HH2 H81fPXH5 1HHH=4 nff.USH%Ht@HHcHHH'@uHtHMHH[]fDHH[]ÐS"H~HC HtAHxHt8xt[DHu[H1[1ff.fUSHeHt@HHcHHHW@uHtHMHH[]fDHH[]ÐSHHH|$Ht$ HD$HHpP1sH[ff.fUH"SHHjHC HtHxHt HH1[]1@1UHSHHvP+Ht>HHcHHH]@uHtHMHH[]@HH[]fAT"USHHC HteHhHt\4HI1HHt7@HH1HLH=HH1 HHuL[]A\1fDATUSH"HIHC HtbHhHtYH1HHtff.UH"SHHdH%(HD$1FHC HtLHxHtC1HT$HD$0t&HL$dH3 %(HuH[]11ff.UH"SHHdH%(HD$1HC HtKHXHtBHHT$H߾D$t&HL$dH3 %(HuH[]1 &1ff.@SHuHtHu[H=ff.S1H"HHC HtHxHt H[1qS1Hq"HHC HtHxHt H[11AW1AVAUATUSHHH|$"HBLs MInHAHXIHHurcMLMtHHLHHILIfH߅t*MtLH8aH=b! H5 H1 AHD$H[]A\A]A^A_17U1HSHHHHHH=HH[]fDAV1AUATUSHHHt$H|$kHD$"HLpDhHk HtbLeMtYLLLAt5LLLOu͌hI?LJEeL"$gS1a<"ƥtjLH[T!ZZ{PJ36;8*b=FhN4]#!{j։!#|Vך Yȕ>)8UIN|hVR7P / +kR`gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 0( ( R8oz z EoPTXX^Bhcpn`w!}<< 2==88?8?@@X @J@J @M @MHM HMPM PMXM XM@O OhP PQ Q Q`QH T(8TXY+PK|]L@@x86_64-linux/syslog.sonuȯELF>`@9@8 @)) X-X- X-  p-p- p- 00888$$))) Std))) PtdX%X%X%QtdRtdX-X- X- GNU۹gP߮z" ݟ)@ @)+BE|.*qXqI_@  UcU%l /, yF"7 1 81  m 1 __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_check_typerb_class2name__snprintf_chkrb_str_new2__stack_chk_failrb_fix2intrb_scan_argsrb_string_valuerb_check_safe_objruby_strduprb_num2intopenlogsetlogmaskrb_block_given_prb_yieldrb_ensurerb_gv_getrb_eRuntimeErrorrb_raiserb_int2inumrb_securerb_f_sprintf__syslog_chkrb_eArgErrorrb_eTypeErrorrb_cNilClassrb_cFalseClassrb_cSymbolrb_cTrueClasscloselogfreeInit_syslogrb_define_modulerb_define_module_underrb_include_modulerb_define_module_functionrb_define_constlibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.4GLIBC_2.2.5GLIBC_2.3.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64ii ui ti X- `- h- h- / / /  / / / / / / #/ $/ %/ (0  0 (0 00 80 @0 H0  P0  X0  `0  h0 p0 x0 0 0 0 0 0 0 0 0 0 0 0  0 !0 "0 %0 &0 'HH! HtH5R! %S! hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D%  D% D% D% D% D% D% D% D% D% D% D% D% D% D% DH= H H9tH. Ht H=y H5r H)HHH?HHtH% HtfD=5 u+UH=  Ht H=v 9d  ]w 1Hff.HAVAUATUSHHdH%(H$1 D5h D-e HHD%\ H-m AVHAUILb1ATUH HbH$dH3%(uGH[]A\A]A^HHmLHI1JHHHHBHHDHHHHcHDf.USH(dH%(HD$1H H1LL$HLD$HHH<$<H4H<$H$HxNH|$H H@H|$ H@‰ 5 H= k1 ljb xudHL$dH3 %(HH([]fD{mfD H|$Hc fH= HHHD1@H= dH$Hw H5| H81nff. u @Hc=a ff.^ u @Hc=5 ff.. u @Hc=  ff.ATIUS{~1 t?L[H HH]1A\fH H5 H81nH_ H5 H81VfDSHHiH[@SHHIH[@SHH)H[@SHH H[@SHHH[@SHHH[@SHHH[@SHH1H[~ u @H=q ff.ATUS~,_H>Lf@t6HkLމH[]A\H H5o H81Ht5Htwrong number of arguments (%d for 2+)must open syslog before setting log mask<#%s: opened=false>syslog already open03$0no log message suppliedmust open syslog before write%stype mismatch: %s givensyslog not openedSyslogConstantsreopenopen!opened?identoptionsfacilityclosemaskmask=LOG_MASKLOG_UPTOinspectinstanceLOG_PIDLOG_CONSLOG_ODELAYLOG_NDELAYLOG_NOWAITLOG_PERRORLOG_AUTHLOG_AUTHPRIVLOG_CRONLOG_DAEMONLOG_FTPLOG_KERNLOG_LPRLOG_MAILLOG_NEWSLOG_SYSLOGLOG_USERLOG_UUCPLOG_LOCAL0LOG_LOCAL1LOG_LOCAL2LOG_LOCAL3LOG_LOCAL4LOG_LOCAL5LOG_LOCAL6LOG_LOCAL7LOG_EMERGemergLOG_ALERTalertLOG_CRITcritLOG_ERRerrLOG_WARNINGwarningLOG_NOTICEnoticeLOG_INFOinfoLOG_DEBUGdebug;X8 8L`(X(X(<P8|Xx$@8\hp((XzRx $XFJ w?:*3$"D\pTFGB A(A0JOJNKIb 0A(A BBBH 8)HQP&HQ( hEAD@  AAG 8 $L($`D$(t`zBDH ` NIE EVEVEVEVEV,EVHEVdES$(FAA m ABA oEu F V A Ha A (D)FDF OCB,HmHMGNUh- GVfq|  "X- `- o`  0  p h o0 oo op-  0@P`p 0@P`pGA$3a1-" GA$3p1067 "GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY 5GA+GLIBCXX_ASSERTIONSsyslog.so-1.8.7-16.el8.x86_64.debug'7zXZִF!t/]?Eh=ڊ2N2ZT\|]ܹEOp2<_#O9220Z `evqWX Ayskߨ,8V[Ġ,]\UM F }A/٤ F^P.du~*BMv!7=:t/+6Y=WgEq=j3yOSQgVZq`jAts@+2Z%b[hl+FH+Rl`1iEG=R<Rs䁩f_a*z:(ӐMZinnG 5vu'Z)T/?!22bPaKCl~b)>O&!}I>$vuiG- siTNZJPdГ9I@Ӥ(@1Gќ>f*;F61Q53 FF;i^doL?ΦD~%Bf Qu~=R mY&yv b_ݑ}-N(0fy3Ys(Xi%|^`)Xb AKy|2'F7>,5%q- յtDžxKrLᯩ@?_`>?,-I3T}:\vE 5^16*V ɋ F˂&Zm0$ #u F+̉~ kk2t].(6wceeގJ?OxÊ.LSTs=C &/9Tܦ7Y/BԷnyXA~"S~y|6eV񧹣prPhϑmƝY-4:q{]hHʏ9_f ib!V Q=^~v2u422euwgU^dVd;,3=m Z oi(_}dS6(ôV4ua|; _t۾6.$ drɱgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 808o ZEo0 0 @Tp p h^B hcnw``} " " 20"0"'X%X%8&8&H)) X- X-`- `-h- h-p- p-0/ /`0 01 1 1 1(81` 1HT3("|3T71PK|]ʏx86_64-linux/re.hnu[/********************************************************************** re.h - $Author: shyouhei $ $Date: 2011-05-21 07:29:10 +0900 (Sat, 21 May 2011) $ created at: Thu Sep 30 14:18:32 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef RE_H #define RE_H #include #include #include "regex.h" typedef struct re_pattern_buffer Regexp; struct RMatch { struct RBasic basic; VALUE str; struct re_registers *regs; }; #define RMATCH(obj) (R_CAST(RMatch)(obj)) #define RMATCH_REGS(obj) (R_MATCH(obj)->regs) VALUE rb_reg_regcomp _((VALUE)); long rb_reg_search _((VALUE, VALUE, long, long)); VALUE rb_reg_regsub _((VALUE, VALUE, struct re_registers *)); long rb_reg_adjust_startpos _((VALUE, VALUE, long, long)); void rb_match_busy _((VALUE)); VALUE rb_reg_quote _((VALUE)); RUBY_EXTERN int ruby_ignorecase; int rb_reg_mbclen2 _((unsigned int, VALUE)); #define mbclen2(c,re) rb_reg_mbclen2((c),(re)) #endif PK|]|qqx86_64-linux/stringio.sonuȯELF>0@j@8 @0M0M ]] ]  (](] (] 00888$$MMM StdMMM PtdPBPBPBQtdRtd]] ] GNUClD@[Pᶛ'& H@ AHK1BE|qX` D{M4` f +fp6t' ]U lAXl~L, (]vF"M6 09Ga Za Na __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_gc_markrb_rsrb_str_substrmemchrrb_scan_argsrb_string_valuememcmp__stack_chk_failrb_str_newrb_string_value_cstrrb_io_mode_flags__errno_locationrb_sys_failrb_fix2intrb_io_modenum_flagsrb_str_resizeruby_xfreerb_class_new_instancerb_block_given_prb_yieldrb_ensurerb_data_object_allocrb_eIOErrorrb_raiserb_str_modifymemsetrb_check_typerb_class2namerb_eTypeErrorrb_cFixnumrb_cFalseClassrb_cNilClassrb_cSymbolrb_cTrueClassrb_call_superruby_xmallocrb_eof_errorrb_num2longrb_num2intmemmoverb_int2inumrb_securerb_eArgErrormemcpyrb_ary_newrb_ary_pushrb_lastline_setrb_notimplementrb_convert_typerb_uint2inumre_mbctabrb_frame_this_funcrb_enumeratorizerb_str_catrb_obj_as_stringrb_str_updateInit_stringiorb_cDatarb_define_classrb_mEnumerablerb_include_modulerb_define_alloc_funcrb_define_singleton_methodrb_define_methodrb_io_addstrrb_io_printrb_io_printfrb_io_putslibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.14GLIBC_2.2.5GLIBC_2.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64=@_ui jii vui j] ]  ]  ] X_ `_ h_  p_  x_  _ _ _ _ $_ '_ )_ +_ ._ 2_ 7_ =_ >_ @_ A_ B_ F`  ` (` 0` 8` @` H`  P`  X` `` h` p` x` ` ` ` ` ` ` ` ` ` ` `  ` !` "` #` %` &a (a *a +a , a -(a /0a 08a 1@a 3Ha 4Pa 5Xa 6`a 8ha 9pa :xa ;a <a ?a Ba Ca Da Ea GHHI HtH5bI %cI hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3%F D%F D% F D%F D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%}E D%uE D%mE D%eE D%]E D%UE D%ME D%EE D%=E D%5E D%-E D%%E D%E D%E D% E D%E D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D D%D DH=D HzD H9tHB Ht H=QD H5JD H)HHH?HHtHEB HtfD= D u+UH=:B Ht H=^? dC ]wHtH?AWIAVAUATUSHHdH%(H$81!HJA HHD$(M/IOMML9MuHD$(K,IHL`MtkI)IM9$LHL6IH+jIGIoH$8dH3 %(|HH[]A\A]A^A_DHH9tW; tHDH9t#x HxmH H)mHuHHLH)L)iAOcfH\$(1HR H H|$(u2M/IOMML9}ImLLHLH):DHxIN4#L9H@Lt$IHD$IHD$K&H9Ht$LLLL$H $H $LL$uHl$II)_H@LHHL$L $05L $HL$H/HhII) @HhLXH$0HD$0fDL HH9uMIt'LLDHrHD0HuM9MMxbLLF4LL)L)LG84t4@HD08u#HBH9uHuN "J, h@NT0M9|UIR^ff.AUATUSHHH(dH%(HD$1Ll$Ld$MLŃtHtsHD$HHCHCHD$dH3%(H([]A\A]@L@HD$HHD1H=CxfDH|$@uuLHHC}w@@LHD$Ct`u\HtTHtK1 IfkKHCfD1H@GG~fDSVHu H[DH=i< HH[HkfDH H~1@uHtHuPH8< H5H81ff.@AUIATUHSHHH?H}ItLgL9~M9|)H[]A\A]fDH[]A\A]9fHEL1L)HxH[]LA\A]ff.PXH5 HHt; H81fS"HRHkH9CuHC [u:HtLHt;HtYtHH{kH5HH: H81`H: H8H: H8H: H8H: H8H: H8@AUIATAHUHSHAHHt)11HLDHH[]A\A]@ VHHH@H@HHCH] PXH5HH$: H81rfHHt1HfHHtSp@tEHHPH;Q}(HIHrHpHHH%HfDpH VfDHHtH3HHt Hff.@SHHtH[@HHt Hff.@HsHtH@H@`H{ff.H3Ht HOff.@HHt@tHHJH9HHH DHHt@HHHHt@HHHcHt@HHwSH3HtH[T@ATUHSHt%IIHHtL`H[]A\fDHIfDHHtHHSHHtH`H[fAVAUATIUHSiHH@HbtqH;HKLoHHqIL9 HGH@8(t!1HPHCHpHLpLHs@(HHt HL tQc[]A\A]A^fDSlfDIuHLHpH~HH@ItI$H Cff.HCHt HxH\ff.HHt HxH,ff.UHSHHt$HtH@u HubcH|$jHD$uHtHH҃SHCHCHH[]fHEuAUATIUHSHdH%(HD$1%H H@H$tDt%Hf4 H5MH81ID$HH$H<$I$H<$HdHHSH<$tH HIH9K^EH HsIE1HHiH)H9HOHH$HsHHxHHpH$HHhHkL9EHL$dH3 %(H[]A\A]fDH HsHAH9}kH)AIHSHHH$Hy1Cu11H$cf.KbK1HtLH$AfDH(HuSHt1m1A'-HH[2 H5H81fHsHt HxtHff.ATAHUSHHdH%(HD$1vHHHI1HD1aHHEH<$Ht@tPHHtUHuYHEHXHeH]HL$dH3 %(H[]A\DHHuH]@HtH=$@HHNH0 H5H818C1ff.AUIATAHUSH4HtOHHCu7@HHCt"HLDHuHH[]A\A] ff.UHSHHHt(@t'HHAHH&HH[]bfHHtHPXHHNHtoff.@ATH HUSHH"H9tYHIHHtxHHtH{ GG~4Hk HtLH بu Iu,@EH[]A\@+Hk Ht@I$%H DATIUSHӃu HuZ(u#I4$HtN@uH@tB?u8HHt9HLH[]A\fDHuDH1[]A\DUHSHHt3H@t HHHx$HCHcH[]HxL1ff.@HSHtPtPHaH- H5H81fHHtPtPHHB- H5H81fHHtPtPHH, H5 H819fSGt6HHuHu-H[HtH[H, H5 H81ff.AUATUHSHHtxH}L @t4HHMl$Hx\HL)L9$HH[]A\A]fDHHI|$H1L)L+HH[]A\A]CH= HSHtHHtHxHcH+ H5 H81ff.AWAVAUIATUSHFLIH@HH@LsHkI9vSL%* DHcI $DT5) HcI9BHHcHIGHIGI9wHL[]A\A]A^A_;HL1H[1]HA\A]HA^A_fLff.USHHH|H@tn7u&AHRHHHMH<HH-HUHEH;B|HH[]DHH1H[1]HHY@AUIATIUHSHRHtyHu?HCtQHLHuHL[]A\A]fHLH[L]HA\A]Hff.@AUIATUHSHHH&H@HHAH;yC@Hs1HHHPHCHHHKD$HHt!HL uIt IUH HH[]A\A]@rE?cH}XHEH;D C@[HHpHsOf.H8Aff.AUIATUSHHgHHHH?~LcMH} H}HGE@~HEHsLnHEHt!HL uIt IUH LeHL[]A\A][HHLcMwH[]A\A]HuH9yLH1HuH}HL`yfH5& SH=H0HH& HH00HH51H߹HH5H߹HwH5H߹HH5spH߹H1H5hU1HHH5=H߹H~H5<"1HH6H5, H߹HH51HHH51HHKH51HHH51HH{H51HHSH5w1HH H5_1HHH5G1HHkH5/1HHSH5H߹HH5~1HHH5l1HHH5Z1HHH5HH߹HH511HHMH5H߹HH5 f1HHH5NH߹HH531HHH51HHOH5H߹HH5H߹HH5H߹HH51HHH5b1HHH5T1HHH5Bj1HHH54R1HHH5,:1HHH5 "H߹HH5H1HH5H1HH5H߹H8H5H߹HmH5H߹HH5H߹HgH5kH߹HH5qPH߹HH55Hv! H߹H5CH{! H߹H5+HP! H߹H5H߹HUH5H H߹H5H߹H_H5H1HH5{H1HH5cH1HH5KH1HH53H1HH5~H1HH5kH[H#H5VHH02not modifiable stringnot opened for readinguninitialized streamnegative length %ld given11closed streaminvalid whenceto_strioStringIOnot opened for writingnegative legnthnot openedinitializeinitialize_copyreopenstring=linenolineno=binmodecloseclose_readclose_writeclosed?closed_read?closed_write?eofeof?fcntlflushfsyncpospos=rewindseeksync=tellpatheacheach_lineeach_bytebyteseach_charcharsgetbyteungetcreadcharreadbytegetsreadlinereadlinessysread<<printprintfputcputssyswriteisattytty?pidfilenosizelengthtruncatewrong argument type %s (expected StringIO)wrong number of arguments (%d for 0)closing non-duplex IO for writingclosing non-duplex IO for reading;8P(<0 p | Pp (H dPpP (D`|Pp <0XPPLxPHd` (  ` P zRx $`PFJ w?:*3$"D@\pHp|BBEB B(A0A8G 8A0A(B BBBF 8BBA A(NPi (A ABBE  :EU F N,@1YXTHBEA D(G0h (A ABBG D (A ABBN T(A AEB|AAKA_ A 8FEG D(D0h (D ABBE $XAAK@\HP A \`jHu S O A |HO A !HS A EQ A !HS A 5Hg A !HS A $;Hb G @<)HU G \P)HU G xd)HU G xEQ A (|JFAD c ABG HQ A 'E\ A <"FBB D(D0 (F BBBG T$HR E p$HR E (EDD0~ AAC 8D~FBD F(D@M (A ABBG $HV A 0DFGA G0  AABF 8DuFEG A(D0J (D ABBA (NEDI l DAA  HO A $!EAD,8FOA r ABE 8FDC a ABG V ABE (P,aEDD m AAD |pGHa A GHa A GHa A  UAf I L A HHFBA D(D0 (D ABBG i (D ABBA @EH[ E `\FBB E(A0A8D@ 8D0A(B BBBH I 8J0C(E BFBE 4|EAG X DAF I JCL LFED F(D0D (D ABBJ I (J DEBI 8HD5FEA D(D0 (D ABBD LH7FEA A(G0 (D ABBH \ (F ABBA 8LGNU ] %3=  L?] ] o`   ` `@ ooofo(]  0@P`p 0@P`p 0@P`pGA$3a1Y? GA$3p1067I?GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY GA+GLIBCXX_ASSERTIONSstringio.so-1.8.7-16.el8.x86_64.debug)"7zXZִF!t/]?Eh=ڊ2NnL$Hѵ?tIכ4/7Mr=4JbC&Un [VVfa˱Ln'3G8w.=okҍ 秙CRB։9Yu&~E;}^[RY8?S hZ V~>J*åtRݞL+AnLLz;yfZƽkVUQ+>yi5\.±' KMV@Sd02" yN^קI-MUH$̮jpT/ !;1'u;4sK'JC+(+Ig!ՋwjezC}#@Z@8 @CC LL L P LL L ``888$$CCC StdCCC Ptd<<<DDQtdRtdLL L ``GNUErCANϧq6jjX@ XZ|CEqX}BWmWaDp w }T.Z , S"F";Noc9 :wL  0DeU.sg+tD'8R Q Q  `5__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_str_new2rl_instreamfileno__fdelt_chkrb_thread_select__stack_chk_failrb_attr_getrl_attempted_completion_overrb_tainted_str_new2rb_internrb_funcallrb_Arrayruby_xmallocrb_obj_as_stringstrcpy__ctype_b_loc__ctype_tolower_locstrncpystrduprb_string_value_ptrrl_username_completion_functionrl_completion_matchesrb_ary_newrb_ary_pushfreerb_ary_shiftrl_filename_completion_functionrb_securehistory_lengthrl_filename_quote_charactersrl_completer_quote_charactersrl_basic_quote_charactersrl_completer_word_break_charactersrl_basic_word_break_charactersremove_historyrb_int2inumhistory_baserb_yieldhistory_getrl_completion_append_characterrb_string_valuerb_check_safe_objadd_historyruby_xreallocrl_emacs_editing_moderl_vi_editing_moderb_ivar_setrb_scan_argsisatty__errno_locationrb_stdoutrb_check_typerb_io_taint_checkrb_io_check_closedrb_stdinrl_outstreamrb_protectrl_cleanup_after_signalrb_jump_tagrb_eIOErrorrb_raiserb_eIndexErrorrb_fix2intrb_num2intreplace_history_entryrb_str_newrb_respond_torb_eArgErrorInit_readlinerl_readline_nameusing_historyrb_define_modulerb_define_module_functionrb_define_singleton_methodrb_cObjectrb_obj_allocrb_mEnumerablerb_extend_objectrb_define_constrl_library_versionrl_attempted_completion_functionrl_event_hookrl_clear_signalslibruby.so.1.8libreadline.so.7libncurses.so.6libtinfo.so.6libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.15GLIBC_2.4GLIBC_2.3/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64 ui , 8ii Cii Mui ,L #L p#L L O  O (O 0O 8O  @O  HO  PO XO `O hO pO #xO %O &O 'O )O *O /O 1O 2O 3O 6O AO HO IO NO OO PO SP  P (P 0P 8P  @P  HP PP XP `P hP pP xP P P P P P P P P  P !P "P $P %P (P +P ,P -Q .Q 0Q 4Q 5 Q 7(Q 80Q 98Q :@Q ;HQ <PQ =XQ >`Q ?hQ @pQ BxQ CQ DQ EQ FQ GQ JQ KQ LQ MQ QQ RQ TQ UQ VQ WHH3 HtH5r4 %s4 hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:A%0 D%0 D%0 D%0 D%0 D%0 D%0 D%0 D%}0 D%u0 D%m0 D%e0 D%]0 D%U0 D%M0 D%E0 D%=0 D%50 D%-0 D%%0 D%0 D%0 D% 0 D%0 D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%/ D%}/ D%u/ D%m/ D%e/ D%]/ D%U/ D%M/ D%E/ D%=/ D%5/ D%-/ D%%/ D%/ D%/ D% / D%/ D%. D%. D%. DH=. H. H9tHF, Ht H=. H5. H)HHH?HHtH , HtfD=u. u+UH=+ Ht H=) 9dM. ]wH=e@ATUSHdH%(H$1ILHH-(+ H}?H}4HcH} ?)ѺHH E111Lx%H$dH34%(uHĐ1[]A\ff.@AWAVAUATUHSH8H5|- H=}- hHH5W- HH=]- H* ;HHD$H=?HHHH1Htu<t IŃ? t H%IMuE E~McILHD$E~UAF1H,f.IE H<IH@HxHT$HHDIt$HH9uHD$JD8AHD$HT$D$HLjHD$ AFHDHD$(fDMeH|$ A$E1H(?fDIEJ 8DMHHL$tsHL$HIt09u,CH_% H8HtHfDHfDHH% H8HtHFfDHfDHH5' H=' HHH5' H=' HgUSHYHtH8HH;HgH_HH[]DHH# 8~1HfDHfDHH# Hc8Hff.AUIATUSHH-# E~71L%f# @H8H9]~A<$HuHL[]A\A]fSHHHt$%H|$uH.# HH[H|$H|$HD$HxtH@H" HH[AUIATUSHHdH%(HD$1t;EHLdHHCHH$,H<$CH$HxL9uHL$dH3 %(Lu H[]A\A]~ff.SHHHt$H|$H|$HD$Hx3HH[f.SHHHt$H|$kH|$H=$ HD$HtPHpHHd$ HHD$HHPHp$HHD$H@H=! HHH[ÐHxH3HH$ SHHHt$H|$H|$H=# HD$HtPHpHSH# HHD$HHPHptHHD$H@HE! HHH[ÐHxHHHY# SHHHt$UH|$ H|$!H=# HD$HtPHpHH" HHD$HHPHpHHD$H@Hu HHH[ÐHxHHH" SHHHt$H|$[H|$qH=Z" HD$HtPHpHH<" HHD$HHPHpHHD$H@He HHH[ÐHxH#HH! SHHHt$H|$H|$H=! HD$HtPHpHCH! HHD$HHPHpdHHD$H@H HHH[ÐHxHsHH1! HN1BHH1HSHH5 H= H[ATIUSH dH%(HD$1H\$LD$HHL11S~H7H|$MHD$Hh1ud8 H H;WH;oHXHHCHH HH H;HH;0HXHHH HH=` HHT$cHËD$ueHD$u8HtHHHHL$dH3 %(Hu%H []A\@HtH뾐HB|$H H5GH81ff.fPXH54HH H81fSHH߃t&H x&9~&1[VfDH yy1HH ~11H@HfDSHNH߃t6y H. H HtH8[vfD@SHHHT$H߃tMH|$H|$y H HD$1҉HpHtHD$H[{bfSqH t$H=g3 HP [f[fSHH=HHtH5 H= H[H H5H81@USHHHP HH=H=H H=Hs HH5HHa H=U HH5]H=6 1HH5VAH= HH5"H= 1H"H5+H= 1HH5]H= 1HZH5QH= H[H5EH= 1HH5FH=l HPH5CtH=M 1H4H5DXH=1 HeH5v9H= 1HH5H= HzH5H= 1H>H5H= HH5H= 1HH5H= HH5H=a 1HHH5lH-  H}HHR HH0g1HHH5/H߹HH5H߹HH5H߹HH5H߹HH5u1HHwH5b1HHH5N1HHH5<{1HHoH5)c1HHWH5K1HHH53HHH5H= HH5RH}iHH5HHH= HH5H},HH5HHH=w HH5HH H82H=K H5tHH HH HHH[]HHHISTORYcall02stdin closedinvalid indexRubycompletion_proccompletion_case_foldReadlinereadlinecompletion_proc=completion_case_fold=vi_editing_modeemacs_editing_modecompletion_append_character=completion_append_characterbasic_word_break_characters=basic_word_break_charactersbasic_quote_characters=basic_quote_characterscompleter_quote_characters=completer_quote_charactersfilename_quote_characters=filename_quote_charactersto_s[][]=<<pushpopshifteachlengthsizeempty?delete_atFILENAME_COMPLETION_PROCUSERNAME_COMPLETION_PROCVERSIONargument must respond to `call'completer_word_break_characters=completer_word_break_characters;D'`4pt P ,PLl@ 4\@@$PHl0`@`$D`d0zRx $XFJ w?:*3$"D\H0pDFFA G  CABA HFBB B(A0D8DpO 8A0A(B BBBB <FAF D0w  DABA L DAB<0FAF D0w  DABA L DABpd+H\|:MX K I:MX K I:MX K I:MX K I:MX K I()H\@4)H\$XLKAFK sDAt:M[ H I%HX4nFJA A(D0N(D ABB$yEL c DH tD8<FEA H(G@k (A ABBA TFEL pD tEL y DB \EL y DB EL y DB tEL y DB EL y DB ((H_@(H_X)E_0tFDH D@A  AABE LAAKP_Ep K :H_ I I\E@ K ~EL Z AD DPGEq J Fd\Ez E (EAK AAGNU#p#L  W p :L L o`8   P  oxoooL  0@P`p 0@P`p 0@P`p 0@GA$3a1p): GA$3p1067#:GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY##GA+GLIBCXX_ASSERTIONSreadline.so-1.8.7-16.el8.x86_64.debug`l$Z7zXZִF!t/]?Eh=ڊ2NthO̗W/Qg ZWz=~?Pl@uی~4e$1uh=&iԶ{"}'Hv -RMlCZ^g}Z}6(tqavsq]@l/h>C٥Q6ǫk< ʑ#aB3B*MWyYP OsNkDѮ+w)md+&ì" [ =9faHrq-]!.ߪs˪gcVm$prPW&HUZ'i{1V =C]hAztm@䊪TQHVs̘pj]\aw2C enKCjL,(1cَWHCG5+m 7< D G QEze&\A "vĹVrnrZŁ/e#!h6~$P.)Š8)zPRE>#zKo{F Uڣf7:*G'8iQ3)BuX}u^]\gJ z>/=޴dr[:f@:LT`u QnvXT6s;"IHsqk+F>&?K:fx< R&:XqrX}04TFXj C +`暯gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 08 8 8oEoxxpT^BhppcnPPw##}:: 20:0:<<D>>CC L LL LL LL L`O OP PQ QH8R`QH 8T,dTlY+PK|]uRx86_64-linux/fcntl.sonuȯELF>@@8 @    00888$$ Std Ptd $$QtdRtd hhGNU.!Y2E{ bz  BE|qXϫq  `, F"}8 @ 8 U __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeInit_fcntlrb_define_modulerb_int2inumrb_define_constlibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64ui   P         ( 0 HH HtH5 % hhhh%m D%e D%] D%U DH=Q HJ H9tH Ht H=! H5 H)HHH?HHtH HtfD= u+UH= Ht H=6 Id ]wSH=1HH5yHHH5eHHH5QHHH5=HHuH5)HHYH5HHw=H5HH[!H5HH?H5HH#1H5HH H5HHH5HH@H5HH|H5|HH`H5gHH~DH5THHb(H5@HHF H5-HH*H5HH1H5 HHH5HHHH5HH[H5HHFcntlF_DUPFDF_GETFDF_GETLKF_SETFDF_GETFLF_SETFLF_SETLKF_SETLKWFD_CLOEXECF_RDLCKF_UNLCKF_WRLCKO_CREATO_EXCLO_NOCTTYO_TRUNCO_APPENDO_NONBLOCKO_NDELAYO_RDONLYO_RDWRO_WRONLYO_ACCMODE;$P@hzRx $PFJ w?:*3$"D0@\ErGNUP  0 (   o` 5  `( oooo `pGA$3a105 GA$3p1067( GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realignfcntl.so-1.8.7-16.el8.x86_64.debugn'7zXZִF!t/]?Eh=ڊ2NpI Q{H ;rw/ɡ";Ƣ6cv'xp5''Cn`V['HفH¨ I Db\6 ]G}$FWʿPB[K3(T!(r ,1[ cCWps SQFEI8n!It}[ \JlҔoaL&J&MNJ*pid*U}g(6Wy{aNajnK/uсhe,=*34 8Hu. R=<1^rRl)y Gh Y ZS.9K! 6nv9CaHh/$:PfO<6#S8fź!K  h#k:h9yæR6\ rK_R' +@8@8 @!! -- -  -- - 00888$$ Std Ptd,,,QtdRtd-- - xxGNU 3@82{s(D0(*BE|UqX Oc l\U`F =(}t, F"1h(1 {P1  2o(1 __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_ary_newrb_tainted_str_new2rb_ary_pushrb_uint2inumrb_struct_newgetgrentendgrentsetgrentrb_yieldrb_securerb_string_valuerb_check_safe_objgetgrnamrb_eArgErrorrb_raiserb_num2uintgetgrgidsetpwentendpwentrb_sys_failgetpwentgetpwnamrb_scan_argsgetuidgetpwuid__stack_chk_failgetlogingetenvrb_block_given_prb_ensurerb_eRuntimeErrorInit_etcrb_define_modulerb_define_module_functionrb_global_variablerb_struct_definelibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.4GLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64^ii ui - 0- - - / / / !/ $/ %/ &0  0 (0 00 80 @0 H0 P0  X0  `0  h0  p0  x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1  1 "1 #1 & 1 'HH! HtH5! %! hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D%  D% D% D% D% D% D% D% D% D% D% D% D% D% DH= H H9tH6 Ht H=q H5j H)HHH?HHtH  HtfD=- u+UH= Ht H= Id ]w ff. ff.AVAUATIUSI\$HH;HtHHH|H;HuA|$H~I|$IHHDI<$IHHDlH=E [IL]LA\HA]1A^jf.HsHtHH1@HfDHHfHHfHsH1HHuHDHHt$H|$OH|$HD$HxHtH1hHHD$H5HPH H81RfSHHHHt H[1 Hu H5H81fHHfH#HfAWAVAUATUSHHHH(H-QHHD_H{ IHHDLH{IHHD9{I{HD$H{H$HHD H;IHHDHMLjH= H1AUATLD$(HL$ H8[]A\A]A^A_H={DHH1HHuHDHHtHH1HfDHH|$Ht$ H|$oHD$Hx!HtH1rHHD$H5HPHv H81 ff.UHSHdH%(HD$1G1HHH|t<'ÉHt;H1HT$dH3%(uH[]H<$H H5H81T@HHtHHH=Hu۸HDH^t+ uE1H1n H=ZHtHH1fHH H5[H81~ff.Ht+ uE1H1 H=OEHtHH1RfHHO H5H81ff.HH=|1HsH5HHR =H=F HH5H=' H H5H= 1H_H5}H= 1HcH5jH= 1HH5WH= 1HH5H= HH5%pH=y H H5QH=Z 1HH55H=> 1HuH5H=" 1H9H5H= 1HH5H= HHL jLoH ;PHHPH5H=1.H H= H gE11LjH HcH5?H=RHc HHHcan't find group for %scan't find group for %d/etc/passwdcan't find user for %s01can't find user for %dUSERparallel group iterationparallel passwd iterationEtcgetlogingetpwuidgetpwnamsetpwentendpwentgetpwentgetgrgidgetgrnamgroupsetgrentendgrentgetgrentgecosnamePasswdshelldirmemGroup;44(T<x$Ddd0Hd d@dzRx $(0FJ w?:*3$"D0 \p8BBB D(A0q(G EEDt*HQ G IHNHN;Hr(nH D A DNEh G `DHNxLHNTTBBB B(A0A8DPXH`NhBpS8A0A(B BBBAP;Hr*HQ G I dH z A (<hEDK0a AAI hKH[ M Z HO I I A HO I I A (2HP O(O0YKGNU0-  0;FT^  - - o`  0 0   o oo| o- @P`p 0@P`p 0@PGA$3a1 GA$3p1067@GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY@TGA+GLIBCXX_ASSERTIONSetc.so-1.8.7-16.el8.x86_64.debug2TU7zXZִF!t/]?Eh=ڊ2N :t'' AA":Xzu֑:Ebͼ;v-3Y ¦Hր uVH<1fI6!H3"NXIe|b2I~!ݼD@\&P}'8w]w%E[߿:fH."lbe ߩ"A 琳yW5A-!]}1 X+V[9k׿5qYMܿ!?G Zq,f_.7G]€]N Vh66;1#OT@mxGa< zIsm7W6RݍTRDvwX y C{=W@+)U~y~}=$J`2i!1oBPZEc&WV P _2J9H=ifj)zO+4hjtZSxox-ȟ'nl@,"4e>U4cɨϰaD;r-P? *H[+IwܚٔnkV y>8g]\…:a% Y뤥D# @NMIϢSq(ht❬QdEWD 6a~ɢx7F2he)4蓜!FgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4(  08o| | XEo 0T  ^B 0hc000n`` wb } 28,, - -- -- -- -0/ /00 0((1 (1(P1`(1H p3(37+PK|]39 x86_64-linux/missing.hnu[/************************************************ missing.h - prototype for *.c in ./missing, and for missing timeval struct $Author: shyouhei $ $Date: 2010-11-22 16:21:27 +0900 (Mon, 22 Nov 2010) $ created at: Sat May 11 23:46:03 JST 2002 ************************************************/ #ifndef MISSING_H #define MISSING_H #if defined(HAVE_SYS_TIME_H) # include #elif !defined(_WIN32) # define time_t long struct timeval { time_t tv_sec; /* seconds */ time_t tv_usec; /* microseconds */ }; #endif #if defined(HAVE_SYS_TYPES_H) # include #endif #if !defined(HAVE_STRUCT_TIMEZONE) struct timezone { int tz_minuteswest; int tz_dsttime; }; #endif #ifndef HAVE_ACOSH extern double acosh _((double)); extern double asinh _((double)); extern double atanh _((double)); #endif #ifndef HAVE_CRYPT extern char *crypt _((const char *, const char *)); #endif #ifndef HAVE_DUP2 extern int dup2 _((int, int)); #endif #ifndef HAVE_EACCESS extern int eaccess _((const char*, int)); #endif #ifndef HAVE_FINITE extern int finite _((double)); #endif #ifndef HAVE_FLOCK extern int flock _((int, int)); #endif /* #ifndef HAVE_FREXP extern double frexp _((double, int *)); #endif */ #ifndef HAVE_HYPOT extern double hypot _((double, double)); #endif #ifndef HAVE_ERF extern double erf _((double)); extern double erfc _((double)); #endif #ifndef HAVE_ISINF # if defined(HAVE_FINITE) && defined(HAVE_ISNAN) # define isinf(x) (!finite(x) && !isnan(x)) # else extern int isinf _((double)); # endif #endif #ifndef HAVE_ISNAN extern int isnan _((double)); #endif /* #ifndef HAVE_MEMCMP extern int memcmp _((char *, char *, int)); #endif */ #ifndef HAVE_MEMMOVE extern void *memmove _((void *, void *, int)); #endif /* #ifndef HAVE_MODF extern double modf _((double, double *)); #endif */ #ifndef HAVE_STRCASECMP extern int strcasecmp _((char *, char *)); #endif #ifndef HAVE_STRNCASECMP extern int strncasecmp _((char *, char *, int)); #endif #ifndef HAVE_STRCHR extern char *strchr _((char *, int)); extern char *strrchr _((char *, int)); #endif #ifndef HAVE_STRERROR extern char *strerror _((int)); #endif #ifndef HAVE_STRFTIME extern size_t strftime _((char *, size_t, const char *, const struct tm *)); #endif #ifndef HAVE_STRSTR extern char *strstr _((char *, char *)); #endif /* #ifndef HAVE_STRTOL extern long strtol _((char *, char **, int)); #endif */ #ifndef HAVE_STRTOUL extern unsigned long strtoul _((char *, char **, int)); #endif #ifndef HAVE_VSNPRINTF # ifdef HAVE_STDARG_PROTOTYPES # include # else # include # endif extern int snprintf __((char *, size_t n, char const *, ...)); extern int vsnprintf _((char *, size_t n, char const *, va_list)); #endif #endif /* MISSING_H */ PK|]ߖ P Px86_64-linux/racc/cparse.sonuȯELF>@H@8 @ 4 4 X=X= X= P p=p= p= 00888$$444 Std444 Ptd@0@0@0QtdRtdX=X= X= GNU{6Lt4u;˶0A @023BE|qX7/m fyI 0U@*{5, Y F"eUs`N8A A 8A  +__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_gc_markrb_ary_storerb_int2inumrb_funcallrb_check_typerb_catchrb_ivar_getrb_fix2intrb_num2intrb_num2longrb_ary_new4rb_ary_poprb_ary_newrb_eTypeErrorrb_raiserb_class2namerb_id2namerb_cFalseClassrb_cFixnumrb_str_newrb_cTrueClassrb_cSymbolrb_eArgErrorrb_hash_arefrb_ivar_set__stack_chk_failrb_iter_breakrb_ary_new2rb_iv_setruby_xmallocrb_data_object_allocrb_iterateInit_cparserb_internrb_cObjectrb_const_definedrb_const_getrb_const_get_atrb_define_private_methodrb_str_new2rb_define_constrb_define_class_underrb_eRuntimeErrorrb_define_modulelibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64ui  ii X= `= Ph= h= ? ? ? ? ? ? ? ? #? &? '? )? /@  @ (@ 0@ 8@ @@  H@  P@  X@  `@  h@ p@ x@ @ @ @ @ @ @ @ @ @ @ @ @  @ !@ "@ $@ %A (A )A *A + A ,(A -0A .HH/ HtH5/ %/ hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#%m- D%e- D%]- D%U- D%M- D%E- D%=- D%5- D%-- D%%- D%- D%- D% - D%- D%, D%, D%, D%, D%, D%, D%, D%, D%, D%, D%, D%, D%, D%, D%, D%, D%}, D%u, D%m, D%e, D%], D%U, DH=Q, HJ, H9tH* Ht H=!, H5, H)HHH?HHtH* HtfD=+ u+UH=* Ht H=' d+ ]wSHH? H{H{H{(H{0H{8H{@H{HH{PH{XH{`H{pH{xHHHHH[wATIHUHSHHHw@u&HHH[H]A\HwHLHwH{L1LLH5* %S"HHC 1Hp Hx1[fUHSH)HHHHH5H=tH{H5* H t8HHHtQH[]f.KH[]@HXfDHx+HWHHO H9HNH)HH4Zf.f.AWAVAUATUSH"HH(Hk HEpHH@ HHLtL|$HA7IH) HLI9 LH0LHD$H@ HHD$HI@LpIu<HD$L@L@HuLL9=( Mt9DH}E3LL$HL$L1LHD$IpHT$L}DEHHBH9SHR H\FHANIL+uhHE`L9p~]H@ JH HH! MH5AH81_H }Hff.@AVAUATUSHHHt$H$HAHHC@H9PH@ H,H @HHEtmHtgDKEnHHH[]A\A]A^@HH{xHt$HHBYtHHHC(H9hrH@ L,I`AIHC0H9hEH@ HH81f.AUIATIUHSHHHxHHHHHHǀ1H)HHH= QLHHD$1H|$IAH1ɺCHD$HH[]A\A]ff.fAWMAVIAUIATIUHSHHHxHHHHHHǀ1H)HHH= gMLLHD$1H|$HI1ɺHCHD$*H3HH=H1HtHH[]A\A]A^A_H{ 8H5IHHO H81 ff.fATH=USH- HHH}vH}H"H=ILHhHH߹HH5]HNHH5SH=WH5QHHAH=HH5LH#HUH5PLH=NH H3 HH H=#H H= H H=H H=H} H=Hb mH=HG ZH=H, GH=H 4H=H !H=H []H A\fH=HUH5HIHaHHracc_jumpnot symbolreturnednext_tokenyielded$%s() %s %s (must be Array[2])token given after EOFextra token after EndOfToken[Racc Bug] wrong arg.size %ld@vstack@tstackRaccParser_racc_do_parse_c_racc_yyparse_c1.4.5Racc_Runtime_Core_Version_CRacc_Runtime_Core_Id_CCparseParams@yydebugon_error_reduce_none@racc_error_statusracc_shiftracc_reduceracc_acceptracc_read_tokenracc_next_stateracc_e_popstate stack unexpectedly empty%s() %s wrong size of array (%ld for 2)[Racc Bug] unknown act value %ld%s() is finished before EndOfToken$originalId: cparse.c,v 1.8 2006/07/06 11:39:46 aamine Exp $;`` (Dp|00`@<pzRx $hPFJ w?:*3$"D@\xE(xBGD t DBI .Eh4AIJ O AAK I AAE 6X FBB B(A0A8O`/ 8F0A(B BBBE hTpYhA`@hBAA D0j  AABJ   AABC XBBB A(A0G@ 0A(A BBBE L 0A(A BBBD (lEDO@w AAA H4BEE E(I0D8D@ 8D0A(B BBBF 4TFED I(D@(A ABBH#FEE E(D0I8DP 8A0A(B BBBA ,FHA  AIC GNUPh= " ( -X= `= o`x O @ ` ` h o0 oo op= `p 0@P`p 0@P`pGA$3a1(- GA$3p1067-GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYYGA+GLIBCXX_ASSERTIONScparse.so-1.8.7-16.el8.x86_64.debug7zXZִF!t/]?Eh=ڊ2Nع&MV~Xo//*PX5`W.CcE܌4ȳ.~FRMMVg>I&H|Ah,32x!W_%xr- ? >Z&#F=`f}+7nE x,Z;?zwW&d=rD!U ަ$I|qߨP6ڪk:m,h{%@”"IҌdK"5V U'n{  P\pÆ\̙]X m*تZAY*~drRҜ+O*8SdE (dZwEҘjį [n~qȈ5금K8A-dAX'>gW$W"I-oO^6P[\Ƴ"m{-mzw~")Ȇ:%lS^ #wI8wkoS_6q抎i)Ul-o PFUDZ|NWl=| HHk5TX{KtIq{%Nj(cr=5/XS>Лbmg JS9d FiegS]:Gbo\T1d+ݍ4CCsiJ?:!"ZăXQ_9){0yFZLML,6C,!da|$-j:w/C,\Jn>CgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 0xxO8o hEo0 0 0T` ` h^B `h((cPPPn@w}-- 2--@0@000444 X= X=`= `=h= h=p= p=0? ?`@ @88A 8ApA`8AH C(CG+PK|]kkP8WWx86_64-linux/ruby.hnu[/********************************************************************** ruby.h - $Author: shyouhei $ created at: Thu Jun 10 14:26:32 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #ifndef RUBY_H #define RUBY_H #if defined(__cplusplus) extern "C" { #if 0 } /* satisfy cc-mode */ #endif #endif #include "config.h" #ifdef RUBY_EXTCONF_H #include RUBY_EXTCONF_H #endif #define NORETURN_STYLE_NEW 1 #ifndef NORETURN # define NORETURN(x) x #endif #ifndef NOINLINE # define NOINLINE(x) x #endif #include "defines.h" #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #else # include #endif #ifdef HAVE_INTRINSICS_H # include #endif #ifdef HAVE_STDINT_H # include #endif #include #include /* need to include to use these macros */ #ifndef ISPRINT #define ISASCII(c) isascii((int)(unsigned char)(c)) #undef ISPRINT #define ISPRINT(c) (ISASCII(c) && isprint((int)(unsigned char)(c))) #define ISSPACE(c) (ISASCII(c) && isspace((int)(unsigned char)(c))) #define ISUPPER(c) (ISASCII(c) && isupper((int)(unsigned char)(c))) #define ISLOWER(c) (ISASCII(c) && islower((int)(unsigned char)(c))) #define ISALNUM(c) (ISASCII(c) && isalnum((int)(unsigned char)(c))) #define ISALPHA(c) (ISASCII(c) && isalpha((int)(unsigned char)(c))) #define ISDIGIT(c) (ISASCII(c) && isdigit((int)(unsigned char)(c))) #define ISXDIGIT(c) (ISASCII(c) && isxdigit((int)(unsigned char)(c))) #endif #if defined(HAVE_ALLOCA_H) #include #else # ifdef _AIX #pragma alloca # endif #endif #if defined(__VMS) # pragma builtins # define alloca __alloca #endif #if SIZEOF_LONG != SIZEOF_VOIDP # error ---->> ruby requires sizeof(void*) == sizeof(long) to be compiled. <<---- #else typedef unsigned long VALUE; typedef unsigned long ID; #endif #ifdef __STDC__ # include #else # ifndef LONG_MAX # ifdef HAVE_LIMITS_H # include # else /* assuming 32bit(2's compliment) long */ # define LONG_MAX 2147483647 # endif # endif # ifndef LONG_MIN # define LONG_MIN (-LONG_MAX-1) # endif # ifndef CHAR_BIT # define CHAR_BIT 8 # endif #endif #ifdef HAVE_LONG_LONG # ifndef LLONG_MAX # ifdef LONG_LONG_MAX # define LLONG_MAX LONG_LONG_MAX # else # ifdef _I64_MAX # define LLONG_MAX _I64_MAX # else /* assuming 64bit(2's complement) long long */ # define LLONG_MAX 9223372036854775807LL # endif # endif # endif # ifndef LLONG_MIN # ifdef LONG_LONG_MIN # define LLONG_MIN LONG_LONG_MIN # else # ifdef _I64_MIN # define LLONG_MIN _I64_MIN # else # define LLONG_MIN (-LLONG_MAX-1) # endif # endif # endif #endif #define FIXNUM_MAX (LONG_MAX>>1) #define FIXNUM_MIN RSHIFT((long)LONG_MIN,1) #define FIXNUM_FLAG 0x01 #define INT2FIX(i) ((VALUE)(((long)(i))<<1 | FIXNUM_FLAG)) #define LONG2FIX(i) INT2FIX(i) #define rb_fix_new(v) INT2FIX(v) VALUE rb_int2inum _((long)); #define INT2NUM(v) rb_int2inum(v) #define LONG2NUM(v) INT2NUM(v) #define rb_int_new(v) rb_int2inum(v) VALUE rb_uint2inum _((unsigned long)); #define UINT2NUM(v) rb_uint2inum(v) #define ULONG2NUM(v) UINT2NUM(v) #define rb_uint_new(v) rb_uint2inum(v) #ifdef HAVE_LONG_LONG VALUE rb_ll2inum _((LONG_LONG)); #define LL2NUM(v) rb_ll2inum(v) VALUE rb_ull2inum _((unsigned LONG_LONG)); #define ULL2NUM(v) rb_ull2inum(v) #endif #if SIZEOF_OFF_T > SIZEOF_LONG && defined(HAVE_LONG_LONG) # define OFFT2NUM(v) LL2NUM(v) #elif SIZEOF_OFF_T == SIZEOF_LONG # define OFFT2NUM(v) LONG2NUM(v) #else # define OFFT2NUM(v) INT2NUM(v) #endif #define FIX2LONG(x) RSHIFT((long)x,1) #define FIX2ULONG(x) (((unsigned long)(x))>>1) #define FIXNUM_P(f) (((long)(f))&FIXNUM_FLAG) #define POSFIXABLE(f) ((f) < FIXNUM_MAX+1) #define NEGFIXABLE(f) ((f) >= FIXNUM_MIN) #define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f)) #define IMMEDIATE_MASK 0x03 #define IMMEDIATE_P(x) ((VALUE)(x) & IMMEDIATE_MASK) #define SYMBOL_FLAG 0x0e #define SYMBOL_P(x) (((VALUE)(x)&0xff)==SYMBOL_FLAG) #define ID2SYM(x) ((VALUE)(((long)(x))<<8|SYMBOL_FLAG)) #define SYM2ID(x) RSHIFT((unsigned long)x,8) /* special contants - i.e. non-zero and non-fixnum constants */ #define Qfalse ((VALUE)0) #define Qtrue ((VALUE)2) #define Qnil ((VALUE)4) #define Qundef ((VALUE)6) /* undefined value for placeholder */ #define RTEST(v) (((VALUE)(v) & ~Qnil) != 0) #define NIL_P(v) ((VALUE)(v) == Qnil) #define CLASS_OF(v) rb_class_of((VALUE)(v)) #define T_NONE 0x00 #define T_NIL 0x01 #define T_OBJECT 0x02 #define T_CLASS 0x03 #define T_ICLASS 0x04 #define T_MODULE 0x05 #define T_FLOAT 0x06 #define T_STRING 0x07 #define T_REGEXP 0x08 #define T_ARRAY 0x09 #define T_FIXNUM 0x0a #define T_HASH 0x0b #define T_STRUCT 0x0c #define T_BIGNUM 0x0d #define T_FILE 0x0e #define T_TRUE 0x20 #define T_FALSE 0x21 #define T_DATA 0x22 #define T_MATCH 0x23 #define T_SYMBOL 0x24 #define T_BLKTAG 0x3b #define T_UNDEF 0x3c #define T_VARMAP 0x3d #define T_SCOPE 0x3e #define T_NODE 0x3f #define T_MASK 0x3f #define BUILTIN_TYPE(x) (((struct RBasic*)(x))->flags & T_MASK) #define TYPE(x) rb_type((VALUE)(x)) #ifdef __GNUC__ #define RB_GC_GUARD_PTR(ptr) \ __extension__ ({volatile VALUE *rb_gc_guarded_ptr = (ptr); rb_gc_guarded_ptr;}) #else #define RB_GC_GUARD_PTR(ptr) (volatile VALUE *)(ptr) #endif #define RB_GC_GUARD(v) (*RB_GC_GUARD_PTR(&(v))) void rb_check_type _((VALUE,int)); #define Check_Type(v,t) rb_check_type((VALUE)(v),t) VALUE rb_str_to_str _((VALUE)); VALUE rb_string_value _((volatile VALUE*)); char *rb_string_value_ptr _((volatile VALUE*)); char *rb_string_value_cstr _((volatile VALUE*)); #define StringValue(v) rb_string_value(&(v)) #define StringValuePtr(v) rb_string_value_ptr(&(v)) #define StringValueCStr(v) rb_string_value_cstr(&(v)) void rb_check_safe_obj _((VALUE)); void rb_check_safe_str _((VALUE)); #define SafeStringValue(v) do {\ StringValue(v);\ rb_check_safe_obj(v);\ } while (0) /* obsolete macro - use SafeStringValue(v) */ #define Check_SafeStr(v) rb_check_safe_str((VALUE)(v)) void rb_secure _((int)); RUBY_EXTERN int ruby_safe_level; #define rb_safe_level() (ruby_safe_level) void rb_set_safe_level _((int)); void rb_secure_update _((VALUE)); long rb_num2long _((VALUE)); unsigned long rb_num2ulong _((VALUE)); #define NUM2LONG(x) (FIXNUM_P(x)?FIX2LONG(x):rb_num2long((VALUE)x)) #define NUM2ULONG(x) rb_num2ulong((VALUE)x) #if SIZEOF_INT < SIZEOF_LONG long rb_num2int _((VALUE)); #define NUM2INT(x) (FIXNUM_P(x)?FIX2INT(x):rb_num2int((VALUE)x)) long rb_fix2int _((VALUE)); #define FIX2INT(x) rb_fix2int((VALUE)x) unsigned long rb_num2uint _((VALUE)); #define NUM2UINT(x) rb_num2uint(x) unsigned long rb_fix2uint _((VALUE)); #define FIX2UINT(x) rb_fix2uint(x) #else #define NUM2INT(x) ((int)NUM2LONG(x)) #define NUM2UINT(x) ((unsigned int)NUM2ULONG(x)) #define FIX2INT(x) ((int)FIX2LONG(x)) #define FIX2UINT(x) ((unsigned int)FIX2ULONG(x)) #endif #ifdef HAVE_LONG_LONG LONG_LONG rb_num2ll _((VALUE)); unsigned LONG_LONG rb_num2ull _((VALUE)); # define NUM2LL(x) (FIXNUM_P(x)?FIX2LONG(x):rb_num2ll((VALUE)x)) # define NUM2ULL(x) rb_num2ull((VALUE)x) #endif #if defined(HAVE_LONG_LONG) && SIZEOF_OFF_T > SIZEOF_LONG # define NUM2OFFT(x) ((off_t)NUM2LL(x)) #else # define NUM2OFFT(x) NUM2LONG(x) #endif double rb_num2dbl _((VALUE)); #define NUM2DBL(x) rb_num2dbl((VALUE)(x)) /* obsolete API - use StringValue() */ char *rb_str2cstr _((VALUE,long*)); /* obsolete API - use StringValuePtr() */ #define STR2CSTR(x) rb_str2cstr((VALUE)(x),0) #define NUM2CHR(x) (((TYPE(x) == T_STRING)&&(RSTRING(x)->len>=1))?\ RSTRING(x)->ptr[0]:(char)(NUM2INT(x)&0xff)) #define CHR2FIX(x) INT2FIX((long)((x)&0xff)) VALUE rb_newobj _((void)); #define NEWOBJ(obj,type) type *obj = (type*)rb_newobj() #define OBJSETUP(obj,c,t) do {\ RBASIC(obj)->flags = (t);\ RBASIC(obj)->klass = (c);\ if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT);\ } while (0) #define CLONESETUP(clone,obj) do {\ OBJSETUP(clone,rb_singleton_class_clone((VALUE)obj),RBASIC(obj)->flags);\ rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);\ if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)clone,(VALUE)obj);\ } while (0) #define DUPSETUP(dup,obj) do {\ OBJSETUP(dup,rb_obj_class(obj),(RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT));\ if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)dup,(VALUE)obj);\ } while (0) struct RBasic { unsigned long flags; VALUE klass; }; struct RObject { struct RBasic basic; struct st_table *iv_tbl; }; struct RClass { struct RBasic basic; struct st_table *iv_tbl; struct st_table *m_tbl; VALUE super; }; #define RCLASS_IV_TBL(c) (RCLASS(c)->iv_tbl) #define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl) #define RCLASS_SUPER(c) (RCLASS(c)->super) #define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m) #define RMODULE_M_TBL(m) RCLASS_M_TBL(m) #define RMODULE_SUPER(m) RCLASS_SUPER(m) struct RFloat { struct RBasic basic; double value; }; #define RFLOAT_VALUE(v) (RFLOAT(v)->value) #define ELTS_SHARED FL_USER2 struct RString { struct RBasic basic; long len; char *ptr; union { long capa; VALUE shared; } aux; }; #define RSTRING_PTR(s) (RSTRING(s)->ptr) #define RSTRING_LEN(s) (RSTRING(s)->len) #define RSTRING_END(s) (RSTRING_PTR(s)+RSTRING_LEN(s)) struct RArray { struct RBasic basic; long len; union { long capa; VALUE shared; } aux; VALUE *ptr; }; #define RARRAY_PTR(s) (RARRAY(s)->ptr) #define RARRAY_LEN(s) (RARRAY(s)->len) struct RRegexp { struct RBasic basic; struct re_pattern_buffer *ptr; long len; char *str; }; #define RREGEXP_SRC_PTR(r) (RREGEXP(r)->src) #define RREGEXP_SRC_LEN(r) (RREGEXP(r)->len) struct RHash { struct RBasic basic; struct st_table *tbl; int iter_lev; VALUE ifnone; }; #define RHASH_TBL(h) (RHASH(h)->tbl) #define RHASH_ITER_LEV(h) (RHASH(h)->iter_lev) #define RHASH_IFNONE(h) (RHASH(h)->ifnone) #define RHASH_SIZE(h) (RHASH(h)->tbl->num_entries) #define RHASH_EMPTY_P(h) (RHASH_SIZE(h) == 0) struct RFile { struct RBasic basic; struct rb_io_t *fptr; }; struct RData { struct RBasic basic; void (*dmark) _((void*)); void (*dfree) _((void*)); void *data; }; #define DATA_PTR(dta) (RDATA(dta)->data) /* #define RUBY_DATA_FUNC(func) ((void (*)_((void*)))func) */ typedef void (*RUBY_DATA_FUNC) _((void*)); VALUE rb_data_object_alloc _((VALUE,void*,RUBY_DATA_FUNC,RUBY_DATA_FUNC)); #define Data_Wrap_Struct(klass,mark,free,sval)\ rb_data_object_alloc(klass,sval,(RUBY_DATA_FUNC)mark,(RUBY_DATA_FUNC)free) #define Data_Make_Struct(klass,type,mark,free,sval) (\ sval = ALLOC(type),\ memset(sval, 0, sizeof(type)),\ Data_Wrap_Struct(klass,mark,free,sval)\ ) #define Data_Get_Struct(obj,type,sval) do {\ Check_Type(obj, T_DATA); \ sval = (type*)DATA_PTR(obj);\ } while (0) struct RStruct { struct RBasic basic; long len; VALUE *ptr; }; #define RSTRUCT_LEN(st) (RSTRUCT(st)->len) #define RSTRUCT_PTR(st) (RSTRUCT(st)->ptr) struct RBignum { struct RBasic basic; char sign; long len; void *digits; }; #define RBIGNUM_SIGN(b) (RBIGNUM(b)->sign) #define RBIGNUM_SET_SIGN(b,s) (RBIGNUM(b)->sign = (s)) #define RBIGNUM_POSITIVE_P(b) RBIGNUM_SIGN(b) #define RBIGNUM_NEGATIVE_P(b) (!RBIGNUM_SIGN(b)) #define RBIGNUM_LEN(b) (RBIGNUM(b)->len) #define RBIGNUM_DIGITS(b) (RBIGNUM(b)->digits) #define R_CAST(st) (struct st*) #define RBASIC(obj) (R_CAST(RBasic)(obj)) #define ROBJECT(obj) (R_CAST(RObject)(obj)) #define RCLASS(obj) (R_CAST(RClass)(obj)) #define RMODULE(obj) RCLASS(obj) #define RFLOAT(obj) (R_CAST(RFloat)(obj)) #define RSTRING(obj) (R_CAST(RString)(obj)) #define RREGEXP(obj) (R_CAST(RRegexp)(obj)) #define RARRAY(obj) (R_CAST(RArray)(obj)) #define RHASH(obj) (R_CAST(RHash)(obj)) #define RDATA(obj) (R_CAST(RData)(obj)) #define RSTRUCT(obj) (R_CAST(RStruct)(obj)) #define RBIGNUM(obj) (R_CAST(RBignum)(obj)) #define RFILE(obj) (R_CAST(RFile)(obj)) #define FL_SINGLETON FL_USER0 #define FL_MARK (1<<6) #define FL_FINALIZE (1<<7) #define FL_TAINT (1<<8) #define FL_EXIVAR (1<<9) #define FL_FREEZE (1<<10) #define FL_USHIFT 11 #define FL_USER0 (1<<(FL_USHIFT+0)) #define FL_USER1 (1<<(FL_USHIFT+1)) #define FL_USER2 (1<<(FL_USHIFT+2)) #define FL_USER3 (1<<(FL_USHIFT+3)) #define FL_USER4 (1<<(FL_USHIFT+4)) #define FL_USER5 (1<<(FL_USHIFT+5)) #define FL_USER6 (1<<(FL_USHIFT+6)) #define FL_USER7 (1<<(FL_USHIFT+7)) #define FL_UMASK (0xff<flags&(f)):0) #define FL_SET(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags |= (f);} while (0) #define FL_UNSET(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags &= ~(f);} while (0) #define FL_REVERSE(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags ^= (f);} while (0) #define OBJ_TAINTED(x) FL_TEST((x), FL_TAINT) #define OBJ_TAINT(x) FL_SET((x), FL_TAINT) #define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT;} while (0) #define OBJ_FROZEN(x) FL_TEST((x), FL_FREEZE) #define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE) #define ALLOC_N(type,n) (type*)xmalloc(sizeof(type)*(n)) #define ALLOC(type) (type*)xmalloc(sizeof(type)) #define REALLOC_N(var,type,n) (var)=(type*)xrealloc((char*)(var),sizeof(type)*(n)) #define ALLOCA_N(type,n) (type*)alloca(sizeof(type)*(n)) #define MEMZERO(p,type,n) memset((p), 0, sizeof(type)*(n)) #define MEMCPY(p1,p2,type,n) memcpy((p1), (p2), sizeof(type)*(n)) #define MEMMOVE(p1,p2,type,n) memmove((p1), (p2), sizeof(type)*(n)) #define MEMCMP(p1,p2,type,n) memcmp((p1), (p2), sizeof(type)*(n)) void rb_obj_infect _((VALUE,VALUE)); typedef int ruby_glob_func(const char*,VALUE); void rb_glob _((const char*,void(*)(const char*,VALUE),VALUE)); void rb_globi _((const char*,void(*)(const char*,VALUE),VALUE)); int ruby_brace_expand _((const char*,int,ruby_glob_func*,VALUE)); int ruby_brace_glob _((const char*,int,ruby_glob_func*,VALUE)); VALUE rb_define_class _((const char*,VALUE)); VALUE rb_define_module _((const char*)); VALUE rb_define_class_under _((VALUE, const char*, VALUE)); VALUE rb_define_module_under _((VALUE, const char*)); void rb_include_module _((VALUE,VALUE)); void rb_extend_object _((VALUE,VALUE)); void rb_define_variable _((const char*,VALUE*)); void rb_define_virtual_variable _((const char*,VALUE(*)(ANYARGS),void(*)(ANYARGS))); void rb_define_hooked_variable _((const char*,VALUE*,VALUE(*)(ANYARGS),void(*)(ANYARGS))); int ruby_glob _((const char*,int,int(*)(const char*,VALUE),VALUE)); int ruby_globi _((const char*,int,int(*)(const char*,VALUE),VALUE)); void rb_define_readonly_variable _((const char*,VALUE*)); void rb_define_const _((VALUE,const char*,VALUE)); void rb_define_global_const _((const char*,VALUE)); #define RUBY_METHOD_FUNC(func) ((VALUE (*)(ANYARGS))func) void rb_define_method _((VALUE,const char*,VALUE(*)(ANYARGS),int)); void rb_define_module_function _((VALUE,const char*,VALUE(*)(ANYARGS),int)); void rb_define_global_function _((const char*,VALUE(*)(ANYARGS),int)); void rb_undef_method _((VALUE,const char*)); void rb_define_alias _((VALUE,const char*,const char*)); void rb_define_attr _((VALUE,const char*,int,int)); void rb_global_variable _((VALUE*)); void rb_gc_register_address _((VALUE*)); void rb_gc_unregister_address _((VALUE*)); ID rb_intern _((const char*)); const char *rb_id2name _((ID)); ID rb_to_id _((VALUE)); const char *rb_class2name _((VALUE)); const char *rb_obj_classname _((VALUE)); void rb_p _((VALUE)); VALUE rb_eval_string _((const char*)); VALUE rb_eval_string_protect _((const char*, int*)); VALUE rb_eval_string_wrap _((const char*, int*)); VALUE rb_funcall __((VALUE, ID, int, ...)); VALUE rb_funcall2 _((VALUE, ID, int, const VALUE*)); VALUE rb_funcall3 _((VALUE, ID, int, const VALUE*)); int rb_scan_args __((int, const VALUE*, const char*, ...)); VALUE rb_call_super _((int, const VALUE*)); VALUE rb_gv_set _((const char*, VALUE)); VALUE rb_gv_get _((const char*)); VALUE rb_iv_get _((VALUE, const char*)); VALUE rb_iv_set _((VALUE, const char*, VALUE)); VALUE rb_equal _((VALUE,VALUE)); RUBY_EXTERN VALUE ruby_verbose, ruby_debug; NORETURN(void rb_raise __((VALUE, const char*, ...))); NORETURN(void rb_fatal __((const char*, ...))); NORETURN(void rb_bug __((const char*, ...))); NORETURN(void rb_sys_fail _((const char*))); NORETURN(void rb_iter_break _((void))); NORETURN(void rb_exit _((int))); NORETURN(void rb_notimplement _((void))); void rb_warning __((const char*, ...)); /* reports if `-w' specified */ void rb_sys_warning __((const char*, ...)); /* reports if `-w' specified */ void rb_warn __((const char*, ...)); /* reports always */ typedef VALUE rb_block_call_func _((VALUE, VALUE)); VALUE rb_each _((VALUE)); VALUE rb_yield _((VALUE)); VALUE rb_yield_values __((int n, ...)); VALUE rb_yield_splat _((VALUE)); int rb_block_given_p _((void)); void rb_need_block _((void)); VALUE rb_iterate _((VALUE(*)(VALUE),VALUE,VALUE(*)(ANYARGS),VALUE)); VALUE rb_rescue _((VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE)); VALUE rb_rescue2 __((VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE,...)); VALUE rb_ensure _((VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE)); VALUE rb_catch _((const char*,VALUE(*)(ANYARGS),VALUE)); NORETURN(void rb_throw _((const char*,VALUE))); VALUE rb_require _((const char*)); #ifdef __ia64 void ruby_init_stack(VALUE*, void*); #define RUBY_INIT_STACK \ VALUE variable_in_this_stack_frame; \ ruby_init_stack(&variable_in_this_stack_frame, rb_ia64_bsp()); #else void ruby_init_stack(VALUE*); #define RUBY_INIT_STACK \ VALUE variable_in_this_stack_frame; \ ruby_init_stack(&variable_in_this_stack_frame); #endif void ruby_init _((void)); void ruby_options _((int, char**)); NORETURN(void ruby_run _((void))); RUBY_EXTERN VALUE rb_mKernel; RUBY_EXTERN VALUE rb_mComparable; RUBY_EXTERN VALUE rb_mEnumerable; RUBY_EXTERN VALUE rb_mPrecision; RUBY_EXTERN VALUE rb_mErrno; RUBY_EXTERN VALUE rb_mFileTest; RUBY_EXTERN VALUE rb_mGC; RUBY_EXTERN VALUE rb_mMath; RUBY_EXTERN VALUE rb_mProcess; RUBY_EXTERN VALUE rb_cObject; RUBY_EXTERN VALUE rb_cArray; RUBY_EXTERN VALUE rb_cBignum; RUBY_EXTERN VALUE rb_cBinding; RUBY_EXTERN VALUE rb_cClass; RUBY_EXTERN VALUE rb_cCont; RUBY_EXTERN VALUE rb_cDir; RUBY_EXTERN VALUE rb_cData; RUBY_EXTERN VALUE rb_cEnumerator; RUBY_EXTERN VALUE rb_cFalseClass; RUBY_EXTERN VALUE rb_cFile; RUBY_EXTERN VALUE rb_cFixnum; RUBY_EXTERN VALUE rb_cFloat; RUBY_EXTERN VALUE rb_cHash; RUBY_EXTERN VALUE rb_cInteger; RUBY_EXTERN VALUE rb_cIO; RUBY_EXTERN VALUE rb_cMatch; RUBY_EXTERN VALUE rb_cMethod; RUBY_EXTERN VALUE rb_cModule; RUBY_EXTERN VALUE rb_cNameErrorMesg; RUBY_EXTERN VALUE rb_cNilClass; RUBY_EXTERN VALUE rb_cNumeric; RUBY_EXTERN VALUE rb_cProc; RUBY_EXTERN VALUE rb_cRange; RUBY_EXTERN VALUE rb_cRegexp; RUBY_EXTERN VALUE rb_cStat; RUBY_EXTERN VALUE rb_cString; RUBY_EXTERN VALUE rb_cStruct; RUBY_EXTERN VALUE rb_cSymbol; RUBY_EXTERN VALUE rb_cThread; RUBY_EXTERN VALUE rb_cTime; RUBY_EXTERN VALUE rb_cTrueClass; RUBY_EXTERN VALUE rb_cUnboundMethod; RUBY_EXTERN VALUE rb_eException; RUBY_EXTERN VALUE rb_eStandardError; RUBY_EXTERN VALUE rb_eSystemExit; RUBY_EXTERN VALUE rb_eInterrupt; RUBY_EXTERN VALUE rb_eSignal; RUBY_EXTERN VALUE rb_eFatal; RUBY_EXTERN VALUE rb_eArgError; RUBY_EXTERN VALUE rb_eEOFError; RUBY_EXTERN VALUE rb_eIndexError; RUBY_EXTERN VALUE rb_eStopIteration; RUBY_EXTERN VALUE rb_eRangeError; RUBY_EXTERN VALUE rb_eIOError; RUBY_EXTERN VALUE rb_eRuntimeError; RUBY_EXTERN VALUE rb_eSecurityError; RUBY_EXTERN VALUE rb_eSystemCallError; RUBY_EXTERN VALUE rb_eThreadError; RUBY_EXTERN VALUE rb_eTypeError; RUBY_EXTERN VALUE rb_eZeroDivError; RUBY_EXTERN VALUE rb_eNotImpError; RUBY_EXTERN VALUE rb_eNoMemError; RUBY_EXTERN VALUE rb_eNoMethodError; RUBY_EXTERN VALUE rb_eFloatDomainError; RUBY_EXTERN VALUE rb_eLocalJumpError; RUBY_EXTERN VALUE rb_eSysStackError; RUBY_EXTERN VALUE rb_eRegexpError; RUBY_EXTERN VALUE rb_eScriptError; RUBY_EXTERN VALUE rb_eNameError; RUBY_EXTERN VALUE rb_eSyntaxError; RUBY_EXTERN VALUE rb_eLoadError; RUBY_EXTERN VALUE rb_stdin, rb_stdout, rb_stderr; RUBY_EXTERN VALUE ruby_errinfo; static inline VALUE #if defined(HAVE_PROTOTYPES) rb_class_of(VALUE obj) #else rb_class_of(obj) VALUE obj; #endif { if (FIXNUM_P(obj)) return rb_cFixnum; if (obj == Qnil) return rb_cNilClass; if (obj == Qfalse) return rb_cFalseClass; if (obj == Qtrue) return rb_cTrueClass; if (SYMBOL_P(obj)) return rb_cSymbol; return RBASIC(obj)->klass; } static inline int #if defined(HAVE_PROTOTYPES) rb_type(VALUE obj) #else rb_type(obj) VALUE obj; #endif { if (FIXNUM_P(obj)) return T_FIXNUM; if (obj == Qnil) return T_NIL; if (obj == Qfalse) return T_FALSE; if (obj == Qtrue) return T_TRUE; if (obj == Qundef) return T_UNDEF; if (SYMBOL_P(obj)) return T_SYMBOL; return BUILTIN_TYPE(obj); } static inline int #if defined(HAVE_PROTOTYPES) rb_special_const_p(VALUE obj) #else rb_special_const_p(obj) VALUE obj; #endif { if (SPECIAL_CONST_P(obj)) return Qtrue; return Qfalse; } #include "missing.h" #include "intern.h" #if defined(EXTLIB) && defined(USE_DLN_A_OUT) /* hook for external modules */ static char *dln_libs_to_be_linked[] = { EXTLIB, 0 }; #endif #if defined(HAVE_LIBPTHREAD) #ifdef HAVE_PTHREAD_H #include #endif typedef pthread_t rb_nativethread_t; # define NATIVETHREAD_CURRENT() pthread_self() # define NATIVETHREAD_EQUAL(t1,t2) pthread_equal((t1),(t2)) # define HAVE_NATIVETHREAD # define NATIVETHREAD_KILL(th,sig) pthread_kill((th),(sig)) # define HAVE_NATIVETHREAD_KILL #elif defined(_WIN32) || defined(_WIN32_WCE) typedef DWORD rb_nativethread_t; # define NATIVETHREAD_CURRENT() GetCurrentThreadId() # define NATIVETHREAD_EQUAL(t1,t2) ((t1) == (t2)) # define HAVE_NATIVETHREAD #endif #ifdef HAVE_NATIVETHREAD int is_ruby_native_thread _((void)); #else #define is_ruby_native_thread() (1) #endif #ifdef HAVE_NATIVETHREAD_KILL void ruby_native_thread_kill _((int)); #endif #if defined(__cplusplus) #if 0 { /* satisfy cc-mode */ #endif } /* extern "C" { */ #endif #endif /* ifndef RUBY_H */ PK|]}=x86_64-linux/zlib.sonuȯELF>&@@@8 @  @   @@888$$؎؎؎ Std؎؎؎ PtdxwxwxwQtdRtd @@GNU!A?A$c@ cefBE|qX)hVV1c DVcl&!y 8KBA,3 rs$ U\c .6-ctwO f:6nU, F"4Np  p  0b __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_check_typerb_cStringrb_str_newrb_str_resizerb_exc_new2rb_exc_raiserb_sys_fail__snprintf_chkzErrorrb_str_substrmemmoverb_scan_argsrb_fix2intinflateInit2___stack_chk_failrb_ensurerb_warningruby_xmallocfreerb_gc_markrb_data_object_alloccrc32memcpyrb_str_buf_newrb_str_buf_cattimedeflateInit2_rb_uint2inumrb_class_new_instancerb_block_given_prb_yieldrb_string_valueinflateInit_deflateInit_get_crc_tablerb_ary_new2rb_ary_pushrb_num2ulongadler32zlibVersionrb_str_new2stderr__fprintf_chkrb_raiserb_num2intrb_str_duprb_int2inumrb_funcallrb_time_newinflateSetDictionaryinflateSyncPointdeflateSetDictionarydeflateCopyinflateSyncrb_thread_scheduledeflateParamsrb_eArgErrorrb_rsmemchrmemcmprb_eRuntimeErrorrb_ary_newrb_lastline_setrb_eEOFErrorrb_respond_torb_str_to_strrb_Integerrb_big2ulongrb_check_safe_objrb_file_openrb_obj_as_stringInit_zlibrb_define_modulerb_eStandardErrorrb_define_class_underrb_define_module_functionrb_define_constrb_cObjectrb_undef_alloc_funcrb_define_methodrb_define_singleton_methodrb_define_alloc_funcrb_internrb_mEnumerablerb_include_modulerb_io_addstrrb_io_printfrb_io_printrb_io_putsinflateResetinflateEndinflatedeflateResetdeflateEnddeflatelibruby.so.1.8libz.so.1libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.14GLIBC_2.4GLIBC_2.2.5GLIBC_2.3.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64ii ui ti  'Ȝ @'М М P 5   = X ` h  p  x     & / 1 8 E Mȟ QП X؟ Y [ ] b  ( 0 8 @ H  P  X ` h p x           Ƞ !Р "ؠ # $ % ' ( ) * + , -( .0 08 1@ 2H 3P 4X 6` 7h 9p :x ; < > ? @ A B C D Fȡ GС Hء I J K L N O R S T U( V0 W8 Z@ \H ]P ^X _` `h aHHY HtH5 % hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJA%} D%} D%} D%} D%} D%} D%} D%} D%} D%} D%} D%} D%} D%} D%}} D%u} D%m} D%e} D%]} D%U} D%M} D%E} D%=} D%5} D%-} D%%} D%} D%} D% } D%} D%| D%| D%| D%| D%| D%| D%| D%| D%| D%| D%| D%| D%| D%| D%| D%| D%}| D%u| D%m| D%e| D%]| D%U| D%M| D%E| D%=| D%5| D%-| D%%| D%| D%| D% | D%| D%{ D%{ D%{ D%{ D%{ D%{ D%{ D%{ D%{ D%{ D%{ D%{ D%{ DH={ H{ H9tHnx Ht H=i{ H5b{ H)HHH?HHtHx HtfD=%{ u+UH=x Ht H=nu dz ]wS"HHC [HHS"H~HC [Hff.S"HNHC HPHt HcBHD[U"SHHHk HEHtKH4w HHPHEHt HH ƒuHt HH H[]fD11DUSHHHoHtMHwHAHv HHEHCHHCHC8C@H[]f.11'HfS"H.H{ uHt HH ƒuHt HH [ff.USHH $HH $HdH%(H$ 1HSHKHcH>H=(y kHH=x TH=x FH=x 8H=x *H=x HrH=x HPALEVH  1H=x ZHY^H%fSHH Hu0HHCHCHC8C@HC[HsPATUHcSH9o~sHHH1RHSIHt H)HID$HCHSHxH4/DHCHSHHH@)HѺ@=@HK8G‰C@L[]A\[]A\GUSHHDHdH%(HD$1H4"HH<$Hk Ht H<$H} pHdDuHMHHT$dH3%(uH[]HuP\Ht@HHHHH<H=Ht@HHHHH H=5*SHtTHu-HHCH{ PuHH[DH=H1H1H=H[HsPpBfHD@SHHH{[DSHHHHH{{H{[qAUIATIUHSHHHxHHHHHHǀ1H)HHH L11HHH1HC`HHCHCHCHChHCpHCPHC C(HC8C@HǃǃHǃǃHǃHǃLHHHǃH[]A\A]f.HEH5n fHUH5n yfATIUHS,HHxHHHHHHǀ1H)HHH w 2HH5HHCHCHCHS`HshHCpHCPHC C(HC8C@L[]A\H5m H5m ATIUHcSHHHtiHCH4(H9w|Cs@)9ֺBʉK@HGHLH5HCHkHkHhHk8[]A\@C@H{HCfHHLHCHfHCHkHPC@HS8H@[]A\fUSHH(dH%(HD$1H@HtHHt ҉D$H߈T$Ht$ D$fL$D$@l$HHt$HPHpHH5CHzHHt$HPHpH]H5CHIH HD$dH3%(u H([]fD1HUHHM>SH(dH%(HD$1HLL$LD$"H-H|$H] Ht H|$uH|$E1Ht H|$KAjpH{ H=APZYu)H$H HHHT$dH3%(uH([]HsPAVAUE1ATUSHHF=H0dH%(HD$(1HL$HHD$(P1LL$(LD$ ^"_HH|$ Hk Ht H|$ aAH|$AHt H|$9AH|$AHt H|$AH|$Ht H|$HV<jpDH} PEEZYu%HMHHT$(dH3%(uH0[]A\A]A^HuP1ff.S"HHC [x@S6Hu H[DH=!k HH[H;&fDSHHt$H|$H\$dH%(H$1HH{ pHD$pHH5?;HD$xHg HD$HD$HD$ HD$(HDŽ$HD$`HD$0D$8HD$HD$PH$HD$HH$HH=0HL$H$H$u1Ht)HT$uHtHH f.H$dH3 %(u H[Ht$`SUH:SHdH%(H$1HLD$HtH|$Ht H|$UHH\$H{ pHdH9HD$HD$pHXHD$xHLf HD$HD$ HD$(HDŽ$HD$`HD$0D$8HD$HD$PH$H$HH$H?H=HL$H$H$u)Ht!H$uHtHH H$dH3 %(u H[]>Ht$`fATUScHLH@H;H HHL9uH[]A\@ATUHH58SH dH%(HD$1H\$LD$HH|$HuqH|$tQ111IH|$tAHHD$LHPHpHtHL$dH3 %(u.H []A\E1L11H;I!Hf 0Hf HHuHtHHHHH HPH <tt HDH <Hf H6H81HSHtH|c H9tH{H[fHIf H z<H6H81|f.SHuH[jf.H[RfS"HBHC t[H=ph H5361BfSHHHtHHH[HHH[ff.HHHEHff.@HSHt 1HxHHHfDH#HcHHDfHHcHHDfHHHUSHHHHtnHH[]fDcHH[]HsHHuHÐHxuHtHHH3HHuHÐH8uHtHHSHHx0H@HtHxH9AHH5`f H1H.111CHǃH[f.HsHcHUSHQHHHHǃHǃHHǃH[]HHx0HfDHHxHH+xHfHHHH1HHQS"HHC t[H=he H521fHHHEHff.@HHc@xHHDDHsH{HÐATUHSP HH HH{IHt;9C@uH[]A\fDHcHsHSHCHBDc@HC8H[]A\Hc1HCHPHCDc@HS8H@H[]A\ff.HHHÐHHHHcHxHHfDHCHx0HfDATUHSHHdH%(HD$1 H$IHtHH بtOHH$I|$ HPHp u=HL$dH3 %(Hu6H[]A\f.HtH%H EIt$PmSfHx Hzt u1[D[HsP&fDATUHSHHdH%(HD$1 H$IHtHH بtOHH$I|$ HPHpu=HL$dH3 %(Hu6H[]A\f.HtH%H EIt$PmATIUH"S8HI\$ KHp H{ HuCHEHtHHCHEHtHHCHEHCHEHL[]A\1ff.H1H5 a tHtHǾHD$HD$Hft\ATUSHHtHH[]A\fDHHIzHLHEHHEH@[]A\ff.@UHcSHHdH%(HD$1fH$HpH{HP[HCHtH9h}3HH$Hu1HL$dH3 %(uH[]@ff.HHtWUSHHPH9HH[]HHxH)H4MH}HwHH)[]HATUSHH@t7HCH{H@D hHC0VL9u5CHH9u[]A\H=^ H5,H=^ H521H=^ H521Ht @H Gt fDHGHff.fS"H.H[ HHƒHu3H{u,@t0H{HtuHtH[@[ÐHfDAUATUHSHHt$H@u HusH|$HD$HhL`HCH~u1H[]A\A]Dk(H{ Lc xŅtϋs(H{ HsPBfHD$uHxH%H Egf.HPH@H{ HS C(AŅt1HCRs(H{ HsPDHCLkLHp+s(LL  fS(Hs H{fDUSHHHHt}HsHGHH)H=?GH~NH@HH=@HNHHSHsk@HrHs8H[]C@@@1HCHPHCC@HS8H@H[]f.UHSH.H@HuhHHKHHSH9QtvHqH~IHCH@@(C@HCt HC8C@H[]@@tE?uH}~HEHK(HuHhHSHKuH KfAVAUAATUSHHHuH{HCk@HPHD$HS HPS(Ls $DEC@Hk@HD$HDLP+k@HkAAuHS(HCHHHtPHs H{UHD$H[]A\A]A^At_AuYS@tRS(H HCuH[]A\A]A^Dk@H'G(HG Hk@S(HCu HsPDHHs H{fSHHVfDHDHD$HD$HtDHD$Hx~HT$HD$HHRHp)HCH tHCH[ÐuH=X H5&1fDSHGHHPHpHH߹1H5&H[SHGHHPHpHH[vfDUHSH.1ҹH5w&HHUH=Ht!HH ƒuHt HUH H[]ff.fAUIATAHUHSHdH%(HD$1DHLHHP%1H<$Htm SH<$uYHHt$HH ƒuHtHUH H\$dH3%(u(H[]A\A]D1H5Y%H:cAVAUIATUHSIHt HH1It LL1LMl$ H5$Lu,L5*f1LfLLt݅u[]A\A]A^It$Pff.@LcHJLL9 )ȉ@UIHSHD)HIqH?LHEH[]@USHHHuHhHtH{u@t^H11[]GHHHHHO@uHtHMHH[]fDHH11[]ATAUSHHHGu&HcH9| !fH9k}HHtHCHtYDH&HHHH@uHtHMH[]A\fD[1]1A\;@uH6HQ H5"H81Jf.HHHtH@H%HHSHfDHHHu[ATIUSHHdH%(HD$17HLHHW!1H<$HtD@u.ƅxBHKH\$dH3%(u%H[]A\fHxHP H5]!H81ATUSHHt HH{ut[]A\HCHLH@1fDHH9s~&<0 tH[LHH]A\fDHLHHjH{t!H(H{utkHCH@yAWAVAUATIUHSH(dH%(HD$1HÅH#O HHD$Hl$HHD$HxHD$D$ LpHD$LhLcM9@HhLcM9}wtM~DHcHH|$dH3<%(HH([]A\A]A^A_f.HAL5+D$ lfDHCLLxDL9~"HHCIM)L@MNjT$ uHD$L9pt L9hLcA6LLH)H HHtrL)HIt6LLHH $t H $HLyL9~lfDH?HŋD$ H8Il$fDHL$H1LhHD$HH|$Hl$HH HxUHFHM H5H81fAUAATIUHSHHHHHLDHuHH[]A\A]ff.ATAUHSH DHHHDHuH[]A\@HHtHHD$HD$HfDSHu H L H5H81HHUH[UHSHHt$Ht 6HHWH5* LH,H5 LHH5 LHH5ʹL1HH5貹1LHFH5蚹1LHH5肹1HHH5j1HHH5R1LHH5:LH[H5Z1HH#H5H1LHH501HHH5׸1LHH5迸LHH5贸LH5z襹LHfH5zLHH5_LHPH5DLHH5x)H2 LH5H2 LH5GH2 LH53طH12 LH5轷HHH5買HH5X裸HHH5x1HHlH5`1HHdH5HHHH5-1HHQH51HH H5q1HHaH5bHHH5QʶHH+H5=诶HH@H5'蔶HHH5yHHH5^HHH5CHߺH5߷HߺH5˷HߺH5跷HߺH5裷HߺH5菷Hߺ H5{Hߺ H5gHߺH5SHߺH5?HߺH5|+Hߺ H5qHߺH5fHߺH5]HߺH5P۶HߺH5DǶHHߺ[H55]A\A]驶HHunknown zlib error %d: %s011.2.11120402zlib(finalizer): %s closed gzip streamstream is not readyfooter is not foundunexpected end of filenegative length %d given rs modifiedend of file reachedheader is already writtenrbwbnot in gzip formatunknown flags 0x%02xZlibStreamEndNeedDictDataErrorStreamErrorMemErrorBufErrorVersionErrorzlib_versionadler32crc32crc_table0.6.0ZLIB_VERSIONZStreamavail_outavail_out=avail_intotal_intotal_outdata_typeadlerfinished?stream_end?closed?ended?closeendresetfinishflush_next_inflush_next_outBINARYASCIIDeflatedeflateinitializeinitialize_copy<<flushparamsset_dictionaryInflateinflatesyncsync_point?NO_COMPRESSIONBEST_SPEEDBEST_COMPRESSIONDEFAULT_COMPRESSIONFILTEREDHUFFMAN_ONLYDEFAULT_STRATEGYMAX_WBITSDEF_MEM_LEVELMAX_MEM_LEVELNO_FLUSHSYNC_FLUSHFULL_FLUSHFINISHwritereadseekGzipFileNoFooterCRCErrorLengthErrorGzipWriterGzipReaderwrapto_iocrcmtimelevelos_codeorig_namecommentlinenolineno=mtime=orig_name=comment=eofeof?sync=postellopenputcprintfprintputsrewindunusedreadchareach_byteungetcgetsreadlineeacheach_linereadlinesOS_CODEOS_MSDOSOS_AMIGAOS_VMSOS_UNIXOS_ATARIOS_OS2OS_MACOSOS_TOPS20OS_WIN32OS_VMCMSOS_ZSYSTEMOS_CPMOS_QDOSOS_RISCOSOS_UNKNOWNȴִ޴yattempt to close uninitialized zstream; ignored.attempt to close unfinished zstream; reset forced.the stream state was inconsistent.the stream was freed prematurely.Zlib::GzipWriter object must be closed explicitly.invalid compressed data -- crc errorinvalid compressed data -- length errordeflateParams() returned Z_BUF_ERRORwrong number of arguments (0 for 1)unsupported compression method %dmulti-part gzip file is not supportedencrypted gzip file is not supported;~@XHtx( XXxȴx(<PlHhXh,x@8xhhȼ8T(t8H, X@ hT l X  ( X4 xL d |  H  ($ xL d | ( X x  HT hl @ p X X (XXpxH84H(L80H(dXT(h8HLl(8T,X`(4hzRx $ȡFJ w?:*3$"D`\)ERx̫$ER0Ej({EFG U AAG (HnAAG J AAK EE4$AAG L@I@@K@a@D@\PAC A 4|حBAD r ABD AAB(0EAN0 AAA 0Ю0 Eu F t A ,H@D T@EQpD?Eu8hFBED I(D0'(A ABB|(BDI AB8044D0BDD V ABE RAB(|0AAG@ AAG 4EKD@H\PFHA@j AAA XTFBE A(A0N`YhFpRhF`hHpQhA`` 0A(A BBBA <ERX:EU F N$xmEGN AA ,EMGq AAA (dLFAA @AB0BAK D@~  AABD 0DX -Hdp$XGc F cdVEd G .EL O I.AW A ̸4E_ D K!HX *Ha8HPP$HPh,HP04MEAG _ DAG ODAP@HV B _p@HV B _vEpHP$(MEAD @AAP$HMh,HQ4HP<HRD.AW A X!HXpHMxHV@FAD s ABG d ABA nABXHVpHPHMHM0 FAD G0o  AABK :E] F F A 0 FAD G0o  AABK ,D @FDI e ABA t >D y8 ȼaFAA R ABK mABH( ADG0e AAE 4 `hJAF T AAI _DA,, BFA C ABA \ 3dN t jEN E F B 8 ljFBA D(D@K (A ABBF 4 AAG ] AAH SAA( 8EDD w FAE T8 wBBE A(A0G@ 0A(A BBBH j 0A(A BBBF $AG e AB  @Ev *E`$ cEDD SAA8 FEG D(D@ (A ABBF <P FBE A(D0 (F BBBA $ TLYIJ ]AA< |AAG e EAL | DAG LEA8 BDA  ABG A CDH 4 8HoL (Eb0h FDA I0e  AABC 4 HBAA a ABH y JBK H BBB B(D0F8D` 8A0A(B BBBK 4 4UFED D(D0t(D ABB(X\<FDD jABp*H a@Ez0jADD0{ AAJ WAA$VEDG @DA8 FEG A(GP (A ABBE PQ~ A j,pT_BDC D ABH EG p AC 8FEG D(D@ (A ABBH AAM8pFBD A(D0P (D ABBA 8XpFBD A(D0P (D ABBA 4lEAG q DAE P DAC 8HBBA A(D@k (A ABBA 00qAAG E AAH KFCd4E\ G KEX0iAG g AH U AB WA4PEAG0p DAF c DAH ( EAG0o AAB 08BDE F0~  AABA <lXFBB D(I0 (D BBBK (]FAA  ABF ( EAG0[ AAF 0HO A 8  FIA A(D0 (I HBBGNU'@'М @OYit 8 p Ȝ o`@    0x o(ooTo p 0@P`p 0@P`p  0 @ P ` p !! !0!@!P!`!p!!!!!!!!!""GA$3a18p GA$3p1067'pGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY''GA+GLIBCXX_ASSERTIONSzlib.so-1.8.7-16.el8.x86_64.debug{!kb7zXZִF!t/"]?Eh=ڊ2N`=n G6,~Xo/)PR2׋d?oܠ#ށ a..A 7 ؚ8ْKmfVzhǫaiALi @ze‹?]JP'^M9/{ug&"k3ː`A)!_ų'z?qbR6vɜL(t5m2e!׹ywo:՝wgD$穓&&FV{b_VsCA\oy1? ;ȣD,jG8t vbR?K){[( '8 ޑޤ0R>ۭ&eXx_n'Jl~Z' (U^ اv I!?i4YG,!%4{6tjGQ*d_TܭTn@*.)"^Jw SwReB)^@@Ss%z :'/-xx>[!&8^p?\m ຏLm^jkd^?0F&g:3x*j㚶X LS#6v\ۥOLHm%]XfکVў7̋R:q<GEȥr,AN5%`*?>:&~hh^)E`Ձ" ΉO@Y@8 @@@ HMHM HM `x `M`M `M PP888$$@@@ Std@@@ Ptd777LLQtdRtdHMHM HM GNUO33uzl ,?;H ;=>BE|qX Uc[ @m 4c#x U()QB1, lNVF"zlQ Q Q { 0q__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_check_typerb_raiserb_hash_newdbm_firstkeydbm_fetchrb_tainted_str_newrb_hash_asetdbm_nextkeyrb_ary_newrb_assoc_newrb_ary_pushrb_string_valuememcmprb_iteraterb_internrb_funcallrb_hash_delete_ifrb_yieldrb_block_given_prb_ary_new2rb_warnrb_eArgErrordbm_closerb_scan_argsrb_fix2intrb_num2intrb_check_safe_objdbm_openruby_xmalloc__stack_chk_failrb_sys_failrb_data_object_allocrb_ensurefreerb_securerb_error_frozendbm_deleterb_str_duprb_protectrb_jump_tagrb_obj_as_stringdbm_store__errno_locationrb_eIndexErrorInit_dbmrb_cObjectrb_define_classrb_eStandardErrorrb_mEnumerablerb_include_modulerb_define_alloc_funcrb_define_singleton_methodrb_define_methodrb_define_constrb_str_new2libruby.so.1.8libgdbm_compat.so.4libgdbm.so.6libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64_ ui ii ui HM `PM  XM XM O O O O  O (O 0O 1O 2O 4O 5P  P (P 0P 8P @P HP  PP  XP  `P  hP  pP xP P P P P P P P P P P P P P P P P  Q !Q "Q #Q $ Q %(Q &0Q '8Q )@Q *HQ +PQ ,XQ -`Q .hQ /pQ 3xQ 5Q 6Q 7Q 8Q 9Q :HHy< HtH5< %< hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1%}9 D%u9 D%m9 D%e9 D%]9 D%U9 D%M9 D%E9 D%=9 D%59 D%-9 D%%9 D%9 D%9 D% 9 D%9 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%8 D%}8 D%u8 D%m8 D%e8 D%]8 D%U8 D%M8 D%E8 D%=8 D%58 D%-8 D%%8 D%8 D%8 D% 8 D%8 D%7 D%7 DH=7 H7 H9tH5 Ht H=7 H57 H)HHH?HHtH5 HtfD=}7 u+UH=5 Ht H=3 dU7 ]wS"HHC HtHx[HD[fPXH51HH=6 DAV"AUATUSHWHC H~L`MtuLIHHHtNfDHHL2HcHHcHILLHLcHHHu[L]A\A]A^15DAWAVAUATUSHH"HIHC Ht}L`MttL,HHHtOHHLHcHII1IcLH#HLHLHHHuHL[]A\A]A^A_1yfS"HHC HtFHXHt=xt1[ø[fHhHtH(Hu11AT"USH{Hk Ht[LeMtRHcE~[HD]A\LHt#1ېLHuHcHD][]A\ø11AV"AUATUSHHC HL`Mt}LLIHHHtVfDHHLHcHHcHIyLHLHLHHHu[L]A\A]A^1ff.fU"SHH9HC HtXHXHtOHHHt0fHH%HcHHHHgHuHH[]1AU"SHHHC HtMHXHtDHHGHt%fHcHeHH HHuHH[]1ff.ATUSHHH|$Ht$HD$"HL`hHC Ht)HxHt LHHH[]HA\1PSHHH|$Ht$%"HHC HtjHXHtaHNHt?fHHHL$HcH;QuHqH tHHuH1[fH[1ff.ATUSHHH|$Ht$r"HHC HHhHt{HHIHtC@HLHHL$HcH;QuHqHPt$H$HIHuH[]A\IcH]H[]A\1ff.fSHHH.H=H[ff.fSHH=H11H[1 f.H1HHDS"HHC HtVHxHtMgHt>fHcHH"HHC HtHxHtHuH[1U"HSHIHE HttHXHtkHHtTf.HH5HcHH"HHE Ht HXHtH[HuHH[]15DAV"AUIATUSIE HHhHH5IHHt|f.HLHHcLHI1HcLH#HHhH@"L#IE Ht(HhHtHIHHu[L]A\A]A^1[ff.AUIATUSHHH|$Ht$!HD$"LL`HhIE HteHxHt\LHt&HcH[HHH[]A\A]f.HuEtHcL&HNH1f1@AUHcATIIUSHHHE~/AELlH3L1HHH_L9uHH[]A\A]ff.1AVHcAUIATUHSH#Ik4"L^IE HHhHHIHHuG@"LIE HHhHHyIHHHLHHcHHcLHHHHHHyHL&i1H=~4EHlfDH3L1HzLHH9u[L]A\A]A^1H) H57H81}ff.fS"HH[ HtH{Ht'HC[1AAUATUHH?SH(dH%(HD$1ILL$LD$LNt!H|$Ht@/H|$H@usALH<$A trH$DځHxIMurHL$dH3 %(H([]A\A]@AfDL(H<$OH$HxxCھBwIHt'HE L`H|H$Hx1Ҿ4IHuH$11HxI- H$HxBfH 11ff.ATH sI1UH1SpLHH1HtuH[]A\H[]A\H=!' HH[H{]A\HtSHHHtH[@SHuHtHu[H= ff.AW1AVAUATUSHH"HHC HHXHHoHIHtTHHIcHIIxIcLIjHHLIHLL[]A\A]A^A_H[]A\A]A^A_1DAWAVAUIATUSHXdH%(HD$H1LD$<I1"LIm HH]HEEH߉D$,tIIAHHD$R_oz 8 5HM PM o`  P P 8 o oo o`M p 0@P`p 0@P`p 0@P`pGA$3a185 GA$3p1067p5GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYpGA+GLIBCXX_ASSERTIONSdbm.so-1.8.7-16.el8.x86_64.debugYqE7zXZִF!t/?r]?Eh=ڊ2NO>>'>L$; =ֿ0٬a<%9%PK ',I3h%̦I@fK( d6:`(~Fٰz2[wib#4YU'ڦ6(̳"ƞQފ a9 [&K+rvW&'V_ NA`*~ uSowIf*j rJ[nO}`d!ntn6dےFcё.Mkn$?\S|l{ɲl$gk [+(Dy$7prѧu 򐶷 RV\ gxiнZ`_CA {@h?=[_W@vO~ Γ2*f6+)Qaj3FܭVGT }@B7\[ݝe6kF.{+M)4~EYgPġb$UkǙ LDg<JFpZ٥A@q7 2xl'TW+XF:{&_, 'Q96q@8hRBpZ `~\䬯Ah.،H33}7Zzss0;"o} (ol|Pͭ4XfHV1XY(+K Z[Γ֌Ջd%R2eW P{]hG\9 mρ w:!%Ϭ?d=$TxgaA%vȁIu)> ҎkHGe<(p:w6o2(zV;%<9iןR 1"dIqe.eUvN 2Kz5e f89ʼ30ѩYG\봃gXUz'@u =,S "2] m(s=%vɈxAswi@%fq4Ĭot0\ªY>=u椛N|Shm X=`H@pk;g̑ŻV"D5[ &PrgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 08o ~Eo PTP P 8^Bh88c``0n w}55 25577L99@@ HM HMPM PMXM XM`M `MPO OPP PQ QQ`QH S(TX+PK|]f""x86_64-linux/rbconfig.rbnu[ # This file was created by mkconfig.rb when ruby was built. Any # changes made to this file will be lost the next time ruby is built. module Config RUBY_VERSION == "1.8.7" or raise "ruby lib version (1.8.7) doesn't match executable version (#{RUBY_VERSION})" TOPDIR = File.dirname(__FILE__).chomp!("/lib/ruby/1.8/x86_64-linux") DESTDIR = '' unless defined? DESTDIR CONFIG = {} CONFIG["DESTDIR"] = DESTDIR CONFIG["PATCHLEVEL"] = "374" CONFIG["INSTALL"] = '/usr/bin/install -c' CONFIG["EXEEXT"] = "" CONFIG["prefix"] = (TOPDIR || DESTDIR + "/opt/alt/ruby18") CONFIG["ruby_install_name"] = "ruby" CONFIG["RUBY_INSTALL_NAME"] = "ruby" CONFIG["RUBY_SO_NAME"] = "ruby" CONFIG["MANTYPE"] = "doc" CONFIG["NROFF"] = "/usr/bin/nroff" CONFIG["configure_args"] = " '--build=x86_64-redhat-linux-gnu' '--host=x86_64-redhat-linux-gnu' '--program-prefix=' '--disable-dependency-tracking' '--prefix=/opt/alt/ruby18' '--exec-prefix=/opt/alt/ruby18' '--bindir=/opt/alt/ruby18/bin' '--sbindir=/opt/alt/ruby18/sbin' '--sysconfdir=/etc' '--datadir=/opt/alt/ruby18/share' '--includedir=/opt/alt/ruby18/include' '--libdir=/opt/alt/ruby18/lib64' '--libexecdir=/opt/alt/ruby18/libexec' '--localstatedir=/var' '--sharedstatedir=/var/lib' '--mandir=/opt/alt/ruby18/share/man' '--infodir=/opt/alt/ruby18/share/info' '--enable-shared' '--enable-rpath' '--enable-pthread' 'build_alias=x86_64-redhat-linux-gnu' 'host_alias=x86_64-redhat-linux-gnu' 'CFLAGS=-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -I/opt/alt/openssl/include' 'LDFLAGS=-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -L/opt/alt/openssl/lib64 -L/opt/alt/ruby18/lib64 -Wl,-rpath=/opt/alt/openssl/lib64,-rpath=/opt/alt/ruby18/lib64'" CONFIG["vendordir"] = "$(libdir)/ruby/vendor_ruby" CONFIG["sitedir"] = "$(libdir)/ruby/site_ruby" CONFIG["sitearch"] = "x86_64-linux" CONFIG["arch"] = "x86_64-linux" CONFIG["MAKEFILES"] = "Makefile" CONFIG["EXPORT_PREFIX"] = "" CONFIG["COMMON_HEADERS"] = "" CONFIG["COMMON_MACROS"] = "" CONFIG["COMMON_LIBS"] = "" CONFIG["MAINLIBS"] = "" CONFIG["ENABLE_SHARED"] = "yes" CONFIG["DLDLIBS"] = " -lc" CONFIG["SOLIBS"] = "$(LIBS)" CONFIG["LIBRUBYARG_SHARED"] = "-Wl,-R -Wl,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)" CONFIG["LIBRUBYARG_STATIC"] = "-l$(RUBY_SO_NAME)-static" CONFIG["LIBRUBYARG"] = "$(LIBRUBYARG_SHARED)" CONFIG["LIBRUBY"] = "$(LIBRUBY_SO)" CONFIG["LIBRUBY_ALIASES"] = "lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR) lib$(RUBY_SO_NAME).so" CONFIG["LIBRUBY_SO"] = "lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR).$(TEENY)" CONFIG["LIBRUBY_A"] = "lib$(RUBY_SO_NAME)-static.a" CONFIG["RUBYW_INSTALL_NAME"] = "" CONFIG["rubyw_install_name"] = "" CONFIG["LIBRUBY_DLDFLAGS"] = "-Wl,-soname,lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR)" CONFIG["LIBRUBY_LDSHARED"] = "$(CC) -shared" CONFIG["debugflags"] = "" CONFIG["optflags"] = "" CONFIG["cflags"] = "$(optflags) $(debugflags)" CONFIG["cppflags"] = "" CONFIG["RDOCTARGET"] = "" CONFIG["ARCHFILE"] = "" CONFIG["EXTOUT"] = ".ext" CONFIG["PREP"] = "miniruby$(EXEEXT)" CONFIG["setup"] = "Setup" CONFIG["EXTSTATIC"] = "" CONFIG["STRIP"] = "strip -S -x" CONFIG["TRY_LINK"] = "" CONFIG["LIBPATHENV"] = "LD_LIBRARY_PATH" CONFIG["RPATHFLAG"] = " -Wl,-R%1$-s" CONFIG["LIBPATHFLAG"] = " -L%1$-s" CONFIG["LINK_SO"] = "" CONFIG["LIBEXT"] = "a" CONFIG["DLEXT2"] = "" CONFIG["DLEXT"] = "so" CONFIG["LDSHARED"] = "$(CC) -shared" CONFIG["CCDLFLAGS"] = " -fPIC" CONFIG["STATIC"] = "" CONFIG["ARCH_FLAG"] = "" CONFIG["DLDFLAGS"] = "" CONFIG["ALLOCA"] = "" CONFIG["MAKEDIRS"] = "mkdir -p" CONFIG["CP"] = "cp" CONFIG["RM"] = "rm -f" CONFIG["INSTALL_DATA"] = "$(INSTALL) -m 644" CONFIG["INSTALL_SCRIPT"] = "$(INSTALL)" CONFIG["INSTALL_PROGRAM"] = "$(INSTALL)" CONFIG["SET_MAKE"] = "" CONFIG["LN_S"] = "ln -s" CONFIG["OBJDUMP"] = "" CONFIG["DLLWRAP"] = "" CONFIG["WINDRES"] = "" CONFIG["NM"] = "" CONFIG["ASFLAGS"] = "" CONFIG["AS"] = "as" CONFIG["AR"] = "ar" CONFIG["RANLIB"] = "ranlib" CONFIG["YFLAGS"] = "" CONFIG["YACC"] = "yacc" CONFIG["OUTFLAG"] = "-o " CONFIG["CPPOUTFILE"] = "-o conftest.i" CONFIG["GNU_LD"] = "yes" CONFIG["EGREP"] = "/usr/bin/grep -E" CONFIG["GREP"] = "/usr/bin/grep" CONFIG["CPP"] = "gcc -E" CONFIG["OBJEXT"] = "o" CONFIG["CPPFLAGS"] = " $(DEFS) $(cppflags)" CONFIG["LDFLAGS"] = "-L. -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -L/opt/alt/openssl/lib64 -L/opt/alt/ruby18/lib64 -Wl,-rpath=/opt/alt/openssl/lib64,-rpath=/opt/alt/ruby18/lib64 -rdynamic -Wl,-export-dynamic" CONFIG["CFLAGS"] = "-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -I/opt/alt/openssl/include -fPIC $(cflags)" CONFIG["CC"] = "gcc" CONFIG["target_os"] = "linux" CONFIG["target_vendor"] = "redhat" CONFIG["target_cpu"] = "x86_64" CONFIG["target"] = "x86_64-redhat-linux-gnu" CONFIG["host_os"] = "linux-gnu" CONFIG["host_vendor"] = "redhat" CONFIG["host_cpu"] = "x86_64" CONFIG["host"] = "x86_64-redhat-linux-gnu" CONFIG["build_os"] = "linux-gnu" CONFIG["build_vendor"] = "redhat" CONFIG["build_cpu"] = "x86_64" CONFIG["build"] = "x86_64-redhat-linux-gnu" CONFIG["TEENY"] = "7" CONFIG["MINOR"] = "8" CONFIG["MAJOR"] = "1" CONFIG["target_alias"] = "" CONFIG["host_alias"] = "x86_64-redhat-linux-gnu" CONFIG["build_alias"] = "x86_64-redhat-linux-gnu" CONFIG["LIBS"] = "-lpthread -lrt -ldl -lcrypt -lm " CONFIG["ECHO_T"] = "" CONFIG["ECHO_N"] = "-n" CONFIG["ECHO_C"] = "" CONFIG["DEFS"] = "" CONFIG["mandir"] = "$(DESTDIR)/opt/alt/ruby18/share/man" CONFIG["localedir"] = "$(datarootdir)/locale" CONFIG["libdir"] = "$(DESTDIR)/opt/alt/ruby18/lib64" CONFIG["psdir"] = "$(docdir)" CONFIG["pdfdir"] = "$(docdir)" CONFIG["dvidir"] = "$(docdir)" CONFIG["htmldir"] = "$(docdir)" CONFIG["infodir"] = "$(DESTDIR)/opt/alt/ruby18/share/info" CONFIG["docdir"] = "$(datarootdir)/doc/$(PACKAGE)" CONFIG["oldincludedir"] = "/usr/include" CONFIG["includedir"] = "$(DESTDIR)/opt/alt/ruby18/include" CONFIG["localstatedir"] = "$(DESTDIR)/var" CONFIG["sharedstatedir"] = "$(DESTDIR)/var/lib" CONFIG["sysconfdir"] = "$(DESTDIR)/etc" CONFIG["datadir"] = "$(DESTDIR)/opt/alt/ruby18/share" CONFIG["datarootdir"] = "$(prefix)/share" CONFIG["libexecdir"] = "$(DESTDIR)/opt/alt/ruby18/libexec" CONFIG["sbindir"] = "$(DESTDIR)/opt/alt/ruby18/sbin" CONFIG["bindir"] = "$(DESTDIR)/opt/alt/ruby18/bin" CONFIG["exec_prefix"] = "$(DESTDIR)/opt/alt/ruby18" CONFIG["PACKAGE_URL"] = "" CONFIG["PACKAGE_BUGREPORT"] = "" CONFIG["PACKAGE_STRING"] = "" CONFIG["PACKAGE_VERSION"] = "" CONFIG["PACKAGE_TARNAME"] = "" CONFIG["PACKAGE_NAME"] = "" CONFIG["PATH_SEPARATOR"] = ":" CONFIG["SHELL"] = "/bin/sh" CONFIG["ruby_version"] = "$(MAJOR).$(MINOR)" CONFIG["rubylibdir"] = "$(libdir)/ruby/$(ruby_version)" CONFIG["archdir"] = "$(rubylibdir)/$(arch)" CONFIG["sitelibdir"] = "$(sitedir)/$(ruby_version)" CONFIG["sitearchdir"] = "$(sitelibdir)/$(sitearch)" CONFIG["vendorlibdir"] = "$(vendordir)/$(ruby_version)" CONFIG["vendorarchdir"] = "$(vendorlibdir)/$(sitearch)" CONFIG["topdir"] = File.dirname(__FILE__) MAKEFILE_CONFIG = {} CONFIG.each{|k,v| MAKEFILE_CONFIG[k] = v.dup} def Config::expand(val, config = CONFIG) val.gsub!(/\$\$|\$\(([^()]+)\)|\$\{([^{}]+)\}/) do |var| if !(v = $1 || $2) '$' elsif key = config[v = v[/\A[^:]+(?=(?::(.*?)=(.*))?\z)/]] pat, sub = $1, $2 config[v] = false Config::expand(key, config) config[v] = key key = key.gsub(/#{Regexp.quote(pat)}(?=\s|\z)/n) {sub} if pat key else var end end val end CONFIG.each_value do |val| Config::expand(val) end end RbConfig = Config # compatibility for ruby-1.9 CROSS_COMPILING = nil unless defined? CROSS_COMPILING PK|]N x86_64-linux/digest/sha1.sonuȯELF> @@8 @      @@888$$ Std Ptd, , , ,,QtdRtd GNUeƓ*ؽp I@ (sS|CEDVqX x , F"_j k X U P _ __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeInit_sha1rb_requirerb_path2classrb_define_class_underrb_cObjectrb_data_object_allocrb_internrb_ivar_setSHA1_InitSHA1_UpdateSHA1_FinishSHA1_Finallibruby.so.1.8libcrypto.so.10libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64N ui p t  @               ( 0 8  @  H  P  HHq HtH5 % hhhhhhhhq% D% D% D% D% D% D% D% DH= H H9tH6 Ht H= H5 H)HHH?HHtH HtfD= u+UH= Ht H=n de ]wUH=SHH=H=HHH5H1H5 1HHP H8H=jHHHHH[]=f.HHHHHdigestDigestDigest::BaseSHA1metadata;(TDl$zRx $FJ w?:*3$"Dp$\EHD bJAGNU@  +6DN| X   o`x    oPoo"o  @`GA$3a1X GA$3p1067P GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1067 GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realignsha1.so-1.8.7-16.el8.x86_64.debugk77zXZִF!t/]?Eh=ڊ2N> ^)U)v3,1?G]]iGʦcӃA5N)({(.8/|gbthwݨ2)d֪On;ʌiԸ(ԋն3b9–'Xhm]"N&M#,2)*PB ^ e&7b${cEW4E"š)Wf8۾\6\/'vn",)Tk5]R=BGU7l,̛kmpiԢ q฼ܱl'p͸dR,:QfJ٦#A-ŽFAqzH2B]6AYSi!1PM MK[@I_A =)5qWmt ߥ]j"B%X-冪K;*p @.<&DSQUL:{}t4+2OPK$R&z9` 3n|5F'%u& h~·d#rAi7?N$ZiϹus쵰U4f5630t+G$U#ʑS(o ,= u84q>]A]pe\7,m jož\tjؑxy`,CyX'{Ըi- ,ULULܣOeESGFm*VVޠiP) 4R薔@m aZ(2Ŋ;v hJ? dgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``8( 0xx8o""(EoPP@T^BhXXcn  w b} 2  ), , ,X X      @ ( X` `8  `d("X1PK|]v AAx86_64-linux/digest/sha2.sonuȯELF>@ @8:@8 @@(@( -- -  -- - 00888$$ ( ( ( Std ( ( ( Ptd$$$QtdRtd-- - ppGNUziu3@ hLIRr\2&BEb{Y˨I|"6DM(qX "FV,-I~\& t , F"| [R 081 U =:  k @8C@1  $ w781  ` Pj P u w  __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_Digest_SHA256_InitSHA256_Transformrb_Digest_SHA256_Updatememcpy__assert_failrb_Digest_SHA256_Finishrb_Digest_SHA512_InitSHA512_Transformrb_Digest_SHA512_UpdateSHA512_Lastrb_Digest_SHA512_Finishrb_Digest_SHA384_Initrb_Digest_SHA384_Updaterb_Digest_SHA384_FinishInit_sha2rb_requirerb_internrb_path2classrb_define_class_underrb_cObjectrb_data_object_allocrb_ivar_setlibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.14GLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64&Hui S-  -  - - / / / /  /  0 0 0 0 0 0  1 (1 01 0  0 (0 00 80 @0 H0 P0  X0 `0 h0  p0  x0  HHq$ HtH5r$ %s$ hhhhhhhhqhah Qh Ah 1h !%# D%# D%# D%# D%}# D%u# D%m# D%e# D%]# D%U# D%M# D%E# D%=# DH=# H# H9tH~" Ht H=# H5# H)HHH?HHtHU" HtfD=}# u+UH=2" Ht H= 9dU# ]wHt3fo /fo7HG fG(WG8GHGXAWHLAVA/BAUATUHo(SDID_Dx XDhH|$D`@Hl$D$%DE0ADd$DEEAIA҉ىډ؋> D!H1ʉA9I1ʉD!1D$D D!ADC<71D 1D1D!1HyDL9el$LxHl$Dd$D$i,@AD\$IEDl$AADD$DDaDDLDDA1qD1DL$DDEDA A D1A΃ AD1ANtA!ADƉ A611D!D1EΉt$ t$1ȉE!A 1DD1!D1A@ HD$0PDPDX DHxXDh[]A\A]A^A_HAUATUHSHHHH HG IH?uYIH? ID$HLl@fDHHH@HE L9uA?MH[]A\A]@@)‰H|(L9rzHLGIIHHDHDL)I)׃r1ƃM 2M 09rHU HI)Hu(HII?/^fDttDfDDHM(DAscAEtAUU(tDADfDILe H[]A\A]LILe H[]A\A]DIEHu0HHE(DITHTH)A I)̓r1҉уI| H<9r{DDAUU(DADDRH ] H5 H= DATUSHHHHHG Lg(HHHHW ?PD(8@LHjfC(ID$0AD$AD$ HS HS`LH:1ʉTHH uH{H1HHC`H)KhH[]A\fG(AD$AD$ ID$0G(D8HL(1)Ѓs]XM1fD?@@)Ht(19rfDHqHHDHH)ȃ1҉уH<9rDH J H5 H= fHHtjfo\ fo d HGPHXfo` foh HGpGOW_H)1HHBHHB@fAWHLh AVI"(ט/BAUATUHoPSLIL_LxHX Lh(H|$L`0HH@8Hl$HD$H%@M0ILd$LMMIIHIHHHH>HHL!HH1HHI9HIH1HHL!H1HD$HLHHLHH!ILHK<7H1LHH1LH1L!H1HH LL9ILxHl$HJiHl$Ld$HD$+IL\$IMLl$IIDHD$HHLDaDLLLLIHHH1qL1LL$LDMLIIHL1A΃ AL1INtI!IHDHHHHHI6H1HHH1HHL!L1MHHHHHHt$HHt$H1HM!IHH1LL1H!L1HHAPHD$H0HPLPLXLH Hx(HX0Lh8[]A\A]A^A_ff.H+AUATUSHHH3HH'HO@IHHunIH!ID$HLHHHC@HHC@H=wHCHHL9uAMH[]A\A]f)‰AHDPM9rqHHxHHJLJLH) H)ƉHHK@HHS@sHCHLM)HsPHII!`DttBLfBLHO@HSPAsVAEuyILc@Lc@HCHH[]A\A]DLHI!Lc@Lc@̐IEH{XLHHCPDILHLH)A H)HAECPAuDALfLbBLBLHO@AECPDALL3H H5H=(+ff.UHoPSHHHG@HWHHHHHWHHHw@PDPpvjHHCH}H1HHCPH)HEv~HHSHHs@HHHHH[]pHLP)ЃrwHyHHDHH)1HHSHHs@f.HGPHXH1HG`HH)pHCP\fDtt1ftf.HLP1)Ѓs-1fD@HqHHDHH)ȃ1҉уH<9rpfDDD@ff.USHHteHHHt(Q1HHHHTHH@uH{H1HǃHH)HH[]H UH5YH=Ymff.fHHtjfoLfo THGPHXfoPfoXHGpGOW_H)1HHBHHB@f'USHHteHHHt(!1HHHHTHH0uH{H1HǃHH)HH[]H uH5)H=)=f.AVH=AUATUSH=,H=H]H=INLH5HIyH-2 11H5G IH}HLH]LLH5;H}11H5 IHLH&LLH5{H}11H5U I]HL[H]A\A]A^HHsha2.ccontext != NULLcontext != NULL && data != NULLrb_Digest_SHA384_Finishrb_Digest_SHA512_Finishrb_Digest_SHA512_Updaterb_Digest_SHA256_Finishrb_Digest_SHA256_Updateɼg j;ʄg+rn<6_:OтRQl>+hkAكy!~[؞]|6*)bp0ZY9Y/1 g&3gXhJd . ۤOHG"(ט/Be#D7q/;Mۉ۵8H[V9YO?m^BؾopE[N1$} Uo{t]r;ހ5%ܛ&itJi%O8GՌƝew̡ $u+Yo,-ntJAܩ\SڈvfRQ>2-m1?!'Y= % GoQcpn g))/F '&&\8!.*Zm,M߳ 8ScTs ew< jvG.;5,rdL迢0BKfpK0TQlReU$* qW5ѻ2pjҸSAQl7LwH'Hᵼ4cZų 9ˊAJNscwOʜ[o.h]t`/CocxrxȄ9dnj(c#齂lPyƲ+SrxqƜa&>'!Ǹ}xnO}orgȢ}c ?G5 q}#w($@{2 ˾L*~e)Y:o_XGJDlg jgrn<:ORQhك[/BD7q۵[V9Y?^[1$} Ut]rހܛtiGƝ̡ $o,-tJܩ\ڈvRQ>m1'Y GQcg)) '8!.m,M 8STs e jv.,r迢KfpK£Ql$օ5pjl7LwH'4 9JNOʜ[o.htocxxȄnjlPxqdigestmetadataDigestDigest::BaseSHA256SHA384SHA512;d4D4D0DzRx $PFJ w?:*3$"D\=@p8FLH B(A0E8 0A(B BBBp[OBA D(D0s (A ABBE H0j (A ABBH T (A ABBF ,(FAA  ABA XTw@lFLL B(A0E8U0A(B BBB` uOBA A(G0 (A ABBJ H0d (A ABBF ((EEG  AAH (@EAD g AAA lw ,EAD g AAA 8hFIB A(A0(D BBBGNU - &_ h L- - o`  0 80  ohoo,o-  0 @ P ` @0 @hGA$3a1h Y GA$3p1067CGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1067PIGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY=GA+GLIBCXX_ASSERTIONSsha2.so-1.8.7-16.el8.x86_64.debug|K7zXZִF!t/A]?Eh=ڊ2N !k& Z;$10,>Dib5kv x]\q a-[ul(7O$3^X+{4F J{pRi-rpfP(w|{æ+#kEVfׇRu61?WGR@f#^q;l.c- -qEQ[vPR o:Ɉ`EoԶ -X6ikUTz }S~Sq'1ҴϲRla$h{!-M- (gK*+3d!qSGMxÌ*_mlCgKQh@$/n/.fܨo!`{ᇳl7Z U:w:Ob!z5sVdAe FzF'| l*>^=1g'%˚!2Ijlp2-{V|?3^KG|@jMQ@O{2O @ @8 @     @@888$$ Std Ptd   ,,QtdRtd GNU P+g(B A^U|CEqX+qZ w , F"^iU @ f S Z  __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeInit_md5rb_requirerb_path2classrb_define_class_underrb_cObjectrb_data_object_allocrb_internrb_ivar_setMD5_InitMD5_UpdateMD5_FinishMD5_Finallibruby.so.1.8libcrypto.so.10libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64 t Iui k 0               ( 0 8  @  H  P  HHy HtH5 % hhhhhhhhq%  D% D% D% D% D% D% D% DH= H  H9tHF Ht H= H5 H)HHH?HHtH  HtfD= u+UH= Ht H=~ du ]wUH=SHH=H=HHH5H1H5 1HH` H8H=iHHHHH[]=f.HHHnHHdigestDigestDigest::BaseMD5metadata;(TDl$zRx $FJ w?:*3$"Dp$\EHD bJAGNU0  &1?Iw P   o`x    oHooo @\GA$3a1P GA$3p1067@ GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1067 GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realignmd5.so-1.8.7-16.el8.x86_64.debug/7zXZִF!t/]?Eh=ڊ2N> ^)U)v3,1?G]]iGɢcӃA<dJvmkXCTBvE/|Hx=&;T_y Ԏ;:(ͩFʷ󓔬h<]GXhL=.I^ [IP<*̮EQ8#ծFn!P[rA[9r˘1p| On,_eH@|B6<0Sc$p/*^SI]W3QHڜ 5Hv_-xOeгӯm6AEWG^a¿H-ji fl͒DwFtUE@Rԏ:Ϩ3_{:{J-3{xČ nD@1ej5v vH؆ztR՟(6i^y.3-]:9&!Giɽ*xWxc%g&>X]\b#2/~h js `r=$¬G/ney#ɠ|u]{d9@VYwX%@ 6Y'œD$4s=HW|W"Ð)-D=tmHMzyajܟ v!['N1({c}~* u3ȧfKe ޛ8)gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``8( 0xx8o(EoHH@T^BhPPcppn w b} 2 (  ,H H      @ ( X` `8  `d("\1PK|]pC x86_64-linux/digest/rmd160.sonuȯELF> @ @8 @     @@888$$ Std Ptd< < < ,,QtdRtd GNU?%,CA9uONlD Ab&|CEqX z , F"alU ` ~ k r  __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeInit_rmd160rb_requirerb_path2classrb_define_class_underrb_cObjectrb_data_object_allocrb_internrb_ivar_setRIPEMD160_InitRIPEMD160_UpdateRMD160_FinishRIPEMD160_Finallibruby.so.1.8libcrypto.so.10libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64 t aui  P                ( 0 8 @  H  P  HHa HtH5r %s hhhhhhhhq% D% D% D% D% D% D% D% DH= H H9tH& Ht H= H5 H)HHH?HHtH HtfD=} u+UH= Ht H=^ dU ]wUH=SHH=H=HHH5H1H5 1HH@ H8H=lHHHHH[]=f.HHH^HHdigestDigestDigest::BaseRMD160metadata;(TDl$zRx $FJ w?:*3$"Dp$\EHD bJAGNUP  #3>IWa h    o`x    o`oo4o   @`GA$3a1h GA$3p1067` GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p1067  GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realignrmd160.so-1.8.7-16.el8.x86_64.debugg܃7zXZִF!t/]?Eh=ڊ2NH@> +p)o·]]h]pƷך9Dp^B+{RkRa!mVGݡpqJ eGXhWf.y=ĦV)&/I!^ >flh,yJPITC+^0xQ(7DM)M=OoaP%Q u "E)|6{Ŗ]l(4WWS#W .ȣ͖ݘD{0T\q>ugxzy'9{0)GvZyC%C2OX=@`׀1 s @-y9\>tF)L=78qyz5rB1f;Eq9xCFeG0_"4Ah 8/FoS`OMW:ܱB$ 6I* 5EL2dݕ<Q&"2&%'* P>}>*'p#`ʜ6 #l/_r|`gj΁BJ8cҵq%aEOuʉ %U \|}^qo(vVVB䍢5j5j$0GiM@ ab 8C>nBӍӋxbeV\-QXȉ>'o ,kKאK{d^C(*зN8䅶X%z\wk:l=C{IvŮ=;PgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``8( 0xx8o44(Eo``@T^Bhhhcn w b}  2  +< < ,h h      @ ( X` `8  `d("`1PK|];..#x86_64-linux/digest/bubblebabble.sonuȯELF>0 @'@8 @HH      00888$$((( Std((( PtdDDQtdRtd  ppGNUNZ"ħvR^$@ BE\1A|qX U pe, F"sx   zx __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_string_valuerb_str_newrb_eRuntimeErrorrb_raiserb_funcallrb_funcall2Init_bubblebabblerb_requirerb_path2classrb_define_module_functionrb_define_singleton_methodrb_define_methodrb_internlibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64iui               ( 0 8 @ H  P  X  `  h p HHQ HtH5b %c hhhhhhhhqhah Qh Ah 1% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E DH=A H: H9tH Ht H= H5  H)HHH?HHtHe HtfD= u+UH=B Ht H= Yd ]wAWAVAUATUSH(H|$H|$HD$H*LhL`LHH9Ht@1HD$H@HD$xMHD$ME1AIH-FAHxL$A)sCDIG-A >HAWHƒAWB4D)AAAø98AD)M9C HAAEADARA)McBDDوGȃAGAщAR)HcDGM9xHD$H([]A\A]A^A_fDDAyLcAYMcHcHcR)DHcL5Ht$B HBx>뛻aAeAH H5@H81VfDHH5Q 11XHHff.H@HHH5  H׉BHHffDATH=USH= H=IH=HLHsHH5HHeH5H1H H5zH=A[]HL A\HHdigest string too longdigestDigestDigest::InstanceDigest::Classbubblebabblebcdfghklmnprstvzxaeiouy;D`(X0zRx $pFJ w?:*3$"DH\*BBB B(A0A8D` 8A0A(B BBBG d$HT| x*HZ(FHA AIGNU  +;FQ_i  8  o`    ` oooTo   0 @ P ` GA$3a1E GA$3p1067 7GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY  GA+GLIBCXX_ASSERTIONSbubblebabble.so-1.8.7-16.el8.x86_64.debuge{x7zXZִF!t/G]?Eh=ڊ2N$=fK> zqbA&@o2Jz_V_)|5gLcS2xڈ*EkSിQB4T`S-Z*ݙz-4&?0Fez|<-Bz~y 5w +M^'Y-ѶzjkLm0X]7 ތl,*FFWN/SE ]|+UAtP6QVZɯpKt =oz]^U e',M.Bo.Įb 8U:d}ҩq \NIM,4J]v~ y֪-JUDcg_Dlo]%_ttU\\՞a],*&]9dP1g-e]k~CH6ؑUH+{^> Bk/ccNL.+F@HHzwI}͹n5ګUb݂A$>'$k }XySpaXD݁_8Jl7YUR A'9pq׿Ww!sG/eҠW ]Q7.0?edXe!Y i|O Q̝_)+4@#&̀ LyEK/X@y9i[8ƒ.q(Pw"[$JlND!1D!|}.FN(0lYCfJ2>i!'S+Wk)z+2YN Z۱gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 08oTT*Eo T^B`` hcnp p w0 0 }88 PPwD((     0 ( xx x  `x H "0"x&+PK|]: r rx86_64-linux/sdbm.sonuȯELF>@j@8 @YY `]`] `]  x]x] x] 00888$$YYY StdYYY PtdLLLQtdRtd`]`] `] GNUGuF}WC^fB:A$ :>EBE|Ϲ = %2?ѣnVqX?~G*ŤZx|[!y (  5uZa]LUiP( p.h>#ku=, F"@ 1a  b  &3 $`b  p%5 ' Da  &2 , % 'w #r__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizereadlseeknullitemmemcmpmemcpysdbm_prep__fxstatfree__errno_location__stack_chk_failsdbm_openstrlensdbm_closesdbm_firstkeysdbm_nextkeysdbm_hashsdbm_fetchsdbm_deletewritesdbm_storerb_check_typerb_raiserb_hash_newrb_tainted_str_newrb_hash_asetrb_ary_newrb_assoc_newrb_ary_pushrb_string_valuerb_iteraterb_internrb_funcallrb_hash_delete_ifrb_yieldrb_block_given_prb_ary_new2rb_warnrb_eArgErrorrb_scan_argsrb_fix2intrb_check_safe_objruby_xmallocrb_num2intrb_sys_failrb_data_object_allocrb_ensurerb_securerb_error_frozenrb_str_duprb_protectrb_jump_tagrb_eIndexErrorInit_sdbmrb_cObjectrb_define_classrb_eStandardErrorrb_mEnumerablerb_include_modulerb_define_alloc_funcrb_define_singleton_methodrb_define_methodlibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.14GLIBC_2.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64^ ui ii ui `] ph] 0p] p] _ >_ _ _ _ _ (_ 0_ 1_ 2_ 4_ 5`  ` (` 0` 8` @` H`  P`  X` E`` ?h`  p`  x`  ` ` ` ` ` ` ` F` ` ` @` ` ` ` ` ` a a a a  a G(a !0a "8a #@a $Ha %Pa &Xa '`a <ha Cpa )xa *a =a +a ,a -a .a /a 3a Da 5a 6a 7a 8a 9HHiJ HtH5J %J hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Q%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%F D%}F D%uF D%mF D%eF D%]F D%UF D%MF D%EF D%=F D%5F D%-F D%%F D%F D%F D% F D%F D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%E D%}E D%uE D%mE D%eE D%]E D%UE D%ME D%EE D%=E D%5E D%-E D%%E DH=!E HE H9tHB Ht H=D H5D H)HHH?HHtHB HtfD=D u+UH=B Ht H=@ dD ]w1fwfѸftYwHGfHOf9|?~#5D89'D@fD9|A9DHٸ1ff.fAWHPIAVAUE1ATU1SHHD$1HHE1fDHt$A?>HMHHLH?H?H4H=HÁH)IDAPH)skHDAT$HNlhM9oAMI]MIIHMMIIM;HtLA?1H H8IcH*HH!MoIG I9o@uH[]A\A]A^A_MgHIP1HHLH 1H)IGHILJ@HA{Hx.ALHxLt Io@w1mHcH*HH!Cf.UHoHSHHfDD9HcȺH4 ~T5HDMHH)Hu}HC({C0HpHs(H9C@tH 1Hx_Hs({Hs@HH~BHt6C0SHC0f`H ? HRHtH[]H> KHHRH[]ff.@AWAVAUATUSH~}LcHT$IMHl6fAD]HH9tAIT]A)HD9uH|$LLNuHD[]A\A]A^A_E1ff.AUATIUHSHL/fE~Bo)Ӆu.IEf\EL,D)Eu9fB\-fEH[]A\A]HcHcDD$ H5DD$ fDHcIcLHDATUSH/AHHE1UI9LcЃNDSLIRHIH SLL HH)B c)t,HH)HfDA A HH9uJT)IJLSf.BHfBH9uD#AAfD#[D]A\APAVIAUIPATAUSHdH%(H$1HH@H@ H@(@0@DL1BCDL1(HƿHD$01ҹHC@HHHHC1HHHSHHHPHHHH$dH3 %(HuTHĠ[]A\A]A^4D; {H1D Nff.AWAVAUATUSHt$ H?HALxHC{HvHx)HC@HHC(C0H[]@HY9 KHPHH[]H.9 HPHH[]HtBfHH8 HPHHff.t(FHL1fDHHi3WHH9u1ff.fAUATIUSHHuHHHt@HDHjHHuKHL8 KHHRH[]A\A]fDH$8 HHRH[]A\A]@sHt8LkHDHL&t"HHTHDHTFHL)fDH7 HR뢐AVHAUIATUSHHouzIDL|HHtMLsHDLLt_Hs@{1H Hx {LHx []A\A]A^ÃKDfDƐ{ff.AWAVAUATLgHUSHHhHt$L$PLt$PT$HdH%(H$X1HPD$L HD$8HGPHD$@LLHk HHI$Ht$8L}HFH|$@HHLH)HLH$PfImL|$(H\$0ILIDHD$ fMIOD)N, LHȉHL)HL$T$LHD$(AIET$HL$LI^AWL;|$ uIH\$0Hk L}HD${H!L L;Hs@1H H{LHHk@H{PILHLI$H)IH)΁H@HLC;MIhIIIHMIIHIHL$I H;HtQ1LLD$ LL$HP;HPeH4HL$;LD$ LL$HHHH?H4HŁH)LH?H=I H)+PHCI9| HHC1L]H;HPHHKH~ALt$HT )ЍV9HC Hs1ɋ{HPHT$H 1HLqHC Hs@HKH Hx;{L3Hx&l$L,H5G D1H$XdH3%(uJHh[]A\A]A^A_ÐH1H bHxŋ{LHf@AWAVAUATIUDSH(Hu!HHt_G4Av*%H([]A\A]A^A_fIDIDL$ LL$VHHHD$DL$ HEHL$HD$At^DUHEfE~jDLDLD$H}HDT$ D$(\fDkADLHDUHL$EѸECT)AV9}Ht$DHL$L$tEDLH}HL3Hu@}1H Hx}HuHHfMfD$DL$ LD$MHEHBH`S"H.HC HtHx[HD[fPXH51HH= 3 %DAV"AUATUSHHC H~L`Mtu\LIQHHHtNfDHHLHcHHcHILLH;L#HHHu[L]A\A]A^15DAWAVAUATUSHH"HIHC Ht}L`MttLHHHtOHHLbHcHIIIcLHHLHLmHHHuHL[]A\A]A^A_1yfS"H^HC HtFHXHt=xt1[ø[fHHtHHu11AT"USHHk Ht[LeMtRHcE~[HD]A\LhHt#1ېLuHuHcHD][]A\ø11AV"AUATUSHgHC HL`Mt}LIHHHtVfDHHLHcHWHcHIILHnLHLHHHu[L]A\A]A^1ff.fU"SHHHC HtXHXHtOHH7Ht0fHHHcHHHOH'HuHH[]1AU"SHH)HC HtMHXHtDbHHHt%fHcH5HHHHuHH[]1ff.ATUSHHH|$Ht$HD$"HL`hHC Ht)HxHt LHHH[]HA\1PSHHH|$Ht$u"H(HC HtjHXHtaHHt?fHHHL$HcH;QuHqHtHHuH1[fH[1ff.ATUSHHH|$Ht$"HuHC HHhHt{HHIHtC@HLHHL$HcH;QuHqHt$HHIHuH[]A\IcH-H[]A\1ff.fSHHH^H=H[ff.fSHH=LH11H[1zf.H1HHDS"H>HC HtVHxHtMHt>fHcHUH"HHC HtHxHtHuH[1U"HSHHE HttHXHtkHOHtTf.HHHcHH"HeHE Ht HXHtHHuHH[]15DAV"AUIATUSIE HHhHHIHHt|f.HLHbHcLHIHcLHHHH"LIE Ht(HhHtHIIHHu[L]A\A]A^1[ff.AUIATUSHHH|$Ht$qHD$"LL`HhIE HteHxHt\LHt&HcH+HHH[]A\A]f.HutHcLHH1f1@AUHcATIIUSHHHE~/AELlH3L1HHH/L9uHH[]A\A]ff.1AVHcAUIATUHSHI;4"LIE HHhHH\IHHuG@"LIE HHhHH9IHHHLHHcHHcLHsHHHH-HyHLi1H=R~4EHlfDH3L1HzLHH9u[L]A\A]A^1H% H5H81ff.fS"HnH[ HtH{HtHC[1AATUSHH9H dH%(HD$1Hl$LD$HH|$H@AHH|$,EHD$1ҾHxHHHC HhHHL$dH3 %(H []A\f.HAH|$fDHArH|$HD$DBHxHHd>HD$11HxHH@AuKfkAHD$Hx@H 11ff.ATH sI1UH1SLHH1HtuH[]A\H[]A\H=# HH[H]A\CSHHHtH[!SHuHtHu[H= ff.AW1AVAUATUSHH"HLc MI\$HHHIHtqHHIcHIHT${HT$LIHchHLHIwA$xA$HLL[]A\A]A^A__H[]A\A]A^A_1ff.fAWAVAUIATUSHXdH%(HD$H1LD$<I1"LtIm HH]HEEH߉D$,IIAHHD$KU4hlE=;?t($z~(=S^ ů ΄V0dWo3.́CbblWꙌfْtAT'Pƺ^F#P0cVg^ɧ:^o-cx'}y{nOd].,$R+|HgV/x}# QUK0[8tͳoU0v OևtDHУgWDeU-4I Tc0 SXεj96dOc5jGT#lYPS.Hhtk(J C̀'Oh<ɴoNþAGg0N3h"B4wQBp)]BX6o5nݖ$&ol_fe n#P$[ =n@)bͲIGJOͥGzۢrwI!'X`Qt!רC07!NIF4Хϴ d/rnU,:)j?Ig1-O2dX#IT=4EUp.'0WW}3c ٴ[#%ҫV" 9ޮTaA #include #if defined(HAVE_DLFCN_H) # include # /* some stranger systems may not define all of these */ #ifndef RTLD_LAZY #define RTLD_LAZY 0 #endif #ifndef RTLD_GLOBAL #define RTLD_GLOBAL 0 #endif #ifndef RTLD_NOW #define RTLD_NOW 0 #endif #else # if defined(HAVE_WINDOWS_H) # include # define dlclose(ptr) FreeLibrary((HINSTANCE)ptr) # define dlopen(name,flag) ((void*)LoadLibrary(name)) # define dlerror() "unknown error" # define dlsym(handle,name) ((void*)GetProcAddress(handle,name)) # define RTLD_LAZY -1 # define RTLD_NOW -1 # define RTLD_GLOBAL -1 # endif #endif #if !defined(StringValue) # define StringValue(v) if(TYPE(v) != T_STRING) v = rb_str_to_str(v) #endif #if !defined(StringValuePtr) # define StringValuePtr(v) RSTRING((TYPE(v) == T_STRING) ? (v) : rb_str_to_str(v))->ptr #endif #ifdef DEBUG #define DEBUG_CODE(b) {printf("DEBUG:%d\n",__LINE__);b;} #define DEBUG_CODE2(b1,b2) {printf("DEBUG:%d\n",__LINE__);b1;} #else #define DEBUG_CODE(b) #define DEBUG_CODE2(b1,b2) b2 #endif #define VOID_DLTYPE 0x00 #define CHAR_DLTYPE 0x01 #define SHORT_DLTYPE 0x02 #define INT_DLTYPE 0x03 #define LONG_DLTYPE 0x04 #define FLOAT_DLTYPE 0x05 #define DOUBLE_DLTYPE 0x06 #define VOIDP_DLTYPE 0x07 #define ARG_TYPE(x,i) (((x) & (0x07 << ((i)*3))) >> ((i)*3)) #define PUSH_ARG(x,t) do{x <<= 3; x |= t;}while(0) #define PUSH_0(x) PUSH_ARG(x,VOID_DLTYPE) #if SIZEOF_INT == SIZEOF_LONG # define PUSH_I(x) PUSH_ARG(x,LONG_DLTYPE) # define ANY2I(x) x.l # define DLINT(x) (long)x #else # define PUSH_I(x) PUSH_ARG(x,INT_DLTYPE) # define ANY2I(x) x.i # define DLINT(x) (int)x #endif #define PUSH_L(x) PUSH_ARG(x,LONG_DLTYPE) #define ANY2L(x) x.l #define DLLONG(x) (long)x #if defined(WITH_TYPE_FLOAT) # if SIZEOF_FLOAT == SIZEOF_DOUBLE # define PUSH_F(x) PUSH_ARG(x,DOUBLE_DLTYPE) # define ANY2F(x) (x.d) # define DLFLOAT(x) ((double)x) # else # define PUSH_F(x) PUSH_ARG(x,FLOAT_DLTYPE) # define ANY2F(x) (x.f) # define DLFLOAT(x) ((float)x) # endif #else # define PUSH_F(x) PUSH_ARG(x,DOUBLE_DLTYPE) # define ANY2F(x) (x.d) # define DLFLOAT(x) ((double)x) #endif #define PUSH_D(x) PUSH_ARG(x,DOUBLE_DLTYPE) #define ANY2D(x) (x.d) #define DLDOUBLE(x) ((double)x) #if SIZEOF_INT == SIZEOF_VOIDP && SIZEOF_INT != SIZEOF_LONG # define PUSH_P(x) PUSH_ARG(x,INT_DLTYPE) # define ANY2P(x) (x.i) # define DLVOIDP(x) ((int)x) #elif SIZEOF_LONG == SIZEOF_VOIDP # define PUSH_P(x) PUSH_ARG(x,LONG_DLTYPE) # define ANY2P(x) (x.l) # define DLVOIDP(x) ((long)x) #else # define PUSH_P(x) PUSH_ARG(x,VOIDP_DLTYPE) # define ANY2P(x) (x.p) # define DLVOIDP(x) ((void*)p) #endif #if defined(WITH_TYPE_CHAR) # define PUSH_C(x) PUSH_ARG(x,CHAR_DLTYPE) # define ANY2C(x) (x.c) # define DLCHAR(x) ((char)x) #else # define PUSH_C(x) PUSH_I(x) # define ANY2C(x) ANY2I(x) # define DLCHAR(x) DLINT(x) #endif #if defined(WITH_TYPE_SHORT) # define PUSH_H(x) PUSH_ARG(x,SHORT_DLTYPE) # define ANY2H(x) (x.h) # define DLSHORT(x) ((short)x) #else # define PUSH_H(x) PUSH_I(x) # define ANY2H(x) ANY2I(x) # define DLSHORT(x) DLINT(x) #endif #define PUSH_S(x) PUSH_P(x) #define ANY2S(x) ANY2P(x) #define DLSTR(x) DLVOIDP(x) #define CBPUSH_0(x) PUSH_0(x) #define CBPUSH_C(x) PUSH_C(x) #define CBPUSH_H(x) PUSH_H(x) #define CBPUSH_I(x) PUSH_I(x) #define CBPUSH_L(x) PUSH_L(x) #define CBPUSH_F(x) PUSH_F(x) #define CBPUSH_D(x) PUSH_D(x) #if defined(WITH_CBTYPE_VOIDP) # define CBPUSH_P(x) PUSH_ARG(x,VOIDP_DLTYPE) #else # define CBPUSH_P(x) PUSH_P(x) #endif #if defined(USE_INLINE_ASM) # if defined(__i386__) && defined(__GNUC__) # define DLSTACK # define DLSTACK_METHOD "asm" # define DLSTACK_REVERSE # define DLSTACK_PROTO # define DLSTACK_ARGS # define DLSTACK_START(sym) # define DLSTACK_END(sym) # define DLSTACK_PUSH_C(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_H(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_I(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_L(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_P(x) asm volatile ("pushl %0" :: "g" (x)); # define DLSTACK_PUSH_F(x) asm volatile ("flds %0"::"g"(x));\ asm volatile ("subl $4,%esp");\ asm volatile ("fstps (%esp)"); # define DLSTACK_PUSH_D(x) asm volatile ("fldl %0"::"g"(x));\ asm volatile ("subl $8,%esp");\ asm volatile ("fstpl (%esp)") # else # error --with-asm is not supported on this machine # endif #elif defined(USE_DLSTACK) # define DLSTACK # define DLSTACK_GUARD # define DLSTACK_METHOD "dl" # define DLSTACK_PROTO long,long,long,long,long,\ long,long,long,long,long,\ long,long,long,long,long # define DLSTACK_ARGS stack[0],stack[1],stack[2],stack[3],stack[4],\ stack[5],stack[6],stack[7],stack[8],stack[9],\ stack[10],stack[11],stack[12],stack[13],stack[14] # define DLSTACK_SIZE (sizeof(long)*15) # define DLSTACK_START(sym) # define DLSTACK_END(sym) # define DLSTACK_PUSH_C(x) {long v=(long)x; memcpy(sp,&v,sizeof(long)); sp++;} # define DLSTACK_PUSH_H(x) {long v=(long)x; memcpy(sp,&v,sizeof(long)); sp++;} # define DLSTACK_PUSH_I(x) {long v=(long)x; memcpy(sp,&v,sizeof(long)); sp++;} # define DLSTACK_PUSH_L(x) memcpy(sp,&x,sizeof(long)); sp++; # define DLSTACK_PUSH_P(x) memcpy(sp,&x,sizeof(void*)); sp++; # define DLSTACK_PUSH_F(x) memcpy(sp,&x,sizeof(float)); sp+=sizeof(float)/sizeof(long); # define DLSTACK_PUSH_D(x) memcpy(sp,&x,sizeof(double)); sp+=sizeof(double)/sizeof(long); #else # define DLSTACK_METHOD "none" #endif extern VALUE rb_mDL; extern VALUE rb_mDLMemorySpace; extern VALUE rb_cDLHandle; extern VALUE rb_cDLSymbol; extern VALUE rb_cDLPtrData; extern VALUE rb_cDLStructData; extern VALUE rb_eDLError; extern VALUE rb_eDLTypeError; #if defined(LONG2NUM) && (SIZEOF_LONG == SIZEOF_VOIDP) # define DLLONG2NUM(x) LONG2NUM((long)x) # define DLNUM2LONG(x) (long)(NUM2LONG(x)) #else # define DLLONG2NUM(x) INT2NUM((long)x) # define DLNUM2LONG(x) (long)(NUM2INT(x)) #endif typedef struct { char c; void *x; } s_voidp; typedef struct { char c; short x; } s_short; typedef struct { char c; int x; } s_int; typedef struct { char c; long x; } s_long; typedef struct { char c; float x; } s_float; typedef struct { char c; double x; } s_double; #define ALIGN_VOIDP (sizeof(s_voidp) - sizeof(void *)) #define ALIGN_SHORT (sizeof(s_short) - sizeof(short)) #define ALIGN_INT (sizeof(s_int) - sizeof(int)) #define ALIGN_LONG (sizeof(s_long) - sizeof(long)) #define ALIGN_FLOAT (sizeof(s_float) - sizeof(float)) #define ALIGN_DOUBLE (sizeof(s_double) - sizeof(double)) /* for compatibility */ #define VOIDP_ALIGN ALIGN_VOIDP #define SHORT_ALIGN ALIGN_SHORT #define INT_ALIGN ALIGN_INT #define LONG_ALIGN ALIGN_LONG #define FLOAT_ALIGN ALIGN_FLOAT #define DOUBLE_ALIGN ALIGN_DOUBLE #define DLALIGN(ptr,offset,align) {\ while( (((unsigned long)((char *)ptr + offset)) % align) != 0 ) offset++;\ } typedef void (*freefunc_t)(void *); #define DLFREEFUNC(func) ((freefunc_t)(func)) typedef union { void* p; char c; short h; int i; long l; float f; double d; char *s; } ANY_TYPE; struct dl_handle { void *ptr; int open; int enable_close; }; struct sym_data { void *func; char *name; char *type; int len; }; enum DLPTR_CTYPE { DLPTR_CTYPE_UNKNOWN, DLPTR_CTYPE_STRUCT, DLPTR_CTYPE_UNION }; struct ptr_data { void *ptr; /* a pointer to the data */ freefunc_t free; /* free() */ char *stype; /* array of type specifiers */ int *ssize; /* size[i] = sizeof(type[i]) > 0 */ int slen; /* the number of type specifiers */ ID *ids; int ids_num; int ctype; /* DLPTR_CTYPE_UNKNOWN, DLPTR_CTYPE_STRUCT, DLPTR_CTYPE_UNION */ long size; }; #define RDLPTR(obj) ((struct ptr_data *)(DATA_PTR(obj))) #define RDLSYM(obj) ((struct sym_data *)(DATA_PTR(obj))) void dlfree(void*); void *dlmalloc(size_t); void *dlrealloc(void*,size_t); char *dlstrdup(const char *); size_t dlsizeof(const char *); void *rb_ary2cary(char t, VALUE ary, long *size); /* void rb_dlmem_delete(void *ptr); void rb_dlmem_aset(void *ptr, VALUE obj); VALUE rb_dlmem_aref(void *ptr); */ void dlptr_free(struct ptr_data *data); void dlptr_init(VALUE val); VALUE rb_dlptr_new(void *ptr, long size, freefunc_t func); VALUE rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func); VALUE rb_dlptr_malloc(long size, freefunc_t func); void *rb_dlptr2cptr(VALUE val); VALUE rb_dlsym_new(void (*func)(), const char *name, const char *type); freefunc_t rb_dlsym2csym(VALUE val); #endif /* RUBY_DL_H */ PK|]O  x86_64-linux/dln.hnu[/********************************************************************** dln.h - $Author: shyouhei $ $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ created at: Wed Jan 19 16:53:09 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef DLN_H #define DLN_H #ifdef __cplusplus # ifndef HAVE_PROTOTYPES # define HAVE_PROTOTYPES 1 # endif # ifndef HAVE_STDARG_PROTOTYPES # define HAVE_STDARG_PROTOTYPES 1 # endif #endif #undef _ #ifdef HAVE_PROTOTYPES # define _(args) args #else # define _(args) () #endif char *dln_find_exe _((const char*,const char*)); char *dln_find_file _((const char*,const char*)); #ifdef USE_DLN_A_OUT extern char *dln_argv0; #endif void *dln_load _((const char*)); #endif PK|]Q)33x86_64-linux/node.hnu[/********************************************************************** node.h - $Author: shyouhei $ $Date: 2009-02-25 15:15:55 +0900 (Wed, 25 Feb 2009) $ created at: Fri May 28 15:14:02 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef NODE_H #define NODE_H #if defined(__cplusplus) extern "C" { #endif enum node_type { NODE_METHOD, NODE_FBODY, NODE_CFUNC, NODE_SCOPE, NODE_BLOCK, NODE_IF, NODE_CASE, NODE_WHEN, NODE_OPT_N, NODE_WHILE, NODE_UNTIL, NODE_ITER, NODE_FOR, NODE_BREAK, NODE_NEXT, NODE_REDO, NODE_RETRY, NODE_BEGIN, NODE_RESCUE, NODE_RESBODY, NODE_ENSURE, NODE_AND, NODE_OR, NODE_NOT, NODE_MASGN, NODE_LASGN, NODE_DASGN, NODE_DASGN_CURR, NODE_GASGN, NODE_IASGN, NODE_CDECL, NODE_CVASGN, NODE_CVDECL, NODE_OP_ASGN1, NODE_OP_ASGN2, NODE_OP_ASGN_AND, NODE_OP_ASGN_OR, NODE_CALL, NODE_FCALL, NODE_VCALL, NODE_SUPER, NODE_ZSUPER, NODE_ARRAY, NODE_ZARRAY, NODE_HASH, NODE_RETURN, NODE_YIELD, NODE_LVAR, NODE_DVAR, NODE_GVAR, NODE_IVAR, NODE_CONST, NODE_CVAR, NODE_NTH_REF, NODE_BACK_REF, NODE_MATCH, NODE_MATCH2, NODE_MATCH3, NODE_LIT, NODE_STR, NODE_DSTR, NODE_XSTR, NODE_DXSTR, NODE_EVSTR, NODE_DREGX, NODE_DREGX_ONCE, NODE_ARGS, NODE_ARGSCAT, NODE_ARGSPUSH, NODE_SPLAT, NODE_TO_ARY, NODE_SVALUE, NODE_BLOCK_ARG, NODE_BLOCK_PASS, NODE_DEFN, NODE_DEFS, NODE_ALIAS, NODE_VALIAS, NODE_UNDEF, NODE_CLASS, NODE_MODULE, NODE_SCLASS, NODE_COLON2, NODE_COLON3, NODE_CREF, NODE_DOT2, NODE_DOT3, NODE_FLIP2, NODE_FLIP3, NODE_ATTRSET, NODE_SELF, NODE_NIL, NODE_TRUE, NODE_FALSE, NODE_DEFINED, NODE_NEWLINE, NODE_POSTEXE, NODE_ALLOCA, NODE_DMETHOD, NODE_BMETHOD, NODE_MEMO, NODE_IFUNC, NODE_DSYM, NODE_ATTRASGN, NODE_LAST }; typedef struct RNode { unsigned long flags; char *nd_file; union { struct RNode *node; ID id; VALUE value; VALUE (*cfunc)(ANYARGS); ID *tbl; } u1; union { struct RNode *node; ID id; long argc; VALUE value; } u2; union { struct RNode *node; ID id; long state; struct global_entry *entry; long cnt; VALUE value; } u3; } NODE; extern NODE *ruby_cref; extern NODE *ruby_top_cref; #define RNODE(obj) (R_CAST(RNode)(obj)) #define nd_type(n) ((int)(((RNODE(n))->flags>>FL_USHIFT)&0xff)) #define nd_set_type(n,t) \ RNODE(n)->flags=((RNODE(n)->flags&~FL_UMASK)|(((t)<flags>>NODE_LSHIFT)&NODE_LMASK)) #define nd_set_line(n,l) \ RNODE(n)->flags=((RNODE(n)->flags&~(-1< #define USE_CONTEXT #endif #include #include "st.h" #ifdef USE_CONTEXT typedef struct { ucontext_t context; volatile int status; } rb_jmpbuf_t[1]; #else typedef RUBY_JMP_BUF rb_jmpbuf_t; #endif enum rb_thread_status { THREAD_TO_KILL, THREAD_RUNNABLE, THREAD_STOPPED, THREAD_KILLED, }; typedef struct rb_thread *rb_thread_t; struct rb_thread { rb_thread_t next, prev; rb_jmpbuf_t context; #if (defined _WIN32 && !defined _WIN32_WCE) || defined __CYGWIN__ unsigned long win32_exception_list; #endif VALUE result; size_t stk_len; size_t stk_max; VALUE *stk_ptr; VALUE *stk_pos; #ifdef __ia64 size_t bstr_len; size_t bstr_max; VALUE *bstr_ptr; VALUE *bstr_pos; #endif struct FRAME *frame; struct SCOPE *scope; struct RVarmap *dyna_vars; struct BLOCK *block; struct iter *iter; struct tag *tag; VALUE klass; VALUE wrapper; NODE *cref; int flags; /* misc. states (vmode/rb_trap_immediate/raised) */ NODE *node; int tracing; VALUE errinfo; VALUE last_status; VALUE last_line; VALUE last_match; int safe; enum rb_thread_status status; int wait_for; int fd; fd_set readfds; fd_set writefds; fd_set exceptfds; int select_value; double delay; rb_thread_t join; int abort; int priority; VALUE thgroup; struct st_table *locals; VALUE thread; VALUE sandbox; }; extern VALUE (*ruby_sandbox_save)_((rb_thread_t)); extern VALUE (*ruby_sandbox_restore)_((rb_thread_t)); extern rb_thread_t rb_curr_thread; extern rb_thread_t rb_main_thread; enum { RAISED_EXCEPTION = 0x1000, RAISED_STACKOVERFLOW = 0x2000, RAISED_NOMEMORY = 0x4000, RAISED_MASK = 0xf000 }; int rb_thread_set_raised(rb_thread_t th); int rb_thread_reset_raised(rb_thread_t th); #define rb_thread_raised_set(th, f) ((th)->flags |= (f)) #define rb_thread_raised_reset(th, f) ((th)->flags &= ~(f)) #define rb_thread_raised_p(th, f) (((th)->flags & (f)) != 0) #define rb_thread_raised_clear(th) (rb_thread_raised_reset(th, RAISED_MASK)) #if defined(__cplusplus) } /* extern "C" { */ #endif #endif PK|]xJHMHMx86_64-linux/intern.hnu[/********************************************************************** intern.h - $Author: shyouhei $ $Date: 2011-05-23 13:49:40 +0900 (Mon, 23 May 2011) $ created at: Thu Jun 10 14:22:17 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ /* * Functions and variables that are used by more than one source file of * the kernel. */ #define ID_ALLOCATOR 1 /* array.c */ void rb_mem_clear _((register VALUE*, register long)); VALUE rb_assoc_new _((VALUE, VALUE)); VALUE rb_check_array_type _((VALUE)); VALUE rb_ary_new _((void)); VALUE rb_ary_new2 _((long)); VALUE rb_ary_new3 __((long,...)); VALUE rb_ary_new4 _((long, const VALUE *)); VALUE rb_ary_freeze _((VALUE)); VALUE rb_ary_aref _((int, VALUE*, VALUE)); void rb_ary_store _((VALUE, long, VALUE)); VALUE rb_ary_dup _((VALUE)); VALUE rb_ary_to_ary _((VALUE)); VALUE rb_ary_to_s _((VALUE)); VALUE rb_ary_push _((VALUE, VALUE)); VALUE rb_ary_pop _((VALUE)); VALUE rb_ary_shift _((VALUE)); VALUE rb_ary_unshift _((VALUE, VALUE)); VALUE rb_ary_entry _((VALUE, long)); VALUE rb_ary_each _((VALUE)); VALUE rb_ary_join _((VALUE, VALUE)); VALUE rb_ary_print_on _((VALUE, VALUE)); VALUE rb_ary_reverse _((VALUE)); VALUE rb_ary_sort _((VALUE)); VALUE rb_ary_sort_bang _((VALUE)); VALUE rb_ary_delete _((VALUE, VALUE)); VALUE rb_ary_delete_at _((VALUE, long)); VALUE rb_ary_clear _((VALUE)); VALUE rb_ary_plus _((VALUE, VALUE)); VALUE rb_ary_concat _((VALUE, VALUE)); VALUE rb_ary_assoc _((VALUE, VALUE)); VALUE rb_ary_rassoc _((VALUE, VALUE)); VALUE rb_ary_includes _((VALUE, VALUE)); VALUE rb_ary_cmp _((VALUE, VALUE)); VALUE rb_protect_inspect _((VALUE(*)(ANYARGS),VALUE,VALUE)); VALUE rb_inspecting_p _((VALUE)); VALUE rb_check_array_value _((VALUE)); VALUE rb_values_at _((VALUE, long, int, VALUE*, VALUE(*) _((VALUE,long)))); /* bignum.c */ VALUE rb_big_clone _((VALUE)); void rb_big_2comp _((VALUE)); VALUE rb_big_norm _((VALUE)); VALUE rb_uint2big _((unsigned long)); VALUE rb_int2big _((long)); VALUE rb_uint2inum _((unsigned long)); VALUE rb_int2inum _((long)); VALUE rb_cstr_to_inum _((const char*, int, int)); VALUE rb_str_to_inum _((VALUE, int, int)); VALUE rb_cstr2inum _((const char*, int)); VALUE rb_str2inum _((VALUE, int)); VALUE rb_big2str _((VALUE, int)); VALUE rb_big2str0 _((VALUE, int, int)); long rb_big2long _((VALUE)); #define rb_big2int(x) rb_big2long(x) unsigned long rb_big2ulong _((VALUE)); #define rb_big2uint(x) rb_big2ulong(x) #if HAVE_LONG_LONG VALUE rb_ll2inum _((LONG_LONG)); VALUE rb_ull2inum _((unsigned LONG_LONG)); LONG_LONG rb_big2ll _((VALUE)); unsigned LONG_LONG rb_big2ull _((VALUE)); #endif /* HAVE_LONG_LONG */ void rb_quad_pack _((char*,VALUE)); VALUE rb_quad_unpack _((const char*,int)); void rb_big_pack(VALUE val, unsigned long *buf, long num_longs); VALUE rb_big_unpack(unsigned long *buf, long num_longs); VALUE rb_dbl2big _((double)); double rb_big2dbl _((VALUE)); VALUE rb_big_plus _((VALUE, VALUE)); VALUE rb_big_minus _((VALUE, VALUE)); VALUE rb_big_mul _((VALUE, VALUE)); VALUE rb_big_divmod _((VALUE, VALUE)); VALUE rb_big_pow _((VALUE, VALUE)); VALUE rb_big_and _((VALUE, VALUE)); VALUE rb_big_or _((VALUE, VALUE)); VALUE rb_big_xor _((VALUE, VALUE)); VALUE rb_big_lshift _((VALUE, VALUE)); VALUE rb_big_rand _((VALUE, double*)); /* class.c */ VALUE rb_class_boot _((VALUE)); VALUE rb_class_new _((VALUE)); VALUE rb_mod_init_copy _((VALUE, VALUE)); VALUE rb_class_init_copy _((VALUE, VALUE)); VALUE rb_singleton_class_clone _((VALUE)); void rb_singleton_class_attached _((VALUE,VALUE)); VALUE rb_make_metaclass _((VALUE, VALUE)); void rb_check_inheritable _((VALUE)); VALUE rb_class_inherited _((VALUE, VALUE)); VALUE rb_define_class_id _((ID, VALUE)); VALUE rb_module_new _((void)); VALUE rb_define_module_id _((ID)); VALUE rb_mod_included_modules _((VALUE)); VALUE rb_mod_include_p _((VALUE, VALUE)); VALUE rb_mod_ancestors _((VALUE)); VALUE rb_class_instance_methods _((int, VALUE*, VALUE)); VALUE rb_class_public_instance_methods _((int, VALUE*, VALUE)); VALUE rb_class_protected_instance_methods _((int, VALUE*, VALUE)); VALUE rb_big_rshift(VALUE, VALUE); VALUE rb_class_private_instance_methods _((int, VALUE*, VALUE)); VALUE rb_obj_singleton_methods _((int, VALUE*, VALUE)); void rb_define_method_id _((VALUE, ID, VALUE (*)(ANYARGS), int)); void rb_frozen_class_p _((VALUE)); void rb_undef _((VALUE, ID)); void rb_define_protected_method _((VALUE, const char*, VALUE (*)(ANYARGS), int)); void rb_define_private_method _((VALUE, const char*, VALUE (*)(ANYARGS), int)); void rb_define_singleton_method _((VALUE, const char*, VALUE(*)(ANYARGS), int)); VALUE rb_singleton_class _((VALUE)); /* compar.c */ int rb_cmpint _((VALUE, VALUE, VALUE)); NORETURN(void rb_cmperr _((VALUE, VALUE))); /* enum.c */ VALUE rb_block_call _((VALUE, ID, int, VALUE*, VALUE (*)(ANYARGS), VALUE)); /* enumerator.c */ VALUE rb_enumeratorize _((VALUE, VALUE, int, VALUE *)); #define RETURN_ENUMERATOR(obj, argc, argv) do { \ if (!rb_block_given_p()) \ return rb_enumeratorize(obj, ID2SYM(rb_frame_this_func()), \ argc, argv); \ } while (0) /* error.c */ RUBY_EXTERN int ruby_nerrs; VALUE rb_exc_new _((VALUE, const char*, long)); VALUE rb_exc_new2 _((VALUE, const char*)); VALUE rb_exc_new3 _((VALUE, VALUE)); NORETURN(void rb_loaderror __((const char*, ...))); NORETURN(void rb_name_error __((ID, const char*, ...))); NORETURN(void rb_invalid_str _((const char*, const char*))); void rb_compile_error __((const char*, ...)); void rb_compile_error_append __((const char*, ...)); NORETURN(void rb_load_fail _((const char*))); NORETURN(void rb_error_frozen _((const char*))); void rb_check_frozen _((VALUE)); /* eval.c */ RUBY_EXTERN struct RNode *ruby_current_node; void ruby_set_current_source _((void)); NORETURN(void rb_exc_raise _((VALUE))); NORETURN(void rb_exc_fatal _((VALUE))); VALUE rb_f_exit _((int,VALUE*)); VALUE rb_f_abort _((int,VALUE*)); void rb_remove_method _((VALUE, const char*)); #define rb_disable_super(klass, name) ((void)0) #define rb_enable_super(klass, name) ((void)0) #define HAVE_RB_DEFINE_ALLOC_FUNC 1 void rb_define_alloc_func _((VALUE, VALUE (*)(VALUE))); void rb_undef_alloc_func _((VALUE)); void rb_clear_cache _((void)); void rb_clear_cache_by_class _((VALUE)); void rb_alias _((VALUE, ID, ID)); void rb_attr _((VALUE,ID,int,int,int)); int rb_method_boundp _((VALUE, ID, int)); VALUE rb_dvar_defined _((ID)); VALUE rb_dvar_curr _((ID)); VALUE rb_dvar_ref _((ID)); void rb_dvar_asgn _((ID, VALUE)); void rb_dvar_push _((ID, VALUE)); VALUE *rb_svar _((int)); VALUE rb_eval_cmd _((VALUE, VALUE, int)); int rb_obj_respond_to _((VALUE, ID, int)); int rb_respond_to _((VALUE, ID)); void rb_interrupt _((void)); VALUE rb_apply _((VALUE, ID, VALUE)); void rb_backtrace _((void)); ID rb_frame_last_func _((void)); ID rb_frame_this_func _((void)); VALUE rb_obj_instance_eval _((int, VALUE*, VALUE)); VALUE rb_mod_module_eval _((int, VALUE*, VALUE)); void rb_load _((VALUE, int)); void rb_load_protect _((VALUE, int, int*)); NORETURN(void rb_jump_tag _((int))); int rb_provided _((const char*)); void rb_provide _((const char*)); VALUE rb_f_require _((VALUE, VALUE)); VALUE rb_require_safe _((VALUE, int)); void rb_obj_call_init _((VALUE, int, VALUE*)); VALUE rb_class_new_instance _((int, VALUE*, VALUE)); VALUE rb_block_proc _((void)); VALUE rb_block_dup _((VALUE, VALUE, VALUE)); VALUE rb_method_dup _((VALUE, VALUE, VALUE)); VALUE rb_f_lambda _((void)); VALUE rb_proc_call _((VALUE, VALUE)); VALUE rb_obj_method _((VALUE, VALUE)); VALUE rb_protect _((VALUE (*)(VALUE), VALUE, int*)); void rb_set_end_proc _((void (*)(VALUE), VALUE)); void rb_mark_end_proc _((void)); void rb_exec_end_proc _((void)); void ruby_finalize _((void)); NORETURN(void ruby_stop _((int))); int ruby_cleanup _((int)); int ruby_exec _((void)); void rb_gc_mark_threads _((void)); void rb_thread_start_timer _((void)); void rb_thread_stop_timer _((void)); void rb_thread_schedule _((void)); void rb_thread_wait_fd _((int)); int rb_thread_fd_writable _((int)); void rb_thread_fd_close _((int)); int rb_thread_alone _((void)); void rb_thread_polling _((void)); void rb_thread_sleep _((int)); void rb_thread_sleep_forever _((void)); VALUE rb_thread_stop _((void)); VALUE rb_thread_wakeup _((VALUE)); VALUE rb_thread_wakeup_alive _((VALUE)); VALUE rb_thread_run _((VALUE)); VALUE rb_thread_kill _((VALUE)); VALUE rb_thread_alive_p _((VALUE)); VALUE rb_thread_create _((VALUE (*)(ANYARGS), void*)); void rb_thread_interrupt _((void)); void rb_thread_trap_eval _((VALUE, int, int)); void rb_thread_signal_raise _((int)); void rb_thread_signal_exit _((void)); int rb_thread_select _((int, fd_set *, fd_set *, fd_set *, struct timeval *)); void rb_thread_wait_for _((struct timeval)); VALUE rb_thread_current _((void)); VALUE rb_thread_main _((void)); VALUE rb_thread_local_aref _((VALUE, ID)); VALUE rb_thread_local_aset _((VALUE, ID, VALUE)); void rb_thread_atfork _((void)); VALUE rb_exec_recursive _((VALUE(*)(VALUE, VALUE, int),VALUE,VALUE)); VALUE rb_funcall_rescue __((VALUE, ID, int, ...)); /* file.c */ VALUE rb_file_s_expand_path _((int, VALUE *)); VALUE rb_file_expand_path _((VALUE, VALUE)); void rb_file_const _((const char*, VALUE)); int rb_find_file_ext _((VALUE*, const char* const*)); VALUE rb_find_file _((VALUE)); char *rb_path_next _((const char *)); char *rb_path_skip_prefix _((const char *)); char *rb_path_last_separator _((const char *)); char *rb_path_end _((const char *)); VALUE rb_file_directory_p _((VALUE,VALUE)); /* gc.c */ NORETURN(void rb_memerror __((void))); int ruby_stack_check _((void)); size_t ruby_stack_length _((VALUE**)); int rb_during_gc _((void)); char *rb_source_filename _((const char*)); void rb_gc_mark_locations _((VALUE*, VALUE*)); void rb_mark_tbl _((struct st_table*)); void rb_mark_set _((struct st_table*)); void rb_mark_hash _((struct st_table*)); void rb_gc_mark_maybe _((VALUE)); void rb_gc_mark _((VALUE)); void rb_gc_force_recycle _((VALUE)); void rb_gc _((void)); void rb_gc_copy_finalizer _((VALUE,VALUE)); void rb_gc_finalize_deferred _((void)); void rb_gc_call_finalizer_at_exit _((void)); VALUE rb_gc_enable _((void)); VALUE rb_gc_disable _((void)); VALUE rb_gc_start _((void)); /* hash.c */ void st_foreach_safe _((struct st_table *, int (*)(ANYARGS), unsigned long)); void rb_hash_foreach _((VALUE, int (*)(ANYARGS), VALUE)); VALUE rb_hash _((VALUE)); VALUE rb_hash_new _((void)); VALUE rb_hash_freeze _((VALUE)); VALUE rb_hash_aref _((VALUE, VALUE)); VALUE rb_hash_lookup _((VALUE, VALUE)); VALUE rb_hash_aset _((VALUE, VALUE, VALUE)); VALUE rb_hash_delete_if _((VALUE)); VALUE rb_hash_delete _((VALUE,VALUE)); int rb_path_check _((const char*)); int rb_env_path_tainted _((void)); /* io.c */ #define rb_defout rb_stdout RUBY_EXTERN VALUE rb_fs; RUBY_EXTERN VALUE rb_output_fs; RUBY_EXTERN VALUE rb_rs; RUBY_EXTERN VALUE rb_default_rs; RUBY_EXTERN VALUE rb_output_rs; VALUE rb_io_write _((VALUE, VALUE)); VALUE rb_io_gets _((VALUE)); VALUE rb_io_getc _((VALUE)); VALUE rb_io_ungetc _((VALUE, VALUE)); VALUE rb_io_close _((VALUE)); VALUE rb_io_eof _((VALUE)); VALUE rb_io_binmode _((VALUE)); VALUE rb_io_addstr _((VALUE, VALUE)); VALUE rb_io_printf _((int, VALUE*, VALUE)); VALUE rb_io_print _((int, VALUE*, VALUE)); VALUE rb_io_puts _((int, VALUE*, VALUE)); VALUE rb_file_open _((const char*, const char*)); VALUE rb_gets _((void)); void rb_write_error _((const char*)); void rb_write_error2 _((const char*, long)); /* marshal.c */ VALUE rb_marshal_dump _((VALUE, VALUE)); VALUE rb_marshal_load _((VALUE)); /* numeric.c */ void rb_num_zerodiv _((void)); VALUE rb_num_coerce_bin _((VALUE, VALUE)); VALUE rb_num_coerce_cmp _((VALUE, VALUE)); VALUE rb_num_coerce_relop _((VALUE, VALUE)); VALUE rb_float_new _((double)); VALUE rb_num2fix _((VALUE)); VALUE rb_fix2str _((VALUE, int)); VALUE rb_dbl_cmp _((double, double)); /* object.c */ int rb_eql _((VALUE, VALUE)); VALUE rb_any_to_s _((VALUE)); VALUE rb_inspect _((VALUE)); VALUE rb_obj_is_instance_of _((VALUE, VALUE)); VALUE rb_obj_is_kind_of _((VALUE, VALUE)); VALUE rb_obj_alloc _((VALUE)); VALUE rb_obj_clone _((VALUE)); VALUE rb_obj_dup _((VALUE)); VALUE rb_obj_init_copy _((VALUE,VALUE)); VALUE rb_obj_taint _((VALUE)); VALUE rb_obj_tainted _((VALUE)); VALUE rb_obj_untaint _((VALUE)); VALUE rb_obj_freeze _((VALUE)); VALUE rb_obj_id _((VALUE)); VALUE rb_obj_class _((VALUE)); VALUE rb_class_real _((VALUE)); VALUE rb_class_inherited_p _((VALUE, VALUE)); VALUE rb_convert_type _((VALUE,int,const char*,const char*)); VALUE rb_check_convert_type _((VALUE,int,const char*,const char*)); VALUE rb_check_to_integer _((VALUE, const char *)); VALUE rb_to_int _((VALUE)); VALUE rb_Integer _((VALUE)); VALUE rb_Float _((VALUE)); VALUE rb_String _((VALUE)); VALUE rb_Array _((VALUE)); double rb_cstr_to_dbl _((const char*, int)); double rb_str_to_dbl _((VALUE, int)); /* parse.y */ RUBY_EXTERN int ruby_sourceline; RUBY_EXTERN char *ruby_sourcefile; int ruby_yyparse _((void)); ID rb_id_attrset _((ID)); void rb_parser_append_print _((void)); void rb_parser_while_loop _((int, int)); int ruby_parser_stack_on_heap _((void)); void rb_gc_mark_parser _((void)); int rb_is_const_id _((ID)); int rb_is_instance_id _((ID)); int rb_is_class_id _((ID)); int rb_is_local_id _((ID)); int rb_is_junk_id _((ID)); int rb_symname_p _((const char*)); int rb_sym_interned_p _((VALUE)); VALUE rb_backref_get _((void)); void rb_backref_set _((VALUE)); VALUE rb_lastline_get _((void)); void rb_lastline_set _((VALUE)); VALUE rb_sym_all_symbols _((void)); /* process.c */ int rb_proc_exec _((const char*)); VALUE rb_f_exec _((int,VALUE*)); int rb_waitpid _((int,int*,int)); void rb_syswait _((int)); VALUE rb_proc_times _((VALUE)); VALUE rb_detach_process _((int)); /* range.c */ VALUE rb_range_new _((VALUE, VALUE, int)); VALUE rb_range_beg_len _((VALUE, long*, long*, long, int)); VALUE rb_length_by_each _((VALUE)); /* random.c */ unsigned long rb_genrand_int32(void); double rb_genrand_real(void); void rb_reset_random_seed(void); /* re.c */ int rb_memcmp _((const void*,const void*,long)); int rb_memcicmp _((const void*,const void*,long)); long rb_memsearch _((const void*,long,const void*,long)); VALUE rb_reg_nth_defined _((int, VALUE)); VALUE rb_reg_nth_match _((int, VALUE)); VALUE rb_reg_last_match _((VALUE)); VALUE rb_reg_match_pre _((VALUE)); VALUE rb_reg_match_post _((VALUE)); VALUE rb_reg_match_last _((VALUE)); VALUE rb_reg_new _((const char*, long, int)); VALUE rb_reg_match _((VALUE, VALUE)); VALUE rb_reg_match2 _((VALUE)); int rb_reg_options _((VALUE)); void rb_set_kcode _((const char*)); const char* rb_get_kcode _((void)); void rb_kcode_set_option _((VALUE)); void rb_kcode_reset_option _((void)); /* ruby.c */ RUBY_EXTERN VALUE rb_argv; RUBY_EXTERN VALUE rb_argv0; void rb_load_file _((const char*)); void ruby_script _((const char*)); void ruby_prog_init _((void)); void ruby_set_argv _((int, char**)); void ruby_process_options _((int, char**)); void ruby_load_script _((void)); void ruby_init_loadpath _((void)); void ruby_incpush _((const char*)); /* signal.c */ VALUE rb_f_kill _((int, VALUE*)); void rb_gc_mark_trap_list _((void)); #ifdef POSIX_SIGNAL #define posix_signal ruby_posix_signal void posix_signal _((int, RETSIGTYPE (*)(int))); #endif void rb_trap_exit _((void)); void rb_trap_exec _((void)); const char *ruby_signal_name _((int)); void ruby_default_signal _((int)); /* sprintf.c */ VALUE rb_f_sprintf _((int, VALUE*)); VALUE rb_str_format _((int, VALUE*, VALUE)); /* string.c */ VALUE rb_str_new _((const char*, long)); VALUE rb_str_new2 _((const char*)); VALUE rb_str_new3 _((VALUE)); VALUE rb_str_new4 _((VALUE)); VALUE rb_str_new5 _((VALUE, const char*, long)); VALUE rb_tainted_str_new _((const char*, long)); VALUE rb_tainted_str_new2 _((const char*)); VALUE rb_str_buf_new _((long)); VALUE rb_str_buf_new2 _((const char*)); VALUE rb_str_tmp_new _((long)); VALUE rb_str_buf_append _((VALUE, VALUE)); VALUE rb_str_buf_cat _((VALUE, const char*, long)); VALUE rb_str_buf_cat2 _((VALUE, const char*)); VALUE rb_obj_as_string _((VALUE)); VALUE rb_check_string_type _((VALUE)); VALUE rb_str_dup _((VALUE)); VALUE rb_str_locktmp _((VALUE)); VALUE rb_str_unlocktmp _((VALUE)); VALUE rb_str_dup_frozen _((VALUE)); VALUE rb_str_plus _((VALUE, VALUE)); VALUE rb_str_times _((VALUE, VALUE)); VALUE rb_str_substr _((VALUE, long, long)); void rb_str_modify _((VALUE)); VALUE rb_str_freeze _((VALUE)); void rb_str_set_len _((VALUE, long)); VALUE rb_str_resize _((VALUE, long)); VALUE rb_str_cat _((VALUE, const char*, long)); VALUE rb_str_cat2 _((VALUE, const char*)); VALUE rb_str_append _((VALUE, VALUE)); VALUE rb_str_concat _((VALUE, VALUE)); int rb_str_hash _((VALUE)); int rb_str_cmp _((VALUE, VALUE)); VALUE rb_str_upto _((VALUE, VALUE, int)); void rb_str_update _((VALUE, long, long, VALUE)); VALUE rb_str_inspect _((VALUE)); VALUE rb_str_dump _((VALUE)); VALUE rb_str_split _((VALUE, const char*)); void rb_str_associate _((VALUE, VALUE)); VALUE rb_str_associated _((VALUE)); void rb_str_setter _((VALUE, ID, VALUE*)); VALUE rb_str_intern _((VALUE)); /* struct.c */ VALUE rb_struct_new __((VALUE, ...)); VALUE rb_struct_define __((const char*, ...)); VALUE rb_struct_alloc _((VALUE, VALUE)); VALUE rb_struct_aref _((VALUE, VALUE)); VALUE rb_struct_aset _((VALUE, VALUE, VALUE)); VALUE rb_struct_getmember _((VALUE, ID)); VALUE rb_struct_iv_get _((VALUE, const char*)); VALUE rb_struct_s_members _((VALUE)); VALUE rb_struct_members _((VALUE)); /* time.c */ VALUE rb_time_new _((time_t, time_t)); /* variable.c */ VALUE rb_mod_name _((VALUE)); VALUE rb_class_path _((VALUE)); void rb_set_class_path _((VALUE, VALUE, const char*)); VALUE rb_path2class _((const char*)); void rb_name_class _((VALUE, ID)); VALUE rb_class_name _((VALUE)); void rb_autoload _((VALUE, ID, const char*)); VALUE rb_autoload_load _((VALUE, ID)); VALUE rb_autoload_p _((VALUE, ID)); void rb_gc_mark_global_tbl _((void)); VALUE rb_f_trace_var _((int, VALUE*)); VALUE rb_f_untrace_var _((int, VALUE*)); VALUE rb_f_global_variables _((void)); void rb_alias_variable _((ID, ID)); struct st_table* rb_generic_ivar_table _((VALUE)); void rb_copy_generic_ivar _((VALUE,VALUE)); void rb_mark_generic_ivar _((VALUE)); void rb_mark_generic_ivar_tbl _((void)); void rb_free_generic_ivar _((VALUE)); VALUE rb_ivar_get _((VALUE, ID)); VALUE rb_ivar_set _((VALUE, ID, VALUE)); VALUE rb_ivar_defined _((VALUE, ID)); VALUE rb_iv_set _((VALUE, const char*, VALUE)); VALUE rb_iv_get _((VALUE, const char*)); VALUE rb_attr_get _((VALUE, ID)); VALUE rb_obj_instance_variables _((VALUE)); VALUE rb_obj_remove_instance_variable _((VALUE, VALUE)); void *rb_mod_const_at _((VALUE, void*)); void *rb_mod_const_of _((VALUE, void*)); VALUE rb_const_list _((void*)); VALUE rb_mod_constants _((VALUE)); VALUE rb_mod_remove_const _((VALUE, VALUE)); int rb_const_defined _((VALUE, ID)); int rb_const_defined_at _((VALUE, ID)); int rb_const_defined_from _((VALUE, ID)); VALUE rb_const_get _((VALUE, ID)); VALUE rb_const_get_at _((VALUE, ID)); VALUE rb_const_get_from _((VALUE, ID)); void rb_const_set _((VALUE, ID, VALUE)); VALUE rb_mod_constants _((VALUE)); VALUE rb_mod_const_missing _((VALUE,VALUE)); VALUE rb_cvar_defined _((VALUE, ID)); #define RB_CVAR_SET_4ARGS 1 void rb_cvar_set _((VALUE, ID, VALUE, int)); VALUE rb_cvar_get _((VALUE, ID)); void rb_cv_set _((VALUE, const char*, VALUE)); VALUE rb_cv_get _((VALUE, const char*)); void rb_define_class_variable _((VALUE, const char*, VALUE)); VALUE rb_mod_class_variables _((VALUE)); VALUE rb_mod_remove_cvar _((VALUE, VALUE)); /* version.c */ void ruby_show_version _((void)); void ruby_show_copyright _((void)); PK|]MVpPPx86_64-linux/st.hnu[/* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */ /* @(#) st.h 5.1 89/12/14 */ #ifndef ST_INCLUDED #define ST_INCLUDED #if SIZEOF_LONG == SIZEOF_VOIDP typedef unsigned long st_data_t; #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP typedef unsigned LONG_LONG st_data_t; #else # error ---->> st.c requires sizeof(void*) == sizeof(long) to be compiled. <<--- - #endif #define ST_DATA_T_DEFINED typedef struct st_table st_table; struct st_hash_type { int (*compare)(); int (*hash)(); }; struct st_table { struct st_hash_type *type; int num_bins; int num_entries; struct st_table_entry **bins; }; #define st_is_member(table,key) st_lookup(table,key,(st_data_t *)0) enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK}; #ifndef _ # define _(args) args #endif #ifndef ANYARGS # ifdef __cplusplus # define ANYARGS ... # else # define ANYARGS # endif #endif st_table *st_init_table _((struct st_hash_type *)); st_table *st_init_table_with_size _((struct st_hash_type *, int)); st_table *st_init_numtable _((void)); st_table *st_init_numtable_with_size _((int)); st_table *st_init_strtable _((void)); st_table *st_init_strtable_with_size _((int)); int st_delete _((st_table *, st_data_t *, st_data_t *)); int st_delete_safe _((st_table *, st_data_t *, st_data_t *, st_data_t)); int st_insert _((st_table *, st_data_t, st_data_t)); int st_lookup _((st_table *, st_data_t, st_data_t *)); int st_foreach _((st_table *, int (*)(ANYARGS), st_data_t)); void st_add_direct _((st_table *, st_data_t, st_data_t)); void st_free_table _((st_table *)); void st_cleanup_safe _((st_table *, st_data_t)); st_table *st_copy _((st_table *)); #define ST_NUMCMP ((int (*)()) 0) #define ST_NUMHASH ((int (*)()) -2) #define st_numcmp ST_NUMCMP #define st_numhash ST_NUMHASH int st_strhash(); #endif /* ST_INCLUDED */ PK|].v>J J x86_64-linux/rubysig.hnu[/********************************************************************** rubysig.h - $Author: shyouhei $ $Date: 2009-01-05 11:16:18 +0900 (Mon, 05 Jan 2009) $ created at: Wed Aug 16 01:15:38 JST 1995 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef SIG_H #define SIG_H #include #ifdef _WIN32 typedef LONG rb_atomic_t; # define ATOMIC_TEST(var) InterlockedExchange(&(var), 0) # define ATOMIC_SET(var, val) InterlockedExchange(&(var), (val)) # define ATOMIC_INC(var) InterlockedIncrement(&(var)) # define ATOMIC_DEC(var) InterlockedDecrement(&(var)) /* Windows doesn't allow interrupt while system calls */ # define TRAP_BEG do {\ int saved_errno = 0;\ rb_atomic_t trap_immediate = ATOMIC_SET(rb_trap_immediate, 1) # define TRAP_END\ ATOMIC_SET(rb_trap_immediate, trap_immediate);\ saved_errno = errno;\ CHECK_INTS;\ errno = saved_errno;\ } while (0) # define RUBY_CRITICAL(statements) do {\ rb_w32_enter_critical();\ statements;\ rb_w32_leave_critical();\ } while (0) #else typedef int rb_atomic_t; # define ATOMIC_TEST(var) ((var) ? ((var) = 0, 1) : 0) # define ATOMIC_SET(var, val) ((var) = (val)) # define ATOMIC_INC(var) (++(var)) # define ATOMIC_DEC(var) (--(var)) # define TRAP_BEG do {\ int saved_errno = 0;\ int trap_immediate = rb_trap_immediate;\ rb_trap_immediate = 1 # define TRAP_END rb_trap_immediate = trap_immediate;\ saved_errno = errno;\ CHECK_INTS;\ errno = saved_errno;\ } while (0) # define RUBY_CRITICAL(statements) do {\ int trap_immediate = rb_trap_immediate;\ rb_trap_immediate = 0;\ statements;\ rb_trap_immediate = trap_immediate;\ } while (0) #endif RUBY_EXTERN rb_atomic_t rb_trap_immediate; RUBY_EXTERN int rb_prohibit_interrupt; #define DEFER_INTS (rb_prohibit_interrupt++) #define ALLOW_INTS do {\ rb_prohibit_interrupt--;\ CHECK_INTS;\ } while (0) #define ENABLE_INTS (rb_prohibit_interrupt--) VALUE rb_with_disable_interrupt _((VALUE(*)(ANYARGS),VALUE)); RUBY_EXTERN rb_atomic_t rb_trap_pending; void rb_trap_restore_mask _((void)); RUBY_EXTERN int rb_thread_critical; RUBY_EXTERN int rb_thread_pending; void rb_thread_schedule _((void)); #if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) # define CHECK_INTS do {\ if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ if (rb_thread_pending) rb_thread_schedule();\ if (rb_trap_pending) rb_trap_exec();\ }\ } while (0) #else /* pseudo preemptive thread switching */ RUBY_EXTERN int rb_thread_tick; #define THREAD_TICK 500 #define CHECK_INTS do {\ if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ if (rb_thread_pending || rb_thread_tick-- <= 0) {\ rb_thread_tick = THREAD_TICK;\ rb_thread_schedule();\ }\ }\ if (rb_trap_pending) rb_trap_exec();\ } while (0) #endif #endif PK|]wACx86_64-linux/curses.sonuȯELF>P-@Ⱦ@8 @@@   0`  PP888$$ Std PtdQtdRtd  GNUŐh^%}Zړ+0zv@  vxBE|qXV ,V aN}zlqpWv+-h'^[  O[`d E]i;Un7M8, C'F"I7gB8 h  ],8 __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeLINESCOLSstdscrisendwinrb_gc_unregister_addressrb_eRuntimeErrorrb_raiseruby_safe_levelrb_check_typerb_num2intwattrsetrb_fix2intrb_eSecurityErrorwattr_onrb_block_given_prb_yieldwattr_offwresizewscrlwsetscrregwcolor_setwmovemvwindelwinfreeruby_xmallocrb_data_object_allocrb_scan_argswborderwaddchrb_num2long__stack_chk_failrb_uint2inumwtimeoutnodelaywbkgdwbkgdsetkeypadidlokscrollokwinsdellnwdelchstdinrb_read_checkwgetnstrrb_tainted_str_new2wgetchrb_str2cstrwaddnstrwinschwinchwnoutrefreshwrefreshwclrtoeolwclearsubwinrb_obj_classrb_obj_allocrb_secureinitscrnewwinreset_prog_modedef_prog_moderb_num2uintmousemaskrb_int2inummouseintervalungetmousepair_contentrb_ary_new3color_contentcan_change_colorhas_colorsinit_colorinit_pairstart_colorresizetermcurs_setkeynamerb_str_new2ungetchflashbeepnonlnocbreaknorawnoechodoupdateInit_cursesrb_define_modulerb_define_module_underrb_gc_register_addressrb_cObjectrb_define_class_underrb_undef_methodrb_define_methodrb_define_module_functionrb_define_aliasrb_cDatarb_define_alloc_funcrb_define_const__sprintf_chkrb_set_end_procrb_cFixnumrb_cFalseClassrb_cNilClassrb_cTrueClassrb_cSymbollibruby.so.1.8libncurses.so.6libtinfo.so.6libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.3.4GLIBC_2.4GLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64ti ii ui  . -  p x      ' ; @ B Eȯ LЯ Tد U _ g l u  ( 0 8 @ H  P  X  `  h p x          Ȱ а ذ   ! " # $ % & ( )( *0 +8 ,@ -H .P /X 0` 1h 2p 3x 4 5 6 7 8 9 : < = >ȱ ?б Aر C D F G H I J K M N( O0 P8 Q@ RH SP VX W` Xh Yp Zx [ \ ] ^ ` a b c d eȲ fв hز i j k l m n o p q r( s0 tHH HtH5B %C hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhc% D% D% D% D%݈ D%Ո D%͈ D%ň D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%݇ D%Շ D%͇ D%Ň D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%݆ D%Ն D%͆ D%ņ D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% DH= Hڅ H9tH Ht H= H5 H)HHH?HHtH= HtfD=m u+UH= Ht H=6 dE ]wH HcHDff.Hu HcHDff.fDHHI H8t vt"H H= HgfPXH5[HH H81bfPXH5[HH H81BfUHSHHu HubH 8hH߾")H[ H;tJHu'H;HH[]HDf.Hu1.H H5cH81fDATUHSHu HH 8"HsLc I<$H@u+I<$1҉yHcH\\upH[]A\I<$1҉NHcH\1tHHI<$1 H[]A\HS>fDHHx1 H~ H5bH81uDUHSHHu HubH~ 8hH߾"YH[ H;tJHu'H;1fHH[]HDHu1^H?~ H5aH81fDAUIATIUSHHu HH~ 8"HHk H}tyLAu>ALAt>AH}H[]HA\A]fDLAuHt_1oHP} H5`H81UHSHHu HubH} 8hH߾"H[ H;tJHu'bH;H[]HfDKHu1H| H50`H81&fDAUIATIUSHHu HH`| 8"HHk H}tyLAu>LAt>H}H[]HA\A]fDsLAuSHt_1H{ H5A_H817UHSHHu HubH{{ 8hH߾"H[ H;tJHu'H;1H[]HfDHu1Hz H5^H81fDAUIATIUSHHu HHz 8"HZHk H}tmLAu6LAt6H}TH[]A\A]@LAuHuk1;Hz H5]H81AUIATIUSHHu HHy 8"HzHk H}tmLAu6!LAt6!H}H[]A\A]@LAuHuk1[H"HHC HHt H@ [HDfHu@1yfSHu Hu:Hx 8>"HHC HHt H@[HDfHu1 fSHu Hu:Hw 8>"H1HC HHt @[HHDDHu`1fSHu Hu:H#w 8>"HHC HHt @[HHDDHu1)fAWAVAUATUHH QSH(dH%(HD$1HLL$LD$@u HHxv 8R"HH] H;+H|$@HAAH<$@HAHH;E1EjDDjjH|$0H H@#HHAH%D0DxH1H.H)DhH1[HFHhH;11OH;DtH;1҉8H;D]H;D H;DEH;D1H;D-H;DDHL$dH3 %(H([]A\A]A^A_HEcNDSAHHAEfD[HhHDhfH|$A@uXH<$A@H<$A@u;12Ht H5WH81HAHHff.@SHu Hu:Hs 8>"HaHC HHt H@[HDfHu1fSHu Hu:HSs 8>"HHC HHt H[HDf.Hu 1YfPXH5VHHr H81rfSHu Hu2Hr 86"HaHC HHtx[@HuSHu Hu2Hcr 86"HHC HHtHcx [KHuX#SHu Hu2Hr 86"HHC HHtHcx[HuSHu Hu2Hq 86"HAHC HHtHcx[HucSHu Hu2HCq 86"HHC HHtH8[+Hu8HHt kHH %Hf;HH %HfPXH57THHp H81"fUHSHHu HuZHkp 8`H߾" H[ H;tBHuH;H[]@Hu1QUHSHHu HuRHo 8XH߾"yHC H8Ht81H@H[]HfHu1fUHSHHu HuRHKo 8mH"Hm H}HtLt7HH,H[]Hf.HEu@HxH}1$@UHSHHu HuBHn 8]H"IHm H}Ht<t'HH!6ܿH=H H5!H1迿H=hH H5!H蟿H=HH H5!HH=(H H5!H_H=H H5!H?H=G H5w!HyH=G H5_!HY H=G H5E!H9߾H=G H5,!H迾H=hG H5!H@蟾H=HG H5 HH=(G H5 H_H=G H5 H?H=F H5 HyH=F H5 HYH=F H5 H9 ߽H=F H5x H@追H=hF H5^ H蟽H=HF H5I Hٿ1肽H=+F H54 H輿bH= F H5 H蜿BH=E H5 H|"H=E H5H\H=E H5H<H=E H5H¼H=kE H5H袼H=KE H5Hܾ肼H=+E H5H輾bH= E H5H蜾BH=D H5tH|"H=D H5dH\H=D H5[H<@H=D H5RH »H=kD H5BH袻H=KD H53Hܽ肻H=+D H5#H輽bH= D H5H蜽BH=C H5H|"H=C H5H\H=C H5H< H=C H5H@ºH=kC H5H袺H=KC H5Hܼ肺H=+C H5H輼bH= C H5H蜼BH=B H5H|"H=B H5H\H=B H5H<H=B H5|H¹H=kB H5hH袹H=KB H5SHܻ肹H=+B H5DH輻bH= B H5:H蜻貵H=A H5H|"H=A H5H\rH=A H5H<H=A H5H2H=cA H5H袸H=KA H5HܺH=#A H5zH輺bH= A H5_H蜺貴H=@ H5CH|"H=@ H5&H\rH=@ H5H<H=@ H5H2H=c@ H5H袷H=K@ H5HܹH=#@ H5H輹bH= @ H5H蜹貳H=? H5fH|@DLH1E藹HoH=? HH=EHH 1_HH3H=d? HHHHuHAA蓶H= H5H膸I蜲H=> H5mHfJ H=> H5PHFJ\H=> H5/H&K̵H=u> H5HKH=M> H5HL茵H=5> H5HƷLܱH= > H5H覷MLH== H5H膷M蜱H== H5HfN H== H5pHFN\H== H5TH&O̴H=u= H58HOH=M= H5HP茴H=5= H5HƶPܰH= = H5H覶QLH=< H5H膶Q蜰H=< H5HfR H=< H5HFR\H=< H5rH&S̳H=u< H5XHSH=M< H5<HT茳H=5< H5"HƵTܯH= < H5H覵ULH=; H5H膵U蜯H=; H5HfV H=; H5HFV\H=; H5H&W̲H=u; H5~HWH=M; H5bHX茲H=5; H5HHƴXܮH= ; H5,H覴YLH=: H5H膴Y蜮H=: H5HfZ H=: H5HFZ\H=: H5H&[̱H=u: H5H[H=M: H5H\茱H=5: H5nHƳ\ܭH= : H5RH観]LH=9 H55H膳]蜭H=9 H5Hf^ H=9 H5HF^\H=9 H5H&_̰H=u9 H5H_H=M9 H5H`茰H=59 H5HƲ`ܬH= 9 H5nH覲aLH=8 H5QH膲a蜬H=8 H55Hfb H=8 H5HFb\H=8 H5H&c̯H=u8 H5HcH=M8 H5Hd茯H=58 H5HƱdܫH= 8 H5H覱eLH=7 H5wH膱e蜫H=7 H5LHff H=7 H5CHFf\H=7 H5H&g̮H=u7 H5 HgH=M7 H5Hh茮H=57 H5HưhܪH= 7 H5H覰iLH=6 H5H膰i蜪H=6 H5Hfj H=6 H5hHFj\H=6 H5fH&k̭H=u6 H51HkH=M6 H50Hl茭H=56 H5HƯlܩH= 6 H5H覯mLH=5 H5H膯m蜩H=5 H5Hfn H=5 H5HFn\H=5 H5H&o̬H=u5 H5XHoH=M5 H5mHp茬H=55 H5!HƮpܨH= 5 H5H覮qLH=4 H5H膮q蜨H=4 H5Hfr H=4 H5HFr\H=4 H5H&s̫H=u4 H5HsH=M4 H5Ht茫H=54 H5LHƭtܧH= 4 H50H覭uLH=3 H5H膭u蜧H=3 H5Hfv H=3 H5HFv\H=3 H5H&w̪H=u3 H5HwH=M3 H5Hx茪H=53 H5~HƬxܦH= 3 H5bH覬yLH=2 H5IH膬y蜦H=2 H5JHfz H=2 H5HFz\H=2 H5H&{̩H=u2 H5H{H=M2 H5H|茩H=52 H5Hƫ|ܥH= 2 H5H覫}LH=1 H5tH膫}蜥H=1 H5XHf~ H=1 H5>HF~\H=1 H5"H&̨H=u1 H5 HH=M1 H5H茨H=51 H5HƪܤH= 1 H5H親LH=0 H5H膪蜤H=0 H5~Hf H=0 H5eHF\H=0 H5IH&̧H=u0 H5.HH=M0 H5H茧H=50 H5HƩܣH= 0 H5H覩LH=/ H5H膩蜣H=/ H5Hf H=/ H5HF\H=/ H5oH&̦H=u/ H5UHH=M/ H59H茦H=5/ H5HƨܢH= / H5H覨LH=. H5 H膨蜢H=. H5 Hf H=. H5 HF\H=. H5 H&̥H=u. H5~ HH=M. H5b H茥H=5. H5H HƧܡH= . H5, H覧LH=- H5 H膧蜡H=- H5 Hf H=- H5 HF\H=- H5 H&̤H=u- H5 HH=M- H5 H茤H=5- H5x HƦܠH= - H5\ H覦LH=, H5B H膦蜠H=, H5& Hf H=, H5 HF\H=, H5 H&̣H=u, H5 HH=M, H5 H茣H=5, H5 HƥܟH= , H5 H覥LH=+ H5o H膥蜟H=+ H5S Hf H=+ H5< HF\H=+ H5 H&̢H=u+ H5 HH=M+ H5 H茢H=5+ H5 HƤܞH= + H5 H覤LH=* H5 H膤蜞H=* H5 Hf H=* H5f HF\H=* H5J H&D$HKEY_CTRLHD$ _xfD$AL H1#LHIH=2* Hɣ[u1H=VHD$dH3%(uVH([]A\A]H\& H84HU& H8%H& H8H'& H8HP& H8HHalready closed windowno such mouse event21failed to create windowcan't initialize cursesCursesKeyMouseEventneweidzbstateinit_screenclose_screenclosed?stdscrdoupdateclearclrtoeolnoechonorawnocbreaknocrmodenonlbeepflashungetchsetposstandoutstandendinchaddchinschaddstrgetstrdelchdeletelninsertlnkeynamelinescolscurs_setscrlsetscrregattroffattronattrsetbkgdsetresizetermresizestart_colorinit_pairinit_colorhas_colors?can_change_color?color_contentpair_contentcolor_pairpair_numberungetmousemouseintervalmousemasktimeout=def_prog_modereset_prog_modeWindowinitializesubwinclosenoutrefreshboxmovecolor_setcurycurxmaxymaxxbegybegx<<scrollscrollokidlokkeypadkeypad=getbkgdnodelay=A_ATTRIBUTESA_NORMALA_STANDOUTA_UNDERLINEA_REVERSEA_BLINKA_DIMA_BOLDA_PROTECTA_INVISA_ALTCHARSETA_CHARTEXTA_HORIZONTALA_LEFTA_LOWA_RIGHTA_TOPA_VERTICALA_COLORCOLOR_BLACKCOLOR_REDCOLOR_GREENCOLOR_YELLOWCOLOR_BLUECOLOR_MAGENTACOLOR_CYANCOLOR_WHITEBUTTON1_PRESSEDBUTTON1_RELEASEDBUTTON1_CLICKEDBUTTON1_DOUBLE_CLICKEDBUTTON1_TRIPLE_CLICKEDBUTTON2_PRESSEDBUTTON2_RELEASEDBUTTON2_CLICKEDBUTTON2_DOUBLE_CLICKEDBUTTON2_TRIPLE_CLICKEDBUTTON3_PRESSEDBUTTON3_RELEASEDBUTTON3_CLICKEDBUTTON3_DOUBLE_CLICKEDBUTTON3_TRIPLE_CLICKEDBUTTON4_PRESSEDBUTTON4_RELEASEDBUTTON4_CLICKEDBUTTON4_DOUBLE_CLICKEDBUTTON4_TRIPLE_CLICKEDBUTTON_SHIFTBUTTON_CTRLBUTTON_ALTALL_MOUSE_EVENTSREPORT_MOUSE_POSITIONKEY_MOUSEKEY_MINKEY_BREAKKEY_DOWNKEY_UPKEY_LEFTKEY_RIGHTKEY_HOMEKEY_BACKSPACEKEY_F%dKEY_DLKEY_ILKEY_DCKEY_ICKEY_EICKEY_CLEARKEY_EOSKEY_EOLKEY_SFKEY_SRKEY_NPAGEKEY_PPAGEKEY_STABKEY_CTABKEY_CATABKEY_ENTERKEY_SRESETKEY_RESETKEY_PRINTKEY_LLKEY_A1KEY_A3KEY_B2KEY_C1KEY_C3KEY_BTABKEY_BEGKEY_CANCELKEY_CLOSEKEY_COMMANDKEY_COPYKEY_CREATEKEY_ENDKEY_EXITKEY_FINDKEY_HELPKEY_MARKKEY_MESSAGEKEY_MOVEKEY_NEXTKEY_OPENKEY_OPTIONSKEY_PREVIOUSKEY_REDOKEY_REFERENCEKEY_REFRESHKEY_REPLACEKEY_RESTARTKEY_RESUMEKEY_SAVEKEY_SBEGKEY_SCANCELKEY_SCOMMANDKEY_SCOPYKEY_SCREATEKEY_SDCKEY_SDLKEY_SELECTKEY_SENDKEY_SEOLKEY_SEXITKEY_SFINDKEY_SHELPKEY_SHOMEKEY_SICKEY_SLEFTKEY_SMESSAGEKEY_SMOVEKEY_SNEXTKEY_SOPTIONSKEY_SPREVIOUSKEY_SPRINTKEY_SREDOKEY_SREPLACEKEY_SRIGHTKEY_SRSUMEKEY_SSAVEKEY_SSUSPENDKEY_SUNDOKEY_SUSPENDKEY_UNDOKEY_RESIZEKEY_MAXKEY_CTRL_%cInsecure: operation on untainted windowInsecure: operation on untainted mouse;w@ 4КH\0xPp @D0P @pp,HPd@ @4P`l p 8 Pd P P  @H t 0  в P X t 0  ( H `h з p 0 0L `d |  P 08\4 `p|@4`Pp@@,H` xP @` $<Tl @`,@D`zRx $XPFJ w?:*3$"D@\hpt |GHl L AAKAAK(EDG L CAP 8<FAD q ABA D ABI (T EDG N CAN 8FED A(G0n (D AEBG (XEDG Q DAJ 8ܙFED A(G0n (D AEBG ($EDG T DAG 8PFED A(G0i (F ABBE 8FED A(G0i (F ABBE \*E`p|.EdAAK0gE| O LgE| O hpA(ǠNjX"۝JÏ55]p׮" @xO(/ V|}zOoRUMNa5?Wju Pfv'6K(kk1$ OCn0p\~@-N[;p\b\PzO@Hjsq&ND*PO‡?ϥZ?۹s2_PyMeYB\7cEP+*iύ3,ʠ23_7ÑG~5b]e]! ]Ybe/`⾱YP[bV2 cɉeX1!(*nW)٬UBE :Iu&K`DpGBgV-ٯa_md';<1XaMƔ0hW؟c?OWި.mN"M3'FlA?MJ}E,AL[U9Ϥ[KoNճBoFD`tFE7[{2) 8*JKMm^V9nt -|`F*߇]n6ʚ9Ϸ^D!VR4 w0ݷOy2HڥSL'Tu5" UlqjHT 2a~E5@L(lKf׿:J=YGؿec&6Ƭg-̞U[. $8XK):P/29q9bYUsr?Â=54  c@[KEOl(U嵱!_JRa+<7J,@&2m6D A6Q mPiߏRg+Uʲ1;LfKFZ Ja~~ @xId)ȣnfmw&]P sNdTg 10~.ӪČ?00fܠq=Hףճo&!ReeOF)&!ϯk|3fZ  5 C!A)w[y{|L hᾈ RdyoO-9}OZYsHθ6xr? 0 # define LONG_LONG long long #elif SIZEOF___INT64 > 0 # define HAVE_LONG_LONG 1 # define LONG_LONG __int64 # undef SIZEOF_LONG_LONG # define SIZEOF_LONG_LONG SIZEOF___INT64 #endif #if SIZEOF_INT*2 <= SIZEOF_LONG_LONG # define BDIGIT unsigned int # define SIZEOF_BDIGITS SIZEOF_INT # define BDIGIT_DBL unsigned LONG_LONG # define BDIGIT_DBL_SIGNED LONG_LONG #elif SIZEOF_INT*2 <= SIZEOF_LONG # define BDIGIT unsigned int # define SIZEOF_BDIGITS SIZEOF_INT # define BDIGIT_DBL unsigned long # define BDIGIT_DBL_SIGNED long #elif SIZEOF_SHORT*2 <= SIZEOF_LONG # define BDIGIT unsigned short # define SIZEOF_BDIGITS SIZEOF_SHORT # define BDIGIT_DBL unsigned long # define BDIGIT_DBL_SIGNED long #else # define BDIGIT unsigned short # define SIZEOF_BDIGITS (SIZEOF_LONG/2) # define BDIGIT_DBL unsigned long # define BDIGIT_DBL_SIGNED long #endif #ifdef __CYGWIN__ #undef _WIN32 #endif #if defined(MSDOS) || defined(_WIN32) || defined(__human68k__) || defined(__EMX__) #define DOSISH 1 #ifndef _WIN32_WCE # define DOSISH_DRIVE_LETTER #endif #endif /* define RUBY_USE_EUC/SJIS for default kanji-code */ #ifndef DEFAULT_KCODE #if defined(DOSISH) || defined(__CYGWIN__) || defined(__MACOS__) || defined(OS2) #define DEFAULT_KCODE KCODE_SJIS #else #define DEFAULT_KCODE KCODE_EUC #endif #endif #if defined(__NeXT__) || defined(__APPLE__) /* Do not trust WORDS_BIGENDIAN from configure since -arch compiler flag may result in a different endian. Instead trust __BIG_ENDIAN__ and __LITTLE_ENDIAN__ which are set correctly by -arch. */ #undef WORDS_BIGENDIAN #ifdef __BIG_ENDIAN__ #define WORDS_BIGENDIAN #endif #endif #ifdef __NeXT__ /* NextStep, OpenStep, Rhapsody */ #ifndef S_IRUSR #define S_IRUSR 0000400 /* read permission, owner */ #endif #ifndef S_IRGRP #define S_IRGRP 0000040 /* read permission, group */ #endif #ifndef S_IROTH #define S_IROTH 0000004 /* read permission, other */ #endif #ifndef S_IWUSR #define S_IWUSR 0000200 /* write permission, owner */ #endif #ifndef S_IWGRP #define S_IWGRP 0000020 /* write permission, group */ #endif #ifndef S_IWOTH #define S_IWOTH 0000002 /* write permission, other */ #endif #ifndef S_IXUSR #define S_IXUSR 0000100 /* execute/search permission, owner */ #endif #ifndef S_IXGRP #define S_IXGRP 0000010 /* execute/search permission, group */ #endif #ifndef S_IXOTH #define S_IXOTH 0000001 /* execute/search permission, other */ #endif #ifndef S_IRWXU #define S_IRWXU 0000700 /* read, write, execute permissions, owner */ #endif #ifndef S_IRWXG #define S_IRWXG 0000070 /* read, write, execute permissions, group */ #endif #ifndef S_IRWXO #define S_IRWXO 0000007 /* read, write, execute permissions, other */ #endif #ifndef S_ISBLK #define S_ISBLK(mode) (((mode) & (0170000)) == (0060000)) #endif #ifndef S_ISCHR #define S_ISCHR(mode) (((mode) & (0170000)) == (0020000)) #endif #ifndef S_ISDIR #define S_ISDIR(mode) (((mode) & (0170000)) == (0040000)) #endif #ifndef S_ISFIFO #define S_ISFIFO(mode) (((mode) & (0170000)) == (0010000)) #endif #ifndef S_ISREG #define S_ISREG(mode) (((mode) & (0170000)) == (0100000)) #endif #ifndef __APPLE__ /* NextStep, OpenStep (but not Rhapsody) */ #ifndef GETPGRP_VOID #define GETPGRP_VOID 1 #endif #ifndef WNOHANG #define WNOHANG 01 #endif #ifndef WUNTRACED #define WUNTRACED 02 #endif #ifndef X_OK #define X_OK 1 #endif #endif /* __APPLE__ */ #endif /* NeXT */ #ifdef _WIN32 #include "win32/win32.h" #endif #if defined(__VMS) #include "vms.h" #endif #if defined(__BEOS__) #include /* intern.h needs fd_set definition */ #endif #ifdef RUBY_EXPORT #undef RUBY_EXTERN #endif #ifndef RUBY_EXTERN #define RUBY_EXTERN extern #endif #ifndef EXTERN #define EXTERN RUBY_EXTERN /* deprecated */ #endif #ifndef RUBY_MBCHAR_MAXSIZE #define RUBY_MBCHAR_MAXSIZE INT_MAX /* MB_CUR_MAX will not work well in C locale */ #endif #if defined(sparc) || defined(__sparc__) static inline void flush_register_windows(void) { asm #ifdef __GNUC__ volatile #endif # if defined(__sparc_v9__) || defined(__sparcv9) || defined(__arch64__) ("flushw") # else ("ta 0x03") # endif /* trap always to flush register windows if we are on a Sparc system */ ; } # define FLUSH_REGISTER_WINDOWS flush_register_windows() #elif defined(__ia64) void *rb_ia64_bsp(void); void rb_ia64_flushrs(void); # define FLUSH_REGISTER_WINDOWS rb_ia64_flushrs() #else # define FLUSH_REGISTER_WINDOWS ((void)0) #endif #if defined(DOSISH) #define PATH_SEP ";" #elif defined(riscos) #define PATH_SEP "," #else #define PATH_SEP ":" #endif #define PATH_SEP_CHAR PATH_SEP[0] #if defined(__human68k__) #define PATH_ENV "path" #else #define PATH_ENV "PATH" #endif #if defined(DOSISH) && !defined(__human68k__) && !defined(__EMX__) #define ENV_IGNORECASE #endif #ifndef CASEFOLD_FILESYSTEM # if defined DOSISH || defined __VMS # define CASEFOLD_FILESYSTEM 1 # else # define CASEFOLD_FILESYSTEM 0 # endif #endif #ifndef DLEXT_MAXLEN #define DLEXT_MAXLEN 4 #endif #ifndef RUBY_PLATFORM #define RUBY_PLATFORM "unknown-unknown" #endif #endif PK|]2x86_64-linux/syck.sonuȯELF>ps@h@8 @ !! ` hh!h!00888$$ Std Ptd\\\  QtdRtd!!ppGNUmB \{h2﹔|`5AfDq 86 2V^Z%pDDX A@ X`(BXǃpLU>=E6"Jޡ9ɹgMIVv`T䷴ $ig ɶpP3Y0n(Q ACP}ot6qX}7ᵧa;JmhJ'{rxj?8/^%rQ 4DfzzԻn!åKX clA8+CQs߿~gw_'vpV]mi9DQxqkx<њd 4=X0м ۙL=[$>!PdI͈n ;tĪpB|X#.e#fJmqA=xN[W|_G /hBEG fgKM;TRpi,ntWƬ ۹T=﷌tؾrxI%j}T SwC!BmL628 =_Ef%_j3:/'; Y1!?"KDRzW Y  GFT 9n$   B ^ avh;ig #) C /   O u U& q 462 ZK D^] G]   r u + , GF"W g i 6 '.  A    R   t  cO 1    @B,x Py |{? B: @  P pw S `v ~  S < y `, |8   t u#  `\   \ @.!   ww ` ' @}7  `  ? Ь @uEH x u  L^  :# P w 5 | =8  P@ Љ# k 0~H  @XC ~( Y  P Q } I0o  . , C:  - `^W Ђ P  w  p  P=`~ ~! L7 v 02 w1a x F   PU `Um  <F^  PS v! {.3 @_ D DO B 0   .Q  PpQ vl 0  `>. =  AP  0@  =  pB  z2(   `<Q1 ?  \  9 . e L  @:  ||  f Эv4 p  0W q  p- C$ PC  6h N P{~ `R  :f @  pF GE PM-+  ;|  r `x F!. }"\ t3 u3h [ z`W!  V S,w `w  0t!    AY w w t Y  P  @; p5 w   @Jt  {G   l  >b ='  X 0A! `A!  Pz pvXc  P!( a>  0  @R  <5 B]  J  ?x__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizememcpysyck_io_file_readfreadsyck_st_free_nodessyck_free_nodesyck_assertfflushstderr__fprintf_chkabortsyck_strndupcallocsyck_parser_reset_cursorsyck_parser_set_root_on_errorsyck_add_symst_insertst_init_numtablesyck_lookup_symst_lookupsyck_st_freest_foreachst_free_tablesyck_parser_handlersyck_parser_implicit_typingsyck_parser_taguri_expansionsyck_parser_error_handlersyck_parser_bad_anchor_handlersyck_parser_set_input_typesyck_parser_current_levelsyck_parser_pop_levelsyck_parser_reset_levelssyck_new_parsermallocsyck_parser_add_levelstrlenreallocfree_any_iosyck_parser_filesyck_parser_strsyck_parser_str_autosyck_move_tokensmemmovesyck_check_limitsyck_parser_readsyck_parser_readlensyck_parsesyckparsesyck_default_error_handler__printf_chksyck_hdlr_add_nodesyck_hdlr_add_anchorst_init_strtable__stack_chk_failsyck_hdlr_remove_anchorst_deletesyck_hdlr_get_anchorsyck_add_transfersyck_type_id_to_urisyck_xprivatestrncatsyck_tagurisyck_try_implicitbytestring_allocbytestring_append__assert_failbytestring_extendsyck_yaml2byte_handlersyck_map_readstrcpysyck_seq_readsyck_yaml2bytesyck_st_free_anchorssyck_base64encsyck_base64decsyck_emitter_st_freesyck_emitter_current_levelsyck_emitter_parent_levelsyck_emitter_pop_levelsyck_emitter_add_levelsyck_emitter_reset_levelssyck_new_emittersyck_emitter_clearsyck_emitter_flushsyck_emitter_writesyck_emit__sprintf_chksyck_emit_tagsyck_tagcmpsyck_emit_indentsyck_scan_scalarsyck_emitter_escapehex_tablesyck_emit_1quotedsyck_emit_2quotedsyck_emit_literalsyck_emit_foldedsyck_emit_scalarsyck_match_implicitsyck_emit_seqsyck_emit_mapsyck_emit_itemsyck_emit_endsyck_emitter_mark_nodememseteat_commentsescape_seqnewline_lenis_newlinesycklex_yaml_utf8syck_parser_ptr__ctype_b_locstrtolsyck_alloc_strtry_tag_implicitsyckwrapsyckerrorsycklexsycklex_bytecode_utf8syck_resolver_detect_implicitrb_str_new2rb_syck_io_str_readrb_int2inumrb_funcall2rb_string_valuerb_syck_err_handlerrb_eArgErrorrb_raisesyck_emitter_node_exportrb_funcallsyck_merge_irb_check_convert_typerb_syck_load_handlerrb_data_object_allocrb_hash_asetrb_syck_bad_anchor_handlersyck_new_mapsyck_resolver_node_importrb_check_typerb_str_newrb_hash_newrb_cHashrb_obj_is_kind_ofrb_cArrayrb_ary_poprb_ary_reverserb_ary_pushrb_eachrb_iteraterb_ary_new2rb_ary_storesyck_badalias_cmprb_ivar_getrb_syck_free_parsersyck_parser_s_allocrb_gc_markrb_gc_mark_maybesyck_resolver_add_typerb_attr_getsyck_parser_set_resolverrb_ivar_setsyck_resolver_use_types_atsyck_emitter_resetrb_scan_argsrb_check_string_typerb_respond_tosyck_out_initializesyck_badalias_initializerb_iv_setsyck_domaintype_initializesyck_yobject_initializesyck_privatetype_initializesyck_scalar_initializesyck_scalar_style_setsyck_scalar_value_setsyck_seq_initializesyck_seq_style_setsyck_map_style_setsyck_node_type_id_setsyck_set_ivarsrb_ary_entrysyck_resolver_tagurizesyck_genericresolver_node_importsyck_map_countsyck_seq_countsyck_scalar_allocsyck_seq_allocsyck_alloc_seqsyck_seq_value_setrb_check_array_typesyck_seq_emptysyck_seq_addsyck_seq_add_msyck_map_allocsyck_alloc_mapsyck_map_initializerb_hash_arefsyck_map_addrb_eTypeErrorsyck_map_add_msyck_map_value_setsyck_map_emptyrb_syck_emitter_handlerrb_syck_free_emittersyck_emitter_s_allocrb_syck_output_handlersyck_emitter_emitrb_fix2intsyck_new_str2syck_node_init_copysyck_defaultresolver_detect_implicitrb_num2intsyck_emitter_set_resolverrb_str_catrb_io_writesyck_parser_assign_iorb_syck_compilesyck_get_hash_arefrb_syck_mktimerb_cTimerb_num2long__memcpy_chkyaml_org_handlerstrncmpstrcmprb_ary_shiftsyck_str_blow_away_commasrb_cstr2inumstrtodrb_float_newrb_requirerb_internrb_cObjectrb_const_getsyck_defaultresolver_node_importsyck_set_modelsyck_parser_loadsyck_parser_load_documentssyck_const_findrb_str_splitrb_to_idrb_const_definedsyck_resolver_transferrb_cBignumrb_obj_allocrb_obj_is_instance_ofrb_ary_newrb_ary_unshiftrb_ary_joinrb_str_appendrb_str_cmprb_str2inumsyck_out_marksyck_out_maprb_yieldsyck_out_seqsyck_out_scalarInit_syckrb_define_modulerb_define_module_underrb_define_constrb_define_module_functionrb_define_class_underrb_define_attrrb_define_methodrb_global_variablerb_define_singleton_methodrb_define_alloc_funcrb_include_modulefwritefputcapply_seq_in_mapsyck_map_assignsyckdebugsyck_map_updatesyck_new_strsyck_new_seqsyck_alloc_nodesyck_replace_str2syck_replace_strsyck_str_readsyck_seq_assignsyck_free_membersstrchrget_inlinelibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_startGLIBC_2.3GLIBC_2.14GLIBC_2.3.4GLIBC_2.4GLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64ii ti ii ui ! t!s!!!!b!!!!ǃ!Ճ!!!!! !(!'0!38!=@!AH!EP!IX!M`!Qh!Up!Yx!]!e!v!i!q!y!!!!!!!ބ!ń!τ!ۄ!!!!B!  !(!!0!/8!?@!OH!`P!]X!k!!!!! !!!! !!!!!!!!v !(!0!"8!@!'H!#P!X!`!h!p! x!!r!!!:!;!!!!!!!!!!!!N!!! !(!0!8!@!H!P! X!W`!h!p!x!!!!a!!!b!!e!u!y!!!!!!m! !(!0!8!@!H!P!X!`!h!p!x!!}! !!!! ! !!!! !!!!$!!!!~!! !(!0!z8!@!H!P!X!`!h!&p!x!!!!!!!!!!!!!!!!! !!!"!#!$ !(!0!t8!%@!&H!{P!X!'`!(h!p!)x!*!+!!!)!,!!-!!!.!!!!/!0!!1!2!3! !4(!0!58!6@!7H!P!X!`!8h!9p!<x!=!>!!?! !!!!@! !!A!!!B!C!D!!!s! !(!0!8!@!H!EP!X!F`!Gh!Hp!x!I!!J!K!L!M!!|!!O!P!Q!!!w!!R!!!!S !T(!0!%8!x@!UH!VP!X!X`!Yh!Zp![x!!!\!]!^!_!`!!!!!! !!!c!q!d!e!!f !(!0!g8!h@!iH!jP!kX!l`!h!np!ox!!pHH!HtH5b!%c!hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!h%}y!D%uy!D%my!D%ey!D%]y!D%Uy!D%My!D%Ey!D%=y!D%5y!D%-y!D%%y!D%y!D%y!D% y!D%y!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%x!D%}x!D%ux!D%mx!D%ex!D%]x!D%Ux!D%Mx!D%Ex!D%=x!D%5x!D%-x!D%%x!D%x!D%x!D% x!D%x!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%w!D%}w!D%uw!D%mw!D%ew!D%]w!D%Uw!D%Mw!D%Ew!D%=w!D%5w!D%-w!D%%w!D%w!D%w!D% w!D%w!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%v!D%}v!D%uv!D%mv!D%ev!D%]v!D%Uv!D%Mv!D%Ev!D%=v!D%5v!D%-v!D%%v!D%v!D%v!D% v!D%v!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%u!D%}u!D%uu!D%mu!D%eu!D%]u!D%Uu!D%Mu!D%Eu!D%=u!D%5u!D%-u!D%%u!D%u!D%u!D% u!D%u!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%t!D%}t!D%ut!D%mt!D%et!D%]t!D%Ut!D%Mt!D%Et!D%=t!D%5t!D%-t!D%%t!D%t!D%t!D% t!D%t!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%s!D%}s!D%us!D%ms!D%es!D%]s!D%Us!D%Ms!D%Es!D%=s!D%5s!D%-s!D%%s!D%s!D%s!DH=s!Hs!H9tH.j!Ht H=r!H5r!H)HHH?HHtHk!HtfD=r!u+UH=k!Ht H=e!idr!]wATIUHSHHNHFHxbH)H~BHHVH9vHFHH9sHHH)HHI<,H[]A\H9rH[]A\HHHVz tH9wUH)HH<SHHHHDH[]ff.fHtHH1H1ff.fATAUH1SEHHj!H1H;8H;ff.UHH~SHHHHHH[]ff.fSHG@HHtgHHCHCHHCPHCXHC`HChHCpHCxHǃHǃ[DH8HC@@HwSHHHHt H HǍYHcH[H<$Ht$H<$HT$HHHt1DSHHHt%H5g!1HHǃHHt%H5g!1HHǃ[@Hw1GÐ1GÐHw Hw(w0HcHHHD@~!HHHHxfff.@USHH~HHuEH[]1H=ǃHEHEHEH[]fDS|H_HHǃHHHHǃHǃHǃHCHC0HC8HC@H[ff.AUAATUSHHHcH9}bHL$E,$LlAD$LLHID$HcHHHhH[]A\A]@HcHHXHcHsDSG4HtuHHtHǃ[ff.SHHHtHǃHHHHGHtH4HHG H{@HǃHt HC@HGH[ff.ATIUHSHHC4HL HtHh[]A\fH-!c!Hh[]A\AUIATIUHSHHHE4 HHXLHHXMtL`H[]A\A]L%a!L`H[]A\A]fATIUHHSHLHH[H]A\2fATUSHw`Ht_HWxHG@HII)H)t@HM~LHHC@HSxHC`HHHCpHHChHCXHCPHCHHSxL[]A\ÐE1[]LA\DHhHG@tHHGxfHGhHGPHGHHGpHHGxUSHHG4tD1u"LH{@HLAPHHHHHH[]fDSLH{@HLAPH@UHSHHG4tIu<LHH{@HLAPHHHHH[]1@LHH{@HLAPHff.SH3H;HH[ff.HOhI1H+OPH5xSHHHHuWHH{tH[fHHD$SHD$H[ATIUHSHH HdH%(HD$1HrHD$HtHT$8udI$HHT$HtH|$HtI$HH?HHL$dH3 %(uQH []A\{tHD$LHHHAT$I$Hu+HI$hFfDUHSHH(HdH%(HD$1Ht$HtOHT$Ht$tH|$HtHHhHD$dH3%(uH([]ÐHHf.AUATIUHSHHdH%(HD$1H$HILuMH$HH{HtH@HL$dH3 %(HH[]A\A]fDH$HuI$HtaLH&uHLAT$(I$HHH$PfHLAT$(HH$H{^Hkbf[HI$yfATAUHH~SHHt aHCEu Hk[]A\H HCHt[H]A\+ff.UH~SHcHfHcHHHx-privatHe:HfAA +H[]@AVIAUIATUHcSVH|I LLtag:HHxA:HLHfBD#[]A\A]A^ff.@fDS(AHøHHC@HC@|C HCH[fAUATUSHH HH9AHAHtHII)IHSH{HCL9H)HD/HGHt$H9vH)1DD5DD7HH9uHȺ fHCL)HCH+CH;CH[]A\A]DHHLhfDLHL$H)H@HHH{HwHHSwHCHtPH{HSHL$=H 8H59H=>mH PH5H=cNH DH5H=/ff.@ATUSHHH9IHH9 F uzHWHnF H+nHGHH9It$H)HH.H9s1  HH9uHHCH)HCH+CH;C[]A\@HV:AHH9 uHH[R]A\fHH)H@HHHSHpHCHSHHCHC=H dYH5H=H EZH5H=H &\H5jH=H qH5KH=ff.@AWAVAUIATUSHH(dH%(HD$1HD$*HSHHt1ɾAHLcMtAEr1LTHXC| HC D$SHPH@HL|fD#IHA EuM9vL9M911A ZHHD11ҾMHHC E1Lt$Hx ~e@L1HLLHuHt$HhLHLLIHFHt$H9HC L9` 11ҾEH.HLHL$dH3 %(HH([]A\A]A^A_fDLHx7L!IHx1LTHLCc11ҾQHHC E1Lt$HxHLHILLHSHt$HFHC L9`t$LH0D$C0fDNHHfDATUHSHdH%(HD$11H1HHH5SU!HK1H1H$HHHHHqu5L$$I|$HxHŸD fEH}EIt$HOHHL$dH3 %(u H[]A\f.@HtHH1H@1ff.fH UHHVUUUUUUUHSH?HHHH)HzHN1H=D HH0?0SAA\H^w>fIcL>H5H\L9t%Hހ>\H^vĺHL9uHH[H5]A\A]A^A_H5HL9uDHcD$ A? L)H9L9fH5NHL9SlfDH5HL9+DfDH5H\L9fDH5H4L9fDH5H L9< < H5gHIHIyfH5HHL9SlfDH5HL9+DfDH5H\L9fDH5H4L9fD*DH5HL9fDIIff.fAVAH5`AUIATIUSHӺA(A2LIXHL9rPfDL9tSH; HkuHLH)YL9tLHH5A2u[]A\A]A^DI9vLH)[L]A\A]A^DH5nLTH5vL4AWAVAAULcH5ATIULSHHT$ A(0|$ 2EL=EMcl$HHIH9r-< uA> tH)L9f.I9tuLL{< uHLH)A< t< tA< t < I9tLML|$ 2H5DuH[]A\A]A^A_L9sLH)HL[]A\A]A^A_DHLLMLEDH5L\gH5L<H5LAWAVAUATIUSH(Hl$`Lt$hH4$L$DD$ MDL$LI HHD$H9HDMuAEE1o|$ LHLHD$HILH=H<$HIA}H4$LLMtLu 1D$ÃAT$ EAED$ L$H|$AML$ƒuAU)Pv&tRD$(w0H 5HcH>ڃu@ H([]A\A]A^A_|$D$2E@|$@AEMЃ)ЃuH<$H5E1QAE1HAHDBD$ Ht$AT$,AUDH<$H5jRM|LjoDAEЃ)Ѓ$H<$McH<$LOAD$BH4$LLsfD|$@9@65DD$HEfDH(L[H5)]A\A]A^A_fDt$ LHLAE @t$ LHLnAEDt$LHL]AE@T$t$ MHLAELHLAEfH5LAE fDD$DAVAUATIUSHHI蜿H+LHIt"AFPvt9AE[]A\A]A^HߺH5 AE[]A\A]A^AFЃ)ЃuH5HAF DAVAUATIUSHWHIܾHLHIt"AFPvt9AE[]A\A]A^HߺH5ULAE[]A\A]A^AFЃ)ЃuH5HAF DAWAVAUIATIUSH#HË@ w9HHcH>@k~ KH5LkLLkH[]A\A]A^A_:f.CLc3EjH5wLFk먐LsuPLH5NLk_kLH5Lѿk0fLhSDsu xA?LakfLHCkfH5LQkfkD3D+0A L=LLD9uA~Hc$B0HcHŅ1D HcH9HL譾H腺FE++(L=/DLLAdD9uf.K) HL1HvUSHHNHH賻Ut{v)tTuAH5HH[]սDuUx H5-tH[]HHߺ[H5]醽fDUt)ʃ)ʃuH5jtH5N\H52DAUATUHSHH(H8dH%(HD$1HD$HD$HHT$HH{@HHt$HT$輸uwHkHHHx HC@Dh ¿HIHD$A1LHP @LEHH1H{@HT$Ht$葻HL$dH3 %(HD$umH([]A\A]ÐH{8HG PHcHT$V@˾HHC8賾HHC@ H-Ž zf.SHHChHSxH)HC`H~s t t~tWHHChHPHShHSp@< < u%HChHPHShH;SxuHֺHShf: t;HC`HCh[ÐH踺HCh|HPHShx NfDHHShHSpH;Sxt< HShDH`HShf.WЀFH ݾHcH>@1Df.f.f. f. f. f. f. f.ff.f t1 t1 @WAWAVAUATUSHHHH.!H~hH<$H0DEuvHChE1H9CPH-HFHIƅu@HChHSxH)HC`H~ 8}HP3HcLH>DH訸HChfǃHHD[]A\A]A^A_@HSxEH-*H)HC`H18.HcTH>f.HShA HC`HChHSh@ fD< t< HChHHChH;CxuHHChѐHShE;.AFDHA jHC`HChDHSh@-DHShHSpH   fE;.gd轺HIHC`HChjHHD$]PtLshHcLH+sPD$8H9u%t H*LshD$8D$dM1ILI_`IGxH)H,Ls< -E< D.< < Mwh{ =MNMOhMOpM;Ox#A< 4 < # <  I_`H"HHIGPI;GHv AIGHIGhH9HHNtHصHSh@: _ HHShH;SxuHShdE1AdHT$EH-3MHT$IHCxEDHSXH)H<  t<  AHC`HSXHHShH98HMcLmA}^Ot=Hu)f}^FLLeM9wH$AL(BHShHSp@ DH蘴HSh@: gHHShH;SxuHShE;.H諳Hߋ0 HC`D @HShHSpH  t[ HHShHC`IcHH+sPH9AF$@HгHSh@: uHHShH;SxuHShHdHC`D HShE;.H˲Hߋ0)HC`D @HShHSp@< L < 4 < , Lk`L(HLHCPH;CHv HCHHChI9qILUtHShx HHShHSpH;Sx)p@HShH輺HShE9.dHT$A1 HT$Dt$AdIIIFxIV`H)HJ HB n= eIFhIFpB< m!< x < p I^`HHHIFPI;FHv AIFHIFhH9HH&tHSh@-fHShGHPHShx DHC`HCh^HHBHChH谳0dδHk`HIED$8 <>t<|D‰D$8D$LkhD$HL9LeA-t8A+ HBD`tκ 1HOLkhD$DD$(fD< <\( HrAHshHspB"HH!D$2CH(HChAE1H- MD$ D$dHCxLc`L)H~A<$-{A$HcDH>HLchf.HD|$裯HShL$2fD8HSPAH)Ѐ: DDH軮HSh:#tpVE1MID$HChHCpA|$- IEnD9l$HC`McC7IcEAID$HChA|$ uHHChHCpH;Cx<  <  <  Lc`L誶HLHCPH;CHv HCHHChI9 ILװt뿐ID$HChHCpAD$IHLch蘭x. HFLchLc`2fHز1聫{H H=HE1҃|$8HE Icƒ|$2LxHHtMEtHMd fDIL uHU |$(HBtHJHLI9II)ID$HBH$A H(HPHShHSpx.HPHShx.HPHShH  ' HHShHUD@Eu~HChHSx}HPHShHSpx-bHPHShx-PHPHShH $  )HHShH٫x%0C@HA "HC`HChDHHHChPHChHSxHPHShx HBHChHCpH;Cxg < 6 < % <  Lk`LHLHCPH;CHv HCHHChI9ILtHPHShHSp@fDHpHSxHshHHHHChH9 t tAD+kPfDHHHCh耪DEHkhHHShf: HHShH;SxuHAHC`ZHŪHSh: &HHShH;SxuL=QfHHShH;Sx>-ILch'HBHChz HCpHChL=HCxHHShH)H  fE;.HC`AH)HxHrݬH4$H+HBHChB0<6w5H~~Hs%HBHChBHЀ6wHHHshHE9oBCD=IcADIHBHChRE9 KL=HL$ŭHL$IcADHShHH-HHShH;Sxg -HC`AH)HxHr̫H4$HHH躭DH蘨HChHSx,HHHKhx HHHShHC`8:HPHShD f.H8HShD$Hct$LìIHSh%HChHPHShH;Sx: HCpHCh@HBHChz oAH:f.HBAHChz tFf.8 3HHChH;CxuHaHChHAHSh<: <] <}HD$MwhxB; tHi^IGhHXI_hHcIw`HcT$HD$ HH)Ht$(H9YH)LHD$H%LLLINIM9uHD$t$H D$Ht$(IH|$ I)LLD=HcAD<,MwhMwpC< J < < L HcIw`M$HD$ HcD$I)Ht$L9XI)HLLd$(HL0HLH~II9uLd$(D$I A B D$Ht$H|$ MLI)LLDhHcADLrMwhA>  IMwhM;wxu@LMLsh1Hc褢HS`HShHP LzHjH4${Hv AhfDALHT$Ic葩HT$Im@8HSxHHAHK`>H{M)ԠLLL)覧HCHZI<HH$HsHHhIVHuHHAϤLwfHHHKhx HfDHEnD9l$HC`McLchC7IcEA8D$(tHSPAH)Ѐ: AEʼnD$(HxHD$0 HHHc0HShH+SPHH9u t$|$(Ɖt$9p9AĺHH{D$?D$ HD$0|$8 uEtHt$01ҋ|$(9>‰ @t$ Lk`E1HKhI9sLת7HKhII9r|$ AE|$?EfD;d$McIcC7 EAHD$0t$()Hc׉|$ H)IHKh9dHHC`HCh1负{IRH=J6ID$1҃|$8ID$ IcƒLxHHEtL|$2tEIlHHCuIT$ |$(HBtHJHLH9HH)HHHBH$L A  HAIf.A~AF H5{H=0HEXIT$HShA|$-HChHKPHAH)΀9 DDDHChHChHHChH;Cx8 HCpHChHShHChHPHShH;Sx: HCpHChH蓠HShIT$HShAL$ 4 tj 2HHShLc`L;cPEnD9l$=A$McILchC7IcEA$HHSh: uHHShH;SxuLAJHx觞J<8^HH$HsHH赜AT$IuHHcDH號HChD$ D$?D$ A1^LmI_hD$Hct$LIFH?HSh&H.HShCHHChCIcG&ELH\$ IID|$D@B IB D9tDAE9AHIcjЁD$Hct$LHL$ NHL$ ID|$LIH\$ HPHShx PHCIGh{ Mwh$"H\utIFhIFprNnwdH5Hc H>HBIFhB0<6w5H~~Hs%HBIFhBHЀ6wHHIFpIFh]A9 IVhHcBA,HcÉA1IFhHPIVhx uD$HD$HBD}IFhZE9HcLEIcDAIVhIFhIvxHIFhH)HHIVh HЀ d t̀  _@;D$(R t$(AH>ALT$IcDT$IPHHShMwhMwpCMwh{#LMwhHD$Mwhx ; tHzIGhHXI_hHcIw`HcT$HD$(HH)Ht$H9ZH)LHD$ H%LLLI^IM9uHD$ t$H D$Ht$IH|$(I) MwhMwpC< < < /LMHChIT$HShA|$ HHCh*H HShQD$Hct$L蝟IdHT$1Ad^HT$IIHCxL{`L)HDAMw< !~E< <'yLshA'u6IDuL{hE9HcIcA,'DA딄<Lsh1贗HI艙x" {bH=8$IEIE HcL`AHhH$L(SHCIGh{ IGhHD$@D$ I_h{ tH{I_htHI_hHcIw`L$HD$HcD$LHt$(H)H9|SH)LHT$ HLLLIIM9uHD$ t$H D$Ht$(IH|$I)8tIWP1ۀ: u)L9;\$8 I`E1fDHGIG`àu@I`I_hH9wAdDeD9d$HcIcAD- DADIW`HAH|I`HbL{hHC`HKxHHChH)HCXH V% DHCXA HChqLIVhIFh1LXLI-xB{H=ܙȚIEIE HcL`HhH$L(sHARLshLspAG< < < Ls`LLHLHCPH;CHv HCHHChI9ILytLshUA9AHcMA,Hc‰A#ǃ H{h?#t.HC`HkhHH+CPHHeHC`D LshA zILshLspL;sxLshALMM A} ILkhL;kxuH:LkhD9(%A DE}MwhIGhHIGhI;Gx>MwhA> IGpIGhHH{XHShӘ10HHD$LHL$HD$HʑE9jD$CD=IcADHSh Lsh8HAHC`H蟔xtDHE1@HGHC`#u HCpHChALIcŕI|HŕDHA 認OH5H=|譍ID$H軐CL讐IFhHIFhI;FxIFh8 IFpIFhsH5H=AID$LOALIcI5HcFt5A HAD9LA9ALHT$Ic蠔HT$IIVP1ۀ: )HChHx!HshH+sPHdH藏?|$8 u E<AAn9l$wIcHcHA A/HC`HCh1躌{IH=PHH5> !1L1҆H53 !LIH1趆MHC HH9h 31HHdHHIQH5*!LI迋HfH5!L觋HLLL0fDH LH0vHtLyHH HHL$H0OHL$HtH5N!H11LI跌LMHI6H LLH= H5!LL1臅fHC Hx#IHC Hx1HHMHLHHHC H9hff.S"H.HC [H@8HDff.@UHSHH5!藆H5x!HH腆H56!HHH[1]馄fDSHHHt'HǃH[3U1HSH, HOfHHHH H`@TH߾H蔊HH[]f.SHH;輇H{資H{[驇fUSHHHH?贊H{諊H}rH}iH}`HHt1H5K&HHtH1H5-[]fDH[]fUHSHHH5!HHHH[]f.SHH5!H艋H[@HHH5~!iHff.@AVI"AUAHATUSHHdH%(HD$1蚅Lc H=I$HEjHEaHLDHEH$1ur=H5!HHH$跊A$H5!H蛊H5!H臊HHL$dH3 %(urH[]A\A]A^H<$觀Ht HEH5a!H<$8t H$fDH<$ 蚄H$H5!HKff.fSHH5Y!HىH[@SHHHdH%(HD$1HuQ H$HH5!H膉H5!HrHHL$dH3 %(u#H[fH<$ ƒH$'SH蓉H5,!HHH[ff.SHHH5>iH[@ATIHH5#UHSH@LHH5.HHH5H[]A\@UHHH5SHHHHH5ٓ߃HH[]DUHHH5SHH豃HHH5蟃HH[]DAUIH5|ATIUHSHHH!cLHߺH5!1*LHߺH5!1HHߺH5!1~HH[]A\A]f.UH"SHHHC HtlH9- t3H9- tzH9- taH9- txH9- uH@  H@ HHH5脂HH[]f.H@ @H@ @H@ @H@ @ATUSHHHt$"H|$Hk ~HD$Le HpHxNHT$HH5ƑID$HE HJHHÁHD$H[]A\DAUI"ATIUHSHH茀H HH5wvLHߺH5 1=}LHߺH5 1$}HHߺH5 1 }HH[]A\A]ff.fUH"SHHHC H9- H@ t%HHH5Ԑ̀HH[]UH"SHHHC H9- H@ t%HHH5tmHH[]USHHHt$"4Hk H}Ht xHEHT$Ht%H|$|HD$HpHxSHT$HEHH5HD$H[]ff.@UHAUATI1SHHdH%(HE1yH}HE|HMHHAHHH%H)HHH9tHH$H9uubLl$@IfAEHQLHq{H߾ByLLHH]dH3%(uHe[A\A]]DH)HL@zUHSHHyHu HH[]Hx{HH{HHtHwHH[]f.AVAUATAUSH"HN}H[ H{Ht,{IċC]HC HpHx+L , IHC t5L  t)L tL tALD H5J [LH= ]1A\A]A^|y@H[]A\A]A^k1I6@HH~H1HIH}LLH|H6H9|HC A8H5 ML1H= xH' H5HH|H[]A\A]A^fH1&wHNI&fHHwHLHH3HvH9|HC A8tGH5 ML1H=A 7xH H5EHH>|H[]A\A]A^fL ) L  @U1HSHuH - HH HHxHH[]fDU1HSHLuH HH HHxHH[]fDAUIATUSH"HrzHMe yHHu%HLH57K{HH[]A\A]DLxH}~1HHHAuLHftH;]|ff.AUATUHSHHH5 px"HIyH5i LLk -yu9HLsH5 H/xHH|HH[]A\A]fDH5 HL17vHfU1HSHrH m HH HH0wHH[]fDAWIAVAUATUSHH(Ht$"HT$HL$xILH H Lc }HHH5 1H1vuHxI~=E1fLLIsHHIuLLH|M;w|H HH5:9yHL$H1H5 tHL$H1H5m tHL$H1H5b tH(H[]A\A]A^A_H H5шH81qff.AVAUATIUHH5 SH/v"HIwH5( LLs vu8LHL{H5 HuLHH wH[]A\A]A^ÐH5 HL1sLLH5 H1sIfDAWAVI"AUATUSHHH|$vIH { LLk Hp{IHt~LtH5 11L\sHxI~31HLHqLHHsHLHzI;_|H|$LH5+wHL[]A\A]A^A_Hb H5H81oATIUSH"HuH[ Ct1u"HC HsE1E11LppuXZ[]A\DHC HsLqHC Hx ~D1H1H#wLHhyHHwLHHIyHC H9h [L]A\3{HC HsLoHC Hx~1HHHpLHxHC H9h[L]A\zSHHHtGnHǃH[wU1HSHlzHoufHHHH O HPH@prH5 HHuH5o HouH1H5 H= qH5 HHyHH[]fDAVAUIATAHUSHH H5 dH%(HD$1hrHyH5 HߍPHHcHT#yHL$LDLD$H1%o"HxsLc HL$M$IMHtI}H5 1&pHuvH5 HqH|$H5~ H1oILLnHcH5 HHToxt;H\$dH3%(LuCH []A\A]A^I}Ht$joIDLLl1LqMuoAW"AVAUATUSHHqrH H[ 1H=M HFapIŋCuHC HpHxqIE IHkHtH*nHH_rID$H[HtH nHH>rID$M,$H5 L1H=B H[]A\A]A^A_nf.1)lIIE HC Hxh1HL5> HHJm1HL1;nLHkHC H9h&1jIIE HC Hx 1L5 HHr1LH1mH1HL= IHr1HL1mLLHBuHC H9h UHSHH9t]HHt[@uU@tO?"uEH߾"opH[ "H^pHE ooKHoS P HH[]H H52H81jff.@USHHH?sCtDu0HC 1Hx~#fHHHkHypHC H9hH[]HC 1Hx ~H1HCqH;pHH+qHHpHC H9h H[]ff.HtHH*1H1ff.fHHjHtHxHpnHHlH=nHlUHSHHHH5> Anu HH[]H5! 1H1}k1H5 Hu8ckHkjHcH߾"knHC Hh8HH[]f+kHtHcff.1DSHHXHt'u"t?uH[ kf.HHqH[HgfAVIAUATIUSH.HsiHtMHE1@t)HSHsL1_rI$D[]A\A]A^HtLmAfH5 HltZH5 Hlu2H HHLA1qI$D[]A\A]A^DH5Y 11HlH, H5}H81fff.UHAVAUATSH HudH%(HE1EqHuHHiH5 HAo1Hzp1Hpm1HqHNfHUHHnLmI}RhHHHH%H)HHH9tHH$H9uufLt$D IfAI~AFIu"fHjpLiEt u Hu1HMdH3 %(u*He[A\A]A^]@H)HLDHgfATIUHS hHHt H[]A\@3qLHHHkH[]A\f.AWIIAVAUATUSHHdH%(HD$81?t HHD$IoA_I~HD$]LetSLL)L9}HL\$+pL\$H IA$ÀuDXt 1LL\$WjL\$HlA\$Ml$At[LL)L9}PL\$oL\$HfIA]ÀuDXt 1LL\$iL\$LdA]MuAtTLL)L9}IL\$UoL\$H IAÀuDXt 1LL\$iL\$LlA^MFAtoLL)L9}dL\$ LD$nLD$L\$ Hf.IAÀuDXtLǺ 1L\$ LD$iL\$ LD$LtIXHL)L9aAPE1Ҁ.u&t+HHL)L94BՃZ„uф1 HLT$}hLT$Lit<:u @t H<:u<:LT$HI1H AVAUH5 ATLD$0HL$(H;eH5 H 1HH1dLT$HH5h LT$8dHiLT$L)LH`aHIUaH;MH5# H1ydGE1L%aH5 IPH& AVAUATLD$0HL$(H814dH Ht$8dH34%(HH[]A\A]A^A_DL\$lL\$H @H]ÀuDXt 1HL\$fL\$HDHD$@Ht$ 1fL\$HDHD$cLT$HH{LT$ 1MhfLT$HHH)M<Ix00L\$(LD$ H|$D$10000fD$5D$7kH|$LD$ HL\$(Hf.HHDAuH)Hv- 1L\$ LD$eLD$L\$ IAP LT$1HL\$ LLD$eL\$ LD$HeLT$HHH)HI) a@AWAVAUATUSHHHoGH4$HH=qvHAAEEu=HAtEH$L HD[]A\A]A^A_@tAE1H}H=dHH=uH H=uHH=uH=H=uH-H=uH7 H=luHAH=YuH H=?uH H=.uHr H=uHo H=uHH5tH[]H5tH4bH5tHbH5tHb H5tH\ZH5tH\hH5tH\)HC 8L`HXZH5aHaLH߅fAIPDtChHC AHpHxCfIAAAgIHC Hx 1pH rHr LfHH5 H11^H5 LIH1d^MHC HH9h j1HHcHHIbH5 LImcH\H5 LUcHLLL`@L0`HtHHD$-^H q HqHeHtH5 1H1]LD$ILidLMHIcHi LLH= _f.H5 LL17]fHGH=_HE1A)HtsH=_HE1AHC HxcIHC Hx1HH[HLHH[eHC H9h@AAAHC AHpHxcH=^HR]H=pHC]IHH5a H1\H=Yw]H5L HH1[H[IE1AHA\HC HxT[IHA\HC Hx,[IHE1y\HC LpHhLI9s`AI^H}I9G}:tSH :tKHHGH9u 12^IILHL)III9rOd$AHHHHA[HC HxgZIH[HC fLhHhLI9ssAI]H}I9}:tmHD:tcHHGH9u1T$)XfLT$I*HL)IIYXL9wf(A}`I0HHHHHHfA^F`IrfA^#`IHHHGq^qfWqA_IHAtZHC 1Hx5W_IsHC AHpHx1\IRHC 1HXCHH(\HHHaIHHuDBt H1[H{IUHHIHuDBt1 [HHH= HH5; MIHH= 1AiXI|_E1IlH5 H= 1A6XIIH5 H= 1AXI&I;:It$H{A$_H=mHXH5> IH=d H1WIH=`mUH=lYHH3 H8\H ATUHSH"HHdH%(HD$1aZH[ 1HH[t$H$HT$dH3%(u;H[]A\H{L$$ XMHH5Y H1VhVAUIATI"UHSHYH] H54 H\L9- HZHU^ItOL9% t61H ZH5 H}]H5 HH[]A\A]tZ@HYŐH5 HWI@H H5 H1UWfDAVAUATUSHH kH dH%(HD$1Ll$LD$LdTH5= HZ1H[UH5$ L% HHbZLH7U"HIwXLc LH1H[I$LLUE8^H5A HHEZLHEHD$HHDHERHL$dH3 %(u H []A\A]A^aTAVAUATIHhUSH dH%(HD$1Ll$LD$LTSH5- LuY1HKTH5 H LHRYHH'T"LIgWI\$ LHL1ZHLHTH59 LEXHEHEH5y H|$H1S\HHEPuHL$dH3 %(u H []A\A]A^4S@AUH5hATUSHH, H([Hx~OI1fDHLHXHI9]~*HLQHZHHIOTuýHH[]A\A]AWAVAUATUHSHH(Ht$HtH|$SHxu

    `WLH=7`KLH=4`H 8LH=&`Hz %LH=`H LH=`HD KH=`H9 KH=_H KH=_H KH=_H KH=_H KH=_HJ KH=_HO zKH=_H4 gKH=_HA TKH=_H& AKH=_H .KH=]H KH=_H KH=]H JH=\JH=x_JH=u_Hg JH=l_H JH=\H JH=M_JH=\H JH=5_H rJH=)_H _JH=_HI LJH=_H. 9JH=_HHH JH=^HHHx JH=JHHHU IH=^HHH" IH=nJHHH IH=^HHH IH=^HHH |IH=k^HHH aIH=U^HHH FIH=B^HHH` +IH=-^HHH= IH- HH5E^HHUHH GOH5^]HH OH= 1H'H5,]KHl H=} H5]lKH H=^ H5]MKH H=? H5\.KH߹ H= H5[KHX H= H5 \JHq H= H5]JH= KH=Q\GH= 1H1EH_ H5[HHI JH H=6 H5I[JH H5\HMH= KH=[WGH=0 1H1DEHM H5&[HH "JH HH5P\MHUHH5M\YMH5v[HH NH= H5a[MH= H5h[MH5h H=y |KH=m HIH5ZMIH=N HH5[.IH=/ 1HH5[IH H= H5[HH H= H5e[HH H= H5ZHHUHH5B["LH H5/[HH HH= H5YLH= H5 ZLH=o 1ɺH5nW|LH=U 1ɺH56WbLH=; 1ɺH5%WHLH H= H5YGH= 1HyH5FYGH HH5\Z'KH5x HH IH" H= H5YrGH; H=| H5/YSGH4 H=] H5 Y4GH] HH5YJH5 HH- IHQ H= H5XFH H= H5XFHӵ H= H5kYFH\ H= H5aXFH HH5:YIH5 HH pHH H=z H5WAFHJ H=[ H5W"FH H=< H5XFH$ H= H5WEHULH5XQIH5THH JH= H5TIH H=~ H5WuEHULH56XHH5hTHH7 IH=& H5ITuIH= H55TXIH H= H5VDHULH5WVHH5SHH IH= H5SHL%b H=s H5VLwDH=X LH5U\DHUHH5/WGH5ISHH yHH H= H5U DH H=ܿ H5TCH=V@H}HSDH= HEHUHH5V1GHUHH5VHl GHUHH5VHZ FH5THHr GH H=_ H5T>CH H=@ H5ACH H=! H5@CH H= H5TBHUHH5UNFH5THH{ FH5W H=h DH H=U H5THyBH=: HڹH5xU^BH H= H5_U?BH H= H5S BHI [H=Խ ]H5tSA\Af.AU ATIUSHH=SUHH- HM/DL9w9I)INlcL%2U H}L1H&DL9uHuH []A\A]=fHcH SHH Ѓ)HT1CH޿)[=HT1CH޿)[=ff.@H~(tEATUHHSHDHs(HID9IT$H߾H8HC([]A\fff.@UHAWAVAUATSHXL%9 HA<$dH%(HE1GHDž1LLDžLLMDžDžHfAH?HTI9@I)MIIH'D H=''HHFHHHDHH%H)HHH9tHH$H9ut H)HLHD$O|-HIHLHH=HHLHL46HIFIHHH=HHA4$N|9Nl/2LM9rfHMdH3 %( He[A\A]A^A_]DHHA $tH{ پHlRH81AH[D4XAA$Dž HcH _ DA6McHWB0;H,YF40EtbA4L A$SHIUDljIEIIcމDDE@uDE L5Qf.H9ZXt=wHH=V<L;A $IIbIHYXu@HZ A΅BHcLE$HHH>[40)HHcItHHH)I)HHE-NwHHRHcH>I}Iu19IEHfE$EtHLHHHXHHHLhHZ0A7HwHcH5fUf4f9HYHIHHxDHa L1H8H;>IGH TH;4H3 7A$IHL,H YV4xA$1HIDžIE.f.DžDžH H=NH<1lHH%7A$fDDžA4$L5 H NH?71I>I6 {6fDH H=MH0fH=dL$;H H=KHX:IIc9DHS$IEHIuIUH<3HpHI}IuPi4IEHIHcH5 HKH H1 H819yIuIUH2HHxpI}X5I}IuH.IEHHI}IuP3IEHLIuL/IuHL/HHv3HJHIuH.H/IuHO.I}Iu0I}8IEIEHHǀHI]xH=3u4HCHIuH50HH=285HHxBH=34HC뜾H=24HHx'H=23HCLHL-IuH1,HI]H{(H|Iu-1-HI}w5HI}IuN-IEH~IuH-H65HZIuH,I}H,IEH.IuH,HML-XMIL;7A<$tH H YHH$11H;6IH;AtyH3 \0Hs H1HC3HX [f.S1H@HH@~3HX [AV1AAUIATUSH*H{L` H0HLI\$HE4$ID$/HE H@H[]A\A]A^USHH+HHH[].fAVAAUIATUHSH_ Ht.IH{Ht(I\$ HCHCHCH}/HkHLD3HHC2/HC([]A\A]A^ÐATAUHHSH*DHH[H]A\3fATIUSHG HxHhH_HH߄t<,tHH߄u[]A\ÐID$ HHH)HHhH1ff.HG H@UHSHH_ H{Ht'H] HCH{Ht'H] HCHC @HC.@HC.HCH[]AUIATIUSHH_ Hk HsH{HEHC H9HCL,L$H[]A\A]HHsH_/H{HCHCH4F/H{HCff.AT1IUHS&LHHH1H[]A\fUSHHn HE H~kH_ HS HKH{HH9~H)HHHtH9LHCLMLE1fDI4H4I4HHS H4Hs HVHS H9M H[]HsHc.H{HCHCH4J.H} HC~H{HS zfHG H@ HG u H@H H@H ff.@HG u H@HH@Hff.@UHSHH_ H{Ht!%H] HCHC@HC[,HCH[]ATIUSH_ HkHsHCHUHSH9L$[]A\HHHsH$-HCL$[]A\U1HSH%HHHN%HH[]@HG H@HG H@Hff.@HG H@Hff.@HSGHt tCu3H{ Ht*HGHtH#H{ HG#HC [fHG HtHxHt#HC H@HxHt#HC H@Hk#HC [Ðff.@SH%H{Ht 5#HCH{Ht#H[#fD?~w'HMHcH><fDH(luHH(Hl(HOWHO079.uGHWDH %9`AHQ<:8H LHcH>@H$9~6HO@fDH$#H5HOfSH#$fDLSH"(@UH"fDÀ:HB<0<5D<9HBHJ<.Z<:tƄHp4Hc"HDJH:wH54KHcH>fDHQIH14PxVfDLH!UGQHJ0 ÀyHH .HOqHH0 q0 qH-@Hs@:q0 RH0 rÀz :rJ H/0 [J 0 Kz :AJ 0 1J0 !HJR960 .uQH+/H5TEHcH>ZuۀyH,HHNHEH+DATAUHSGH`t3Hlt(HuHG HpHxKHH}Ht HEHAtHH[HE]A\HމH=N[HE]A\fDH9HtHu 1fDATUHSHH-HHbHIHHL#LHHt#HHtHLLD$ (H D$ H[]A\f.AVAUATUSH;H,O߀Yw[H5DHc H>J0 w;J0 w/J-J 0 wJ 0 w z :HމH=[]A\A]A^f{HsWԀNwH EHcH>@SJԀNwH5FHc H>H{p[]A\A]A^@{HsWԀNbH GHcH>SHsp-M1H HHcH>H{,NH IHcH>@HH~VHVHHLvMI)I}IUHIHuLH!%tLDHQHDʺ2@Hyaml.orgHL)ID A .H0LfP H@,200L)bLHH[]A\A]A^HDV0 V0 V0 V0 V-/HLfMI)LIVHHI_HLLL)LHGfDHH=~ILJVHNZ:A} 0 7QHq,N#HcH>_tavHVHN-MIcL>@SHs.R/g`SHs.)/:7Sу,bHSH=JH5"L,NDHc H>fHSHs./3rSHs./ iSHs.X/vfSHs.//a=SHs.u/tSHs.L/feS Hs .#/=:HH[]A\A]A^NJHH -MHc H>J0 J0 J0 J0 J-+:jdH=gKH5LHJRZA} 0 4HH ,NHc H>H -MHc H>,V0 V0 V-t2H/_haVV 0 uV 0 e~ /[H @AVAdAUATAUSHd IHkhHSxH)HH~A tM ttt`HHChE9ECD%CD%If.HHCh uHHChx t^[L]A\A]A^fHkhL[]A\A]A^HPHShx uHHChALIcaIjfH;CHvHCPHCHfAWAVAUIATUSHHH H~hH0t!ǃH[]A\A]A^A_fDHp xIt*HChHSxH)HC`H8D}HC`HChL%KH. xIƅu@HChHSxH)HC`HHP8cIw@Ic L>HShpHH@ tX@ upHKhx HHQHSh t* uGHPHShx HHRHSh uHHAHKh/HC`HChfHHHShx LxHuL{h8 AFL AF Ѓ)Ѓ:DhH HChH (HPHShHSpH t eHPHShx SEL$HBHChErE$E3H HChA6HShfH߽ HC`HChfDAFHSh?vtA6H߃^H߽HIEHHChx 5H;CH+HCPHCHfDHShH  &HPHShx HHChAFfu AVQ HH> P*HCh x MHShH  HPHShx OHANAVHChu r1@ŃA6H߃HChx U9 DAFHShA6H߃H߽ HIEHChx HHChwfDHShH  HPHShx ?HANAVHChu r1@ŃA6H߃HCh@HShHCxL{`L)HAIW< < HShIfDAFHShOvtA6H߃nH IHChx %A<$!A|$L6-@AFHShN5A6H߃L{hd dIHSxLL)H~\  DHHChDeD9GAHSxHcL{hA.IcDL)ALHH߉ $HCh $fHHYHPHShHSp@<.<_~ a<HCxHHShH)H<_#<;}<.<9~HJHKhB<.<_HCxHHKhH)H#<_<.}< t< uGHAHChy u9HShHBHChfD: pHSxHC`H)H8VHC` HChHAFA6H߽-#HC`HChfDHShz \H9SHRHSPHSH>@L{h1Hc~HHP HjLrIE {sI}fDL9{HL{PL{HfHPHShx L`Lch@hashstr->bufferext && HASH == ext->hash(str->buffer + str->length) - str->remainingext->buffer[0] ==YAMLBYTE_ANCHORbytestring_extendbytestring_append--- %%YAML:%d.%d --- &%s *%s! tag:yaml.org,2002/x-private:!!--- \"\\\0\a\b\f\r\t\v\e\n|+~tag:yaml.org,2002:nulltag:yaml.org,2002:str? tag:yaml.org,2002:seq[tag:yaml.org,2002:map{[] {} : id%03d3111111`383322`282111111111111121111111111111111111111111111111111111111111111111111111111111111`1688,9 9L9<<;;T<;;;;;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/0123456789ABCDEF4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT>LLLLLLLLLLT>T>T>T>T>T>T>LLLLLLLLLLLLLLLLLLLLLLLLLLT>T>T>T>LT>LLLLLLLLLLLLLLLLLLLLLLLLLLKMKMKMKMKMKMKMKMKMKMKMKMKMKKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKMKKMKMKMKMKKKMKMKKKMKMKMKMKMKMKMKKMKMKMKKMKKMKKMKJDHHHHHHHHHDHHDHHHHHHHHHHHHHHHHHHHHHDHHHHHHHHHCGXHXHGGGGGGGGGGXHXHXHXHXHXHXHGGGGGGGGGGGGGGGGGGGGGGGGGGXHXHXHXHGXHGGGGGGGGGGGGGGGGGGGGGGGGGG?FFFFFFFFFFFFFFFFFFFFFinternupdatedetect_implicitdupdefault=matchpushhas_key?keysnode_importtr!unpackwriteyaml_tag_read_classyaml_tag_subclasses?emitterset_resolvernode_exportto_yamltransformyaml_newyaml_initialize@tags@optionstype_id=@resolver@levelstyle=value=@out@inputModelGenericbytecodescalarquote1quote2foldliteralplaininlineadd_typeuse_types_attagurizeDefaultResolverGenericResolverParserbufsize=bufsizeloadload_documentsNodeinitialize_copyScalarSeqaddMapPrivateTypeDomainTypeObjectBadAliasComparableMergeKeyDefaultKeyOutEmitterresetemittag:ruby.yaml.org,2002:object:YAML::Syck::BadAlias?Stack now %dtoken %s (nterm %s (Starting parse parser stack overflowStack size increased to %lu Entering state %d Reading a token: Now at end of input. Next token isShifting token %s, -> %s syntax errorError: poppingError: discardingShifting error token, $end$undefinedYAML_ANCHORYAML_ALIASYAML_TRANSFERYAML_TAGURIYAML_ITRANSFERYAML_WORDYAML_PLAINYAML_BLOCKYAML_DOCSEPYAML_IOPENYAML_INDENTYAML_IEND'-'':''['']''{''}'',''?'$acceptdocind_repatom_or_emptyindent_openindent_endindent_sepindent_flex_endword_repstruct_repbasic_seqtop_imp_seqin_implicit_seqin_inline_seqinline_seq_atomtop_imp_mapcomplex_keycomplex_valuecomplex_mappingin_implicit_mapbasic_mappingin_inline_mapinline_map_atomReducing stack by rule %d (line %u), HH?HHHHH;HHHHHH;UHHHHHH]mִHHff]HHHN;HثdTTkثdثdOTTTƳJ!ث߰dDYTT1v**J!ث߰dTqűTqTձ !"#'*1!!!!()0023 !$%&+,./! %+%+%+ )3!&/&/&/ $-$.9; i?@mC 567QP "#$% S) cMNO k567WUmZ] :"#$%HIJ)LMNOUWZ9S]UWZ]HIJmLMNOQ"#$W)Z]567567567?kCm"#$%)MNOMNOMNO aHIJLMNOstuvwx             `!d14{hjf~l>>vO vvv`OOO O>$$k---O>>O &'(gce=>?,-@A}BC.23 "#$%&    4758KNOLA0E3J/@+<->) !'(29:HI6MA.?*;,=B1CDFG !!!!!!!!"""""##$%%%%%%&&&''(())**++++++,,-.////011223388<AFGJKPU^dehmqy~ $(.29:@ELQV[`djkq{ !"     !!!! ! #'*1%&&%&%&%$&$&()()0+//+/+/+!,-./$/./23230  $%(+.1368:d??D@t@@ @L$AtdAABDC0ChDDD4E$FFHH$IdIJLJJDLM<MODOOdQ`DSSTT(UHUU4V4WX0Xh^di, j` j l 4m$!m\!4r!r!ds "4t8"td"ă"T"Ą"$#ĒL#h#d###T# $\$4$$$4$Ė,%X%ė%ԗ%%4%% &H&$\&Dp&d&$&d&&'tD''IJ (zRx $ FJ w?:*3$"D 8\hFDD O ABH L ABI $3EKG YAA#NNEFDF $,3EHL WAA DEm F @ TXEG a CH xlEfL HD@ <  8 44@10HlEAG } AAD wAA|E8LFEA C(G0o (A ABBE 2ElE4 x`FDD u ABJ LABHD~FED D(G0@ (A ABBH O(A ABB(.FDG RDB4{FAA c ABB DAE 8(L|EAG  DAG (4EDG { DAH `"E\|($0HEG Y AJ VA0XFDD G@  AABD ($EDG@l AAB 8'FBD D(D@w (A ABBG 4XUFDH _ ABD RDB$LEGI tAA8aFEE A(D0D(A BBB  GEA8(<FBA A(D@ (A ABBF 8dFAA  ABE i FBG HFBB E(A0A8G` 8A0A(B BBBG 4FAD D0  AABA $@#MND<XMQN  AAB @ AAF _ AAG (EDG  AAA D^EX18FEA C(G0v (A ABBF 0D`EAG } AAD ~AAxE | xcEYDE` K (UEDG y AAE 8 4FED A(G0v (A ABBE @\ FBB A(D0GP 0A(A BBBK P OBB A(D0p (A BBBA `H04 `FDA c ABG IDBH, COEA A(  ABBH  H(Dx OBI E(D0s (A BBBC PH tvFBL B(A0D8GP} 8I0H(B BBBH H FBJ H(K0D8DPu 8I0H(B BBBE LX \ FLE D(A0 (A BBBF L (D BBBJ ` FBE L(D0D8GP 8A0A(B BBBA O 8D0A(B BBBJ d hFBB B(D0A8F` 8A0A(B BBBA  8I0H(B BBBK Lt FBB D(C0G (A BBBA ] (A BBBD L FBB D(C0G (A BBBA ] (A BBBD H pFBB E(D0A8D@_ 8A0A(B BBBO @` EAG t DAJ f AAH D IHK < vFBA D(GP (A ABBB  E B ,, H@M-FBB B(A0A8G 8D0A(B BBBE   <, yHZ N U K U K D !8!FEA E(GPp (A ABBB 4!_HH!\!FE@,x,"FDA | ABF  #DE~`@#FEB B(A0A8OPV 8F0A(B BBBK D 8D0A(B BBBG (|%!ER$D%JEDD iGHl%-Ec$%fEFD QDA&'E]0(&EAG ] JAK DAA$&6EDG ^FA(&EVD&!HX@\&SFJH A(A0G@ 0A(A BBBH 'EV 'EN b AJ T($E^h(EV(l(LFND pAB$D(;ENG [DA$l(;ENG [DA4(FLD D(G0[(D ABB()EIG k DAK ,){FAA G0g AAB4( *FJD D(G0j(D ABB(`t*XEIG r DAD (*XEIG r DAD $*EAG0qAA(D+EC DF F 0 ,VEDG O DAD hDAt@4,\FBB G(A0 (P DBBI I (A BBBH  (A BBBJ  (A BBBC $.:EFD hAA$4.:EFD hAA8L.FEA A(L0p (D ABBF 8D.FBA D(G0\ (D ABBG $/:EFD hAAH,/RFEB B(A0A8G` 8D0A(B BBBA <@0FBB D(K0^ (A BBBB H40FBJ B(A0A8GP 8D0A(B BBBA Ld1 FDA (C0H(A A ABF b DBH EDB42-Ec$H2EFD DA@2pFBE G(A0GP 0A(A BBBD HX3FGB B(A0A8G@ 8F0A(B BBBO (5EDD f DAA 46EAG H AAI OAA6#NN 6@H_ I K4@6EDJ T DAD Q DAJ x<7 87WEl O OLx7FEB D(A0w (A BBBH c (A BBBF ((8NEC K E 4(L9FFDD R ABE ZABt`d9FHB B(A0A8DNGI]IBBXX 8A0A(B BBBF H> FBB B(A0A8GPa 8D0A(B BBBE 0$0IFAD O0B  AABH 8XIFEI D(D0r (D ABBI @PJFBB A(A0NP 0A(A BBBA @K,FBB K(A0DP 0A(A BBBA 4LFIA A(D0i(D ABBHT`LlFBB B(A0D8G`G 8D0A(B BBBD 4PYFAI p ABE FDB(PEKD@ AAI (PQEKD@ AAI (0QEKD@ AAE ,\RFHA MI4(aBGI A(N0V(F ABBaaKh M \,aQMAG uABC,b EC P F Dpo5Eo`oQEK|oFE@ p8Er80p`FGE A(A0D(A BBB$Tp'ECG IIA8\pFEE A(D0b(A BBB(Tp.FDG RDB(pbFDA p ABB p $pxEDD hAA8@Rnׁ,:G7JȘ1r@I cSSCM>ZP ߿ޕ÷4iC]reO^w<hDbifјVpس=xX@yQa3 sOϭ%~u@^zX\nc~:>b<w c 4<.};_ʲl0&\E=YJ:4Bi]6٧.`ԓ 35xqc:|W]?YJ9Pv/I :) 38'dxB*̠YHiYk< k^rJ~ѐ2LVAJwk<1?Ԃ[-崊o" VRE&mzZ gQYQeʸt"_>}PN옓ɧ+\L%ߵ p*mZɄ5"a|]V$H"1MY1Q*IYb gY638ez,8{PUO"sNukoW,fn妃 s-}Z ƾo |rIEAiå J G O;:-Tjdز֝E"6ltU~ A䶁udkd,6?hvo./)aO cFXk; ?M4ɟ2;eiSOvq '#:xy]40kv|0qe1M"EdWhj g(Z3'(܈N4.Sf_w1){.t^BN1l_sIw~qN8+>B#U?73l['hnoJ} C?ˬ(84@DWh㥀pZPf(J2ƏPlR0b??+Xah? E\` <7E]Ә~B6}A4pƌQ`IA.<?A?uvU 16wgmgZYJ/ %m^ jҫSM4LK8.=wb^n%l2ѼsI O0+_ Zruo(P|0vF{eCqmgbK ׾#_[i}.AX! c0 sI"aجfzO.E} ff6Q}P'Rl7:,P7Rua u9aǾ.Ҩ%!݆nM~Qc-SjB VOMOtTUn[(UfšM fHl\ÅkdX,܈N9jEu8wsL996GI=\ZsV.2L{iަ BYz[9x+ޅvB^78 6/aDI>F¦-W'q~W}KGGhx i ѬMoZt4UEɁU~ȸ3=~%?p~EP>i-cL.a0B$BZ Ť1Kb!X㩚9*dQby5NMnGr'Y*.qvu3ja 0Q@ LgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``( 0##A8o77TEoh9h9`T99` ^B(F(FPhxYxYcYY nff wpspsm}jj kk\> \\ hhP" !!! h!h0!h!!!P a("d 41PK|]mɐx86_64-linux/bigdecimal.sonuȯELF>p@@8 @ `` ` 8 xx x 00888$$ Std Ptd000QtdRtd`` ` GNU 1FHDuOHD x9~)эHcHfDfHcH@ftftEftO1ftfNaN@fuJt|0.0Ãt[u+HHInfinityFH-0.0FH-InfinitHyfF@ H+0.0F 0.0FAWIAAVAUATUSHH(H<$T$Ht$u-f{~5AHD$Au(HH@+DH([]A\A]A^A_A-IA0.LxE1IfH$H@HD$HJDH$ Nl L1HHIIHHtKHt I9rL1H sLHHI1L1IDIL9d$qH4$AFHN DMcHw$H̺fHIHHH9r@0uIAA0tH rHL1tD$t$H|$H([]A\A]A^A_\Ht$HF H4$.FHN DMcHFDG0~9~NWD9}yfHG HG~Yfw1H5rDf~AHG HGfW1H5qDfODHG HGfGff.fOAfw#]HsHG 1HGÐHWf.HBH| u,HHuHG HGf~_1fWUSHHo HWHthHHuH| tHtH)HHWvuH[]fG1HCHt(H{ Hɸ@HWAWH88HAVHAUATUSHHBHHL% HD$H.H@ŀu%HH+@ŀu @DA u@#M]HE1E1HxHhHD$IHHHDdEeEtMAĀu&HL$MAHL$HPf%fIA_t#IN,1HDdEeEuHMuAEHMIt3B\5Àu(BD%ItB\%Àu HDZ u߹ H=WoH H=:oH{ H=%oHH=pHE<-E1<+AAFd5E-AĀAE1H&fDIIIFd5EqIAĀu ADBuA.HD$0BT5LE1H88JHPHHHH!IHHHHH!I~LT=AHՁu BD5I~H|$8qDAƀcHT$(1LL$ LT$H|$8LT$H0LL$ HD=HT$(fHD4EtAƀu BDvu@HD$LL$(LT$ H9ILBJ(HHT$AHT$LT$ ILxLL$(H@ H@rfHH(1I~ LL$LT$HLL$2LT$A<-1<+uABH0Ay!KAC DHD92AHH9rDE<-<+>LA1E1A98E EADD1D)׉A9 DE1AD)H9bO IA Hw4H9v/1HDfUf.HgH|$HQAFH|$H7M.1f}H@J\ HhfDfHG HGA1fDGH8[]A\A]A^A_AfDHD$M)1DL$$JH| DL$$AHgJcH>JD Ht$HD1fw EL޻ E1E11f}HAEAFHHD HHff.LW MtWI̋G)LAIHHI w DHHAIHH wAP1ff.fATIUH- SH*tfHtQHtMt9H= w/H H fHcH>Ivf}~ H[]A\A]DIvf}~HHHH[]A\A]IE#wDIdwDIE#wIeIwAtIwjf.AVAUATUSFHfAffPfVLnHH Hv WDfAOąL9oLFoLoN4fGLA t+L9mL1HM MtHUDHCLkCD[]A\A]A^ÐDHC fHCDNE~?1fs[]A\A]A^HG 1HG1f{[]A\A]A^1fKDHG fHGDNE~/fWR@1HLk6DfG#ff.fATAUպ SH:~DH[]A\4@[1]A\fH~ tyHcF~qHVNH9stH)HGGH9HG1fHWfGHcFHt"HHHLfHL IL HH9uHfDHG HGf~ fWÐfGfDSHftftQft+H[fD1H5`]H[1H5`=H[1H5`H[AVAUATIUSH0Ht$H|$dH%(HD$(1H|$4HD$LpAI:@ŀ0E1HI:t0@ŀDZ0AKDHcLlEuI IELLGLH 1LHH9HHD$Iv"H88LHHH9SvHHSsH]HL$(dH3 %(uPH0[]A\A]A^L16H 1LHHHHD$H H5__H81ffffAD ftcft]CfAHG HGfDG1H5u^t\tff~W1HG 1H5 ZHGfOf.tRfXfHG HGfwLff.VfkfffDfCf.Pf+f~Lf~LHG HGfWf~ff4f~HG HGfGvff.AWE1IAVAUATIUHSHHXHF HFfDVAwHT$@HQAWAL$rAff;ffHE HEfEHt$@AD$f~%fHC HCfSHEHX[]A\A]A^A_f(ID$HD$HHHEH|$@HD$0HwHCHD$H9HC HHVHHLHL HHH9uHD$H9T$vfDHHDH9u1H|$0HT$0lHHDH9uID$ HD$8Hiʚ;H|$HHD$ HD$v(ID$(HD$8HD$ 1Ht$ H|$HHHD$HD$Ht$0HH9HGHD$HHD$HAISZ/DH4LpHt$(fJ IuH< HG HHiʚ;HG(H9D$ H9D$H;t$041Ht$8HD (ML$MIL;L$uHt$(LJL E1HLLMlfDHH HIH Hiʚ;H)H9AHʚ;NDH)HL(HL L9Hʚ;L)AHL LH)I9rH[]A\fH<$HtѾ H<$SxHHx /Hv H5DLH81AWAAVIAUATIUSHH8vHɃtMANA|$QGfuFfHC HCfAfDSH8[]A\A]A^A_DfAvE\$ADEMnIT$D9L9MLFMt5ID$ I9F w1DMD M9D wdHI9uL9rPzE1DfAfAOBDPMu+AHC HCfDKMfDHkAffDCAOH}HC DLHLD)LcJL9HCI$EtmH9E1L9wM|IH9 ICH9L)HMt fDDfDNAVfD{WH91L9wILIH9ICH9L)ID HHD$(wDLHHCH8[]A\A]A^A_@HLMMIʼnDA@LHxHC@HD$(Hi1ɉsH߾HkLT$HL$ L\$HT$LT$d<$HT$L\$HL$ KHHD$(H9H$IL9ʚ;"fHI+L JHL L9pHHH)HHuILDHiE1E1sH߾HkDL$L\$ HT$LT$>DL$<$LT$HT$L\$ HK7H$IL9IsHHHt(HIL HL I9s_HHHuHD LHL)HtL9HHD H9u1IHKL HL I9wHLH|HH)M1f.H1HHt2ILHIL HH=ɚ;vH-ʚ;HfHI)H)MtEHLLH1HHt"HID H=ɚ;vH-ʚ;H֐L)HuH1AfCHSHtHTH $H1HCH8[]A\A]A^A_fHDfH)H $1|fHD$(fE1L95HLL)Lf.HIt It H9uHL)HthHHHH4HM 2LHH)ȹHʚ;L)ID Ht%IDHM\ M, L9rH)1L)@H)H)HtHHH)H4HfDH)1HT Ht!HIT H9sɚ;H)HtH)LM9t.fAzA1AfCff.fA~fSBfDsH߾HkLT$LT$t<$@H$psH߾HkDL$LT$rDL$t<$LT$tfDH$LHDL$SH$DL$yLֺHLT$+H$LT$ffCNLOH11Hff.USHHdH%(H$1Hu/1H$dH3 %(HĘ[]@t̋? t)"uTHuH9Cu"HHC @ HHXHHHx 3yfD `HHH =B1HIغH4Hu)Ht HHl H5 GH81~H@USHH`BHHdH%(HD$81HH߾wH5DCHHHHD$1Hp2H (BHHD$HD$HXHEHL1H11HH4HH|$HHD$HT$8dH3%(uHH[]qHP1ftftft HD1HÐH~Pft1fHDHff.H>fxHHff.HH@HHDff.@ATUSHH@dH%(HD$81H5AHHHHD$1P H IؾH `@HD$HD$HL`1LL1ɺ HIHHHMHUH<1L LHH @LH|$HHD$H\$8dH3%(u H@[]A\sSH@fHDH[DH@fHHDHdH%(HD$1NHH$HPHtH|$dH3<%(HDu>HfHxHt%1DHHH)HT HHH1H9uHc@H脿@HHHHUSH8dH%(HD$(1H5S>HHH$HEH*=HD$(dH3%(H8LH[]A\A]=D)@EЅB*؀"H ;HcH>fffOfD*"H<HcH>u>1HL$(dH3 %(DH8[]A\A]LHHtŸfD*u@fofHD$(dH3%(H8LH[]A\A]闶t_PfDffxA9}f*"wpH;HcH>fD%HHHf.*"wH;HcH>H=81蜴@fQ*"wH<HcH>f~߃*"wH<HcH>LHMEM9LIFHt*Iu H9p rwL1LT M9T wr7HH9uM9s7f*"MH<HcH>flFv*f~˃*"H<HcH>*"HZ=HcH>Hz1HHl*"H=HcH>ff.Gf>rfLbf<Rf=Bf*2fAWAVAUATUHSH HHHdH%(HD$81諳HHIHHx HEؾHIHHD$AEfIEH51HHD$DHCH50H|苿H50IH@HH| oLHILLLcufDHLLLH $#LLSH $H L9vLHL)LH&H|$MtLLs`IHH5/HHHD$!HCCHC fCHD$8dH3%(aHHH[]A\A]A^A_!EAHC HCf{DHD$:f.I}I} HCfKfA}CHC >A4fS!@hfDAHC HCfDSAtAHC HCfDKDHZ LLH LH+USH8dH%(HD$(1,Ht$H|$HHHHD$ H|$4~k1H52D$ff/Y f.z$u"HW HX ^Y D$gf.HH5Z.1Hǯ11HHD$HD$HhH蕭1HH蒭;"D$8NHL$(dH3 %(ueH8[]D$%Y f.LFHW H6W ^fWF8X T@UHSHH(dH%(HD$1Ht?@u9@t3?u)HT$dH3%(uFH(HH[]H߾;H8H<$HD$dH3%(uH(H[]ƭ豬AUIATUHSH8dH%(HD$(11LIHH$HtiHHH5z+HD$HCID$HuH8H[]A\A]HD$(dH3%(uH8LH[]A\A];֫fDAUIATIUSH8dH%(HD$(11LHHH$HHHf{HD$t f}u,HEHT$(dH3%(!H8[]A\A]fHHIHt|HHHHf{HD$t f}u,HEHT$(dH3%(!H8[]A\A]fHHIHt|HH5HHDH|EH"It$H|$8HIcFH4$HPHHHHLHNH)Ht$0HD$FL|$0D$8HrqqLLHLH?HH988HH)HL$0H)HIH9t)D$8d$HI^I?IID$8fQf.f.f(fTY$f.!$f.Qf/f(wfW$ #f/#E1f^If/sMT$1I|$ T$(D$ Jd$LT$2D$ fLT$d$T$(f/)-#M|1-r#H3fDH,fID H*\f/I93Yf/rf(\H,H1E1H5F1ID$ ID$ fET$肝At$8ID$ ID$fAT$H $E|$HL? ɰsHmH\$HdH3%(uQHP[]A\A]A^H4$HTfH4$HL$HT$HHD$aHuH|$w'AUATIUHHSH(dH%(HD$1Du0HD$dH3%(H(LH[]A\A]HLL-S> HF> L-5> H5= HHHH$裯HD$dH3%(uuH(H[]A\A]-HAUATIUHHSH(dH%(HD$1du0HD$dH3%(H(LH[]A\A]HLL-s= Hf= L-U= H 5= HHHH$îHD$dH3%(uuH(H[]A\A]MhAUATIUHHSH(dH%(HD$1u0HD$dH3%(H(LH[]A\A]HLL-< H< L-u< H-5'< HHHH$HD$dH3%(uuH(H[]A\A]m舐AWAVAUIATAHUSHXdH%(HD$H1H\$HLDHHHPHD$ 1tH5LHE1E1誘1H谑HD$HD$LhDDLHљLɏH|$HHD$Ht$HdH34%(HX[]A\A]A^A_@H|$H@ @ANj?HH|$'HD$LhA] E1+uA]AIE1fDIÀ ߀FH5}H萗HE~Ic1HD1HHt1HD$HD$LhE}DL蹗f}~JA@LAu@I]AE+5@E1AH5HE1HfAE-I]HELc}HD$MyE1H|$Mu_fDMxXLE HH { 1HL$H֍L$HMu.HIL9t$IMtJD Hs D1HH0H׈CHHHHHH9uHMu.HXHIx#HK HHPB0H9ufDHP0t.E5DL;%fDHP uCDdCA]DL+|$^fD0.H{f ~LHHHL)HL3HP @H@0H9uH9uH7I5fD0f4I]AE fA]AI@HI@ATIHm US1H@dH%(HD$81Hl$IH踋t H<$HcHH|$腋HD$HHp脙H 1LHH sHHHD$YHL$8dH3 %(u H@[]A\[ff.UH S1HHdH%(HD$81Hl$IHt H<$_HcHdH|$ʊHD$HHp9HpHHT$赬HL$8dH3 %(uHH[]蹊fff. 6 SzuHT4 ^ 6 f.5 z$u"H4 H"4 ^ 5  5 5 f.zlujH3 H3 f.~% ^f(fW t5 ztOf.z9u7^fW L5 f.f.ztHY3 ^4 H5- 耗H5 H%5 hH= H 5 H2 H0蛋H2 H5H=HIH;H*H5nH;H/H5SH;H4H58H;1H H5 H;HQH5yH;HH5kH;1H.H5Y҉H;5wH5InH;H5:ZH;H54FH;H5.2H; H5-H;H5- H;H5,H;H5-H;H5$ΉH;H5躉H;H5覉H; H5 蒉H; H5~H; H5jH;H5VH;H5BH;H5.H;HH5H;H5H;HH5H;H5ڈH;HH5ĈH;1HXH5H;HMH5чH;HRH5趇H;HWH5蛇H;HH5耇H;1H4H5xhH;HH5bMH;1HH5O5H;1HH5<H;1HqH5+H;HH5H;HH5φH;1HÈH5跆H;1HH5蟆H;HH5 脆H;H5H5iH;HH5NH;HH5o3H;HH5VH;HH5BH;HH51H;1HH5 ʅH;1HNH5 貅H;HH5藅H;1HH5H;H0H5dH;1HH5LH;HH51H;HH5H;HH5yH;HH5dH;HqH5LńH;HFH56誄H;H+H5菄H;HH5tH;HH5YH;HH5>H;HH5W#H;HdH5H;1HH5H;1HDH5t؃H;HIH5b轃H;1HH5Q襃H;1HH5A荃H;1HH52uH;1HIH5]H;1HH5 EH;1HH5-H;HH5H;[HH5HH%sfailed to allocate memory111.0.1%luE%ldExponent underflowExponent overflow+Infinity-Infinityexponent overflowComputation results to 'NaN'(VpDivd) 0/0 not defined(NaN)(VpDivd) Divide by zero#001argument must be positive%lu:#02(VpSqrt) SQRT(negative value)#1F.5BigDecimalnewmodelimitdouble_figinduced_from_loadverBASEEXCEPTION_ALLEXCEPTION_NaNEXCEPTION_INFINITYEXCEPTION_UNDERFLOWEXCEPTION_OVERFLOWEXCEPTION_ZERODIVIDEROUND_MODEROUND_UPROUND_DOWNROUND_HALF_UPROUND_HALF_DOWNROUND_CEILINGROUND_FLOORROUND_HALF_EVENSIGN_NaNSIGN_POSITIVE_ZEROSIGN_NEGATIVE_ZEROSIGN_POSITIVE_FINITESIGN_NEGATIVE_FINITESIGN_POSITIVE_INFINITESIGN_NEGATIVE_INFINITEprecsaddsubmultdivhashto_sto_ito_intsplit+-+@-@/quo%moduloremainderdivmodto_fabssqrtfixroundfracfloorceilpower**<=>===eql?<<=>=nonzero?coerceinspectexponentsignnan?infinite?truncate_dumpsecond argument must be true or falsefirst argument for BigDecimal#mode invalidConversion from String to BigDecimal overflow (last few digits discarded).Computation results to 'NaN'(Not a Number)Computation results to 'Infinity'Computation results to '-Infinity'load failed: invalid character in the marshaled stringERROR(VpDivd): space for remainder too small.%s can't be coerced into BigDecimalUndefined operation in BigDecimalCmp()BigDecimal to Float conversion(VpSqrt) SQRT(NaN or negative value)ؕhؕxHrXhX(x6~~~~~~~~~~~~~~~~~[ ~~~~~~~~ ~~~~[,fffffffffffffffffCffffffffCffff|||DNNNNNNNNNNNNNNNNN+NNNNNNNN+NNNN+ddd66666666666666666666666666666LLL?4o4oo'& .>C]r2<eA?C;Wqt@wJw x 0x4@xHPz\pzpz0{|}}0~D~XPXt@00L0 8L`x`Ph0 4 ` в, D @\ pt  0< h ` 8 t 0  ` t (TP0@@, 8PTxPPhP PLzRx $nFJ w?:*3$"Dpq\t pttvvlRN(PwHADD ^ AAG HtwBBB B(A0A8DP 8A0A(B BBBJ <xH0 A XlylhylydzBHB B(A0A8G`M 8A0A(B BBBA f 8A0A(B BBBE H|0}yAD DAADL LD}m FOE B(A0A8L" 8D0A(B BBBG ,AjA E ^dBEB B(A0A8Dp 8A0A(B BBBG T 8A0A(B BBBA 8,c8LBDH @ FBJ S ABJ L܌BED D(J0K (A ABBF _ (D ABBH `BBB A(A0 (A BBBB m (A BBBD Y (A BBBH 4<؎7BDH V ABI ACBt(xAX G W I W I W@FBB D(A0D`$ 0A(A BBBA ,| (UBHB B(D0D8G 8A0A(E BBBA  8C0A(B BBBJ S 8A0A(B BBBE YW4BGB B(D0D8K`Z 8A0A(E BBBI t 8A0A(B BBBB D 8C0A(B BBBA  8A0A(B BBBA 0<(FAD F0Q  AABJ |peBEE B(D0A8Gpn 8A0A(B BBBF  8A0A(E BBBE  8A0A(E BBBC (HAAJM AAE (ȧEAN` AAA H|?Hj F Fh4HkĨ%HVܨ!HS0FFA G`  AABA +Ee+H\ H E C 4HT(LEFDPd DAE (xEFDPk DAE (PEFDPw DAE (īEFDPi DAE 8(FBA A(Np (A ABBG 88 FBA A(Np (A ABBG 8t FBA A(Np (A ABBG @ t<FBB A(A0Np 0A(A BBBG  p\HO( qEFD0P GAE `8 eBBI D(F` (G ABBJ  (A ABBH X (G ABBL       L /FBB B(A0D8O 8D0A(B BBBF (d EFDP' AAH 4 TEDG@H GAH h DAE L FJA D(D` (D ABBH T (G ABBE ` LFJD A(D`g (A ABBJ | (D ABBK T (G ABBH `| FJD A(D`g (A ABBJ | (D ABBK T (G ABBH L EFGB B(A0A8Dt 8A0A(B BBBK 40 REFD` AAE  FAF dh FBB J(A0D8Dm 8D0A(B BBBI d 8A0A(B BBBA $zRx ,|f d HBJE E(D0A8D 8A0A(B BBBJ  8G0A(B BBBL twH@i A EDP AA LpUFJA D(D (D ABBI L (A ABBA zRx (Ve <H4AZ A HXlFBB B(A0I8D 8A0A(B BBBE DFBB A(K0D 0A(A BBBA L(FBD G(DPq (G ABBL e (D ABBE L<FBD G(DPq (G ABBL e (D ABBE LHFBD G(DPq (G ABBL e (D ABBE HlFBB J(G0A8D 8A0A(B BBBE 0(FKA F`  AABA (\EHF`| AAA QGNU@p 4CS^iw  l` h o`(    H P o oo0 ox  0@P`p 0@P`p 0@P`p@@?GA$3a1y GA$3p1067pjGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYPjGA+GLIBCXX_ASSERTIONSbigdecimal.so-1.8.7-16.el8.x86_64.debugn7zXZִF!t/w]?Eh=ڊ2N$MF!5S[S)qIHZI_ڪ+M;7K1g ¬,  voAK8`,1緤=xCVs/$ 5= oBw>?B l" 'CW P Q!P@4CR،if' -刲S;b c_%'dU?3; /.l;mxk-6=QѸ%0C:m۲P:NJce?!aθ(;*Ͷӧq鮕U%VK AӤvCݨsH2/.R- AGGp XW\nWkÉ~,/IDȰ)v ϡ`.TӈGolJ1d)5/\h(sE잫#1gDD暱g.LΆp⵻FFOJ d˿dٶ(4"kn{^OF2w7$3FKB,֠|oa\*ٸ8K-U(ԞQ*]&.[#cx&+^ԏ:7*mxJIZdųΞS>>[0/R8nHАsƿ9D[~Mc䃅i8e= E?5kIѓ űbb!).uE>:b¶p^ VnlT|ʭDjFwT`EY,j@i laCEjj|%ZR XˏG gD) KHp.LI -u]ZnI.69룻^CYi9}u>gEUZ>"~YD0J;mpwG TuTi:kV QH6w'/UaT֗tDls 8tzbi,grPN~%AwkeB"!#5Q@ĉЎЗSvN3(GtG)0KЕbu 21sI;o l*/K5`˻s{͆(YF$ kv5払p<~i~;8$QAoYa00#b>?+DjØ&j{G[2N|mz?WeWf^{XU\KUEbQ:Q7z~%CNBfߙc6EjCUDsabE l{31чEmRVR7ӄ%yDDdrF)o .FPb:7G&fY nh{ʫ8OF*tvG`a(21ر61EaL꡻Vi0`E딯DU)dϫ[c/D 6[7 gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``@( 0((8o0 0 vEo TH H P^B hcnwpp{}ll  00 ` `h hp px x0 X xx x  H`H," 1PK|]˚bbx86_64-linux/strscan.sonuȯELF>@Z@8 @@A@A @M@M @M 8 XMXM XM 00888$$ A A A Std A A A Ptd777QtdRtd@M@M @M GNUqK#*_A,yDH8@`8;V`TdBE|qX$V{ !pM.[U bZ4B{?3Ep, F"hs 0-_`Q xQ `Q __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeruby_xmallocrb_check_typerb_num2intrb_int2inumrb_fix2intrb_eRangeErrorrb_raiserb_eArgErrorrb_string_valuerb_str_duprb_obj_freezeruby_re_copy_registersrb_obj_classnamerb_eTypeErrorrb_gc_markrb_scan_args__stack_chk_failruby_re_free_registersfreerb_data_object_allocrb_str_newrb_num2longre_mbctabrb_kcode_set_optionruby_re_searchrb_kcode_reset_optionruby_re_matchrb_warning__memcpy_chkrb_str_dumprb_str_new2rb_str_appendrb_class2name__snprintf_chkrb_cFalseClassrb_cFixnumrb_cNilClassrb_cTrueClassrb_cSymbolInit_strscanrb_internrb_cObjectrb_define_classrb_eStandardErrorrb_define_class_underrb_const_definedrb_const_setrb_define_alloc_funcrb_define_private_methodrb_define_singleton_methodrb_define_methodrb_aliaslibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.4GLIBC_2.2.5GLIBC_2.3.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64ii ui ti @M HM PPM PM O O O  O  O O O O O %O *O +O 1O 2O 3O 6P  P (P 0P 8P @P HP  PP  XP  `P hP pP xP P P P P P P P P P P P  P !P "P #P $P &Q 'Q (Q )Q , Q -(Q .0Q /8Q 0@Q 3HQ 4PQ 5XQ 7HH!= HtH5R= %S= hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(a%: D%: D%: D%: D%: D%: D%: D%: D%}: D%u: D%m: D%e: D%]: D%U: D%M: D%E: D%=: D%5: D%-: D%%: D%: D%: D% : D%: D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%9 D%}9 DH=y9 Hr9 H9tH7 Ht H=I9 H5B9 H)HHH?HHtH7 HtfD=9 u+UH=7 Ht H=4 )d8 ]wHSG Ht%HG0HS(C$HS+S[D((HC(xC HC0ff.UH"SHHVH[ H{tjHu3~HSHRHx3H9|3HCHH[]f.KHSHRHyHyH6 H5;H81HB6 H5H81fSHHHt$"H|$H[ H|$-HCHH#HD$HCH[f.ATUHSH"HHtwurtm?"ucHH9CuV"HLe Hs I9t0HI|$ H I$HFID$HFID$HFID$H[]A\@H0H5HH4 H81DHAVI"AUAHATUSHH dH%(HD$1Hl$UHLD$LHD1Lc eHHD$ID$HL$dH3 %(uH H[]A\A]A^^ff.SHH H[fDSH8fHH HHH H@0H@@@ [1HuHt H%H DLGIHH9|NSHHHH9HNHH)I@H:uHtHHsHD$HD$H[fff.@UHSH"HHm H}tpEtJtXHHcU$Hx4H9~4HU(Hc t'HU0HuHHcH[]HH"fHyH[]HHH2 H5mH81SS"H.H[ HsHtHHSH~HHH9}aHNH5.2  H6 HSHL H9HOHHHHKHS0HK(HHC[HcHc1HHO[H2 H5H81fSHHHHOH9|BLHH)L9HLHwHHVuHtHHsHD$HD$H[ff.AVAAUAATEUHSHHH߾"H[ HCHH#HKH9HHHCHsLC H}P)HpEuUM1AhQxDHsHC0H HsHcEtHHCHDEu*[]A\A]A^Ð1D[]A\A]A^fH[]A\A]A^Hq0 H5"H81H=1 H5P1HHE1f.E11ff.fE111pE11ɺ]ff.fE1:f.HAHA1f.A11ff.fA1ɺf.AUHSH"HvHm HEHt7HuH@HHH9}@H<HH)H9HHLH[]DHHuHHEH@H9|1H=uHtHHuHD$aHD$H[]H6. H5H81ff.fU1HSHH=HHHH[]SHH_dH%(H$1H9~|H)HwHOIHL ILH>HvH$dH3%(uAH[f.I$FD$...D$먐H=d-ff.fPXH5HH- H81fS"HHS HBHtHJHPH9}H)HD[ff.@S1HH=ZH[@S"HHH[ HCHtRHsHPH9}HH[f1H=uHtHHsHD$EHD$H[DS"HH{ HGHt'tHPHG0[Hc0HwfD[@S"HNH{ Ht"tHG(1[HcHW[\ff.S"HH{ Ht*tHW0HO(HG[HcHc1HHp[@S"HHC Hxt H[HS"H~HS HBHtH@H9B[HS"H>HS HBHtH@H9B[HXS1HH=H[@S"HHC HPHt-HHH;JHtHB| H[ff.S"H~HS HztH t,HBHH HBH[H) H5i H81OH= + H5Y1:f.S"HHC Hxt H@[HD3S"HHC H@Ht[ fS"HHS HBHtH@H"HBH[f.S1HH= H[@S"HNHS HztHHBH"[mff.fS"HHC Hxt*tHP0H@([:+8Hcf[@S1HH=O H[@S"HH[ HKHtWHHSHHH;Q}#<%s fin>#<%s %ld/%ld @ %s>#<%s %ld/%ld %s @ %s>ScanErrorStringScanner0.7.0VersionIdinitializeinitialize_copymust_C_versionresetterminateclearstringstring=concat<<pospos=pointerpointer=skipmatch?checkscan_fullscan_untilskip_untilexist?check_untilsearch_fullgetchget_bytegetbytepeekpeepunscanbeginning_of_line?bol?eos?empty?rest?matched?matchedmatched_sizematchedsize[]pre_matchpost_matchrestrest_sizerestsizeinspect;7h 4(P|8$@\8pXt8X(<tHh@8dH<xXt8x$hHdH zRx $FJ w?:*3$"DX\pUAi F (EIG w DAO TVEG HA,FAD  ABE $ @ FJH A(A0GP` 0D(A BBBA `|EP|OEE aSJ AC4 EDL L AAM I FAH E{ X F A , bAL SA`Lp-BEE D(I0 (A BBBB Q (F BBBC D (A BBBE <&Xd`lx)(<Pd4xEDL0G AAJ P AAA $l/EFN IGA tAGl AK AAKAEv A 4HEU(PL{EL d DG t AA |LEi R F A DEd O F A LEj Q F A $-E\ G 88Eg G  \8Eg G <EUXREG A xfEs A -E] F ,'E\ A @6Ek A dEUh3Eh A LEf U F A DEU `|EZ Q F A EU(NEAG0v DAA t@bFGB B(A0A8QKGBII 8A0A(B BBBJ VIOLI(D8_EHD  COL GNUPPM N]mx  3@M HM o`8  P   o ooD oXM  0@P`p 0@P`p 0@GA$3a13 GA$3p10673GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONSstrscan.so-1.8.7-16.el8.x86_64.debugGr7zXZִF!t//}]?Eh=ڊ2Nz\#%#%^%ف"q1DžnjmAޫuX0 8OmlR!KgV#U9d0!ރa0776: dj 4IĊ6Xzn 0s amDr UFizUoY$+ =۸ 6zZ^"ol-a^DڴQ X(q@o~(s0?8!mDeJ A+݌C?zzZz֋{BLYU+ĶWk ;UB˝oV3g*UhXB1)4 `:g5 gDEL$[?cW]m؁H0R:'9s=>hRd2%.k]wHyRsWEc/3gۃ󜱘9h"K G%G>CvBtvoo4Mg}; Sf6q%6;*Hs17rm;0^H=>lpIHӌ{J\|}OQ`=tF:iJ+DZ$}Msb,g}"Q*hI2քW B_10:]`"~4[kǷVܠҐ?o-҂J9BhY5N&)dF^rux\Q[S+25mNvH *cH4f_k#5SK9;oITe”z.XFP~o@ygLmq6cfIDcFMGH/ctfWSݧ3SF56D~"pBC"} NeOI"JDS9g@?K/+f[#vwQ -˫H1U=/>lƇ_d)M-Y>rM PЁO7^L Zq"ۣEj ls`$D"OLsECq|%?+|Fm $Bf; $TD ,C 2#qgYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 088 8oD D xEo @T ^BhcnPPw}33 233G7799p A A @M @MHM HMPM PMXM XM0O OxP P``Q `QxQ``QH S,SY+PK|]ʈxxx86_64-linux/env.hnu[/********************************************************************** env.h - $Author: knu $ $Date: 2007-03-03 16:28:54 +0900 (Sat, 03 Mar 2007) $ created at: Mon Jul 11 11:53:03 JST 1994 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef ENV_H #define ENV_H extern struct FRAME { VALUE self; int argc; ID last_func; ID orig_func; VALUE last_class; struct FRAME *prev; struct FRAME *tmp; struct RNode *node; int iter; int flags; unsigned long uniq; } *ruby_frame; void rb_gc_mark_frame _((struct FRAME *)); #define FRAME_DMETH 1 #define FRAME_FUNC 2 extern struct SCOPE { struct RBasic super; ID *local_tbl; VALUE *local_vars; int flags; } *ruby_scope; #define SCOPE_ALLOCA 0 #define SCOPE_MALLOC 1 #define SCOPE_NOSTACK 2 #define SCOPE_DONT_RECYCLE 4 #define SCOPE_CLONE 8 extern int ruby_in_eval; extern VALUE ruby_class; struct RVarmap { struct RBasic super; ID id; VALUE val; struct RVarmap *next; }; extern struct RVarmap *ruby_dyna_vars; #endif /* ENV_H */ PK|]kBQQx86_64-linux/thread.sonuȯELF>@XJ@8 @h:h: 8=8= 8=   P=P= P= 00888$$H:H:H: StdH:H:H: Ptd000QtdRtd8=8= 8= GNUWSAa +j)2@ @24BE|qXO+?M Uh2%ScC zxy4^(, VF"@0A SXA G0A m )X__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_thread_criticalrb_thread_currentrb_check_typerb_thread_alive_prb_ensurerb_yieldruby_xmallocrb_thread_joinrb_thread_wakeup_aliverb_thread_set_joinrb_thread_schedulerb_thread_stoprb_marshal_loadrb_ary_shiftrb_num2ulongrb_eTypeErrorrb_raiserb_eArgErrorrb_data_object_allocrb_gc_markrb_internrb_funcallrb_str_new2rb_eThreadErrorrb_iteraterb_cFixnumrb_cFalseClassrb_cNilClassrb_cTrueClassrb_cSymbol__stack_chk_failrb_uint2inumrb_ary_newrb_ary_pushrb_ary_unshiftrb_marshal_dumpruby_xfreerb_thread_killInit_threadrb_cThreadrb_define_singleton_methodrb_cObjectrb_define_classrb_define_alloc_funcrb_define_methodrb_aliaslibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib646ui Xii d8= 0@= H= H= ? ? ? ? ? ? ? ? ? ? "? %? +? ,? .? /? 0@  @ (@ 0@  8@  @@  H@  P@  X@ `@ h@ p@ x@ @ @ @ @ @ @ @ @ @ @ @  @ !@ #@ $@ &@ 'A (A )A *A - A /(A 1HH. HtH5. %. hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"%, D%, D%, D%, D%, D%, D%, D%, D%}, D%u, D%m, D%e, D%], D%U, D%M, D%E, D%=, D%5, D%-, D%%, D%, D%, D% , D%, D%+ D%+ D%+ D%+ D%+ D%+ D%+ D%+ D%+ D%+ D%+ DH=+ H+ H9tH) Ht H=y+ H5r+ H)HHH?HHtH) HtfD=5+ u+UH=) Ht H=6' Id + ]wHU) 8ff.ffDSHH HtH;uZ@H;tHHQHu[HqHBHHkHztHCHBHS[fDHKHH1S"HnH[ H;Ht HuOH[D1[ff.S"HHC H8Hu1[f.+H¸Hu1f.ATUSHH-' H;IEHuL#E[]A\HtHKHHH=Af.f.S"HNH{ eH[He' H=n' HHc@HHHH=hsS"HH{ H=' H[HS 9fSHHHGHtGHPHWHSH0H@HtHBHCHCH[HHCHCH[fDHt$9Ht$fATUSH0H{HIqH;H-G& D;Ht/H;L9t*>EJH;EHuL#[]A\f.HHtJSH+fHCHkH:HBHS'HHtHuHBHH9SuHC[øH?tSHfHH;u[fUSHH^HHt!HHtDH;HH[HuHH[]f.S"HH$ Hs HH=UHc'RH[ff.fSHHHS[ff.AUATIUSH"HBHIl$ uHtuHèun<tj? u`H{~qHHhEHHE HCH[ t!LlDH3HH!I9uHL[]A\A]fDH# H5bH81H$ H5gH81hSH^HH HHHH@H@H@H@ H@(H@0H@8H@@H@HH@PH@XH@`H@hH@pH@xHǀHǀ[off.@SH HH HHHH@H@H@[DSH(>HH HmHHH@H@H@H@ [ff.fSHHtH;H[Hu[ff.fSHH?H[HtH;H[Hu[ff.fUHSHH](HtDH;H[HuH]HHtfDH;hH[HuH]hHtfDH;HH[HuH[]SHH6HH=gHoH=HH{1H1#[ff.SHH=|H1[H1ff.H=M USHHH/kH9uH{-HH[]H H5BH81ff.SH)H[@USHHH-0 EH9u-HgHuH[]HH[]RH+ H5EH81ATUHSH"H dH%(HD$1tLe HHHHCH9! tDHHL$$HH=\H\$HT$dH3%(HH []A\f"HH[ HHLHZH=>@H  HlfH HTH HDH H4H H$lff.HHt Hh t HDHD$HD$H@HH5 HHH=tHcfHHt Hff.U"SHHH[ HHHHvHH[]ff.WATI"UHSHCH[ I$HHH;HChHuHusHk(L%Hu1DHHLHH=P[HH{htHH[]HMH=A\/HHChHH H5 H81ZH H5 H81@U"SHHIH[ H]H{`H{@`HHHH[]ff.U"SHHH[ H HHHHH[]ff.U"SHHHk 1HHHxHHH[]ff.S"H^H{ EHHDH[ÐHHe HHH=HcHuHfHH@HHfHWhHtsHBHGhH;Wpt5HOxHHHJHWxHHt H;wHGpfDHHHHD$HD$H@fU"HSH)H] H=HCpHt+HShHKxHHHSxHChHCpHǃH{HHHH[]ff.S"HH{ eH[S"HH Hs HLH=EHcHt HHH[f.AUIATUSH"H"HMe 6HtiLH&I$H9sHu$I$LHL[]A\A]fDHI$Il$HH)DHpHuH H5H81pAT"USH{Lc I\$hHHtDH3HH[HuI$oHH[H]A\UHSHHtfH_wHHuH}HtfDH_WHHuH[]UHSHH_Htf.H;(H[HuH]HHtfDH;H[HuH](HtfDH;H[HuH}Hu2H}(Hu8%H}HHuXH}hHux HH[]ff.fUHSHHHtH;pH[HuH]HHuHH[]9fUHSHH_Htf.H;H[HuH]HHu_HH[]AVI"AUIATUSTI] HhHHtVH;wMHkHL%(fDH;w1HHLHH=ozHHHuH{hL*Hs(HH\H=@[L]A\A]A^@H S1H[H5H8H H=H3vH5HHE 0H=9 H=H5H= 1HH5qH= 1HH5biH= 1HyH5NMH= 1H}H561H= 1HQH5H= 1HH5H=r 1HH5H3H=nH5HH5 (H=) H5H5xH=  1HH5i}H= HjH5^H= 1HH5oBH= 1HH5]&H3H=H50HHv qH=j H.H5H=K 1HH5H=/ 1HH5H= 1HzH5H= 1HH5rH= 1HH5VH= HH57H= HTH5zH=n|H=gHmH=f HHKH=AOH=>H@H=9 HHH="H=HH=  HHH=H=HH= HHH=H=HH= HHH5 H=HxH5HHo H=c 1H2H58H=G HH5%H=( HH5 H=  1HxH5H= HH5mH=H=HH= HHH=H=HH= HHsH=ewH=iHhH=Y HHFH=8JH=@H;H=, H[HHHexpected Array of queue datamissing capacity valueexclusive_unlocknot ownerqueue emptyvalue must be positiveexclusiveMutexmarshal_loadmarshal_dumplocked?try_locksynchronizeConditionVariablewaitbroadcastsignalclearempty?lengthnum_waitingpoppushenq<<deqshiftsizeSizedQueueinitializemaxmax=not owner of the synchronization mutexwrong number of arguments (%d for 1)ꌠ9Y>)F;9P0DX0|@Pp(<XpP ,PH0P 8T p0`8Xp@PP,@Tpppp  \ @( d zRx $X@FJ w?:*3$"Dp0\HpT PEr I i G DEu F CFE` K (fBAA u ABD T$P EZ@T,Tph|7Ea(nAG v AA P AG (vFAA eFB8XIHA|.KYD$FEAG sDA<CE}X$E^8tFBD A(L0 (D ABBG EXKEASEI#E] 3Em$<xEDD hAAd`DE~$EU(EEAG ] AAA EV4mAAG l AAI D DAE 00DFAD L@  AABC d <D ^ F S@BD}$xDEFG lDA ,FIF  APL $lEEFG mDA$0DEFG lDA$XEEFG mDA/EiLDr J G(HN0d W$rEID ZDA EZ0VEP8LHFEA A(L0G (D ABBG (mFFA PIB$HADD |AA$(EDD DA$GEDD pDA$,OEDD xDA8TFJE A(A0(D BBBXLDGNU0H= ,6n  /8= @= o`  @ H   o ooD oP= 0@P`p 0@P`p 0@GA$3a1%/ GA$3p1067@/GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY@SGA+GLIBCXX_ASSERTIONSthread.so-1.8.7-16.el8.x86_64.debug 7zXZִF!t/_K]?Eh=ڊ2N~ uehU𽢶MPPhI,u%=*s .AoEݹ[Rɜb[P$+چi]hii]("^O--JU_|(I꾉YYs>fEdn_ZiZ~BI+LFE`ߴ=ht}a*'~QPV=A ?,=Ԥi|Yqyo8k,|(ܞcbQg}$4VHkhw߬Q5srb% +#:bo(zu)m'8N>E-Y'6vm ϼ縦WH? ShʯM>6 G0 H,ߎ}E gu3ezSV @xcxEuL%#VuIqB7f#=;EY!Ц)\6;ue:UM<'uOIwA" qz^2od Hy}V}۔t{y wvT$Σ1xFE^"U@ D. N|M,e~ L( $T=!mu{Fg]ns]1Y_Bm.H{kbo?vQi*+|JYLt;4A]WU ڟ!3mڎ$ X/1|pfyp=k6oN 6Pγc^Լ<=)5 lOj;'[I1;91׉r5fE9yO`cۭ9Gaa?APs <- @X9@8 @)) p-p- p- 0 -- - 00888$$))) Std))) Ptd$$$QtdRtdp-p- p- GNUBdoH11HHYHH5jH[]A\fATUSHH9tJHHHxH"IHm "HH{ IT$HH[]A\ff.H9= ATUSt7HHxIkHHAT$ HH1H  []A\H H52H81`ATUSH dH%(HD$1~nHIԉH|$HHD$L^HUsHD$H|$(HL$H|$1H5 KHL$dH3 %(u!H []A\H  H5H81DUSHHsHdH%(HD$1H~pH5A 1H1H $1H5 HH5 1H1H5 1HH1HHL$dH3 %(uH[]HHNff.HH11dH%(HD$1HH$0H$HxHL$dH3 %(uHfUHSHHH(H5V dH%(HD$1Ht{H5 1H1H\$HD$H|$H|$Ht$H|$HFH9Gt1HL$dH3 %(uKH([]DsuٸH11$H11HD$HD${@HH=ILH=JHV 9H=0H; &H=^H  H=HH H=?H H=:H HH5"HH xH= H5H9H5HH H= HH5H= 1HH5KH=q 1HH5)H=U 1H|H5[H=9 1H@H5H= HH5KeH= 1HeH52IH= 1HyH5-H= H*H5H= 1HH5H= H/H5H=l 1HH5H=P 1HH5H=4 1HKH5H= 1H/H5hcH4 H= H5SHH5 HH H= H}H5!H= HH5H=VHw H= H5H" H5HHD H=8 H,H5H= 1HH5tH= H!H5UH= HH56H= 1HH5H= 1HH5H= 1HH5BHHH%s does not implement %s()block_lengthresetfinishupdatedigest string too long01#<: >no data givenhexdigestdigest_lengthDigesthexencodeInstance<<==inspectnewhexdigest!to_ssizeClassmetadataBaseinitialize_copyIncompatible digest API versionDigest::Base cannot be directly inherited in RubyDigest::Base is an abstract class0123456789abcdef;@X l@0P8pTt0``(Th@P@,XPpPzRx $p`FJ w?:*3$"DP\p$=EEG fDA%E_7ADG EAKEAK  EAK<EAKXAU J x"HU"HU$;EAG hDA(RFAD CAB,^FAA G0G DAB(,0AAD0z AAA X l*HZ$AEEG fDA(EAN0 AAD (t~FAD oAB(bFAA VAB(0 `MAA q ABE 0\@FAA D@}  AABA (EAN0 AAA PWH I A (EDJ@} AAF HHGNU`-  c  #p- x- o`H  0 x    o@ oo o- P`p 0@P`p 0@P`pGA$3a1!# GA$3p1067#GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONSdigest.so-1.8.7-16.el8.x86_64.debug7'27zXZִF!t/W9]?Eh=ڊ2N :'dPW؀^Mme3r7NT?\5>\yv@=]ڽ!]8uv˘ ٭JЩ7%ZOu!Dѽ ([,(ۻ"7tFF5xIA=D"{>+ 'gZAcg^'IoSc}82 ݂SqQ;)[֋/cۍZ{[PJtd/WSfуC{ruR)ޅ+2},9q-wޤrK5 nb%bAmxat/40v_B_~ȏdy8<Yާ#5x$&J[Ld!-ު~;0+<޴9E ߂0WO`VɼN2iRP~ZlgiPW5Tf H-r]Ds Hqѥ%gakٰ "PJa~NF_=&pPV9]CEOw@`G.F=U}$oJb,Bw[/R HeKK_6R3O,)8Ry3,z4J(*d~mJ5Ċ֖02þQcaeV_UiXrU8!N( `P 'gA>_-+ŷܦ͍gI zFAFpt|\e1ҏE{tfI9W" iiA*3C>`ƟEUy̷(eFڟltX-ZOŸ*j|\:2;,fnM? c,:LeM;)"In~#28߬R_ i.^V;6ez);Bޘq?iV`)CNMOT7dm"Ȓ猷CTiZ+uVYq &ngYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 0HH8o dEo@ @ @T ^B xhc@@`nPw"}## 0#0#$$%% )) p- p-x- x-- -- -0/ /H0 0@@1 @1`1`@1H 3(3|,8+PK|]Xx86_64-linux/socket.sonuȯELF>0@@8 @@@ ؼؼ ؼ X  00888$$ Std PtdHHHQtdRtdؼؼ ؼ ((GNUynݏZT[k -NtX-p tx}BEvjdu|ޛm ? @ A B C D E F G H I J( K0 M8 N@ OH PP QX R` Sh Up Wx X Y Z [ \ ] ^ _ ` a b c d e i l m n o p q r( sHHi HtH5қ %ӛ hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahb% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݔ D%Ք D%͔ D%Ŕ D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݓ D%Փ D%͓ D%œ D% D% D% D% D% D% D% D% D%} D%u D%m D%e D%] D%U D%M D%E D%= D%5 D%- D%% D% D% D% D% D% D% D% D% D%ݒ D%Ւ D%͒ D%Œ D% D% D% D% D% D% D% DH= H H9tHn Ht H=Y H5R H)HHH?HHtH͎ HtfD= u+UH=ʎ Ht H= d ]w 1Hff.HIf? jLDE1E1VZYuHÉH= H5`H1 ff.SHdH%(H$1HHuHH$dH3 %(u H[ff.1ftf u#HOH:RH= H5_1AUSHH|$Ht$'f8Hl$HUHnHXHH9r^HaH9u HnHmaHu'HtHT$uHt HH H[]HnuHHUHHnH9uH H5iH81jH nH5iH81MHN H5_H815H떉HGH`SHH9HCH H=^HH[HDUSHH|$Ht$HfuXH1HŨu%HtHD$uHt H%H E{frHHH[]Hq H5hH81XAVIAUIATUHSHHHuUAHHHtLHtHU H=^HAE[]A\A]A^Ð;fH߃[]AEA\A]A^fIHIT$H=e]HH=?]HH=1]HtJH=]HH= ]HAfA@'fD H=\Ht> H=\Hu1H H[SHHVH`dH%(HD$X1HLD$H\$tvHD$H$Ht$HD$ H8HHH=4>HD$(HD$0HD$8HD$@HD$HFH\$XdH3%(uH`[H$HD$HD${ff.SHH VHpdH%(HD$h1HHHD$ P1LL$ LD$HD$Ht$0H\$0HD$HHH=m=HD$8HD$HD$`HD$@HD$ HD$PHD$(HD$XHHD$hXZHdH\$hdH3%(uHp[fSHdH%(H$1HTHx,HƄ$SH$dH3%(uH[H=Tk&fDATAUHSHtH}HE0DH5SHEHHH@H@@H@ H@(KDH5oTH9CHHCH[]A\ff.ATUHHSHH dH%(HD$1HL$ Ht$H߃Ld$t$ |$Lxn\$HHlj1Dd$HHDH1HH^HT$dH3%(u_H []A\D[{@vH=ZSDt$ |$LISZf.UHHSSH(dH%(HD$1HL$LD$u'HD$HD$fHT$~HL$H1bH|$dH3<%(uH([]fDUHHSHt;HH{HH1^HHsHxHH[] HfDAWAVAUA@ATAUSHHHQH8dH%(H$(1HL$LD$D$ H|$Ht@PCAA@H|$@P(IHHhHH}xJH}L1AHHHHl$ 2HsIDLL$ LDHH9CiHqAtuEt$At$ HHHHH$(dH3%(HH8[]A\A]A^A_fDHSHCHAuD$ tHHH4HCH|$AA@@(IH=Z1H=UPH/| H5)PH81.9fHHHH1HHff.AWAVAUATUSHHHJOHhL$,LD$HHL$@dH%(H$X1D$<H|$HD$Ht@D$H|$@@HD$H;HXHH;NH;7Ht$1AHH-yz IHD$PHD$HD$H/HhHsH}:މxH[]ÐH=(B+ff.ATUHHASHdH%(H$1HLD$5u!HBm HH$HD$ ~HH$kL`LI<$vH1HHc~E1H{ ?)ѺH1H Ā1I<$Hl$0H$HD$`HD$`HD$ HHD$D$HD$hHD$(HD$8D$@HDŽ$H$DŽ$1Ht$|H=HT$8HH$H$$Hc$H<$H\Ht6H5[o HtNHD$HL$PH\$PHHD$XEWHH$dH34%(Hu*H[]A\fH=@H<$HHn H=n 1H5(JsH=n H5I1YH=n H5vI1?H=n H5I1%H=p?ifUSHdH%(H$1D$ nHl$HXH2H;HT$ HKx)t$ H{H$dH3 %(uHĘ[]H=>ff.fUSHdH%(H$1D$ Hl$NHXHH;ZHT$ Hx%HH$dH3 %(uHĨ[]H=O>6USH(dH%(H$1D$ Hl$HXHH;HT$ Hx)t$ H[H$dH3 %(uH([]H==]ff.fUSHdH%(H$1D$ nHl$HXHbH;*HT$ H[x)t$ HH$dH3 %(uHĘ[]H=*=ff.fUSHdH%(H$1HXHH{ Ht&qH$dH3 %(u]HĘ[]@H;D$ nHl$[HT$ Hx,D$ H}HH<H9HCJHHC 15DUSHdH%(H$1D$ Hl$HXHH;HT$ Hx%HH$dH3 %(uHĨ[]H=;aUSH(dH%(H$1D$ Hl$.HXHrH;:HT$ Hkx)t$ HH$dH3 %(uH([]H=:;ff.fAVAUATIUHSHH HL$dH%(HD$1hH߃HH|$@HHHtH@? utD$ALl$LL`LEI<$ ELމ HT$dH3%(H []A\A]A^D!t# tgH|$DHD$LhDpyfD$ALl$_ HH|$@ALl$D$I|$ Tff.@AWAVIAUAATIUSH8dH%(HD$(1H\$Hl$ILD$ HH!9LD12HJH|$tH:LHXHH{HAH-c L=7ff.@UHAVAUIHATISHdH%(HE1LAAHEH9tHH$H9uHH$LLt$IHxbL LhLNI}LELDމxOuLHMdH3 %(u>He[A\A]A^][LA4GA/I} UHSHdH%(HD$1H` 8~#HHHH51H<$Htq@u[ÃHHhH?H}މtOHT$dH3%(uAH[]@H_ H5s?H81y1}Hn` H5o?H81UDUHSHcHH\HHH_ H8H=c HHH[]rfUHSHHHdH%(H$1H_ H0HH.HHhHfH$Ƅ$HD$@HD$@HD$HD$PD$dD$tH}HD$ HH$D$HD$HHD$HD$(D$0HD$PHD$X\$`F1H:HtLH$dH3 %(u/HĘ[]fHHXH,H;H=A3H] H5=H81@ATUSHHt$H\$HkH{HdH%(H$1H)HD$lHCfHH|$fD$HI HkwsLHk'nHu.Ht&HT$uHtHH H$dH3%(u HĐ[]A\H] kH5<H81AUH2ATU1SHdH%(H$x1Ld$Ll$HD$0HD$(MMH\$HD$ HHHD$ HD$HD$HD$8PHD$8PHD$8P1H H|$t%HHl$pHHƄ$oLL$1It5AI1H$pL 1H5H|$f)D$@)D$P)D$`Ht_@LEHtHH=/H€Hƹ H=/uD$D H|$ Ht@#D$HH|$(Ht@D$LH|$0Ht@bD$@HL$8HT$@HHH\$8H4NIH{HcsHHHt6HcsHHt6zHcs HHt6iHL^H[(HuH|$8LH$xdH3 %(HĈ[]A\A]K4fD;fD+fDD$DfLH$pHHƄ$oD$DkH=] H5.H1DOH=] H5-1*f.AWAVAUATUSHH $HH-E1dH%(H$1HL$LD$0HD$HD$ HD$(HD$8HD$0HD$=H|$0Ht@AH|$&HHHPHD$HLD$pHpLf|$p IHCGHULǾL$AL$HMAUL ^_vH|$8HH_(HL$ H$H{HMAf? DHAUZY HLLLH[(HuH|$8LDLH9HHH$dH3 %(H[]A\A]A^A_DAcHLǾH|$RHfHD$)D$@)D$P)D$`HPHsH@ HHT$HPHT$(HPHT$ HD$@H|$ H$JHHZƄ$LL$(IWAI1H$L+H1AH|$D$HH@0D$DHL$8HT$@HHHD$8Hxf? EhH@ HHT$HPHT$(H@HD$ 1H$H|$(H$?HHOƄ$4D$DYH|$ HFH=(H€uPD$DH@HD$ jA01fD$H|$8,H= Y H5v51Hƹ H=)D$D H|$8Ht D$ D$ H=X H5'H16HoT H5)H81)HU H54H81H|$8Ht D$ nD$ CH=DX H5w)H1˿HT H5=4H81賿HS H5o)H81蛿ff.AUAATAUSHÅxH[]A\A]fDkwHDD[]A\A]DAUIATIUHSHHdH%(HD$1H1HL$HLH߃tGJt$<$H19x9L1HT$dH3%(uH[]A\A]fDS蜿H=i(ATIUSHHdH%(HD$1BHLH'1ܾt:11xIH1H\$dH3%(u9H[]A\H<$@tYD蛾H='־fDAWAVAUATAUHSHHt$Lt$LdH%(H$1DH|$11OHD$2Ll$01M}I}IEfLH)lHfL$0HD$HxkLlLHEuHT$Ht$ Ll$ H=\$(踿T$H1HHxH$dH3%(HHĸ[]A\A]A^A_nLxE߾ٿH1=HUHXH虿HD$Hx{HC {fI}`H=%THQ kH5<0H81۽|$bf111UHSHH P 8~@u_HtVHtMH臾HXH˾Ct%H{茾 cH[]HH[]HO H5"%H81f.AW1AVIAUA1ATUSHl߉A1VDLɿŅy%κINjjtd: u1Ņt=D߾1 H[]A\A]A^A_@rw҉1WŅuAA1DUSHHoHu9fH[(Ht'SHs1xH[]H1[]HHnH01HHff.SHHH|$Ht$UH|$˺HHD$莼HXHҼH;蚼HL$1HQHqDx H[H={"艾fH(1ҹdH%(HD$1Hf $HD$fP@ |$H1臿HD$dH3%(uH(ݹff.fUSHH|$H3HM HH0蹼HH|$FH|$HD$HhHtVEtN<<HFH=3HH߃1ҨuduPHH[]fDH11HH[]fH|$Hމ1HH[]fDDfDLf HtDUr@H1HHPfDH1[]H=w!H2 H=_!HH޿HHHL H53!H81ff.AVAUATUSHHoHdH%(H$1Lo蚸H} IH赸LHںH} HtQ,HHtD_H[IHt=H;Ht5sHLH蔺H;Huf.1ɺILLHhHc}LHT@E9CusH{ALH3H[(HuH$dH3%(Lu)H[]A\A]A^@HH1H趶fDAWAVAAUAATUHSHxdH%(H$h1Ht$`HD$Hl$IH@Hl$HH|$蝵HD$LxL HH\$@LHP H詷DHD fHL$HLD$HE$E,EDl$Dt$Åt>H-M MtL芵A| H5"HH1sH$hdH3%(HD$Hx[]A\A]A^A_fH\$@I 1I HLHl$гDHD |$@uE1H HHHD$OHD$Htˀ8uHAfH5(H1蟳DD uE11Hl$茴HHzH H5H81aAU11IATI1ULSHHxpHHH褸@uAHt8AuIt IE%H EAuIt I$%H EHH[]A\A]ff.@UH1ɺSHdH%(H$1HHPHpH"HH$1HHHXH$dH3 %(u HĘ[]6fDSHH dH%(HD$1H1AH2F HH$HH=HD$HT$HF cHL$dH3 %(uH [訲SHH dH%(HD$1ZH1HE HH$HH=IHD$HT$H@F ӲHL$dH3 %(uH [ATIUHSHH dH%(HD$11ɺLH1HH$HXHH;ͳH $HHE H=HD$/HtHL$dH3 %(uH []A\H=蠵[ff.AVAUATIUHSH1LH1mHHL`LVHtJHI<$DsLk DLxHD[]A\A]A^fDH[(HuHH=AW1IAVAUATUSH8_8HwdH%(HD$(1HD$$IIGt*I Iw(HuHt1ɺ1xMwIG0AG H=GHHE胫H}1H&H5ʬH}1H}H5豬H}HqH5蕬H}HH5艬HuH=IL%B= H=HI$I<$HH5CI<$HH5I4$H=L%< H=HI$荪I<$1H0H5ԫI<$1HWH5t軫I<$1H~H5k被I<$HH5<膫I<$HVH5=jHuH=4:H-; H=+HHEH}HH5$H}HDH5H}HH5H}HH5 ЪH}HH5贪H3H=腬H-; H=HHE+H}HH5%oH}1HH5yVH}1H9H5F=H}1HPH5$H}HH5wH}HH5H}HH;HH5#H;HH5H;HH5H;HH5bҦH;HH5E跦H;H8H5D蜦H;HH5$聦H;HRH5fH;H5 臧H= H: 1 1H=| 1H=t 1H=y 1H=W 1 H=\ 1H= 1H= 1H= u1H= b1H==OH= 1<1H=)1H=l 1H=1H= 11H= 11H= 1 H= 1 H= 1H={ 1H= 1H= q1H= ^1H= K1H= 8"H=z 1%1"H=m 1-H=b 1-H=V 1H=J 1H=> 1H=3 1H=) 1H=$ 1 H= z1H= g1H= T1@H= A1H= .11H= 1H= H= 111H= 1H= 1H= 1H= 1H= 1 H= 1H= v1H= c1H= P1H= =1H= *1H= 11H= 1H= H= 11H= 1H= 1H= 1H= 1H= 1H=~ o1H=v \1H=j I1H=^ 61H=W #1H=S 1 H=K 1!H=H 1"H=F 1#H=E $H=F 11H=D 1H=J 1H=Q x1H=Q e1H=G R1H=A ?1H=; ,1H=0 1H=& 1H= 1H= 1H= 1 H= 1 H= 1 H= H= 11 H= n1H= [1H= H1H= 51H= "1H= 1H= 1H= 1H= 1H=81H=M1H= 1H= 1H= w1H= dH= 1Q1H= >1H=} +1H=u 1H=q 1H=h 1H=b 1H=X 1H=P 1H=H 1H=@ 1H=8 1H=1 m1H=+ Z1H=# G1H= 4H= 1!H= 1 H= 1H= 1H= 1 H= 1H= 1H= 1H= 1H= 1vH= 1c1H= 1SH= 1@[]H= 1A\)HHgetnameinfo: %sunknown socket family:%dnot an AF_UNIX sockaddrAF_UNIXAF_INETPF_INETPF_UNIXPF_AX25PF_IPXunknown socket domain %sSOCK_STREAMSOCK_DGRAMSOCK_RAWSOCK_SEQPACKETSOCK_RDMSOCK_PACKETunknown socket type %sAF_UNSPECAF_INET6AF_LOCALunknown:%d11tcpno such service %s/%shost not found22gethostnamewsocketpair(2)02recvfrom for buffered IOrecvfrom(2)recv for buffered IOaccept(2)bind(2)connect(2)listen(2)recvmsg(2)for_fdgetpeername(2)getsockname(2)21send(2)01sendmsg(2)24%ldgetaddrinfo: %ssockaddr length too bigexpecting String or Arraysocket(2)socket(2) - udpInsecure: can't close sockethostname too long (%d)service name too long (%d)sendto(2)SocketErrorBasicSocketinitializedo_not_reverse_lookupdo_not_reverse_lookup=close_readclose_writeshutdownsetsockoptgetsockoptgetsocknamegetpeernamesendrecvrecv_nonblockIPSocketIPsocketpeeraddrrecvfromgetaddressTCPSocketTCPsocketgethostbynameTCPServerTCPserveraccept_nonblocksysacceptlistenUDPSocketUDPsocketconnectbindrecvfrom_nonblockUNIXSocketUNIXsocketpathsend_iorecv_iosocketpairUNIXServerUNIXserverconnect_nonblockgethostbyaddrgetservbynamegetaddrinfogetnameinfounpack_sockaddr_inunpack_sockaddr_unConstantsAF_AX25AF_IPXAF_APPLETALKPF_APPLETALKPF_UNSPECPF_INET6PF_LOCALAF_SNAPF_SNAAF_ROUTEPF_ROUTEAF_ISDNPF_ISDNAF_MAXPF_MAXPF_KEYMSG_OOBMSG_PEEKMSG_DONTROUTEMSG_EORMSG_TRUNCMSG_CTRUNCMSG_WAITALLMSG_DONTWAITSOL_SOCKETSOL_IPSOL_TCPSOL_UDPIPPROTO_IPIPPROTO_ICMPIPPROTO_IGMPIPPROTO_TCPIPPROTO_EGPIPPROTO_PUPIPPROTO_UDPIPPROTO_IDPIPPROTO_TPIPPROTO_RAWIPPORT_RESERVEDIPPORT_USERRESERVEDINADDR_ANYINADDR_BROADCASTINADDR_LOOPBACKINADDR_UNSPEC_GROUPINADDR_ALLHOSTS_GROUPINADDR_MAX_LOCAL_GROUPINADDR_NONEIP_OPTIONSIP_HDRINCLIP_TOSIP_TTLIP_RECVOPTSIP_RECVRETOPTSIP_RETOPTSIP_MULTICAST_IFIP_MULTICAST_TTLIP_MULTICAST_LOOPIP_ADD_MEMBERSHIPIP_DROP_MEMBERSHIPIP_DEFAULT_MULTICAST_TTLIP_DEFAULT_MULTICAST_LOOPIP_MAX_MEMBERSHIPSSO_DEBUGSO_REUSEADDRSO_REUSEPORTSO_TYPESO_ERRORSO_DONTROUTESO_BROADCASTSO_SNDBUFSO_RCVBUFSO_KEEPALIVESO_OOBINLINESO_NO_CHECKSO_PRIORITYSO_LINGERSO_PASSCREDSO_PEERCREDSO_RCVLOWATSO_SNDLOWATSO_RCVTIMEOSO_SNDTIMEOSO_ACCEPTCONNSO_SECURITY_AUTHENTICATIONSO_BINDTODEVICESO_ATTACH_FILTERSO_DETACH_FILTERSO_PEERNAMESO_TIMESTAMPTCP_NODELAYTCP_MAXSEGEAI_ADDRFAMILYEAI_AGAINEAI_BADFLAGSEAI_FAILEAI_FAMILYEAI_MEMORYEAI_NODATAEAI_NONAMEEAI_SERVICEEAI_SOCKTYPEEAI_SYSTEMAI_PASSIVEAI_CANONNAMEAI_NUMERICHOSTAI_ALLAI_ADDRCONFIGAI_V4MAPPEDNI_MAXHOSTNI_MAXSERVNI_NOFQDNNI_NUMERICHOSTNI_NAMEREQDNI_NUMERICSERVNI_DGRAMSHUT_RDSHUT_WRSHUT_RDWRtoo long sockaddr_un - %ld longer than %dsockaddr_un.sun_path not NUL terminatednot an AF_INET/AF_INET6 sockaddrs_recvfrom_nonblock called with bad valuefile descriptor was not passed (msg_controllen=%d, %d expected)file descriptor was not passed (cmsg_len=%d, %d expected)file descriptor was not passed (cmsg_level=%d, %d expected)file descriptor was not passed (cmsg_type=%d, %d expected)Insecure: can't shutdown socket`how' should be either 0, 1, 2neither IO nor file descriptortoo long unix socket path (max: %dbytes)sockaddr size differs - should not happenarray size should be 3 or 4, %ld givensockaddr resolved to multiple nodenamenewline at the end of hostnameSO_SECURITY_ENCRYPTION_TRANSPORTSO_SECURITY_ENCRYPTION_NETWORK;Y(08DhXhH( 8\hx88 XTXx$أ88Xx<h88 8$ ج` x x  < H ȱ  (4 ` X H < ( H$ L |  xxh4X0d|h T8x,PXXlzRx $@FJ w?:*3$"D0\ pTDN YAH A (TAL@ AA d`Ow(EAD0 AAH  ;Ne((EAD0s AAA `TBEE A(D0f (A BBBB b (A FBBC ) (A JBBH dBBB A(A0JBFAe 0A(A BBBD cHFA( EHD@ AAI 8LFIA A(DP" (A ABBC Ԗ)Ec ENp AA 0ENWFoA` AA 0zELV AA ( BDD AB0LFAG G@  AABF (EKF@| AAA (pZEGD z DAA LBBB H(D0A8V6 8A0A(B BBBG (t<PLdBBB B(A0A8V  8A0A(B BBBD ht`wBBB E(A0C8D` 8A0D(D BBBE ^ 8D0A(B BBBE (hEAG AAA ((EAG AAA vEGc AA ~EGk AA TvEGc AA ,~EGk AA 8P BED I(G0_ (F CBBE (pEAG AAA uEGb AA @uEGb AA 0rFAA G0M  FABA 04FAA G0d  CFBA HhDgBBB E(D0F8L 8A0A(B BBBA hGEA(uEIG B FAB 4FAK I  AABC (4xEAGr AAA (`EAGn AAA (PEAGr AAA (ĪEAGr AAA (8EAGL AAE ( ̫EAGn AAA (< 0EAGr AAA @h FBB I(D0GP 0A(A BBBF H AFBE J(D0A8Dp 8A0A(B BBBB ( $/EC DHH H ($ (EDD0 AAE $P >ADR ZGA,x 4|EDM AAC 0 FAA G  AABA P `VFIA C(GGdFFK (A ABBD p0 lFBB B(A0A8G L""E"I"A"d"B"F"A"} 8A0A(B BBBF H [BED C(D0O (C ABBG X(G CBB8 FEI D(G@l (A ABBG 0, FDH G0g  AABD L` BBB B(D0D8G# 8A0A(B BBBD  < 8 4 4EDD [ FAA D DAE H BDJ G(A0A8F@h 8C0A(B BBBE 0\ YEAD w FAH DCA L$KV dwEG X FA  cD0Y A L AAD0 AAG P DAC \ DAG d CAH D8JFBB A(A0G 0A(A BBBE L?BBE E(A0D8G 9 8A0A(B BBBC 4FIF D(D0j(D ABB(EKL v AAA 4hEL0p AA XEL0p AA 0|@FDD L@  AABA <FBB D(D0k (F BBBG H޲L|`(4zEq WsfďGG)z¶$ V7Jx$XSvoG,rhBW)ZSN9h/ Vc)O`F2S{oF@OM0VI#Ǭ65~;b^_c .h"ɵ39!+Zn`u7~ eykL\Oo!)H5ʌ|\83VC{WDK1oRiX*Q9vQC^wHl2 ylBIx16]a>k2KJy)c,Ϊl?۬  ?]Vc窣SG2/O?b#%vR_7 Ҕm_hVfO)^@rHM5.l%z5'm-P+5BNnmXjM9:DS`c@ad/b ; 3 ։Ɠi><6k=vQ|4M {]ˊsŮDK"]Ѝ2CülI[0-r!%,J|o'ŀ 68psдQ,[q')^!P$ʔ?AYI *5 3UɆxݼ 1c3u=E: 5!=![RO]&i47@5BSumafIn20LB,ɺ f'˵!;Y}^ٓAK[A\Nё9P'k/ &ٴiUT2}*>Tbm -j?`t*oT_SGc$)qQF;6Gg+25#H1s/$ ɦ{8 Ʒ•Kiɽ%L팙r Bq(1zIE(ӧ#QT(|W$HPN_3bw|aMe].o|9/R'GG.;G*)} 7֪@gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``d( 0 0l8oddEohhpT^BH h$$c0$0$@np*p*0w00a}hh 2xx HH  ؼ ؼ   0  00 0h`0H x(h+PK|]  x86_64-linux/openssl.sonuȯELF>y@@8 @ȄȄ 00$0$&* pp$p$PP888$$ Std PtdllQtdRtd00$0$ GNU 79(Z=(KO&  B" @D@ (Q 4I @BH $ @\a @@ @ !@D@@ H!$` QJ$ @J)&@X01B @@ D₋@ @@ bRHB@P @     "#$'(*+,-/03578;<?@ABCIJKLMNOPQSUVWXZ[\^_`acefhijlmnprsuvw{|}~ wP') 0t:li-2kE{1bolS6‰GX{+p=&4U8\x%!!0JSqO_/:'9< rJ _z /i(Bг;Yyqc ,TҀ? MPTEtdQk'm !1a ,Tνc IɌATmqβG' !m> [- Iq#I5A A|7)4y]|[{+E'm3͍h!, ,Y.\*y\X-Կ[6#BEq$BQ!I)*%P\8;ӨA+nD[H) t- I)04pߝ)4~-)+b^I-(7evH|wvDqXU` u$. z^H|T sY`iƵk,oeRFRO\ժ }Ns byl=v|0z ИmXf9Q;e-&uX_SfEӕ2=v$.ѫ ];\c0S*48>I%2~&rm<  3U3V 3$ 7}"Y1i* h-;M +'h'E<G4p.z-=9'M;8786&^ :5T0 z0v;g4-!)S}B( d92B1k=t5a,   |>5/6d79^6-'r$Ql\l#W2Z%: n*&%B,?= .} R"[q1>R7r"% 1"'Z?1=h67/P>13&F"K&T$3k- E71! -$50'$!74!5=/ :6'SE 0Q(p=2*'d=q2M61 5/)116b'6Sdo62"8J8"* #. @! \4P78gF+/;%$(lu 8( i Y!(0 )'2E  $:n'2".W:$j3 2*#:F0U,x  %* 6U 8-}<77:=-1+)(8 `d"0 1L4#V , 8#66 U-%7)86>3 G<0 'W/"& g!(.49c67k&D/v V=#W-4 ^ 0 B%{: 1+ G]>(=u79 67N -.,8 2>(;e:6!<>0X.#W,+  E:,X)O'-=0k4tCw8.)5"  +.z(M, E > Cw+5=<4-x38(%a +H#$")+5C, "D9N=*4/e)(=$6<G2#=E!re2 // ,a+ - 2K:59.)qa98(:3 &+%;/&$/ ,,R)n: 2&gW #'t'>7n9&66< 11)0: : +*+)):@3+-E<]7 X;<,5#*;$&qc70 %  'N<(>P9,@<:s)*1 u!84&1U 7-94 R8;(R&.&+:7+nq/ n v84[2:)3,203L>d8 | #= =:d9( >//'<2X.#E  ^ 004G 3,B'38p * 7O-!"(*6+: 2i\#*7{, |Z;k7G/;H%7r 7P3!C%1B.:.% 3(8\5q>M HA  g2 2= ) 4$@"h$*$0(p$[   C}0$$ PSj|2 &Os$  PS$ @v4 0B< J)`$a8$9;$ @,$( $$ ~:$H p<$- '`$0$4 @;r, p|$! PGn% qh$0H$Z# S$"$($ $5 PL8$+л$C$  1  $51$} @gZ =x$" $Y ;$ $2$$i$" CN T1) P""$,$_$  pV($$?#H$ G.$-$$ /$X$@$8$(x$ 0CZ&P$ $ȼ$ ($&@$.$-$< D+$8t$y=$$ `O  [$"$'  0;$  3f D*9$N$> Q&X$!p$ Jx/ؽ$~ ?${ `1= @0$5 |ve ! @JU3$ a& @#( PJ( pDi$j $ 02c% @\(h$  W Ƚ$%)$e x$! Q5P$+ Ei3 p:" ys$$! d2cP$> @$  p<*($ h$5 M4@$Nػ$*$ 9p$0 )*$!$tH$'0$   c$ @Z<$5 `v}%  % 0 Ч3!Ȼ$ n Z e=" j' 8$! :Z$  Z  pd25X$ Yf  DQ?$6  X$% ;$0@$?$м$$p$1 `Z.н$ ! dj/ d 3$j   i( "0$%H$?) C"$J`$8$ Px$`$$>  $jP$ؼ$i$$4 K $ |0$U `f__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_check_typeEVP_PKEY_typerb_hash_newossl_bn_newrb_str_new2rb_hash_asetrb_eRuntimeErrorrb_raiseossl_raiseGetBNPtrBN_copyBN_neweBNErrorBN_clear_freerb_scan_argsrb_fix2intrb_string_valueRSA_sizerb_str_newRSA_private_decryptrb_str_set_lenrb_num2intrb_iv_geteRSAError__stack_chk_failRSA_private_encryptRSA_public_decryptRSA_public_encrypti2d_RSAPrivateKeyi2d_RSAPublicKey__assert_failBIO_s_memBIO_newossl_pem_passwd_cbPEM_write_bio_RSAPrivateKeyBIO_freePEM_write_bio_RSAPublicKeyossl_membio2strGetCipherPtrrb_string_value_ptrRSA_printrb_block_given_pRSA_generate_keyossl_to_der_if_possibleossl_obj2bioPEM_read_bio_RSAPrivateKeyEVP_PKEY_assignRSA_newossl_generate_cbBIO_ctrlPEM_read_bio_RSAPublicKeyPEM_read_bio_RSA_PUBKEYd2i_RSAPrivateKey_biod2i_RSAPublicKey_biod2i_RSA_PUBKEY_bioRSA_freeEVP_PKEY_newEVP_PKEY_freerb_data_object_allocrb_iv_setRSAPublicKey_duprb_cFixnumrb_cFalseClassrb_cNilClassrb_cTrueClassrb_cSymbolossl_rsa_newcRSArb_eTypeErrorInit_ossl_rsaePKeyErrormPKeyrb_define_class_undercPKeyrb_define_singleton_methodrb_define_methodrb_define_aliasrb_define_construby_xmallocEVP_CIPHER_CTX_initrb_obj_classrb_class2namerb_warningrb_internrb_funcallEVP_CIPHER_CTX_block_sizerb_str_resizeEVP_CipherUpdaterb_eArgErroreCipherErrorGetDigestPtrEVP_CIPHER_CTX_cipherEVP_BytesToKeyEVP_CipherInit_exOPENSSL_cleanseEVP_md5rb_ary_newOBJ_NAME_do_all_sortedrb_ary_pushEVP_CIPHER_CTX_cleanupruby_xfreeEVP_CIPHER_CTX_set_paddingEVP_CIPHER_block_sizerb_int2inumEVP_CIPHER_iv_lengthEVP_CIPHER_CTX_iv_lengthEVP_CIPHER_key_lengthEVP_CIPHER_CTX_set_key_lengthEVP_CIPHER_CTX_key_lengthEVP_CIPHER_nidOBJ_nid2snEVP_CipherFinal_exrb_warn__memcpy_chkEVP_get_cipherbynamerb_check_frozencCipherrb_obj_is_kind_ofEVP_CIPHER_CTX_copyrb_obj_classnameossl_cipher_newInit_ossl_cipherrb_cObjectmOSSLeOSSLErrorrb_define_alloc_funcrb_define_module_functionSSL_SESSION_printPEM_write_bio_SSL_SESSIONcSSLSessionmemcmpcSSLSocketrb_obj_is_instance_ofPEM_read_bio_SSL_SESSIONSSL_get1_sessionSSL_SESSION_newd2i_SSL_SESSIONASN1_d2i_bioSSL_SESSION_freei2d_SSL_SESSIONSSL_SESSION_get_idSSL_SESSION_get_timeoutrb_cTimeSSL_SESSION_set_timeoutrb_num2longSSL_SESSION_get_timeSSL_SESSION_set_timeInit_ossl_ssl_sessionmSSLX509_STORE_set_ex_dataCRYPTO_set_ex_dataX509_STORE_get_ex_dataCRYPTO_get_ex_dataGetX509StorePtrossl_x509_ary2skOCSP_basic_verifyX509_freesk_pop_freeERR_peek_errorERR_error_stringGetX509CertPtrGetPrivPKeyPtrEVP_sha1OCSP_basic_signsk_new_nulleOCSPErrorOCSP_resp_countOCSP_resp_get0OCSP_single_get0_statusOCSP_CERTID_dupOCSP_CERTID_freecOCSPCertIdasn1time_to_timeOCSP_SINGLERESP_get_ext_countOCSP_SINGLERESP_get_extossl_x509ext_newrb_Integerrb_protectX509_gmtime_adjOCSP_basic_add1_statusX509_EXTENSION_freeDupX509ExtPtrOCSP_SINGLERESP_add_extASN1_TIME_freecX509Extrb_jump_tagOCSP_basic_add1_noncei2d_OCSP_RESPONSEi2d_OCSP_REQUESTOCSP_request_verifyOCSP_request_signOCSP_request_onereq_countOCSP_request_onereq_get0OCSP_onereq_get0_idOCSP_request_add1_nonceOCSP_cert_to_idOCSP_id_issuer_cmpOCSP_id_cmpOCSP_CERTID_newcOCSPReqOCSP_copy_nonceOCSP_BASICRESP_newOCSP_BASICRESP_freeOCSP_response_get1_basiccOCSPBasicResOCSP_response_statusOCSP_response_status_strd2i_OCSP_RESPONSEOCSP_RESPONSE_newOCSP_RESPONSE_freeOCSP_response_createOCSP_request_add0_idOCSP_check_nonced2i_OCSP_REQUESTOCSP_REQUEST_newOCSP_REQUEST_freeasn1integer_to_numInit_ossl_ocsprb_define_module_undermOCSPcOCSPResi2d_X509_ATTRIBUTEeX509AttrErrori2d_ASN1_TYPEi2d_ASN1_SETmASN1ossl_asn1_get_asn1typeASN1_TYPE_getASN1_TYPE_freesk_freeeASN1ErrorX509_ATTRIBUTE_get0_objectOBJ_obj2nidi2a_ASN1_OBJECTd2i_X509_ATTRIBUTEX509_ATTRIBUTE_newX509_ATTRIBUTE_freeOBJ_txt2objX509_ATTRIBUTE_set1_objectossl_x509attr_newX509_ATTRIBUTE_dupcX509AttrDupX509AttrPtrInit_ossl_x509attrmX509cEC_GROUPEC_GROUP_get_point_conversion_formcBNrb_obj_allocossl_bn_ctxEC_POINT_point2bneEC_POINTeEC_GROUPEC_POINT_set_to_infinitycEC_POINTEC_POINT_invertEC_POINT_make_affineEC_POINT_is_on_curveEC_POINT_is_at_infinityEC_POINT_dupEC_POINT_bn2pointEC_POINT_newEC_POINT_clear_freeECPKParameters_printPEM_write_bio_ECPKParametersi2d_ECPKParametersASN1_i2d_bioeECErrorEC_GROUP_set_generatorEC_GROUP_cmpEC_POINT_cmpEC_GROUP_new_curve_GFpEC_GFp_nist_methodEC_GROUP_newEC_GROUP_dupPEM_read_bio_ECPKParametersEC_GFp_simple_methodEC_GFp_mont_methodd2i_ECPKParametersrb_str2cstrOBJ_sn2nidEC_GROUP_new_by_curve_nameEC_GROUP_set_asn1_flagEC_GROUP_set_point_conversion_formEC_GROUP_clear_freeEC_KEY_printEC_KEY_get0_public_keyEC_KEY_check_keyEC_KEY_get0_private_keyPEM_write_bio_ECPrivateKeyi2d_ECPrivateKey_bioPEM_write_bio_EC_PUBKEYi2d_EC_PUBKEY_bioECDSA_verifyECDSA_sizeECDSA_signECDH_compute_keyEC_KEY_set_public_keyEC_KEY_set_private_keyEC_KEY_set_groupEC_KEY_get0_groupcECEC_KEY_dupPEM_read_bio_ECPrivateKeyEC_KEY_newPEM_read_bio_EC_PUBKEYd2i_ECPrivateKey_biod2i_EC_PUBKEY_bioEC_KEY_new_by_curve_nameEC_KEY_set_asn1_flagEC_KEY_set_conv_formEC_KEY_freeEC_get_builtin_curvesrb_ary_new2rb_undef_methodEC_GROUP_get_degreeEC_GROUP_set_seedEC_GROUP_get_seed_lenEC_GROUP_get0_seedEC_GROUP_get_asn1_flagEC_GROUP_get_curve_nameEC_GROUP_get_cofactorEC_GROUP_get_orderEC_GROUP_get0_generatorEC_KEY_generate_keyossl_ec_newInit_ossl_ecrb_uint2inumrb_attrEVP_MD_CTX_mdEVP_MD_sizeEVP_DigestFinal_exEVP_DigestInit_exeDigestErrorEVP_MD_CTX_createEVP_MD_CTX_destroyossl_digest_updateEVP_DigestUpdateEVP_MD_typeEVP_MD_block_sizecDigestEVP_MD_CTX_copyEVP_get_digestbynameossl_digest_newInit_ossl_digestrb_requirerb_path2classrb_define_private_methodInit_ossl_x509Init_ossl_x509certInit_ossl_x509crlInit_ossl_x509extInit_ossl_x509nameInit_ossl_x509reqInit_ossl_x509revokedInit_ossl_x509storeX509_get_default_cert_areaX509_get_default_cert_dirX509_get_default_cert_fileX509_get_default_cert_dir_envX509_get_default_cert_file_envX509_get_default_private_dirX509_STORE_CTX_freeX509_STORE_CTX_set_timecX509StoreDupX509CertPtrX509_STORE_CTX_initeX509StoreErrorX509_STORE_CTX_set_trustX509_STORE_CTX_set_purposeX509_STORE_CTX_set_flagsX509_STORE_CTX_cleanupossl_x509crl_newX509_STORE_CTX_get_current_certossl_x509_newX509_STORE_CTX_get_error_depthX509_STORE_CTX_get_errorX509_verify_cert_error_stringX509_STORE_CTX_set_errorX509_STORE_CTX_get_chainsk_numsk_valuedOSSLstderrfwrite__fprintf_chkcX509StoreContextrb_block_procossl_verify_cb_idxX509_STORE_CTX_set_ex_dataX509_verify_certX509_STORE_CTX_newGetX509CRLPtrX509_STORE_add_crlX509_STORE_add_certX509_STORE_set_default_pathsrb_check_safe_strX509_LOOKUP_fileX509_STORE_add_lookupX509_LOOKUP_ctrlX509_LOOKUP_hash_dirX509_STORE_set_trustX509_STORE_set_purposeX509_STORE_set_flagsossl_verify_cbX509_STORE_newX509_STORE_freeossl_x509store_newDupX509StorePtrCRYPTO_add_lockossl_x509stctx_newossl_x509stctx_clear_ptrX509_REQ_add1_attreX509ReqErrorX509_REQ_printi2d_X509_REQeX509CertErrorPEM_write_bio_X509_REQPEM_read_bio_X509_REQd2i_X509_REQ_bioX509_REQ_newX509_REQ_freeX509_REQ_get_attr_countX509_REQ_get_attrGetPKeyPtrX509_REQ_verifyX509_REQ_signX509_REQ_set_pubkeyX509_REQ_get_pubkeyossl_pkey_newGetX509NamePtrX509_REQ_set_subject_nameossl_x509name_newX509_REQ_set_versionASN1_INTEGER_getcX509ReqX509_REQ_dupossl_x509req_newGetX509ReqPtrDupX509ReqPtrrb_attr_getOBJ_txt2nidOBJ_nid2lncASN1Setrb_funcall3cASN1SequencecASN1GeneralizedTimecASN1UTCTimecASN1ObjectIdcASN1NullcASN1BMPStringcASN1UniversalStringcASN1GeneralStringcASN1ISO64StringcASN1GraphicStringcASN1IA5StringcASN1VideotexStringcASN1T61StringcASN1PrintableStringcASN1NumericStringcASN1UTF8StringcASN1OctetStringcASN1BitStringcASN1EnumeratedcASN1IntegercASN1Booleanrb_ary_eachrb_block_callrb_str_appendASN1_get_objectossl_asn1_info_sizerb_cArrayd2i_ASN1_OBJECTASN1_OBJECT_freecASN1Datarb_yieldd2i_ASN1_TIMEd2i_ASN1_BOOLEANd2i_ASN1_INTEGERASN1_INTEGER_freed2i_ASN1_BIT_STRINGASN1_BIT_STRING_freed2i_ASN1_NULLASN1_NULL_freed2i_ASN1_ENUMERATEDASN1_ENUMERATED_freerb_str_new4rb_ary_entrysscanfrb_funcall2ASN1_INTEGER_to_BNBN_freeASN1_object_sizeASN1_put_objectmemcpyOBJ_obj2txtOBJ_createtime_to_time_tasn1str_to_strnum_to_asn1integerBN_to_ASN1_INTEGERASN1_GENERALIZEDTIME_setCRYPTO_mallocASN1_TYPE_setASN1_BIT_STRING_newASN1_BIT_STRING_setASN1_STRING_newASN1_STRING_setASN1_STRING_freeASN1_NULL_newossl_to_derASN1_UTCTIME_setossl_buf2strInit_ossl_asn1rb_ary_storecASN1Primitiverb_mEnumerablecASN1Constructiverb_include_moduleHMAC_CTX_copyHMAC_FinalHMAC_CTX_cleanupeHMACErrorstring2hexCRYPTO_freeHMAC_CTX_initHMAC_UpdateHMAC_InitcHMACInit_ossl_hmacX509_CRL_add_exteX509CRLErrorX509_CRL_printPEM_write_bio_X509_CRLi2d_X509_CRL_biocX509RevX509_REVOKED_freeDupX509RevokedPtrX509_CRL_add0_revokedX509_CRL_sortPEM_read_bio_X509_CRLd2i_X509_CRL_bioX509_CRL_newX509_CRL_freeX509_CRL_get_ext_countX509_CRL_get_extX509_CRL_verifyX509_CRL_signossl_x509revoked_newX509_time_adjX509_CRL_set_issuer_nameX509_CRL_set_versioncX509CRLX509_CRL_dupDupX509CRLPtrEVP_DigestInitEVP_VerifyFinalid_private_qEVP_PKEY_sizeEVP_SignFinalrb_eNotImpErrorossl_dh_newossl_dsa_newossl_pkey_new_from_filerb_check_safe_objfopenPEM_read_PrivateKeyfclose__errno_locationstrerrorDupPKeyPtrDupPrivPKeyPtrInit_ossl_pkeyInit_ossl_dsaInit_ossl_dhNETSCAPE_SPKI_printeSPKIErrori2d_NETSCAPE_SPKINETSCAPE_SPKI_verifyNETSCAPE_SPKI_signNETSCAPE_SPKI_set_pubkeyNETSCAPE_SPKI_get_pubkeyNETSCAPE_SPKI_b64_encodestrlenNETSCAPE_SPKI_b64_decodeNETSCAPE_SPKI_freeERR_clear_errord2i_NETSCAPE_SPKINETSCAPE_SPKI_newInit_ossl_ns_spkimNetscapecSPKIi2d_X509_NAMEeX509NameErrorX509_NAME_entry_countX509_NAME_get_entryi2t_ASN1_OBJECTOBJ_ln2nidrb_ary_new3rb_num2ulongX509_NAME_print_exX509_NAME_onelineX509_NAME_add_entry_by_txtcX509Namerb_const_getrb_check_array_typed2i_X509_NAMEX509_NAME_newX509_NAME_freeX509_NAME_hashX509_NAME_cmpX509_NAME_hash_oldX509_NAME_dupGetConfigPtrcConfigNCONF_newNCONF_load_bioNCONF_freeeConfigErrorInit_ossl_configCONF_get1_default_config_filei2d_PKCS12ePKCS12Errord2i_PKCS12_bioPKCS12_parseossl_x509_sk2aryPKCS12_createcPKCS12PKCS12_freePKCS12_newInit_ossl_pkcs12i2d_PKCS7ePKCS7ErrorPKCS7_decryptossl_protect_x509_ary2skPKCS7_verifyERR_get_errorERR_reason_error_stringPKCS7_dataInitBIO_writeBIO_readPKCS7_dataFinalPKCS7_content_newd2i_PKCS7_RECIP_INFOi2d_PKCS7_RECIP_INFOASN1_dupcPKCS7RecipientPKCS7_RECIP_INFO_freePKCS7_RECIP_INFO_newPKCS7_get_signer_infod2i_PKCS7_SIGNER_INFOi2d_PKCS7_SIGNER_INFOcPKCS7SignerPKCS7_SIGNER_INFO_freePKCS7_SIGNER_INFO_newPEM_read_bio_PKCS7d2i_PKCS7_bioPKCS7_encryptcPKCS7PKCS7_freeEVP_rc2_40_cbcPKCS7_signSMIME_write_PKCS7PKCS7_ctrlPKCS7_RECIP_INFO_setPKCS7_get_signed_attributePKCS7_SIGNER_INFO_setPEM_write_bio_PKCS7ossl_x509crl_sk2arysk_popPKCS7_add_crlPKCS7_add_certificatePKCS7_add_recipient_infoPKCS7_add_signerOBJ_nid2objPKCS7_add_signed_attributePKCS7_set_cipherstrcmpPKCS7_set_typerb_id2namePKCS7_dupPKCS7_newSMIME_read_PKCS7Init_ossl_pkcs7eDSAErrori2d_DSAPrivateKeyi2d_DSA_PUBKEYPEM_write_bio_DSAPrivateKeyi2d_DSAPublicKeyPEM_ASN1_write_bioDSA_printRAND_bytesDSA_generate_parametersDSA_generate_keyDSA_freePEM_read_bio_DSAPrivateKeyDSA_newd2i_DSAPublicKeyPEM_ASN1_read_bioPEM_read_bio_DSA_PUBKEYd2i_DSAPrivateKey_biod2i_DSA_PUBKEY_biocDSAPKCS5_PBKDF2_HMAC_SHA1ePKCS5PKCS5_PBKDF2_HMACInit_ossl_pkcs5mPKCS5i2d_X509_EXTENSIONeX509ExtErrorX509_EXTENSION_get_objectASN1_OCTET_STRING_newX509_EXTENSION_set_dataASN1_OCTET_STRING_freed2i_X509_EXTENSIONX509V3_EXT_nconf_nidX509V3_EXT_printASN1_STRING_printX509_EXTENSION_get_criticalX509_EXTENSION_set_criticalX509_EXTENSION_set_objectX509V3_set_nconfX509V3_set_ctxX509_EXTENSION_newX509_EXTENSION_dupGetX509ExtPtrcX509ExtFactoryRAND_statusrb_num2dblRAND_addRAND_seedeRandomErrorRAND_egd_bytesRAND_egdRAND_pseudo_bytesRAND_write_fileRAND_load_fileInit_ossl_randmRandomDH_sizeeDHErrori2d_DHparamsPEM_write_bio_DHparamsDHparams_printDH_generate_parametersDH_generate_keyDH_freePEM_read_bio_DHparamsDH_newd2i_DHparamsDHparams_dupDH_checkBN_bin2bncDHOSSL_DEFAULT_DH_512OSSL_DEFAULT_DH_1024ENGINE_get_cmd_defnsENGINE_ctrl_cmd_stringeEngineErrorENGINE_load_public_keyENGINE_load_private_keyENGINE_get_firstENGINE_freeENGINE_get_nextENGINE_cleanupENGINE_load_opensslENGINE_load_builtin_enginesENGINE_by_idENGINE_initENGINE_ctrlENGINE_set_defaultENGINE_get_digestENGINE_get_cipherENGINE_finishENGINE_get_nameENGINE_get_idrb_str_cat2ENGINE_newInit_ossl_enginecEngineX509_add_exti2d_X509PEM_read_bio_X509d2i_X509_bioX509_newX509_get_ext_countX509_get_extX509_check_private_keyX509_verifyX509_signX509_set_pubkeyX509_get_pubkeyX509_set_issuer_nameX509_get_issuer_nameX509_set_subject_nameX509_get_subject_nameX509_get_serialNumberrb_inspectX509_set_versionX509_printPEM_write_bio_X509cX509CertX509_dupossl_x509_new_from_filePEM_read_X509ossl_call_verify_cb_procERR_peek_last_error__vsnprintf_chk__snprintf_chkrb_exc_newossl_get_errorsCRYPTO_mem_ctrlossl_x509_ary2sk0PEM_def_callbackX509_STORE_CTX_get_ex_datarb_ensureossl_s_to_derrb_respond_torb_exc_raisesk_pushossl_exc_newInit_opensslSSL_library_initOPENSSL_add_all_algorithms_noconfERR_load_crypto_stringsSSL_load_error_stringsrb_define_modulerb_eStandardErrorX509_STORE_CTX_get_ex_new_indexInit_ossl_bnInit_ossl_sslX509_REVOKED_add_exteX509RevErrorX509_REVOKED_newX509_REVOKED_get_ext_countX509_REVOKED_get_extd2i_X509_REVOKEDi2d_X509_REVOKEDBN_is_prime_fasttestBN_bn2decBN_bn2hexBN_bn2mpiBN_num_bitsBN_bn2binBN_is_primeBN_pseudo_randBN_randBN_hex2bnBN_mpi2bnBN_dec2bnrb_cstr_to_inumBN_rshiftBN_lshiftBN_mask_bitsBN_is_bit_setBN_clear_bitBN_set_bitrb_assoc_newBN_sqrBN_duprb_StringBN_mod_inverseBN_generate_primeBN_pseudo_rand_rangeBN_rand_rangeBN_ucmpBN_cmpBN_gcdBN_mod_expBN_expBN_mod_sqrBN_mod_mulBN_mod_subBN_mod_addBN_divBN_mulBN_subBN_addBN_CTX_newSSL_get_verify_resultSSL_newrb_io_taint_checkrb_io_check_closedrb_io_check_readablerb_io_check_writablefilenoSSL_set_fdossl_ssl_ex_ptr_idxSSL_set_ex_dataossl_ssl_ex_vcb_idxossl_ssl_ex_client_cert_cb_idxossl_ssl_ex_tmp_dh_callback_idxeSSLErrorSSL_set_sessionSSL_pendingSSL_state_stringruby_verboseSSL_state_string_longSSL_CIPHER_get_nameSSL_CIPHER_get_versionSSL_CIPHER_get_bitsSSL_get_current_cipherSSL_get_peer_cert_chainSSL_get_peer_certificateSSL_writeSSL_get_errorrb_io_wait_writablerb_io_wait_readablerb_sys_failrb_str_modifySSL_readrb_eof_errorrb_thread_wait_fdID_callback_staterb_ivar_setrb_ivar_getSSL_acceptSSL_connectSSL_CTX_flush_sessionsSSL_CTX_ctrlSSL_get_ex_dataSSL_get_ex_data_X509_STORE_CTX_idxSSL_CTX_get_ex_dataossl_ssl_ex_store_pSSL_CTX_freeSSL_CTX_set_tmp_dh_callbackSSL_CTX_set_ex_dataSSL_CTX_set_cert_storeSSL_CTX_use_certificateSSL_CTX_use_PrivateKeySSL_CTX_check_private_keySSL_CTX_add_client_CASSL_CTX_set_verifySSL_CTX_set_timeoutSSL_CTX_set_verify_depthrb_obj_freezeSSL_CTX_set_session_id_contextSSL_CTX_load_verify_locationsSSL_CTX_sess_set_remove_cbSSL_CTX_sess_set_new_cbSSL_CTX_sess_set_get_cbSSL_CTX_set_client_cert_cbcSSLContextrb_call_superSSL_ctrlSSL_get_certificateSSL_shutdownSSL_clearSSL_CTX_remove_sessionSSLv23_methodSSL_CTX_newSSL_freeossl_ssl_method_tabSSL_CTX_set_ssl_versionSSL_CTX_add_sessionSSL_CTX_set_cipher_listSSL_get_ex_new_indexTLSv1_methodTLSv1_server_methodTLSv1_client_methodSSLv2_methodSSLv2_server_methodSSLv2_client_methodSSLv3_methodSSLv3_server_methodSSLv3_client_methodSSLv23_server_methodSSLv23_client_methodBIO_new_mem_buffdopenBIO_new_fpossl_membio2str0ossl_protect_obj2bioossl_protect_membio2strlibruby.so.1.8libssl.so.10libcrypto.so.10libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.4GLIBC_2.14GLIBC_2.3.4GLIBC_2.2.5OPENSSL_1.0.1_EC/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64 y?Pii ??ti ?ui ?;? ui ?? Лw ?+?3? t +?0$y8$py@$@$`$p${$$$$.$$$$$$$$ $($0$%8$1@$H$P$ X$`$h$$1$$$$Е$$$ $$( $-0$8@$EP$P`$]p$l${$$$$Ж$$$$$ $0$@$ P$`$*$$$o $|0$ @$P$`$p$$$$$$N$N$p$$Y$Yȕ$$ؕ$@$$/$/($RЛ$RH$($$$$e@$e$A$A$Sh$SȖ$H$ؖ$$$8$$ȟ$$x$$$($$8$0$H$П$h$G$G$Oș$Й$ؙ$$$$ $$"$&$`$ $($[0$\8$AP$PX$Q`$ah$#p$x$$k$u$x$b$n$$$$Ț$К$ؚ$$?$$B$$$8$U$ $($0$8$'@$H$0P$X$Q`$ p$x$$<$ $ $$$K$Jț$#؛$$$$A$v$$ $ $ 8$H$P$qX$%`$sh$vp$yx$${$$$$$=$$Ȝ$М$^؜$$$$$$,$4$$f $($0$M8$@$1H$P$X$9`$h$x$~$]$$@$!$2$$$5ȝ$FН$؝$$$l$$$$$ $"($)0$@$H$9P$TX$`$h$p$Tx$$d$f$m$$w$$k$Ȟ$О$-؞$$L$$$$$$ $($60$ 8$@$zH$P$X$i`$qh$Wp$$$$$$$$$;؟$$&$H$o$$($a8$H$kX$h$x$$$u$$/$ $($0$8$@$pH$P$X$`$ h$p$$x$ $ $ $ $$$$$$CȠ$Р$ؠ$$$$$$$$$ $ ($!0$"8$#@$H$$P$%X$&`$'h$(p$x$)$*$+$,$-$$.$/$P$0ȡ$1С$2ء$3$4$5$6$7$8$9$:$; $<($=0$>8$?@$@H$BP$CX$D`$Eh$Fp$Gx$H$I$J$K$L$M$N$O$$RȢ$SТ$Tآ$U$V$W$X$Y$Z$[$\$] $^($_0$`8$b@$cH$dP$eX$f`$gh$hp$ix$j$l$m$n$o$p$q$r$s$tȣ$vУ$wأ$x$y$z${$|$}$~$$ $($0$8$@$H$P$X$`$h$p$x$$$$$$$$$$Ȥ$Ф$ؤ$|$$$$$$$$ $($0$8$@$H$P$X$`$h$p$x$$$$$$$$}$$ȥ$Х$_إ$$$$$$$$$ $($0$8$@$H$P$X$`$h$p$x$$$$$$$$$$Ȧ$Ц$(ئ$$$$$$$$$ $($0$8$@$H$P$X$`$h$p$x$$$$$$$$$$ȧ$XЧ$wا$$$$$$$$$ $7($0$8$@$H$P$X$`$h$p$x$$$$$$ $ $ $$Ȩ$Ш$ب$$$$$$$$Z$ $($0$8$I@$H$P$X$ `$!h$"p$#x$$$$%$&$'$($ $)$*$+ȩ$,Щ$-ة$.$/$0$1$2$3$4$5$6 $7($80$98$:@$;H$<P$=X$>`$?h$@p$Ax$B$C$D$E$F$x$G$H$I$JȪ$KЪ$Lت$M$$N$O$P$Q$R$S$T $U($V0$W8$X@$YH$P$ZX$[`$\h$]p$^x$_$`$a$b$c$$d$e$f$gȫ$hЫ$ث$i$j$k$l$m$n$o$p$q $r($s0$t8$u@$wH$xP$X$z`$h$|p$}x$~$$$$$$$$$Ȭ$Ь$ج$$$$$$$$$ $($0$8$@$H$P$X$`$h$p$x$>$$$$$$$$$ȭ$Э$ح$$$$$$$$$ $($0$8$D@$H$P$X$`$h$p$x$$$$$$$$$$Ȯ$Ю$خ$$$$$$$$$ $($0$8$E@$H$P$X$`$h$p$x$$$$$$$$$$ȯ$Я$د$$$~$$$$$$ $($0${8$@$H$P$uX$`$h$p$x$c$$r$$$$$$$Ȱ$ а$ ذ$ $ $ $$$$$$ $($0$8$@$H$P$X$`$ h$!p$"x$#$$$:$%$&$'$($)$*$yȱ$+б$,ر$-$.$0$1$$2$$3$4 $5($60$78$8@$:H$;P$<X$=`$>h$p$?x$@$A$B$C$D$E$F$G$H$IȲ$Jв$Kز$"$L$M$N$O$P$Q$$ $R($S0$U8$V@$WH$XP$YX$Z`$[h$\p$]x$^$_$`$a$b$c$e$g$h$iȳ$jг$lس$m$n$o$p$q$r$s$t$u $v($w0$x8$y@$zH${P$|X$}`$~h$p$x$$$g$$$$$$$ȴ$д$ش$$$$$$$$$ $($0$8$@$H$P$X$`$h$p$x$$$$$$$$$$ȵ$е$ص$$$$$$$$$ $($0$8$@$H$P$X$`$h$dp$x$$$$$$$$$$ȶ$ж$ض$$$*$$$$$$ $($0$8$@$H$P$X$`$h$p$x$$$$$$$$$$ȷ$;з$ط$$$$$$$$$ $($0$.8$@$H$P$X$`$h$p$x$$$$$$$$$$ȸ$ HH#HtH5#%#hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6h7qh8ah9Qh:Ah;1h<!h=h>h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhehfhgqhhahiQhjAhk1hl!hmhnhohphqhrhshthuhvhwqhxahyQhzAh{1h|!h}h~hhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhahQhAh1h!hhhhhhhhhhhqhah Qh Ah 1h !h hhhhhhhhh%}X#D%uX#D%mX#D%eX#D%]X#D%UX#D%MX#D%EX#D%=X#D%5X#D%-X#D%%X#D%X#D%X#D% X#D%X#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%W#D%}W#D%uW#D%mW#D%eW#D%]W#D%UW#D%MW#D%EW#D%=W#D%5W#D%-W#D%%W#D%W#D%W#D% W#D%W#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%V#D%}V#D%uV#D%mV#D%eV#D%]V#D%UV#D%MV#D%EV#D%=V#D%5V#D%-V#D%%V#D%V#D%V#D% V#D%V#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%U#D%}U#D%uU#D%mU#D%eU#D%]U#D%UU#D%MU#D%EU#D%=U#D%5U#D%-U#D%%U#D%U#D%U#D% U#D%U#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%T#D%}T#D%uT#D%mT#D%eT#D%]T#D%UT#D%MT#D%ET#D%=T#D%5T#D%-T#D%%T#D%T#D%T#D% T#D%T#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%S#D%}S#D%uS#D%mS#D%eS#D%]S#D%US#D%MS#D%ES#D%=S#D%5S#D%-S#D%%S#D%S#D%S#D% S#D%S#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%R#D%}R#D%uR#D%mR#D%eR#D%]R#D%UR#D%MR#D%ER#D%=R#D%5R#D%-R#D%%R#D%R#D%R#D% R#D%R#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%Q#D%}Q#D%uQ#D%mQ#D%eQ#D%]Q#D%UQ#D%MQ#D%EQ#D%=Q#D%5Q#D%-Q#D%%Q#D%Q#D%Q#D% Q#D%Q#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%P#D%}P#D%uP#D%mP#D%eP#D%]P#D%UP#D%MP#D%EP#D%=P#D%5P#D%-P#D%%P#D%P#D%P#D% P#D%P#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%O#D%}O#D%uO#D%mO#D%eO#D%]O#D%UO#D%MO#D%EO#D%=O#D%5O#D%-O#D%%O#D%O#D%O#D% O#D%O#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%N#D%}N#D%uN#D%mN#D%eN#D%]N#D%UN#D%MN#D%EN#D%=N#D%5N#D%-N#D%%N#D%N#D%N#D% N#D%N#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%M#D%}M#D%uM#D%mM#D%eM#D%]M#D%UM#D%MM#D%EM#D%=M#D%5M#D%-M#D%%M#D%M#D%M#D% M#D%M#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%L#D%}L#D%uL#D%mL#D%eL#D%]L#D%UL#D%ML#D%EL#D%=L#D%5L#D%-L#D%%L#D%L#D%L#D% L#D%L#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%K#D%}K#D%uK#D%mK#D%eK#D%]K#D%UK#D%MK#D%EK#D%=K#D%5K#D%-K#D%%K#D%K#D%K#D% K#D%K#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%J#D%}J#D%uJ#D%mJ#D%eJ#D%]J#D%UJ#D%MJ#D%EJ#D%=J#D%5J#D%-J#D%%J#D%J#D%J#D% J#D%J#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%I#D%}I#D%uI#D%mI#D%eI#D%]I#D%UI#D%MI#D%EI#D%=I#D%5I#D%-I#D%%I#D%I#D%I#D% I#D%I#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%H#D%}H#D%uH#D%mH#D%eH#D%]H#D%UH#D%MH#D%EH#D%=H#D%5H#D%-H#D%%H#D%H#D%H#D% H#D%H#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%G#D%}G#D%uG#D%mG#D%eG#D%]G#D%UG#D%MG#D%EG#D%=G#D%5G#D%-G#D%%G#D%G#D%G#D% G#D%G#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%F#D%}F#D%uF#D%mF#D%eF#D%]F#D%UF#D%MF#D%EF#D%=F#D%5F#D%-F#D%%F#D%F#D%F#D% F#D%F#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%E#D%}E#D%uE#D%mE#D%eE#D%]E#D%UE#D%ME#D%EE#D%=E#D%5E#D%-E#D%%E#D%E#D%E#D% E#D%E#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%D#D%}D#D%uD#D%mD#D%eD#D%]D#D%UD#D%MD#D%ED#D%=D#D%5D#D%-D#D%%D#D%D#D%D#D% D#D%D#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%C#D%}C#D%uC#D%mC#D%eC#D%]C#D%UC#D%MC#D%EC#D%=C#D%5C#D%-C#D%%C#D%C#D%C#D% C#D%C#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%B#D%}B#D%uB#D%mB#D%eB#D%]B#D%UB#D%MB#D%EB#D%=B#D%5B#D%-B#D%%B#D%B#D%B#D% B#D%B#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%A#D%}A#D%uA#D%mA#D%eA#D%]A#D%UA#D%MA#D%EA#D%=A#D%5A#D%-A#D%%A#D%A#D%A#D% A#D%A#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%@#D%}@#D%u@#D%m@#D%e@#D%]@#D%U@#D%M@#D%E@#D%=@#D%5@#D%-@#D%%@#D%@#D%@#D% @#D%@#D%?#D%?#D%?#D%?#D%?#D%?#D%?#DH=A#HA#H9tH&#Ht H=A#H5A#H)HHH?HHtHU&#HtfD=EA#u+UH=B!#Ht H=#YdA#]wAT"USHKH[ Hp;xHHC Hx iH=YILHHHC Hx(?H=wZILHHHC Hx0H=6aIvLHHHC Hx8H=JILLHHnHC Hx@H=V=I"LHHDHC HxHH=.=ILHHHC HxPmH= =ILHHHC HxXCH=<HHHHH[]A\H'$#H5<H81&H$#H5<H81^ff.ATUHSH"HtHm HHtiH9Le HI|$XHt3Ht/HH[]A\fHD$Ht$ID$XHE HxXHuH #1H81@HE HxX{HE H@XHH[]A\H,##H5;H81+ff.ATUHSH"HHm HHtiHYLe HI|$PHtSHt/HH[]A\fHD$Ht$ID$PHE HxPHuH@#1H81@HE HxPHE H@PHH[]A\HL"#H5:H81Kff.ATUHSH"HHm HHtiHyLe HI|$HHtsHt/HH[]A\fHD$&Ht$ID$HHE HxHHuH`#1H81@HE HxHHE H@HHH[]A\Hl!#H59H81kff.ATUHSH"HHm HHtiHLe HI|$@HtHt/HH[]A\fHD$FHt$ID$@HE Hx@HuH#1H81@HE Hx@HE H@@HH[]A\H #H58H81ff.ATUHSH"HHm HHtiHLe HI|$8HtHt/HH[]A\fHD$fHt$ID$8HE Hx8HuH#1H81<@HE Hx8HE H@8HH[]A\H#H58H81ff.ATUHSH"HHm HHtiHLe HI|$0HtHt/HH[]A\fHD$Ht$ID$0HE Hx0HuH#1H81\@HE Hx0HE H@0HH[]A\H#H5%7H81ff.ATUHSH"H4Hm HHtiHLe HI|$(HtHt/HH[]A\fHD$Ht$ID$(HE Hx(HuH#1H81|@HE Hx(;HE H@(HH[]A\H#H5E6H81ff.ATUHSH"HTHm HHtiHLe HI|$ HtHt/HH[]A\fHD$Ht$ID$ HE Hx HuH#1H81@HE Hx [HE H@ HH[]A\H #H5e5H81 ff.AUI"ATIUHSH(dH%(HD$1]I\$ H8;HC Hx8Hx@Ld$1LD$LLH%5tH|$@ LbH{ Y1pHcHK AIHD$IT$HpHx HcLLHL$dH3 %(H([]A\A]fD{z@H5V4LH"HP#H5>4H81H#H53H81Hp#H53H81oH#1H81AUI"ATIUHSH(dH%(HD$1I\$ H8;HC Hx8Hx@Ld$1LD$LLHu3EtH|$@\LH{ 1pHcHHHH[1]AUATUHHSH(dH%(HD$1H\$Ll$HMHKHD$HXL`H"Hm HHH|$D$tvLHct$H|$߯HD$HpHT$ALH賱H|$Hct$H;w}qVHD$HL$dH3 %(uRH([]A\A]fDHc1&HD$HX#H5sH81觬H"H5DH81?ZH S bH5RH=Y諻H#1H81XAWAVAUE1ATUHH:SHdH%(H$1H\$Ld$HHD$0MHP1LL$0%YH^諼H|$/H|$ AHt@AH|$(H8HD$"HL} MHD$H\$0LL@LpL$ۺSELLHHl$HULD$Ht$X1ZA1IHLo@H)HH$dH3 %(uyHĘ[]A\A]A^A_f+H|$(AH4HD$f.LhHD$Hxu9LhH,#H5GH81{FH"1H81cH|"H5%H81ff.SfH5HHH[f.SHHHH1[PX1HH"H81שS"HH{ HtE1111AuH[H0#H5KH81f.HtSHH[%Dff.@ATIHUSHt:腯L"VI|$ Ht*uH[]A\;H{#H5H81ʨf.PXH5yHHL#H81袨fS"HH{ HtH[Hcf.S"HH{ Ht谷H蘬[Hc_jf.USHHH|$Ht$ĸH߾"7H[ HtFHD$HHh譭HH9|KHD$111AHL@u$HD$H[]HA"H5\H81萧H"H5H81sS"HH{ HtHh[Hcozf.ATIHUSHt:uL"FI|$ Ht*uH[]A\+Hk"H5H81躦f.USHHH|$Ht$TH߾"H[ HtGHD$HHhHH9|LHD$E111AHHH舶u$HD$H[]H"H5H81*H3"H5'H81fS"H.H{ HtPHx[HȱU"SHHdH%(HD$1Hk HtWH1Hc޵HT$HHpH tiHct$H;s?H賶HHL$dH3 %(uH[]H"H5H81!H {H5H=2=H"1H81f.AWAVAUAATUSHHCHdH%(HD$x1Ld$Hl$MH͹5HHH=nHHH1nH&"HLs M5H|$foHHl$ )D$ HD$HHLxHL$臩LH${jEHAHLd$8ATHL$Ht$4XIZL11EL HH\$xdH3%(HĈ[]A\A]A^A_LPHD$HPH~AH@Hl$ o)L$ H;1HH5ҽH;HH56跽H;H8H5蜽H;1HH5脽H;HH5iH;1HH5QH;1HeH59H;[HH5f.U"SHHdH%(HD$1Hk HtoH蓷HHHHtd1HsH膟H$HxH0趭HHHHT$dH3%(uH[]H"H5CH81H謩H=#H5j1H=#H5I1fU"SHHdH%(HD$1Hk Hto H裶HHHHtd1HsH薞H$HxH0ƬHHHHT$dH3%(uH[]H"H5SH81)H輨H=#H5z1H=#H5Y1fATUH"SHH[ Ht[L%"HI4$1@۷HH9k#HC H<谟H|$HI苎Lu蟷H<$LLH"1H81s転D$f諢D$H H耵H{E1H-#"fIL;{HC HuN4J"HH0HtH"H詫Hs HtHXH[]HH"H5PH81.H&fDUHSH"HFHm HtGH"HH0kHtH"HHs HtH訐H[]HHO"H5H81螂HfDPX1HH"H81wSHHtH g"H1H[ٟ@ATUHSH"hHm HtBL%"HI4$茤HtZ"H:Hs Ht,H蹨[]HcA\ Hv"H5H81ŁH^"H5H81譁I<$4HHiHH5HH}"H81{ff.SHCHtH "H1H[ٞ@PXH5/HH"H81"fS"HNH{ Ht4耆Ht#HH"1[H "H8o[ff.S"HH{ Ht[HcǪRfS"H辨H{ Ht萔Hc[H_f.UHHuSH(dH%(HD$1H\$HOH|$Hu$HL$dH3 %(Hu`H([]f.軋HHD$螐HD$Ht$H} HPHT$HPHuHB"H5H81lff.SHHtH "H1H[@ATIHUHStJ襅HtJ"HpHu HtKHt,H "[L1]HA\铜KHu1Hx"1H81~ATI"USHHk Ht4L"I|$ Ht:HH踔Ht H[]A\H"H5H81c~H"H5hH81F~fDATUHSH"hHm HtBL%"HI4$茠HtZ"H:Hs Ht,Hy[]HcA\ Hv"H5H81}H^"H5H81}I<$4HHiHH5HH}"H81{}ff.UHHSH(dH%(HD$1H\$HoH|$Hu$HL$dH3 %(Hu`H([]f.ۈHHD$辍HD$Ht$H} HPHT$HPHuHb"H5H81|茘ff.SHӀHtH w"H1H[@S"H认HC Ht Hx[{H"H5eH81C|H="ATH5USH8"HC"H"H5qHHHOL%`"H;H5\Hw"HI$+H-"H5HHEH}HAH5fH}H%H5ɚH}H9H5譚H}HH5葚H}1HH5xH}HXH5\H}H,H5@H}1H#H5'I$H;H5$H-"HaHH5NHEN~H}H5ΆH}H>H5C™H}1HH5=詙H}1HH5萙H}1H#H5wH}1HjH5^I$H;H5[H-"H5HHE!H}HH5H}HH5~H}H H5ݘH}HH5QH}1H$H5<記H}HH5"茘H}HlH5pI$H;H5mH-"H5HHE3H}HcH5'H}HH5 H}H H5H}1H"H5֗1迢H;H5{H裢H;H5H臢H;H5^HśkH;H5`H詛OH;H5]H荛3H;H5]HqHH;H5\HS1H;H5[H:H;H5ZHġH;H5[H訡H;H5H茡H;H5?HʚpH;H5H讚TH;H5H蒚8H;H5HvH;H5HZH;H5H>H;H5H"ȠH;H5H謠H;H5H 萠H;H5HΙ@tH;H5H貙XH;H5H薙HHs}HH5HH"H81kHF"H56H81ff.fAUH5 ATUSHH3"HHsHC HtaL ML-"HIu苍H"H5HE HtkH8HtKL輐u&HH[]A\A]H"H5KH81aH"H5H81jHr"H5fH811HZ"H5#H81I}HH%|HH5HH9"H817jH"H5H81~ff.@AUH5ATUSHH}"HH#HC HtkL ML-o"HIu;H"HHE HtuH8HtUH%"LHu&HH[]A\A]H0"H5H81~H"H5kH81?iH"H5 H81}H"H5H81}I}薃HHzHH5qHH߿"H81hH"H5H81u}DAUH5kATUSHH|"HHӐHC HtkL ML-"HIuH"H蕐HE HtuH8HtUHպ"LHju&HH[]A\A]H"H5H81|H0"H5+H81gHȽ"H5H81|H"H5yH81o|I}FHH{yHH5!HH"H81gHN"H5>H81%|DATH5USHI{"HH艏HC HHHL%Ѿ"HI4$蝉H"HGHE Ht}H8Ht]H"HHktu[]A\Ð[1]A\H"H5H81fHr"H53H81I{Hr"H5fH811{HZ"H5#H81{I<$HH%xHH5HH9"H817fH"H5H81zff.@ATH5USHy"HH)HC HHHL%q"HI4$=H"HHE HtuH8HtUHNitu[]A\[1]A\H"H5H81YeH"H5H81yH"H5H81yH"H5H81yI<$HHvHH5sHH"H81dH"H5H81wyH"AVAUIATUSH8H~"HHӌL54"HLe I6HtQ"H諌HC HH0HtxLeI$HtOHHH5~[H]A\A]A^I>~HHuHH5HH"H81cH"H5\H81cH"H5H81vxH"H5hH81^xff.AVAUI"ATUHSHH dH%(HD$1請Le I<$1HL$LD$LHox-L-κ"H|$Iu蘅HH\$IuH~H"H(HC HL(MH"H|$H0;HtH|$zH9"LHH 1cHHI$HH5(H|HHL$dH3 %(H []A\A]A^@L-i"H|$Iu諄HH|$H5vL5"HHI6|H"H&HC HL0MIuH|$?HH|$"HD$H@ HH8HLb@L-"H|$IuHFH\$IuHɃH"HsHC HtUH8HteH"H52H81uHq"H5H81uH"1H81`H"H5wH81muH"H5H81UuHf"H5H81=uH&"H5H81%u@|I}zHH,rHHHG"H5H81>`H|$DHlH"H5H81`Hյ"H5H81tI>I}~zH|$HqHH"H5^H81ttH"H5uH81\tff.SGHu H?Ht}H[Kff.SH螁fH1H H[|fSHnfH1H H[|fU"SHH9HC HtMtQH1HE1jE11HzXZHuKH[]A\A]xHHMt%Po@HHvfi_Hc"H5oH81RHI"H5H81RH1"H5H81RH"H5H810gH"H5H81gH"H5H81PRH"H5BH81f2f1%DSHHHt$"H$1zH[ H;x=H[ HH|${bHsbH$Ht$1IHVHHHvD@@dtuH[@H1[H"H5 H81XQH"H5JH81eH"H5H81eH"H5yH81QUSHH(Ht$"dH%(HD$1$yH[ H;w=H[ HH|$naHdHHk1pHc`1ILD$HHD$HMHPHp5uCt$HSHHT$dH3%(uH([]Hӧ"H5,H81dkH"H5H81PH"H5H81OHn"H5UH81dHn"H5&H81Off.fATUH"SHwH[ H;4v=0Lc M H"HH3qH"HwHE HH(Htm1_E1LHHxHVx+HHcQH[]A\H"H5H81cH["H5H81NH"H5sH81ZcHk"H5,H81BcH;iHHO`HH5HHc"H81aNH"H5H81bH"H5H811NATUHSH"XvHm H}t=Hm HHt]L%"HI4$RpH"HuHC HH0HH[TuH[]A\fD1H>TvH"H5RH81aMH"H5H81IMH"H5;H81aH"H5H81aHڢ"H5H81aH¢"H5H81aI<$pgHH^HH5KHH"H81LU"HSHtH] Htl;9s=H{ HtiXHHt8H=d1HH1maHtkHHH[]vfDH[]H"H5H81`H"H5tH81`H"H5EH81KH]"H5VH81K@ATUH"SHsH[ H;Dr=H[ HHu1H|Pw.H[]A\HpcHHIRPuMtH"H5(H81!KuH[]A\H"H5H81_H|"H5cH81_H|"H54H81Jff.AWAVAUATUH"SHHrLc MA<$8q=Ml$ MhL5"HI6lH"HrHE HL8MH5H^IHtHI6HlH+"L5rID$ LH5H@NdH5Hߺ:dLL]u*HH[]A\A]A^A_H1"H5H810^H"H5H81hIHA"H55H81^H)"H5H81]I>cHHZHH5HH "H81IH"H5oH81]H"H5@H81HI>_cLHAU"ATUSHHpHk H}@o=Le MH5)HY\HHtHH[]A\A]fLhIHtL-"I}PbIuHHjHH"KpHE HHH5L @kbHHH5YbHH[]A\A]HL"H53H81c\HL"H5H81GH4"H5H813\I} bHH?YHH5HHS"H81QGAUI"ATAHUSHH(dH%(HD$1\oHk HH} DHL$LD$LHg1\Ld$IL-"LIuDiHIuH|$-iHH|$"nHD$L` M%A<$*m=I|$ HkHH"H81CHC"H5H81CH"LH5߿H81wCH"LH5H81\Cff.U11HAWAVAUATSH(dH%(HE1JHLcILHHHHH)HH9tHH$H9u%H\$LHHfJHLGIE~uAD$HHDHE;hLsI`GLIuNLH lMt LXNHLHkLLkH;]uHMdH3 %(Lu$He[A\A]A^A_]H)HL(]H"H5H81ADSH5BHKHH5uKHH5ʼKHH5[KfPXH5rHHl"H812VfS"HiHC HH8HtrFtWt:tH"H5H81UH"[HHH"[HHH"[HHBH"H5H81zUf.S"HhHC HtH8Ht&xV[HcjHh"H51H81'UfSHHHt$"hHC Ht;HHtcH|$PHD$HHPHpaHT$H9Bu!HH[H"H5H81THҕ"H5H81?H"H5H81yTfU"SHHgHC HtIHHtSHg"H50H81&SH"H5pH81Sff.UHSH"HvfHE Ht;H(Ht.HuhSH\HH[]@[DRH˓"H5H81Rf.S"HeHC HtH8Ht&>[HHDHx"H5AH817RfS"HeHC Ht,H8HtNc[HHI[H"H5ۻH81QU"SHHIeHC Ht>HHtf1_HHUHw"HHHARu"HH[]H"H5dH81ZQH"H5cH81HHtf1^HHVTHǎ"HHHXu"HH[]H"H5H81PHӑ"H5ɸH81;H"H5H81zPf.S"HcHC HtH8Ht)bH[ Ht*;`=u9H{ Ht+IM[HHHd"H5H81cNNHG"H5H819fDS"HaH[ Ht4;`=uCH{ Ht5LHt H[[[Hڐ"H53H81MH"H5uH81 9ff.U"SHH)aHk Ht,}_=ueH} HtD?u"HH[]HM"H5H81LMH"H5H818H"H5H81MH"H5H81T8@ATUSHtSH?^=H"H H"1HH8U1H5GHHRHtbH[]A\fJHHtKH"L RHHt4HھH]tH ى"1HLH9H"1H817Hv"H5H81m7ff.fAUH5vATUSHH"H"H;HEH"H;H5LHHߋ"H_EL%p"H-ъ"H5(HI$HE:EH"I$H5 H}HEL-"H;H5QL%"IUI$DH"I<$H5+HIUDHJ"H=HOH=H"NH=NH=H^"NH=HC"NH=H("NH=NH=vH"NH=nH"yNHͨ"TH}H5MHEYH}1HhH5QL9H}HLH5QTH}1HH55TH}HH5TH}1HH51TH}HrH5fTH}1HiH5 MTH}HH51TH}1HH5TH}1HH5vSH}1HH5SH}1HH5SH}HH54SH}HQH5'SH}H5H5ySH}1H H5 `SH}1HH5GSH}1HH5ˤ.SH;H5@H;HH5SH;HH5RH;HH5#EH;1HH5sRH;HH5TRH;1HH57RH;1HH5 pRH;1HH5 XRH;1HI<$H_H53QH=wJI<$E11HƺYI<$HH5PI<$HH5.CI<$1HH5ԯPI<$1HH5ůPI<$1HH5PI<$1H6H5zPI<$1HH5aPI<$1H$H5HPH}H;I<$H[]A\A]@USHHHdH%(HD$1HHEH߾"XH[ Ht{H<$tTHLAHAHEH<$Hc 3H$Hp1H2H$HL$dH3 %(uBH[]HxAHE1Hc@H$H"H5ұH810KU"SHH)XHk Ht$HA1HHK_u"HH[]HU"H5nH81/H"H5ҰH81/ff.SH@HtH w"H1H[LH"H5H81A/PXH5HH̆"H81"/fSHHH|$Ht$?H߾"8WH{ HtHD$HPHp]WHH[ff.@S"HVH{ Ht?HNT[H:CS"HVH{ Ht?H5[HcX f.S"HnVH{ Ht`?HxC[Hc?Xf.AUATUHSHH'IH9tP"HVLc MtHL-͂"HIu9PHt["HUHu HtL2t&HH[]A\A]H"H56H81l-HU"1H81Y-I}GHH?HH5HH)"H81'-USHHHt@u@t ?tHH5HHj"H81h,H"H5H81P,H"HH5H815,DATUSHHwH dH%(HD$1Hl$HL$I(AH|$~LH|$ItHH7H0H;H5HH'H0H;H5HH:Hs0H;H5[HGSHHHt H5@z"sOH{Ht%EH[1ff.SHHH5>H[@PXH5tHH{"H81#fATUHHSHKHߨt3KHIH"KH} Ht$L1=H[]A\[KH2IyfAVAUATUSHHH dH%(HD$1HLL$LD$d8"HgKHk HNL%y"H<$I4$EHH<$"/KH$L` M*H|$E1Ht;=IH|$E1Ht%5ILLLHA+u{H<$H5|6Ht HHH<$H5"[6H5HHH81!g=ATUHSHt-IIH"IH} HtD'H[]A\ÐHx0I>ff.ATUHSHt-IIH"JIH} HtD7H[]A\ÐH0Iff.ATUHSHt-IIH"HH} HtL6H[]A\ÐH/I~ff.S"HHH{ Ht +H[FfDS"HnHHC HtHHt [37[@S"H.HH{ Ht@6[H8fS"HGH{ HtN[HHDfS"HGH{ Ht>[HHDrfS"HGH{ Ht`>Hc(B[H?+:f.UHSH"HVGHm Ht.HuP4Hf+HH[]@C%f.AU"ATUSHHFH{ H c*HHHAAąxPHc`#IEt-1fDH H6LHGA9uHL[]A\A]DHIr"H8t+H[]A\A]L5@HA[L]A\A]@Hs" H=H MH H=MH;A1H HEtH8u"H5H81ATUHHȍSH dH%(HD$1HL$LD${2H\$Ld$H=@5HHHSo"IMH8132Hk<GHH5Hl7H=p51HH11HI&H5ƤHH47HB1H[SHCEHtH i"H1H[4@HtHxl"HH Vi"1H83PHm"H5H81CUSHHH-4l"Hu8Ht"HQ>HC Ht9H[]H}0HH'HH5cHHl"H81Hhm"H5YH81USHHH-k"Hu8HtCH߾"=H[ Ht_AT HH F>HH[]H}/HH'HH5HHl"H81Hl"H5H81HtH g"HH 1H8l2PHtl"H5H81USHHH-f"Hu#7HtHC HH[]H}/HHH&HH5HH\k"H81Zf.ATHki"H5}UH-Tk"SHH}w"L%k"H}H5aHVj"HI$R"Hj"H=H|,H;E11ɺH;H=[,H;E11ɺH:H=:,H;E11ɺH:H=,H;E11Hƺ:H;H5H;HH5 2H;HH5o2H;HH5|T2H;HH5h92H;HH5V2H;HH52H;HH5'1H;HIH51H;1HH51H;HVH51H;HH51H;HH5֍d1I$H}H5Ě` H5YHH/d"HH$H߹HuH51H1HH5s1H1HH5˙0H1HH50H߹HRH570H1HH5r0H1HH50H1H:H5n0H1HH5V0H1HH5>0H߹HH5K#0H߹HH570H߹H)H5%/H[]HH5{A\/f.@AVIAUATUH SH8H}~6L%h"1ېHE I4$L,H<2HHH9]Ծ"LW8Mf MI$H5/f"Hx0&;I$H}H@0~)1ېHE HH(HHt^HH&tG1HsHH$HxH0FHH{HHT$dH3%(u:H[]HYHb"1H81 H?e"H5H81 Y)fU"SHHdH%(HD$15Hk Hti1Hf(HcH1HHHH@H$=(~nH4$H+s9s|BHcHaHHT$dH3%(uH[]Hd"H5ɕH81 (H cH5H=}H a"1H81 Hb"1H81 DU"SHHdH%(HD$14Hk HR"H8H[] UHSH=vHHHHN"H8H[] UHSH=uHUHHHFP"H8H[]H UHSH=uHHHHFP"H8H[] SHH=HHQ HIH[@U1H1SH~ H=҃HIH1L 1H&)HH[]ff.SHHH|$H|$HD${ Ht$H^ H[AWHAVIAUATUSHHHH|$@HT$HHL$DD$DL$dH%(H$1H$zM.HD$Ll$xHwHD$pHD$(HD$lHD$ H$HD$0HD$xH$H$HD$8H$HD$XHL$(HT$ IHt$0H<$UAǨLd$xT$M)McL$H$L)ML$H9;D$pH-k"tH-k"u@H-k"HD-k"A HD$HHA!u HDL$HT$8E1H<$}IH9-Sk"Hc|$lHIM"98HHE"HHDHmHLIHI"H0EH|$lD$lHHcH>$Ht$X1L$DHc"IH>H&Ņ'HPHH LHIL HIfD1H=rLLH1 |$lIWH|$L{ D$Ll$xH+$u HHD$@HT$HL(H$HHD$H$dH3%(kHĨ[]A\A]A^A_ H=jqIIMLHHH"IIH81R IBf.K H|$H> HHH$& HHL HHxH$HH`DHHcLD$p@H5h"HHH Hc|$lHHHH|$xIH$HD$xH$DL$HT$8E1HH<$LT$PbLT$PIH$L)H$fH5 h"HHW@H5h"HH?@H5g"HH'@HH5\~LH$Ht$X1D$tL$DHcPHHH=J"HT$tH@HI|$t@$Ht$X1L$DHcoA1EM$Ht$X1D$tL$DHc<HHoH=IK"HT$tHHIa|$tUW$Ht$X1L$DHc IHHhHc0I|$HHELI*$Ht$X1L$DHc HH1A$Ht$X1D$tL$DHcHHttH=NJ"HT$tHHIf|$tZ\DLHYI1HH"H5|H819LHH"1H81 fH8HHt$dH%(HD$(1HD$H|$HD$H E1E11HD$ HD$ HT$H|$H@HD$HD$ HpHL$(dH3 %(uH8N ff.H8HHt$dH%(HD$(1HD$H|$HD$H E11HT$HD$ HD$ H|$AH@HD$HD$ HpUHL$(dH3 %(u H8 fDH8HHt$dH%(HD$(1HD$rH|$HD$SHkE11HT$HD$ HD$ H|$AH@HD$HD$ Hp1HHL$(dH3 %(uH8 HdH%(HD$x1H|LWMoWfHHD$0)$)D$)D$ HpPHHLVHPLHL@ H5y1ZY.|$HcHc|$HD$@Hc|$ HD$HHc|$HD$PHc|$HD$XHc<$HD$`tH=yHD$hHL$@HHA"H8Ht$xdH34%(HĈ1H=%yHpPHHLVHPLHL@ H5x1^_u^|$D)|$f.ofDl|$< H]E"H5yxH81THEE"H5:xH81"HHD$H2^HH|$H=EwOHHH+HǨHAHD$HpHHcH1H|$EHH@DHD$HD$HP HD$H|$HpHPHD$HpHt$Ht$H+s9s|hHcH`HHL$dH3 %(uiH([]A\A]f;<@H|$AHD$H/B"1H81H zH5/vH=[OHA"H5uH81gSHH=vHHUHt'<u'HH;^"tH;o^"u[fD1[HA"H5uH81ff.AUIATUSHL%$@"A$~?H-8"1A9$~*HEHHtH0L' HtH[]A\A]Au;ItMMt"H8H?"H8H>"H8AWAVAUATUSHH(dH%(HD$1H=`tAgHHH=Ft]HHHHAHHA/H=H׃uhHHT$*f.HxHcHD$HHD$HY"HHHD$ fDHH<"H5pH81H~<"H5pH81Hf<"H5NpH81HN<"H5uH81ff.fHH|$H|$]HD$1HxHtHHD$HxHuH;"H5:pH81PUSHH=nHdH%(H$1HHH# H[HHHHKHH$dH3%(u HĘ[]H(H|$Ht$HT$HL$_H|$UH|$KHD$HPHD$HpHD$Hx t H(H:"1H81Jf.AUATUSHHHIIHH;RW"HuHuUPHuSLHH5incLHH5mQHHH5(n?HH[]A\A]Ð HH:"H5LsH81H:"H5mH81rfSH3 Hߨu' [H~fD [Hff.Hc7HSH3HHHt[H"8"1H81ff.AUATUSHHdH%(HD$1H=glfLx1H^IHHL-8"+H5lHHqfLHuHHL$dH3 %(AH[]A\A]I+IH5lM/IEHHuHI8"H5lH81L1fL-3"I<H=\kHHHHǨdHL$$HIHH IHH$LHPHp_ID$HL-4"HH HID$HL$$IHH$LHPHpL-5"XIIHtL-5"2DLL-4"IHhHpIHt>HSHsHHL-95"@L01HIHH6"1H81[Ho6"H5jH81fDL$$1L1AH46"H5jH81AWAVAUATUSHH= jHdH%(HD$1HHtH=iHHUHHsHAHA1HIH5iLcH?."H;H5.dHHHUH;H5dHw+"H;H5dHH6aHUH;H5cHW+"H;H5cHH)HUH;H5cH+"H;H5cHHFHUH;H5c^H."H;H5cHHHUH;H5sc&H-"H;H5XcHHVHUH;H5EcH("H;H5*cHHIHUH;H5cL%,"H;HpH5bI$HUH;H5b}H."H;H5bHHHUH;H5bEH-"H;H5bHHuIUH;H5b H-"H;H5obHHhIUH;H5[bH)"H;H5@bHH0I<$HH5bI<$1HH5bkI<$1H>H5aRI<$1HH5_N9I<$HaH5arI<$HaH5a[H=^OI>HE1[]A\HA]A^A_fATIUHHSH0dH%(H$(1HH^H<$uH5$dHEHt5LHHKHH$(dH3%(u9H0[]A\HH ("H8tH &"H5AdH81H)" H=[H H<$ H;Hc1H;Aw1H ZcHu[^zfS"HH dH%(HD$1zH{ Ht`HT$Ht$H|$t$1HT$ L$H|$ 9uID$H|$47HL$dH3 %(uH [Hj*"H5bH81H$"H5bH81AVIAUATUSH0H $H|$HT$dH%(HD$(1HH$LLhL`HD$HXHhHE1MHT$$HLHRZY1ɋt$HT$ H\$49u'H|$ 7HL$(dH3 %(u%H0[]A\A]A^H#"H5aH81}ff.fAVIAUATUSH H $H|$HT$dH%(HD$1*H"H$LLhL`HD$HhHXHE1MHT$LHHR!ZYHct$HrHL$dH3 %(u H []A\A]A^SHH[f.UH SH1HxHHHHHHǀ1H) HHH HHHH[]ff.@PXH5@`HH'"H812fS"HH dH%(HD$1JH{ Ht3HT$ Ht$bt$ H|$4HL$dH3 %(u H [y@SHHH|$Ht$eH߾"H{ HtHD$HPHpHH[ff.@S"HH{ Ht111H[AUATUHSHHWH9tL"HELc MtDL--$"HIuiHtD"HHu HtLHH[]A\A]HQ&"H5^H81I}'HH\HH5AHHp%"H81nff.ATIUSHHH|$Ht$"HrHk Ht,LHt$HHHVHvHH[]A\SH #"H5^H!"HH;H"H;H5eHH%"HH""H5HHH;HH5]H;HH5]H;HH5=~H;HH5@cH;1HH5@KH;HHC HtHH8z[Hff.AUATUHSHHH9t]"HLc MtUL-"HIu HthH"H} Ht' HHt2L Hk HH[]A\A]H"H5MH81/H"1H81I}HHHH5~/HH"H81f.USHHH-"HuCHt"HHC Ht9H[]H}(HH]HH5/HHq"H81oH"H5LH81WUSHHH-"HuHt@H߾"aH[ Ht\H{A7H LXHH[]H}uHHHH5P.HH"H81輻HU"H5.LH81褻@HHt3.Ht0HH"H 8"1H8Hf.+H"1H81FfDSH\"H5KHF"HH;kH|"H;H5*2HHh"HHH9"H5HHH;HpH5+H;HH5 .H;1HH5CH;HH5]H;1H*H5CH;1HrH530H;HH5JkH;1HH5JSH;HH5J8H;1HH4Hk"H5>H81躬f.UH"SHHH[ HtIHHHʾtuH[]DH1[]H"1H81DH"H55>H81,ff.ATUHSHHHIH߾"H/H{ HtHL+t H[]A\Hh"H5=H81跫fUH"SHHH[ Ht!HHH*t"HH[]H"H5]=H81Tff.@S"HnH{ Ht`Ht!H[颴H"H5=H81DS"HH{ Ht HHt+HH[HN"H5<H81蝪hUSHHH(dH%(HD$1Hl$H菿uHL$dH3 %(HusH([]ÐHHD$Hx5HHtH{ Hk 諪fHD$Ht$1HPHT$HPHHuSHCHtH '!H1H[9t@H!SH5;H8腲H!H!H5;HHH買H!H;H5;HH"H菷H"H5aHHVH;HH5KH;1HH53H;1HH5H;HH5UH;1HH5H;1HaH5CH;HH5&H;HKH55$H;HH5#H;1HH5:lH;[H H5u:PU"SHHdH%(HD$1)Hk Htx1HHcH~S1'HHHH@H$~2H4$H+s9s|UHcHHHT$dH3%(u2H[]H4!1H81hH!H59H81PH :]H59H=lff.AW"AVAUATUSHH(dH%(H$1+HC H$HH<$AŅHc螫HD$E1Hl$fH<$IH(HH虰H趨IIFHcHHc0HxLt 裶LI8LLH1H|$HA9mH$dH3%(HD$H([]A\A]A^A_H!H8t HD$H! H=p-H H H=58vH;A1H 8Hj-SH!1H81NH!H57H816ATUHHSSH dH%(HD$1HL$0H|$HtuIHHHH"HHu HHL1H߅tdAHT$dH3%(uH []A\H"H} Ht@111HHVHHD$9HD$ݰH!1H81*H!H56H81ݿff.fAUATUSHHH(dH%(HD$1Hl$ILL$ILLxHpH|$"HHk HHD$H|$L`Lh@uR轸H$HLEAHHpjZYt{HL$dH3 %(Hu{H([]A\A]D{H=5L$$Hc-V"艻HHg!H8臥LHH1HD$$H!1H81赢耾HI!H5#5H81蘢ATI"UHSHH0dH%(HD$(1HC H$H61HL$LD$LHau%HL$(dH3 %(HH0[]A\DH|$莨HHtMHT$HH޿1觬H=+IXM11LHHDH|$nH|$ HD$ OHD$ Ht$HHPHT$HPPH$HS H2H!1H81L@H=3̹HH!H8ʣHHD$7H!H53H81ATUH1SHHH dH%(HD$1tHId HH1HJHH$9HHD$'HD$Ht4HLlHL$dH3 %(uYH []A\fDHc5"H $H1NHD$HuH=2觸HH!H8襢HD$ɻfSHHtH !H1H[YH!1H81趟fDS"HH{ Ht[HgH !H51H81off.@ATUHSH"Hm Ht:L%!HI4$Ht:"H^Hs Ht [H]A\yH!H5|1H81I<$xHH議HH5SHH!H81连ff.@HCHx 1҃HTHH@u.HtpHt[Htu@tHVH!H9t1@H!HH!H9uH¸t1HH!H@H!H@H!H@HI!HvS"HH{ Ht`[H釼H@!H50H81菝ff.@HHt3Ht0HH!H !1H8Hںf.kH!1H81&fDUSHHH-!Hu胿Ht"H1HC Ht9H[]H}hHH蝮HH5CHH!H81诜HH!H5"/H81藜AVH=h/AUATUSH!H5R/"H!H;H袪H !H;H5[/HH!HH!H51HHFH;HwH5 ;H;HH5. H;HH5 H;1HH5.H;HH5:ҺH;Hs:H5. H;HH5Q衺H;1HH5S.艺H;1HmH5@.qH;1HH5 Y ?I2I%H;LH5-I`H=2Lp HȦLHHH=-讦LHHКH=-蔦LHH趚H=-zLHH蜚H=-`LHH肚H=-FLHHhH=|-,LHHNH;HH5,茽1H;H5tHsɸH;H57-HW譸H;H5#-H;葸H;H5-[H]A\A]A^USHHH-!dH%(HD$1H$HuۻHH=9 ֱ1HH1WH?1HHHHHH۝Hu4蟥HwH$H~>H!H5,H81֘fDkHHL$dH3 %(umH[]ÐH!H57,H81蘘H0H!1H81}H}HH9HH5 HHM!H81KfDUH5+SHH0!HI!H;HfH!H;H5+HHc!HCH-H5H<$HD$$I|$^t!H|$HI9D11ɾLڃ@HEHBL:H+!1H81臀H}H<$HBHH5HHV!H81TH!H5H817E1ff.@PXH5"HH!H81fS"H.HC Ht Hx[鋝fDS"HHC HtH@[HxǭfS"HΧHC HtH@[Hx闭H!H5H81_ff.@S"H~HC Ht H@[H8鈝PX1HH!H81USHHH{H߾"HH{ HtHJt"HH[]HU!H5H81~ff.@SH賬HtH _!H1H[D@S"H莦H{ Ht/4蛌Ht88t[f.Hx[馡H!H5/H81}fAUATIUHSHHH聦LIVHIKH߾"HH{ Ht HLLdt&HH[]A\A]H!H5H81j}EDSHHtH !H1H[ɚ@U"SHHYHk Ht2kHHHtMHH0H߅t#H[]~Hw!H5CH81|aHR!1H81|fPXH5 HH,!H81|fS"H貤H[ Ht#H{Ыt t1[fHC [H@HHH׉ATIUHSHH訪H`HuH=oMH1LP1HH[]A\ff.S"HH[ Ht#H{t t1[fHC [H@ATIUHSHH8H谤HuH=迓MH1L1HFH[]A\ff.HCHH7ATI"USHHk HtLǫHH謘t H[]A\H9!H5H81zcHHH두ATI"USH蘢Hk HtLעHHH贖H;H5)[H]A\f.@AT"USH苔H[ H;tHHC Hx詎H=NI xLHH,lHC Hx H=IwLHHlHC Hx(UH=IwLHHkHC Hx0+H=IwLHHkHC Hx8H=HbwHHHkH[]A\H!H5>H81H!H5(H81kff.ATUHSH"H4Hm HHtiHLe HI|$8HtHt/HH[]A\fHD$覙Ht$ID$8HE Hx8HuH!1H81|j@HE Hx8;HE H@8HH[]A\H!H5EH81~ff.ATUHSH"HTHm HHtiHLe HI|$0HtHt/HH[]A\fHD$ƘHt$ID$0HE Hx0HuH!1H81i@HE Hx0[HE H@0HH[]A\H !H5eH81 ~ff.ATUHSH"HtHm HHtiH9Le HI|$(Ht3Ht/HH[]A\fHD$Ht$ID$(HE Hx(HuH !1H81h@HE Hx({HE H@(HH[]A\H,!H5H81+}ff.ATUHSH"H蔐Hm HHtiHYLe HI|$ HtSHt/HH[]A\fHD$Ht$ID$ HE Hx HuH@!1H81g@HE Hx HE H@ HH[]A\HL!H5H81K|ff.ATUHSH"H贏Hm HHtiHyLe HI|$HtsHt/HH[]A\fHD$&Ht$ID$HE HxHuH`!1H81f@HE Hx~HE H@HH[]A\Hl!H5H81k{ff.SHHHt$"H$юH[ HtX;1tuwH|$2wH*wH$Ht$1LK HVHHHvD@趍x*H[HHɽ!H5"H81zHi!1H81fH!H5H81eff.fUHSH(Ht$"dH%(HD$1H] H;PtH|$MvH{ H8tb{1pHcuLK 1LD$HHD$HMHPHpLmtxHct$HvHHT$dH3%(uSH([]ÐH5VHyHuNH{ H!H5H81dH!H5H81y蠀H!!1H81dH!H5H81dDAT"USHHdH%(HD$1跌Hk H}tH} H8tnL%!1AHcH~c1tHH} HH@H$AԅxCH4$H+s9s|aHcHbuHHT$dH3%(uzH[]A\fDL%i!H(!1H81cH]!H5H81cH E'H5H=rH&!H5H81%x@AUI"ATAHUSHH(dH%(HD$1|H[ HL;؉tHl$DHL$LIH1.xH|$Hu{E1E1HH|HHHs H~8tyHL !1LATE1HlZYH:HT$dH3%(H([]A\A]3wE1H|$ItH虂IdHHE1E1jH=b!HH5~jjsH yHnHd!1H81bH!H5H81a}H|!H5H81{vff.U"SHHH[ Htq;ItuMH{HHt%Hs H1vHt H[]mH!1H81GaH!H5;H81/aHȸ!H5!H81uUSH8dH%(HD$(1H\$H要~9E1ɅuRHL$HjHLD$tHXZHtIH!|t-HT$(dH3%(Hu.H8[]L y!H舅1'|AVI"AUAHATUSHH dH%(HD$1ZLc MHl$1HL$LIHnDuH|$@E1H|$tHH|$IkHHD$踎H!L1HI}HHLlHtL]9HL$dH3 %(H/H []A\A]A^Ðe$HHuH}!1H81_fیHfD11ҾLaE1E11H=p!LH5$`HH@11ҾL`111LaHH11ҾL`1LdHH11ҾL`1LwLHjHH!H5H81,^HDyH!H5 H81rfAUIATIU1SHxHt?LtHHt=H !1HLI{1H5HH%xHH[]A\A]H_HH[]A\A]f.U"SHH虅Hk H}tHU H5!H=Q!lHuHC HtH@ Hx8Ht[r}f[@S"HHC HtH@ Hx0Ht[2}f[d@S"H辂HC HtH@ Hx(Ht[|f[$@S"H~HC HtH@ Hx Ht[|f[@S"H>HC HtH@ HxHt[r|f[@S"HH[ Ht ;^tu,HC [Hx0HH.!H5H81-nH!H5qH81eYDSHtNH?tuzH0!H a!H1H8v1H5`HHsHt3H[fDӆHtHH!H8HH1!1H81XH!H5H81XDSH|!H5 H!HH;fHܭ!H;H5HH8!HfHQ!HHH5H[H;HH5hwH;1HLH5PwH;1H4H58wH;1H,H5 wH;HaH5wH;HH5?iH;HH5)iH;1HH5yvH;1HH5ivH;HzH5vH;HH5svH;1HH5\[vH;H|H5O@vH;1HH5(vH;HiH5 vH;1H1H5uH;HVH5uH;1HH5uH;HCH5uH;1HKH5quH;H0H5tuH;1[HH5m[uf.AULATIUSHAHt$H$D\H|$fHf1Hc&fLAHLhtF\AH$HD$HAHJHpHRHxAU}ZYu,HH[]A\A]fjAfDjrH-!H5H81_Ht0HH7!H P!1H8Hef._Hj!1H81HfDUSHHH-!HucjHt"HpHC Ht9H[]H}HbHH}YHH5#HH!H81GH(!H5H81wGUSHHH-T!HuiHt'H߾"oH{ HtV#^Ht9H[]H}aHHXHH5HH!H81FHF!1H81FH{!H5H81Ff.ATHۛ!H5tUH-ĝ!SHH}TL%!H}H5\H֝!HI$TH!H5DHHRH;HZH5~eH=^H;E11ɺHMmH=^H;E11ɺH,mH=k^H;E11ɺH mH=E_^H;E11ɺHlH=>^H;E11HƺlH;HJH5kdH;HH5ddH;HtH5^dH;H H5TmdH;HH5>RdH;HH5+7dI$H}H5"3SHԘ!H55HHPH;HH5pcH;H`H5սcH;HH5cH;HH5cH;1HH5cH;1HH5ncH;1HRH5_VcH;1[HY]H5A\:cf.HoHHUHSHHH|$Ht$qTHoHD$HpHxGNHH[]ff.fHH|$Ht$)THD$HpHx'LHD$Hff.fPX1HH!H81'CSHHHt$tBeIHH|$SH|$~QHD$HxltH[XHyfHH|$Ht$YSH|$QHD$Hx!ct H.ff.UHSHt.H1HcRHxHOdtHH[]ÐkWfUHSHt.YH1HcMRHxHbtHH[]ÐWfHH|$Ht$iRH|$/PHD$Hxat H=ff.fHH|$Ht$RH|$OHD$HHxZGt HH!SH5qH8JH&!H!H5[HHH2OHS!H;H5HHB_H;H.H5iBDH;HH5_H;HH5 DH;HH5_H;HH5CH;HgH5[_H;HLH5CH;HH5%_H;HH5tjCH;H[H5f^H;H@H5K4CH;HH5=^H;HH5"BH;H/H5 ^H;HH5BH;1H,H5P^H;1[HH5BAT"USHgH[ H;weyhHHC Hx9aH=޻IJLHH>HC HxaH={IpJLHH>HC Hx `H=cIFJLHHh>HC Hx(`H=AHJHHH>>H[]A\H!H5H81RH!H5H81=fDATUHSH"HeHm HHtiHULe HI|$(HtjHt/HH[]A\fHD$flHt$ID$(HE Hx(HuH!1H81<=@HE Hx(THE H@(HH[]A\H!H5H81Qff.ATUHSH"HeHm HHtiHTLe HI|$ HtiHt/HH[]A\fHD$kHt$ID$ HE Hx HuH!1H81\<@HE Hx THE H@ HH[]A\H̓!H5%H81Pff.ATUHSH"H4dHm HHtiHSLe HI|$HthHt/HH[]A\fHD$jHt$ID$HE HxHuH!1H81|;@HE Hx;SHE H@HH[]A\H!H5EH81Off.ATUHSH"HTcHm HHtiHSLe HI|$HthHt/HH[]A\fHD$iHt$ID$HE HxHuH!1H81:@HE Hx[RHE H@HH[]A\H !H5eH81 Off.ATI"USHxbH[ HtV;`uuHk L7RHIL^1HcbJHLHxH9x+HcHAKH[]A\Hr!H5˩H81qNH!1H819HG!H5uH819fDU"SHHdH%(HD$1aHk H}`uzH} 1fHcH~T1IH} HHH@H$ex2H4$H+s9s|mHcHbJHHT$dH3%(uJH[]H!1H818Hn!H5H818HV!H5H81UMpTH H5tH=GU"SHH`H[ Hto; _uKhHGRHHt#Hs HSHt H[]]DHM!1H81 8H!H5H817H!H5H81LfU"SHH_H[ Hto;Y^uKgHQHHt#Hs H;Ht H[]] DH!1H81Y7H!H5 H81A7Hڎ!H53H81KfUSHqV1҅tH!1ɉ 7HHt H);t HH[]H1NFff.AUI"ATAHUSHH(dH%(HD$1^Hk Hn1HL$LD$LHDKH|$@t~HD$AHtHǨHu:HttHt_HtyH{Ht&HHtH[]H!H8HuHICH!1H813fDH!H8@HI!H8@HA!H8@H!H8uH !H5cH81 HH!H5 H81A3UHHSH(dH%(HD$1HL$LD$8HH|$@tDO9މHHtDHHHt4HT$dH3%(ujH([]GމHHuHBHÆ!1H812H|$@t 8bGUNff.@PXH5 HH̉!H81"2fS"HNZH[ Ht<;Xu+HS Hz(t [1H[HHb!H5H81aFS"HYH[ Ht ;>Xu,HC [Hx HH!H5gH81 FPXH5GHH܈!H81EfS"H^YHC HtH@ Hx(Ht[Sf[@S"HYHC HtH@ Hx Ht[RSf[d@S"HXHC HtH@ HxHt[Sf[$@S"HXHC HtH@ HxHt[Rf[@U"SHHYXHk Ht$}VuGH} :4t"HH[]H!H5ޟH81DH!H5H81/HU!H5H81/@S"HHdH%(HD$1WH[ HtD;VuUH{ Ht$G1҅t |$H҃HL$dH3 %(HuH[HƆ!H5H81CJff.AUIATIUHSHX:HtI1DLH3I1ҾHHC IH{HCtHtHH[]A\A]H>H˂!1H81.SHtNH?UuzHh!H !H1H8K1H5HHHHt3H[fD9HtHH!H8HH1!1H81-Hބ!H5H81-DSH!H5H.!HH;;H܁!H;H5HHX!H;H!H5HH5H1H;HH5 LH;1HH5pLH;1HH5XLH;1HH;HH5L>H;1H H5KH;1H8H5KH;1HH5KH;1H8H5KH;HH5!KH;1HH5jiKH;HH5]NKH;1HRH56KH;HH5KH;1HH5KH;HH54JH;1HlH5JH;HH5 JH;1HyH5JH!@H=*!EH.!H=r!HHH!#HĀ!H[AU"ATUSHH5SH[ HBHICHHL-BfH=f6HHH ,THL!TAH{Hf6HHSH{R6HHSCt?vuH=,6f.u+H=~6of.L5XH=5DHL[]A\A]Hc!H5 H81)fAWI"AVAHAUATUSHH(dH%(HD$1QHk HLd$Ll$LDMLH1w>L9H|$u?1HD$1HHp2t\HL$dH3 %(HuDH([]A\A]A^A_@L9HD$HtHPHx!H5 H81(DH3~!1H81(ff.@AUE1ATUSHHH(dH%(HD$1Hl$Ld$IL=H|$t LHIE1H|$t HzHIH߾"jPH{ Ht51LL4-Ht@H1HL$dH3 %(u#H([]A\A]H!H5-H81'CH@}!1H81'ff.AUE1ATUSHHH(dH%(HD$1Hl$Ld$IL4@Hx!SH5HH;u!H8{/HLv!Hv!H5ջHHHX/Hyv!H;H5wH-H;HH5t$H;1HH5\$H;1HH5yD$H;H5H5f)$H.HDH+HA<IHxH5T)*H;1HH5q?H;1HH5Y?H;1HMH5A?H;HH5ɺ&?H;HH5 ?H;H H5>H;HH5>H;HH5>H;HH5v>H;1HCH5g>H;1H+H5o>UIH;H5;HB9IH;H5*HwBIH;H5H[BIH;H5H?B@HH;H5H#BHH;H5HBHH;H5ݹHA1HH;H5Ϲ[HAH s!H8H!u!H8Hr!H8Hr!H8Hys!H8AVIAUATUH SH!FH}~6L%q!1ېHE I4$L,H<7@HHH9]Ծ"LEMn MIEH5t!HxHHIEH}H@H~?1AHE H<;/LDHI7LtR.GHH9][H]A\A]A^I<$7HHE J<(.HH5uHHs!H81FH%s!1H81Hbt!H5cH81U"SHHdH%(HD$1DHk Htx1HFHcH~S1,HHHH@H$F~2H4$H+s9s|UHcH-HHT$dH3%(u2H[]Hdr!1H81Hs!H5H817H 4H5H== +ff.ATUSHHHdH%(HD$1H0u&HH\$dH3%(H[]A\fDH<$Lc +'HH$_J11LHHIHtH'fD11ҾH7LH<(HI'MjHAq!1H816PX1HH!q!H81SH+HtH p!H1H[)8@PXH5/HHr!H81rfATUH"SHBH[ Ht/H7,HߺHI4Lt(DH[]A\DH_p!1H81AU"ATUSHH%BLc MtkLdŅxNHcIŅt+1DL:HsJLH8C9uHL[]A\A]fDH[]A\A]0ff.USHHHAH߾"H{AH{ HHfEt HH[]H!m!H8t3~8H@H=H19H1H[]fHn! H=H H+8H3@H;HeH1z@H;A[1H 9HnW@_Ho!H5H81Jf.USHHH{6H߾"H[@H{ HtHZx(H[]HHo!H5H81fATUHSHHj@HI?8H߾"H?H{ HtHL{ t H[]A\Ho!H5H81gfUH"SHH?H[ Ht!H5HHGt"HH[]Hn!H5H81ff.@S"H?H{ HtAHt!H[R H[n!H5\H81DUHSHHHdH%(HD$1x"HH$>HC Ht4H1HH@ Hx9 Ht7HL$dH3 %(HuH[]Hm!H5ıH811(UHSHHHdH%(HD$1"HH$>HC Ht3H1HH@ H8Ht7HL$dH3 %(HuH[]H$m!H5%H81s>1fS"H=HC HtHH@ HxHt[8Hl!H5ɰH812fS"H>=HC HtHH@ H8Ht[p8Hyl!H5zH81UH"SHHH8-H=DILHH2HH5h2H5̛H2HH?HH$HH5.2H5H2HHd?HH#HH5j2H5H[2HH+?HH#HH512H5H"2HH>HHW#HH51H5H1H!H>HH#HH5[]A\1ff.U"SHHy9Hk Ht:AH#+HHtUHEHH@H0H߅t#H[]6Hh!H5H81yH"g!1H81ATIUSHt=HHHx\L"8I|$ Ht-H;tH[]A\HH~Hg!H5H81FHf!H5\H81.ff.S"HN8HC HtHH85[H!:\ff.U"SHH 8Hk Ht2@H)HHtMHH@-H߅t#H[].5H'g!H5(H81vHe!1H81^yfU"SHHy7Hk Ht2?H#)HHtMHHpH߅t#H[]4Hf!H5H81H*e!1H81fAUATUHSHH)H9tZ"H6Lc MtRL-e!HIu0HteH"6H} Ht$Y>Ht2HC L8/HH[]A\A]He!H5ԩH81"Hkd!1H81I}(HHHH5qHHd!H81 ff.fHHt3=Ht0HHe!H c!1H8H*+f.{Hc!1H81v fDUSHH|$H|$H|$HD$H5kHx+HtC111HH2HH%HtIHkd!H b!H1H8*H[][ 8H5XHH#c!H81 Hc!1H81 fDUSHHH-c!Hu/Ht"H4HC Ht9H[]H}&HH-HH5~HHAc!H81? Hc!H5٧H81' USHHH-lc!Hu.Ht@H߾"14H[ Ht\H{AjH (5HH[]H}E&HHzHH5 ~HHb!H81 H%c!H5&H81t @SH`!H5eHvb!HH;Ha!H;H5SHHb!HxHb!H5ZHH?H;H@H5{4*H;H%H5=~*H;1HH5{*H;1HeH5{)H;H{H5{#H;1HH5X{)H;1HOH5)H;HH5)H;1HH5p)H;1H4H5 X)H;HH5=)H;1HaH59%)H;HH5& )H;1HnH5(H;HH5W(H;1H{H5(H;HpH5Z(H;1HH5(H;HH53q(H;1H5H5Y(H;HH5>(H;HH5#(H;HH5z(H;HYH5'H;1HH5'H;HH5'H;HH5'H;1[HH5'fDHM\!HÐHc1fHdH%(HD$1HH$H<$~H$HT$dH3%(uH#ATUSHLgHoH=A H;M[HH]1A\DAVAUATUSHH $HH $HdH%(H$ 1IHIk1IH_HIغM Ho=L-&[!IEMtat]H'L.H HcL HL/LDH)޺PHcH1ZYIEL-H. ~>HH!сကtDHPHD‰@H)HcHL!H$ dH3 %(ufH []A\A]A^1HLH1 t%HuWf.1H1L!ff.SH1HfHHH#/$HuH[@H}Y!SHHH0H9t Ht@Ht H[D1i$H-[!H=H 5H[@6$HZ!H=lH4H[ÐAVAUATUS,69HHAI }H5OIHHEtQEMLE1MHcHH7@ 2B H BDIL9uHcHMtA,$[]A\A]A^Ht)[]A\A]A^ýff.@HHH=?W!'f.HdH%(HD$1Ht$D$|$uHT$dH3%(u HT%Off.@AUATUSHHt}Hu&AąxNHc&IEt+1@HHcLH,A9uHL[]A\A]DHW!H8H[]A\A]HV!AH8uHX! H=~H 2H H=O2H;Av1H 1Hxa*Y@HaX! H=H 82H H=2H;Av1H ̞H)AUATUSHHt}H%AąxNHcIEt+1@H+HLHH+A9uHL[]A\A]DHU!H8H[]A\A]HU!AH8uHVW! H=H -1H H=ߝ1H;Aw1H H(Y@HV! H=H 0H H=0H;Aw1H \H(ATIH=PUSHcHHdH%(HD$1HT$D$b$HHtHxHLL"|$uHL$dH3 %(HuH[]A\!@AWAVAUIATAUSHHdH%(HD$1D$Ht>HDL HL$dH3 %(H[]A\A]A^A_tALt$D}MIALLH=;f#T$uNHPӃ~39HpHcLwDH=1' DH=1 똻BAUATIUSLHHL-Q!dH%(HD$81D$Au+HHHu(HL$8dH3 %(HH[]A\A]H=T!HT$Lt"T$u:1҅H=Q!Ht$ HHl$ HHD$0HT$(HU!XHtZL*t.1qAuI<$k.HRDDLD$ G D$ 0fD1L. ff.@H1dH%(HD$1H7T!H01HH$)H$HL$dH3 %(uHff.HS!SHH09%uH[H[ PXHHT$0HL$8LD$@LL$Ht7)D$P)L$`)T$p)$)$)$)$)$dH%(HD$1H$H$HD$HD$ D$0HD$Hff.AV AUATIUS$"HI|$I~JL5S!1DHL(I6HHHt*HHfLHI9\$[L]A\A]A^H5Q!L&HP!H5H81HP!1H81ff.HHT$0HL$8LD$@LL$Ht7)D$P)L$`)T$p)$)$)$)$)$dH%(HD$1H$H$HD$HD$ D$0HD$hHL$dH3 %(uHff.USH+H=HN!H=HH;H5HH=wrH;H5H_!$H;H5xHHEM!H;H5vH{H-LO!11E1H5f1HEH,M!H N!H;1HH5CHH;HUH5'H"Q!H;1H5qH=j%HFP!H#,WH''O& U0H[]H}H51#HAVIAUATUH SH1!H}~6L%L!1ېHE I4$L,HD!E1H|$AE11Ht6u5H\$dH3%(uKH([]D1HE!1H819HH!H5lH81! ff.ATUSHH2fHdH%(HD$1HtmH߾"H[ HcH{HHHH߉HHT$dH3%(H;H[]A\f.H<$@ufH߾"H[ H~J nH HHeHeD!1H81[ur1H"1HcI5HHpHA9#HD`DI1AIcHHpH8A9fHA!H5H81`HF!H5H81H UHHedS1HdH%(HD$1HBt]H"@H} Ht{HA!E11҉Ht%uIH\$dH3%(u_H[]@1@H<$@tDHB!1H81|HF!H5H81d/ ff.@AVIHAUATUSH dH%(HD$1HLL$LD$DH|$E1H|$A@AH<$A@utHHDDHlt{H !B!1HL$ H\$dH3%(urH []A\A]A^E1E1H<$@tAfDH|$E1@tGHeHvA!1H81ff.fAVIH>AUATUSH dH%(HD$1HLL$LD$H|$E1H|$A@H<$A@utxHHDDHt{H @!1HL H\$dH3%(urH []A\A]A^E1E1H<$@tkKAfDH|$E1@tGHH&@!1H81ff.fATUHH[S H dH%(HD$1Ld$LD$LL""HHE H$HhH}=!H|$H0 H~I HHD$HHp&tEfHL$dH3 %(HH []A\Å HD$H$HpHxb HuH>!1H81f.H|$@tufH|$"HD$Hp HtwH<$zHQHD$HHp/mf.[@HD$H$HpHxJH/HuA!H5H81H0!H5UH81 f.USHHHt;FH߾"H{ Ht,HdtHH[]fDH;>!H5ՄH81f.ATI"USHHk Ht5LAuHtH[]A\H=!H5]H81fUHHSHt;VH"'H} Ht'H[]HD bfATI"USH Hk Ht5LAuHtH[]A\HH#!LLHLLurHHHL-5%!H{L1L4H{IHL1 [L]HA\A]1A^FfDH)%!L-$!H;L1LH;If.H!'!H$!H$!Hy%!L?H7HH$!1H81H}'!H5nH81LAUATUSHHH"HILc MHHH "!LLHHauHtXHtCHt]thH{H "!HH1[]A\A]fH"!H8@H$!H8@Hy"!H8@Hq"!H8@H#!H8HH!!1H81H"%!H5kH81qAUATUSHHHw"HILc M5HHLLH[u>HtXHtCHt]thH{H m!!HH1[]A\A]ifH!!H8@H#!H8@HY!!H8@HQ!!H8@H!!H8HH !1H81iH$!H5jH81QATUHSH}H9t."HkLc Mt H:LH?Ht H[]A\H#!H55jH81EDSHg!HHAH!H !H5CjH;HH!H;H5/jHH"!HH!H5HHH;HH5 <H;HH5>qH;HH5>VH;1HJH5i>H;1HH5i&H;HgH5i H;H,H5jiH;HH5viH;1HiH5YiH;HH5iH;HH5iH;HxH5hlH;H-H5hQH;HH5h6H;HH5hH;HLH5hH;HH5hH;HH5uhH;H+H5_hH;HPhH5_\H;HH5-h~H;H/H5GcH;HGH5hH;HFH5gH;1HKH5gH;1HH5gH;1HH5gH;HH5g4H;H5H5gH;HZH5ygH;HH5WgH;HdH5NgH;HH5BgMH;HH5.g2H;H3H5gH;HH5 gH;H-H5fH;HH5;H;HgH5fH;H\H5fH;HH5fuH;HH5 8ZH;1HH5;BH;H;H5cf|H;1HH5]EH;HH59eH;HH5fH;[H~H5 fH!H5dH81jf.S1H=f[t1u H!H[DH![Hff.S"H>H{ Ht[HDf1H=l[ff.AU"ATUSHHH{ tH[]A\A]fH5^eHq"IHI|$ HHHC H57eH8HLhL4L,LI}HAHz!HH0LH5LHHH!0LH5dHHH>!0LH5dHHH!0H[]A\A]HU!H5TdH81lff.ATUHSHH"Hm HtGL%H!HI4$HtJ"HRHs Ht~HquYH[]A\@1H=jH[]A\I<$\HHHH576HH!H81Ht!H5cH81H$!H57H81sS"HH{ HtP[Hcw1H=7jB[ff.U"SHHIH[ Ht`HHHH!H8uHH[]fDH5JH!HYHHHH[]@1H=iHH[]UHSHdH%(HD$1=HHHJHHHH/HHHt$HHHcHt6Hct$HHt6HT$dH3%(u HH[]fDS"HH{ Ht[H'1H=h[ff.AU"ATUSHHH{ Ht|HHtWHgHcIIE~)1fHH[LHA9uHL[]A\A]DHA[L]A\A]@1H=gAHL[]A\A]ff.U"SHHH{ Ht@+HHt#HHH`HH[]fDHH[]Ð1H=GgMHH[]ATUHSHH|$Ht$"HEH5_HH] HL`LHHD$HHpHPH߉Ɖ4t_~u0I<$ofDu$HcH[]A\u ޿u0H9!H5v_H81PI<$f1aH=P_H=fH1#Ld$HH5^HHL1 aDAUATUHH&/SH(dH%(HD$1Ld$HL$MH|$@t[H|$Lct[LAH|$'H|$LuKHD$HL$dH3 %(H([]A\A]fH|$LcuL1HD$t"HNH5]HH] HLhLHHL%gHD$HHpHPH߉Ɖ&IcL>kuwHur-DI}?fDI}'fDH|$HcHD$HHfD19fI}H=]lH=cH1Ll$HLd$H5\MLHH14Hf!H5\H81}HAWI׺AVAUIATUHSHL5!I6"HxH5\HH] HL`L1HAՅHwtjuXHŋLH߉D$ [H#L$ ILDHw!H5bH81莻fDI<$O1HAՅgI6HHu^HH[]A\A]A^A_DI<$pHDELIH!H5#bH81HǨt M1ff.@SHH5d !H[HZVILHHHHu11ҾHdH\H= VHHHHHH7H[]A\ff.@U SHH1HoH5THHtBH5UHHHt*H=P&HHHH[1]H[]ff.U SHH1HH5 TH HtBH5"UH HHt*H=lPHHHH[1] H[]ff.AT"USHH4!H{ 0 H1HH=OHٺHH1 HH1HHIHHHLH5ATHHH54/H[]A\ff.UHcSHcHl-H\H8dH%(HD$(1H? !0(HT$ Ht$Hl$H=HD$H\$ T$ u;t7H|$H5SvHH@ HL$(dH3 %(uH8[]1'ATIUHSHdH%(HD$1H!0HT$H=DHHT$uu1HL$dH3 %(uHH[]A\fH5RHH9H5-HI$H>HEnff.USHHH$HtKHIHt;Ht6HLLLaLH5JHڼH$HtvHH<Hƒ? Hx~61fDHB H<LHH$HH9ZH52JHKH$HILH5JHH H$HH1H@H5JH1H$HtHǨELHIH5GH赻HH5IH蚻H$HtHHL H5IHkH$HtHLH5uIH=H$HOHH1ɾ LRHzH5H&Ht11ɺ!HHZHHH[H 81]頼H H5qAH81SHHt H&H[]ff.fAVAUATIUSHHt$Ht/H@u&@t ?$uHݥHH|$覾HL- 1MI>Ht1I uH HH5@H81f.HcHATHHtǾ"L/I|$ H"uHD$H[]A\A]A^H H5R@H81賝AWL g%IAVL5 AUMATL%3@UHSHX|$ H\$ dH%(HD$H1MI H1M MHH護M9uȋ|$ 1HL$LHG>t Ht$H=HL$HdH3 %(HuHX[]A\A]A^A_覸fDATUHSH"Le H- HHu!Ht/"HHs HtKL[]A\HH}HH)HH5HH= H81;H H5MH81#AUATIUSHHdH%(HD$17HHƒH? 11L-;1H{H$HH9HHu/Ht)Ht$HtHt<t? u 1HH]H<$HHCHPH9~H<$LxHCfHH$īL"7I|$ HtLH$Hp0t#HL$dH3 %(Hu H[]A\A]艶H H5]=H81衚Hr H5;H81艚fAWH=>=AVAUATL%n UM$SHH 11E1H5=H1脭H 11E1H5=1fH 11E1H5=1HHa 11E1H5[B1*HS 11E1H5]B1 H H56H H8蝢H H- H56HHHEɧHJ HL5 H}H5o<I蠧H) H5HHgH= I<$I諱H;E1H3M9uH;H:H5<xH;H)H5 H;HH5;H;1HH5 ڷH;HkH5;迷H;1HH5;觷H;H5;ӻH;H5;迻H;H5;諻H;H5;藻H;H5;胻H;H5@oH;H5@[H;H5;GH;HH5;H;H-H5q;ѶH;1HEH5h;蹶H;HH5`;螶H;1HH5\;膶H;HH5T;kH;1HH5P;SH;HH5I;8 ΛL= IMDI?I\LHHHYM9uL H;LH5:IH}H5:פH H5 HH螢H=O6H;E11ɺH}H=6ѮH;E11ɺH\H=v8谮H;E1Hƺ8H;H5H5d:肧H;HH5H;1H+H56H;1HH55H;HH55̴H;HMH55豴H;1HUH59虴H;1HH5 聴H;1HH59iH;1HH59QH;1H5H5/9H;1HH57!H;1HeH5d9 H;1HH5T9H;HBH5I9ֳH;1HzH5:9辳H}H539H}H5*9ԷH}H5!9迷H} H5(9誷H}H5&9蕷H}H5*9耷H}H5<kH}H5=VH}AH59AH}H59,H}H59H}H59H}H59H}H5<ضH}H59H辶H}H5<詶H}H58蔶H} H58H}H58jH}H58UH}H58@H}H58+H}H58H}H58H}H58H}H58׵H}H58µH}@H58譵H}H[H5;]A\A]A^A_銵f.USHH|$Ht@u@t ?t2H|$舢HD$HpHx膧HtoH[]f.[HXH菼H臭H;OHŅxJH5$THHt-H?HuH"Hc 1H81/H1QH1ҾsdH%(HD$1HH$HxH0IHT$dH3%(uH蟬ff.@HHH= 麴f.HHH=? 隴f.USHHdH%(HD$1Ht$D$aHH|$uHT$dH3%(Hu H[]HHPKEY wasn't initialized!THIS IS NOT A RSA!qdmp1dmq1iqmpprivateprivate key needed.11ossl_pkey_rsa.cnewlen <= len02Neither PUB key nor PRIV key:Not a RSA key!RSAErrorgenerateinitializepublic?private?to_textexportto_pemto_sto_derpublic_encryptpublic_decryptprivate_encryptprivate_decryptq=dmp1=dmq1=iqmp=paramsPKCS1_PADDINGSSLV23_PADDINGNO_PADDINGPKCS1_OAEP_PADDINGossl_rsa_to_der%s#<< is deprecated; use %s#update insteadsalt must be an 8-octet stringargumtents for %s#encrypt and %s#decrypt were deprecated; use %s#pkcs5_keyivgen to derive key and IVunsupported cipher algorithm (%s)wrong argument (%s)! (Expected kind of %s)data must not be emptyCipher not inititalized!ossl_cipher.cout_len < RSTRING_LEN(str)13iv length too shortkey length too shortout_len <= RSTRING_LEN(str)CipherCipherErrorinitialize_copyciphersresetpkcs5_keyivgen<<finalkey_len=key_leniv=iv_lenblock_sizepadding=ossl_cipher_updateossl_cipher_finalOpenSSL for RubySSL Session wasn't initialized.SSL Session already initializedBIO_s_mem()SSL_SESSION_print()no session availableunknown typei2d_SSL_SESSIONi2d_SSL_SESSION too largeto_iSessionSessionErrortime=timeout=21Response wasn't initialized!22Cert ID wasn't initialized!01ossl_ocsp.cRequest wasn't initialized!OCSPOCSPErrorRequestadd_noncecheck_nonceadd_certidcreatestatus_stringbasicBasicResponsecopy_nonceadd_statusCertificateIdcmp_issuerserialRESPONSE_STATUS_SUCCESSFULRESPONSE_STATUS_INTERNALERRORRESPONSE_STATUS_TRYLATERRESPONSE_STATUS_SIGREQUIREDRESPONSE_STATUS_UNAUTHORIZEDREVOKED_STATUS_NOSTATUSREVOKED_STATUS_UNSPECIFIEDREVOKED_STATUS_KEYCOMPROMISEREVOKED_STATUS_CACOMPROMISEREVOKED_STATUS_SUPERSEDEDREVOKED_STATUS_REMOVEFROMCRLNOCERTSNOINTERNNOSIGSNOCHAINNOVERIFYNOEXPLICITNOCASIGNNODELEGATEDNOCHECKSTRUSTOTHERNOTIMEV_CERTSTATUS_GOODV_CERTSTATUS_REVOKEDV_CERTSTATUS_UNKNOWNV_RESPID_NAMEV_RESPID_KEYcannot load DER encoded responsecannot load DER encoded requestRESPONSE_STATUS_MALFORMEDREQUESTREVOKED_STATUS_AFFILIATIONCHANGEDREVOKED_STATUS_CESSATIONOFOPERATIONREVOKED_STATUS_CERTIFICATEHOLDossl_ocspreq_to_derossl_ocspres_to_derATTR wasn't initialized!ossl_x509attr.cdecodecould not get ASN1_TYPEoid=value=AttributeErrorAttributeoidcouldn't set SEQUENCE for attribute value.ossl_x509attr_get_value@groupEC_POINT is not initializedEC_GROUP is not initializedEC_POINT_point2bnEC_POINT_set_to_infinityEC_POINT_invertEC_POINT_make_affineEC_POINT_is_on_curveEC_POINT_is_at_infinityEC_POINT_dupEC_POINT already initializedunknown type for 2nd argwrong number of argumentsBIO_new(BIO_s_mem())EC_GROUP_set_generatorEC_GROUP_newEC_GROUP_dupunknown curve name (%s)unable to create curve (%s)EC_GROUP_new_by_GF*THIS IS NOT A EC PKEY!EC_KEY is not initializedEC_KEY_printoutlen=%dECDSA_verifyPrivate EC key needed!ECDSA_signECDH_compute_keyEC_KEY_set_public_keyEC_KEY_set_private_key@keyEC_KEY_set_groupEC_KEY already initializedunknown curve name (%s) unable to create curve (%s) EVP_PKEY_assign_EC_KEYgroup=EC_get_builtin_curvescloneEC_GROUP_set_seedEC_GROUP_get_cofactorEC_GROUP_get_orderEC_KEY_check_keyEC_KEY_generate_keyNot a EC key!ECErrorECGroupPointGFpGF2mGFp_simpleGFp_montGFp_nistGF2m_simpleuncompressedhybridNAMED_CURVEprivate_key=public_key=private_key?public_key?dh_compute_keydsa_sign_asn1dsa_verify_asn1eql?curve_nameasn1_flagasn1_flag=point_conversion_formpoint_conversion_form=seed=degreeinfinity?on_curve?make_affine!invert!set_to_infinity!to_bnmissing ossl_ec_point structuremissing ossl_ec_group structurewrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group1st argument must be OpenSSL::PKey::EC::Groupmissing group (internal error)EC_GROUP is already initializedunknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simpleunknown symbol, must be :GFp or :GF2munknown argument, must be :GFp or :GF2mcan't export - no public key setcan't export - EC_KEY_check_key failedEC_KEY_get0_get0_group (has public_key but no group???unsupported point conversion form: %d, this module should be updatedform must be :compressed, :uncompressed, or :hybridDigest initialization failed.EVP_MD_CTX_create() failedopensslDigest::ClassDigestDigestErrorfinishdigest_lengthblock_lengthDigest CTX wasn't initialized!Unsupported digest algorithm (%s).X509V_OKV_ERR_UNABLE_TO_GET_CRLV_ERR_CERT_SIGNATURE_FAILUREV_ERR_CRL_SIGNATURE_FAILUREV_ERR_CERT_NOT_YET_VALIDV_ERR_CERT_HAS_EXPIREDV_ERR_CRL_NOT_YET_VALIDV_ERR_CRL_HAS_EXPIREDV_ERR_OUT_OF_MEMV_ERR_CERT_CHAIN_TOO_LONGV_ERR_CERT_REVOKEDV_ERR_INVALID_CAV_ERR_PATH_LENGTH_EXCEEDEDV_ERR_INVALID_PURPOSEV_ERR_CERT_UNTRUSTEDV_ERR_CERT_REJECTEDV_ERR_SUBJECT_ISSUER_MISMATCHV_ERR_AKID_SKID_MISMATCHV_ERR_KEYUSAGE_NO_CERTSIGNV_FLAG_CRL_CHECKV_FLAG_CRL_CHECK_ALLPURPOSE_SSL_CLIENTPURPOSE_SSL_SERVERPURPOSE_NS_SSL_SERVERPURPOSE_SMIME_SIGNPURPOSE_SMIME_ENCRYPTPURPOSE_CRL_SIGNPURPOSE_ANYPURPOSE_OCSP_HELPERTRUST_COMPATTRUST_SSL_CLIENTTRUST_SSL_SERVERTRUST_EMAILTRUST_OBJECT_SIGNTRUST_OCSP_SIGNTRUST_OCSP_REQUESTDEFAULT_CERT_AREADEFAULT_CERT_DIRDEFAULT_CERT_FILEDEFAULT_CERT_DIR_ENVDEFAULT_CERT_FILE_ENVDEFAULT_PRIVATE_DIRV_ERR_UNABLE_TO_GET_ISSUER_CERTV_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATUREV_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATUREV_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEYV_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELDV_ERR_ERROR_IN_CERT_NOT_AFTER_FIELDV_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELDV_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELDV_ERR_DEPTH_ZERO_SELF_SIGNED_CERTV_ERR_SELF_SIGNED_CERT_IN_CHAINV_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLYV_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATUREV_ERR_AKID_ISSUER_SERIAL_MISMATCHV_ERR_APPLICATION_VERIFICATION@timeSTORE_CTX is out of scope!STORE wasn't initialized!@verify_callback@certOSSL_DEBUG: certs in chain < 0???ossl_x509store.c [%s:%d] @error@error_string@chainSTORE_CTX wasn't initialized!StoreErrorStoreverify_callback=flags=purpose=trust=add_pathadd_fileset_default_pathsadd_certadd_crlStoreContexterror=error_depthcurrent_certcurrent_crlcleanupReq wasn't initialized!ossl_x509req.ccount < 0???version must be >= 0!RequestErrorversionsubjectsubject=signature_algorithmattributesattributes=add_attributeossl_x509req_to_der@valueeachvalue is too short@unused_bits%2d%2d%2d%2d%2d%2dZbad UTCTIME format%4d%2d%2d%2d%2d%2dZbad GENERALIZEDTIME formatunknown time formatutcASN1_INTEGER is NULL!@tag_classinvalid tag class@tagtag number not specifiedossl_asn1.c@tagginginvalid tag defaultmust specify tag numberinvalid OBJECT IDnil expectedunsupported ASN.1 typeASN1_TYPE alloc failurecannot alloc bufferreallen <= lenEOCUNIVERSALCONTEXT_SPECIFICAPPLICATIONPRIVATEIMPLICITASN1ASN1Errortraversedecode_allUNIVERSAL_TAG_NAMEASN1DataPrimitiveConstructiveBooleanIntegerEnumeratedBitStringOctetStringUTF8StringNumericStringPrintableStringT61StringVideotexStringIA5StringGraphicStringISO64StringGeneralStringUniversalStringBMPStringNullObjectIdUTCTimeGeneralizedTimeSequenceSetregistersnlnshort_namelong_nameBOOLEANINTEGERBIT_STRINGOCTET_STRINGNULLOBJECTOBJECT_DESCRIPTOREXTERNALREALENUMERATEDEMBEDDED_PDVUTF8STRINGRELATIVE_OID[UNIVERSAL 14][UNIVERSAL 15]SEQUENCESETNUMERICSTRINGPRINTABLESTRINGT61STRINGVIDEOTEXSTRINGIA5STRINGUTCTIMEGENERALIZEDTIMEGRAPHICSTRINGISO64STRINGGENERALSTRINGUNIVERSALSTRINGCHARACTER_STRINGBMPSTRINGz}}0~z~zzzz~zzzzzzzzzzzz'}'}Fhashhash_oldcountryNameserialNumberdnQualifierDCdomainComponentemailAddressRFC2253ONELINEMULTILINEossl_x509name_to_derwrong config formaterror in line %dConfigErrorConfigDEFAULT_CONFIG_FILEPKCS12 wasn't initialized.ossl_pkcs12.cPKCS12_parse@certificate@ca_certs46Unknown PBE algorithm %sPKCS12PKCS12Errorossl_pkcs12_to_derPKCS7 wasn't initialized.ossl_pkcs7.c@datasignedencryptedenvelopedsignedAndEnvelopedNegative number of recipient!Negative number of signers!32PKCS7ri wasn't initialized.PKCS7si wasn't initialized.Could not add recipient.Could not add signer.must specify a booleanunknown type "%s"PKCS7PKCS7Errorread_smimewrite_smimetype=detached=detacheddetached?cipher=add_signersignersadd_recipientrecipientsadd_certificatecertificates=certificatescrls=crlsadd_datadata=SignerInfoSignersigned_timeRecipientInfoenc_keyTEXTDETACHEDBINARYNOATTRNOSMIMECAPOpenSSL::PKCS7#get_signer_info == NULL!ossl_pkcs7_to_derTHIS IS NOT A DSA!pub_keypriv_keyPrivate DSA key needed!ossl_pkey_dsa.cDSA PUBLIC KEYNot a DSA key!DSAErrorsyssignsysverifypub_key=priv_key=ossl_dsa_to_derPKCS5_PBKDF2_HMAC_SHA1PKCS5_PBKDF2_HMACPKCS5PKCS5Errorpbkdf2_hmacpbkdf2_hmac_sha1EXT wasn't initialized!ossl_x509ext.cmalloc errorcritical=critical,unknown OID `%s'@config%s = %s@crl@subject_request@subject_certificate@issuer_certificate04CTX wasn't allocated!ExtensionErrorExtensionFactoryissuer_certificate=subject_certificate=subject_request=crl=config=create_extExtensioncritical?ossl_x509ext_to_derRandomRandomErrorrandom_addload_random_filewrite_random_filerandom_bytespseudo_bytesegdegd_bytesstatus?THIS IS NOT A DH!ossl_pkey_dh.cFailed to generate keyNot a DH key!DHErrorparams_ok?generate_key!ossl_dh_to_derENGINE wasn't initialized.NUMERICNO_INPUTno such digest `%s'no such cipher `%s'#< id="" name="">EngineEngineErrorloadenginesby_idcipherload_private_keyload_public_keyset_defaultctrl_cmdcmdsMETHOD_RSAMETHOD_DSAMETHOD_DHMETHOD_RANDMETHOD_CIPHERSMETHOD_DIGESTSMETHOD_ALLMETHOD_NONEno such builtin loader for `%s'CERT wasn't initialized!ossl_x509cert.cCheck private key:%s, serial=not_before=not_after=CertificateErrorCertificatenot_beforenot_aftercheck_private_keyossl_x509_to_dercall%s%serror on stack: %sOSSL_DEBUG: IS NOW ON! OSSL_DEBUG: IS NOW OFF! ossl.cempty sk!items in sk < -1???object not X509 cert in arrayOpenSSL1.0.0OpenSSL 1.0.2u 20 Dec 2019OPENSSL_VERSIONOPENSSL_VERSION_NUMBEROpenSSLErrorossl_verify_cb_idxdebugdebug=errorspassword must be longer than 4 bytespassword must be shorter then %d bytesX509_STORE_CTX_get_ex_new_index0123456789abcdefREV wasn't initialized!ossl_x509revoked.cRevokedErrorRevokedBN wasn't initialized!invalid radix %dDon't know how to coerceCannot init BN_CTXBNErrorBNnum_bytesnum_bits+-/%mod_addmod_submod_mulmod_sqr**mod_expgcducmp===zero?one?odd?pseudo_randpseudo_rand_rangegenerate_primeprime?set_bit!clear_bit!bit_set?mask_bits!>>lshift!rshift!to_intmod_inverseprime_fasttest?Cannot convert into OpenSSL::BNusing default DH parameters.@contextSSL_new:@io@client_cert_cb@tmp_dh_callbackSSL_set_sessionSSL_write:syswriteSSL_read:sysreadSSL_acceptSSL_connectarg must be Time or nilcache_numconnect_goodconnect_renegotiateaccept_goodaccept_renegotiatecache_hitscb_hitscache_missescache_fulltimeouts@session_new_cb@session_get_cb@x509@tmp_dhossl_ssl.cSSL_CTX is not initialized.@cert_store@extra_chain_certSSL_CTX_use_certificate:SSL_CTX_use_PrivateKey:SSL_CTX_check_private_key:@client_caSSL_CTX_add_client_CA@ca_file@ca_pathcan't set verify locations@verify_mode@timeout@verify_depth@options@session_id_context@session_remove_cb@sync_closeSSL_session_reusedSSL_CTX_new:unknown SSL method `%s'.SSL_CTX_set_ssl_version:@%sSSL_CTX_set_cipher_list:@callback_stateossl_ssl_ex_vcb_idxossl_ssl_ex_store_possl_ssl_ex_ptr_idxSSLContextssl_timeoutssl_version=ciphers=setupSESSION_CACHE_OFFSESSION_CACHE_CLIENTSESSION_CACHE_SERVERSESSION_CACHE_BOTHSESSION_CACHE_NO_AUTO_CLEARSESSION_CACHE_NO_INTERNALsession_addsession_removesession_cache_modesession_cache_mode=session_cache_sizesession_cache_size=session_cache_statsflush_sessionsMETHODSSSLSocketto_iosysclosepeer_certpeer_cert_chainpendingsession_reused?session=verify_resultVERIFY_NONEVERIFY_PEERVERIFY_FAIL_IF_NO_PEER_CERTVERIFY_CLIENT_ONCEOP_MICROSOFT_SESS_ID_BUGOP_NETSCAPE_CHALLENGE_BUGOP_MICROSOFT_BIG_SSLV3_BUFFEROP_MSIE_SSLV2_RSA_PADDINGOP_SSLEAY_080_CLIENT_DH_BUGOP_TLS_D5_BUGOP_TLS_BLOCK_PADDING_BUGOP_ALLOP_SINGLE_ECDH_USEOP_SINGLE_DH_USEOP_EPHEMERAL_RSAOP_CIPHER_SERVER_PREFERENCEOP_TLS_ROLLBACK_BUGOP_NO_SSLv2OP_NO_SSLv3OP_NO_TLSv1OP_NO_TICKETOP_PKCS1_CHECK_1OP_PKCS1_CHECK_2OP_NETSCAPE_CA_DN_BUGTLSv1_serverTLSv1_clientSSLv2_serverSSLv2_clientSSLv3_serverSSLv3_clientSSLv23SSLv23_serverSSLv23_clientSSL session is not started yet.%s SYSCALL returned=%d errno=%d state=%s%s returned=%d errno=%d state=%sSSL SESSION remove callback enteredSSL SESSION new callback enteredSSL SESSION get callback enteredSSL_CTX_set_session_id_context:SSL SESSION get callback addedSSL SESSION new callback addedSSL SESSION remove callback addedossl_ssl_ex_client_cert_cb_idxossl_ssl_ex_tmp_dh_callback_idxSESSION_CACHE_NO_INTERNAL_LOOKUPSESSION_CACHE_NO_INTERNAL_STOREOP_NETSCAPE_REUSE_CIPHER_CHANGE_BUGOP_SSLREF2_REUSE_CERT_TYPE_BUGOP_DONT_INSERT_EMPTY_FRAGMENTSOP_NO_SESSION_RESUMPTION_ON_RENEGOTIATIONOP_NETSCAPE_DEMO_CIPHER_CHANGE_BUGȘ;hT$Uԉ8|tT4HԐP4Ԗ8D$<Ԟh$d(Lp$d,LtlTԩh4Td <ĭXtt$ d0 D\ D T d !P!|!!T!D!4$"T""4""4"#Խ #L#p#Ŀ#$#4#D#T#d4$$D$8%dd%T%D%T%P&&&$&t'H't'''''(d8(T(p(((T()D)tp))))*4*Td**D**$(+D+4p+4++,d@,|,,d,4-x-----(.<.P.$../l/D/4//0$0P0t|00t 0d 1d P1d 11(2DX2t22d22d243|3T3334d@4\4x4d444$45L5D%5$&5&5&6'6d'@6'\6'x6$(6)6)7*<7d+h7,71727$27D272$84h848T585859$6,9T6H96d96969T798(:9\:T::t::::;:;;;4;<t>4<>`<t?<?<?<t@<$A=dA=AH=Et=F=G=H >I8>Jd>dK>K>K>$L>DML?Mx?4N?N?N?dO(@OD@4Pp@P@tQ@Q@dRASv>@v4?lv?v$@v@vAvdAwADw$B`wBwBw4CwdCwDxdEHxFtxDFxFxdGxTH$yH@ytIlyJyJyMyMyN zTN(zNTztPzPzDQz4RH{TR\{Rx{$T{U|$VL|4W|X|X|Y}Y,}Zl}T[}]}]}T^~t^$~^@~_l~4`~`~`$a daLahbbdde f@gl$itjl(lDl`l|4mmm؁4ndn n<$ohoptppTqDrpsDt܃uu4$wXTxyz(zTz${D{ąt|}@~|4d8xĄd0lԉDԈďd4đ TLltȊD<xTċԛ<Tȟ4ġ,T`$ԣ`Ȏ D\|DĴ ,`dĶ4dtHTđ$LxdzRx $ 1FJ w?:*3$"D ?p1,\8qFFA  ABA @rFAD L0  DABC U  DABA @tsFAD L0  DABC U  DABA @tFAD L0  DABC U  DABA @XtFAD L0  DABC U  DABA @HuFAD L0  DABC U  DABA @uFAD L0  DABC U  DABA @$vFAD L0  DABC U  DABA @hwFAD L0  DABC U  DABA 8wFJD F(DP (A ABBG 8,yFJD F(DP (A ABBG 8$zIFJA D(IP (A ABBE 8`{IFJA D(IP (A ABBE 0|7FFA G0  AABA D}|FJG A(GPXN`LXAPK (A ABBB ( EFG H AAE @DFJH A(A0GP< 0A(A BBBK H,BED C(D0M (D ABBH L(D ABB(pEFG h AAD 4dEID p FAG ^ AAA 8܃AAK T<Ed G F A x<Ed G F A <Ed G F A 4<Ed G F A P<Ed G F A l<Ed G F A ,<Ed G F A P<Ed G F A 0tFKF D@  AABE ^Eh A ЅEL G `E$qEID YDA$,XXEDG qJH8TxFBA K(DP (A ABBG lԋFBB E(A0K8GaLMDRPCX 8A0A(B BBBC t&E` EZ8AAFTVEs A pԍ!JL(vFGA v ABI <AAK@6Ed H d6Ed H ( EAG0h AAA 8 6Ed H (T 0vFGA v ABI ( EAG0i AAA  =Ek H ( ,EFG0r AAA X BBB E(A0A8QVPDy 8A0A(B BBBD P d 0x |FAA G0V  DABA 8 FBA D(G0_ (D ABBA ( EAG o AAE , MDA J ABA D `3L(d EFG0 AAA ( DEFG0 AAA , FAI h ABA , FAA Y ABD  (0 EG L@LPo AA \ HAAK x LmEL P AA  .E\ H ( FAI  ABN @lE@ [ F A ( FAI  ABN 4 [L<T ` h \ | X8 T FBA K(FP (A ABBF T (hFBB B(A0C8NpYxFRxAp 8A0A(B BBBF L$@pFGB B(A0A8G 8A0A(B BBBA Xt`@FBE E(G0D8DpxH[xAp 8A0A(B BBBH (DEAN0l AAF (EFG0 AAA ((EFG0 AAA 8TFBA K(FP (A ABBA TTjFBB B(D0A8NpYxFRxAp 8A0A(B BBBE LlFGA A(G0 (D ABBF D (G DBBA (8 EAN0l AAF ,dFDA N ABA  AADD (PEDL L DAD (EDL L DAD  AAF(,E] E ,D0FAD M AEE tЬ,E] E AAK TEm V F A $.E\ H 86Ed H (\EKD@ AAK 4,E] E (PFJD y FEH ,|hFIA A ABA ,ȮFAD M AEE (hEKD@ AAK ,E] E $=E[ E (@4$MHA DB(l8EFG0w AAA 0̷FFA G0  AABK ,HFDA ^ ABD 4EFG F DAK K ADE 84`9FJG A(GP (A ABBE pd:E] E 0FAD D0K  AABB ZHi O (8EAG y AAA E8$FIA A(G0 (D ABBA 8`AFIA A(G0u (D ABBA 8KFIA A(G0 (D ABBA 8KFIA A(G0 (D ABBA 80QFHA  FBB A CBA 8PTIFHA } FBD A CBA <hIBE A(A0| (D BBBA @HFBJ A(D0IP3 0A(A BBBE %E[,.EdH,.Ed(d@EFG C AAE ,BAH F ABL d` H\bFBE E(A0I8G@ 8D0A(B BBBA ,4FAD g AEJ Ld@FBD A(N0k (C ABBB  (A ABBA LFBJ A(F0G`mhRpRhA` 0A(A BBBE %E[( EFG Z AAE DLxBBI A(G08J@P8A0L (A ABBH  (EG  FE D CA (SEAG@ AAA ,FAI  ABA ,D@yFAD  ABG 4tEID [ GAK D FAA 8HFAI M ABH A ABA H FBB B(A0I8G@ 8D0A(B BBBA L4oFGA A(G0N (D ABBC { (D ABBA 8FJG A(GPZ (A ABBA ,kEG M H >Ax AAK(( E[ P H P H I TNEd H pEG N DA 4`EFG r DDL D FAA DFDD K ABD N ABG N ABA (PvEDL q DAE @NEd H \_Ek P F A (EFG F DAA (EFG F DAA QEg H `AAKdzEs M ,E} A H\zEs M dE{ H F A (,EFG t DAA ,FAA R ABC <p|FIA A(D0\(A ABB($EAN0 AAD (PdtEFG l DAA |?E] E AAK QEG { DA =Ek H @6Ed H  d6Ed H 8, FBA D(G0^ (D ABBA 4h ,EAG Q AAH [ AAA 0 FAA N@  AABH ( ~EDD { DAA !aEI!HLEFG0 AAA (5?EFG0 AAA (6@@EFG0 AAA <@6@<FEB A(I0 (D BBBA (6AEFG0 AAA 06BFAA N0w  AABG 6TCAAF6XC,E] E 7lCAAK(47pCmFAI | ABA L`7CFGA A(G0b (D ABBG Q (A ABBI (7DjEIG o DAD 87DzFJD A(G0w (D ABBA (8 EiEIG q DAA LD8PE&FGA A(G0g (D ABBJ Q (A ABBI (80FEDJ0` AAA (8FEDJ0\ AAA 8G-EZ I 9,G-EZ I ($9@GaEIG i DAA P9G-EZ I (l9GFDA z ABH 9 H4Eb H 890HFBA D(G0k (D ABBA (9HEAG o AAA (:HIEAG O DAA H:IZHi O d:JE0:LFIA Gp  AABB 0:lM]FCD G  AABA :N9LT A ;NREy A ($;OSFIC yAB,P;4OEf E I G D L D E (;OEAD0e AAA (;PEAG o AAA (;|PEEG I AAA (<QEAG O DAA (0<QEEG i DAA \<XRL(|<8SEFG0 AAA (<SEFG0 AAA <TAAF <TvEG K AA =UEm N R N 48=UEIG n FAF D CAA ,p=$VnFAD B ABA (=dVaEIG i DAA =VKEd E =VXEo G (> WEAN@x AAB 0>W,E] E L>WLl(l>8YEFG0 AAA L>YFGB B(A0A8J 8A0A(B BBBH 0>[#FAK D@  AABI D?\hFBA A(NPXU`FXAP[ (A ABBF 0d?]FIF GPb  AABF 0?_FAF J@  AABG ?_:E] E ?`AE\ H ,@P`BAD E DBE 4@`-HdL@`RVd@aAE\ H @aZHi O (@aEAG o AAA 8@\bFIB A(A0(D BBB(A eJEAG0 AAB (0ADfEHD nDA(\AfEFG0 AAA @AlgFBB A(A0Np6 0A(A BBBH AiFIE B(A0A8G^LFFGGFFPJEBZ 8A0A(B BBBD TBPk:E] E pBtkL(BxlEFG0 AAA @B> >0>@>P>`>p>>>>>>>>>?? ?0?@?P?`?p?????????@@ @0@@@P@`@p@@@@@@@@@AA A0A@APA`ApAAAAAAAAABB B0B@BPB`BpBBBBBBBBBCC C0C@CPC`CpCCCCCCCCCDD D0D@DPD`DpDDDDDDDDDEE E0E@EPE`EpEEEEEEEEEFF F0F@FPF`FpFFFFFFFFFGG G0G@GPG`GpGG%9\T%֟LLSt @׺p(a`LI_`=ө^d`&u1WLe1o}vO{)hW@T@5%WQwq?O`.| qc'DȓHLmzJMRJ1DGJȋ$o| GA$3a1շ GA$3p1067yƷGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA$3p10670ֵGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYyGA+GLIBCXX_ASSERTIONSopenssl.so-1.8.7-16.el8.x86_64.debug /%7zXZִF!t/!]?Eh=ڊ2Nv-]W:WEv 4Z]HKDVTs VI;~>?]8Nh8\;-%gNo~2m ڥ[瘙ym YvdP ci_ w uyb#lO^Ix%yLS o+n]ZDbÈڗ>;F{ؿoH&jUSۉl:}R 5$ǥ2vk܍X鲖\j78iw=Ο[beEwssƹ!|/Ljme8g HI w;Q݂7:܃`qo6`p`~}욑qXTT8A֦nyH/eUSƝ?T3Rþ +u}:#@gDy5֌Qh4I23[#qo2 ?VsމgSP+06^2SQŒBŗcc,8'JG3t|Zݠ7Z@ك)F4ҋpdGB1S6,sn+g*+-'}_Bc6+b_&rcTy3{KDsj=ȹ$%${:(B N,!-2cem2Ks2L$K8%%1w)72$t:~ }EzP c4RwH7FZ)aa=th0,PB ghbUGe &7UTBi8]+wl[MZkiCg-OBd(i/}`Ņ!W([KnM>XxP-Za*~L_XmFkwMƾ̈ epU_a^:P h;wQRڿrLNwMխ)d1]>#|DiA}`#A D(1X|bߎS;G#jzbjtJpt`y>ZWb -B#0x5% %f> fN}k.e~f` =Xou++yTo9hYgcⷳbjӽIb$Q˺S!6Fu-p֪mr$BwH~bTX9|ـ3|Xj4A$z98Ay&@jA[c9Bv9'i#0q >7R}mf#bm\/eE5w ,vkL{s29˵P% mqV哜dӹ1"&.jg^D@/J%YQEę6wNTathJ$kl3HSܙ4@[铆dP0^Vv)*[Z3SW#CWu<҂[1d,ﻵ3_"\#nxpap: |sO} EP~bъޜQ+n~QlepkG+M"k_i#`.;bnRZ {"M?NՉ(0+;eQuϧ?Z.4i:x0'#,`)#Gbote ]e%p +&1[рe: D~jA+v_oKw[>*jc6ۙ+.ey솲]-Ivu2崝R8հ#ڒFUtү/+Ž} xٖuM[> Uʢ&uXʼDvǫ/0zXqjPsbttY0 {7~Le/bN!pp8!L@̗+ޫknGH'%2n㼫U#l;vlUwe,k`\!'Z21,̲~]`+)s P] pT^ T8HՀ @Gz,-8Xo WEx c5F'Qv6(6z,k3c_qkFw]ʻ~a&,u *|'F P0V'8%;8* uoGMR(~~#Wu #|td3=x|ɖ>Q E6kRJY(D}_]v8 }S. [d0tZj?^JM2ϔu3A.q,/jYұp.!G+Pȍ|=@~4%FBnFK. `cpABh]tE^[حxL9=IPBzQ+Z˝:KɌYw,s4|u,}2Rv KY™{(+qwgBhU4!)S'>].q[4[ u͐oC ŌbbDt5;#Eg6s~yaћшF(8gdN!|:N[s֛ݏ-W5?F}5I84c?hro{=00T^%t$SOY!VB-pg$ fNAzGxҰ[qԠ= nhs@ä`Lho9=rr:[)ѢMnոo#=ƦP a Mڢ݉XAܖf8C?6*c)rMX$0?.PYMG$WUԨE6ѓ:Xw #_ 7Y=ķ1fE禡ovWLGt[ڹ 13mi'trҵĩ]xKEBm; lgrC8bN\C,v^ ]qYD VܨC 4$n'-`K/P7fH޷tԤkîdLc梀 'f@t5qVar"|YטSe-7j7rB1赻$17LHzCS0;6k' ԑJ:%t~\1[rb" 'mZb<`VI)Nm5i(|J:rSGmV.|.{Ĵa> >F+yG\PG dYNy?&ZgWpsO@COh˥xO)TxʒlphP o"|BzT[E4nF2jCrȰPGN͜| UXBfoY:T P35.-ļgQby fU)et7"ʜz`I`b)l~aԼix 90Q|oHc>d/T5!ZP4hpR#t+YCiEvڱoqG]i|aڨ>M>U'ӏ̻_GKzZdx^?? <.$,`;ޔKKF o!,92Pe?M")tC(*JƔb6{1w8fF\G͘k _jIo4>N/R9LcWco{"hHSA:-49I0NIm˂T|leKUs#e^BwK^ G͘ޝ`R *$7kKyD"kPT~#ZzR`5A8^j‚/5-[+w-ѭz6R,ddx( ^gK`iZYH_G;CN$$4fpv.a `բrqK }{NVp~]h쳋X<'+NBST"My NqQ˦irȎHkC#$h)s _OG6c0o@5ȧj0+wݘnHF'ĺE#$e)ṗ[D1?ho& ?{t[` ݓ_[Z PPΤڗJ"dRrv IYWu"- n݂<76Tj` 2|"nQ/k~2vRc׸ݿg)E'wJ2Hc I2)-Ϊ"5C>I6kUcҫXv.!8/@nbR?#&4Դ\uT5P Y<oo'2=gq{iZ>Fy>辧tLXOKr k$sxӸJh IOMKjJz/g2M-@`D^5 ڗSKy$R5(`"-\2'JpAB~]2l -Ez[k%HђP {dA=hxجy=NYX/! ˽Vᚍ8ZJo#(2/ku6ze`c {u AY0:j‹٥ ƿLrRw.ƥFƯa*Dr?^Ab5X=jVG @~ gI<7ls+hA"߫;͛O B?78a#8-SЮT+oѫ),ًoY;&9+hm@!haw&;'ܨY/z71t]8qyh@l~]JuLBV$ CBt_tTrҏI)nue q1GMTvVhr*okn~⎁XF[7/*3bR?nP$;oHɄ,$ LklH286W sx2.jȯ+iZW:Cmh!F|79:%%\u 0{Qe)ȐN08Q мX9tAq#S}$9|Łj ;{J pܣQ& яwp}!,ԁm$M$mge5;0㔊3|6q~f}2Ą#Z4/#csk1~0m v h$Ev:P!bʦWoW0ls0oL3]=K'~ l}daE7^e7PWN$bnGf I6q R\d7Åa럇 >>`2"Qc/ߛ{f?f5t؛.Kr6eoWrvgͧSsq(?rWZ?Wҋ U\D2;0.nqËT3sF&6rb@q+?ϲoj4CNX]y%4u[8 r]o{|k?o%ެAdk{$0DJ !P{SHz怼q9F58B9`]o` fpjK ǽӨҟ5iPd];Z|YF-0֐9vPΙyefM^"M*ub߯n;m4[>҄ jE$Po G!U%:im5VĊaSG gpE|%fz>I7>Хd>gtOxMI։"O{Z/U˓'T -ϒc(6X*/Ys1lNle_+F;ẽnS;aOvzI0<'ă p)ܣPO?(C@*jv<|}^)bEV׻>Mav>hkT=ѳXjP;M0(B-րd!)k!Fz}3mw^;4嬐+wyJM c(8:# [ŭ~B~`rdjz8-@P!8 ̗~Κy31\ ~1s1)zŘAΏJƌlsZ%\1ׁP}feiߝYTzs`uqL!xJ6u*ebk8S%_ƽS0Ȍ{ܪ)Uef=5+wYmJ&X}Qh&BU.;#[ƥY[K/\9mZҷN Sb4[g c?2 H ;gI*!nC0uV&j)- ByW ɉ$`pp'D gKCL  z*u@~}{G˴j{YHѨյ#>0gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``(  \0ff@8oƦƦEoTHH^B(Jhc1nGGp1wyy>}ȷȷ 9l((| 0$08$8@$@0 p$pP$@$$ $dܾ,"dl1PK|] %0Q0Qx86_64-linux/iconv.sonuȯELF> @I@8 @:: 8=8= 8=  P=P= P= 00888$$::: Std::: Ptd050505QtdRtd8=8= 8= GNUuU^\^8TD>9k/ gF@FHIBE|qX > j:3G$S wYUP>{[aAm)jy, F"ao!,4A G B ;A  @1__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizerb_attr_getrb_call_superrb_ivar_seticonv_closerb_str_newrb_str_substrrb_string_value_ptrrb_internrb_funcall2st_lookup__stack_chk_failrb_data_object_allocrb_class2namerb_str_new2rb_str_buf_cat2rb_str_buf_catrb_inspectrb_str_buf_appendrb_cFixnumrb_cFalseClassrb_cNilClassrb_cTrueClassrb_cSymbolrb_check_typerb_eArgErrorrb_raiserb_ensurerb_obj_duprb_class_new_instancerb_ary_new4rb_str_cat2__errno_locationrb_exc_raiserb_sys_failiconv_open__sprintf_chkstrlenrb_gcrb_ary_new3rb_str_appendrb_ary_pushrb_ary_new2rb_block_given_prb_yieldrb_string_valueruby_errinforb_str_concatmemcmprb_str_catrb_fix2intrb_scan_argsrb_range_beg_lenrb_num2longInit_iconvrb_cDatarb_define_classrb_define_alloc_funcrb_define_singleton_methodrb_define_methodrb_define_module_underrb_define_class_underrb_eRuntimeErrorrb_include_modulerb_gc_register_addressrb_hash_newlibruby.so.1.8libpthread.so.0librt.so.1libdl.so.2libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.3.4GLIBC_2.4GLIBC_2.2.5/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64*@ti Lii Xui bui b8= @= H= H= ? ? ?  ? ? ?  ? !? #? '? +? .? 3? 8? 9? :? D@  @ (@ 0@ 8@ @@ H@  P@  X@  `@  h@ p@ x@ @ @ @ @ @ @ @ @ @ @ @ @ @ @  @ "@ $A %A &A (A ) A *(A ,0A -8A /@A 0HA 1PA 2XA 4`A 5hA 6pA 7xA :A ;A <A =A >A ?A @A AA BA CA EHH) HtH5) %) hhhhhhhhqhah Qh Ah 1h !h hhhhhhhhhhqhahQhAh1h!hhhh h!h"h#h$h%h&h'qh(ah)Qh*Ah+1h,!h-h.h/h0h1h2h3h4h5h6%]& D%U& D%M& D%E& D%=& D%5& D%-& D%%& D%& D%& D% & D%& D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%% D%}% D%u% D%m% D%e% D%]% D%U% D%M% D%E% D%=% D%5% D%-% D%%% D%% D%% D% % D%% D%$ D%$ D%$ D%$ D%$ D%$ D%$ D%$ D%$ D%$ D%$ DH=$ H$ H9tHF" Ht H=y$ H5r$ H)HHH?HHtHe" HtfD=5$ u+UH=J" Ht H= d $ ]wH# @H5# H5# ATIUHSHHHt$Ht$gH5# LHeH5# HHSHH[]A\HD@HHcHttLGHWI9tGLH1SHH9tGHHt HH ڃuHt HH [DHH9uL)HHrH8SHH dH%(HD$1HHD$H" H@Ht@ u!HHL$dH3 %(u]H [H=H|$11HH|$HD$Ht$HT$H3" HxtHD$Hff.@H 11ff.AUATUSHHHHHH{7H5! HIEH5! HI3H=HTLHYH5HLHHH_H5ZH[HHHH5HH5/[H]A\A]'H H85H H8%Hy H8H H8H H8S"HHH9CuHC [u:HtLHt;HtYtHH{H5HHR H81@H H8H H8H H8H- H8H H8@SHSHt&HC HHHH=r[@[ÐAVAUIATIUHSHH dH%(HD$1Mt A8Htut?u H{HH$Ld$H\$Ht#H}Lu 9LHAHc}HD$CHL#HL$dH3 %(ujH []A\A]A^fDLH$fHuHHD$D1HIH1H5HH$D@SHu#I1ɺH={ HNHfDHH$tHH=wff.HuÐHHff.fAWMAVIAUIATIUSHHMLHLLHHt+H;uAHHEH[]A\A]A^A_f.HHtߋEtH~&t1Tu@H H[]A\A]A^A_fDu HM HQ 1H=AUATUSH(H|$H|$H4$#HHHHHHtH([]A\A]fD IAHHT$H$1H@HBHtHT$HIHD$ HD$ H LJHHxHD$p1RHD$(HXHHT$(HBXZAt`HDHuAIH8DHHHEeH$Ht$1[I1ɾH= HHzf.ATIUHSHHu%HC LHBHHC H[]A\HfDU1HSH1HHHL$dH%(HD$81HD$D$HD$ H HD$0DHHHD$(HHt$HD$HH=y HqHT$8dH3%(uHH[]DSH0dH%(HD$(1~nHFHHD$HL |$HcHD$ {HsH;HD$*HHH=H$HHHT$(dH3%(u%H0[H H5 H81PSHHH1HH QHHH.u H[DH=a HH[HFfDAWAVAUATUSHH $HH $HHt$HLD$(dH%(H$ 1HH|$HIaH|$HHHHD$HLxHc@IL|$`Hx HHH9}H)HHD$xL$H$HD$pHD$HD$hHD$HD$`HD$H$HL$hL1HD$ HD$HHD$0L$HL$LLl$pHT$Ht$HD$x Ƅ$tIHD$xH=  H)HL$xIt%LD$`LL)H9w'H|$hH|$HI)HLHH"HT$xLHL|$`HLIHL9T$hH|$HLGLD$ LHHL$(HIHD$HI*H@ LL IĨHt=HHH<? M|$MWL|$`HL9`H$ dH34%(HH []A\A]A^A_@HD$hH-ID$ HH0ItID$ H@HD$HH{H|$0XHT$HHjHBHl$`IHD$h@A H|$ 2H I)1RL%S L|$`ZLH+HHT$HHHH DLH|$HHH)mL|$`HHL$HD$hHD$`HD$`LD$xHL$pHT$hHL$Ll$pHD$x HL$HT$HD$vH HD$`E11LH|$HHH)H%DHLuL|$`H1HLLLD$@HL$8HL$8LD$@H|$htnMfDLHHH)OL|$`DLHHH)/f.HLLHL$8HL$8HIL|$`|HL$(E1HǾvHH HHt2u.<t*? u Hx~yH@ H8HH|$HDH|$HHHu HdH|$HU=v2H|$HHtLHMaHD$HH|$_D$_HD$HL5HF H5H81-HAUATAHUHSH8dH%(HD$(1IQHLL$LHLD$1DHj1HD$HD$ H<$t LzHhH|$AHt'@HHHT$HH9HL$Ht_HHT$HL$ H)H9Hl$ HH4$HE1HHt$(dH34%(H8[]A\A]HHT$HL$ DHHT$pHL$ E1HT$ Ht$HHu#H|$fkHHL$ HT$HHHHff.HE111ҾATUSGH~^HGIH(H;1ILHH{HS CPHCSHHCHuHC[]A\H;11IؾH= 1HH5@"H= 1HH5,H= 1HfH5H-K HH5 HUHUHH5HS HUHH5H) H- HH5H HUHUHH5H qH5 H= H H5 H= H5 H= H5 H= H5 H=p H= H= HI |H=- H. )D1HHH  HH5 []HHdowncase#<: , >Iconv expected (%s)...iconv_closeinvalid encoding %s("%s", "%s")closed iconvbug?(output length = %ld)12IconvopeninitializeFailuresuccessfailedinspectInvalidEncodingIllegalSequenceInvalidCharacterOutOfRangeBrokenLibrarycharset_mapwrong number of arguments (%d for %d);0H\p@P$`| `,0 0T0tPpTzRx $FJ w?:*3$"DHp\` p\X,TYFDD L0w DAB ayFPP AG0K AD $88OFBA A(G0 (M DBBL tA_ A ,?Ej I F@L,BBE D(D0GP 0A(A BBBG 8:A `"DQ A (t#TN`@BEE E(D0A8G@~ 8A0A(B BBBK g 8A0A(B BBBG DBBA A(DPv (A ABBJ GXp`bXAP(PJFDD k ABD (tEFI` AAA DED@ AA htZEu F NT`BBB B(A0A8G L@LBx 8A0A(B BBBE 8FBG D(D` (A ABBI @40LFAA \ ABI jAB(hEHD HAGNUH=  *n  38= @= o`   @ ( ooo$oP= @P`p 0@P`p 0@P`p 0@P`pGA$3a13 GA$3p10673GA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFYGA+GLIBCXX_ASSERTIONSiconv.so-1.8.7-16.el8.x86_64.debugz}7zXZִF!t/C]?Eh=ڊ2N.]@F@N}eql,h>L2}sF%Bm}Vjq ]3`V7q:~<44Ft?N>Xm~`c#1lб*f8%V oڧGbOm$= [-]V|y szn; qˢnIe2B|@p2D:XeúeI{`/U ^4rh)6SEIݑY 9|1]c$*A™'%Ê8Y;.0E{_g  KoIg>ogLBh̒ϕE3%tm5a0J[=%V!hauW.b@h)Ojc6 |VwVЛ:zc`B$C}(#8Ӑ]'fipl>b.xXLJOGaUG_3KD+#@Q·b0nD; fN=EWs*PrzN椇cWT~\P2S,K>4^]}xy䒄 ]5ޏȯsf-vZJ p6 ia`w!5Wi,#b:*Se#VDyB,:SKF3… zJh}'`a@<)yx93k'Fpřk{V/aR8f=vp IK#LCb\ig>8utrt5`#:4[G']ح#igYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``4( 0 8o$$Eo`T^B(hc00npw  }33 23380505 6 6:: 8= 8=@= @=H= H=P= P=0? ?@ @A AP B`AH D(@DH+PK|]VEB{{x86_64-linux/digest.hnu[/************************************************ digest.h - header file for ruby digest modules $Author: shyouhei $ created at: Fri May 25 08:54:56 JST 2001 Copyright (C) 2001-2006 Akinori MUSHA $RoughId: digest.h,v 1.3 2001/07/13 15:38:27 knu Exp $ $Id: digest.h 11708 2007-02-12 23:01:19Z shyouhei $ ************************************************/ #include "ruby.h" #define RUBY_DIGEST_API_VERSION 2 typedef void (*rb_digest_hash_init_func_t)(void *); typedef void (*rb_digest_hash_update_func_t)(void *, unsigned char *, size_t); typedef void (*rb_digest_hash_finish_func_t)(void *, unsigned char *); typedef struct { int api_version; size_t digest_len; size_t block_len; size_t ctx_size; rb_digest_hash_init_func_t init_func; rb_digest_hash_update_func_t update_func; rb_digest_hash_finish_func_t finish_func; } rb_digest_metadata_t; PK|]vex86_64-linux/dl.sonuȯELF>?@@8 @(\(\ XkXk!Xk! pkpk!pk!00888$$\\\ Std\\\ Ptd<<<$$QtdRtdXkXk!Xk!GNUpTį^zmCe H "1DB(JI4J PeoI 1 eghjloqrstuvxyz|}rJD-ADw AnxؐhY=vTF#I\^ËV>.: [=Jra u4S$-6B-30vl~]'[|#OZw[>[fWXu#`MVXls\A]=_^E0 *l/xEN_ͻVD`$ן^ gk#TM,%R=#QbGBEr&ׂV>s?uz鹩]uh|rvhJџ qqX v7SFy) <= &%l/YL : kaH\6Aw2k_x DvKt} RU:9Ka  0$Ty, LF"(.d  ;  ) 5  DHv!k 1  ]  kPv! /> `k  AM 1  qXv! 4l @ &^ V R 5  0U @  P ) jF i - n P?8 0'kK 0  p3 A2_ @  ; PDv  @ V p  0]\ 2 @8v!y ] 1o 0 hv!`v! P PB% e -0  Hs!] P$g @D@v! PAM  @t `( pv!  a P,! 0 ( p 3 Hs! ' 0__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizedlfreeruby_xfreerb_io_to_ptrrb_io_taint_checkrb_io_check_closedrb_dlptr_newrb_dl_dlopenrb_securerb_cDLHandlerb_class_new_instancerb_dl_mallocrb_dlptr_mallocrb_num2longrb_dl_strduprb_string_valuerb_check_safe_objrb_dlsym2csymrb_int2inumrb_assoc_newrb_hash_asetrb_scan_argsrb_block_given_prb_hash_arefrb_eDLErrorrb_raiserb_block_proc__sprintf_chkrb_dlsym_newrb_eDLTypeError__stack_chk_failrb_tainted_str_new2rb_float_newrb_check_typerb_ary_entryrb_funcall2rb_dlptr2cptrrb_eArgErrorrb_num2intrb_fix2intdlmallocruby_xmallocrb_str_to_ptrmemcpydlreallocruby_xreallocdlstrdupstrlenstrcpyrb_cDLPtrDatarb_obj_is_kind_ofrb_check_string_typerb_check_safe_strrb_internrb_funcalldlsizeof__ctype_b_locstrncpystrtolrb_string_value_ptrrb_ary2caryrb_check_array_typerb_ary_to_ptrInit_dlrb_define_modulerb_eStandardErrorrb_mDLrb_define_class_underrb_hash_newrb_define_constrb_define_module_functionInit_dlptrInit_dlsymInit_dlhandlerb_cStringrb_define_methodrb_cArrayrb_cIOrb_dlptr_null_pdlptr_freerb_data_object_allocrb_dlptr_to_irb_dlptr_free_setrb_dlptr_free_getrb_dlptr_to_srb_tainted_str_newrb_bugrb_dlptr_to_strrb_dlptr_define_data_typerb_to_idrb_dlptr_define_structrb_dlptr_define_unionrb_dlptr_get_data_typerb_dlmem_eachst_foreachrb_yieldrb_Integerrb_dlptr_sizest_deleterb_dlptr_inspectrb_class2name__snprintf_chkrb_str_new2rb_cFixnumrb_cFalseClassrb_cNilClassrb_cTrueClassrb_cSymbolrb_ary_new3rb_dlptr_asetmemsetrb_id2namerb_eNameErrordlptr_initst_insertrb_dlptr_new2st_lookuprb_dlptr_ptrrb_dlptr_refrb_dlptr_to_arrayrb_ary_newrb_ary_pushrb_eTypeErrorrb_dlptr_eqlrb_dlptr_cmprb_dlptr_plusrb_dlptr_arefrb_dlptr_minusrb_cObjectrb_define_alloc_funcrb_define_singleton_methodrb_define_module_underrb_mDLMemorySpacest_init_numtabledlhandle_freedlcloserb_dlhandle_enable_closerb_dlhandle_disable_closerb_dlhandle_closerb_dlhandle_to_irb_dlhandle_s_allocaterb_dlhandle_initializedlerrorrb_eRuntimeErrorrb_ensurerb_dlhandle_to_ptrrb_dlhandle_symdlsym_freerb_dlsym_s_allocaterb_dlsym_to_ptrrb_dlsym_initializerb_s_dlsym_char2typerb_dlsym_namerb_dlsym_protorb_dlsym_cprotorb_str_cat2rb_str_catrb_dlsym_inspectrb_dlsym_to_i__errno_locationrb_thread_currentrb_thread_local_asetrb_thread_local_arefrb_dlsym_callrb_secure_updaterb_cDLSymbollibruby.so.1.8libdl.so.2libpthread.so.0librt.so.1libcrypt.so.1libm.so.6libc.so.6_edata__bss_start_endGLIBC_2.2.5GLIBC_2.3GLIBC_2.14GLIBC_2.4GLIBC_2.3.4/opt/alt/openssl/lib64:/opt/alt/ruby18/lib64  ui    ui   ii  ' ii 2 ui  ti < Xk!@`k!`@hk!hk!m!em!m!hm!m!sm!vm! m!om!im!fm!m!n!n!|n!n! n!(n!0n!8n!p@n!Hn!wPn!Xn! `n!hn!pn!xn!n!jn!qn!n!mn!yn!n!2n!}n!5n!n!n!n!n!n!nn!o!>o!o!Ao! o!x(o!0o!8o!D@o!gHo!Po!IXo!L`o!uho!po!~xo!Mo!to!o!o!Qo!o!o!ko!o!Xo!o![o!o!\o!{o!o!dp! p!(p!0p!8p!@p!vHp!Pp!Xp!`p! hp! pp! xp! p!p!lp!p!p!rp!p!p!p!p!p!p!p!p!p!p!q!q!!q!"q! q!#(q!$0q!%8q!&@q!'Hq!(Pq!)Xq!*`q!+hq!,pq!xq!-q!.q!/q!0q!1q!3q!4q!5q!6q!7q!8q!q!9q!:q!nq!;q!<r!=r!r!?r!@ r!(r!0r!B8r!C@r!EHr!FPr!Xr!G`r!Hhr!Jpr!xr!Kr!~r!Nr!Or!Pr!r!zr!Rr!Sr!Tr!Ur!Vr!Wr!r!Yr!Zr!s!s!\s!]s!^ s!_(s!`0s!a8s!b@s!cHH;!HtH5h?h@hAhBhChDhEhFhGqhHahIQhJAhK1hL!hMhNhOhPhQhRhShThUhVhWqhXahYQhZAh[1h\!h]h^h_h`hahbhchdhe%}6!D%u6!D%m6!D%e6!D%]6!D%U6!D%M6!D%E6!D%=6!D%56!D%-6!D%%6!D%6!D%6!D% 6!D%6!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%5!D%}5!D%u5!D%m5!D%e5!D%]5!D%U5!D%M5!D%E5!D%=5!D%55!D%-5!D%%5!D%5!D%5!D% 5!D%5!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%4!D%}4!D%u4!D%m4!D%e4!D%]4!D%U4!D%M4!D%E4!D%=4!D%54!D%-4!D%%4!D%4!D%4!D% 4!D%4!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%3!D%}3!D%u3!D%m3!D%e3!D%]3!D%U3!DH=Q3!HJ3!H9tH-!Ht H=!3!H53!H)HHH?HHtHu/!HtfD=2!u+UH=j/!Ht H=*!d2!]wUHSH>HXHbH;HtH11[]H[]ff.UHATISH-!L[A\H]ff.UHSHHt!HHH5-!H[]fHxHUHSH}HHuH}HEHxHX\H,!HHH[]UHAVAUE1ATSHHH1!I1fDHcL9$t'HH uIHPIu[A\A]A^]ÐKLIHPI8LHH=3!HIu벐UHAWAVAUIATASH0HdH%(HE11HLL8DHiHDž8t$HDž8fDE1E1f1fDHLc-LI"LHH=2!HHHH uHm+!H5H81@AAf.AAoAAWAA?AA'AAAAH8fDH8H0HILL@H(H(HH=F1!LHAEH L1H0LHPKI DH}.!HDI>ID@HMJDICT=uHED H(D[A\A]A^A_]I>11IpfDI>I|f.I>IHcaI>IHHsfAZ]DIIHEE>fDI>IH#E12H'!H5H81UHAUATSHdH%(HE1HEH` HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE7H*HHH=.!HHHHǾ 1HHILII|$|HIt$HH`HbHLH5_+!:HrHMdH3 %(u&H[A\A]]H&!H5H81Ha'!H5H81pUHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHOH=,!HHHHǾ V1H,HILI,I|$|HIt$HH`HHLH5)!HHMdH3 %(u&H[A\A]]H>%!H5H81H%!H5}H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHH=H+!H`HHHǾ 1HHI|LII|$|HIt$HH`H"HLH5(!H2HMdH3 %(u&H[A\A]]H#!H5gH81MxH!$!H5H810UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEWHJHHH=)!HHHHǾ 1HHILII|$|HIt$HH`HHLH5&!ZHHMdH3 %(u&H[A\A]]H!!H5H81H"!H5=H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHoH=(!H HHHǾ v1HLHI<LILI|$|HIt$HH`HHLH5$!HHMdH3 %(u&H[A\A]]H^ !H5'H81 8H !H5H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEH HHH=h&!HHHHǾ 1HHILII|$|HIt$HH`HBHLH5?#!HRHMdH3 %(u&H[A\A]]H!H5H81mHA!H5H81PUHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEwHjHH/H=$!HHHHǾ 61H HILI I|$|HIt$HH`HHLH5!!zHHMdH3 %(u&H[A\A]]H!H5H81H!H5]H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHH=(#!H@HHHǾ 1HlHI\LIlI|$|HIt$HH`HHLH5!HHMdH3 %(u&H[A\A]]H~!H5GH81-XH!H5H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE7H*HHH=!!HHHHǾ 1HHILII|$|HIt$HH`HbHLH5_!:HrHMdH3 %(u&H[A\A]]H!H5H81Ha!H5H81pUHAUATSHdH%(HE1HEH`1HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHRH=!HHHHǾ Y1H/HILI/I|$|HIt$HH`HHLH5!HHMdH3 %(u&H[A\A]]HA!H5 H81H!H5H81UHAUATSHdH%(HE1HEH` HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHH=H!H`HHHǾ 1HHI|LII|$yHIt$HH`H"HLH5!@HEdH3%(u&H[A\A]]H!H5jH81P{H$!H5H813UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEWHJHHH=!HHHHǾ 1HHILII|$yHIt$HH`HHLH5!Z@HEdH3%(u&H[A\A]]H!H5H81H!H5@H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHoH=!H HHHǾ v1HLHI<LILI|$yHIt$HH`HHLH5!@HEdH3%(u&H[A\A]]Ha!H5*H81;H!H5H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEH HHH=h!HHHHǾ 1HHILII|$yHIt$HH`HBHLH5?!@HEdH3%(u&H[A\A]]H!H5H81pHD!H5H81SUHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEwHjHH/H=!HHHHǾ 61H HILI I|$yHIt$HH`HHLH5!z@HEdH3%(u&H[A\A]]H!!H5H81H!H5`H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHH=(!H@HHHǾ 1HlHI\LIlI|$yHIt$HH`HHLH5!@HEdH3%(u&H[A\A]]H!H5JH810[H!H5H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE7H*HHH=!HHHHǾ 1HHILII|$yHIt$HH`HbHLH5_!:@HEdH3%(u&H[A\A]]H !H5H81Hd !H5 H81sUHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHOH=!HHHHǾ V1H,HILI,I|$yHIt$HH`HHLH5!@HEdH3%(u&H[A\A]]HA !H5 H81H !H5H81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHH=H!H`HHHǾ 1HHI|LII|$yHIt$HH`H"HLH5!@HEdH3%(u&H[A\A]]H !H5jH81P{H$ !H5H813UHAUATSHdH%(HE1HEH`1HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEZHMHHH=!HHHHǾ 1HHILII|$yHIt$HH`HHLH5 !]@HEdH3%(u&H[A\A]]H!H5H81H!H5CH81fDUHAUATSHdH%(HE1HEH` HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHoH=!H HHHǾ v1HLHI<LILI|$}HIt$HH`HHLH5 !fZ@HEdH3%(u&H[A\A]]H]!H5&H81 7H!H5H81ff.@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHHH=X !HpHHHǾ 1HHILII|$}HIt$HH`H2HLH5/ ! fZ@HEdH3%(u&H[A\A]]H!H5vH81\H0!H5H81?ff.@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEWHJHHH= !HHHHǾ 1HHILII|$}HIt$HH`HHLH5!ZfZ@HEdH3%(u&H[A\A]]H!H5ƾH81H!H5<H81ff.@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHH_H=!HHHHǾ f1H<HI,LIHMdH3 %(uH[A\A]]Ð dH H5ɪH81HU H5H81@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE'HHH߽H=x H萻HHHǾ 1H輺HI謺LI輼I|$pHIt$HH`HRLHH5O *HǨu#莺HMdH3 %(uH[A\A]]Ð[贺H] H5H81lH H5nH81T@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEwHjHH/H= HHHHǾ 61H HILI I|$pHIt$HH`HLHH5 zHǨu#޸HMdH3 %(uH[A\A]]Ð諽H H5iH81輷H H5H81褷@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEǶH躶HHH= H0HHHǾ 膹1H\HILLI\I|$pHIt$HH`HLHH5 ʸHǨu#.HMdH3 %(uH[A\A]]ÐTH H5H81 HE H5H81@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEH HHϸH=h H耶HHHǾ ַ1H謵HI蜵LI謷I|$pHIt$HH`HBLHH5? HǨu#~HMdH3 %(uH[A\A]]ÐK褵HM H5 H81\H H5^H81D@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEgHZHHH= HдHHHǾ &1HHILII|$pHIt$HH`H蒾LHH5 jHǨu#γHMdH3 %(uH[A\A]]Ð蛸H H5YH81謲H H5H81蔲@UHAUATSHdH%(HE1HEH`1HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE躱H譱HHrH= H#HHHǾ y1HOHI?LIOI|$sHIt$HH`HLHH5 轳HǨu&!HMdH3 %(uH[A\A]]@DH H5H81H5 H5H81@UHAUATSHdH%(HE1HEH` HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHHH迳H=X HpHHHǾ Ʋ1H蜰HI茰LI蜲I|$pHIt$HH`H2LHH5/ HǨu#nHMdH3 %(uH[A\A]]Ð;蔰H= H5H81LH H5NH814@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEWHJHHH= HHHHǾ 1HHIܮLII|$pHIt$HH`H肹LHH5 ZHǨu#辮HMdH3 %(uH[A\A]]Ð苳H H5IH81蜭H H5H81脭@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE觬H蚬HH_H= HHHHǾ f1H<HI,LIH81$@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEGH:HHH= H谪HHHǾ 1HܩHI̩LIܫI|$pHIt$HH`HrLHH5o JHǨu#让HMdH3 %(uH[A\A]]Ð{ԩH} H59H81茨H H5H81t@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE藧H芧HHOH= HHHHǾ V1H,HILI,I|$pHIt$HH`H²LHH5 蚩HǨu#HMdH3 %(uH[A\A]]Ðˬ$H H5H81ܦH H5ޗH81Ħ@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHڥHH蟩H=8 HPHHHǾ 覨1H|HIlLI|I|$pHIt$HH`HLHH5 HǨu#NHMdH3 %(uH[A\A]]ÐtH H5ٔH81,He H5.H81@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE7H*HHH= H蠥HHHǾ 1H̤HI輤LI̦I|$pHIt$HH`HbLHH5_ :HǨu#螤HMdH3 %(uH[A\A]]ÐkĤHm H5)H81|H H5~H81d@UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE臢HzHH?H= HHHHǾ F1HHI LII|$pHIt$HH`H貭LHH5 芤HǨu#HMdH3 %(uH[A\A]]Ð軧H H5yH81̡H H5ΒH81贡@UHAUATSHdH%(HE1HEH`1HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEڠH͠HH蒤H=+ HCHHHǾ 虣1HoHI_LIoI|$sHIt$HH`HLHH5 ݢHǨu&AHMdH3 %(uH[A\A]]@ dH H5ɏH81HU H5H81@UHAUATSHdH%(HE1HEH` HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE'HHHߢH=x H萠HHHǾ 1H輟HI謟LI輡I|$|HIt$HH`HRHLH5O *H肤HMdH3 %(u&H[A\A]]H H5H81}訟HQ H5 H81`UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE臝HzHH?H= HHHHǾ F1HHI LII|$|HIt$HH`H貨HLH5 芟HHMdH3 %(u&H[A\A]]H. H5H81ݜH H5mH81UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEHڛHH蟟H=8 HPHHHǾ 覞1H|HIlLI|I|$|HIt$HH`HHLH5 HBHMdH3 %(u&H[A\A]]H H5WH81=hH H5͊H81 UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHEGH:HHH= H谛HHHǾ 1HܚHI̚LIܜI|$|HIt$HH`HrHLH5o JH袟HMdH3 %(u&H[A\A]]H H5H81蝙ȚHq H5-H81耙UHAUATSHdH%(HE1HEH`HhHEHEHpHEHE HxHEHE(LEHEHE0LMHEHE8HEHE@HEHEHHEHEPHE觘H蚘HH_H= HHHHǾ f1H<HI,LI6qIAFHEEuHHtvHtp<tl?tw"Hҟ LH0oH"LnIE HKIGL;}tPILHEkIŨxLkIHLmI}nKIGL;}uHL[A\A]A^A_]fuKfDH=wZm1LH1 lIH LH0nHt8"LFmIF HK(DHܞ H5[H81[jDfDUHAWIAVAUATSH8dH%(HE14kEoDEE11IH 5\McI9E1Kt7HDWC47V0HcH>HuHHGl,E9HMdH3 %(HHe[A\A]A^A_]HuDHuDHuHHHuHHCHuHHj@HH\fDAEHIDGKD7ADALAT$HBDWuHcMcHHHHH)HHH9tHH$H9u%t H)HLLT$LDEILMLL]hL] 1HBjH jZDELMKfE1ۺY1lHu @H5WH81giff.UHHH}HujHlHwgDUHAWAVIAUAHATSHdH%(HE1iHfPHÅM1HgIĨHHH<?"HZHcH>L-Q LIukHu0H=VkIEwEuE1VHnHtNHtH<tD?Nu1fZHC IEM9ILHETftH DH5VH81eDHHL$Lt$IAL(ACP`AHLkIcHI>jIE~EuE1bHt>HVHL<D?  $1fClIEM9ILHEOetHsjfCl@CE1ELkIcHI>iIEEuE1YHtjHH|<t?tBa@CIEM9OILHEdt/KfDADGH' H5SH81cfDAIuLkIcHI>hIEEuE1^fHt>HH<?  |CIEM9mILHEctHhC@E)LkIcHI>DhIEEuE1cHt>HH<? F =KIEM9ILHEbtHhK@Ah~AiAl1UAcHLkIcI>ggIEAEuE1WfHt:HH< ? ~ tyC,IEM9ILHEbtHAgC,Hԕ H5SQH81SaH(bHbHbfDHa>bHw H5PH81`fDUHAUIHPATSH]HH(dH%(HE1zat~uHcHUL8ZdIĸMt5H& HuLbHtLH ƒuIu>fDHMdH3 %(u8H([A\A]]fDHUL1cIDIUH H ט H PH5ј H5bH ˘ H H5Ř H5H HH H JH5 H5|H HH H `H5 H5H HH H VH5 H5H HZH H H= H=NH5o H5Hq HH k H ĸH=m H=VH H5P H5HR HH L H űH=N H=WH58 H5H: HH 4 H ͪH=6 H=_H5 H5H" HH  H գH= H=gH5 H5 H HH  H ݜH= H=H5 H5H HH H H= H=H5ؗ H5)Hڗ HH ԗ H H=֗ H=H5 H51H— HÉH H H= H=DŽH5 H5YH H H H ]H= H=~H5 H5H HS|H H zH= H=WwH5x H5xHz HuH= H=pH5n H5?rHp HnH=z H=jH < H sH5V H5kHX H9hH=b H;H ( H mH5B H5IKHD HH " `ZH;H5)KH`ZH;H5KHu`ZH;H5KHY`oZH;H5JH=`SZH;H5JH!`7ZH;H5JH`ZH;H5JH_YH;H5JH_YH;H5JH_1YH;H5JH_H=J\H;H5JHz_H;HȎ H5lJ?^H;H`bH5_J$^H;HEbH5=J ^H;HzaH52J]H;H, H5M]H;H H5 J]H;HIH5I]1]1\1]H= HIH5I]H;H5IH|^H 1H H5{HH8\H Hό H5YHH8k\H 1H H5:HH8H[]F\fDU"HSHH[HC H8H[]Hff.UHATIS\@ZfL1H HH@@ @0ZHHCHCHCC HC(HC0HC8[A\]ÐU"HSHHFZHC H8H[]4W@UHATI"SHZH[ LYZHC[A\]ff.U"HSHHYHC HGH5JHxH[][DUHAUI"ATAHSHHdH%(HE1zY1HMLHFDH[ ^WtJuOH}@u+fWH;Hc[HUdH3%(u4H[A\A]]Ð+\fH;xXH=I1VcWUHAUI"ATAHSHHdH%(HE1X1HMLHEDH[ VtJuSH}@u+VH;HcZHUdH3%(u8H[A\A]]Ðk[fHs8H;ZH=I1UVff.@UHAWAVLuHMAULMMATIHHSHHdH%(HE1U"LWMl$ qXH}@:UELVH} WH}LgE~/A\$E1 DH}ILAUHYIGL9uEI}Ee Ee0AE4HtVIcHYI}IEHtVH<YI}(IEHtVIc}0HYLIE(WHE:YIAD$E1HE%@IEHBID$L9eIH}LkTIU(HN4XHsJ IIEB IHCDBtHHHDBuIHI)I@HH%H)HHH9tHH$H9u3LL$LHMILELGSLEHM1 HBIMHMUHMID$L9efD;I}8HEHxWIE8z{XEH}DH}@tvQXHI}AE IE0Ht TIEI}(Ht TIE(HMdH3 %(uIHe[A\A]A^A_]@RHH)HLHˇ H5EH81QSH H5EH81Qff.fUDWHHdH%(HE1IcIHHH%I)HLH9tHH$H9uuVLD$IIA~DO1HH ILHHI9uLDUHUdH3%(uH)HL RUDWHHdH%(HE1IcIHHH%I)HLH9tHH$H9uuVLD$IIA~DO1HH ILHHI9uLDTHUdH3%(uH)HL HQU"HSHHRH[ H{Ht)Hcs THc{4H[H]H|?YSfHc{4H[]H|?7SUH=̋ 1H5HP]ff.UHSHHOHHRHRH[]ff.UHAVAUHMILMATLEHBSH dH%(HE1OttPH=B1BOfH}'SH};SHRLeHA6IE1wDH}RH}RHRHE1E1EH}RH}RH^RLeHAIH}1QIHt1L"PMm I}Ht IEHtI]Me8MuHUdH3%(|H [A\A]A^]RLeHHAzLQImQHQLeHHALE1|QI6Nff.@UHSHH4=HMHdH%(HE1MtEHEt%HHHS HJ8H]dH3%(u/H[]ÐHPHHEHC Hx8{LM@UHSHHdH%(HE1HHt.HE{PH= Hu1MHCHtH;H{HtNH{HtNH{(HtNHEdH3%(uH[]FMfDU"HAWAVAUATSHHdH%(HE1NLc M|$Mt$8M,$HHHH{2OAWHAVILh@HAU1ATKH HdMHUdH3%(udHe[A\A]A^A_]fDHq H8@H H8zHA H8jH H8ZH H8J Lff.UHATS@Ht@u@t? tfD1I!LLHƉ[A\]@NUHAWAVIAUAATLeSHH8dH%(HE1HEHEHE-N1HMMLEH>LDJuHEHEHEH}@(HN"HILLc AD$4AD$01L=>q@HudH34%(HEmH8[A\A]A^A_]fID$HcHHE:Hu1I<$HUIHLLKHA9\$0~ID$(L9,uIT$H A<0IcL>DID$HcHHED@? t LJH߾"nKHC H}H@!HHEHH}LpL`H@JIIM9LLHIN2KM9LJ<#1L)IAD$0MD$DH11H5>LT>A<WHcH>M$HcM4ITAtf.IӃHAMuIT$(L9,C0GIcL>DI $HcH<HTtHуHHuIT$(L;,IT$HPI9H'I $HcH<HTtHуHHuIT$(L;,utIfDHuHUHUHcI<$IHILII $HcH<HTtHуHHuIT$(L9,YIT$+I $HcH<HTtHуHHuIT$(L;,IT$SI $HcH<HTtHуHHuIT$(L9,DDIT$ID$HcHEGfDID$HcHHE,SKIIHLLH:HLkHy H5)9H811E@H>F4?FuHHtrHtaHtOt>H{HLH0EHH58HH4y H81DHz H8Hz H8Hy H8Hz H8Hx H8fDU"HSHHdH%(HE1GHC H0Ht*H={ HEt>HEdH3%(uAH[]ÿHuHH=C Hu1 EfDHtH EUHAWIAVIAUIATISH(dH%(HE1GMtAH= HULYCtUH]HtKHtEMt"H#FHC LhHMdH3 %(HH([A\A]A^A_]fD@EfL1H w H@@ @0HEELEHHM MhI@I@A@ Mp8I@(I@0 GYCff.@Hv HHHH8C@U"HSHH&EHC 11HH8H[]Cff.fU"HSHHDH{ H1[1]CUHAWAVAUI"ATAHSHH8dH%(HE1DL{ H]1LEHLDH(1sB"HDH}D @bBkCIŅCACL5r81HE@A0wJDIcL>DIHHHHUTCLHEHUHBDHCH9]t>HfIHu H<1{BLHpEHCH9]ufDHUdH3%(LH8[A\A]A^A_]IHLC>fDI_8HI_8ALHI_8AIHI_8AHH{I_8AFHhI_8ADHUA_8ACF@IH=21??fDUHAWAVAUATSH@HA։Eu%C@H6@HcH>AE15@HEAEL-7ED}[KcDL>H;11H?HDH}ABE9uHEH[A\A]A^A_]H;H=HHc;Hl=HH;HS=HfDfHZCBHvfDfHZCAHVfDH;HH?H[A\A]A^A_]LH[HA\]=ff.UH+HSHMLEH(dH%(HE1<tSuqH}@u4HC HH[]Hn H5q/H81%;DUHATIS;LH;H9[A\]HÐUHATIS;LH;H)H[A\]:UHAUIATSHHT;IIE Lh8t$HHLI<1H)[A\A]]HUHAWAVHMLEAUATSHH)H(dH%(HE1HEHE:H}@H>H}H@@t?t $q>"HIc@E? t 2HEHHHEp>HuH?I8HcH4HLt@H΃HHuIH(L9$ IH HJL9AHfI8HcH4HLt@H΃HHuIH(L;$uDIfI8HcH4HLt@H΃HHuIH(L;$IH [fI8HcH4HLt@H΃HHuIH(L;$QIH H fI8HcH4HLt@H΃HHuIH(L;$DfDIH@A@0Ip(L;&HH HH9HPL9duHIHI8IH4vD1)6HETI8IHHHNjHHi H5Y+H81/6LHj H5)H816H룾F11_uHHtZHtIHtlt[H{l9LH6HH5)HHj H815Hj H8Hk H8Hi H86H{k H8Hwj H8fUHAUIATSHH5IIE Lh8t$HHLJ4+1H)[A\A]]6fDH(9HUH5O)HAUATSHL%j Hh I<$H^:Hi H5HH9H;HVH5(8H;H[H5d(O8H;H5h H5(48H;1HPh H51%8H;1Hh H5(8L-5h H;1H5#L7H;1LH5x(7L-vi H;1H5c(L7H;1LH5P(7H;1Hh H5;(7H;Hh H5&(s7H;HIg H5!'X7H;H~h H5'=7H;1Hh H5'%7H;HKi H5' 7L-g H;H5'L6H;LH5'6H;Hh H5'6H;Hg H5m'6H;HEh H5T'6H;Hbg H5J'i6H;H?h H57'N6H;1Hg H5 '66H;Hf H5 '6H;Hg H5&6L-g H;H5&L5H;LH5&5I<$H5&6H,f H 5H;H5&Hm a7H;1He HH5&[A\A]]6f.DHHtOtW uDHH5U"HSHH4HC @ H[]ff.@U"HSHH3HC @ H[]ff.@U"HSHH3HC @H84H[Hc]e0DU"HSHHF3H{ H[]70UHSH2fH d 1HHHde H8T2HHCH[]ff.UHAUATLEIHfSH]HH(dH%(HE10 ^E1H}H}@s5L2IHL"@2I\$ H;HtSt C L+HCq4HMdH3 %(H([A\A]]fDH2H}I@_/LX2IH_4HQHH|d H5"H81.H}t9H1I@Hb H=bc LLW09fE1K2H=(1./U"HSHH0H{ H1[]/UHAWIAVLuAUAATISH]H(dH%(HE11DILHAL1E1.H}HtL/H},.L0Hþ"LD0ID$ PH8H2IHt1LHL2HMdH3 %(uuH([A\A]A^A_]D2HtHb HH5&H81 -H.H}-H/I,Hb H5&H81,-f.UH` H5&HATSHH]b H8%2Ha H5` HHL1H;Hb` H5F 10H;1Hma H5 0H;1Ha H50H;1HU` H5&/L% b H;H5%L/H;LH5 /H;1Hha H5%/H;1[H` A\H5%]/0CH&HcH>H%H4 H%H%HN%H9%HH%H^%H2%H %H %H$H$H$1ff.fUHSHHHHt2*H{HtH[]*fDH[]ÐUHATI S,fL1H @_ HH@F,HHCHCC[A\]U"HSHH,HC 1ҾH8H[]m+ff.fUHAWAVHMIHzAULmATLeMSMH(dH%(HE1;*H}-H}-HHH}u*IIuHLL-+!&H5%!L9(f;@t1HLHt&;tLL';@uϺH5 L'HL[A\A]A^A_]ÐH5 H'IuHSH5z GH=x D(IuIHt L%H5_ L%H53 ff.@U"HAVAUATSHt(HLk %HXIƍ{dHc+AvscMAuIHcHL'H1%XLZ'LH'HeH[A\A]A^]U"HSHH'H{ H[]$UHHATSHt:*A$D L%#a %HLH%[A\]fD%AfDUHIHSHHdH4%(Hu1HH9tHH$H9uHHL$HT$0HHU@C^H @HcH>fHHHHPHpppphp`pXpPpHp@p8p0LH(L@ H8AHPHH]dH3%(H]fHHHHPHpppphp`pXpPpHp@p8p0LH(L@ H8AHPf.HHHHPHpppphp`pXpPpHp@p8p0LH(L@ H8AHPfKfDHHHPHHpppphp`pXpPpHp@p8p0LH(L@ H8AHPDHHHPHHpppphp`pXpPpHp@p8p0LH(L@ H8AHPDHHHHPHpppphp`pXpPpHp@p8p0LH(L@ H8AHP\HHHPHHpppphp`pXpPpHp@p8p0LH(L@ H8AHPf1#@UHSHH ^ "HHH[]%fDUHAWAVAUIATAHSHHdH%(HE1$"H+$L{ AGPD9 HcH<#IAGxHcH#HAGxHcH#AOM_HÃHHcLL5SHMIfDBEIUCD+A<2 IcL>BpKfDBaK4H11#KHLXK<@"HK@AHI9t2F<2vDAEAxrH1L H@AD3LFA<2w7IcL>f.Af.IHHGM_AGLƃD9A;HDHc8L5eW HHLHIG0KfDyfDfD{fD[ HLZ6C HLY@?HHG@?HHGIHHGM_f.AM_qIcHHGM_[IHHGM_BfHHLX9HHLXH= DK<1H1H M HHH1TDHH}M DH5cH81fHHDžHDE1AH~jLMIǐBDHIH5zHc H>@K<11HH@AEID9LHHHHH]dH3%(H[A\A]A^A_]@K<HHK<'rfKH8HHTOKfZ'HH(#KHHKHH0HHfKH8HHKHc8HHHDžHH%HHCHfZ&HH=HHc%HH HqH11HUHHDžH:5H)HJ H1HIEB|0AtK4HTOK<LHL7H+H#IGHH5HI H81LL牅HHH5HJ H81(HH5LH|HtIGH5aHI H81LMHAH9IGH5'HH H81jHCJ H5H81R}LHHH J H5H81LHHHfH DH5nH81UHAWAVAUIATISHHHHބʉHHuAMte fH jH 1IH@HG H8dM&IMt LqIMnHbHIF&AFHL[A\A]A^A_]HL11[A\A]A^A_]HOG H5 H81ff.UHSHHHqF H0HuHu)H1[]DH߾";HC HH[]HF H5Q H81UDUH5N HAUATSHL%G H*F I<$HHE H5F HHH;HF H5 H;HG H5L-F H;H5LH;LH5ZjH;1HF H5 RH;1HfF H5 :L-;E H;1H5w LH;1H+E H5H;L1H5H;1HE H5HTF H;1H5aH= GI<$1HH5 H M I<$H[HH5 A\A]]HH11unsupported type `%c'rb_dl_callback_func_%d_%dtoo many argumentsto_ptrunexpected type '%c'an array is expected.type mismatchunsupported type01callDLDLErrorDLTypeErrorFuncTableRTLD_GLOBALRTLD_LAZYRTLD_NOWALIGN_INTALIGN_LONGALIGN_FLOATALIGN_SHORTALIGN_DOUBLEALIGN_VOIDPMAX_ARGdlDLSTACKdlopendefine_callbackremove_callbackstrdupsizeof0PfreeFREEtoo many callbacks are defined.callback function does not exist in DL::FuncTableunexpected type of the element #%d | x`H0xhXX}}PP(free)rb_dlptr_to_srb_dlptr_to_str11*wrong argumentstoo few/many arguments12rb_dlptr_initialize21unsupported type '%c'undefined key `%s' for %srb_dlptr_to_arrayrb_dlptr_s_mallocDL::PtrData was expectedPtrDatafree=to_i+@ref-@null?to_ainspect<=>==eql?+-define_data_typestruct!union![][]=sizesize=MemorySpaceMemoryTableeach#<%s:0x%lx ptr=0x%lx size=%ld free=0x%lx>the key must be a string or symbolLLLLLLLLKHxmi=i=iimiiimiimiiiiiiiiiiiiiiimi=i=iimiiimiim8XWDf1f fffffffffffffffffffffffffffffffffffffpjeO55aalaaTaaaaa3P`T{{D{{T{{{T{{Trb_dlhandle_newclosed handleunknown symbol "%s"Handlesymdisable_closeenable_closevoidvoid *charshortshort *intint *longlong *doubledouble *const char *(null), );void ()()%d arguments are neededunknown type '%c'.too many arguments.unknown type `%c'unknown argument type '%c'unknown type specifier '%c'DL::Symbol was expectedSymbolchar2typenamecprotoDLErrnolast_errorlast_error=x8XXh8H((hHhx(xxxx(xxx(phH8<8 4Dd}Dd}+4lD#unexpected type of argument #%dunknown type '%c' of the return value.unknown type `%c' of the return value.;$`@hP0$P  ` 0\@  8`d@  "@ $l % `' ) * P,H .t / `1 3 4$ p6P 8| 9 p; = >, @X 0B C E @G H4 J` PL N O `QS<ThpV XY[0]D^pp`bcPe fLhx0jkpmo(pTPrsu0wx0pz\|}p P80dЊ@pl@P8X@0<`@ЧP, Px ,`X|P4 T<@`p00DdP 0p`0p8@X` DPhPpzRx $pFJ w?:*3$"D``\h $pdDEC Ec H K  2EC BD_  MEH Ad N MEC I{ (EH DFW B ,,EC FEI A (\(mAC M A (lEC LV A (EC LV A (TEC LV A ( EC LV A (8< EC LV A (d EC LV A ($ EC LV A ( EC LV A ( EC LV A (EC LS A (@EC LS A (lhEC LS A (EC LS A (PEC LS A (EC LS A (8EC LS A (HEC LS A (t EC LS A (EC LS A (EC LP A (| EC LW A ($"EC LW A (P#EC LW A (|%EC LW A (&EC LW A ((EC LW A ()EC LW A (,+EC LW A (X,EC LW A ( .EC LT A (/EC LZ B (1EC LZ B (2EC LZ B (4 4EC LZ B (`5EC LZ B ((7EC LZ B (8EC LZ B (0:EC LZ B (;EC LZ B (<8=EC LW E (h>EC LZ B (@@EC LZ B (AEC LZ B (HCEC LZ B ( DEC LZ B (D PFEC LZ B (p GEC LZ B ( XIEC LZ B ( JEC LZ B ( `LEC LW E ( MEC LV A (L XOEC LV A (x PEC LV A ( @REC LV A ( SEC LV A ( (UEC LV A (( VEC LV A (T XEC LV A ( YEC LV A ( ZEC LS A ( l\EC LK A ( ]EC LK A (0 T_EC LK A (\ `EC LK A ( qϨ <tN*Il5ѣޘyRk* ls\[(Dj -t=o^p0LT=xDwD nL9Jw դ)nuiՓB Y4Ѭ[`[rP -.ѷ\a "GޞtV6K-kLʪRSVcCVmݧJ|t`6I  _y{GTGz%h۶b%GBV]QAtS_n(_ _AOKk="v 9o3YuU[:4mh#林(1[ca'+6Meã%_se;#k%:}6v`2ÁL_VU+7Ґ"MUO/{S[LBo o^3,֚ c@~E q˶%TKtbTN8ogf%WXn?3uY);?~G"@W UHL3\*xPzɤ\}U.w̽T`L-d/! e%?<)>ֻW?`tC+7iz#΄~jE5Վ![! PLadSMTP=6MAfE幁>`*Kn.c[ ԡpe=6)Gd6If{D{vAjl\)=J갅 ` }*L3&r a;r;pN,z ᘄU &IAJnͳe5FaiEx #FT&i*gYZ.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.note.gnu.property.init_array.fini_array.data.rel.ro.dynamic.got.got.plt.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88$o``( 0u 8obEo`!`!T""h^Bh)h) h22c 3 3pn99`w??_}P)P) `)`)`<<$AA \\ Xk!Xk`k!`khk!hkpk!pk0m!m`p!pH`s!Hs pvaHs dw$w+PK|]x86_64-linux/config.hnu[/* confdefs.h */ #define PACKAGE_NAME "" #define PACKAGE_TARNAME "" #define PACKAGE_VERSION "" #define PACKAGE_STRING "" #define PACKAGE_BUGREPORT "" #define PACKAGE_URL "" #define OLD_YACC 1 #define STDC_HEADERS 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRING_H 1 #define HAVE_MEMORY_H 1 #define HAVE_STRINGS_H 1 #define HAVE_INTTYPES_H 1 #define HAVE_STDINT_H 1 #define HAVE_UNISTD_H 1 #define __EXTENSIONS__ 1 #define _ALL_SOURCE 1 #define _GNU_SOURCE 1 #define _POSIX_PTHREAD_SEMANTICS 1 #define _TANDEM_SOURCE 1 #define HAVE_LONG_LONG 1 #define HAVE_OFF_T 1 #define SIZEOF_INT 4 #define SIZEOF_SHORT 2 #define SIZEOF_LONG 8 #define SIZEOF_LONG_LONG 8 #define SIZEOF___INT64 0 #define SIZEOF_OFF_T 8 #define SIZEOF_VOIDP 8 #define SIZEOF_FLOAT 4 #define SIZEOF_DOUBLE 8 #define SIZEOF_TIME_T 8 #define rb_pid_t pid_t #define rb_gid_t gid_t #define rb_uid_t uid_t #define HAVE_PROTOTYPES 1 #define TOKEN_PASTE(x,y) x##y #define HAVE_STDARG_PROTOTYPES 1 #define NORETURN(x) __attribute__ ((noreturn)) x #define NOINLINE(x) __attribute__ ((noinline)) x #define HAVE_DECL_SYS_NERR 1 #define HAVE_LIBCRYPT 1 #define HAVE_LIBDL 1 #define HAVE_LIBRT 1 #define HAVE_DIRENT_H 1 #define STDC_HEADERS 1 #define HAVE_SYS_WAIT_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRING_H 1 #define HAVE_UNISTD_H 1 #define HAVE_LIMITS_H 1 #define HAVE_SYS_FILE_H 1 #define HAVE_SYS_IOCTL_H 1 #define HAVE_SYS_SYSCALL_H 1 #define HAVE_FCNTL_H 1 #define HAVE_SYS_FCNTL_H 1 #define HAVE_SYS_SELECT_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TIMES_H 1 #define HAVE_SYS_PARAM_H 1 #define HAVE_SYSCALL_H 1 #define HAVE_PWD_H 1 #define HAVE_GRP_H 1 #define HAVE_A_OUT_H 1 #define HAVE_UTIME_H 1 #define HAVE_MEMORY_H 1 #define HAVE_SYS_RESOURCE_H 1 #define HAVE_NETINET_IN_SYSTM_H 1 #define HAVE_FLOAT_H 1 #define HAVE_PTHREAD_H 1 #define HAVE_UCONTEXT_H 1 #define HAVE_TIME_H 1 #define SIZEOF_RLIM_T 8 #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 #define HAVE_ST_BLKSIZE 1 #define HAVE_STRUCT_STAT_ST_BLOCKS 1 #define HAVE_ST_BLOCKS 1 #define HAVE_STRUCT_STAT_ST_RDEV 1 #define HAVE_ST_RDEV 1 #define HAVE_INT8_T 1 #define SIZEOF_INT8_T 1 #define HAVE_UINT8_T 1 #define SIZEOF_UINT8_T 1 #define HAVE_INT16_T 1 #define SIZEOF_INT16_T 2 #define HAVE_UINT16_T 1 #define SIZEOF_UINT16_T 2 #define HAVE_INT32_T 1 #define SIZEOF_INT32_T 4 #define HAVE_UINT32_T 1 #define SIZEOF_UINT32_T 4 #define HAVE_INT64_T 1 #define SIZEOF_INT64_T 8 #define HAVE_UINT64_T 1 #define SIZEOF_UINT64_T 8 #define HAVE_STRUCT_TIMEZONE 1 #define GETGROUPS_T gid_t #define RETSIGTYPE void #define HAVE_ALLOCA_H 1 #define HAVE_ALLOCA 1 #define HAVE_FSEEKO 1 #define HAVE_FTELLO 1 #define HAVE_DUP2 1 #define HAVE_MEMMOVE 1 #define HAVE_STRCASECMP 1 #define HAVE_STRNCASECMP 1 #define HAVE_STRERROR 1 #define HAVE_STRFTIME 1 #define HAVE_STRCHR 1 #define HAVE_STRSTR 1 #define HAVE_STRTOUL 1 #define HAVE_CRYPT 1 #define HAVE_FLOCK 1 #define HAVE_VSNPRINTF 1 #define HAVE_ISNAN 1 #define HAVE_FINITE 1 #define HAVE_ISINF 1 #define HAVE_HYPOT 1 #define HAVE_ACOSH 1 #define HAVE_ERF 1 #define HAVE_FMOD 1 #define HAVE_KILLPG 1 #define HAVE_WAIT4 1 #define HAVE_WAITPID 1 #define HAVE_SYSCALL 1 #define HAVE_CHROOT 1 #define HAVE_FSYNC 1 #define HAVE_GETCWD 1 #define HAVE_EACCESS 1 #define HAVE_TRUNCATE 1 #define HAVE_FTRUNCATE 1 #define HAVE_TIMES 1 #define HAVE_UTIMES 1 #define HAVE_FCNTL 1 #define HAVE_LOCKF 1 #define HAVE_LSTAT 1 #define HAVE_SYMLINK 1 #define HAVE_LINK 1 #define HAVE_READLINK 1 #define HAVE_SETITIMER 1 #define HAVE_SETEUID 1 #define HAVE_SETREUID 1 #define HAVE_SETRESUID 1 #define HAVE_SETEGID 1 #define HAVE_SETREGID 1 #define HAVE_SETRESGID 1 #define HAVE_PAUSE 1 #define HAVE_LCHOWN 1 #define HAVE_GETPGRP 1 #define HAVE_SETPGRP 1 #define HAVE_GETPGID 1 #define HAVE_SETPGID 1 #define HAVE_INITGROUPS 1 #define HAVE_GETGROUPS 1 #define HAVE_SETGROUPS 1 #define HAVE_GETPRIORITY 1 #define HAVE_GETRLIMIT 1 #define HAVE_SETRLIMIT 1 #define HAVE_SYSCONF 1 #define HAVE_GROUP_MEMBER 1 #define HAVE_DLOPEN 1 #define HAVE_SIGPROCMASK 1 #define HAVE_SIGACTION 1 #define HAVE__SETJMP 1 #define HAVE__LONGJMP 1 #define HAVE_SETSID 1 #define HAVE_TELLDIR 1 #define HAVE_SEEKDIR 1 #define HAVE_FCHMOD 1 #define HAVE_MKTIME 1 #define HAVE_TIMEGM 1 #define HAVE_GETTIMEOFDAY 1 #define HAVE_COSH 1 #define HAVE_SINH 1 #define HAVE_TANH 1 #define HAVE_ROUND 1 #define HAVE_SETUID 1 #define HAVE_SETGID 1 #define HAVE_SETENV 1 #define HAVE_UNSETENV 1 #define RUBY_SETJMP(env) _setjmp(env) #define RUBY_LONGJMP(env,val) _longjmp(env,val) #define RUBY_JMP_BUF jmp_buf #define HAVE_STRUCT_TM_TM_ZONE 1 #define HAVE_TM_ZONE 1 #define HAVE_STRUCT_TM_TM_GMTOFF 1 #define HAVE_DAYLIGHT 1 #define HAVE_VAR_TIMEZONE 1 #define TYPEOF_VAR_TIMEZONE long #define NEGATIVE_TIME_T 1 #define POSIX_SIGNAL 1 #define GETPGRP_VOID 1 #define SETPGRP_VOID 1 #define RSHIFT(x,y) ((x)>>(int)y) #define FILE_READPTR _IO_read_ptr #define FILE_READEND _IO_read_end #define HAVE__SC_CLK_TCK 1 #define STACK_GROW_DIRECTION -1 #define _REENTRANT 1 #define _THREAD_SAFE 1 #define HAVE_LIBPTHREAD 1 #define HAVE_NANOSLEEP 1 #define HAVE_GETCONTEXT 1 #define HAVE_SETCONTEXT 1 #define DEFAULT_KCODE KCODE_NONE #define USE_ELF 1 #define DLEXT_MAXLEN 3 #define DLEXT ".so" #define RUBY_LIB "/opt/alt/ruby18/lib64/ruby/1.8" #define RUBY_SITE_LIB "/opt/alt/ruby18/lib64/ruby/site_ruby" #define RUBY_SITE_LIB2 "/opt/alt/ruby18/lib64/ruby/site_ruby/1.8" #define RUBY_VENDOR_LIB "/opt/alt/ruby18/lib64/ruby/vendor_ruby" #define RUBY_VENDOR_LIB2 "/opt/alt/ruby18/lib64/ruby/vendor_ruby/1.8" #define RUBY_PLATFORM "x86_64-linux" #define RUBY_ARCHLIB "/opt/alt/ruby18/lib64/ruby/1.8/x86_64-linux" #define RUBY_SITE_ARCHLIB "/opt/alt/ruby18/lib64/ruby/site_ruby/1.8/x86_64-linux" #define RUBY_VENDOR_ARCHLIB "/opt/alt/ruby18/lib64/ruby/vendor_ruby/1.8/x86_64-linux" PK|]M{ x86_64-linux/rubyio.hnu[/********************************************************************** rubyio.h - $Author: nobu $ $Date: 2008-04-15 12:35:55 +0900 (Tue, 15 Apr 2008) $ created at: Fri Nov 12 16:47:09 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto **********************************************************************/ #ifndef RUBYIO_H #define RUBYIO_H #include #include #if defined(HAVE_STDIO_EXT_H) #include #endif typedef struct rb_io_t { FILE *f; /* stdio ptr for read/write */ FILE *f2; /* additional ptr for rw pipes */ int mode; /* mode flags */ int pid; /* child's pid (for pipes) */ int lineno; /* number of lines read */ char *path; /* pathname for file */ void (*finalize) _((struct rb_io_t*,int)); /* finalize proc */ } rb_io_t; #define HAVE_RB_IO_T 1 #define OpenFile rb_io_t /* for backward compatibility */ #define FMODE_READABLE 1 #define FMODE_WRITABLE 2 #define FMODE_READWRITE 3 #define FMODE_APPEND 64 #define FMODE_CREATE 128 #define FMODE_BINMODE 4 #define FMODE_SYNC 8 #define FMODE_WBUF 16 #define FMODE_RBUF 32 #define FMODE_WSPLIT 0x200 #define FMODE_WSPLIT_INITIALIZED 0x400 #define GetOpenFile(obj,fp) rb_io_check_closed((fp) = RFILE(rb_io_taint_check(obj))->fptr) #define MakeOpenFile(obj, fp) do {\ if (RFILE(obj)->fptr) {\ rb_io_close(obj);\ free(RFILE(obj)->fptr);\ RFILE(obj)->fptr = 0;\ }\ fp = 0;\ fp = RFILE(obj)->fptr = ALLOC(rb_io_t);\ fp->f = fp->f2 = NULL;\ fp->mode = 0;\ fp->pid = 0;\ fp->lineno = 0;\ fp->path = NULL;\ fp->finalize = 0;\ } while (0) #define GetReadFile(fptr) ((fptr)->f) #define GetWriteFile(fptr) (((fptr)->f2) ? (fptr)->f2 : (fptr)->f) FILE *rb_fopen _((const char*, const char*)); FILE *rb_fdopen _((int, const char*)); int rb_getc _((FILE*)); long rb_io_fread _((char *, long, FILE *)); long rb_io_fwrite _((const char *, long, FILE *)); int rb_io_mode_flags _((const char*)); int rb_io_modenum_flags _((int)); void rb_io_check_writable _((rb_io_t*)); void rb_io_check_readable _((rb_io_t*)); void rb_io_fptr_finalize _((rb_io_t*)); void rb_io_synchronized _((rb_io_t*)); void rb_io_check_initialized _((rb_io_t*)); void rb_io_check_closed _((rb_io_t*)); int rb_io_wait_readable _((int)); int rb_io_wait_writable _((int)); void rb_io_set_nonblock(rb_io_t *fptr); VALUE rb_io_taint_check _((VALUE)); NORETURN(void rb_eof_error _((void))); void rb_read_check _((FILE*)); int rb_read_pending _((FILE*)); #endif PK|]rFO O singleton.rbnu[# The Singleton module implements the Singleton pattern. # # Usage: # class Klass # include Singleton # # ... # end # # * this ensures that only one instance of Klass lets call it # ``the instance'' can be created. # # a,b = Klass.instance, Klass.instance # a == b # => true # a.new # NoMethodError - new is private ... # # * ``The instance'' is created at instantiation time, in other # words the first call of Klass.instance(), thus # # class OtherKlass # include Singleton # # ... # end # ObjectSpace.each_object(OtherKlass){} # => 0. # # * This behavior is preserved under inheritance and cloning. # # # # This is achieved by marking # * Klass.new and Klass.allocate - as private # # Providing (or modifying) the class methods # * Klass.inherited(sub_klass) and Klass.clone() - # to ensure that the Singleton pattern is properly # inherited and cloned. # # * Klass.instance() - returning ``the instance''. After a # successful self modifying (normally the first) call the # method body is a simple: # # def Klass.instance() # return @__instance__ # end # # * Klass._load(str) - calling Klass.instance() # # * Klass._instantiate?() - returning ``the instance'' or # nil. This hook method puts a second (or nth) thread calling # Klass.instance() on a waiting loop. The return value # signifies the successful completion or premature termination # of the first, or more generally, current "instantiation thread". # # # The instance method of Singleton are # * clone and dup - raising TypeErrors to prevent cloning or duping # # * _dump(depth) - returning the empty string. Marshalling strips # by default all state information, e.g. instance variables and # taint state, from ``the instance''. Providing custom _load(str) # and _dump(depth) hooks allows the (partially) resurrections of # a previous state of ``the instance''. module Singleton # disable build-in copying methods def clone raise TypeError, "can't clone instance of singleton #{self.class}" end def dup raise TypeError, "can't dup instance of singleton #{self.class}" end # default marshalling strategy def _dump(depth=-1) '' end end class << Singleton # Method body of first instance call. FirstInstanceCall = proc do # @__instance__ takes on one of the following values # * nil - before and after a failed creation # * false - during creation # * sub_class instance - after a successful creation # the form makes up for the lack of returns in progs Thread.critical = true if @__instance__.nil? @__instance__ = false Thread.critical = false begin @__instance__ = new ensure if @__instance__ class < mes puts mes end puts "\nThreaded example with exception and customized #_instantiate?() hook"; p Thread.abort_on_exception = false class Ups < SomeSingletonClass def initialize self.class.__sleep puts "initialize called by thread ##{Thread.current[:i]}" end end class << Ups def _instantiate? @enter.push Thread.current[:i] while false.equal?(@__instance__) Thread.critical = false sleep 0.08 Thread.critical = true end @leave.push Thread.current[:i] @__instance__ end def __sleep sleep(rand(0.08)) end def new begin __sleep raise "boom - thread ##{Thread.current[:i]} failed to create instance" ensure # simple flip-flop class << self remove_method :new end end end def instantiate_all @enter = [] @leave = [] 1.upto(9) {|i| Thread.new { begin Thread.current[:i] = i __sleep instance rescue RuntimeError => mes puts mes end } } puts "Before there were #{num_of_instances(self)}" sleep 3 puts "Now there is #{num_of_instances(self)}" puts "#{@enter.join '; '} was the order of threads entering the waiting loop" puts "#{@leave.join '; '} was the order of threads leaving the waiting loop" end end Ups.instantiate_all # results in message like # Before there were 0 Ups instance(s) # boom - thread #6 failed to create instance # initialize called by thread #3 # Now there is 1 Ups instance(s) # 3; 2; 1; 8; 4; 7; 5 was the order of threads entering the waiting loop # 3; 2; 1; 7; 4; 8; 5 was the order of threads leaving the waiting loop puts "\nLets see if class level cloning really works" Yup = Ups.clone def Yup.new begin __sleep raise "boom - thread ##{Thread.current[:i]} failed to create instance" ensure # simple flip-flop class << self remove_method :new end end end Yup.instantiate_all puts "\n\n","Customized marshalling" class A include Singleton attr_accessor :persist, :die def _dump(depth) # this strips the @die information from the instance Marshal.dump(@persist,depth) end end def A._load(str) instance.persist = Marshal.load(str) instance end a = A.instance a.persist = ["persist"] a.die = "die" a.taint stored_state = Marshal.dump(a) # change state a.persist = nil a.die = nil b = Marshal.load(stored_state) p a == b # => true p a.persist # => ["persist"] p a.die # => nil puts "\n\nSingleton with overridden default #inherited() hook" class Up end def Up.inherited(sub_klass) puts "#{sub_klass} subclasses #{self}" end class Middle < Up include Singleton end class Down < Middle; end puts "and basic \"Down test\" is #{Down.instance == Down.instance}\n Various exceptions" begin module AModule include Singleton end rescue TypeError => mes puts mes #=> Inclusion of the OO-Singleton module in module AModule end begin 'aString'.extend Singleton rescue NoMethodError => mes puts mes #=> undefined method `extend_object' for Singleton:Module end end PK|]x6&OSS resolv.rbnu[require 'socket' require 'fcntl' require 'timeout' require 'thread' begin require 'securerandom' rescue LoadError end # Resolv is a thread-aware DNS resolver library written in Ruby. Resolv can # handle multiple DNS requests concurrently without blocking. The ruby # interpreter. # # See also resolv-replace.rb to replace the libc resolver with # Resolv. # # Resolv can look up various DNS resources using the DNS module directly. # # Examples: # # p Resolv.getaddress "www.ruby-lang.org" # p Resolv.getname "210.251.121.214" # # Resolv::DNS.open do |dns| # ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A # p ress.map { |r| r.address } # ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX # p ress.map { |r| [r.exchange.to_s, r.preference] } # end # # # == Bugs # # * NIS is not supported. # * /etc/nsswitch.conf is not supported. class Resolv ## # Looks up the first IP address for +name+. def self.getaddress(name) DefaultResolver.getaddress(name) end ## # Looks up all IP address for +name+. def self.getaddresses(name) DefaultResolver.getaddresses(name) end ## # Iterates over all IP addresses for +name+. def self.each_address(name, &block) DefaultResolver.each_address(name, &block) end ## # Looks up the hostname of +address+. def self.getname(address) DefaultResolver.getname(address) end ## # Looks up all hostnames for +address+. def self.getnames(address) DefaultResolver.getnames(address) end ## # Iterates over all hostnames for +address+. def self.each_name(address, &proc) DefaultResolver.each_name(address, &proc) end ## # Creates a new Resolv using +resolvers+. def initialize(resolvers=[Hosts.new, DNS.new]) @resolvers = resolvers end ## # Looks up the first IP address for +name+. def getaddress(name) each_address(name) {|address| return address} raise ResolvError.new("no address for #{name}") end ## # Looks up all IP address for +name+. def getaddresses(name) ret = [] each_address(name) {|address| ret << address} return ret end ## # Iterates over all IP addresses for +name+. def each_address(name) if AddressRegex =~ name yield name return end yielded = false @resolvers.each {|r| r.each_address(name) {|address| yield address.to_s yielded = true } return if yielded } end ## # Looks up the hostname of +address+. def getname(address) each_name(address) {|name| return name} raise ResolvError.new("no name for #{address}") end ## # Looks up all hostnames for +address+. def getnames(address) ret = [] each_name(address) {|name| ret << name} return ret end ## # Iterates over all hostnames for +address+. def each_name(address) yielded = false @resolvers.each {|r| r.each_name(address) {|name| yield name.to_s yielded = true } return if yielded } end ## # Indicates a failure to resolve a name or address. class ResolvError < StandardError; end ## # Indicates a timeout resolving a name or address. class ResolvTimeout < TimeoutError; end ## # DNS::Hosts is a hostname resolver that uses the system hosts file. class Hosts if /mswin32|mingw|bccwin/ =~ RUBY_PLATFORM require 'win32/resolv' DefaultFileName = Win32::Resolv.get_hosts_path else DefaultFileName = '/etc/hosts' end ## # Creates a new DNS::Hosts, using +filename+ for its data source. def initialize(filename = DefaultFileName) @filename = filename @mutex = Mutex.new @initialized = nil end def lazy_initialize # :nodoc: @mutex.synchronize { unless @initialized @name2addr = {} @addr2name = {} open(@filename) {|f| f.each {|line| line.sub!(/#.*/, '') addr, hostname, *aliases = line.split(/\s+/) next unless addr addr.untaint hostname.untaint @addr2name[addr] = [] unless @addr2name.include? addr @addr2name[addr] << hostname @addr2name[addr] += aliases @name2addr[hostname] = [] unless @name2addr.include? hostname @name2addr[hostname] << addr aliases.each {|n| n.untaint @name2addr[n] = [] unless @name2addr.include? n @name2addr[n] << addr } } } @name2addr.each {|name, arr| arr.reverse!} @initialized = true end } self end ## # Gets the IP address of +name+ from the hosts file. def getaddress(name) each_address(name) {|address| return address} raise ResolvError.new("#{@filename} has no name: #{name}") end ## # Gets all IP addresses for +name+ from the hosts file. def getaddresses(name) ret = [] each_address(name) {|address| ret << address} return ret end ## # Iterates over all IP addresses for +name+ retrieved from the hosts file. def each_address(name, &proc) lazy_initialize if @name2addr.include?(name) @name2addr[name].each(&proc) end end ## # Gets the hostname of +address+ from the hosts file. def getname(address) each_name(address) {|name| return name} raise ResolvError.new("#{@filename} has no address: #{address}") end ## # Gets all hostnames for +address+ from the hosts file. def getnames(address) ret = [] each_name(address) {|name| ret << name} return ret end ## # Iterates over all hostnames for +address+ retrieved from the hosts file. def each_name(address, &proc) lazy_initialize if @addr2name.include?(address) @addr2name[address].each(&proc) end end end ## # Resolv::DNS is a DNS stub resolver. # # Information taken from the following places: # # * STD0013 # * RFC 1035 # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters # * etc. class DNS ## # Default DNS Port Port = 53 ## # Default DNS UDP packet size UDPSize = 512 ## # Group of DNS resolver threads (obsolete) DNSThreadGroup = ThreadGroup.new ## # Creates a new DNS resolver. See Resolv::DNS.new for argument details. # # Yields the created DNS resolver to the block, if given, otherwise # returns it. def self.open(*args) dns = new(*args) return dns unless block_given? begin yield dns ensure dns.close end end ## # Creates a new DNS resolver. # # +config_info+ can be: # # nil:: Uses /etc/resolv.conf. # String:: Path to a file using /etc/resolv.conf's format. # Hash:: Must contain :nameserver, :search and :ndots keys. # # Example: # # Resolv::DNS.new(:nameserver => ['210.251.121.21'], # :search => ['ruby-lang.org'], # :ndots => 1) def initialize(config_info=nil) @mutex = Mutex.new @config = Config.new(config_info) @initialized = nil end def lazy_initialize # :nodoc: @mutex.synchronize { unless @initialized @config.lazy_initialize @initialized = true end } self end ## # Closes the DNS resolver. def close @mutex.synchronize { if @initialized @initialized = false end } end ## # Gets the IP address of +name+ from the DNS resolver. # # +name+ can be a Resolv::DNS::Name or a String. Retrieved address will # be a Resolv::IPv4 or Resolv::IPv6 def getaddress(name) each_address(name) {|address| return address} raise ResolvError.new("DNS result has no information for #{name}") end ## # Gets all IP addresses for +name+ from the DNS resolver. # # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will # be a Resolv::IPv4 or Resolv::IPv6 def getaddresses(name) ret = [] each_address(name) {|address| ret << address} return ret end ## # Iterates over all IP addresses for +name+ retrieved from the DNS # resolver. # # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will # be a Resolv::IPv4 or Resolv::IPv6 def each_address(name) each_resource(name, Resource::IN::A) {|resource| yield resource.address} each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address} end ## # Gets the hostname for +address+ from the DNS resolver. # # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved # name will be a Resolv::DNS::Name. def getname(address) each_name(address) {|name| return name} raise ResolvError.new("DNS result has no information for #{address}") end ## # Gets all hostnames for +address+ from the DNS resolver. # # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved # names will be Resolv::DNS::Name instances. def getnames(address) ret = [] each_name(address) {|name| ret << name} return ret end ## # Iterates over all hostnames for +address+ retrieved from the DNS # resolver. # # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved # names will be Resolv::DNS::Name instances. def each_name(address) case address when Name ptr = address when IPv4::Regex ptr = IPv4.create(address).to_name when IPv6::Regex ptr = IPv6.create(address).to_name else raise ResolvError.new("cannot interpret as address: #{address}") end each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name} end ## # Look up the +typeclass+ DNS resource of +name+. # # +name+ must be a Resolv::DNS::Name or a String. # # +typeclass+ should be one of the following: # # * Resolv::DNS::Resource::IN::A # * Resolv::DNS::Resource::IN::AAAA # * Resolv::DNS::Resource::IN::ANY # * Resolv::DNS::Resource::IN::CNAME # * Resolv::DNS::Resource::IN::HINFO # * Resolv::DNS::Resource::IN::MINFO # * Resolv::DNS::Resource::IN::MX # * Resolv::DNS::Resource::IN::NS # * Resolv::DNS::Resource::IN::PTR # * Resolv::DNS::Resource::IN::SOA # * Resolv::DNS::Resource::IN::TXT # * Resolv::DNS::Resource::IN::WKS # # Returned resource is represented as a Resolv::DNS::Resource instance, # i.e. Resolv::DNS::Resource::IN::A. def getresource(name, typeclass) each_resource(name, typeclass) {|resource| return resource} raise ResolvError.new("DNS result has no information for #{name}") end ## # Looks up all +typeclass+ DNS resources for +name+. See #getresource for # argument details. def getresources(name, typeclass) ret = [] each_resource(name, typeclass) {|resource| ret << resource} return ret end ## # Iterates over all +typeclass+ DNS resources for +name+. See # #getresource for argument details. def each_resource(name, typeclass, &proc) lazy_initialize requester = make_requester senders = {} begin @config.resolv(name) {|candidate, tout, nameserver| msg = Message.new msg.rd = 1 msg.add_question(candidate, typeclass) unless sender = senders[[candidate, nameserver]] sender = senders[[candidate, nameserver]] = requester.sender(msg, candidate, nameserver) end reply, reply_name = requester.request(sender, tout) case reply.rcode when RCode::NoError extract_resources(reply, reply_name, typeclass, &proc) return when RCode::NXDomain raise Config::NXDomain.new(reply_name.to_s) else raise Config::OtherResolvError.new(reply_name.to_s) end } ensure requester.close end end def make_requester # :nodoc: nameserver_port = @config.nameserver_port if nameserver_port.length == 1 Requester::ConnectedUDP.new(*nameserver_port[0]) else Requester::UnconnectedUDP.new(*nameserver_port) end end def extract_resources(msg, name, typeclass) # :nodoc: if typeclass < Resource::ANY n0 = Name.create(name) msg.each_answer {|n, ttl, data| yield data if n0 == n } end yielded = false n0 = Name.create(name) msg.each_answer {|n, ttl, data| if n0 == n case data when typeclass yield data yielded = true when Resource::CNAME n0 = data.name end end } return if yielded msg.each_answer {|n, ttl, data| if n0 == n case data when typeclass yield data end end } end if defined? SecureRandom def self.random(arg) # :nodoc: begin SecureRandom.random_number(arg) rescue NotImplementedError rand(arg) end end else def self.random(arg) # :nodoc: rand(arg) end end def self.rangerand(range) # :nodoc: base = range.begin len = range.end - range.begin if !range.exclude_end? len += 1 end base + random(len) end RequestID = {} RequestIDMutex = Mutex.new def self.allocate_request_id(host, port) # :nodoc: id = nil RequestIDMutex.synchronize { h = (RequestID[[host, port]] ||= {}) begin id = rangerand(0x0000..0xffff) end while h[id] h[id] = true } id end def self.free_request_id(host, port, id) # :nodoc: RequestIDMutex.synchronize { key = [host, port] if h = RequestID[key] h.delete id if h.empty? RequestID.delete key end end } end def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: begin port = rangerand(1024..65535) udpsock.bind(bind_host, port) rescue Errno::EADDRINUSE retry end end class Requester # :nodoc: def initialize @senders = {} @socks = nil end def request(sender, tout) timelimit = Time.now + tout sender.send while true now = Time.now timeout = timelimit - now if timeout <= 0 raise ResolvTimeout end select_result = IO.select(@socks, nil, nil, timeout) if !select_result raise ResolvTimeout end reply, from = recv_reply(select_result[0]) begin msg = Message.decode(reply) rescue DecodeError next # broken DNS message ignored end if s = @senders[[from,msg.id]] break else # unexpected DNS message ignored end end return msg, s.data end def close socks = @socks @socks = nil if socks socks.each {|sock| sock.close } end end class Sender # :nodoc: def initialize(msg, data, sock) @msg = msg @data = data @sock = sock end end class UnconnectedUDP < Requester # :nodoc: def initialize(*nameserver_port) super() @nameserver_port = nameserver_port @socks_hash = {} @socks = [] nameserver_port.each {|host, port| if host.index(':') bind_host = "::" af = Socket::AF_INET6 else bind_host = "0.0.0.0" af = Socket::AF_INET end next if @socks_hash[bind_host] sock = UDPSocket.new(af) sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD DNS.bind_random_port(sock, bind_host) @socks << sock @socks_hash[bind_host] = sock } end def recv_reply(readable_socks) reply, from = readable_socks[0].recvfrom(UDPSize) return reply, [from[3],from[1]] end def sender(msg, data, host, port=Port) service = [host, port] id = DNS.allocate_request_id(host, port) request = msg.encode request[0,2] = [id].pack('n') sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"] return @senders[[service, id]] = Sender.new(request, data, sock, host, port) end def close super @senders.each_key {|service, id| DNS.free_request_id(service[0], service[1], id) } end class Sender < Requester::Sender # :nodoc: def initialize(msg, data, sock, host, port) super(msg, data, sock) @host = host @port = port end attr_reader :data def send @sock.send(@msg, 0, @host, @port) end end end class ConnectedUDP < Requester # :nodoc: def initialize(host, port=Port) super() @host = host @port = port is_ipv6 = host.index(':') sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET) @socks = [sock] sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0") sock.connect(host, port) end def recv_reply(readable_socks) reply = readable_socks[0].recv(UDPSize) return reply, nil end def sender(msg, data, host=@host, port=@port) unless host == @host && port == @port raise RequestError.new("host/port don't match: #{host}:#{port}") end id = DNS.allocate_request_id(@host, @port) request = msg.encode request[0,2] = [id].pack('n') return @senders[[nil,id]] = Sender.new(request, data, @socks[0]) end def close super @senders.each_key {|from, id| DNS.free_request_id(@host, @port, id) } end class Sender < Requester::Sender # :nodoc: def send @sock.send(@msg, 0) end attr_reader :data end end class TCP < Requester # :nodoc: def initialize(host, port=Port) super() @host = host @port = port sock = TCPSocket.new(@host, @port) @socks = [sock] sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD @senders = {} end def recv_reply(readable_socks) len = readable_socks[0].read(2).unpack('n')[0] reply = @socks[0].read(len) return reply, nil end def sender(msg, data, host=@host, port=@port) unless host == @host && port == @port raise RequestError.new("host/port don't match: #{host}:#{port}") end id = DNS.allocate_request_id(@host, @port) request = msg.encode request[0,2] = [request.length, id].pack('nn') return @senders[[nil,id]] = Sender.new(request, data, @socks[0]) end class Sender < Requester::Sender # :nodoc: def send @sock.print(@msg) @sock.flush end attr_reader :data end def close super @senders.each_key {|from,id| DNS.free_request_id(@host, @port, id) } end end ## # Indicates a problem with the DNS request. class RequestError < StandardError end end class Config # :nodoc: def initialize(config_info=nil) @mutex = Mutex.new @config_info = config_info @initialized = nil end def Config.parse_resolv_conf(filename) nameserver = [] search = nil ndots = 1 open(filename) {|f| f.each {|line| line.sub!(/[#;].*/, '') keyword, *args = line.split(/\s+/) args.each { |arg| arg.untaint } next unless keyword case keyword when 'nameserver' nameserver += args when 'domain' next if args.empty? search = [args[0]] when 'search' next if args.empty? search = args when 'options' args.each {|arg| case arg when /\Andots:(\d+)\z/ ndots = $1.to_i end } end } } return { :nameserver => nameserver, :search => search, :ndots => ndots } end def Config.default_config_hash(filename="/etc/resolv.conf") if File.exist? filename config_hash = Config.parse_resolv_conf(filename) else if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM require 'win32/resolv' search, nameserver = Win32::Resolv.get_resolv_info config_hash = {} config_hash[:nameserver] = nameserver if nameserver config_hash[:search] = [search].flatten if search end end config_hash end def lazy_initialize @mutex.synchronize { unless @initialized @nameserver = [] @search = nil @ndots = 1 case @config_info when nil config_hash = Config.default_config_hash when String config_hash = Config.parse_resolv_conf(@config_info) when Hash config_hash = @config_info.dup if String === config_hash[:nameserver] config_hash[:nameserver] = [config_hash[:nameserver]] end if String === config_hash[:search] config_hash[:search] = [config_hash[:search]] end else raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}") end @nameserver = config_hash[:nameserver] if config_hash.include? :nameserver @search = config_hash[:search] if config_hash.include? :search @ndots = config_hash[:ndots] if config_hash.include? :ndots @nameserver = ['0.0.0.0'] if @nameserver.empty? if @search @search = @search.map {|arg| Label.split(arg) } else hostname = Socket.gethostname if /\./ =~ hostname @search = [Label.split($')] else @search = [[]] end end if !@nameserver.kind_of?(Array) || !@nameserver.all? {|ns| String === ns } raise ArgumentError.new("invalid nameserver config: #{@nameserver.inspect}") end if !@search.kind_of?(Array) || !@search.all? {|ls| ls.all? {|l| Label::Str === l } } raise ArgumentError.new("invalid search config: #{@search.inspect}") end if !@ndots.kind_of?(Integer) raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}") end @initialized = true end } self end def single? lazy_initialize if @nameserver.length == 1 return @nameserver[0] else return nil end end def nameserver_port lazy_initialize @nameserver_port ||= @nameserver.map {|i| [i, Port] } @nameserver_port end def generate_candidates(name) candidates = nil name = Name.create(name) if name.absolute? candidates = [name] else if @ndots <= name.length - 1 candidates = [Name.new(name.to_a)] else candidates = [] end candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)}) end return candidates end InitialTimeout = 5 def generate_timeouts ts = [InitialTimeout] ts << ts[-1] * 2 / @nameserver.length ts << ts[-1] * 2 ts << ts[-1] * 2 return ts end def resolv(name) candidates = generate_candidates(name) timeouts = generate_timeouts begin candidates.each {|candidate| begin timeouts.each {|tout| @nameserver.each {|nameserver| begin yield candidate, tout, nameserver rescue ResolvTimeout end } } raise ResolvError.new("DNS resolv timeout: #{name}") rescue NXDomain end } rescue ResolvError end end ## # Indicates no such domain was found. class NXDomain < ResolvError end ## # Indicates some other unhandled resolver error was encountered. class OtherResolvError < ResolvError end end module OpCode # :nodoc: Query = 0 IQuery = 1 Status = 2 Notify = 4 Update = 5 end module RCode # :nodoc: NoError = 0 FormErr = 1 ServFail = 2 NXDomain = 3 NotImp = 4 Refused = 5 YXDomain = 6 YXRRSet = 7 NXRRSet = 8 NotAuth = 9 NotZone = 10 BADVERS = 16 BADSIG = 16 BADKEY = 17 BADTIME = 18 BADMODE = 19 BADNAME = 20 BADALG = 21 end ## # Indicates that the DNS response was unable to be decoded. class DecodeError < StandardError end ## # Indicates that the DNS request was unable to be encoded. class EncodeError < StandardError end module Label # :nodoc: def self.split(arg) labels = [] arg.scan(/[^\.]+/) {labels << Str.new($&)} return labels end class Str # :nodoc: def initialize(string) @string = string @downcase = string.downcase end attr_reader :string, :downcase def to_s return @string end def inspect return "#<#{self.class} #{self.to_s}>" end def ==(other) return @downcase == other.downcase end def eql?(other) return self == other end def hash return @downcase.hash end end end ## # A representation of a DNS name. class Name ## # Creates a new DNS name from +arg+. +arg+ can be: # # Name:: returns +arg+. # String:: Creates a new Name. def self.create(arg) case arg when Name return arg when String return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false) else raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}") end end def initialize(labels, absolute=true) # :nodoc: @labels = labels @absolute = absolute end def inspect # :nodoc: "#<#{self.class}: #{self.to_s}#{@absolute ? '.' : ''}>" end ## # True if this name is absolute. def absolute? return @absolute end def ==(other) # :nodoc: return false unless Name === other return @labels.join == other.to_a.join && @absolute == other.absolute? end alias eql? == # :nodoc: ## # Returns true if +other+ is a subdomain. # # Example: # # domain = Resolv::DNS::Name.create("y.z") # p Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true # p Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true # p Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false # p Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false # p Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false # p Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false # def subdomain_of?(other) raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other return false if @absolute != other.absolute? other_len = other.length return false if @labels.length <= other_len return @labels[-other_len, other_len] == other.to_a end def hash # :nodoc: return @labels.hash ^ @absolute.hash end def to_a # :nodoc: return @labels end def length # :nodoc: return @labels.length end def [](i) # :nodoc: return @labels[i] end ## # returns the domain name as a string. # # The domain name doesn't have a trailing dot even if the name object is # absolute. # # Example: # # p Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z" # p Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z" def to_s return @labels.join('.') end end class Message # :nodoc: @@identifier = -1 def initialize(id = (@@identifier += 1) & 0xffff) @id = id @qr = 0 @opcode = 0 @aa = 0 @tc = 0 @rd = 0 # recursion desired @ra = 0 # recursion available @rcode = 0 @question = [] @answer = [] @authority = [] @additional = [] end attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode attr_reader :question, :answer, :authority, :additional def ==(other) return @id == other.id && @qr == other.qr && @opcode == other.opcode && @aa == other.aa && @tc == other.tc && @rd == other.rd && @ra == other.ra && @rcode == other.rcode && @question == other.question && @answer == other.answer && @authority == other.authority && @additional == other.additional end def add_question(name, typeclass) @question << [Name.create(name), typeclass] end def each_question @question.each {|name, typeclass| yield name, typeclass } end def add_answer(name, ttl, data) @answer << [Name.create(name), ttl, data] end def each_answer @answer.each {|name, ttl, data| yield name, ttl, data } end def add_authority(name, ttl, data) @authority << [Name.create(name), ttl, data] end def each_authority @authority.each {|name, ttl, data| yield name, ttl, data } end def add_additional(name, ttl, data) @additional << [Name.create(name), ttl, data] end def each_additional @additional.each {|name, ttl, data| yield name, ttl, data } end def each_resource each_answer {|name, ttl, data| yield name, ttl, data} each_authority {|name, ttl, data| yield name, ttl, data} each_additional {|name, ttl, data| yield name, ttl, data} end def encode return MessageEncoder.new {|msg| msg.put_pack('nnnnnn', @id, (@qr & 1) << 15 | (@opcode & 15) << 11 | (@aa & 1) << 10 | (@tc & 1) << 9 | (@rd & 1) << 8 | (@ra & 1) << 7 | (@rcode & 15), @question.length, @answer.length, @authority.length, @additional.length) @question.each {|q| name, typeclass = q msg.put_name(name) msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue) } [@answer, @authority, @additional].each {|rr| rr.each {|r| name, ttl, data = r msg.put_name(name) msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl) msg.put_length16 {data.encode_rdata(msg)} } } }.to_s end class MessageEncoder # :nodoc: def initialize @data = '' @names = {} yield self end def to_s return @data end def put_bytes(d) @data << d end def put_pack(template, *d) @data << d.pack(template) end def put_length16 length_index = @data.length @data << "\0\0" data_start = @data.length yield data_end = @data.length @data[length_index, 2] = [data_end - data_start].pack("n") end def put_string(d) self.put_pack("C", d.length) @data << d end def put_string_list(ds) ds.each {|d| self.put_string(d) } end def put_name(d) put_labels(d.to_a) end def put_labels(d) d.each_index {|i| domain = d[i..-1] if idx = @names[domain] self.put_pack("n", 0xc000 | idx) return else @names[domain] = @data.length self.put_label(d[i]) end } @data << "\0" end def put_label(d) self.put_string(d.to_s) end end def Message.decode(m) o = Message.new(0) MessageDecoder.new(m) {|msg| id, flag, qdcount, ancount, nscount, arcount = msg.get_unpack('nnnnnn') o.id = id o.qr = (flag >> 15) & 1 o.opcode = (flag >> 11) & 15 o.aa = (flag >> 10) & 1 o.tc = (flag >> 9) & 1 o.rd = (flag >> 8) & 1 o.ra = (flag >> 7) & 1 o.rcode = flag & 15 (1..qdcount).each { name, typeclass = msg.get_question o.add_question(name, typeclass) } (1..ancount).each { name, ttl, data = msg.get_rr o.add_answer(name, ttl, data) } (1..nscount).each { name, ttl, data = msg.get_rr o.add_authority(name, ttl, data) } (1..arcount).each { name, ttl, data = msg.get_rr o.add_additional(name, ttl, data) } } return o end class MessageDecoder # :nodoc: def initialize(data) @data = data @index = 0 @limit = data.length yield self end def get_length16 len, = self.get_unpack('n') save_limit = @limit @limit = @index + len d = yield(len) if @index < @limit raise DecodeError.new("junk exists") elsif @limit < @index raise DecodeError.new("limit exceeded") end @limit = save_limit return d end def get_bytes(len = @limit - @index) d = @data[@index, len] @index += len return d end def get_unpack(template) len = 0 template.each_byte {|byte| case byte when ?c, ?C len += 1 when ?n len += 2 when ?N len += 4 else raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'") end } raise DecodeError.new("limit exceeded") if @limit < @index + len arr = @data.unpack("@#{@index}#{template}") @index += len return arr end def get_string len = @data[@index] raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len d = @data[@index + 1, len] @index += 1 + len return d end def get_string_list strings = [] while @index < @limit strings << self.get_string end strings end def get_name return Name.new(self.get_labels) end def get_labels(limit=nil) limit = @index if !limit || @index < limit d = [] while true case @data[@index] when 0 @index += 1 return d when 192..255 idx = self.get_unpack('n')[0] & 0x3fff if limit <= idx raise DecodeError.new("non-backward name pointer") end save_index = @index @index = idx d += self.get_labels(limit) @index = save_index return d else d << self.get_label end end return d end def get_label return Label::Str.new(self.get_string) end def get_question name = self.get_name type, klass = self.get_unpack("nn") return name, Resource.get_class(type, klass) end def get_rr name = self.get_name type, klass, ttl = self.get_unpack('nnN') typeclass = Resource.get_class(type, klass) return name, ttl, self.get_length16 {typeclass.decode_rdata(self)} end end end ## # A DNS query abstract class. class Query def encode_rdata(msg) # :nodoc: raise EncodeError.new("#{self.class} is query.") end def self.decode_rdata(msg) # :nodoc: raise DecodeError.new("#{self.class} is query.") end end ## # A DNS resource abstract class. class Resource < Query ## # Remaining Time To Live for this Resource. attr_reader :ttl ClassHash = {} # :nodoc: def encode_rdata(msg) # :nodoc: raise NotImplementedError.new end def self.decode_rdata(msg) # :nodoc: raise NotImplementedError.new end def ==(other) # :nodoc: return self.class == other.class && self.instance_variables == other.instance_variables && self.instance_variables.collect {|name| self.instance_eval name} == other.instance_variables.collect {|name| other.instance_eval name} end def eql?(other) # :nodoc: return self == other end def hash # :nodoc: h = 0 self.instance_variables.each {|name| h ^= self.instance_eval("#{name}.hash") } return h end def self.get_class(type_value, class_value) # :nodoc: return ClassHash[[type_value, class_value]] || Generic.create(type_value, class_value) end ## # A generic resource abstract class. class Generic < Resource ## # Creates a new generic resource. def initialize(data) @data = data end ## # Data for this generic resource. attr_reader :data def encode_rdata(msg) # :nodoc: msg.put_bytes(data) end def self.decode_rdata(msg) # :nodoc: return self.new(msg.get_bytes) end def self.create(type_value, class_value) # :nodoc: c = Class.new(Generic) c.const_set(:TypeValue, type_value) c.const_set(:ClassValue, class_value) Generic.const_set("Type#{type_value}_Class#{class_value}", c) ClassHash[[type_value, class_value]] = c return c end end ## # Domain Name resource abstract class. class DomainName < Resource ## # Creates a new DomainName from +name+. def initialize(name) @name = name end ## # The name of this DomainName. attr_reader :name def encode_rdata(msg) # :nodoc: msg.put_name(@name) end def self.decode_rdata(msg) # :nodoc: return self.new(msg.get_name) end end # Standard (class generic) RRs ClassValue = nil # :nodoc: ## # An authoritative name server. class NS < DomainName TypeValue = 2 # :nodoc: end ## # The canonical name for an alias. class CNAME < DomainName TypeValue = 5 # :nodoc: end ## # Start Of Authority resource. class SOA < Resource TypeValue = 6 # :nodoc: ## # Creates a new SOA record. See the attr documentation for the # details of each argument. def initialize(mname, rname, serial, refresh, retry_, expire, minimum) @mname = mname @rname = rname @serial = serial @refresh = refresh @retry = retry_ @expire = expire @minimum = minimum end ## # Name of the host where the master zone file for this zone resides. attr_reader :mname ## # The person responsible for this domain name. attr_reader :rname ## # The version number of the zone file. attr_reader :serial ## # How often, in seconds, a secondary name server is to check for # updates from the primary name server. attr_reader :refresh ## # How often, in seconds, a secondary name server is to retry after a # failure to check for a refresh. attr_reader :retry ## # Time in seconds that a secondary name server is to use the data # before refreshing from the primary name server. attr_reader :expire ## # The minimum number of seconds to be used for TTL values in RRs. attr_reader :minimum def encode_rdata(msg) # :nodoc: msg.put_name(@mname) msg.put_name(@rname) msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum) end def self.decode_rdata(msg) # :nodoc: mname = msg.get_name rname = msg.get_name serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN') return self.new( mname, rname, serial, refresh, retry_, expire, minimum) end end ## # A Pointer to another DNS name. class PTR < DomainName TypeValue = 12 # :nodoc: end ## # Host Information resource. class HINFO < Resource TypeValue = 13 # :nodoc: ## # Creates a new HINFO running +os+ on +cpu+. def initialize(cpu, os) @cpu = cpu @os = os end ## # CPU architecture for this resource. attr_reader :cpu ## # Operating system for this resource. attr_reader :os def encode_rdata(msg) # :nodoc: msg.put_string(@cpu) msg.put_string(@os) end def self.decode_rdata(msg) # :nodoc: cpu = msg.get_string os = msg.get_string return self.new(cpu, os) end end ## # Mailing list or mailbox information. class MINFO < Resource TypeValue = 14 # :nodoc: def initialize(rmailbx, emailbx) @rmailbx = rmailbx @emailbx = emailbx end ## # Domain name responsible for this mail list or mailbox. attr_reader :rmailbx ## # Mailbox to use for error messages related to the mail list or mailbox. attr_reader :emailbx def encode_rdata(msg) # :nodoc: msg.put_name(@rmailbx) msg.put_name(@emailbx) end def self.decode_rdata(msg) # :nodoc: rmailbx = msg.get_string emailbx = msg.get_string return self.new(rmailbx, emailbx) end end ## # Mail Exchanger resource. class MX < Resource TypeValue= 15 # :nodoc: ## # Creates a new MX record with +preference+, accepting mail at # +exchange+. def initialize(preference, exchange) @preference = preference @exchange = exchange end ## # The preference for this MX. attr_reader :preference ## # The host of this MX. attr_reader :exchange def encode_rdata(msg) # :nodoc: msg.put_pack('n', @preference) msg.put_name(@exchange) end def self.decode_rdata(msg) # :nodoc: preference, = msg.get_unpack('n') exchange = msg.get_name return self.new(preference, exchange) end end ## # Unstructured text resource. class TXT < Resource TypeValue = 16 # :nodoc: def initialize(first_string, *rest_strings) @strings = [first_string, *rest_strings] end ## # Returns an Array of Strings for this TXT record. attr_reader :strings ## # Returns the first string from +strings+. def data @strings[0] end def encode_rdata(msg) # :nodoc: msg.put_string_list(@strings) end def self.decode_rdata(msg) # :nodoc: strings = msg.get_string_list return self.new(*strings) end end ## # A Query type requesting any RR. class ANY < Query TypeValue = 255 # :nodoc: end ClassInsensitiveTypes = [ # :nodoc: NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, ANY ] ## # module IN contains ARPA Internet specific RRs. module IN ClassValue = 1 # :nodoc: ClassInsensitiveTypes.each {|s| c = Class.new(s) c.const_set(:TypeValue, s::TypeValue) c.const_set(:ClassValue, ClassValue) ClassHash[[s::TypeValue, ClassValue]] = c self.const_set(s.name.sub(/.*::/, ''), c) } ## # IPv4 Address resource class A < Resource TypeValue = 1 ClassValue = IN::ClassValue ClassHash[[TypeValue, ClassValue]] = self # :nodoc: ## # Creates a new A for +address+. def initialize(address) @address = IPv4.create(address) end ## # The Resolv::IPv4 address for this A. attr_reader :address def encode_rdata(msg) # :nodoc: msg.put_bytes(@address.address) end def self.decode_rdata(msg) # :nodoc: return self.new(IPv4.new(msg.get_bytes(4))) end end ## # Well Known Service resource. class WKS < Resource TypeValue = 11 ClassValue = IN::ClassValue ClassHash[[TypeValue, ClassValue]] = self # :nodoc: def initialize(address, protocol, bitmap) @address = IPv4.create(address) @protocol = protocol @bitmap = bitmap end ## # The host these services run on. attr_reader :address ## # IP protocol number for these services. attr_reader :protocol ## # A bit map of enabled services on this host. # # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP # service (port 25). If this bit is set, then an SMTP server should # be listening on TCP port 25; if zero, SMTP service is not # supported. attr_reader :bitmap def encode_rdata(msg) # :nodoc: msg.put_bytes(@address.address) msg.put_pack("n", @protocol) msg.put_bytes(@bitmap) end def self.decode_rdata(msg) # :nodoc: address = IPv4.new(msg.get_bytes(4)) protocol, = msg.get_unpack("n") bitmap = msg.get_bytes return self.new(address, protocol, bitmap) end end ## # An IPv6 address record. class AAAA < Resource TypeValue = 28 ClassValue = IN::ClassValue ClassHash[[TypeValue, ClassValue]] = self # :nodoc: ## # Creates a new AAAA for +address+. def initialize(address) @address = IPv6.create(address) end ## # The Resolv::IPv6 address for this AAAA. attr_reader :address def encode_rdata(msg) # :nodoc: msg.put_bytes(@address.address) end def self.decode_rdata(msg) # :nodoc: return self.new(IPv6.new(msg.get_bytes(16))) end end ## # SRV resource record defined in RFC 2782 # # These records identify the hostname and port that a service is # available at. class SRV < Resource TypeValue = 33 ClassValue = IN::ClassValue ClassHash[[TypeValue, ClassValue]] = self # :nodoc: # Create a SRV resource record. # # See the documentation for #priority, #weight, #port and #target # for +priority+, +weight+, +port and +target+ respectively. def initialize(priority, weight, port, target) @priority = priority.to_int @weight = weight.to_int @port = port.to_int @target = Name.create(target) end # The priority of this target host. # # A client MUST attempt to contact the target host with the # lowest-numbered priority it can reach; target hosts with the same # priority SHOULD be tried in an order defined by the weight field. # The range is 0-65535. Note that it is not widely implemented and # should be set to zero. attr_reader :priority # A server selection mechanism. # # The weight field specifies a relative weight for entries with the # same priority. Larger weights SHOULD be given a proportionately # higher probability of being selected. The range of this number is # 0-65535. Domain administrators SHOULD use Weight 0 when there # isn't any server selection to do, to make the RR easier to read # for humans (less noisy). Note that it is not widely implemented # and should be set to zero. attr_reader :weight # The port on this target host of this service. # # The range is 0-65535. attr_reader :port # The domain name of the target host. # # A target of "." means that the service is decidedly not available # at this domain. attr_reader :target def encode_rdata(msg) # :nodoc: msg.put_pack("n", @priority) msg.put_pack("n", @weight) msg.put_pack("n", @port) msg.put_name(@target) end def self.decode_rdata(msg) # :nodoc: priority, = msg.get_unpack("n") weight, = msg.get_unpack("n") port, = msg.get_unpack("n") target = msg.get_name return self.new(priority, weight, port, target) end end end end end ## # A Resolv::DNS IPv4 address. class IPv4 ## # Regular expression IPv4 addresses must match. Regex256 = /0 |1(?:[0-9][0-9]?)? |2(?:[0-4][0-9]?|5[0-5]?|[6-9])? |[3-9][0-9]?/x Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/ def self.create(arg) case arg when IPv4 return arg when Regex if (0..255) === (a = $1.to_i) && (0..255) === (b = $2.to_i) && (0..255) === (c = $3.to_i) && (0..255) === (d = $4.to_i) return self.new([a, b, c, d].pack("CCCC")) else raise ArgumentError.new("IPv4 address with invalid value: " + arg) end else raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}") end end def initialize(address) # :nodoc: unless address.kind_of?(String) && address.length == 4 raise ArgumentError.new('IPv4 address must be 4 bytes') end @address = address end ## # A String representation of this IPv4 address. ## # The raw IPv4 address as a String. attr_reader :address def to_s # :nodoc: return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC")) end def inspect # :nodoc: return "#<#{self.class} #{self.to_s}>" end ## # Turns this IPv4 address into a Resolv::DNS::Name. def to_name return DNS::Name.create( '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse) end def ==(other) # :nodoc: return @address == other.address end def eql?(other) # :nodoc: return self == other end def hash # :nodoc: return @address.hash end end ## # A Resolv::DNS IPv6 address. class IPv6 ## # IPv6 address format a:b:c:d:e:f:g:h Regex_8Hex = /\A (?:[0-9A-Fa-f]{1,4}:){7} [0-9A-Fa-f]{1,4} \z/x ## # Compressed IPv6 address format a::b Regex_CompressedHex = /\A ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) \z/x ## # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z Regex_6Hex4Dec = /\A ((?:[0-9A-Fa-f]{1,4}:){6,6}) (\d+)\.(\d+)\.(\d+)\.(\d+) \z/x ## # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z Regex_CompressedHex4Dec = /\A ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: ((?:[0-9A-Fa-f]{1,4}:)*) (\d+)\.(\d+)\.(\d+)\.(\d+) \z/x ## # A composite IPv6 address Regexp. Regex = / (?:#{Regex_8Hex}) | (?:#{Regex_CompressedHex}) | (?:#{Regex_6Hex4Dec}) | (?:#{Regex_CompressedHex4Dec})/x ## # Creates a new IPv6 address from +arg+ which may be: # # IPv6:: returns +arg+. # String:: +arg+ must match one of the IPv6::Regex* constants def self.create(arg) case arg when IPv6 return arg when String address = '' if Regex_8Hex =~ arg arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')} elsif Regex_CompressedHex =~ arg prefix = $1 suffix = $2 a1 = '' a2 = '' prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')} suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')} omitlen = 16 - a1.length - a2.length address << a1 << "\0" * omitlen << a2 elsif Regex_6Hex4Dec =~ arg prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')} address << [a, b, c, d].pack('CCCC') else raise ArgumentError.new("not numeric IPv6 address: " + arg) end elsif Regex_CompressedHex4Dec =~ arg prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d a1 = '' a2 = '' prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')} suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')} omitlen = 12 - a1.length - a2.length address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC') else raise ArgumentError.new("not numeric IPv6 address: " + arg) end else raise ArgumentError.new("not numeric IPv6 address: " + arg) end return IPv6.new(address) else raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}") end end def initialize(address) # :nodoc: unless address.kind_of?(String) && address.length == 16 raise ArgumentError.new('IPv6 address must be 16 bytes') end @address = address end ## # The raw IPv6 address as a String. attr_reader :address def to_s # :nodoc: address = sprintf("%X:%X:%X:%X:%X:%X:%X:%X", *@address.unpack("nnnnnnnn")) unless address.sub!(/(^|:)0(:0)+(:|$)/, '::') address.sub!(/(^|:)0(:|$)/, '::') end return address end def inspect # :nodoc: return "#<#{self.class} #{self.to_s}>" end ## # Turns this IPv6 address into a Resolv::DNS::Name. #-- # ip6.arpa should be searched too. [RFC3152] def to_name return DNS::Name.new( @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa']) end def ==(other) # :nodoc: return @address == other.address end def eql?(other) # :nodoc: return self == other end def hash # :nodoc: return @address.hash end end ## # Default resolver to use for Resolv class methods. DefaultResolver = self.new ## # Address Regexp to use for matching IP addresses. AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/ end PK|]usKK rss/atom.rbnu[require 'base64' require 'rss/parser' module RSS module Atom URI = "http://www.w3.org/2005/Atom" XHTML_URI = "http://www.w3.org/1999/xhtml" module CommonModel NSPOOL = {} ELEMENTS = [] def self.append_features(klass) super klass.install_must_call_validator("atom", URI) [ ["lang", :xml], ["base", :xml], ].each do |name, uri, required| klass.install_get_attribute(name, uri, required, [nil, :inherit]) end klass.class_eval do class << self def required_uri URI end def need_parent? true end end end end end module ContentModel module ClassMethods def content_type @content_type ||= nil end end class << self def append_features(klass) super klass.extend(ClassMethods) klass.content_setup(klass.content_type, klass.tag_name) end end def maker_target(target) target end private def setup_maker_element_writer "#{self.class.name.split(/::/).last.downcase}=" end def setup_maker_element(target) target.__send__(setup_maker_element_writer, content) super end end module URIContentModel class << self def append_features(klass) super klass.class_eval do @content_type = [nil, :uri] include(ContentModel) end end end end module TextConstruct def self.append_features(klass) super klass.class_eval do [ ["type", ""], ].each do |name, uri, required| install_get_attribute(name, uri, required, :text_type) end content_setup add_need_initialize_variable("xhtml") class << self def xml_getter "xhtml" end def xml_setter "xhtml=" end end end end attr_writer :xhtml def xhtml return @xhtml if @xhtml.nil? if @xhtml.is_a?(XML::Element) and [@xhtml.name, @xhtml.uri] == ["div", XHTML_URI] return @xhtml end children = @xhtml children = [children] unless children.is_a?(Array) XML::Element.new("div", nil, XHTML_URI, {"xmlns" => XHTML_URI}, children) end def have_xml_content? @type == "xhtml" end def atom_validate(ignore_unknown_element, tags, uri) if have_xml_content? if @xhtml.nil? raise MissingTagError.new("div", tag_name) end unless [@xhtml.name, @xhtml.uri] == ["div", XHTML_URI] raise NotExpectedTagError.new(@xhtml.name, @xhtml.uri, tag_name) end end end private def maker_target(target) target.__send__(self.class.name.split(/::/).last.downcase) {|x| x} end def setup_maker_attributes(target) target.type = type target.content = content target.xml_content = @xhtml end end module PersonConstruct def self.append_features(klass) super klass.class_eval do [ ["name", nil], ["uri", "?"], ["email", "?"], ].each do |tag, occurs| install_have_attribute_element(tag, URI, occurs, nil, :content) end end end def maker_target(target) target.__send__("new_#{self.class.name.split(/::/).last.downcase}") end class Name < RSS::Element include CommonModel include ContentModel end class Uri < RSS::Element include CommonModel include URIContentModel end class Email < RSS::Element include CommonModel include ContentModel end end module DateConstruct def self.append_features(klass) super klass.class_eval do @content_type = :w3cdtf include(ContentModel) end end def atom_validate(ignore_unknown_element, tags, uri) raise NotAvailableValueError.new(tag_name, "") if content.nil? end end module DuplicateLinkChecker def validate_duplicate_links(links) link_infos = {} links.each do |link| rel = link.rel || "alternate" next unless rel == "alternate" key = [link.hreflang, link.type] if link_infos.has_key?(key) raise TooMuchTagError.new("link", tag_name) end link_infos[key] = true end end end class Feed < RSS::Element include RootElementMixin include CommonModel include DuplicateLinkChecker install_ns('', URI) [ ["author", "*", :children], ["category", "*", :children, "categories"], ["contributor", "*", :children], ["generator", "?"], ["icon", "?", nil, :content], ["id", nil, nil, :content], ["link", "*", :children], ["logo", "?"], ["rights", "?"], ["subtitle", "?", nil, :content], ["title", nil, nil, :content], ["updated", nil, nil, :content], ["entry", "*", :children, "entries"], ].each do |tag, occurs, type, *args| type ||= :child __send__("install_have_#{type}_element", tag, URI, occurs, tag, *args) end def initialize(version=nil, encoding=nil, standalone=nil) super("1.0", version, encoding, standalone) @feed_type = "atom" @feed_subtype = "feed" end alias_method :items, :entries def have_author? authors.any? {|author| !author.to_s.empty?} or entries.any? {|entry| entry.have_author?(false)} end private def atom_validate(ignore_unknown_element, tags, uri) unless have_author? raise MissingTagError.new("author", tag_name) end validate_duplicate_links(links) end def have_required_elements? super and have_author? end def maker_target(maker) maker.channel end def setup_maker_element(channel) prev_dc_dates = channel.dc_dates.to_a.dup super channel.about = id.content if id channel.dc_dates.replace(prev_dc_dates) end def setup_maker_elements(channel) super items = channel.maker.items entries.each do |entry| entry.setup_maker(items) end end class Author < RSS::Element include CommonModel include PersonConstruct end class Category < RSS::Element include CommonModel [ ["term", "", true], ["scheme", "", false, [nil, :uri]], ["label", ""], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end private def maker_target(target) target.new_category end end class Contributor < RSS::Element include CommonModel include PersonConstruct end class Generator < RSS::Element include CommonModel include ContentModel [ ["uri", "", false, [nil, :uri]], ["version", ""], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end private def setup_maker_attributes(target) target.generator do |generator| generator.uri = uri if uri generator.version = version if version end end end class Icon < RSS::Element include CommonModel include URIContentModel end class Id < RSS::Element include CommonModel include URIContentModel end class Link < RSS::Element include CommonModel [ ["href", "", true, [nil, :uri]], ["rel", ""], ["type", ""], ["hreflang", ""], ["title", ""], ["length", ""], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end private def maker_target(target) target.new_link end end class Logo < RSS::Element include CommonModel include URIContentModel def maker_target(target) target.maker.image end private def setup_maker_element_writer "url=" end end class Rights < RSS::Element include CommonModel include TextConstruct end class Subtitle < RSS::Element include CommonModel include TextConstruct end class Title < RSS::Element include CommonModel include TextConstruct end class Updated < RSS::Element include CommonModel include DateConstruct end class Entry < RSS::Element include CommonModel include DuplicateLinkChecker [ ["author", "*", :children], ["category", "*", :children, "categories"], ["content", "?", :child], ["contributor", "*", :children], ["id", nil, nil, :content], ["link", "*", :children], ["published", "?", :child, :content], ["rights", "?", :child], ["source", "?"], ["summary", "?", :child], ["title", nil], ["updated", nil, :child, :content], ].each do |tag, occurs, type, *args| type ||= :attribute __send__("install_have_#{type}_element", tag, URI, occurs, tag, *args) end def have_author?(check_parent=true) authors.any? {|author| !author.to_s.empty?} or (check_parent and @parent and @parent.have_author?) or (source and source.have_author?) end private def atom_validate(ignore_unknown_element, tags, uri) unless have_author? raise MissingTagError.new("author", tag_name) end validate_duplicate_links(links) end def have_required_elements? super and have_author? end def maker_target(items) if items.respond_to?("items") # For backward compatibility items = items.items end items.new_item end Author = Feed::Author Category = Feed::Category class Content < RSS::Element include CommonModel class << self def xml_setter "xml=" end def xml_getter "xml" end end [ ["type", ""], ["src", "", false, [nil, :uri]], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end content_setup add_need_initialize_variable("xml") attr_writer :xml def have_xml_content? inline_xhtml? or inline_other_xml? end def xml return @xml unless inline_xhtml? return @xml if @xml.nil? if @xml.is_a?(XML::Element) and [@xml.name, @xml.uri] == ["div", XHTML_URI] return @xml end children = @xml children = [children] unless children.is_a?(Array) XML::Element.new("div", nil, XHTML_URI, {"xmlns" => XHTML_URI}, children) end def xhtml if inline_xhtml? xml else nil end end def atom_validate(ignore_unknown_element, tags, uri) if out_of_line? raise MissingAttributeError.new(tag_name, "type") if @type.nil? unless (content.nil? or content.empty?) raise NotAvailableValueError.new(tag_name, content) end elsif inline_xhtml? if @xml.nil? raise MissingTagError.new("div", tag_name) end unless @xml.name == "div" and @xml.uri == XHTML_URI raise NotExpectedTagError.new(@xml.name, @xml.uri, tag_name) end end end def inline_text? !out_of_line? and [nil, "text", "html"].include?(@type) end def inline_html? return false if out_of_line? @type == "html" or mime_split == ["text", "html"] end def inline_xhtml? !out_of_line? and @type == "xhtml" end def inline_other? return false if out_of_line? media_type, subtype = mime_split return false if media_type.nil? or subtype.nil? true end def inline_other_text? return false unless inline_other? return false if inline_other_xml? media_type, subtype = mime_split return true if "text" == media_type.downcase false end def inline_other_xml? return false unless inline_other? media_type, subtype = mime_split normalized_mime_type = "#{media_type}/#{subtype}".downcase if /(?:\+xml|^xml)$/ =~ subtype or %w(text/xml-external-parsed-entity application/xml-external-parsed-entity application/xml-dtd).find {|x| x == normalized_mime_type} return true end false end def inline_other_base64? inline_other? and !inline_other_text? and !inline_other_xml? end def out_of_line? not @src.nil? end def mime_split media_type = subtype = nil if /\A\s*([a-z]+)\/([a-z\+]+)\s*(?:;.*)?\z/i =~ @type.to_s media_type = $1.downcase subtype = $2.downcase end [media_type, subtype] end def need_base64_encode? inline_other_base64? end private def empty_content? out_of_line? or super end end Contributor = Feed::Contributor Id = Feed::Id Link = Feed::Link class Published < RSS::Element include CommonModel include DateConstruct end Rights = Feed::Rights class Source < RSS::Element include CommonModel [ ["author", "*", :children], ["category", "*", :children, "categories"], ["contributor", "*", :children], ["generator", "?"], ["icon", "?"], ["id", "?", nil, :content], ["link", "*", :children], ["logo", "?"], ["rights", "?"], ["subtitle", "?"], ["title", "?"], ["updated", "?", nil, :content], ].each do |tag, occurs, type, *args| type ||= :attribute __send__("install_have_#{type}_element", tag, URI, occurs, tag, *args) end def have_author? !author.to_s.empty? end Author = Feed::Author Category = Feed::Category Contributor = Feed::Contributor Generator = Feed::Generator Icon = Feed::Icon Id = Feed::Id Link = Feed::Link Logo = Feed::Logo Rights = Feed::Rights Subtitle = Feed::Subtitle Title = Feed::Title Updated = Feed::Updated end class Summary < RSS::Element include CommonModel include TextConstruct end Title = Feed::Title Updated = Feed::Updated end end class Entry < RSS::Element include RootElementMixin include CommonModel include DuplicateLinkChecker [ ["author", "*", :children], ["category", "*", :children, "categories"], ["content", "?"], ["contributor", "*", :children], ["id", nil, nil, :content], ["link", "*", :children], ["published", "?", :child, :content], ["rights", "?"], ["source", "?"], ["summary", "?"], ["title", nil], ["updated", nil, nil, :content], ].each do |tag, occurs, type, *args| type ||= :attribute __send__("install_have_#{type}_element", tag, URI, occurs, tag, *args) end def initialize(version=nil, encoding=nil, standalone=nil) super("1.0", version, encoding, standalone) @feed_type = "atom" @feed_subtype = "entry" end def items [self] end def setup_maker(maker) maker = maker.maker if maker.respond_to?("maker") super(maker) end def have_author? authors.any? {|author| !author.to_s.empty?} or (source and source.have_author?) end private def atom_validate(ignore_unknown_element, tags, uri) unless have_author? raise MissingTagError.new("author", tag_name) end validate_duplicate_links(links) end def have_required_elements? super and have_author? end def maker_target(maker) maker.items.new_item end Author = Feed::Entry::Author Category = Feed::Entry::Category Content = Feed::Entry::Content Contributor = Feed::Entry::Contributor Id = Feed::Entry::Id Link = Feed::Entry::Link Published = Feed::Entry::Published Rights = Feed::Entry::Rights Source = Feed::Entry::Source Summary = Feed::Entry::Summary Title = Feed::Entry::Title Updated = Feed::Entry::Updated end end Atom::CommonModel::ELEMENTS.each do |name| BaseListener.install_get_text_element(Atom::URI, name, "#{name}=") end module ListenerMixin private def initial_start_feed(tag_name, prefix, attrs, ns) check_ns(tag_name, prefix, ns, Atom::URI) @rss = Atom::Feed.new(@version, @encoding, @standalone) @rss.do_validate = @do_validate @rss.xml_stylesheets = @xml_stylesheets @rss.lang = attrs["xml:lang"] @rss.base = attrs["xml:base"] @last_element = @rss pr = Proc.new do |text, tags| @rss.validate_for_stream(tags) if @do_validate end @proc_stack.push(pr) end def initial_start_entry(tag_name, prefix, attrs, ns) check_ns(tag_name, prefix, ns, Atom::URI) @rss = Atom::Entry.new(@version, @encoding, @standalone) @rss.do_validate = @do_validate @rss.xml_stylesheets = @xml_stylesheets @rss.lang = attrs["xml:lang"] @rss.base = attrs["xml:base"] @last_element = @rss pr = Proc.new do |text, tags| @rss.validate_for_stream(tags) if @do_validate end @proc_stack.push(pr) end end end PK|]%I{rss/dublincore.rbnu[require "rss/rss" module RSS DC_PREFIX = 'dc' DC_URI = "http://purl.org/dc/elements/1.1/" module BaseDublinCoreModel def append_features(klass) super return if klass.instance_of?(Module) DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| plural = plural_name || "#{name}s" full_name = "#{DC_PREFIX}_#{name}" full_plural_name = "#{DC_PREFIX}_#{plural}" klass_name = "DublinCore#{Utils.to_class_name(name)}" klass.install_must_call_validator(DC_PREFIX, DC_URI) klass.install_have_children_element(name, DC_URI, "*", full_name, full_plural_name) klass.module_eval(<<-EOC, *get_file_and_line_from_caller(0)) remove_method :#{full_name} remove_method :#{full_name}= remove_method :set_#{full_name} def #{full_name} @#{full_name}.first and @#{full_name}.first.value end def #{full_name}=(new_value) @#{full_name}[0] = Utils.new_with_value_if_need(#{klass_name}, new_value) end alias set_#{full_name} #{full_name}= EOC end klass.module_eval(<<-EOC, *get_file_and_line_from_caller(0)) if method_defined?(:date) alias date_without_#{DC_PREFIX}_date= date= def date=(value) self.date_without_#{DC_PREFIX}_date = value self.#{DC_PREFIX}_date = value end else alias date #{DC_PREFIX}_date alias date= #{DC_PREFIX}_date= end # For backward compatibility alias #{DC_PREFIX}_rightses #{DC_PREFIX}_rights_list EOC end end module DublinCoreModel extend BaseModel extend BaseDublinCoreModel TEXT_ELEMENTS = { "title" => nil, "description" => nil, "creator" => nil, "subject" => nil, "publisher" => nil, "contributor" => nil, "type" => nil, "format" => nil, "identifier" => nil, "source" => nil, "language" => nil, "relation" => nil, "coverage" => nil, "rights" => "rights_list" } DATE_ELEMENTS = { "date" => "w3cdtf", } ELEMENT_NAME_INFOS = DublinCoreModel::TEXT_ELEMENTS.to_a DublinCoreModel::DATE_ELEMENTS.each do |name, | ELEMENT_NAME_INFOS << [name, nil] end ELEMENTS = TEXT_ELEMENTS.keys + DATE_ELEMENTS.keys ELEMENTS.each do |name, plural_name| module_eval(<<-EOC, *get_file_and_line_from_caller(0)) class DublinCore#{Utils.to_class_name(name)} < Element include RSS10 content_setup class << self def required_prefix DC_PREFIX end def required_uri DC_URI end end @tag_name = #{name.dump} alias_method(:value, :content) alias_method(:value=, :content=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end def full_name tag_name_with_prefix(DC_PREFIX) end def maker_target(target) target.new_#{name} end def setup_maker_attributes(#{name}) #{name}.content = content end end EOC end DATE_ELEMENTS.each do |name, type| tag_name = "#{DC_PREFIX}:#{name}" module_eval(<<-EOC, *get_file_and_line_from_caller(0)) class DublinCore#{Utils.to_class_name(name)} < Element remove_method(:content=) remove_method(:value=) date_writer("content", #{type.dump}, #{tag_name.dump}) alias_method(:value=, :content=) end EOC end end # For backward compatibility DublincoreModel = DublinCoreModel DublinCoreModel::ELEMENTS.each do |name| class_name = Utils.to_class_name(name) BaseListener.install_class_name(DC_URI, name, "DublinCore#{class_name}") end DublinCoreModel::ELEMENTS.collect! {|name| "#{DC_PREFIX}_#{name}"} end require 'rss/dublincore/1.0' require 'rss/dublincore/2.0' require 'rss/dublincore/atom' PK|] rss/xml-stylesheet.rbnu[require "rss/utils" module RSS module XMLStyleSheetMixin attr_accessor :xml_stylesheets def initialize(*args) super @xml_stylesheets = [] end private def xml_stylesheet_pi xsss = @xml_stylesheets.collect do |xss| pi = xss.to_s pi = nil if /\A\s*\z/ =~ pi pi end.compact xsss.push("") unless xsss.empty? xsss.join("\n") end end class XMLStyleSheet include Utils ATTRIBUTES = %w(href type title media charset alternate) GUESS_TABLE = { "xsl" => "text/xsl", "css" => "text/css", } attr_accessor(*ATTRIBUTES) attr_accessor(:do_validate) def initialize(*attrs) if attrs.size == 1 and (attrs.first.is_a?(Hash) or attrs.first.is_a?(Array)) attrs = attrs.first end @do_validate = true ATTRIBUTES.each do |attr| __send__("#{attr}=", nil) end vars = ATTRIBUTES.dup vars.unshift(:do_validate) attrs.each do |name, value| if vars.include?(name.to_s) __send__("#{name}=", value) end end end def to_s rv = "" if @href rv << %Q[] end rv end remove_method(:href=) def href=(value) @href = value if @href and @type.nil? @type = guess_type(@href) end @href end remove_method(:alternate=) def alternate=(value) if value.nil? or /\A(?:yes|no)\z/ =~ value @alternate = value else if @do_validate args = ["?xml-stylesheet?", %Q[alternate="#{value}"]] raise NotAvailableValueError.new(*args) end end @alternate end def setup_maker(maker) xss = maker.xml_stylesheets.new_xml_stylesheet ATTRIBUTES.each do |attr| xss.__send__("#{attr}=", __send__(attr)) end end private def guess_type(filename) /\.([^.]+)$/ =~ filename GUESS_TABLE[$1] end end end PK|]/Hrss/content.rbnu[require "rss/rss" module RSS CONTENT_PREFIX = 'content' CONTENT_URI = "http://purl.org/rss/1.0/modules/content/" module ContentModel extend BaseModel ELEMENTS = ["#{CONTENT_PREFIX}_encoded"] def self.append_features(klass) super klass.install_must_call_validator(CONTENT_PREFIX, CONTENT_URI) ELEMENTS.each do |full_name| name = full_name[(CONTENT_PREFIX.size + 1)..-1] klass.install_text_element(name, CONTENT_URI, "?", full_name) end end end prefix_size = CONTENT_PREFIX.size + 1 ContentModel::ELEMENTS.each do |full_name| name = full_name[prefix_size..-1] BaseListener.install_get_text_element(CONTENT_URI, name, full_name) end end require 'rss/content/1.0' require 'rss/content/2.0' PK|]Y%% rss/0.9.rbnu[require "rss/parser" module RSS module RSS09 NSPOOL = {} ELEMENTS = [] def self.append_features(klass) super klass.install_must_call_validator('', "") end end class Rss < Element include RSS09 include RootElementMixin %w(channel).each do |name| install_have_child_element(name, "", nil) end attr_writer :feed_version alias_method(:rss_version, :feed_version) alias_method(:rss_version=, :feed_version=) def initialize(feed_version, version=nil, encoding=nil, standalone=nil) super @feed_type = "rss" end def items if @channel @channel.items else [] end end def image if @channel @channel.image else nil end end def textinput if @channel @channel.textInput else nil end end def setup_maker_elements(maker) super items.each do |item| item.setup_maker(maker.items) end image.setup_maker(maker) if image textinput.setup_maker(maker) if textinput end private def _attrs [ ["version", true, "feed_version"], ] end class Channel < Element include RSS09 [ ["title", nil, :text], ["link", nil, :text], ["description", nil, :text], ["language", nil, :text], ["copyright", "?", :text], ["managingEditor", "?", :text], ["webMaster", "?", :text], ["rating", "?", :text], ["pubDate", "?", :date, :rfc822], ["lastBuildDate", "?", :date, :rfc822], ["docs", "?", :text], ["cloud", "?", :have_attribute], ["skipDays", "?", :have_child], ["skipHours", "?", :have_child], ["image", nil, :have_child], ["item", "*", :have_children], ["textInput", "?", :have_child], ].each do |name, occurs, type, *args| __send__("install_#{type}_element", name, "", occurs, name, *args) end alias date pubDate alias date= pubDate= private def maker_target(maker) maker.channel end def setup_maker_elements(channel) super [ [skipDays, "day"], [skipHours, "hour"], ].each do |skip, key| if skip skip.__send__("#{key}s").each do |val| target_skips = channel.__send__("skip#{key.capitalize}s") new_target = target_skips.__send__("new_#{key}") new_target.content = val.content end end end end def not_need_to_call_setup_maker_variables %w(image textInput) end class SkipDays < Element include RSS09 [ ["day", "*"] ].each do |name, occurs| install_have_children_element(name, "", occurs) end class Day < Element include RSS09 content_setup def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end end end class SkipHours < Element include RSS09 [ ["hour", "*"] ].each do |name, occurs| install_have_children_element(name, "", occurs) end class Hour < Element include RSS09 content_setup(:integer) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end end end class Image < Element include RSS09 %w(url title link).each do |name| install_text_element(name, "", nil) end [ ["width", :integer], ["height", :integer], ["description"], ].each do |name, type| install_text_element(name, "", "?", name, type) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.url = args[0] self.title = args[1] self.link = args[2] self.width = args[3] self.height = args[4] self.description = args[5] end end private def maker_target(maker) maker.image end end class Cloud < Element include RSS09 [ ["domain", "", true], ["port", "", true, :integer], ["path", "", true], ["registerProcedure", "", true], ["protocol", "", true], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.domain = args[0] self.port = args[1] self.path = args[2] self.registerProcedure = args[3] self.protocol = args[4] end end end class Item < Element include RSS09 [ ["title", '?', :text], ["link", '?', :text], ["description", '?', :text], ["category", '*', :have_children, "categories"], ["source", '?', :have_child], ["enclosure", '?', :have_child], ].each do |tag, occurs, type, *args| __send__("install_#{type}_element", tag, "", occurs, tag, *args) end private def maker_target(items) if items.respond_to?("items") # For backward compatibility items = items.items end items.new_item end def setup_maker_element(item) super @enclosure.setup_maker(item) if @enclosure @source.setup_maker(item) if @source end class Source < Element include RSS09 [ ["url", "", true] ].each do |name, uri, required| install_get_attribute(name, uri, required) end content_setup def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.url = args[0] self.content = args[1] end end private def maker_target(item) item.source end def setup_maker_attributes(source) source.url = url source.content = content end end class Enclosure < Element include RSS09 [ ["url", "", true], ["length", "", true, :integer], ["type", "", true], ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.url = args[0] self.length = args[1] self.type = args[2] end end private def maker_target(item) item.enclosure end def setup_maker_attributes(enclosure) enclosure.url = url enclosure.length = length enclosure.type = type end end class Category < Element include RSS09 [ ["domain", "", false] ].each do |name, uri, required| install_get_attribute(name, uri, required) end content_setup def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.domain = args[0] self.content = args[1] end end private def maker_target(item) item.new_category end def setup_maker_attributes(category) category.domain = domain category.content = content end end end class TextInput < Element include RSS09 %w(title description name link).each do |name| install_text_element(name, "", nil) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.title = args[0] self.description = args[1] self.name = args[2] self.link = args[3] end end private def maker_target(maker) maker.textinput end end end end RSS09::ELEMENTS.each do |name| BaseListener.install_get_text_element("", name, name) end module ListenerMixin private def initial_start_rss(tag_name, prefix, attrs, ns) check_ns(tag_name, prefix, ns, "") @rss = Rss.new(attrs['version'], @version, @encoding, @standalone) @rss.do_validate = @do_validate @rss.xml_stylesheets = @xml_stylesheets @last_element = @rss pr = Proc.new do |text, tags| @rss.validate_for_stream(tags, @ignore_unknown_element) if @do_validate end @proc_stack.push(pr) end end end PK|]Ye rss/xml.rbnu[require "rss/utils" module RSS module XML class Element include Enumerable attr_reader :name, :prefix, :uri, :attributes, :children def initialize(name, prefix=nil, uri=nil, attributes={}, children=[]) @name = name @prefix = prefix @uri = uri @attributes = attributes if children.is_a?(String) or !children.respond_to?(:each) @children = [children] else @children = children end end def [](name) @attributes[name] end def []=(name, value) @attributes[name] = value end def <<(child) @children << child end def each(&block) @children.each(&block) end def ==(other) other.kind_of?(self.class) and @name == other.name and @uri == other.uri and @attributes == other.attributes and @children == other.children end def to_s rv = "<#{full_name}" attributes.each do |key, value| rv << " #{Utils.html_escape(key)}=\"#{Utils.html_escape(value)}\"" end if children.empty? rv << "/>" else rv << ">" children.each do |child| rv << child.to_s end rv << "" end rv end def full_name if @prefix "#{@prefix}:#{@name}" else @name end end end end end PK|]Trss/dublincore/atom.rbnu[require "rss/atom" require "rss/dublincore" module RSS module Atom Feed.install_ns(DC_PREFIX, DC_URI) class Feed include DublinCoreModel class Entry; include DublinCoreModel; end end class Entry include DublinCoreModel end end end PK|]G//rss/dublincore/1.0.rbnu[require "rss/1.0" require "rss/dublincore" module RSS RDF.install_ns(DC_PREFIX, DC_URI) class RDF class Channel; include DublinCoreModel; end class Image; include DublinCoreModel; end class Item; include DublinCoreModel; end class Textinput; include DublinCoreModel; end end end PK|]]Srss/dublincore/2.0.rbnu[require "rss/2.0" require "rss/dublincore" module RSS Rss.install_ns(DC_PREFIX, DC_URI) class Rss class Channel include DublinCoreModel class Item; include DublinCoreModel; end end end end PK|]*>>:: rss/parser.rbnu[require "forwardable" require "open-uri" require "rss/rss" require "rss/xml" module RSS class NotWellFormedError < Error attr_reader :line, :element # Create a new NotWellFormedError for an error at +line+ # in +element+. If a block is given the return value of # the block ends up in the error message. def initialize(line=nil, element=nil) message = "This is not well formed XML" if element or line message << "\nerror occurred" message << " in #{element}" if element message << " at about #{line} line" if line end message << "\n#{yield}" if block_given? super(message) end end class XMLParserNotFound < Error def initialize super("available XML parser was not found in " << "#{AVAILABLE_PARSER_LIBRARIES.inspect}.") end end class NotValidXMLParser < Error def initialize(parser) super("#{parser} is not an available XML parser. " << "Available XML parser"<< (AVAILABLE_PARSERS.size > 1 ? "s are ": " is ") << "#{AVAILABLE_PARSERS.inspect}.") end end class NSError < InvalidRSSError attr_reader :tag, :prefix, :uri def initialize(tag, prefix, require_uri) @tag, @prefix, @uri = tag, prefix, require_uri super("prefix <#{prefix}> doesn't associate uri " << "<#{require_uri}> in tag <#{tag}>") end end class Parser extend Forwardable class << self @@default_parser = nil def default_parser @@default_parser || AVAILABLE_PARSERS.first end # Set @@default_parser to new_value if it is one of the # available parsers. Else raise NotValidXMLParser error. def default_parser=(new_value) if AVAILABLE_PARSERS.include?(new_value) @@default_parser = new_value else raise NotValidXMLParser.new(new_value) end end def parse(rss, do_validate=true, ignore_unknown_element=true, parser_class=default_parser) parser = new(rss, parser_class) parser.do_validate = do_validate parser.ignore_unknown_element = ignore_unknown_element parser.parse end end def_delegators(:@parser, :parse, :rss, :ignore_unknown_element, :ignore_unknown_element=, :do_validate, :do_validate=) def initialize(rss, parser_class=self.class.default_parser) @parser = parser_class.new(normalize_rss(rss)) end private # Try to get the XML associated with +rss+. # Return +rss+ if it already looks like XML, or treat it as a URI, # or a file to get the XML, def normalize_rss(rss) return rss if maybe_xml?(rss) uri = to_uri(rss) if uri.respond_to?(:read) uri.read elsif !rss.tainted? and File.readable?(rss) File.open(rss) {|f| f.read} else rss end end # maybe_xml? tests if source is a string that looks like XML. def maybe_xml?(source) source.is_a?(String) and / :xml}] @tag_stack = [[]] @text_stack = [''] @proc_stack = [] @last_element = nil @version = @encoding = @standalone = nil @xml_stylesheets = [] @xml_child_mode = false @xml_element = nil @last_xml_element = nil end # set instance vars for version, encoding, standalone def xmldecl(version, encoding, standalone) @version, @encoding, @standalone = version, encoding, standalone end def instruction(name, content) if name == "xml-stylesheet" params = parse_pi_content(content) if params.has_key?("href") @xml_stylesheets << XMLStyleSheet.new(params) end end end def tag_start(name, attributes) @text_stack.push('') ns = @ns_stack.last.dup attrs = {} attributes.each do |n, v| if /\Axmlns(?:\z|:)/ =~ n ns[$POSTMATCH] = v else attrs[n] = v end end @ns_stack.push(ns) prefix, local = split_name(name) @tag_stack.last.push([_ns(ns, prefix), local]) @tag_stack.push([]) if @xml_child_mode previous = @last_xml_element element_attrs = attributes.dup unless previous ns.each do |ns_prefix, value| next if ns_prefix == "xml" key = ns_prefix.empty? ? "xmlns" : "xmlns:#{ns_prefix}" element_attrs[key] ||= value end end next_element = XML::Element.new(local, prefix.empty? ? nil : prefix, _ns(ns, prefix), element_attrs) previous << next_element if previous @last_xml_element = next_element pr = Proc.new do |text, tags| if previous @last_xml_element = previous else @xml_element = @last_xml_element @last_xml_element = nil end end @proc_stack.push(pr) else if @rss.nil? and respond_to?("initial_start_#{local}", true) __send__("initial_start_#{local}", local, prefix, attrs, ns.dup) elsif respond_to?("start_#{local}", true) __send__("start_#{local}", local, prefix, attrs, ns.dup) else start_else_element(local, prefix, attrs, ns.dup) end end end def tag_end(name) if DEBUG p "end tag #{name}" p @tag_stack end text = @text_stack.pop tags = @tag_stack.pop pr = @proc_stack.pop pr.call(text, tags) unless pr.nil? @ns_stack.pop end def text(data) if @xml_child_mode @last_xml_element << data if @last_xml_element else @text_stack.last << data end end private def _ns(ns, prefix) ns.fetch(prefix, "") end CONTENT_PATTERN = /\s*([^=]+)=(["'])([^\2]+?)\2/ # Extract the first name="value" pair from content. # Works with single quotes according to the constant # CONTENT_PATTERN. Return a Hash. def parse_pi_content(content) params = {} content.scan(CONTENT_PATTERN) do |name, quote, value| params[name] = value end params end def start_else_element(local, prefix, attrs, ns) class_name = self.class.class_name(_ns(ns, prefix), local) current_class = @last_element.class if class_name and (current_class.const_defined?(class_name) or current_class.constants.include?(class_name)) next_class = current_class.const_get(class_name) start_have_something_element(local, prefix, attrs, ns, next_class) else if !@do_validate or @ignore_unknown_element @proc_stack.push(nil) else parent = "ROOT ELEMENT???" if current_class.tag_name parent = current_class.tag_name end raise NotExpectedTagError.new(local, _ns(ns, prefix), parent) end end end NAMESPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/ def split_name(name) name =~ NAMESPLIT [$1 || '', $2] end def check_ns(tag_name, prefix, ns, require_uri) unless _ns(ns, prefix) == require_uri if @do_validate raise NSError.new(tag_name, prefix, require_uri) else # Force bind required URI with prefix @ns_stack.last[prefix] = require_uri end end end def start_get_text_element(tag_name, prefix, ns, required_uri) pr = Proc.new do |text, tags| setter = self.class.setter(required_uri, tag_name) if @last_element.respond_to?(setter) if @do_validate getter = self.class.getter(required_uri, tag_name) if @last_element.__send__(getter) raise TooMuchTagError.new(tag_name, @last_element.tag_name) end end @last_element.__send__(setter, text.to_s) else if @do_validate and !@ignore_unknown_element raise NotExpectedTagError.new(tag_name, _ns(ns, prefix), @last_element.tag_name) end end end @proc_stack.push(pr) end def start_have_something_element(tag_name, prefix, attrs, ns, klass) check_ns(tag_name, prefix, ns, klass.required_uri) attributes = collect_attributes(tag_name, prefix, attrs, ns, klass) @proc_stack.push(setup_next_element(tag_name, klass, attributes)) end def collect_attributes(tag_name, prefix, attrs, ns, klass) attributes = {} klass.get_attributes.each do |a_name, a_uri, required, element_name| if a_uri.is_a?(String) or !a_uri.respond_to?(:include?) a_uri = [a_uri] end unless a_uri == [""] for prefix, uri in ns if a_uri.include?(uri) val = attrs["#{prefix}:#{a_name}"] break if val end end end if val.nil? and a_uri.include?("") val = attrs[a_name] end if @do_validate and required and val.nil? unless a_uri.include?("") for prefix, uri in ns if a_uri.include?(uri) a_name = "#{prefix}:#{a_name}" end end end raise MissingAttributeError.new(tag_name, a_name) end attributes[a_name] = val end attributes end def setup_next_element(tag_name, klass, attributes) previous = @last_element next_element = klass.new(@do_validate, attributes) previous.set_next_element(tag_name, next_element) @last_element = next_element @last_element.parent = previous if klass.need_parent? @xml_child_mode = @last_element.have_xml_content? Proc.new do |text, tags| p(@last_element.class) if DEBUG if @xml_child_mode @last_element.content = @xml_element.to_s xml_setter = @last_element.class.xml_setter @last_element.__send__(xml_setter, @xml_element) @xml_element = nil @xml_child_mode = false else if klass.have_content? if @last_element.need_base64_encode? text = Base64.decode64(text.lstrip) end @last_element.content = text end end if @do_validate @last_element.validate_for_stream(tags, @ignore_unknown_element) end @last_element = previous end end end unless const_defined? :AVAILABLE_PARSER_LIBRARIES AVAILABLE_PARSER_LIBRARIES = [ ["rss/xmlparser", :XMLParserParser], ["rss/xmlscanner", :XMLScanParser], ["rss/rexmlparser", :REXMLParser], ] end AVAILABLE_PARSERS = [] AVAILABLE_PARSER_LIBRARIES.each do |lib, parser| begin require lib AVAILABLE_PARSERS.push(const_get(parser)) rescue LoadError end end if AVAILABLE_PARSERS.empty? raise XMLParserNotFound end end PK|](||rss/xmlscanner.rbnu[require 'xmlscan/scanner' require 'stringio' module RSS class XMLScanParser < BaseParser class << self def listener XMLScanListener end end private def _parse begin if @rss.is_a?(String) input = StringIO.new(@rss) else input = @rss end scanner = XMLScan::XMLScanner.new(@listener) scanner.parse(input) rescue XMLScan::Error => e lineno = e.lineno || scanner.lineno || input.lineno raise NotWellFormedError.new(lineno){e.message} end end end class XMLScanListener < BaseListener include XMLScan::Visitor include ListenerMixin ENTITIES = { 'lt' => '<', 'gt' => '>', 'amp' => '&', 'quot' => '"', 'apos' => '\'' } def on_xmldecl_version(str) @version = str end def on_xmldecl_encoding(str) @encoding = str end def on_xmldecl_standalone(str) @standalone = str end def on_xmldecl_end xmldecl(@version, @encoding, @standalone == "yes") end alias_method(:on_pi, :instruction) alias_method(:on_chardata, :text) alias_method(:on_cdata, :text) def on_etag(name) tag_end(name) end def on_entityref(ref) text(entity(ref)) end def on_charref(code) text([code].pack('U')) end alias_method(:on_charref_hex, :on_charref) def on_stag(name) @attrs = {} end def on_attribute(name) @attrs[name] = @current_attr = '' end def on_attr_value(str) @current_attr << str end def on_attr_entityref(ref) @current_attr << entity(ref) end def on_attr_charref(code) @current_attr << [code].pack('U') end alias_method(:on_attr_charref_hex, :on_attr_charref) def on_stag_end(name) tag_start(name, @attrs) end def on_stag_end_empty(name) tag_start(name, @attrs) tag_end(name) end private def entity(ref) ent = ENTITIES[ref] if ent ent else wellformed_error("undefined entity: #{ref}") end end end end PK|]LN{ { rss/utils.rbnu[module RSS module Utils module_function # Convert a name_with_underscores to CamelCase. def to_class_name(name) name.split(/[_\-]/).collect do |part| "#{part[0, 1].upcase}#{part[1..-1]}" end.join("") end def get_file_and_line_from_caller(i=0) file, line, = caller[i].split(':') line = line.to_i line += 1 if i.zero? [file, line] end # escape '&', '"', '<' and '>' for use in HTML. def html_escape(s) s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/ is missing in tag <#{parent}>") end end class TooMuchTagError < InvalidRSSError attr_reader :tag, :parent def initialize(tag, parent) @tag, @parent = tag, parent super("tag <#{tag}> is too much in tag <#{parent}>") end end class MissingAttributeError < InvalidRSSError attr_reader :tag, :attribute def initialize(tag, attribute) @tag, @attribute = tag, attribute super("attribute <#{attribute}> is missing in tag <#{tag}>") end end class UnknownTagError < InvalidRSSError attr_reader :tag, :uri def initialize(tag, uri) @tag, @uri = tag, uri super("tag <#{tag}> is unknown in namespace specified by uri <#{uri}>") end end class NotExpectedTagError < InvalidRSSError attr_reader :tag, :uri, :parent def initialize(tag, uri, parent) @tag, @uri, @parent = tag, uri, parent super("tag <{#{uri}}#{tag}> is not expected in tag <#{parent}>") end end # For backward compatibility :X NotExceptedTagError = NotExpectedTagError class NotAvailableValueError < InvalidRSSError attr_reader :tag, :value, :attribute def initialize(tag, value, attribute=nil) @tag, @value, @attribute = tag, value, attribute message = "value <#{value}> of " message << "attribute <#{attribute}> of " if attribute message << "tag <#{tag}> is not available." super(message) end end class UnknownConversionMethodError < Error attr_reader :to, :from def initialize(to, from) @to = to @from = from super("can't convert to #{to} from #{from}.") end end # for backward compatibility UnknownConvertMethod = UnknownConversionMethodError class ConversionError < Error attr_reader :string, :to, :from def initialize(string, to, from) @string = string @to = to @from = from super("can't convert #{@string} to #{to} from #{from}.") end end class NotSetError < Error attr_reader :name, :variables def initialize(name, variables) @name = name @variables = variables super("required variables of #{@name} are not set: #{@variables.join(', ')}") end end class UnsupportedMakerVersionError < Error attr_reader :version def initialize(version) @version = version super("Maker doesn't support version: #{@version}") end end module BaseModel include Utils def install_have_child_element(tag_name, uri, occurs, name=nil, type=nil) name ||= tag_name add_need_initialize_variable(name) install_model(tag_name, uri, occurs, name) writer_type, reader_type = type def_corresponded_attr_writer name, writer_type def_corresponded_attr_reader name, reader_type install_element(name) do |n, elem_name| <<-EOC if @#{n} "\#{@#{n}.to_s(need_convert, indent)}" else '' end EOC end end alias_method(:install_have_attribute_element, :install_have_child_element) def install_have_children_element(tag_name, uri, occurs, name=nil, plural_name=nil) name ||= tag_name plural_name ||= "#{name}s" add_have_children_element(name, plural_name) add_plural_form(name, plural_name) install_model(tag_name, uri, occurs, plural_name, true) def_children_accessor(name, plural_name) install_element(name, "s") do |n, elem_name| <<-EOC rv = [] @#{n}.each do |x| value = "\#{x.to_s(need_convert, indent)}" rv << value if /\\A\\s*\\z/ !~ value end rv.join("\n") EOC end end def install_text_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil) name ||= tag_name disp_name ||= name self::ELEMENTS << name unless self::ELEMENTS.include?(name) add_need_initialize_variable(name) install_model(tag_name, uri, occurs, name) def_corresponded_attr_writer(name, type, disp_name) def_corresponded_attr_reader(name, type || :convert) install_element(name) do |n, elem_name| <<-EOC if respond_to?(:#{n}_content) content = #{n}_content else content = @#{n} end if content rv = "\#{indent}<#{elem_name}>" value = html_escape(content) if need_convert rv << convert(value) else rv << value end rv << "" rv else '' end EOC end end def install_date_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil) name ||= tag_name type ||= :w3cdtf disp_name ||= name self::ELEMENTS << name add_need_initialize_variable(name) install_model(tag_name, uri, occurs, name) # accessor convert_attr_reader name date_writer(name, type, disp_name) install_element(name) do |n, elem_name| <<-EOC if @#{n} rv = "\#{indent}<#{elem_name}>" value = html_escape(@#{n}.#{type}) if need_convert rv << convert(value) else rv << value end rv << "" rv else '' end EOC end end private def install_element(name, postfix="") elem_name = name.sub('_', ':') method_name = "#{name}_element#{postfix}" add_to_element_method(method_name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{method_name}(need_convert=true, indent='') #{yield(name, elem_name)} end private :#{method_name} EOC end def inherit_convert_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{attr}_without_inherit convert(@#{attr}) end def #{attr} if @#{attr} #{attr}_without_inherit elsif @parent @parent.#{attr} else nil end end EOC end end def uri_convert_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{attr}_without_base convert(@#{attr}) end def #{attr} value = #{attr}_without_base return nil if value.nil? if /\\A[a-z][a-z0-9+.\\-]*:/i =~ value value else "\#{base}\#{value}" end end EOC end end def convert_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{attr} convert(@#{attr}) end EOC end end def yes_clean_other_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, __FILE__, __LINE__ + 1) attr_reader(:#{attr}) def #{attr}? YesCleanOther.parse(@#{attr}) end EOC end end def yes_other_attr_reader(*attrs) attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, __FILE__, __LINE__ + 1) attr_reader(:#{attr}) def #{attr}? Utils::YesOther.parse(@#{attr}) end EOC end end def csv_attr_reader(*attrs) separator = nil if attrs.last.is_a?(Hash) options = attrs.pop separator = options[:separator] end separator ||= ", " attrs.each do |attr| attr = attr.id2name if attr.kind_of?(Integer) module_eval(<<-EOC, __FILE__, __LINE__ + 1) attr_reader(:#{attr}) def #{attr}_content if @#{attr}.nil? @#{attr} else @#{attr}.join(#{separator.dump}) end end EOC end end def date_writer(name, type, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.nil? @#{name} = new_value elsif new_value.kind_of?(Time) @#{name} = new_value.dup else if @do_validate begin @#{name} = Time.__send__('#{type}', new_value) rescue ArgumentError raise NotAvailableValueError.new('#{disp_name}', new_value) end else @#{name} = nil if /\\A\\s*\\z/ !~ new_value.to_s begin unless Date._parse(new_value, false).empty? @#{name} = Time.parse(new_value) end rescue ArgumentError end end end end # Is it need? if @#{name} class << @#{name} undef_method(:to_s) alias_method(:to_s, :#{type}) end end end EOC end def integer_writer(name, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.nil? @#{name} = new_value else if @do_validate begin @#{name} = Integer(new_value) rescue ArgumentError raise NotAvailableValueError.new('#{disp_name}', new_value) end else @#{name} = new_value.to_i end end end EOC end def positive_integer_writer(name, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.nil? @#{name} = new_value else if @do_validate begin tmp = Integer(new_value) raise ArgumentError if tmp <= 0 @#{name} = tmp rescue ArgumentError raise NotAvailableValueError.new('#{disp_name}', new_value) end else @#{name} = new_value.to_i end end end EOC end def boolean_writer(name, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.nil? @#{name} = new_value else if @do_validate and ![true, false, "true", "false"].include?(new_value) raise NotAvailableValueError.new('#{disp_name}', new_value) end if [true, false].include?(new_value) @#{name} = new_value else @#{name} = new_value == "true" end end end EOC end def text_type_writer(name, disp_name=name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if @do_validate and !["text", "html", "xhtml", nil].include?(new_value) raise NotAvailableValueError.new('#{disp_name}', new_value) end @#{name} = new_value end EOC end def content_writer(name, disp_name=name) klass_name = "self.class::#{Utils.to_class_name(name)}" module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{name}=(new_value) if new_value.is_a?(#{klass_name}) @#{name} = new_value else @#{name} = #{klass_name}.new @#{name}.content = new_value end end EOC end def yes_clean_other_writer(name, disp_name=name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(value) value = (value ? "yes" : "no") if [true, false].include?(value) @#{name} = value end EOC end def yes_other_writer(name, disp_name=name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(new_value) if [true, false].include?(new_value) new_value = new_value ? "yes" : "no" end @#{name} = new_value end EOC end def csv_writer(name, disp_name=name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(new_value) @#{name} = Utils::CSV.parse(new_value) end EOC end def csv_integer_writer(name, disp_name=name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(new_value) @#{name} = Utils::CSV.parse(new_value) {|v| Integer(v)} end EOC end def def_children_accessor(accessor_name, plural_name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) def #{plural_name} @#{accessor_name} end def #{accessor_name}(*args) if args.empty? @#{accessor_name}.first else @#{accessor_name}[*args] end end def #{accessor_name}=(*args) receiver = self.class.name warn("Warning:\#{caller.first.sub(/:in `.*'\z/, '')}: " \ "Don't use `\#{receiver}\##{accessor_name} = XXX'/" \ "`\#{receiver}\#set_#{accessor_name}(XXX)'. " \ "Those APIs are not sense of Ruby. " \ "Use `\#{receiver}\##{plural_name} << XXX' instead of them.") if args.size == 1 @#{accessor_name}.push(args[0]) else @#{accessor_name}.__send__("[]=", *args) end end alias_method(:set_#{accessor_name}, :#{accessor_name}=) EOC end end module SetupMaker def setup_maker(maker) target = maker_target(maker) unless target.nil? setup_maker_attributes(target) setup_maker_element(target) setup_maker_elements(target) end end private def maker_target(maker) nil end def setup_maker_attributes(target) end def setup_maker_element(target) self.class.need_initialize_variables.each do |var| value = __send__(var) next if value.nil? if value.respond_to?("setup_maker") and !not_need_to_call_setup_maker_variables.include?(var) value.setup_maker(target) else setter = "#{var}=" if target.respond_to?(setter) target.__send__(setter, value) end end end end def not_need_to_call_setup_maker_variables [] end def setup_maker_elements(parent) self.class.have_children_elements.each do |name, plural_name| if parent.respond_to?(plural_name) target = parent.__send__(plural_name) __send__(plural_name).each do |elem| elem.setup_maker(target) end end end end end class Element extend BaseModel include Utils extend Utils::InheritedReader include SetupMaker INDENT = " " MUST_CALL_VALIDATORS = {} MODELS = [] GET_ATTRIBUTES = [] HAVE_CHILDREN_ELEMENTS = [] TO_ELEMENT_METHODS = [] NEED_INITIALIZE_VARIABLES = [] PLURAL_FORMS = {} class << self def must_call_validators inherited_hash_reader("MUST_CALL_VALIDATORS") end def models inherited_array_reader("MODELS") end def get_attributes inherited_array_reader("GET_ATTRIBUTES") end def have_children_elements inherited_array_reader("HAVE_CHILDREN_ELEMENTS") end def to_element_methods inherited_array_reader("TO_ELEMENT_METHODS") end def need_initialize_variables inherited_array_reader("NEED_INITIALIZE_VARIABLES") end def plural_forms inherited_hash_reader("PLURAL_FORMS") end def inherited_base ::RSS::Element end def inherited(klass) klass.const_set("MUST_CALL_VALIDATORS", {}) klass.const_set("MODELS", []) klass.const_set("GET_ATTRIBUTES", []) klass.const_set("HAVE_CHILDREN_ELEMENTS", []) klass.const_set("TO_ELEMENT_METHODS", []) klass.const_set("NEED_INITIALIZE_VARIABLES", []) klass.const_set("PLURAL_FORMS", {}) tag_name = klass.name.split(/::/).last tag_name[0, 1] = tag_name[0, 1].downcase klass.instance_variable_set("@tag_name", tag_name) klass.instance_variable_set("@have_content", false) end def install_must_call_validator(prefix, uri) self::MUST_CALL_VALIDATORS[uri] = prefix end def install_model(tag, uri, occurs=nil, getter=nil, plural=false) getter ||= tag if m = self::MODELS.find {|t, u, o, g, p| t == tag and u == uri} m[2] = occurs else self::MODELS << [tag, uri, occurs, getter, plural] end end def install_get_attribute(name, uri, required=true, type=nil, disp_name=nil, element_name=nil) disp_name ||= name element_name ||= name writer_type, reader_type = type def_corresponded_attr_writer name, writer_type, disp_name def_corresponded_attr_reader name, reader_type if type == :boolean and /^is/ =~ name alias_method "#{$POSTMATCH}?", name end self::GET_ATTRIBUTES << [name, uri, required, element_name] add_need_initialize_variable(disp_name) end def def_corresponded_attr_writer(name, type=nil, disp_name=nil) disp_name ||= name case type when :integer integer_writer name, disp_name when :positive_integer positive_integer_writer name, disp_name when :boolean boolean_writer name, disp_name when :w3cdtf, :rfc822, :rfc2822 date_writer name, type, disp_name when :text_type text_type_writer name, disp_name when :content content_writer name, disp_name when :yes_clean_other yes_clean_other_writer name, disp_name when :yes_other yes_other_writer name, disp_name when :csv csv_writer name when :csv_integer csv_integer_writer name else attr_writer name end end def def_corresponded_attr_reader(name, type=nil) case type when :inherit inherit_convert_attr_reader name when :uri uri_convert_attr_reader name when :yes_clean_other yes_clean_other_attr_reader name when :yes_other yes_other_attr_reader name when :csv csv_attr_reader name when :csv_integer csv_attr_reader name, :separator => "," else convert_attr_reader name end end def content_setup(type=nil, disp_name=nil) writer_type, reader_type = type def_corresponded_attr_writer :content, writer_type, disp_name def_corresponded_attr_reader :content, reader_type @have_content = true end def have_content? @have_content end def add_have_children_element(variable_name, plural_name) self::HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name] end def add_to_element_method(method_name) self::TO_ELEMENT_METHODS << method_name end def add_need_initialize_variable(variable_name) self::NEED_INITIALIZE_VARIABLES << variable_name end def add_plural_form(singular, plural) self::PLURAL_FORMS[singular] = plural end def required_prefix nil end def required_uri "" end def need_parent? false end def install_ns(prefix, uri) if self::NSPOOL.has_key?(prefix) raise OverlappedPrefixError.new(prefix) end self::NSPOOL[prefix] = uri end def tag_name @tag_name end end attr_accessor :parent, :do_validate def initialize(do_validate=true, attrs=nil) @parent = nil @converter = nil if attrs.nil? and (do_validate.is_a?(Hash) or do_validate.is_a?(Array)) do_validate, attrs = true, do_validate end @do_validate = do_validate initialize_variables(attrs || {}) end def tag_name self.class.tag_name end def full_name tag_name end def converter=(converter) @converter = converter targets = children.dup self.class.have_children_elements.each do |variable_name, plural_name| targets.concat(__send__(plural_name)) end targets.each do |target| target.converter = converter unless target.nil? end end def convert(value) if @converter @converter.convert(value) else value end end def valid?(ignore_unknown_element=true) validate(ignore_unknown_element) true rescue RSS::Error false end def validate(ignore_unknown_element=true) do_validate = @do_validate @do_validate = true validate_attribute __validate(ignore_unknown_element) ensure @do_validate = do_validate end def validate_for_stream(tags, ignore_unknown_element=true) validate_attribute __validate(ignore_unknown_element, tags, false) end def to_s(need_convert=true, indent='') if self.class.have_content? return "" if !empty_content? and !content_is_set? rv = tag(indent) do |next_indent| if empty_content? "" else xmled_content end end else rv = tag(indent) do |next_indent| self.class.to_element_methods.collect do |method_name| __send__(method_name, false, next_indent) end end end rv = convert(rv) if need_convert rv end def have_xml_content? false end def need_base64_encode? false end def set_next_element(tag_name, next_element) klass = next_element.class prefix = "" prefix << "#{klass.required_prefix}_" if klass.required_prefix key = "#{prefix}#{tag_name.gsub(/-/, '_')}" if self.class.plural_forms.has_key?(key) ary = __send__("#{self.class.plural_forms[key]}") ary << next_element else __send__("#{key}=", next_element) end end protected def have_required_elements? self.class::MODELS.all? do |tag, uri, occurs, getter| if occurs.nil? or occurs == "+" child = __send__(getter) if child.is_a?(Array) children = child children.any? {|c| c.have_required_elements?} else !child.to_s.empty? end else true end end end private def initialize_variables(attrs) normalized_attrs = {} attrs.each do |key, value| normalized_attrs[key.to_s] = value end self.class.need_initialize_variables.each do |variable_name| value = normalized_attrs[variable_name.to_s] if value __send__("#{variable_name}=", value) else instance_variable_set("@#{variable_name}", nil) end end initialize_have_children_elements @content = normalized_attrs["content"] if self.class.have_content? end def initialize_have_children_elements self.class.have_children_elements.each do |variable_name, plural_name| instance_variable_set("@#{variable_name}", []) end end def tag(indent, additional_attrs={}, &block) next_indent = indent + INDENT attrs = collect_attrs return "" if attrs.nil? return "" unless have_required_elements? attrs.update(additional_attrs) start_tag = make_start_tag(indent, next_indent, attrs.dup) if block content = block.call(next_indent) else content = [] end if content.is_a?(String) content = [content] start_tag << ">" end_tag = "" else content = content.reject{|x| x.empty?} if content.empty? return "" if attrs.empty? end_tag = "/>" else start_tag << ">\n" end_tag = "\n#{indent}" end end start_tag + content.join("\n") + end_tag end def make_start_tag(indent, next_indent, attrs) start_tag = ["#{indent}<#{full_name}"] unless attrs.empty? start_tag << attrs.collect do |key, value| %Q[#{h key}="#{h value}"] end.join("\n#{next_indent}") end start_tag.join(" ") end def collect_attrs attrs = {} _attrs.each do |name, required, alias_name| value = __send__(alias_name || name) return nil if required and value.nil? next if value.nil? return nil if attrs.has_key?(name) attrs[name] = value end attrs end def tag_name_with_prefix(prefix) "#{prefix}:#{tag_name}" end # For backward compatibility def calc_indent '' end def children rv = [] self.class.models.each do |name, uri, occurs, getter| value = __send__(getter) next if value.nil? value = [value] unless value.is_a?(Array) value.each do |v| rv << v if v.is_a?(Element) end end rv end def _tags rv = [] self.class.models.each do |name, uri, occurs, getter, plural| value = __send__(getter) next if value.nil? if plural and value.is_a?(Array) rv.concat([[uri, name]] * value.size) else rv << [uri, name] end end rv end def _attrs self.class.get_attributes.collect do |name, uri, required, element_name| [element_name, required, name] end end def __validate(ignore_unknown_element, tags=_tags, recursive=true) if recursive children.compact.each do |child| child.validate end end must_call_validators = self.class.must_call_validators tags = tag_filter(tags.dup) p tags if DEBUG must_call_validators.each do |uri, prefix| _validate(ignore_unknown_element, tags[uri], uri) meth = "#{prefix}_validate" if !prefix.empty? and respond_to?(meth, true) __send__(meth, ignore_unknown_element, tags[uri], uri) end end end def validate_attribute _attrs.each do |a_name, required, alias_name| value = instance_variable_get("@#{alias_name || a_name}") if required and value.nil? raise MissingAttributeError.new(tag_name, a_name) end __send__("#{alias_name || a_name}=", value) end end def _validate(ignore_unknown_element, tags, uri, models=self.class.models) count = 1 do_redo = false not_shift = false tag = nil models = models.find_all {|model| model[1] == uri} element_names = models.collect {|model| model[0]} if tags tags_size = tags.size tags = tags.sort_by {|x| element_names.index(x) || tags_size} end _tags = tags.dup if tags models.each_with_index do |model, i| name, model_uri, occurs, getter = model if DEBUG p "before" p tags p model end if not_shift not_shift = false elsif tags tag = tags.shift end if DEBUG p "mid" p count end case occurs when '?' if count > 2 raise TooMuchTagError.new(name, tag_name) else if name == tag do_redo = true else not_shift = true end end when '*' if name == tag do_redo = true else not_shift = true end when '+' if name == tag do_redo = true else if count > 1 not_shift = true else raise MissingTagError.new(name, tag_name) end end else if name == tag if models[i+1] and models[i+1][0] != name and tags and tags.first == name raise TooMuchTagError.new(name, tag_name) end else raise MissingTagError.new(name, tag_name) end end if DEBUG p "after" p not_shift p do_redo p tag end if do_redo do_redo = false count += 1 redo else count = 1 end end if !ignore_unknown_element and !tags.nil? and !tags.empty? raise NotExpectedTagError.new(tags.first, uri, tag_name) end end def tag_filter(tags) rv = {} tags.each do |tag| rv[tag[0]] = [] unless rv.has_key?(tag[0]) rv[tag[0]].push(tag[1]) end rv end def empty_content? false end def content_is_set? if have_xml_content? __send__(self.class.xml_getter) else content end end def xmled_content if have_xml_content? __send__(self.class.xml_getter).to_s else _content = content _content = Base64.encode64(_content) if need_base64_encode? h(_content) end end end module RootElementMixin include XMLStyleSheetMixin attr_reader :output_encoding attr_reader :feed_type, :feed_subtype, :feed_version attr_accessor :version, :encoding, :standalone def initialize(feed_version, version=nil, encoding=nil, standalone=nil) super() @feed_type = nil @feed_subtype = nil @feed_version = feed_version @version = version || '1.0' @encoding = encoding @standalone = standalone @output_encoding = nil end def feed_info [@feed_type, @feed_version, @feed_subtype] end def output_encoding=(enc) @output_encoding = enc self.converter = Converter.new(@output_encoding, @encoding) end def setup_maker(maker) maker.version = version maker.encoding = encoding maker.standalone = standalone xml_stylesheets.each do |xss| xss.setup_maker(maker) end super end def to_feed(type, &block) Maker.make(type) do |maker| setup_maker(maker) block.call(maker) if block end end def to_rss(type, &block) to_feed("rss#{type}", &block) end def to_atom(type, &block) to_feed("atom:#{type}", &block) end def to_xml(type=nil, &block) if type.nil? or same_feed_type?(type) to_s else to_feed(type, &block).to_s end end private def same_feed_type?(type) if /^(atom|rss)?(\d+\.\d+)?(?::(.+))?$/i =~ type feed_type = ($1 || @feed_type).downcase feed_version = $2 || @feed_version feed_subtype = $3 || @feed_subtype [feed_type, feed_version, feed_subtype] == feed_info else false end end def tag(indent, attrs={}, &block) rv = super(indent, ns_declarations.merge(attrs), &block) return rv if rv.empty? "#{xmldecl}#{xml_stylesheet_pi}#{rv}" end def xmldecl rv = %Q[\n" rv end def ns_declarations decls = {} self.class::NSPOOL.collect do |prefix, uri| prefix = ":#{prefix}" unless prefix.empty? decls["xmlns#{prefix}"] = uri end decls end def maker_target(target) target end end end PK|]J"u"u" rss/1.0.rbnu[require "rss/parser" module RSS module RSS10 NSPOOL = {} ELEMENTS = [] def self.append_features(klass) super klass.install_must_call_validator('', ::RSS::URI) end end class RDF < Element include RSS10 include RootElementMixin class << self def required_uri URI end end @tag_name = 'RDF' PREFIX = 'rdf' URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" install_ns('', ::RSS::URI) install_ns(PREFIX, URI) [ ["channel", nil], ["image", "?"], ["item", "+", :children], ["textinput", "?"], ].each do |tag, occurs, type| type ||= :child __send__("install_have_#{type}_element", tag, ::RSS::URI, occurs) end alias_method(:rss_version, :feed_version) def initialize(version=nil, encoding=nil, standalone=nil) super('1.0', version, encoding, standalone) @feed_type = "rss" end def full_name tag_name_with_prefix(PREFIX) end class Li < Element include RSS10 class << self def required_uri URI end end [ ["resource", [URI, ""], true] ].each do |name, uri, required| install_get_attribute(name, uri, required) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end def full_name tag_name_with_prefix(PREFIX) end end class Seq < Element include RSS10 Li = ::RSS::RDF::Li class << self def required_uri URI end end @tag_name = 'Seq' install_have_children_element("li", URI, "*") install_must_call_validator('rdf', ::RSS::RDF::URI) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() @li = args[0] if args[0] end end def full_name tag_name_with_prefix(PREFIX) end def setup_maker(target) lis.each do |li| target << li.resource end end end class Bag < Element include RSS10 Li = ::RSS::RDF::Li class << self def required_uri URI end end @tag_name = 'Bag' install_have_children_element("li", URI, "*") install_must_call_validator('rdf', URI) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() @li = args[0] if args[0] end end def full_name tag_name_with_prefix(PREFIX) end def setup_maker(target) lis.each do |li| target << li.resource end end end class Channel < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["about", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end [ ['title', nil, :text], ['link', nil, :text], ['description', nil, :text], ['image', '?', :have_child], ['items', nil, :have_child], ['textinput', '?', :have_child], ].each do |tag, occurs, type| __send__("install_#{type}_element", tag, ::RSS::URI, occurs) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end private def maker_target(maker) maker.channel end def setup_maker_attributes(channel) channel.about = about end class Image < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["resource", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end end class Textinput < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["resource", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end end class Items < Element include RSS10 Seq = ::RSS::RDF::Seq class << self def required_uri ::RSS::URI end end install_have_child_element("Seq", URI, nil) install_must_call_validator('rdf', URI) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.Seq = args[0] end self.Seq ||= Seq.new end def resources if @Seq @Seq.lis.collect do |li| li.resource end else [] end end end end class Image < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["about", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end %w(title url link).each do |name| install_text_element(name, ::RSS::URI, nil) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end private def maker_target(maker) maker.image end end class Item < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["about", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end [ ["title", nil], ["link", nil], ["description", "?"], ].each do |tag, occurs| install_text_element(tag, ::RSS::URI, occurs) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end private def maker_target(items) if items.respond_to?("items") # For backward compatibility items = items.items end items.new_item end end class Textinput < Element include RSS10 class << self def required_uri ::RSS::URI end end [ ["about", URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{PREFIX}:#{name}") end %w(title description name link).each do |name| install_text_element(name, ::RSS::URI, nil) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end private def maker_target(maker) maker.textinput end end end RSS10::ELEMENTS.each do |name| BaseListener.install_get_text_element(URI, name, name) end module ListenerMixin private def initial_start_RDF(tag_name, prefix, attrs, ns) check_ns(tag_name, prefix, ns, RDF::URI) @rss = RDF.new(@version, @encoding, @standalone) @rss.do_validate = @do_validate @rss.xml_stylesheets = @xml_stylesheets @last_element = @rss pr = Proc.new do |text, tags| @rss.validate_for_stream(tags, @ignore_unknown_element) if @do_validate end @proc_stack.push(pr) end end end PK|]DG`rss/maker/atom.rbnu[require "rss/atom" require "rss/maker/base" module RSS module Maker module AtomPersons module_function def def_atom_persons(klass, name, maker_name, plural=nil) plural ||= "#{name}s" klass_name = Utils.to_class_name(name) plural_klass_name = Utils.to_class_name(plural) klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1) class #{plural_klass_name} < #{plural_klass_name}Base class #{klass_name} < #{klass_name}Base def to_feed(feed, current) #{name} = feed.class::#{klass_name}.new set = setup_values(#{name}) unless set raise NotSetError.new(#{maker_name.dump}, not_set_required_variables) end current.#{plural} << #{name} set_parent(#{name}, current) setup_other_elements(#{name}) end private def required_variable_names %w(name) end end end EOC end end module AtomTextConstruct class << self def def_atom_text_construct(klass, name, maker_name, klass_name=nil, atom_klass_name=nil) klass_name ||= Utils.to_class_name(name) atom_klass_name ||= Utils.to_class_name(name) klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1) class #{klass_name} < #{klass_name}Base include #{self.name} def to_feed(feed, current) #{name} = current.class::#{atom_klass_name}.new if setup_values(#{name}) current.#{name} = #{name} set_parent(#{name}, current) setup_other_elements(feed) elsif variable_is_set? raise NotSetError.new(#{maker_name.dump}, not_set_required_variables) end end end EOC end end private def required_variable_names if type == "xhtml" %w(xml_content) else %w(content) end end def variables if type == "xhtml" super + %w(xhtml) else super end end end module AtomCategory def to_feed(feed, current) category = feed.class::Category.new set = setup_values(category) if set current.categories << category set_parent(category, current) setup_other_elements(feed) else raise NotSetError.new(self.class.not_set_name, not_set_required_variables) end end private def required_variable_names %w(term) end def variables super + ["term", "scheme"] end end module AtomLink def to_feed(feed, current) link = feed.class::Link.new set = setup_values(link) if set current.links << link set_parent(link, current) setup_other_elements(feed) else raise NotSetError.new(self.class.not_set_name, not_set_required_variables) end end private def required_variable_names %w(href) end end module AtomGenerator def to_feed(feed, current) generator = current.class::Generator.new if setup_values(generator) current.generator = generator set_parent(generator, current) setup_other_elements(feed) elsif variable_is_set? raise NotSetError.new(self.class.not_set_name, not_set_required_variables) end end private def required_variable_names %w(content) end end module AtomLogo def to_feed(feed, current) logo = current.class::Logo.new class << logo alias_method(:uri=, :content=) end set = setup_values(logo) class << logo remove_method(:uri=) end if set current.logo = logo set_parent(logo, current) setup_other_elements(feed) elsif variable_is_set? raise NotSetError.new(self.class.not_set_name, not_set_required_variables) end end private def required_variable_names %w(uri) end end end end PK|]-crss/maker/dublincore.rbnu[require 'rss/dublincore' require 'rss/maker/1.0' module RSS module Maker module DublinCoreModel def self.append_features(klass) super ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| plural_name ||= "#{name}s" full_name = "#{RSS::DC_PREFIX}_#{name}" full_plural_name = "#{RSS::DC_PREFIX}_#{plural_name}" klass_name = Utils.to_class_name(name) plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}" full_plural_klass_name = "self.class::#{plural_klass_name}" full_klass_name = "#{full_plural_klass_name}::#{klass_name}" klass.def_classed_elements(full_name, "value", plural_klass_name, full_plural_name, name) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) def new_#{full_name}(value=nil) _#{full_name} = #{full_plural_name}.new_#{name} _#{full_name}.value = value if block_given? yield _#{full_name} else _#{full_name} end end EOC end klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) # For backward compatibility alias #{DC_PREFIX}_rightses #{DC_PREFIX}_rights_list EOC end ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| plural_name ||= "#{name}s" full_name ||= "#{DC_PREFIX}_#{name}" full_plural_name ||= "#{DC_PREFIX}_#{plural_name}" klass_name = Utils.to_class_name(name) full_klass_name = "DublinCore#{klass_name}" plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}" module_eval(<<-EOC, __FILE__, __LINE__ + 1) class #{plural_klass_name}Base < Base def_array_element(#{name.dump}, #{full_plural_name.dump}, #{full_klass_name.dump}) class #{full_klass_name}Base < Base attr_accessor :value add_need_initialize_variable("value") alias_method(:content, :value) alias_method(:content=, :value=) def have_required_values? @value end def to_feed(feed, current) if value and current.respond_to?(:#{full_name}) new_item = current.class::#{full_klass_name}.new(value) current.#{full_plural_name} << new_item end end end #{klass_name}Base = #{full_klass_name}Base end EOC end def self.install_dublin_core(klass) ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| plural_name ||= "#{name}s" klass_name = Utils.to_class_name(name) full_klass_name = "DublinCore#{klass_name}" plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}" klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class #{plural_klass_name} < #{plural_klass_name}Base class #{full_klass_name} < #{full_klass_name}Base end #{klass_name} = #{full_klass_name} end EOC end end end class ChannelBase include DublinCoreModel end class ImageBase; include DublinCoreModel; end class ItemsBase class ItemBase include DublinCoreModel end end class TextinputBase; include DublinCoreModel; end makers.each do |maker| maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class Channel DublinCoreModel.install_dublin_core(self) end class Image DublinCoreModel.install_dublin_core(self) end class Items class Item DublinCoreModel.install_dublin_core(self) end end class Textinput DublinCoreModel.install_dublin_core(self) end EOC end end end PK|]ërss/maker/content.rbnu[require 'rss/content' require 'rss/maker/1.0' require 'rss/maker/2.0' module RSS module Maker module ContentModel def self.append_features(klass) super ::RSS::ContentModel::ELEMENTS.each do |name| klass.def_other_element(name) end end end class ItemsBase class ItemBase; include ContentModel; end end end end PK|])j,,rss/maker/0.9.rbnu[require "rss/0.9" require "rss/maker/base" module RSS module Maker class RSS09 < RSSBase def initialize(feed_version="0.92") super @feed_type = "rss" end private def make_feed Rss.new(@feed_version, @version, @encoding, @standalone) end def setup_elements(rss) setup_channel(rss) end class Channel < ChannelBase def to_feed(rss) channel = Rss::Channel.new set = setup_values(channel) _not_set_required_variables = not_set_required_variables if _not_set_required_variables.empty? rss.channel = channel set_parent(channel, rss) setup_items(rss) setup_image(rss) setup_textinput(rss) setup_other_elements(rss, channel) rss else raise NotSetError.new("maker.channel", _not_set_required_variables) end end private def setup_items(rss) @maker.items.to_feed(rss) end def setup_image(rss) @maker.image.to_feed(rss) end def setup_textinput(rss) @maker.textinput.to_feed(rss) end def variables super + ["pubDate"] end def required_variable_names %w(link language) end def not_set_required_variables vars = super vars << "description" unless description {|d| d.have_required_values?} vars << "title" unless title {|t| t.have_required_values?} vars end class SkipDays < SkipDaysBase def to_feed(rss, channel) unless @days.empty? skipDays = Rss::Channel::SkipDays.new channel.skipDays = skipDays set_parent(skipDays, channel) @days.each do |day| day.to_feed(rss, skipDays.days) end end end class Day < DayBase def to_feed(rss, days) day = Rss::Channel::SkipDays::Day.new set = setup_values(day) if set days << day set_parent(day, days) setup_other_elements(rss, day) end end private def required_variable_names %w(content) end end end class SkipHours < SkipHoursBase def to_feed(rss, channel) unless @hours.empty? skipHours = Rss::Channel::SkipHours.new channel.skipHours = skipHours set_parent(skipHours, channel) @hours.each do |hour| hour.to_feed(rss, skipHours.hours) end end end class Hour < HourBase def to_feed(rss, hours) hour = Rss::Channel::SkipHours::Hour.new set = setup_values(hour) if set hours << hour set_parent(hour, hours) setup_other_elements(rss, hour) end end private def required_variable_names %w(content) end end end class Cloud < CloudBase def to_feed(*args) end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Links < LinksBase def to_feed(rss, channel) return if @links.empty? @links.first.to_feed(rss, channel) end class Link < LinkBase def to_feed(rss, channel) if have_required_values? channel.link = href else raise NotSetError.new("maker.channel.link", not_set_required_variables) end end private def required_variable_names %w(href) end end end class Authors < AuthorsBase def to_feed(rss, channel) end class Author < AuthorBase def to_feed(rss, channel) end end end class Contributors < ContributorsBase def to_feed(rss, channel) end class Contributor < ContributorBase end end class Generator < GeneratorBase def to_feed(rss, channel) end end class Copyright < CopyrightBase def to_feed(rss, channel) channel.copyright = content if have_required_values? end private def required_variable_names %w(content) end end class Description < DescriptionBase def to_feed(rss, channel) channel.description = content if have_required_values? end private def required_variable_names %w(content) end end class Title < TitleBase def to_feed(rss, channel) channel.title = content if have_required_values? end private def required_variable_names %w(content) end end end class Image < ImageBase def to_feed(rss) image = Rss::Channel::Image.new set = setup_values(image) if set image.link = link rss.channel.image = image set_parent(image, rss.channel) setup_other_elements(rss, image) elsif required_element? raise NotSetError.new("maker.image", not_set_required_variables) end end private def required_variable_names %w(url title link) end def required_element? true end end class Items < ItemsBase def to_feed(rss) if rss.channel normalize.each do |item| item.to_feed(rss) end setup_other_elements(rss, rss.items) end end class Item < ItemBase def to_feed(rss) item = Rss::Channel::Item.new set = setup_values(item) _not_set_required_variables = not_set_required_variables if _not_set_required_variables.empty? rss.items << item set_parent(item, rss.channel) setup_other_elements(rss, item) elsif variable_is_set? raise NotSetError.new("maker.items", _not_set_required_variables) end end private def required_variable_names [] end def not_set_required_variables vars = super if @maker.feed_version == "0.91" vars << "title" unless title {|t| t.have_required_values?} vars << "link" unless link {|l| l.have_required_values?} end vars end class Guid < GuidBase def to_feed(*args) end end class Enclosure < EnclosureBase def to_feed(*args) end end class Source < SourceBase def to_feed(*args) end class Authors < AuthorsBase def to_feed(*args) end class Author < AuthorBase end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Contributors < ContributorsBase def to_feed(*args) end class Contributor < ContributorBase end end class Generator < GeneratorBase def to_feed(*args) end end class Icon < IconBase def to_feed(*args) end end class Links < LinksBase def to_feed(*args) end class Link < LinkBase end end class Logo < LogoBase def to_feed(*args) end end class Rights < RightsBase def to_feed(*args) end end class Subtitle < SubtitleBase def to_feed(*args) end end class Title < TitleBase def to_feed(*args) end end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Authors < AuthorsBase def to_feed(*args) end class Author < AuthorBase end end class Links < LinksBase def to_feed(rss, item) return if @links.empty? @links.first.to_feed(rss, item) end class Link < LinkBase def to_feed(rss, item) if have_required_values? item.link = href else raise NotSetError.new("maker.link", not_set_required_variables) end end private def required_variable_names %w(href) end end end class Contributors < ContributorsBase def to_feed(rss, item) end class Contributor < ContributorBase end end class Rights < RightsBase def to_feed(rss, item) end end class Description < DescriptionBase def to_feed(rss, item) item.description = content if have_required_values? end private def required_variable_names %w(content) end end class Content < ContentBase def to_feed(rss, item) end end class Title < TitleBase def to_feed(rss, item) item.title = content if have_required_values? end private def required_variable_names %w(content) end end end end class Textinput < TextinputBase def to_feed(rss) textInput = Rss::Channel::TextInput.new set = setup_values(textInput) if set rss.channel.textInput = textInput set_parent(textInput, rss.channel) setup_other_elements(rss, textInput) end end private def required_variable_names %w(title description name link) end end end add_maker("0.9", "0.92", RSS09) add_maker("0.91", "0.91", RSS09) add_maker("0.92", "0.92", RSS09) add_maker("rss0.91", "0.91", RSS09) add_maker("rss0.92", "0.92", RSS09) end end PK|]rss/maker/slash.rbnu[require 'rss/slash' require 'rss/maker/1.0' module RSS module Maker module SlashModel def self.append_features(klass) super ::RSS::SlashModel::ELEMENT_INFOS.each do |name, type| full_name = "#{RSS::SLASH_PREFIX}_#{name}" case type when :csv_integer klass.def_csv_element(full_name, :integer) else klass.def_other_element(full_name) end end klass.module_eval do alias_method(:slash_hit_parades, :slash_hit_parade) alias_method(:slash_hit_parades=, :slash_hit_parade=) end end end class ItemsBase class ItemBase include SlashModel end end end end PK|]Fv((rss/maker/1.0.rbnu[require "rss/1.0" require "rss/maker/base" module RSS module Maker class RSS10 < RSSBase def initialize(feed_version="1.0") super @feed_type = "rss" end private def make_feed RDF.new(@version, @encoding, @standalone) end def setup_elements(rss) setup_channel(rss) setup_image(rss) setup_items(rss) setup_textinput(rss) end class Channel < ChannelBase def to_feed(rss) set_default_values do _not_set_required_variables = not_set_required_variables if _not_set_required_variables.empty? channel = RDF::Channel.new(@about) set = setup_values(channel) channel.dc_dates.clear rss.channel = channel set_parent(channel, rss) setup_items(rss) setup_image(rss) setup_textinput(rss) setup_other_elements(rss, channel) else raise NotSetError.new("maker.channel", _not_set_required_variables) end end end private def setup_items(rss) items = RDF::Channel::Items.new seq = items.Seq set_parent(items, seq) target_items = @maker.items.normalize raise NotSetError.new("maker", ["items"]) if target_items.empty? target_items.each do |item| li = RDF::Channel::Items::Seq::Li.new(item.link) seq.lis << li set_parent(li, seq) end rss.channel.items = items set_parent(rss.channel, items) end def setup_image(rss) if @maker.image.have_required_values? image = RDF::Channel::Image.new(@maker.image.url) rss.channel.image = image set_parent(image, rss.channel) end end def setup_textinput(rss) if @maker.textinput.have_required_values? textinput = RDF::Channel::Textinput.new(@maker.textinput.link) rss.channel.textinput = textinput set_parent(textinput, rss.channel) end end def required_variable_names %w(about link) end def not_set_required_variables vars = super vars << "description" unless description {|d| d.have_required_values?} vars << "title" unless title {|t| t.have_required_values?} vars end class SkipDays < SkipDaysBase def to_feed(*args) end class Day < DayBase end end class SkipHours < SkipHoursBase def to_feed(*args) end class Hour < HourBase end end class Cloud < CloudBase def to_feed(*args) end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Links < LinksBase def to_feed(rss, channel) return if @links.empty? @links.first.to_feed(rss, channel) end class Link < LinkBase def to_feed(rss, channel) if have_required_values? channel.link = href else raise NotSetError.new("maker.channel.link", not_set_required_variables) end end private def required_variable_names %w(href) end end end class Authors < AuthorsBase def to_feed(rss, channel) end class Author < AuthorBase def to_feed(rss, channel) end end end class Contributors < ContributorsBase def to_feed(rss, channel) end class Contributor < ContributorBase end end class Generator < GeneratorBase def to_feed(rss, channel) end end class Copyright < CopyrightBase def to_feed(rss, channel) end end class Description < DescriptionBase def to_feed(rss, channel) channel.description = content if have_required_values? end private def required_variable_names %w(content) end end class Title < TitleBase def to_feed(rss, channel) channel.title = content if have_required_values? end private def required_variable_names %w(content) end end end class Image < ImageBase def to_feed(rss) if @url image = RDF::Image.new(@url) set = setup_values(image) if set rss.image = image set_parent(image, rss) setup_other_elements(rss, image) end end end def have_required_values? super and @maker.channel.have_required_values? end private def variables super + ["link"] end def required_variable_names %w(url title link) end end class Items < ItemsBase def to_feed(rss) if rss.channel normalize.each do |item| item.to_feed(rss) end setup_other_elements(rss, rss.items) end end class Item < ItemBase def to_feed(rss) set_default_values do item = RDF::Item.new(link) set = setup_values(item) if set item.dc_dates.clear rss.items << item set_parent(item, rss) setup_other_elements(rss, item) elsif !have_required_values? raise NotSetError.new("maker.item", not_set_required_variables) end end end private def required_variable_names %w(link) end def variables super + %w(link) end def not_set_required_variables set_default_values do vars = super vars << "title" unless title {|t| t.have_required_values?} vars end end class Guid < GuidBase def to_feed(*args) end end class Enclosure < EnclosureBase def to_feed(*args) end end class Source < SourceBase def to_feed(*args) end class Authors < AuthorsBase def to_feed(*args) end class Author < AuthorBase end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Contributors < ContributorsBase def to_feed(*args) end class Contributor < ContributorBase end end class Generator < GeneratorBase def to_feed(*args) end end class Icon < IconBase def to_feed(*args) end end class Links < LinksBase def to_feed(*args) end class Link < LinkBase end end class Logo < LogoBase def to_feed(*args) end end class Rights < RightsBase def to_feed(*args) end end class Subtitle < SubtitleBase def to_feed(*args) end end class Title < TitleBase def to_feed(*args) end end end class Categories < CategoriesBase def to_feed(*args) end class Category < CategoryBase end end class Authors < AuthorsBase def to_feed(*args) end class Author < AuthorBase end end class Links < LinksBase def to_feed(*args) end class Link < LinkBase end end class Contributors < ContributorsBase def to_feed(rss, item) end class Contributor < ContributorBase end end class Rights < RightsBase def to_feed(rss, item) end end class Description < DescriptionBase def to_feed(rss, item) item.description = content if have_required_values? end private def required_variable_names %w(content) end end class Content < ContentBase def to_feed(rss, item) end end class Title < TitleBase def to_feed(rss, item) item.title = content if have_required_values? end private def required_variable_names %w(content) end end end end class Textinput < TextinputBase def to_feed(rss) if @link textinput = RDF::Textinput.new(@link) set = setup_values(textinput) if set rss.textinput = textinput set_parent(textinput, rss) setup_other_elements(rss, textinput) end end end def have_required_values? super and @maker.channel.have_required_values? end private def required_variable_names %w(title description name link) end end end add_maker("1.0", "1.0", RSS10) add_maker("rss1.0", "1.0", RSS10) end end PK|]ц22rss/maker/feed.rbnu[require "rss/maker/atom" module RSS module Maker module Atom class Feed < RSSBase def initialize(feed_version="1.0") super @feed_type = "atom" @feed_subtype = "feed" end private def make_feed ::RSS::Atom::Feed.new(@version, @encoding, @standalone) end def setup_elements(feed) setup_channel(feed) setup_image(feed) setup_items(feed) end class Channel < ChannelBase def to_feed(feed) set_default_values do setup_values(feed) feed.dc_dates.clear setup_other_elements(feed) if image_favicon.about icon = feed.class::Icon.new icon.content = image_favicon.about feed.icon = icon end unless have_required_values? raise NotSetError.new("maker.channel", not_set_required_variables) end end end def have_required_values? super and (!authors.empty? or @maker.items.any? {|item| !item.authors.empty?}) end private def required_variable_names %w(id updated) end def variables super + %w(id updated) end def variable_is_set? super or !authors.empty? end def not_set_required_variables vars = super if authors.empty? and @maker.items.all? {|item| item.author.to_s.empty?} vars << "author" end vars << "title" unless title {|t| t.have_required_values?} vars end def _set_default_values(&block) keep = { :id => id, :updated => updated, } self.id ||= about self.updated ||= dc_date super(&block) ensure self.id = keep[:id] self.updated = keep[:updated] end class SkipDays < SkipDaysBase def to_feed(*args) end class Day < DayBase end end class SkipHours < SkipHoursBase def to_feed(*args) end class Hour < HourBase end end class Cloud < CloudBase def to_feed(*args) end end class Categories < CategoriesBase class Category < CategoryBase include AtomCategory def self.not_set_name "maker.channel.category" end end end class Links < LinksBase class Link < LinkBase include AtomLink def self.not_set_name "maker.channel.link" end end end AtomPersons.def_atom_persons(self, "author", "maker.channel.author") AtomPersons.def_atom_persons(self, "contributor", "maker.channel.contributor") class Generator < GeneratorBase include AtomGenerator def self.not_set_name "maker.channel.generator" end end AtomTextConstruct.def_atom_text_construct(self, "rights", "maker.channel.copyright", "Copyright") AtomTextConstruct.def_atom_text_construct(self, "subtitle", "maker.channel.description", "Description") AtomTextConstruct.def_atom_text_construct(self, "title", "maker.channel.title") end class Image < ImageBase def to_feed(feed) logo = feed.class::Logo.new class << logo alias_method(:url=, :content=) end set = setup_values(logo) class << logo remove_method(:url=) end if set feed.logo = logo set_parent(logo, feed) setup_other_elements(feed, logo) elsif variable_is_set? raise NotSetError.new("maker.image", not_set_required_variables) end end private def required_variable_names %w(url) end end class Items < ItemsBase def to_feed(feed) normalize.each do |item| item.to_feed(feed) end setup_other_elements(feed, feed.entries) end class Item < ItemBase def to_feed(feed) set_default_values do entry = feed.class::Entry.new set = setup_values(entry) setup_other_elements(feed, entry) if set feed.entries << entry set_parent(entry, feed) elsif variable_is_set? raise NotSetError.new("maker.item", not_set_required_variables) end end end def have_required_values? set_default_values do super and title {|t| t.have_required_values?} end end private def required_variable_names %w(id updated) end def variables super + ["updated"] end def not_set_required_variables vars = super vars << "title" unless title {|t| t.have_required_values?} vars end def _set_default_values(&block) keep = { :id => id, :updated => updated, } self.id ||= link self.updated ||= dc_date super(&block) ensure self.id = keep[:id] self.updated = keep[:updated] end class Guid < GuidBase def to_feed(feed, current) end end class Enclosure < EnclosureBase def to_feed(feed, current) end end class Source < SourceBase def to_feed(feed, current) source = current.class::Source.new setup_values(source) current.source = source set_parent(source, current) setup_other_elements(feed, source) current.source = nil if source.to_s == "" end private def required_variable_names [] end def variables super + ["updated"] end AtomPersons.def_atom_persons(self, "author", "maker.item.source.author") AtomPersons.def_atom_persons(self, "contributor", "maker.item.source.contributor") class Categories < CategoriesBase class Category < CategoryBase include AtomCategory def self.not_set_name "maker.item.source.category" end end end class Generator < GeneratorBase include AtomGenerator def self.not_set_name "maker.item.source.generator" end end class Icon < IconBase def to_feed(feed, current) icon = current.class::Icon.new class << icon alias_method(:url=, :content=) end set = setup_values(icon) class << icon remove_method(:url=) end if set current.icon = icon set_parent(icon, current) setup_other_elements(feed, icon) elsif variable_is_set? raise NotSetError.new("maker.item.source.icon", not_set_required_variables) end end private def required_variable_names %w(url) end end class Links < LinksBase class Link < LinkBase include AtomLink def self.not_set_name "maker.item.source.link" end end end class Logo < LogoBase include AtomLogo def self.not_set_name "maker.item.source.logo" end end maker_name_base = "maker.item.source." maker_name = "#{maker_name_base}rights" AtomTextConstruct.def_atom_text_construct(self, "rights", maker_name) maker_name = "#{maker_name_base}subtitle" AtomTextConstruct.def_atom_text_construct(self, "subtitle", maker_name) maker_name = "#{maker_name_base}title" AtomTextConstruct.def_atom_text_construct(self, "title", maker_name) end class Categories < CategoriesBase class Category < CategoryBase include AtomCategory def self.not_set_name "maker.item.category" end end end AtomPersons.def_atom_persons(self, "author", "maker.item.author") AtomPersons.def_atom_persons(self, "contributor", "maker.item.contributor") class Links < LinksBase class Link < LinkBase include AtomLink def self.not_set_name "maker.item.link" end end end AtomTextConstruct.def_atom_text_construct(self, "rights", "maker.item.rights") AtomTextConstruct.def_atom_text_construct(self, "summary", "maker.item.description", "Description") AtomTextConstruct.def_atom_text_construct(self, "title", "maker.item.title") class Content < ContentBase def to_feed(feed, current) content = current.class::Content.new if setup_values(content) content.src = nil if content.src and content.content current.content = content set_parent(content, current) setup_other_elements(feed, content) elsif variable_is_set? raise NotSetError.new("maker.item.content", not_set_required_variables) end end alias_method(:xml, :xml_content) private def required_variable_names if out_of_line? %w(type) elsif xml_type? %w(xml_content) else %w(content) end end def variables if out_of_line? super elsif xml_type? super + %w(xml) else super end end def xml_type? _type = type return false if _type.nil? _type == "xhtml" or /(?:\+xml|\/xml)$/i =~ _type or %w(text/xml-external-parsed-entity application/xml-external-parsed-entity application/xml-dtd).include?(_type.downcase) end end end end class Textinput < TextinputBase end end end add_maker("atom", "1.0", Atom::Feed) add_maker("atom:feed", "1.0", Atom::Feed) add_maker("atom1.0", "1.0", Atom::Feed) add_maker("atom1.0:feed", "1.0", Atom::Feed) end end PK|]ئf f rss/maker/image.rbnu[require 'rss/image' require 'rss/maker/1.0' require 'rss/maker/dublincore' module RSS module Maker module ImageItemModel def self.append_features(klass) super name = "#{RSS::IMAGE_PREFIX}_item" klass.def_classed_element(name) end def self.install_image_item(klass) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class ImageItem < ImageItemBase DublinCoreModel.install_dublin_core(self) end EOC end class ImageItemBase < Base include Maker::DublinCoreModel attr_accessor :about, :resource, :image_width, :image_height add_need_initialize_variable("about") add_need_initialize_variable("resource") add_need_initialize_variable("image_width") add_need_initialize_variable("image_height") alias width= image_width= alias width image_width alias height= image_height= alias height image_height def have_required_values? @about end def to_feed(feed, current) if current.respond_to?(:image_item=) and have_required_values? item = current.class::ImageItem.new setup_values(item) setup_other_elements(item) current.image_item = item end end end end module ImageFaviconModel def self.append_features(klass) super name = "#{RSS::IMAGE_PREFIX}_favicon" klass.def_classed_element(name) end def self.install_image_favicon(klass) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class ImageFavicon < ImageFaviconBase DublinCoreModel.install_dublin_core(self) end EOC end class ImageFaviconBase < Base include Maker::DublinCoreModel attr_accessor :about, :image_size add_need_initialize_variable("about") add_need_initialize_variable("image_size") alias size image_size alias size= image_size= def have_required_values? @about and @image_size end def to_feed(feed, current) if current.respond_to?(:image_favicon=) and have_required_values? favicon = current.class::ImageFavicon.new setup_values(favicon) setup_other_elements(favicon) current.image_favicon = favicon end end end end class ChannelBase; include Maker::ImageFaviconModel; end class ItemsBase class ItemBase; include Maker::ImageItemModel; end end makers.each do |maker| maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class Channel ImageFaviconModel.install_image_favicon(self) end class Items class Item ImageItemModel.install_image_item(self) end end EOC end end end PK|]g  rss/maker/itunes.rbnu[require 'rss/itunes' require 'rss/maker/2.0' module RSS module Maker module ITunesBaseModel def def_class_accessor(klass, name, type, *args) name = name.gsub(/-/, "_").gsub(/^itunes_/, '') full_name = "#{RSS::ITUNES_PREFIX}_#{name}" case type when nil klass.def_other_element(full_name) when :yes_other def_yes_other_accessor(klass, full_name) when :yes_clean_other def_yes_clean_other_accessor(klass, full_name) when :csv def_csv_accessor(klass, full_name) when :element, :attribute recommended_attribute_name, = *args klass_name = "ITunes#{Utils.to_class_name(name)}" klass.def_classed_element(full_name, klass_name, recommended_attribute_name) when :elements plural_name, recommended_attribute_name = args plural_name ||= "#{name}s" full_plural_name = "#{RSS::ITUNES_PREFIX}_#{plural_name}" klass_name = "ITunes#{Utils.to_class_name(name)}" plural_klass_name = "ITunes#{Utils.to_class_name(plural_name)}" def_elements_class_accessor(klass, name, full_name, full_plural_name, klass_name, plural_klass_name, recommended_attribute_name) end end def def_yes_other_accessor(klass, full_name) klass.def_other_element(full_name) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{full_name}? Utils::YesOther.parse(@#{full_name}) end EOC end def def_yes_clean_other_accessor(klass, full_name) klass.def_other_element(full_name) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{full_name}? Utils::YesCleanOther.parse(#{full_name}) end EOC end def def_csv_accessor(klass, full_name) klass.def_csv_element(full_name) end def def_elements_class_accessor(klass, name, full_name, full_plural_name, klass_name, plural_klass_name, recommended_attribute_name=nil) if recommended_attribute_name klass.def_classed_elements(full_name, recommended_attribute_name, plural_klass_name, full_plural_name) else klass.def_classed_element(full_plural_name, plural_klass_name) end klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) def new_#{full_name}(text=nil) #{full_name} = @#{full_plural_name}.new_#{name} #{full_name}.text = text if block_given? yield #{full_name} else #{full_name} end end EOC end end module ITunesChannelModel extend ITunesBaseModel class << self def append_features(klass) super ::RSS::ITunesChannelModel::ELEMENT_INFOS.each do |name, type, *args| def_class_accessor(klass, name, type, *args) end end end class ITunesCategoriesBase < Base def_array_element("category", "itunes_categories", "ITunesCategory") class ITunesCategoryBase < Base attr_accessor :text add_need_initialize_variable("text") def_array_element("category", "itunes_categories", "ITunesCategory") def have_required_values? text end alias_method :to_feed_for_categories, :to_feed def to_feed(feed, current) if text and current.respond_to?(:itunes_category) new_item = current.class::ITunesCategory.new(text) to_feed_for_categories(feed, new_item) current.itunes_categories << new_item end end end end class ITunesImageBase < Base add_need_initialize_variable("href") attr_accessor("href") def to_feed(feed, current) if @href and current.respond_to?(:itunes_image) current.itunes_image ||= current.class::ITunesImage.new current.itunes_image.href = @href end end end class ITunesOwnerBase < Base %w(itunes_name itunes_email).each do |name| add_need_initialize_variable(name) attr_accessor(name) end def to_feed(feed, current) if current.respond_to?(:itunes_owner=) _not_set_required_variables = not_set_required_variables if (required_variable_names - _not_set_required_variables).empty? return end unless have_required_values? raise NotSetError.new("maker.channel.itunes_owner", _not_set_required_variables) end current.itunes_owner ||= current.class::ITunesOwner.new current.itunes_owner.itunes_name = @itunes_name current.itunes_owner.itunes_email = @itunes_email end end private def required_variable_names %w(itunes_name itunes_email) end end end module ITunesItemModel extend ITunesBaseModel class << self def append_features(klass) super ::RSS::ITunesItemModel::ELEMENT_INFOS.each do |name, type, *args| def_class_accessor(klass, name, type, *args) end end end class ITunesDurationBase < Base attr_reader :content add_need_initialize_variable("content") %w(hour minute second).each do |name| attr_reader(name) add_need_initialize_variable(name, '0') end def content=(content) if content.nil? @hour, @minute, @second, @content = nil else @hour, @minute, @second = ::RSS::ITunesItemModel::ITunesDuration.parse(content) @content = content end end def hour=(hour) @hour = Integer(hour) update_content end def minute=(minute) @minute = Integer(minute) update_content end def second=(second) @second = Integer(second) update_content end def to_feed(feed, current) if @content and current.respond_to?(:itunes_duration=) current.itunes_duration ||= current.class::ITunesDuration.new current.itunes_duration.content = @content end end private def update_content components = [@hour, @minute, @second] @content = ::RSS::ITunesItemModel::ITunesDuration.construct(*components) end end end class ChannelBase include Maker::ITunesChannelModel class ITunesCategories < ITunesCategoriesBase class ITunesCategory < ITunesCategoryBase ITunesCategory = self end end class ITunesImage < ITunesImageBase; end class ITunesOwner < ITunesOwnerBase; end end class ItemsBase class ItemBase include Maker::ITunesItemModel class ITunesDuration < ITunesDurationBase; end end end end end PK|]tPPrss/maker/trackback.rbnu[require 'rss/trackback' require 'rss/maker/1.0' require 'rss/maker/2.0' module RSS module Maker module TrackBackModel def self.append_features(klass) super klass.def_other_element("#{RSS::TRACKBACK_PREFIX}_ping") klass.def_classed_elements("#{RSS::TRACKBACK_PREFIX}_about", "value", "TrackBackAbouts") end class TrackBackAboutsBase < Base def_array_element("about", nil, "TrackBackAbout") class TrackBackAboutBase < Base attr_accessor :value add_need_initialize_variable("value") alias_method(:resource, :value) alias_method(:resource=, :value=) alias_method(:content, :value) alias_method(:content=, :value=) def have_required_values? @value end def to_feed(feed, current) if current.respond_to?(:trackback_abouts) and have_required_values? about = current.class::TrackBackAbout.new setup_values(about) setup_other_elements(about) current.trackback_abouts << about end end end end end class ItemsBase class ItemBase; include TrackBackModel; end end makers.each do |maker| maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class Items class Item class TrackBackAbouts < TrackBackAboutsBase class TrackBackAbout < TrackBackAboutBase end end end end EOC end end end PK|]r]]rss/maker/syndication.rbnu[require 'rss/syndication' require 'rss/maker/1.0' module RSS module Maker module SyndicationModel def self.append_features(klass) super ::RSS::SyndicationModel::ELEMENTS.each do |name| klass.def_other_element(name) end end end class ChannelBase; include SyndicationModel; end end end PK|]}Z[[rss/maker/base.rbnu[require 'forwardable' require 'rss/rss' module RSS module Maker class Base extend Utils::InheritedReader OTHER_ELEMENTS = [] NEED_INITIALIZE_VARIABLES = [] class << self def other_elements inherited_array_reader("OTHER_ELEMENTS") end def need_initialize_variables inherited_array_reader("NEED_INITIALIZE_VARIABLES") end def inherited_base ::RSS::Maker::Base end def inherited(subclass) subclass.const_set("OTHER_ELEMENTS", []) subclass.const_set("NEED_INITIALIZE_VARIABLES", []) end def add_other_element(variable_name) self::OTHER_ELEMENTS << variable_name end def add_need_initialize_variable(variable_name, init_value="nil") self::NEED_INITIALIZE_VARIABLES << [variable_name, init_value] end def def_array_element(name, plural=nil, klass_name=nil) include Enumerable extend Forwardable plural ||= "#{name}s" klass_name ||= Utils.to_class_name(name) def_delegators("@#{plural}", :<<, :[], :[]=, :first, :last) def_delegators("@#{plural}", :push, :pop, :shift, :unshift) def_delegators("@#{plural}", :each, :size, :empty?, :clear) add_need_initialize_variable(plural, "[]") module_eval(<<-EOC, __FILE__, __LINE__ + 1) def new_#{name} #{name} = self.class::#{klass_name}.new(@maker) @#{plural} << #{name} if block_given? yield #{name} else #{name} end end alias new_child new_#{name} def to_feed(*args) @#{plural}.each do |#{name}| #{name}.to_feed(*args) end end def replace(elements) @#{plural}.replace(elements.to_a) end EOC end def def_classed_element_without_accessor(name, class_name=nil) class_name ||= Utils.to_class_name(name) add_other_element(name) add_need_initialize_variable(name, "make_#{name}") module_eval(<<-EOC, __FILE__, __LINE__ + 1) private def setup_#{name}(feed, current) @#{name}.to_feed(feed, current) end def make_#{name} self.class::#{class_name}.new(@maker) end EOC end def def_classed_element(name, class_name=nil, attribute_name=nil) def_classed_element_without_accessor(name, class_name) if attribute_name module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name} if block_given? yield(@#{name}) else @#{name}.#{attribute_name} end end def #{name}=(new_value) @#{name}.#{attribute_name} = new_value end EOC else attr_reader name end end def def_classed_elements(name, attribute, plural_class_name=nil, plural_name=nil, new_name=nil) plural_name ||= "#{name}s" new_name ||= name def_classed_element(plural_name, plural_class_name) local_variable_name = "_#{name}" new_value_variable_name = "new_value" additional_setup_code = nil if block_given? additional_setup_code = yield(local_variable_name, new_value_variable_name) end module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name} #{local_variable_name} = #{plural_name}.first #{local_variable_name} ? #{local_variable_name}.#{attribute} : nil end def #{name}=(#{new_value_variable_name}) #{local_variable_name} = #{plural_name}.first || #{plural_name}.new_#{new_name} #{additional_setup_code} #{local_variable_name}.#{attribute} = #{new_value_variable_name} end EOC end def def_other_element(name) attr_accessor name def_other_element_without_accessor(name) end def def_other_element_without_accessor(name) add_need_initialize_variable(name) add_other_element(name) module_eval(<<-EOC, __FILE__, __LINE__ + 1) def setup_#{name}(feed, current) if !@#{name}.nil? and current.respond_to?(:#{name}=) current.#{name} = @#{name} end end EOC end def def_csv_element(name, type=nil) def_other_element_without_accessor(name) attr_reader(name) converter = "" if type == :integer converter = "{|v| Integer(v)}" end module_eval(<<-EOC, __FILE__, __LINE__ + 1) def #{name}=(value) @#{name} = Utils::CSV.parse(value)#{converter} end EOC end end attr_reader :maker def initialize(maker) @maker = maker @default_values_are_set = false initialize_variables end def have_required_values? not_set_required_variables.empty? end def variable_is_set? variables.any? {|var| not __send__(var).nil?} end private def initialize_variables self.class.need_initialize_variables.each do |variable_name, init_value| instance_eval("@#{variable_name} = #{init_value}", __FILE__, __LINE__) end end def setup_other_elements(feed, current=nil) current ||= current_element(feed) self.class.other_elements.each do |element| __send__("setup_#{element}", feed, current) end end def current_element(feed) feed end def set_default_values(&block) return yield if @default_values_are_set begin @default_values_are_set = true _set_default_values(&block) ensure @default_values_are_set = false end end def _set_default_values(&block) yield end def setup_values(target) set = false if have_required_values? variables.each do |var| setter = "#{var}=" if target.respond_to?(setter) value = __send__(var) if value target.__send__(setter, value) set = true end end end end set end def set_parent(target, parent) target.parent = parent if target.class.need_parent? end def variables self.class.need_initialize_variables.find_all do |name, init| "nil" == init end.collect do |name, init| name end end def not_set_required_variables required_variable_names.find_all do |var| __send__(var).nil? end end def required_variables_are_set? required_variable_names.each do |var| return false if __send__(var).nil? end true end end module AtomPersonConstructBase def self.append_features(klass) super klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1) %w(name uri email).each do |element| attr_accessor element add_need_initialize_variable(element) end EOC end end module AtomTextConstructBase module EnsureXMLContent class << self def included(base) super base.class_eval do %w(type content xml_content).each do |element| attr_reader element attr_writer element if element != "xml_content" add_need_initialize_variable(element) end alias_method(:xhtml, :xml_content) end end end def ensure_xml_content(content) xhtml_uri = ::RSS::Atom::XHTML_URI unless content.is_a?(RSS::XML::Element) and ["div", xhtml_uri] == [content.name, content.uri] children = content children = [children] unless content.is_a?(Array) children = set_xhtml_uri_as_default_uri(children) content = RSS::XML::Element.new("div", nil, xhtml_uri, {"xmlns" => xhtml_uri}, children) end content end def xml_content=(content) @xml_content = ensure_xml_content(content) end def xhtml=(content) self.xml_content = content end private def set_xhtml_uri_as_default_uri(children) children.collect do |child| if child.is_a?(RSS::XML::Element) and child.prefix.nil? and child.uri.nil? RSS::XML::Element.new(child.name, nil, ::RSS::Atom::XHTML_URI, child.attributes.dup, set_xhtml_uri_as_default_uri(child.children)) else child end end end end def self.append_features(klass) super klass.class_eval do include EnsureXMLContent end end end module SetupDefaultDate private def _set_default_values(&block) keep = { :date => date, :dc_dates => dc_dates.to_a.dup, } _date = _parse_date_if_needed(date) if _date and !dc_dates.any? {|dc_date| dc_date.value == _date} dc_date = self.class::DublinCoreDates::DublinCoreDate.new(self) dc_date.value = _date.dup dc_dates.unshift(dc_date) end self.date ||= self.dc_date super(&block) ensure date = keep[:date] dc_dates.replace(keep[:dc_dates]) end def _parse_date_if_needed(date_value) date_value = Time.parse(date_value) if date_value.is_a?(String) date_value end end class RSSBase < Base class << self def make(version, &block) new(version).make(&block) end end %w(xml_stylesheets channel image items textinput).each do |element| attr_reader element add_need_initialize_variable(element, "make_#{element}") module_eval(<<-EOC, __FILE__, __LINE__) private def setup_#{element}(feed) @#{element}.to_feed(feed) end def make_#{element} self.class::#{Utils.to_class_name(element)}.new(self) end EOC end attr_reader :feed_version alias_method(:rss_version, :feed_version) attr_accessor :version, :encoding, :standalone def initialize(feed_version) super(self) @feed_type = nil @feed_subtype = nil @feed_version = feed_version @version = "1.0" @encoding = "UTF-8" @standalone = nil end def make if block_given? yield(self) to_feed else nil end end def to_feed feed = make_feed setup_xml_stylesheets(feed) setup_elements(feed) setup_other_elements(feed) if feed.valid? feed else nil end end private remove_method :make_xml_stylesheets def make_xml_stylesheets XMLStyleSheets.new(self) end end class XMLStyleSheets < Base def_array_element("xml_stylesheet", nil, "XMLStyleSheet") class XMLStyleSheet < Base ::RSS::XMLStyleSheet::ATTRIBUTES.each do |attribute| attr_accessor attribute add_need_initialize_variable(attribute) end def to_feed(feed) xss = ::RSS::XMLStyleSheet.new guess_type_if_need(xss) set = setup_values(xss) if set feed.xml_stylesheets << xss end end private def guess_type_if_need(xss) if @type.nil? xss.href = @href @type = xss.type end end def required_variable_names %w(href type) end end end class ChannelBase < Base include SetupDefaultDate %w(cloud categories skipDays skipHours).each do |name| def_classed_element(name) end %w(generator copyright description title).each do |name| def_classed_element(name, nil, "content") end [ ["link", "href", Proc.new {|target,| "#{target}.href = 'self'"}], ["author", "name"], ["contributor", "name"], ].each do |name, attribute, additional_setup_maker| def_classed_elements(name, attribute, &additional_setup_maker) end %w(id about language managingEditor webMaster rating docs ttl).each do |element| attr_accessor element add_need_initialize_variable(element) end %w(date lastBuildDate).each do |date_element| attr_reader date_element add_need_initialize_variable(date_element) end def date=(_date) @date = _parse_date_if_needed(_date) end def lastBuildDate=(_date) @lastBuildDate = _parse_date_if_needed(_date) end def pubDate date end def pubDate=(date) self.date = date end def updated date end def updated=(date) self.date = date end alias_method(:rights, :copyright) alias_method(:rights=, :copyright=) alias_method(:subtitle, :description) alias_method(:subtitle=, :description=) def icon image_favicon.about end def icon=(url) image_favicon.about = url end def logo maker.image.url end def logo=(url) maker.image.url = url end class SkipDaysBase < Base def_array_element("day") class DayBase < Base %w(content).each do |element| attr_accessor element add_need_initialize_variable(element) end end end class SkipHoursBase < Base def_array_element("hour") class HourBase < Base %w(content).each do |element| attr_accessor element add_need_initialize_variable(element) end end end class CloudBase < Base %w(domain port path registerProcedure protocol).each do |element| attr_accessor element add_need_initialize_variable(element) end end class CategoriesBase < Base def_array_element("category", "categories") class CategoryBase < Base %w(domain content label).each do |element| attr_accessor element add_need_initialize_variable(element) end alias_method(:term, :domain) alias_method(:term=, :domain=) alias_method(:scheme, :content) alias_method(:scheme=, :content=) end end class LinksBase < Base def_array_element("link") class LinkBase < Base %w(href rel type hreflang title length).each do |element| attr_accessor element add_need_initialize_variable(element) end end end class AuthorsBase < Base def_array_element("author") class AuthorBase < Base include AtomPersonConstructBase end end class ContributorsBase < Base def_array_element("contributor") class ContributorBase < Base include AtomPersonConstructBase end end class GeneratorBase < Base %w(uri version content).each do |element| attr_accessor element add_need_initialize_variable(element) end end class CopyrightBase < Base include AtomTextConstructBase end class DescriptionBase < Base include AtomTextConstructBase end class TitleBase < Base include AtomTextConstructBase end end class ImageBase < Base %w(title url width height description).each do |element| attr_accessor element add_need_initialize_variable(element) end def link @maker.channel.link end end class ItemsBase < Base def_array_element("item") attr_accessor :do_sort, :max_size def initialize(maker) super @do_sort = false @max_size = -1 end def normalize if @max_size >= 0 sort_if_need[0...@max_size] else sort_if_need[0..@max_size] end end private def sort_if_need if @do_sort.respond_to?(:call) @items.sort do |x, y| @do_sort.call(x, y) end elsif @do_sort @items.sort do |x, y| y <=> x end else @items end end class ItemBase < Base include SetupDefaultDate %w(guid enclosure source categories content).each do |name| def_classed_element(name) end %w(rights description title).each do |name| def_classed_element(name, nil, "content") end [ ["author", "name"], ["link", "href", Proc.new {|target,| "#{target}.href = 'alternate'"}], ["contributor", "name"], ].each do |name, attribute| def_classed_elements(name, attribute) end %w(comments id published).each do |element| attr_accessor element add_need_initialize_variable(element) end %w(date).each do |date_element| attr_reader date_element add_need_initialize_variable(date_element) end def date=(_date) @date = _parse_date_if_needed(_date) end def pubDate date end def pubDate=(date) self.date = date end def updated date end def updated=(date) self.date = date end alias_method(:summary, :description) alias_method(:summary=, :description=) def <=>(other) _date = date || dc_date _other_date = other.date || other.dc_date if _date and _other_date _date <=> _other_date elsif _date 1 elsif _other_date -1 else 0 end end class GuidBase < Base %w(isPermaLink content).each do |element| attr_accessor element add_need_initialize_variable(element) end end class EnclosureBase < Base %w(url length type).each do |element| attr_accessor element add_need_initialize_variable(element) end end class SourceBase < Base include SetupDefaultDate %w(authors categories contributors generator icon logo rights subtitle title).each do |name| def_classed_element(name) end [ ["link", "href"], ].each do |name, attribute| def_classed_elements(name, attribute) end %w(id content).each do |element| attr_accessor element add_need_initialize_variable(element) end alias_method(:url, :link) alias_method(:url=, :link=) %w(date).each do |date_element| attr_reader date_element add_need_initialize_variable(date_element) end def date=(_date) @date = _parse_date_if_needed(_date) end def updated date end def updated=(date) self.date = date end private AuthorsBase = ChannelBase::AuthorsBase CategoriesBase = ChannelBase::CategoriesBase ContributorsBase = ChannelBase::ContributorsBase GeneratorBase = ChannelBase::GeneratorBase class IconBase < Base %w(url).each do |element| attr_accessor element add_need_initialize_variable(element) end end LinksBase = ChannelBase::LinksBase class LogoBase < Base %w(uri).each do |element| attr_accessor element add_need_initialize_variable(element) end end class RightsBase < Base include AtomTextConstructBase end class SubtitleBase < Base include AtomTextConstructBase end class TitleBase < Base include AtomTextConstructBase end end CategoriesBase = ChannelBase::CategoriesBase AuthorsBase = ChannelBase::AuthorsBase LinksBase = ChannelBase::LinksBase ContributorsBase = ChannelBase::ContributorsBase class RightsBase < Base include AtomTextConstructBase end class DescriptionBase < Base include AtomTextConstructBase end class ContentBase < Base include AtomTextConstructBase::EnsureXMLContent %w(src).each do |element| attr_accessor(element) add_need_initialize_variable(element) end def xml_content=(content) content = ensure_xml_content(content) if inline_xhtml? @xml_content = content end alias_method(:xml, :xml_content) alias_method(:xml=, :xml_content=) def inline_text? [nil, "text", "html"].include?(@type) end def inline_html? @type == "html" end def inline_xhtml? @type == "xhtml" end def inline_other? !out_of_line? and ![nil, "text", "html", "xhtml"].include?(@type) end def inline_other_text? return false if @type.nil? or out_of_line? /\Atext\//i.match(@type) ? true : false end def inline_other_xml? return false if @type.nil? or out_of_line? /[\+\/]xml\z/i.match(@type) ? true : false end def inline_other_base64? return false if @type.nil? or out_of_line? @type.include?("/") and !inline_other_text? and !inline_other_xml? end def out_of_line? not @src.nil? and @content.nil? end end class TitleBase < Base include AtomTextConstructBase end end end class TextinputBase < Base %w(title description name link).each do |element| attr_accessor element add_need_initialize_variable(element) end end end end PK|]_ rss/maker/taxonomy.rbnu[require 'rss/taxonomy' require 'rss/maker/1.0' require 'rss/maker/dublincore' module RSS module Maker module TaxonomyTopicsModel def self.append_features(klass) super klass.def_classed_element("#{RSS::TAXO_PREFIX}_topics", "TaxonomyTopics") end def self.install_taxo_topics(klass) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class TaxonomyTopics < TaxonomyTopicsBase def to_feed(feed, current) if current.respond_to?(:taxo_topics) topics = current.class::TaxonomyTopics.new bag = topics.Bag @resources.each do |resource| bag.lis << RDF::Bag::Li.new(resource) end current.taxo_topics = topics end end end EOC end class TaxonomyTopicsBase < Base attr_reader :resources def_array_element("resource") remove_method :new_resource end end module TaxonomyTopicModel def self.append_features(klass) super class_name = "TaxonomyTopics" klass.def_classed_elements("#{TAXO_PREFIX}_topic", "value", class_name) end def self.install_taxo_topic(klass) klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) class TaxonomyTopics < TaxonomyTopicsBase class TaxonomyTopic < TaxonomyTopicBase DublinCoreModel.install_dublin_core(self) TaxonomyTopicsModel.install_taxo_topics(self) def to_feed(feed, current) if current.respond_to?(:taxo_topics) topic = current.class::TaxonomyTopic.new(value) topic.taxo_link = value taxo_topics.to_feed(feed, topic) if taxo_topics current.taxo_topics << topic setup_other_elements(feed, topic) end end end end EOC end class TaxonomyTopicsBase < Base def_array_element("topic", nil, "TaxonomyTopic") alias_method(:new_taxo_topic, :new_topic) # For backward compatibility class TaxonomyTopicBase < Base include DublinCoreModel include TaxonomyTopicsModel attr_accessor :value add_need_initialize_variable("value") alias_method(:taxo_link, :value) alias_method(:taxo_link=, :value=) def have_required_values? @value end end end end class RSSBase include TaxonomyTopicModel end class ChannelBase include TaxonomyTopicsModel end class ItemsBase class ItemBase include TaxonomyTopicsModel end end makers.each do |maker| maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1) TaxonomyTopicModel.install_taxo_topic(self) class Channel TaxonomyTopicsModel.install_taxo_topics(self) end class Items class Item TaxonomyTopicsModel.install_taxo_topics(self) end end EOC end end end PK|]ƾrss/maker/entry.rbnu[require "rss/maker/atom" require "rss/maker/feed" module RSS module Maker module Atom class Entry < RSSBase def initialize(feed_version="1.0") super @feed_type = "atom" @feed_subtype = "entry" end private def make_feed ::RSS::Atom::Entry.new(@version, @encoding, @standalone) end def setup_elements(entry) setup_items(entry) end class Channel < ChannelBase class SkipDays < SkipDaysBase class Day < DayBase end end class SkipHours < SkipHoursBase class Hour < HourBase end end class Cloud < CloudBase end Categories = Feed::Channel::Categories Links = Feed::Channel::Links Authors = Feed::Channel::Authors Contributors = Feed::Channel::Contributors class Generator < GeneratorBase include AtomGenerator def self.not_set_name "maker.channel.generator" end end Copyright = Feed::Channel::Copyright class Description < DescriptionBase end Title = Feed::Channel::Title end class Image < ImageBase end class Items < ItemsBase def to_feed(entry) (normalize.first || Item.new(@maker)).to_feed(entry) end class Item < ItemBase def to_feed(entry) set_default_values do setup_values(entry) entry.dc_dates.clear setup_other_elements(entry) unless have_required_values? raise NotSetError.new("maker.item", not_set_required_variables) end end end private def required_variable_names %w(id updated) end def variables super + ["updated"] end def variable_is_set? super or !authors.empty? end def not_set_required_variables set_default_values do vars = super if authors.all? {|author| !author.have_required_values?} vars << "author" end vars << "title" unless title {|t| t.have_required_values?} vars end end def _set_default_values(&block) keep = { :authors => authors.to_a.dup, :contributors => contributors.to_a.dup, :categories => categories.to_a.dup, :id => id, :links => links.to_a.dup, :rights => @rights, :title => @title, :updated => updated, } authors.replace(@maker.channel.authors) if keep[:authors].empty? if keep[:contributors].empty? contributors.replace(@maker.channel.contributors) end if keep[:categories].empty? categories.replace(@maker.channel.categories) end self.id ||= link || @maker.channel.id links.replace(@maker.channel.links) if keep[:links].empty? unless keep[:rights].variable_is_set? @maker.channel.rights {|r| @rights = r} end unless keep[:title].variable_is_set? @maker.channel.title {|t| @title = t} end self.updated ||= @maker.channel.updated super(&block) ensure authors.replace(keep[:authors]) contributors.replace(keep[:contributors]) categories.replace(keep[:categories]) links.replace(keep[:links]) self.id = keep[:id] @rights = keep[:rights] @title = keep[:title] self.updated = keep[:prev_updated] end Guid = Feed::Items::Item::Guid Enclosure = Feed::Items::Item::Enclosure Source = Feed::Items::Item::Source Categories = Feed::Items::Item::Categories Authors = Feed::Items::Item::Authors Contributors = Feed::Items::Item::Contributors Links = Feed::Items::Item::Links Rights = Feed::Items::Item::Rights Description = Feed::Items::Item::Description Title = Feed::Items::Item::Title Content = Feed::Items::Item::Content end end class Textinput < TextinputBase end end end add_maker("atom:entry", "1.0", Atom::Entry) add_maker("atom1.0:entry", "1.0", Atom::Entry) end end PK|]*:e  rss/maker/2.0.rbnu[require "rss/2.0" require "rss/maker/0.9" module RSS module Maker class RSS20 < RSS09 def initialize(feed_version="2.0") super end class Channel < RSS09::Channel private def required_variable_names %w(link) end class SkipDays < RSS09::Channel::SkipDays class Day < RSS09::Channel::SkipDays::Day end end class SkipHours < RSS09::Channel::SkipHours class Hour < RSS09::Channel::SkipHours::Hour end end class Cloud < RSS09::Channel::Cloud def to_feed(rss, channel) cloud = Rss::Channel::Cloud.new set = setup_values(cloud) if set channel.cloud = cloud set_parent(cloud, channel) setup_other_elements(rss, cloud) end end private def required_variable_names %w(domain port path registerProcedure protocol) end end class Categories < RSS09::Channel::Categories def to_feed(rss, channel) @categories.each do |category| category.to_feed(rss, channel) end end class Category < RSS09::Channel::Categories::Category def to_feed(rss, channel) category = Rss::Channel::Category.new set = setup_values(category) if set channel.categories << category set_parent(category, channel) setup_other_elements(rss, category) end end private def required_variable_names %w(content) end end end class Generator < GeneratorBase def to_feed(rss, channel) channel.generator = content end private def required_variable_names %w(content) end end end class Image < RSS09::Image private def required_element? false end end class Items < RSS09::Items class Item < RSS09::Items::Item private def required_variable_names [] end def not_set_required_variables vars = super if !title {|t| t.have_required_values?} and !description {|d| d.have_required_values?} vars << "title or description" end vars end def variables super + ["pubDate"] end class Guid < RSS09::Items::Item::Guid def to_feed(rss, item) guid = Rss::Channel::Item::Guid.new set = setup_values(guid) if set item.guid = guid set_parent(guid, item) setup_other_elements(rss, guid) end end private def required_variable_names %w(content) end end class Enclosure < RSS09::Items::Item::Enclosure def to_feed(rss, item) enclosure = Rss::Channel::Item::Enclosure.new set = setup_values(enclosure) if set item.enclosure = enclosure set_parent(enclosure, item) setup_other_elements(rss, enclosure) end end private def required_variable_names %w(url length type) end end class Source < RSS09::Items::Item::Source def to_feed(rss, item) source = Rss::Channel::Item::Source.new set = setup_values(source) if set item.source = source set_parent(source, item) setup_other_elements(rss, source) end end private def required_variable_names %w(url content) end class Links < RSS09::Items::Item::Source::Links def to_feed(rss, source) return if @links.empty? @links.first.to_feed(rss, source) end class Link < RSS09::Items::Item::Source::Links::Link def to_feed(rss, source) source.url = href end end end end class Categories < RSS09::Items::Item::Categories def to_feed(rss, item) @categories.each do |category| category.to_feed(rss, item) end end class Category < RSS09::Items::Item::Categories::Category def to_feed(rss, item) category = Rss::Channel::Item::Category.new set = setup_values(category) if set item.categories << category set_parent(category, item) setup_other_elements(rss) end end private def required_variable_names %w(content) end end end class Authors < RSS09::Items::Item::Authors def to_feed(rss, item) return if @authors.empty? @authors.first.to_feed(rss, item) end class Author < RSS09::Items::Item::Authors::Author def to_feed(rss, item) item.author = name end end end end end class Textinput < RSS09::Textinput end end add_maker("2.0", "2.0", RSS20) add_maker("rss2.0", "2.0", RSS20) end end PK|] # rss/maker.rbnu[require "rss/rss" module RSS module Maker MAKERS = {} class << self def make(version, &block) m = maker(version) raise UnsupportedMakerVersionError.new(version) if m.nil? m[:maker].make(m[:version], &block) end def maker(version) MAKERS[version] end def add_maker(version, normalized_version, maker) MAKERS[version] = {:maker => maker, :version => normalized_version} end def versions MAKERS.keys.uniq.sort end def makers MAKERS.values.collect {|info| info[:maker]}.uniq end end end end require "rss/maker/1.0" require "rss/maker/2.0" require "rss/maker/feed" require "rss/maker/entry" require "rss/maker/content" require "rss/maker/dublincore" require "rss/maker/slash" require "rss/maker/syndication" require "rss/maker/taxonomy" require "rss/maker/trackback" require "rss/maker/image" require "rss/maker/itunes" PK|];}Pxx rss/image.rbnu[require 'rss/1.0' require 'rss/dublincore' module RSS IMAGE_PREFIX = 'image' IMAGE_URI = 'http://purl.org/rss/1.0/modules/image/' RDF.install_ns(IMAGE_PREFIX, IMAGE_URI) IMAGE_ELEMENTS = [] %w(item favicon).each do |name| class_name = Utils.to_class_name(name) BaseListener.install_class_name(IMAGE_URI, name, "Image#{class_name}") IMAGE_ELEMENTS << "#{IMAGE_PREFIX}_#{name}" end module ImageModelUtils def validate_one_tag_name(ignore_unknown_element, name, tags) if !ignore_unknown_element invalid = tags.find {|tag| tag != name} raise UnknownTagError.new(invalid, IMAGE_URI) if invalid end raise TooMuchTagError.new(name, tag_name) if tags.size > 1 end end module ImageItemModel include ImageModelUtils extend BaseModel def self.append_features(klass) super klass.install_have_child_element("item", IMAGE_URI, "?", "#{IMAGE_PREFIX}_item") klass.install_must_call_validator(IMAGE_PREFIX, IMAGE_URI) end class ImageItem < Element include RSS10 include DublinCoreModel @tag_name = "item" class << self def required_prefix IMAGE_PREFIX end def required_uri IMAGE_URI end end install_must_call_validator(IMAGE_PREFIX, IMAGE_URI) [ ["about", ::RSS::RDF::URI, true], ["resource", ::RSS::RDF::URI, false], ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{::RSS::RDF::PREFIX}:#{name}") end %w(width height).each do |tag| full_name = "#{IMAGE_PREFIX}_#{tag}" disp_name = "#{IMAGE_PREFIX}:#{tag}" install_text_element(tag, IMAGE_URI, "?", full_name, :integer, disp_name) BaseListener.install_get_text_element(IMAGE_URI, tag, full_name) end alias width= image_width= alias width image_width alias height= image_height= alias height image_height def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] self.resource = args[1] end end def full_name tag_name_with_prefix(IMAGE_PREFIX) end private def maker_target(target) target.image_item end def setup_maker_attributes(item) item.about = self.about item.resource = self.resource end end end module ImageFaviconModel include ImageModelUtils extend BaseModel def self.append_features(klass) super unless klass.class == Module klass.install_have_child_element("favicon", IMAGE_URI, "?", "#{IMAGE_PREFIX}_favicon") klass.install_must_call_validator(IMAGE_PREFIX, IMAGE_URI) end end class ImageFavicon < Element include RSS10 include DublinCoreModel @tag_name = "favicon" class << self def required_prefix IMAGE_PREFIX end def required_uri IMAGE_URI end end [ ["about", ::RSS::RDF::URI, true, ::RSS::RDF::PREFIX], ["size", IMAGE_URI, true, IMAGE_PREFIX], ].each do |name, uri, required, prefix| install_get_attribute(name, uri, required, nil, nil, "#{prefix}:#{name}") end AVAILABLE_SIZES = %w(small medium large) alias_method :set_size, :size= private :set_size def size=(new_value) if @do_validate and !new_value.nil? new_value = new_value.strip unless AVAILABLE_SIZES.include?(new_value) attr_name = "#{IMAGE_PREFIX}:size" raise NotAvailableValueError.new(full_name, new_value, attr_name) end end set_size(new_value) end alias image_size= size= alias image_size size def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] self.size = args[1] end end def full_name tag_name_with_prefix(IMAGE_PREFIX) end private def maker_target(target) target.image_favicon end def setup_maker_attributes(favicon) favicon.about = self.about favicon.size = self.size end end end class RDF class Channel; include ImageFaviconModel; end class Item; include ImageItemModel; end end end PK|]9'' rss/itunes.rbnu[require 'rss/2.0' module RSS ITUNES_PREFIX = 'itunes' ITUNES_URI = 'http://www.itunes.com/dtds/podcast-1.0.dtd' Rss.install_ns(ITUNES_PREFIX, ITUNES_URI) module ITunesModelUtils include Utils def def_class_accessor(klass, name, type, *args) normalized_name = name.gsub(/-/, "_") full_name = "#{ITUNES_PREFIX}_#{normalized_name}" klass_name = "ITunes#{Utils.to_class_name(normalized_name)}" case type when :element, :attribute klass::ELEMENTS << full_name def_element_class_accessor(klass, name, full_name, klass_name, *args) when :elements klass::ELEMENTS << full_name def_elements_class_accessor(klass, name, full_name, klass_name, *args) else klass.install_must_call_validator(ITUNES_PREFIX, ITUNES_URI) klass.install_text_element(normalized_name, ITUNES_URI, "?", full_name, type, name) end end def def_element_class_accessor(klass, name, full_name, klass_name, recommended_attribute_name=nil) klass.install_have_child_element(name, ITUNES_PREFIX, "?", full_name) end def def_elements_class_accessor(klass, name, full_name, klass_name, plural_name, recommended_attribute_name=nil) full_plural_name = "#{ITUNES_PREFIX}_#{plural_name}" klass.install_have_children_element(name, ITUNES_PREFIX, "*", full_name, full_plural_name) end end module ITunesBaseModel extend ITunesModelUtils ELEMENTS = [] ELEMENT_INFOS = [["author"], ["block", :yes_other], ["explicit", :yes_clean_other], ["keywords", :csv], ["subtitle"], ["summary"]] end module ITunesChannelModel extend BaseModel extend ITunesModelUtils include ITunesBaseModel ELEMENTS = [] class << self def append_features(klass) super return if klass.instance_of?(Module) ELEMENT_INFOS.each do |name, type, *additional_infos| def_class_accessor(klass, name, type, *additional_infos) end end end ELEMENT_INFOS = [ ["category", :elements, "categories", "text"], ["image", :attribute, "href"], ["owner", :element], ["new-feed-url"], ] + ITunesBaseModel::ELEMENT_INFOS class ITunesCategory < Element include RSS09 @tag_name = "category" class << self def required_prefix ITUNES_PREFIX end def required_uri ITUNES_URI end end [ ["text", "", true] ].each do |name, uri, required| install_get_attribute(name, uri, required) end ITunesCategory = self install_have_children_element("category", ITUNES_URI, "*", "#{ITUNES_PREFIX}_category", "#{ITUNES_PREFIX}_categories") def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.text = args[0] end end def full_name tag_name_with_prefix(ITUNES_PREFIX) end private def maker_target(categories) if text or !itunes_categories.empty? categories.new_category else nil end end def setup_maker_attributes(category) category.text = text if text end def setup_maker_elements(category) super(category) itunes_categories.each do |sub_category| sub_category.setup_maker(category) end end end class ITunesImage < Element include RSS09 @tag_name = "image" class << self def required_prefix ITUNES_PREFIX end def required_uri ITUNES_URI end end [ ["href", "", true] ].each do |name, uri, required| install_get_attribute(name, uri, required) end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.href = args[0] end end def full_name tag_name_with_prefix(ITUNES_PREFIX) end private def maker_target(target) if href target.itunes_image {|image| image} else nil end end def setup_maker_attributes(image) image.href = href end end class ITunesOwner < Element include RSS09 @tag_name = "owner" class << self def required_prefix ITUNES_PREFIX end def required_uri ITUNES_URI end end install_must_call_validator(ITUNES_PREFIX, ITUNES_URI) [ ["name"], ["email"], ].each do |name,| ITunesBaseModel::ELEMENT_INFOS << name install_text_element(name, ITUNES_URI, nil, "#{ITUNES_PREFIX}_#{name}") end def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.itunes_name = args[0] self.itunes_email = args[1] end end def full_name tag_name_with_prefix(ITUNES_PREFIX) end private def maker_target(target) target.itunes_owner end def setup_maker_element(owner) super(owner) owner.itunes_name = itunes_name owner.itunes_email = itunes_email end end end module ITunesItemModel extend BaseModel extend ITunesModelUtils include ITunesBaseModel class << self def append_features(klass) super return if klass.instance_of?(Module) ELEMENT_INFOS.each do |name, type| def_class_accessor(klass, name, type) end end end ELEMENT_INFOS = ITunesBaseModel::ELEMENT_INFOS + [["duration", :element, "content"]] class ITunesDuration < Element include RSS09 @tag_name = "duration" class << self def required_prefix ITUNES_PREFIX end def required_uri ITUNES_URI end def parse(duration, do_validate=true) if do_validate and /\A(?: \d?\d:[0-5]\d:[0-5]\d| [0-5]?\d:[0-5]\d )\z/x !~ duration raise ArgumentError, "must be one of HH:MM:SS, H:MM:SS, MM::SS, M:SS: " + duration.inspect end components = duration.split(':') components[3..-1] = nil if components.size > 3 components.unshift("00") until components.size == 3 components.collect do |component| component.to_i end end def construct(hour, minute, second) components = [minute, second] if components.include?(nil) nil else components.unshift(hour) if hour and hour > 0 components.collect do |component| "%02d" % component end.join(":") end end end content_setup alias_method(:value, :content) remove_method(:content=) attr_reader :hour, :minute, :second def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() args = args[0] if args.size == 1 and args[0].is_a?(Array) if args.size == 1 self.content = args[0] elsif args.size > 3 raise ArgumentError, "must be (do_validate, params), (content), " + "(minute, second), ([minute, second]), " + "(hour, minute, second) or ([hour, minute, second]): " + args.inspect else @second, @minute, @hour = args.reverse update_content end end end def content=(value) if value.nil? @content = nil elsif value.is_a?(self.class) self.content = value.content else begin @hour, @minute, @second = self.class.parse(value, @do_validate) rescue ArgumentError raise NotAvailableValueError.new(tag_name, value) end @content = value end end alias_method(:value=, :content=) def hour=(hour) @hour = @do_validate ? Integer(hour) : hour.to_i update_content hour end def minute=(minute) @minute = @do_validate ? Integer(minute) : minute.to_i update_content minute end def second=(second) @second = @do_validate ? Integer(second) : second.to_i update_content second end def full_name tag_name_with_prefix(ITUNES_PREFIX) end private def update_content @content = self.class.construct(hour, minute, second) end def maker_target(target) if @content target.itunes_duration {|duration| duration} else nil end end def setup_maker_element(duration) super(duration) duration.content = @content end end end class Rss class Channel include ITunesChannelModel class Item; include ITunesItemModel; end end end element_infos = ITunesChannelModel::ELEMENT_INFOS + ITunesItemModel::ELEMENT_INFOS element_infos.each do |name, type| case type when :element, :elements, :attribute class_name = Utils.to_class_name(name) BaseListener.install_class_name(ITUNES_URI, name, "ITunes#{class_name}") else accessor_base = "#{ITUNES_PREFIX}_#{name.gsub(/-/, '_')}" BaseListener.install_get_text_element(ITUNES_URI, name, accessor_base) end end end PK|]vEJJrss/xmlparser.rbnu[begin require "xml/parser" rescue LoadError require "xmlparser" end begin require "xml/encoding-ja" rescue LoadError require "xmlencoding-ja" if defined?(Kconv) module XMLEncoding_ja class SJISHandler include Kconv end end end end module XML class Parser unless defined?(Error) Error = ::XMLParserError end end end module RSS class REXMLLikeXMLParser < ::XML::Parser include ::XML::Encoding_ja def listener=(listener) @listener = listener end def startElement(name, attrs) @listener.tag_start(name, attrs) end def endElement(name) @listener.tag_end(name) end def character(data) @listener.text(data) end def xmlDecl(version, encoding, standalone) @listener.xmldecl(version, encoding, standalone == 1) end def processingInstruction(target, content) @listener.instruction(target, content) end end class XMLParserParser < BaseParser class << self def listener XMLParserListener end end private def _parse begin parser = REXMLLikeXMLParser.new parser.listener = @listener parser.parse(@rss) rescue ::XML::Parser::Error => e raise NotWellFormedError.new(parser.line){e.message} end end end class XMLParserListener < BaseListener include ListenerMixin def xmldecl(version, encoding, standalone) super # Encoding is converted to UTF-8 when XMLParser parses XML. @encoding = 'UTF-8' end end end PK|]V rss/trackback.rbnu[require 'rss/1.0' require 'rss/2.0' module RSS TRACKBACK_PREFIX = 'trackback' TRACKBACK_URI = 'http://madskills.com/public/xml/rss/module/trackback/' RDF.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI) Rss.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI) module TrackBackUtils private def trackback_validate(ignore_unknown_element, tags, uri) return if tags.nil? if tags.find {|tag| tag == "about"} and !tags.find {|tag| tag == "ping"} raise MissingTagError.new("#{TRACKBACK_PREFIX}:ping", tag_name) end end end module BaseTrackBackModel ELEMENTS = %w(ping about) def append_features(klass) super unless klass.class == Module klass.module_eval {include TrackBackUtils} klass.install_must_call_validator(TRACKBACK_PREFIX, TRACKBACK_URI) %w(ping).each do |name| var_name = "#{TRACKBACK_PREFIX}_#{name}" klass_name = "TrackBack#{Utils.to_class_name(name)}" klass.install_have_child_element(name, TRACKBACK_URI, "?", var_name) klass.module_eval(<<-EOC, __FILE__, __LINE__) remove_method :#{var_name} def #{var_name} @#{var_name} and @#{var_name}.value end remove_method :#{var_name}= def #{var_name}=(value) @#{var_name} = Utils.new_with_value_if_need(#{klass_name}, value) end EOC end [%w(about s)].each do |name, postfix| var_name = "#{TRACKBACK_PREFIX}_#{name}" klass_name = "TrackBack#{Utils.to_class_name(name)}" klass.install_have_children_element(name, TRACKBACK_URI, "*", var_name) klass.module_eval(<<-EOC, __FILE__, __LINE__) remove_method :#{var_name} def #{var_name}(*args) if args.empty? @#{var_name}.first and @#{var_name}.first.value else ret = @#{var_name}.__send__("[]", *args) if ret.is_a?(Array) ret.collect {|x| x.value} else ret.value end end end remove_method :#{var_name}= remove_method :set_#{var_name} def #{var_name}=(*args) if args.size == 1 item = Utils.new_with_value_if_need(#{klass_name}, args[0]) @#{var_name}.push(item) else new_val = args.last if new_val.is_a?(Array) new_val = new_value.collect do |val| Utils.new_with_value_if_need(#{klass_name}, val) end else new_val = Utils.new_with_value_if_need(#{klass_name}, new_val) end @#{var_name}.__send__("[]=", *(args[0..-2] + [new_val])) end end alias set_#{var_name} #{var_name}= EOC end end end end module TrackBackModel10 extend BaseModel extend BaseTrackBackModel class TrackBackPing < Element include RSS10 class << self def required_prefix TRACKBACK_PREFIX end def required_uri TRACKBACK_URI end end @tag_name = "ping" [ ["resource", ::RSS::RDF::URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{::RSS::RDF::PREFIX}:#{name}") end alias_method(:value, :resource) alias_method(:value=, :resource=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end def full_name tag_name_with_prefix(TRACKBACK_PREFIX) end end class TrackBackAbout < Element include RSS10 class << self def required_prefix TRACKBACK_PREFIX end def required_uri TRACKBACK_URI end end @tag_name = "about" [ ["resource", ::RSS::RDF::URI, true] ].each do |name, uri, required| install_get_attribute(name, uri, required, nil, nil, "#{::RSS::RDF::PREFIX}:#{name}") end alias_method(:value, :resource) alias_method(:value=, :resource=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.resource = args[0] end end def full_name tag_name_with_prefix(TRACKBACK_PREFIX) end private def maker_target(abouts) abouts.new_about end def setup_maker_attributes(about) about.resource = self.resource end end end module TrackBackModel20 extend BaseModel extend BaseTrackBackModel class TrackBackPing < Element include RSS09 @tag_name = "ping" content_setup class << self def required_prefix TRACKBACK_PREFIX end def required_uri TRACKBACK_URI end end alias_method(:value, :content) alias_method(:value=, :content=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end def full_name tag_name_with_prefix(TRACKBACK_PREFIX) end end class TrackBackAbout < Element include RSS09 @tag_name = "about" content_setup class << self def required_prefix TRACKBACK_PREFIX end def required_uri TRACKBACK_URI end end alias_method(:value, :content) alias_method(:value=, :content=) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.content = args[0] end end def full_name tag_name_with_prefix(TRACKBACK_PREFIX) end end end class RDF class Item; include TrackBackModel10; end end class Rss class Channel class Item; include TrackBackModel20; end end end BaseTrackBackModel::ELEMENTS.each do |name| class_name = Utils.to_class_name(name) BaseListener.install_class_name(TRACKBACK_URI, name, "TrackBack#{class_name}") end BaseTrackBackModel::ELEMENTS.collect! {|name| "#{TRACKBACK_PREFIX}_#{name}"} end PK|]#  rss/syndication.rbnu[require "rss/1.0" module RSS SY_PREFIX = 'sy' SY_URI = "http://purl.org/rss/1.0/modules/syndication/" RDF.install_ns(SY_PREFIX, SY_URI) module SyndicationModel extend BaseModel ELEMENTS = [] def self.append_features(klass) super klass.install_must_call_validator(SY_PREFIX, SY_URI) klass.module_eval do [ ["updatePeriod"], ["updateFrequency", :positive_integer] ].each do |name, type| install_text_element(name, SY_URI, "?", "#{SY_PREFIX}_#{name}", type, "#{SY_PREFIX}:#{name}") end %w(updateBase).each do |name| install_date_element(name, SY_URI, "?", "#{SY_PREFIX}_#{name}", 'w3cdtf', "#{SY_PREFIX}:#{name}") end end klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1) alias_method(:_sy_updatePeriod=, :sy_updatePeriod=) def sy_updatePeriod=(new_value) new_value = new_value.strip validate_sy_updatePeriod(new_value) if @do_validate self._sy_updatePeriod = new_value end EOC end private SY_UPDATEPERIOD_AVAILABLE_VALUES = %w(hourly daily weekly monthly yearly) def validate_sy_updatePeriod(value) unless SY_UPDATEPERIOD_AVAILABLE_VALUES.include?(value) raise NotAvailableValueError.new("updatePeriod", value) end end end class RDF class Channel; include SyndicationModel; end end prefix_size = SY_PREFIX.size + 1 SyndicationModel::ELEMENTS.uniq! SyndicationModel::ELEMENTS.each do |full_name| name = full_name[prefix_size..-1] BaseListener.install_get_text_element(SY_URI, name, full_name) end end PK|]Prss/converter.rbnu[require "rss/utils" module RSS class Converter include Utils def initialize(to_enc, from_enc=nil) normalized_to_enc = to_enc.downcase.gsub(/-/, '_') from_enc ||= 'utf-8' normalized_from_enc = from_enc.downcase.gsub(/-/, '_') if normalized_to_enc == normalized_from_enc def_same_enc() else def_diff_enc = "def_to_#{normalized_to_enc}_from_#{normalized_from_enc}" if respond_to?(def_diff_enc) __send__(def_diff_enc) else def_else_enc(to_enc, from_enc) end end end def convert(value) value end def def_convert(depth=0) instance_eval(<<-EOC, *get_file_and_line_from_caller(depth)) def convert(value) if value.kind_of?(String) #{yield('value')} else value end end EOC end def def_iconv_convert(to_enc, from_enc, depth=0) begin require "iconv" @iconv = Iconv.new(to_enc, from_enc) def_convert(depth+1) do |value| <<-EOC begin @iconv.iconv(#{value}) rescue Iconv::Failure raise ConversionError.new(#{value}, "#{to_enc}", "#{from_enc}") end EOC end rescue LoadError, ArgumentError, SystemCallError raise UnknownConversionMethodError.new(to_enc, from_enc) end end def def_else_enc(to_enc, from_enc) def_iconv_convert(to_enc, from_enc, 0) end def def_same_enc() def_convert do |value| value end end def def_uconv_convert_if_can(meth, to_enc, from_enc, nkf_arg) begin require "uconv" def_convert(1) do |value| <<-EOC begin Uconv.#{meth}(#{value}) rescue Uconv::Error raise ConversionError.new(#{value}, "#{to_enc}", "#{from_enc}") end EOC end rescue LoadError require 'nkf' if NKF.const_defined?(:UTF8) def_convert(1) do |value| "NKF.nkf(#{nkf_arg.dump}, #{value})" end else def_iconv_convert(to_enc, from_enc, 1) end end end def def_to_euc_jp_from_utf_8 def_uconv_convert_if_can('u8toeuc', 'EUC-JP', 'UTF-8', '-We') end def def_to_utf_8_from_euc_jp def_uconv_convert_if_can('euctou8', 'UTF-8', 'EUC-JP', '-Ew') end def def_to_shift_jis_from_utf_8 def_uconv_convert_if_can('u8tosjis', 'Shift_JIS', 'UTF-8', '-Ws') end def def_to_utf_8_from_shift_jis def_uconv_convert_if_can('sjistou8', 'UTF-8', 'Shift_JIS', '-Sw') end def def_to_euc_jp_from_shift_jis require "nkf" def_convert do |value| "NKF.nkf('-Se', #{value})" end end def def_to_shift_jis_from_euc_jp require "nkf" def_convert do |value| "NKF.nkf('-Es', #{value})" end end def def_to_euc_jp_from_iso_2022_jp require "nkf" def_convert do |value| "NKF.nkf('-Je', #{value})" end end def def_to_iso_2022_jp_from_euc_jp require "nkf" def_convert do |value| "NKF.nkf('-Ej', #{value})" end end def def_to_utf_8_from_iso_8859_1 def_convert do |value| "#{value}.unpack('C*').pack('U*')" end end def def_to_iso_8859_1_from_utf_8 def_convert do |value| <<-EOC array_utf8 = #{value}.unpack('U*') array_enc = [] array_utf8.each do |num| if num <= 0xFF array_enc << num else array_enc.concat "&\#\#{num};".unpack('C*') end end array_enc.pack('C*') EOC end end end end PK|]&@  rss/taxonomy.rbnu[require "rss/1.0" require "rss/dublincore" module RSS TAXO_PREFIX = "taxo" TAXO_URI = "http://purl.org/rss/1.0/modules/taxonomy/" RDF.install_ns(TAXO_PREFIX, TAXO_URI) TAXO_ELEMENTS = [] %w(link).each do |name| full_name = "#{TAXO_PREFIX}_#{name}" BaseListener.install_get_text_element(TAXO_URI, name, full_name) TAXO_ELEMENTS << "#{TAXO_PREFIX}_#{name}" end %w(topic topics).each do |name| class_name = Utils.to_class_name(name) BaseListener.install_class_name(TAXO_URI, name, "Taxonomy#{class_name}") TAXO_ELEMENTS << "#{TAXO_PREFIX}_#{name}" end module TaxonomyTopicsModel extend BaseModel def self.append_features(klass) super klass.install_must_call_validator(TAXO_PREFIX, TAXO_URI) %w(topics).each do |name| klass.install_have_child_element(name, TAXO_URI, "?", "#{TAXO_PREFIX}_#{name}") end end class TaxonomyTopics < Element include RSS10 Bag = ::RSS::RDF::Bag class << self def required_prefix TAXO_PREFIX end def required_uri TAXO_URI end end @tag_name = "topics" install_have_child_element("Bag", RDF::URI, nil) install_must_call_validator('rdf', RDF::URI) def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.Bag = args[0] end self.Bag ||= Bag.new end def full_name tag_name_with_prefix(TAXO_PREFIX) end def maker_target(target) target.taxo_topics end def resources if @Bag @Bag.lis.collect do |li| li.resource end else [] end end end end module TaxonomyTopicModel extend BaseModel def self.append_features(klass) super var_name = "#{TAXO_PREFIX}_topic" klass.install_have_children_element("topic", TAXO_URI, "*", var_name) end class TaxonomyTopic < Element include RSS10 include DublinCoreModel include TaxonomyTopicsModel class << self def required_prefix TAXO_PREFIX end def required_uri TAXO_URI end end @tag_name = "topic" install_get_attribute("about", ::RSS::RDF::URI, true, nil, nil, "#{RDF::PREFIX}:about") install_text_element("link", TAXO_URI, "?", "#{TAXO_PREFIX}_link") def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.about = args[0] end end def full_name tag_name_with_prefix(TAXO_PREFIX) end def maker_target(target) target.new_taxo_topic end end end class RDF include TaxonomyTopicModel class Channel include TaxonomyTopicsModel end class Item; include TaxonomyTopicsModel; end end end PK|] rss/content/1.0.rbnu[require 'rss/1.0' require 'rss/content' module RSS RDF.install_ns(CONTENT_PREFIX, CONTENT_URI) class RDF class Item; include ContentModel; end end end PK|]?yrss/content/2.0.rbnu[require "rss/2.0" require "rss/content" module RSS Rss.install_ns(CONTENT_PREFIX, CONTENT_URI) class Rss class Channel class Item; include ContentModel; end end end end PK|]>sqqrss/rexmlparser.rbnu[require "rexml/document" require "rexml/streamlistener" /\A(\d+)\.(\d+)(?:\.\d+)+\z/ =~ REXML::Version if ([$1.to_i, $2.to_i] <=> [2, 5]) < 0 raise LoadError, "needs REXML 2.5 or later (#{REXML::Version})" end module RSS class REXMLParser < BaseParser class << self def listener REXMLListener end end private def _parse begin REXML::Document.parse_stream(@rss, @listener) rescue RuntimeError => e raise NotWellFormedError.new{e.message} rescue REXML::ParseException => e context = e.context line = context[0] if context raise NotWellFormedError.new(line){e.message} end end end class REXMLListener < BaseListener include REXML::StreamListener include ListenerMixin class << self def raise_for_undefined_entity? false end end def xmldecl(version, encoding, standalone) super(version, encoding, standalone == "yes") # Encoding is converted to UTF-8 when REXML parse XML. @encoding = 'UTF-8' end alias_method(:cdata, :text) end end PK|]$@ @ rss/2.0.rbnu[require "rss/0.9" module RSS class Rss class Channel [ ["generator"], ["ttl", :integer], ].each do |name, type| install_text_element(name, "", "?", name, type) end [ %w(category categories), ].each do |name, plural_name| install_have_children_element(name, "", "*", name, plural_name) end [ ["image", "?"], ["language", "?"], ].each do |name, occurs| install_model(name, "", occurs) end Category = Item::Category class Item [ ["comments", "?"], ["author", "?"], ].each do |name, occurs| install_text_element(name, "", occurs) end [ ["pubDate", '?'], ].each do |name, occurs| install_date_element(name, "", occurs, name, 'rfc822') end alias date pubDate alias date= pubDate= [ ["guid", '?'], ].each do |name, occurs| install_have_child_element(name, "", occurs) end private alias _setup_maker_element setup_maker_element def setup_maker_element(item) _setup_maker_element(item) @guid.setup_maker(item) if @guid end class Guid < Element include RSS09 [ ["isPermaLink", "", false, :boolean] ].each do |name, uri, required, type| install_get_attribute(name, uri, required, type) end content_setup def initialize(*args) if Utils.element_initialize_arguments?(args) super else super() self.isPermaLink = args[0] self.content = args[1] end end alias_method :_PermaLink?, :PermaLink? private :_PermaLink? def PermaLink? perma = _PermaLink? perma or perma.nil? end private def maker_target(item) item.guid end def setup_maker_attributes(guid) guid.isPermaLink = isPermaLink guid.content = content end end end end end RSS09::ELEMENTS.each do |name| BaseListener.install_get_text_element("", name, name) end end PK|]_shell/error.rbnu[# # shell/error.rb - # $Release Version: 0.6.0 $ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # require "e2mmap" class Shell module Error extend Exception2MessageMapper def_e2message TypeError, "wrong argument type %s (expected %s)" def_exception :DirStackEmpty, "Directory stack empty." def_exception :CantDefine, "Can't define method(%s, %s)." def_exception :CantApplyMethod, "This method(%s) does not apply to this type(%s)." def_exception :CommandNotFound, "Command not found(%s)." end end PK|]DN_::shell/version.rbnu[# # version.rb - shell version definition file # $Release Version: 0.6.0$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # class Shell @RELEASE_VERSION = "0.6.0" @LAST_UPDATE_DATE = "01/03/19" end PK|]n n shell/system-command.rbnu[# # shell/system-command.rb - # $Release Version: 0.6.0 $ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # require "shell/filter" class Shell class SystemCommand < Filter def initialize(sh, command, *opts) if t = opts.find{|opt| !opt.kind_of?(String) && opt.class} Shell.Fail Error::TypeError, t.class, "String" end super(sh) @command = command @opts = opts @input_queue = Queue.new @pid = nil sh.process_controller.add_schedule(self) end attr_reader :command alias name command def wait? @shell.process_controller.waiting_job?(self) end def active? @shell.process_controller.active_job?(self) end def input=(inp) super if active? start_export end end def start @pid, @pipe_in, @pipe_out = @shell.process_controller.sfork(self) { Dir.chdir @shell.pwd exec(@command, *@opts) } if @input start_export end start_import end def flush @pipe_out.flush if @pipe_out and !@pipe_out.closed? end def terminate begin @pipe_in.close rescue IOError end begin @pipe_out.close rescue IOError end end def kill(sig) if @pid Process.kill(sig, @pid) end end def start_import # Thread.critical = true notify "Job(%id) start imp-pipe.", @shell.debug? rs = @shell.record_separator unless rs _eop = true # Thread.critical = false th = Thread.start { Thread.critical = true begin Thread.critical = false while l = @pipe_in.gets @input_queue.push l end _eop = false rescue Errno::EPIPE _eop = false ensure if _eop notify("warn: Process finishing...", "wait for Job[%id] to finish pipe importing.", "You can use Shell#transact or Shell#check_point for more safe execution.") # Tracer.on Thread.current.run redo end Thread.exclusive do notify "job(%id}) close imp-pipe.", @shell.debug? @input_queue.push :EOF @pipe_in.close end end } end def start_export notify "job(%id) start exp-pipe.", @shell.debug? _eop = true th = Thread.start{ Thread.critical = true begin Thread.critical = false @input.each{|l| @pipe_out.print l} _eop = false rescue Errno::EPIPE _eop = false ensure if _eop notify("shell: warn: Process finishing...", "wait for Job(%id) to finish pipe exporting.", "You can use Shell#transact or Shell#check_point for more safe execution.") # Tracer.on redo end Thread.exclusive do notify "job(%id) close exp-pipe.", @shell.debug? @pipe_out.close end end } end alias super_each each def each(rs = nil) while (l = @input_queue.pop) != :EOF yield l end end # ex) # if you wish to output: # "shell: job(#{@command}:#{@pid}) close pipe-out." # then # mes: "job(%id) close pipe-out." # yorn: Boolean(@shell.debug? or @shell.verbose?) def notify(*opts, &block) Thread.exclusive do @shell.notify(*opts) {|mes| yield mes if iterator? mes.gsub!("%id", "#{@command}:##{@pid}") mes.gsub!("%name", "#{@command}") mes.gsub!("%pid", "#{@pid}") } end end end end PK|]Z>!shell/filter.rbnu[# # shell/filter.rb - # $Release Version: 0.6.0 $ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # class Shell # # Filter # A method to require # each() # class Filter include Enumerable def initialize(sh) @shell = sh # parent shell @input = nil # input filter end attr_reader :input def input=(filter) @input = filter end def each(rs = nil) rs = @shell.record_separator unless rs if @input @input.each(rs){|l| yield l} end end def < (src) case src when String cat = Cat.new(@shell, src) cat | self when IO self.input = src self else Shell.Fail Error::CantApplyMethod, "<", to.class end end def > (to) case to when String dst = @shell.open(to, "w") begin each(){|l| dst << l} ensure dst.close end when IO each(){|l| to << l} else Shell.Fail Error::CantApplyMethod, ">", to.class end self end def >> (to) begin Shell.cd(@shell.pwd).append(to, self) rescue CantApplyMethod Shell.Fail Error::CantApplyMethod, ">>", to.class end end def | (filter) filter.input = self if active? @shell.process_controller.start_job filter end filter end def + (filter) Join.new(@shell, self, filter) end def to_a ary = [] each(){|l| ary.push l} ary end def to_s str = "" each(){|l| str.concat l} str end def inspect if @shell.debug.kind_of?(Integer) && @shell.debug > 2 super else to_s end end end end PK|]Ro shell/builtin-command.rbnu[# # shell/builtin-command.rb - # $Release Version: 0.6.0 $ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # require "shell/filter" class Shell class BuiltInCommand # def expand_path(path) @shell.expand_path(path) end # # File related commands # Shell#foreach # Shell#open # Shell#unlink # Shell#test # # - # # CommandProcessor#foreach(path, rs) # path: String # rs: String - record separator # iterator # Same as: # File#foreach (when path is file) # Dir#foreach (when path is directory) # path is relative to pwd # def foreach(path = nil, *rs) path = "." unless path path = expand_path(path) if File.directory?(path) Dir.foreach(path){|fn| yield fn} else IO.foreach(path, *rs){|l| yield l} end end # # CommandProcessor#open(path, mode) # path: String # mode: String # return: File or Dir # Same as: # File#open (when path is file) # Dir#open (when path is directory) # mode has an effect only when path is a file # def open(path, mode) path = expand_path(path) if File.directory?(path) Dir.open(path) else effect_umask do File.open(path, mode) end end end # public :open # # CommandProcessor#unlink(path) # same as: # Dir#unlink (when path is directory) # File#unlink (when path is file) # def unlink(path) path = expand_path(path) if File.directory?(path) Dir.unlink(path) else IO.unlink(path) end end # # CommandProcessor#test(command, file1, file2) # CommandProcessor#[command, file1, file2] # command: char or String or Symbol # file1: String # file2: String(optional) # return: Boolean # same as: # test() (when command is char or length 1 string or symbol) # FileTest.command (others) # example: # sh[?e, "foo"] # sh[:e, "foo"] # sh["e", "foo"] # sh[:exists?, "foo"] # sh["exists?", "foo"] # alias top_level_test test def test(command, file1, file2=nil) file1 = expand_path(file1) file2 = expand_path(file2) if file2 command = command.id2name if command.kind_of?(Symbol) case command when Integer if file2 top_level_test(command, file1, file2) else top_level_test(command, file1) end when String if command.size == 1 if file2 top_level_test(command, file1, file2) else top_level_test(command, file1) end else if file2 FileTest.send(command, file1, file2) else FileTest.send(command, file1) end end end end alias [] test # # Dir related methods # # Shell#mkdir # Shell#rmdir # #-- # # CommandProcessor#mkdir(*path) # path: String # same as Dir.mkdir() # def mkdir(*path) for dir in path Dir.mkdir(expand_path(dir)) end end # # CommandProcessor#rmdir(*path) # path: String # same as Dir.rmdir() # def rmdir(*path) for dir in path Dir.rmdir(expand_path(dir)) end end # # CommandProcessor#system(command, *opts) # command: String # opts: String # return: SystemCommand # Same as system() function # example: # print sh.system("ls", "-l") # sh.system("ls", "-l") | sh.head > STDOUT # def system(command, *opts) if opts.empty? if command =~ /\*|\?|\{|\}|\[|\]|<|>|\(|\)|~|&|\||\\|\$|;|'|`|"|\n/ return SystemCommand.new(@shell, find_system_command("sh"), "-c", command) else command, *opts = command.split(/\s+/) end end SystemCommand.new(@shell, find_system_command(command), *opts) end # # ProcessCommand#rehash # clear command hash table. # def rehash @system_commands = {} end # # ProcessCommand#transact # def check_point @shell.process_controller.wait_all_jobs_execution end alias finish_all_jobs check_point def transact(&block) begin @shell.instance_eval(&block) ensure check_point end end # # internal commands # def out(dev = STDOUT, &block) dev.print transact(&block) end def echo(*strings) Echo.new(@shell, *strings) end def cat(*filenames) Cat.new(@shell, *filenames) end # def sort(*filenames) # Sort.new(self, *filenames) # end def glob(pattern) Glob.new(@shell, pattern) end def append(to, filter) case to when String AppendFile.new(@shell, to, filter) when IO AppendIO.new(@shell, to, filter) else Shell.Fail Error::CantApplyMethod, "append", to.class end end def tee(file) Tee.new(@shell, file) end def concat(*jobs) Concat.new(@shell, *jobs) end # %pwd, %cwd -> @pwd def notify(*opts, &block) Thread.exclusive do Shell.notify(*opts) {|mes| yield mes if iterator? mes.gsub!("%pwd", "#{@cwd}") mes.gsub!("%cwd", "#{@cwd}") } end end # # private functions # def effect_umask if @shell.umask Thread.critical = true save = File.umask begin yield ensure File.umask save Thread.critical = false end else yield end end private :effect_umask def find_system_command(command) return command if /^\// =~ command case path = @system_commands[command] when String if exists?(path) return path else Shell.Fail Error::CommandNotFound, command end when false Shell.Fail Error::CommandNotFound, command end for p in @shell.system_path path = join(p, command) if FileTest.exists?(path) @system_commands[command] = path return path end end @system_commands[command] = false Shell.Fail Error::CommandNotFound, command end # # CommandProcessor.def_system_command(command, path) # command: String # path: String # define 'command()' method as method. # def self.def_system_command(command, path = command) begin eval((d = %Q[def #{command}(*opts) SystemCommand.new(@shell, '#{path}', *opts) end]), nil, __FILE__, __LINE__ - 1) rescue SyntaxError Shell.notify "warn: Can't define #{command} path: #{path}." end Shell.notify "Define #{command} path: #{path}.", Shell.debug? Shell.notify("Definition of #{command}: ", d, Shell.debug.kind_of?(Integer) && Shell.debug > 1) end def self.undef_system_command(command) command = command.id2name if command.kind_of?(Symbol) remove_method(command) Shell.module_eval{remove_method(command)} Filter.module_eval{remove_method(command)} self end # define command alias # ex) # def_alias_command("ls_c", "ls", "-C", "-F") # def_alias_command("ls_c", "ls"){|*opts| ["-C", "-F", *opts]} # @alias_map = {} def self.alias_map @alias_map end def self.alias_command(ali, command, *opts, &block) ali = ali.id2name if ali.kind_of?(Symbol) command = command.id2name if command.kind_of?(Symbol) begin if iterator? @alias_map[ali.intern] = proc eval((d = %Q[def #{ali}(*opts) @shell.__send__(:#{command}, *(CommandProcessor.alias_map[:#{ali}].call *opts)) end]), nil, __FILE__, __LINE__ - 1) else args = opts.collect{|opt| '"' + opt + '"'}.join(",") eval((d = %Q[def #{ali}(*opts) @shell.__send__(:#{command}, #{args}, *opts) end]), nil, __FILE__, __LINE__ - 1) end rescue SyntaxError Shell.notify "warn: Can't alias #{ali} command: #{command}." Shell.notify("Definition of #{ali}: ", d) raise end Shell.notify "Define #{ali} command: #{command}.", Shell.debug? Shell.notify("Definition of #{ali}: ", d, Shell.debug.kind_of?(Integer) && Shell.debug > 1) self end def self.unalias_command(ali) ali = ali.id2name if ali.kind_of?(Symbol) @alias_map.delete ali.intern undef_system_command(ali) end # # CommandProcessor.def_builtin_commands(delegation_class, command_specs) # delegation_class: Class or Module # command_specs: [[command_name, [argument,...]],...] # command_name: String # arguments: String # FILENAME?? -> expand_path(filename??) # *FILENAME?? -> filename??.collect{|f|expand_path(f)}.join(", ") # define command_name(argument,...) as # delegation_class.command_name(argument,...) # def self.def_builtin_commands(delegation_class, command_specs) for meth, args in command_specs arg_str = args.collect{|arg| arg.downcase}.join(", ") call_arg_str = args.collect{ |arg| case arg when /^(FILENAME.*)$/ format("expand_path(%s)", $1.downcase) when /^(\*FILENAME.*)$/ # \*FILENAME* -> filenames.collect{|fn| expand_path(fn)}.join(", ") $1.downcase + '.collect{|fn| expand_path(fn)}' else arg end }.join(", ") d = %Q[def #{meth}(#{arg_str}) #{delegation_class}.#{meth}(#{call_arg_str}) end] Shell.notify "Define #{meth}(#{arg_str})", Shell.debug? Shell.notify("Definition of #{meth}: ", d, Shell.debug.kind_of?(Integer) && Shell.debug > 1) eval d end end # # CommandProcessor.install_system_commands(pre) # pre: String - command name prefix # defines every command which belongs in default_system_path via # CommandProcessor.command(). It doesn't define already defined # methods twice. By default, "pre_" is prefixes to each method # name. Characters that may not be used in a method name are # all converted to '_'. Definition errors are just ignored. # def self.install_system_commands(pre = "sys_") defined_meth = {} for m in Shell.methods defined_meth[m] = true end sh = Shell.new for path in Shell.default_system_path next unless sh.directory? path sh.cd path sh.foreach do |cn| if !defined_meth[pre + cn] && sh.file?(cn) && sh.executable?(cn) command = (pre + cn).gsub(/\W/, "_").sub(/^([0-9])/, '_\1') begin def_system_command(command, sh.expand_path(cn)) rescue Shell.notify "warn: Can't define #{command} path: #{cn}" end defined_meth[command] = command end end end end #---------------------------------------------------------------------- # # class initializing methods - # #---------------------------------------------------------------------- def self.add_delegate_command_to_shell(id) id = id.intern if id.kind_of?(String) name = id.id2name if Shell.method_defined?(id) Shell.notify "warn: override definnition of Shell##{name}." Shell.notify "warn: alias Shell##{name} to Shell##{name}_org.\n" Shell.module_eval "alias #{name}_org #{name}" end Shell.notify "method added: Shell##{name}.", Shell.debug? Shell.module_eval(%Q[def #{name}(*args, &block) begin @command_processor.__send__(:#{name}, *args, &block) rescue Exception $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` $@.delete_if{|s| /^\\(eval\\):/ =~ s} raise end end], __FILE__, __LINE__) if Shell::Filter.method_defined?(id) Shell.notify "warn: override definnition of Shell::Filter##{name}." Shell.notify "warn: alias Shell##{name} to Shell::Filter##{name}_org." Filter.module_eval "alias #{name}_org #{name}" end Shell.notify "method added: Shell::Filter##{name}.", Shell.debug? Filter.module_eval(%Q[def #{name}(*args, &block) begin self | @shell.__send__(:#{name}, *args, &block) rescue Exception $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` $@.delete_if{|s| /^\\(eval\\):/ =~ s} raise end end], __FILE__, __LINE__) end # # define default builtin commands # def self.install_builtin_commands # method related File. # (exclude open/foreach/unlink) normal_delegation_file_methods = [ ["atime", ["FILENAME"]], ["basename", ["fn", "*opts"]], ["chmod", ["mode", "*FILENAMES"]], ["chown", ["owner", "group", "*FILENAME"]], ["ctime", ["FILENAMES"]], ["delete", ["*FILENAMES"]], ["dirname", ["FILENAME"]], ["ftype", ["FILENAME"]], ["join", ["*items"]], ["link", ["FILENAME_O", "FILENAME_N"]], ["lstat", ["FILENAME"]], ["mtime", ["FILENAME"]], ["readlink", ["FILENAME"]], ["rename", ["FILENAME_FROM", "FILENAME_TO"]], # ["size", ["FILENAME"]], ["split", ["pathname"]], ["stat", ["FILENAME"]], ["symlink", ["FILENAME_O", "FILENAME_N"]], ["truncate", ["FILENAME", "length"]], ["utime", ["atime", "mtime", "*FILENAMES"]]] def_builtin_commands(File, normal_delegation_file_methods) alias_method :rm, :delete # method related FileTest def_builtin_commands(FileTest, FileTest.singleton_methods(false).collect{|m| [m, ["FILENAME"]]}) # method related ftools normal_delegation_ftools_methods = [ ["syscopy", ["FILENAME_FROM", "FILENAME_TO"]], ["copy", ["FILENAME_FROM", "FILENAME_TO"]], ["move", ["FILENAME_FROM", "FILENAME_TO"]], ["compare", ["FILENAME_FROM", "FILENAME_TO"]], ["safe_unlink", ["*FILENAMES"]], ["makedirs", ["*FILENAMES"]], # ["chmod", ["mode", "*FILENAMES"]], ["install", ["FILENAME_FROM", "FILENAME_TO", "mode"]], ] def_builtin_commands(File, normal_delegation_ftools_methods) alias_method :cmp, :compare alias_method :mv, :move alias_method :cp, :copy alias_method :rm_f, :safe_unlink alias_method :mkpath, :makedirs end end end PK|]iishell/process-controller.rbnu[# # shell/process-controller.rb - # $Release Version: 0.6.0 $ # $Revision: 12006 $ # $Date: 2007-03-06 18:59:25 +0900 (Tue, 06 Mar 2007) $ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) # # -- # # # require "mutex_m" require "monitor" require "sync" class Shell class ProcessController @ProcessControllers = {} @ProcessControllers.extend Mutex_m class< if $SAFE > 0 STDERR.print "-r debug.rb is not available in safe mode\n" exit 1 end require 'tracer' require 'pp' class Tracer def Tracer.trace_func(*vars) Single.trace_func(*vars) end end SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__ class DEBUGGER__ class Mutex def initialize @locker = nil @waiting = [] @locked = false; end def locked? @locked end def lock return if Thread.critical return if @locker == Thread.current while (Thread.critical = true; @locked) @waiting.push Thread.current Thread.stop end @locked = true @locker = Thread.current Thread.critical = false self end def unlock return if Thread.critical return unless @locked unless @locker == Thread.current raise RuntimeError, "unlocked by other" end Thread.critical = true t = @waiting.shift @locked = false @locker = nil Thread.critical = false t.run if t self end end MUTEX = Mutex.new class Context DEBUG_LAST_CMD = [] begin require 'readline' def readline(prompt, hist) Readline::readline(prompt, hist) end rescue LoadError def readline(prompt, hist) STDOUT.print prompt STDOUT.flush line = STDIN.gets exit unless line line.chomp! line end USE_READLINE = false end def initialize if Thread.current == Thread.main @stop_next = 1 else @stop_next = 0 end @last_file = nil @file = nil @line = nil @no_step = nil @frames = [] @finish_pos = 0 @trace = false @catch = "StandardError" @suspend_next = false end def stop_next(n=1) @stop_next = n end def set_suspend @suspend_next = true end def clear_suspend @suspend_next = false end def suspend_all DEBUGGER__.suspend end def resume_all DEBUGGER__.resume end def check_suspend return if Thread.critical while (Thread.critical = true; @suspend_next) DEBUGGER__.waiting.push Thread.current @suspend_next = false Thread.stop end Thread.critical = false end def trace? @trace end def set_trace(arg) @trace = arg end def stdout DEBUGGER__.stdout end def break_points DEBUGGER__.break_points end def display DEBUGGER__.display end def context(th) DEBUGGER__.context(th) end def set_trace_all(arg) DEBUGGER__.set_trace(arg) end def set_last_thread(th) DEBUGGER__.set_last_thread(th) end def debug_eval(str, binding) begin val = eval(str, binding) rescue StandardError, ScriptError => e at = eval("caller(1)", binding) stdout.printf "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '') for i in at stdout.printf "\tfrom %s\n", i end throw :debug_error end end def debug_silent_eval(str, binding) begin eval(str, binding) rescue StandardError, ScriptError nil end end def var_list(ary, binding) ary.sort! for v in ary stdout.printf " %s => %s\n", v, eval(v, binding).inspect end end def debug_variable_info(input, binding) case input when /^\s*g(?:lobal)?\s*$/ var_list(global_variables, binding) when /^\s*l(?:ocal)?\s*$/ var_list(eval("local_variables", binding), binding) when /^\s*i(?:nstance)?\s+/ obj = debug_eval($', binding) var_list(obj.instance_variables, obj.instance_eval{binding()}) when /^\s*c(?:onst(?:ant)?)?\s+/ obj = debug_eval($', binding) unless obj.kind_of? Module stdout.print "Should be Class/Module: ", $', "\n" else var_list(obj.constants, obj.module_eval{binding()}) end end end def debug_method_info(input, binding) case input when /^i(:?nstance)?\s+/ obj = debug_eval($', binding) len = 0 for v in obj.methods.sort len += v.size + 1 if len > 70 len = v.size + 1 stdout.print "\n" end stdout.print v, " " end stdout.print "\n" else obj = debug_eval(input, binding) unless obj.kind_of? Module stdout.print "Should be Class/Module: ", input, "\n" else len = 0 for v in obj.instance_methods(false).sort len += v.size + 1 if len > 70 len = v.size + 1 stdout.print "\n" end stdout.print v, " " end stdout.print "\n" end end end def thnum num = DEBUGGER__.instance_eval{@thread_list[Thread.current]} unless num DEBUGGER__.make_thread_list num = DEBUGGER__.instance_eval{@thread_list[Thread.current]} end num end def debug_command(file, line, id, binding) MUTEX.lock unless defined?($debugger_restart) and $debugger_restart callcc{|c| $debugger_restart = c} end set_last_thread(Thread.current) frame_pos = 0 binding_file = file binding_line = line previous_line = nil if ENV['EMACS'] stdout.printf "\032\032%s:%d:\n", binding_file, binding_line else stdout.printf "%s:%d:%s", binding_file, binding_line, line_at(binding_file, binding_line) end @frames[0] = [binding, file, line, id] display_expressions(binding) prompt = true while prompt and input = readline("(rdb:%d) "%thnum(), true) catch(:debug_error) do if input == "" next unless DEBUG_LAST_CMD[0] input = DEBUG_LAST_CMD[0] stdout.print input, "\n" else DEBUG_LAST_CMD[0] = input end case input when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/ if defined?( $2 ) if $1 == 'on' set_trace_all true else set_trace_all false end elsif defined?( $1 ) if $1 == 'on' set_trace true else set_trace false end end if trace? stdout.print "Trace on.\n" else stdout.print "Trace off.\n" end when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:]+)$/ pos = $2 if $1 klass = debug_silent_eval($1, binding) file = $1 end if pos =~ /^\d+$/ pname = pos pos = pos.to_i else pname = pos = pos.intern.id2name end break_points.push [true, 0, klass || file, pos] stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, klass || file, pname when /^\s*b(?:reak)?\s+(.+)[#.]([^.:]+)$/ pos = $2.intern.id2name klass = debug_eval($1, binding) break_points.push [true, 0, klass, pos] stdout.printf "Set breakpoint %d at %s.%s\n", break_points.size, klass, pos when /^\s*wat(?:ch)?\s+(.+)$/ exp = $1 break_points.push [true, 1, exp] stdout.printf "Set watchpoint %d:%s\n", break_points.size, exp when /^\s*b(?:reak)?$/ if break_points.find{|b| b[1] == 0} n = 1 stdout.print "Breakpoints:\n" for b in break_points if b[0] and b[1] == 0 stdout.printf " %d %s:%s\n", n, b[2], b[3] end n += 1 end end if break_points.find{|b| b[1] == 1} n = 1 stdout.print "\n" stdout.print "Watchpoints:\n" for b in break_points if b[0] and b[1] == 1 stdout.printf " %d %s\n", n, b[2] end n += 1 end end if break_points.size == 0 stdout.print "No breakpoints\n" else stdout.print "\n" end when /^\s*del(?:ete)?(?:\s+(\d+))?$/ pos = $1 unless pos input = readline("Clear all breakpoints? (y/n) ", false) if input == "y" for b in break_points b[0] = false end end else pos = pos.to_i if break_points[pos-1] break_points[pos-1][0] = false else stdout.printf "Breakpoint %d is not defined\n", pos end end when /^\s*disp(?:lay)?\s+(.+)$/ exp = $1 display.push [true, exp] stdout.printf "%d: ", display.size display_expression(exp, binding) when /^\s*disp(?:lay)?$/ display_expressions(binding) when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/ pos = $1 unless pos input = readline("Clear all expressions? (y/n) ", false) if input == "y" for d in display d[0] = false end end else pos = pos.to_i if display[pos-1] display[pos-1][0] = false else stdout.printf "Display expression %d is not defined\n", pos end end when /^\s*c(?:ont)?$/ prompt = false when /^\s*s(?:tep)?(?:\s+(\d+))?$/ if $1 lev = $1.to_i else lev = 1 end @stop_next = lev prompt = false when /^\s*n(?:ext)?(?:\s+(\d+))?$/ if $1 lev = $1.to_i else lev = 1 end @stop_next = lev @no_step = @frames.size - frame_pos prompt = false when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/ display_frames(frame_pos) when /^\s*l(?:ist)?(?:\s+(.+))?$/ if not $1 b = previous_line ? previous_line + 10 : binding_line - 5 e = b + 9 elsif $1 == '-' b = previous_line ? previous_line - 10 : binding_line - 5 e = b + 9 else b, e = $1.split(/[-,]/) if e b = b.to_i e = e.to_i else b = b.to_i - 5 e = b + 9 end end previous_line = b display_list(b, e, binding_file, binding_line) when /^\s*up(?:\s+(\d+))?$/ previous_line = nil if $1 lev = $1.to_i else lev = 1 end frame_pos += lev if frame_pos >= @frames.size frame_pos = @frames.size - 1 stdout.print "At toplevel\n" end binding, binding_file, binding_line = @frames[frame_pos] stdout.print format_frame(frame_pos) when /^\s*down(?:\s+(\d+))?$/ previous_line = nil if $1 lev = $1.to_i else lev = 1 end frame_pos -= lev if frame_pos < 0 frame_pos = 0 stdout.print "At stack bottom\n" end binding, binding_file, binding_line = @frames[frame_pos] stdout.print format_frame(frame_pos) when /^\s*fin(?:ish)?$/ if frame_pos == @frames.size stdout.print "\"finish\" not meaningful in the outermost frame.\n" else @finish_pos = @frames.size - frame_pos frame_pos = 0 prompt = false end when /^\s*cat(?:ch)?(?:\s+(.+))?$/ if $1 excn = $1 if excn == 'off' @catch = nil stdout.print "Clear catchpoint.\n" else @catch = excn stdout.printf "Set catchpoint %s.\n", @catch end else if @catch stdout.printf "Catchpoint %s.\n", @catch else stdout.print "No catchpoint.\n" end end when /^\s*q(?:uit)?$/ input = readline("Really quit? (y/n) ", false) if input == "y" exit! # exit -> exit!: No graceful way to stop threads... end when /^\s*v(?:ar)?\s+/ debug_variable_info($', binding) when /^\s*m(?:ethod)?\s+/ debug_method_info($', binding) when /^\s*th(?:read)?\s+/ if DEBUGGER__.debug_thread_info($', binding) == :cont prompt = false end when /^\s*pp\s+/ PP.pp(debug_eval($', binding), stdout) when /^\s*p\s+/ stdout.printf "%s\n", debug_eval($', binding).inspect when /^\s*r(?:estart)?$/ $debugger_restart.call when /^\s*h(?:elp)?$/ debug_print_help() else v = debug_eval(input, binding) stdout.printf "%s\n", v.inspect end end end MUTEX.unlock resume_all end def debug_print_help stdout.print < b[reak] [class.] set breakpoint to some position wat[ch] set watchpoint to some expression cat[ch] (|off) set catchpoint to an exception b[reak] list breakpoints cat[ch] show catchpoint del[ete][ nnn] delete some or all breakpoints disp[lay] add expression into display expression list undisp[lay][ nnn] delete one particular or all display expressions c[ont] run until program ends or hit breakpoint s[tep][ nnn] step (into methods) one line or till line nnn n[ext][ nnn] go over one line or till line nnn w[here] display frames f[rame] alias for where l[ist][ (-|nn-mm)] list program, - lists backwards nn-mm lists given lines up[ nn] move to higher frame down[ nn] move to lower frame fin[ish] return to outer frame tr[ace] (on|off) set trace mode of current thread tr[ace] (on|off) all set trace mode of all threads q[uit] exit from debugger v[ar] g[lobal] show global variables v[ar] l[ocal] show local variables v[ar] i[nstance] show instance variables of object v[ar] c[onst] show constants of object m[ethod] i[nstance] show methods of object m[ethod] show instance methods of class or module th[read] l[ist] list all threads th[read] c[ur[rent]] show current thread th[read] [sw[itch]] switch thread context to nnn th[read] stop stop thread nnn th[read] resume resume thread nnn p expression evaluate expression and print its value h[elp] print this help evaluate EOHELP end def display_expressions(binding) n = 1 for d in display if d[0] stdout.printf "%d: ", n display_expression(d[1], binding) end n += 1 end end def display_expression(exp, binding) stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s end def frame_set_pos(file, line) if @frames[0] @frames[0][1] = file @frames[0][2] = line end end def display_frames(pos) 0.upto(@frames.size - 1) do |n| if n == pos stdout.print "--> " else stdout.print " " end stdout.print format_frame(n) end end def format_frame(pos) bind, file, line, id = @frames[pos] sprintf "#%d %s:%s%s\n", pos + 1, file, line, (id ? ":in `#{id.id2name}'" : "") end def display_list(b, e, file, line) stdout.printf "[%d, %d] in %s\n", b, e, file if lines = SCRIPT_LINES__[file] and lines != true n = 0 b.upto(e) do |n| if n > 0 && lines[n-1] if n == line stdout.printf "=> %d %s\n", n, lines[n-1].chomp else stdout.printf " %d %s\n", n, lines[n-1].chomp end end end else stdout.printf "No sourcefile available for %s\n", file end end def line_at(file, line) lines = SCRIPT_LINES__[file] if lines return "\n" if lines == true line = lines[line-1] return "\n" unless line return line end return "\n" end def debug_funcname(id) if id.nil? "toplevel" else id.id2name end end def check_break_points(file, klass, pos, binding, id) return false if break_points.empty? n = 1 for b in break_points if b[0] # valid if b[1] == 0 # breakpoint if (b[2] == file and b[3] == pos) or (klass and b[2] == klass and b[3] == pos) stdout.printf "Breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos return true end elsif b[1] == 1 # watchpoint if debug_silent_eval(b[2], binding) stdout.printf "Watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos return true end end end n += 1 end return false end def excn_handle(file, line, id, binding) if $!.class <= SystemExit set_trace_func nil exit end if @catch and ($!.class.ancestors.find { |e| e.to_s == @catch }) stdout.printf "%s:%d: `%s' (%s)\n", file, line, $!, $!.class fs = @frames.size tb = caller(0)[-fs..-1] if tb for i in tb stdout.printf "\tfrom %s\n", i end end suspend_all debug_command(file, line, id, binding) end end def trace_func(event, file, line, id, binding, klass) Tracer.trace_func(event, file, line, id, binding, klass) if trace? context(Thread.current).check_suspend @file = file @line = line case event when 'line' frame_set_pos(file, line) if !@no_step or @frames.size == @no_step @stop_next -= 1 @stop_next = -1 if @stop_next < 0 elsif @frames.size < @no_step @stop_next = 0 # break here before leaving... else # nothing to do. skipped. end if @stop_next == 0 or check_break_points(file, nil, line, binding, id) @no_step = nil suspend_all debug_command(file, line, id, binding) end when 'call' @frames.unshift [binding, file, line, id] if check_break_points(file, klass, id.id2name, binding, id) suspend_all debug_command(file, line, id, binding) end when 'c-call' frame_set_pos(file, line) when 'class' @frames.unshift [binding, file, line, id] when 'return', 'end' if @frames.size == @finish_pos @stop_next = 1 @finish_pos = 0 end @frames.shift when 'end' @frames.shift when 'raise' excn_handle(file, line, id, binding) end @last_file = file end end trap("INT") { DEBUGGER__.interrupt } @last_thread = Thread::main @max_thread = 1 @thread_list = {Thread::main => 1} @break_points = [] @display = [] @waiting = [] @stdout = STDOUT class << DEBUGGER__ def stdout @stdout end def stdout=(s) @stdout = s end def display @display end def break_points @break_points end def waiting @waiting end def set_trace( arg ) saved_crit = Thread.critical Thread.critical = true make_thread_list for th, in @thread_list context(th).set_trace arg end Thread.critical = saved_crit arg end def set_last_thread(th) @last_thread = th end def suspend saved_crit = Thread.critical Thread.critical = true make_thread_list for th, in @thread_list next if th == Thread.current context(th).set_suspend end Thread.critical = saved_crit # Schedule other threads to suspend as soon as possible. Thread.pass unless Thread.critical end def resume saved_crit = Thread.critical Thread.critical = true make_thread_list for th, in @thread_list next if th == Thread.current context(th).clear_suspend end waiting.each do |th| th.run end waiting.clear Thread.critical = saved_crit # Schedule other threads to restart as soon as possible. Thread.pass end def context(thread=Thread.current) c = thread[:__debugger_data__] unless c thread[:__debugger_data__] = c = Context.new end c end def interrupt context(@last_thread).stop_next end def get_thread(num) th = @thread_list.index(num) unless th @stdout.print "No thread ##{num}\n" throw :debug_error end th end def thread_list(num) th = get_thread(num) if th == Thread.current @stdout.print "+" else @stdout.print " " end @stdout.printf "%d ", num @stdout.print th.inspect, "\t" file = context(th).instance_eval{@file} if file @stdout.print file,":",context(th).instance_eval{@line} end @stdout.print "\n" end def thread_list_all for th in @thread_list.values.sort thread_list(th) end end def make_thread_list hash = {} for th in Thread::list if @thread_list.key? th hash[th] = @thread_list[th] else @max_thread += 1 hash[th] = @max_thread end end @thread_list = hash end def debug_thread_info(input, binding) case input when /^l(?:ist)?/ make_thread_list thread_list_all when /^c(?:ur(?:rent)?)?$/ make_thread_list thread_list(@thread_list[Thread.current]) when /^(?:sw(?:itch)?\s+)?(\d+)/ make_thread_list th = get_thread($1.to_i) if th == Thread.current @stdout.print "It's the current thread.\n" else thread_list(@thread_list[th]) context(th).stop_next th.run return :cont end when /^stop\s+(\d+)/ make_thread_list th = get_thread($1.to_i) if th == Thread.current @stdout.print "It's the current thread.\n" elsif th.stop? @stdout.print "Already stopped.\n" else thread_list(@thread_list[th]) context(th).suspend end when /^resume\s+(\d+)/ make_thread_list th = get_thread($1.to_i) if th == Thread.current @stdout.print "It's the current thread.\n" elsif !th.stop? @stdout.print "Already running." else thread_list(@thread_list[th]) th.run end end end end stdout.printf "Debug.rb\n" stdout.printf "Emacs support available.\n\n" set_trace_func proc { |event, file, line, id, binding, klass, *rest| DEBUGGER__.context.trace_func event, file, line, id, binding, klass } end PK|][k k ostruct.rbnu[# # = ostruct.rb: OpenStruct implementation # # Author:: Yukihiro Matsumoto # Documentation:: Gavin Sinclair # # OpenStruct allows the creation of data objects with arbitrary attributes. # See OpenStruct for an example. # # # OpenStruct allows you to create data objects and set arbitrary attributes. # For example: # # require 'ostruct' # # record = OpenStruct.new # record.name = "John Smith" # record.age = 70 # record.pension = 300 # # puts record.name # -> "John Smith" # puts record.address # -> nil # # It is like a hash with a different way to access the data. In fact, it is # implemented with a hash, and you can initialize it with one. # # hash = { "country" => "Australia", :population => 20_000_000 } # data = OpenStruct.new(hash) # # p data # -> # class OpenStruct # # Create a new OpenStruct object. The optional +hash+, if given, will # generate attributes and values. For example. # # require 'ostruct' # hash = { "country" => "Australia", :population => 20_000_000 } # data = OpenStruct.new(hash) # # p data # -> # # By default, the resulting OpenStruct object will have no attributes. # def initialize(hash=nil) @table = {} if hash for k,v in hash @table[k.to_sym] = v new_ostruct_member(k) end end end # Duplicate an OpenStruct object members. def initialize_copy(orig) super @table = @table.dup end def marshal_dump @table end def marshal_load(x) @table = x @table.each_key{|key| new_ostruct_member(key)} end def modifiable if self.frozen? raise TypeError, "can't modify frozen #{self.class}", caller(2) end @table end protected :modifiable def new_ostruct_member(name) name = name.to_sym unless self.respond_to?(name) class << self; self; end.class_eval do define_method(name) { @table[name] } define_method("#{name}=") { |x| modifiable[name] = x } end end name end def method_missing(mid, *args) # :nodoc: mname = mid.id2name len = args.length if mname.chomp!('=') if len != 1 raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1) end modifiable[new_ostruct_member(mname)] = args[0] elsif len == 0 @table[mid] else raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1) end end # # Remove the named field from the object. # def delete_field(name) @table.delete name.to_sym end InspectKey = :__inspect_key__ # :nodoc: # # Returns a string containing a detailed summary of the keys and values. # def inspect str = "#<#{self.class}" ids = (Thread.current[InspectKey] ||= []) if ids.include?(object_id) return str << ' ...>' end ids << object_id begin first = true for k,v in @table str << "," unless first first = false str << " #{k}=#{v.inspect}" end return str << '>' ensure ids.pop end end alias :to_s :inspect attr_reader :table # :nodoc: protected :table # # Compare this object and +other+ for equality. # def ==(other) return false unless(other.kind_of?(OpenStruct)) return @table == other.table end end PK|]?߅optparse/version.rbnu[# OptionParser internal utility class << OptionParser def show_version(*pkg) progname = ARGV.options.program_name result = false show = proc do |klass, cname, version| str = "#{progname}" unless klass == ::Object and cname == :VERSION version = version.join(".") if Array === version str << ": #{klass}" unless klass == Object str << " version #{version}" end [:Release, :RELEASE].find do |rel| if klass.const_defined?(rel) str << " (#{klass.const_get(rel)})" end end puts str result = true end if pkg.size == 1 and pkg[0] == "all" self.search_const(::Object, /\AV(?:ERSION|ersion)\z/) do |klass, cname, version| unless cname[1] == ?e and klass.const_defined?(:Version) show.call(klass, cname.intern, version) end end else pkg.each do |pkg| begin pkg = pkg.split(/::|\//).inject(::Object) {|m, c| m.const_get(c)} v = case when pkg.const_defined?(:Version) pkg.const_get(n = :Version) when pkg.const_defined?(:VERSION) pkg.const_get(n = :VERSION) else n = nil "unknown" end show.call(pkg, n, v) rescue NameError end end end result end def each_const(path, klass = ::Object) path.split(/::|\//).inject(klass) do |klass, name| raise NameError, path unless Module === klass klass.constants.grep(/#{name}/i) do |c| klass.const_defined?(c) or next c = klass.const_get(c) end end end def search_const(klass, name) klasses = [klass] while klass = klasses.shift klass.constants.each do |cname| klass.const_defined?(cname) or next const = klass.const_get(cname) yield klass, cname, const if name === cname klasses << const if Module === const and const != ::Object end end end end PK|]7&optparse/time.rbnu[require 'optparse' require 'time' OptionParser.accept(Time) do |s,| begin (Time.httpdate(s) rescue Time.parse(s)) if s rescue raise OptionParser::InvalidArgument, s end end PK|][hzddoptparse/uri.rbnu[# -*- ruby -*- require 'optparse' require 'uri' OptionParser.accept(URI) {|s,| URI.parse(s) if s} PK|];EEoptparse/date.rbnu[require 'optparse' require 'date' OptionParser.accept(DateTime) do |s,| begin DateTime.parse(s) if s rescue ArgumentError raise OptionParser::InvalidArgument, s end end OptionParser.accept(Date) do |s,| begin Date.parse(s) if s rescue ArgumentError raise OptionParser::InvalidArgument, s end end PK|]Zvvyyoptparse/shellwords.rbnu[# -*- ruby -*- require 'shellwords' require 'optparse' OptionParser.accept(Shellwords) {|s,| Shellwords.shellwords(s)} PK|]}y4 tracer.rbnu[# # tracer.rb - # $Release Version: 0.2$ # $Revision: 1.8 $ # $Date: 1998/05/19 03:42:49 $ # by Keiju ISHITSUKA(Nippon Rational Inc.) # # -- # # # # # tracer main class # class Tracer @RCS_ID='-$Id: tracer.rb,v 1.8 1998/05/19 03:42:49 keiju Exp keiju $-' @stdout = STDOUT @verbose = false class << self attr :verbose, true alias verbose? verbose attr :stdout, true end EVENT_SYMBOL = { "line" => "-", "call" => ">", "return" => "<", "class" => "C", "end" => "E", "c-call" => ">", "c-return" => "<", } def initialize @threads = Hash.new if defined? Thread.main @threads[Thread.main.object_id] = 0 else @threads[Thread.current.object_id] = 0 end @get_line_procs = {} @filters = [] end def stdout Tracer.stdout end def on if block_given? on begin yield ensure off end else set_trace_func method(:trace_func).to_proc stdout.print "Trace on\n" if Tracer.verbose? end end def off set_trace_func nil stdout.print "Trace off\n" if Tracer.verbose? end def add_filter(p = proc) @filters.push p end def set_get_line_procs(file, p = proc) @get_line_procs[file] = p end def get_line(file, line) if p = @get_line_procs[file] return p.call(line) end unless list = SCRIPT_LINES__[file] begin f = open(file) begin SCRIPT_LINES__[file] = list = f.readlines ensure f.close end rescue SCRIPT_LINES__[file] = list = [] end end if l = list[line - 1] l else "-\n" end end def get_thread_no if no = @threads[Thread.current.object_id] no else @threads[Thread.current.object_id] = @threads.size end end def trace_func(event, file, line, id, binding, klass, *) return if file == __FILE__ for p in @filters return unless p.call event, file, line, id, binding, klass end saved_crit = Thread.critical Thread.critical = true stdout.printf("#%d:%s:%d:%s:%s: %s", get_thread_no, file, line, klass || '', EVENT_SYMBOL[event], get_line(file, line)) Thread.critical = saved_crit end Single = new def Tracer.on if block_given? Single.on{yield} else Single.on end end def Tracer.off Single.off end def Tracer.set_get_line_procs(file_name, p = proc) Single.set_get_line_procs(file_name, p) end def Tracer.add_filter(p = proc) Single.add_filter(p) end end SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__ if $0 == __FILE__ # direct call $0 = ARGV[0] ARGV.shift Tracer.on require $0 elsif caller(0).size == 1 Tracer.on end PK|]܃t3030 rational.rbnu[# # rational.rb - # $Release Version: 0.5 $ # $Revision: 1.7 $ # $Date: 1999/08/24 12:49:28 $ # by Keiju ISHITSUKA(SHL Japan Inc.) # # Documentation by Kevin Jackson and Gavin Sinclair. # # When you require 'rational', all interactions between numbers # potentially return a rational result. For example: # # 1.quo(2) # -> 0.5 # require 'rational' # 1.quo(2) # -> Rational(1,2) # # See Rational for full documentation. # # # Creates a Rational number (i.e. a fraction). +a+ and +b+ should be Integers: # # Rational(1,3) # -> 1/3 # # Note: trying to construct a Rational with floating point or real values # produces errors: # # Rational(1.1, 2.3) # -> NoMethodError # def Rational(a, b = 1) if a.kind_of?(Rational) && b == 1 a else Rational.reduce(a, b) end end # # Rational implements a rational class for numbers. # # A rational number is a number that can be expressed as a fraction p/q # where p and q are integers and q != 0. A rational number p/q is said to have # numerator p and denominator q. Numbers that are not rational are called # irrational numbers. (http://mathworld.wolfram.com/RationalNumber.html) # # To create a Rational Number: # Rational(a,b) # -> a/b # Rational.new!(a,b) # -> a/b # # Examples: # Rational(5,6) # -> 5/6 # Rational(5) # -> 5/1 # # Rational numbers are reduced to their lowest terms: # Rational(6,10) # -> 3/5 # # But not if you use the unusual method "new!": # Rational.new!(6,10) # -> 6/10 # # Division by zero is obviously not allowed: # Rational(3,0) # -> ZeroDivisionError # class Rational < Numeric @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-' # # Reduces the given numerator and denominator to their lowest terms. Use # Rational() instead. # def Rational.reduce(num, den = 1) raise ZeroDivisionError, "denominator is zero" if den == 0 if den < 0 num = -num den = -den end gcd = num.gcd(den) num = num.div(gcd) den = den.div(gcd) if den == 1 && defined?(Unify) num else new!(num, den) end end # # Implements the constructor. This method does not reduce to lowest terms or # check for division by zero. Therefore #Rational() should be preferred in # normal use. # def Rational.new!(num, den = 1) new(num, den) end private_class_method :new # # This method is actually private. # def initialize(num, den) if den < 0 num = -num den = -den end if num.kind_of?(Integer) and den.kind_of?(Integer) @numerator = num @denominator = den else @numerator = num.to_i @denominator = den.to_i end end # # Returns the addition of this value and +a+. # # Examples: # r = Rational(3,4) # -> Rational(3,4) # r + 1 # -> Rational(7,4) # r + 0.5 # -> 1.25 # def + (a) if a.kind_of?(Rational) num = @numerator * a.denominator num_a = a.numerator * @denominator Rational(num + num_a, @denominator * a.denominator) elsif a.kind_of?(Integer) self + Rational.new!(a, 1) elsif a.kind_of?(Float) Float(self) + a else x, y = a.coerce(self) x + y end end # # Returns the difference of this value and +a+. # subtracted. # # Examples: # r = Rational(3,4) # -> Rational(3,4) # r - 1 # -> Rational(-1,4) # r - 0.5 # -> 0.25 # def - (a) if a.kind_of?(Rational) num = @numerator * a.denominator num_a = a.numerator * @denominator Rational(num - num_a, @denominator*a.denominator) elsif a.kind_of?(Integer) self - Rational.new!(a, 1) elsif a.kind_of?(Float) Float(self) - a else x, y = a.coerce(self) x - y end end # # Returns the product of this value and +a+. # # Examples: # r = Rational(3,4) # -> Rational(3,4) # r * 2 # -> Rational(3,2) # r * 4 # -> Rational(3,1) # r * 0.5 # -> 0.375 # r * Rational(1,2) # -> Rational(3,8) # def * (a) if a.kind_of?(Rational) num = @numerator * a.numerator den = @denominator * a.denominator Rational(num, den) elsif a.kind_of?(Integer) self * Rational.new!(a, 1) elsif a.kind_of?(Float) Float(self) * a else x, y = a.coerce(self) x * y end end # # Returns the quotient of this value and +a+. # r = Rational(3,4) # -> Rational(3,4) # r / 2 # -> Rational(3,8) # r / 2.0 # -> 0.375 # r / Rational(1,2) # -> Rational(3,2) # def / (a) if a.kind_of?(Rational) num = @numerator * a.denominator den = @denominator * a.numerator Rational(num, den) elsif a.kind_of?(Integer) raise ZeroDivisionError, "division by zero" if a == 0 self / Rational.new!(a, 1) elsif a.kind_of?(Float) Float(self) / a else x, y = a.coerce(self) x / y end end # # Returns this value raised to the given power. # # Examples: # r = Rational(3,4) # -> Rational(3,4) # r ** 2 # -> Rational(9,16) # r ** 2.0 # -> 0.5625 # r ** Rational(1,2) # -> 0.866025403784439 # def ** (other) if other.kind_of?(Rational) Float(self) ** other elsif other.kind_of?(Integer) if other > 0 num = @numerator ** other den = @denominator ** other elsif other < 0 num = @denominator ** -other den = @numerator ** -other elsif other == 0 num = 1 den = 1 end Rational.new!(num, den) elsif other.kind_of?(Float) Float(self) ** other else x, y = other.coerce(self) x ** y end end def div(other) (self / other).floor end # # Returns the remainder when this value is divided by +other+. # # Examples: # r = Rational(7,4) # -> Rational(7,4) # r % Rational(1,2) # -> Rational(1,4) # r % 1 # -> Rational(3,4) # r % Rational(1,7) # -> Rational(1,28) # r % 0.26 # -> 0.19 # def % (other) value = (self / other).floor return self - other * value end # # Returns the quotient _and_ remainder. # # Examples: # r = Rational(7,4) # -> Rational(7,4) # r.divmod Rational(1,2) # -> [3, Rational(1,4)] # def divmod(other) value = (self / other).floor return value, self - other * value end # # Returns the absolute value. # def abs if @numerator > 0 self else Rational.new!(-@numerator, @denominator) end end # # Returns +true+ iff this value is numerically equal to +other+. # # But beware: # Rational(1,2) == Rational(4,8) # -> true # Rational(1,2) == Rational.new!(4,8) # -> false # # Don't use Rational.new! # def == (other) if other.kind_of?(Rational) @numerator == other.numerator and @denominator == other.denominator elsif other.kind_of?(Integer) self == Rational.new!(other, 1) elsif other.kind_of?(Float) Float(self) == other else other == self end end # # Standard comparison operator. # def <=> (other) if other.kind_of?(Rational) num = @numerator * other.denominator num_a = other.numerator * @denominator v = num - num_a if v > 0 return 1 elsif v < 0 return -1 else return 0 end elsif other.kind_of?(Integer) return self <=> Rational.new!(other, 1) elsif other.kind_of?(Float) return Float(self) <=> other elsif defined? other.coerce x, y = other.coerce(self) return x <=> y else return nil end end def coerce(other) if other.kind_of?(Float) return other, self.to_f elsif other.kind_of?(Integer) return Rational.new!(other, 1), self else super end end # # Converts the rational to an Integer. Not the _nearest_ integer, the # truncated integer. Study the following example carefully: # Rational(+7,4).to_i # -> 1 # Rational(-7,4).to_i # -> -1 # (-1.75).to_i # -> -1 # # In other words: # Rational(-7,4) == -1.75 # -> true # Rational(-7,4).to_i == (-1.75).to_i # -> true # def floor() @numerator.div(@denominator) end def ceil() -((-@numerator).div(@denominator)) end def truncate() if @numerator < 0 return -((-@numerator).div(@denominator)) end @numerator.div(@denominator) end alias_method :to_i, :truncate def round() if @numerator < 0 num = -@numerator num = num * 2 + @denominator den = @denominator * 2 -(num.div(den)) else num = @numerator * 2 + @denominator den = @denominator * 2 num.div(den) end end # # Converts the rational to a Float. # def to_f @numerator.fdiv(@denominator) end # # Returns a string representation of the rational number. # # Example: # Rational(3,4).to_s # "3/4" # Rational(8).to_s # "8" # def to_s if @denominator == 1 @numerator.to_s else @numerator.to_s+"/"+@denominator.to_s end end # # Returns +self+. # def to_r self end # # Returns a reconstructable string representation: # # Rational(5,8).inspect # -> "Rational(5, 8)" # def inspect sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect) end # # Returns a hash code for the object. # def hash @numerator.hash ^ @denominator.hash end attr :numerator attr :denominator private :initialize end class Integer # # In an integer, the value _is_ the numerator of its rational equivalent. # Therefore, this method returns +self+. # def numerator self end # # In an integer, the denominator is 1. Therefore, this method returns 1. # def denominator 1 end # # Returns a Rational representation of this integer. # def to_r Rational(self, 1) end # # Returns the greatest common denominator of the two numbers (+self+ # and +n+). # # Examples: # 72.gcd 168 # -> 24 # 19.gcd 36 # -> 1 # # The result is positive, no matter the sign of the arguments. # def gcd(other) min = self.abs max = other.abs while min > 0 tmp = min min = max % min max = tmp end max end # # Returns the lowest common multiple (LCM) of the two arguments # (+self+ and +other+). # # Examples: # 6.lcm 7 # -> 42 # 6.lcm 9 # -> 18 # def lcm(other) if self.zero? or other.zero? 0 else (self.div(self.gcd(other)) * other).abs end end # # Returns the GCD _and_ the LCM (see #gcd and #lcm) of the two arguments # (+self+ and +other+). This is more efficient than calculating them # separately. # # Example: # 6.gcdlcm 9 # -> [3, 18] # def gcdlcm(other) gcd = self.gcd(other) if self.zero? or other.zero? [gcd, 0] else [gcd, (self.div(gcd) * other).abs] end end end class Fixnum remove_method :quo # If Rational is defined, returns a Rational number instead of a Float. def quo(other) Rational.new!(self, 1) / other end alias rdiv quo # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0). def rpower (other) if other >= 0 self.power!(other) else Rational.new!(self, 1)**other end end end class Bignum remove_method :quo # If Rational is defined, returns a Rational number instead of a Float. def quo(other) Rational.new!(self, 1) / other end alias rdiv quo # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0). def rpower (other) if other >= 0 self.power!(other) else Rational.new!(self, 1)**other end end end unless defined? 1.power! class Fixnum alias power! ** alias ** rpower end class Bignum alias power! ** alias ** rpower end end PK|]zn@ ??rinda/rinda.rbnu[require 'drb/drb' require 'thread' ## # A module to implement the Linda distributed computing paradigm in Ruby. # # Rinda is part of DRb (dRuby). # # == Example(s) # # See the sample/drb/ directory in the Ruby distribution, from 1.8.2 onwards. # #-- # TODO # == Introduction to Linda/rinda? # # == Why is this library separate from DRb? module Rinda ## # Rinda error base class class RindaError < RuntimeError; end ## # Raised when a hash-based tuple has an invalid key. class InvalidHashTupleKey < RindaError; end ## # Raised when trying to use a canceled tuple. class RequestCanceledError < ThreadError; end ## # Raised when trying to use an expired tuple. class RequestExpiredError < ThreadError; end ## # A tuple is the elementary object in Rinda programming. # Tuples may be matched against templates if the tuple and # the template are the same size. class Tuple ## # Creates a new Tuple from +ary_or_hash+ which must be an Array or Hash. def initialize(ary_or_hash) if hash?(ary_or_hash) init_with_hash(ary_or_hash) else init_with_ary(ary_or_hash) end end ## # The number of elements in the tuple. def size @tuple.size end ## # Accessor method for elements of the tuple. def [](k) @tuple[k] end ## # Fetches item +k+ from the tuple. def fetch(k) @tuple.fetch(k) end ## # Iterate through the tuple, yielding the index or key, and the # value, thus ensuring arrays are iterated similarly to hashes. def each # FIXME if Hash === @tuple @tuple.each { |k, v| yield(k, v) } else @tuple.each_with_index { |v, k| yield(k, v) } end end ## # Return the tuple itself def value @tuple end private def hash?(ary_or_hash) ary_or_hash.respond_to?(:keys) end ## # Munges +ary+ into a valid Tuple. def init_with_ary(ary) @tuple = Array.new(ary.size) @tuple.size.times do |i| @tuple[i] = ary[i] end end ## # Ensures +hash+ is a valid Tuple. def init_with_hash(hash) @tuple = Hash.new hash.each do |k, v| raise InvalidHashTupleKey unless String === k @tuple[k] = v end end end ## # Templates are used to match tuples in Rinda. class Template < Tuple ## # Matches this template against +tuple+. The +tuple+ must be the same # size as the template. An element with a +nil+ value in a template acts # as a wildcard, matching any value in the corresponding position in the # tuple. Elements of the template match the +tuple+ if the are #== or # #===. # # Template.new([:foo, 5]).match Tuple.new([:foo, 5]) # => true # Template.new([:foo, nil]).match Tuple.new([:foo, 5]) # => true # Template.new([String]).match Tuple.new(['hello']) # => true # # Template.new([:foo]).match Tuple.new([:foo, 5]) # => false # Template.new([:foo, 6]).match Tuple.new([:foo, 5]) # => false # Template.new([:foo, nil]).match Tuple.new([:foo]) # => false # Template.new([:foo, 6]).match Tuple.new([:foo]) # => false def match(tuple) return false unless tuple.respond_to?(:size) return false unless tuple.respond_to?(:fetch) return false unless self.size == tuple.size each do |k, v| begin it = tuple.fetch(k) rescue return false end next if v.nil? next if v == it next if v === it return false end return true end ## # Alias for #match. def ===(tuple) match(tuple) end end ## # Documentation? class DRbObjectTemplate ## # Creates a new DRbObjectTemplate that will match against +uri+ and +ref+. def initialize(uri=nil, ref=nil) @drb_uri = uri @drb_ref = ref end ## # This DRbObjectTemplate matches +ro+ if the remote object's drburi and # drbref are the same. +nil+ is used as a wildcard. def ===(ro) return true if super(ro) unless @drb_uri.nil? return false unless (@drb_uri === ro.__drburi rescue false) end unless @drb_ref.nil? return false unless (@drb_ref === ro.__drbref rescue false) end true end end ## # TupleSpaceProxy allows a remote Tuplespace to appear as local. class TupleSpaceProxy ## # Creates a new TupleSpaceProxy to wrap +ts+. def initialize(ts) @ts = ts end ## # Adds +tuple+ to the proxied TupleSpace. See TupleSpace#write. def write(tuple, sec=nil) @ts.write(tuple, sec) end ## # Takes +tuple+ from the proxied TupleSpace. See TupleSpace#take. def take(tuple, sec=nil, &block) port = [] @ts.move(DRbObject.new(port), tuple, sec, &block) port[0] end ## # Reads +tuple+ from the proxied TupleSpace. See TupleSpace#read. def read(tuple, sec=nil, &block) @ts.read(tuple, sec, &block) end ## # Reads all tuples matching +tuple+ from the proxied TupleSpace. See # TupleSpace#read_all. def read_all(tuple) @ts.read_all(tuple) end ## # Registers for notifications of event +ev+ on the proxied TupleSpace. # See TupleSpace#notify def notify(ev, tuple, sec=nil) @ts.notify(ev, tuple, sec) end end ## # An SimpleRenewer allows a TupleSpace to check if a TupleEntry is still # alive. class SimpleRenewer include DRbUndumped ## # Creates a new SimpleRenewer that keeps an object alive for another +sec+ # seconds. def initialize(sec=180) @sec = sec end ## # Called by the TupleSpace to check if the object is still alive. def renew @sec end end end PK|]гJ77rinda/tuplespace.rbnu[require 'monitor' require 'thread' require 'drb/drb' require 'rinda/rinda' require 'enumerator' require 'forwardable' module Rinda ## # A TupleEntry is a Tuple (i.e. a possible entry in some Tuplespace) # together with expiry and cancellation data. class TupleEntry include DRbUndumped attr_accessor :expires ## # Creates a TupleEntry based on +ary+ with an optional renewer or expiry # time +sec+. # # A renewer must implement the +renew+ method which returns a Numeric, # nil, or true to indicate when the tuple has expired. def initialize(ary, sec=nil) @cancel = false @expires = nil @tuple = make_tuple(ary) @renewer = nil renew(sec) end ## # Marks this TupleEntry as canceled. def cancel @cancel = true end ## # A TupleEntry is dead when it is canceled or expired. def alive? !canceled? && !expired? end ## # Return the object which makes up the tuple itself: the Array # or Hash. def value; @tuple.value; end ## # Returns the canceled status. def canceled?; @cancel; end ## # Has this tuple expired? (true/false). # # A tuple has expired when its expiry timer based on the +sec+ argument to # #initialize runs out. def expired? return true unless @expires return false if @expires > Time.now return true if @renewer.nil? renew(@renewer) return true unless @expires return @expires < Time.now end ## # Reset the expiry time according to +sec_or_renewer+. # # +nil+:: it is set to expire in the far future. # +false+:: it has expired. # Numeric:: it will expire in that many seconds. # # Otherwise the argument refers to some kind of renewer object # which will reset its expiry time. def renew(sec_or_renewer) sec, @renewer = get_renewer(sec_or_renewer) @expires = make_expires(sec) end ## # Returns an expiry Time based on +sec+ which can be one of: # Numeric:: +sec+ seconds into the future # +true+:: the expiry time is the start of 1970 (i.e. expired) # +nil+:: it is Tue Jan 19 03:14:07 GMT Standard Time 2038 (i.e. when # UNIX clocks will die) def make_expires(sec=nil) case sec when Numeric Time.now + sec when true Time.at(1) when nil Time.at(2**31-1) end end ## # Retrieves +key+ from the tuple. def [](key) @tuple[key] end ## # Fetches +key+ from the tuple. def fetch(key) @tuple.fetch(key) end ## # The size of the tuple. def size @tuple.size end ## # Creates a Rinda::Tuple for +ary+. def make_tuple(ary) Rinda::Tuple.new(ary) end private ## # Returns a valid argument to make_expires and the renewer or nil. # # Given +true+, +nil+, or Numeric, returns that value and +nil+ (no actual # renewer). Otherwise it returns an expiry value from calling +it.renew+ # and the renewer. def get_renewer(it) case it when Numeric, true, nil return it, nil else begin return it.renew, it rescue Exception return it, nil end end end end ## # A TemplateEntry is a Template together with expiry and cancellation data. class TemplateEntry < TupleEntry ## # Matches this TemplateEntry against +tuple+. See Template#match for # details on how a Template matches a Tuple. def match(tuple) @tuple.match(tuple) end alias === match def make_tuple(ary) # :nodoc: Rinda::Template.new(ary) end end ## # Documentation? class WaitTemplateEntry < TemplateEntry attr_reader :found def initialize(place, ary, expires=nil) super(ary, expires) @place = place @cond = place.new_cond @found = nil end def cancel super signal end def wait @cond.wait end def read(tuple) @found = tuple signal end def signal @place.synchronize do @cond.signal end end end ## # A NotifyTemplateEntry is returned by TupleSpace#notify and is notified of # TupleSpace changes. You may receive either your subscribed event or the # 'close' event when iterating over notifications. # # See TupleSpace#notify_event for valid notification types. # # == Example # # ts = Rinda::TupleSpace.new # observer = ts.notify 'write', [nil] # # Thread.start do # observer.each { |t| p t } # end # # 3.times { |i| ts.write [i] } # # Outputs: # # ['write', [0]] # ['write', [1]] # ['write', [2]] class NotifyTemplateEntry < TemplateEntry ## # Creates a new NotifyTemplateEntry that watches +place+ for +event+s that # match +tuple+. def initialize(place, event, tuple, expires=nil) ary = [event, Rinda::Template.new(tuple)] super(ary, expires) @queue = Queue.new @done = false end ## # Called by TupleSpace to notify this NotifyTemplateEntry of a new event. def notify(ev) @queue.push(ev) end ## # Retrieves a notification. Raises RequestExpiredError when this # NotifyTemplateEntry expires. def pop raise RequestExpiredError if @done it = @queue.pop @done = true if it[0] == 'close' return it end ## # Yields event/tuple pairs until this NotifyTemplateEntry expires. def each # :yields: event, tuple while !@done it = pop yield(it) end rescue ensure cancel end end ## # TupleBag is an unordered collection of tuples. It is the basis # of Tuplespace. class TupleBag class TupleBin extend Forwardable def_delegators '@bin', :find_all, :delete_if, :each, :empty? def initialize @bin = [] end def add(tuple) @bin.push(tuple) end def delete(tuple) idx = @bin.rindex(tuple) @bin.delete_at(idx) if idx end def find(&blk) @bin.reverse_each do |x| return x if yield(x) end nil end end def initialize # :nodoc: @hash = {} @enum = Enumerable::Enumerator.new(self, :each_entry) end ## # +true+ if the TupleBag to see if it has any expired entries. def has_expires? @enum.find do |tuple| tuple.expires end end ## # Add +tuple+ to the TupleBag. def push(tuple) key = bin_key(tuple) @hash[key] ||= TupleBin.new @hash[key].add(tuple) end ## # Removes +tuple+ from the TupleBag. def delete(tuple) key = bin_key(tuple) bin = @hash[key] return nil unless bin bin.delete(tuple) @hash.delete(key) if bin.empty? tuple end ## # Finds all live tuples that match +template+. def find_all(template) bin_for_find(template).find_all do |tuple| tuple.alive? && template.match(tuple) end end ## # Finds a live tuple that matches +template+. def find(template) bin_for_find(template).find do |tuple| tuple.alive? && template.match(tuple) end end ## # Finds all tuples in the TupleBag which when treated as templates, match # +tuple+ and are alive. def find_all_template(tuple) @enum.find_all do |template| template.alive? && template.match(tuple) end end ## # Delete tuples which dead tuples from the TupleBag, returning the deleted # tuples. def delete_unless_alive deleted = [] @hash.each do |key, bin| bin.delete_if do |tuple| if tuple.alive? false else deleted.push(tuple) true end end end deleted end private def each_entry(&blk) @hash.each do |k, v| v.each(&blk) end end def bin_key(tuple) head = tuple[0] if head.class == Symbol return head else false end end def bin_for_find(template) key = bin_key(template) key ? @hash.fetch(key, []) : @enum end end ## # The Tuplespace manages access to the tuples it contains, # ensuring mutual exclusion requirements are met. # # The +sec+ option for the write, take, move, read and notify methods may # either be a number of seconds or a Renewer object. class TupleSpace include DRbUndumped include MonitorMixin ## # Creates a new TupleSpace. +period+ is used to control how often to look # for dead tuples after modifications to the TupleSpace. # # If no dead tuples are found +period+ seconds after the last # modification, the TupleSpace will stop looking for dead tuples. def initialize(period=60) super() @bag = TupleBag.new @read_waiter = TupleBag.new @take_waiter = TupleBag.new @notify_waiter = TupleBag.new @period = period @keeper = nil end ## # Adds +tuple+ def write(tuple, sec=nil) entry = create_entry(tuple, sec) synchronize do if entry.expired? @read_waiter.find_all_template(entry).each do |template| template.read(tuple) end notify_event('write', entry.value) notify_event('delete', entry.value) else @bag.push(entry) start_keeper if entry.expires @read_waiter.find_all_template(entry).each do |template| template.read(tuple) end @take_waiter.find_all_template(entry).each do |template| template.signal end notify_event('write', entry.value) end end entry end ## # Removes +tuple+ def take(tuple, sec=nil, &block) move(nil, tuple, sec, &block) end ## # Moves +tuple+ to +port+. def move(port, tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? synchronize do entry = @bag.find(template) if entry port.push(entry.value) if port @bag.delete(entry) notify_event('take', entry.value) return entry.value end raise RequestExpiredError if template.expired? begin @take_waiter.push(template) start_keeper if template.expires while true raise RequestCanceledError if template.canceled? raise RequestExpiredError if template.expired? entry = @bag.find(template) if entry port.push(entry.value) if port @bag.delete(entry) notify_event('take', entry.value) return entry.value end template.wait end ensure @take_waiter.delete(template) end end end ## # Reads +tuple+, but does not remove it. def read(tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? synchronize do entry = @bag.find(template) return entry.value if entry raise RequestExpiredError if template.expired? begin @read_waiter.push(template) start_keeper if template.expires template.wait raise RequestCanceledError if template.canceled? raise RequestExpiredError if template.expired? return template.found ensure @read_waiter.delete(template) end end end ## # Returns all tuples matching +tuple+. Does not remove the found tuples. def read_all(tuple) template = WaitTemplateEntry.new(self, tuple, nil) synchronize do entry = @bag.find_all(template) entry.collect do |e| e.value end end end ## # Registers for notifications of +event+. Returns a NotifyTemplateEntry. # See NotifyTemplateEntry for examples of how to listen for notifications. # # +event+ can be: # 'write':: A tuple was added # 'take':: A tuple was taken or moved # 'delete':: A tuple was lost after being overwritten or expiring # # The TupleSpace will also notify you of the 'close' event when the # NotifyTemplateEntry has expired. def notify(event, tuple, sec=nil) template = NotifyTemplateEntry.new(self, event, tuple, sec) synchronize do @notify_waiter.push(template) end template end private def create_entry(tuple, sec) TupleEntry.new(tuple, sec) end ## # Removes dead tuples. def keep_clean synchronize do @read_waiter.delete_unless_alive.each do |e| e.signal end @take_waiter.delete_unless_alive.each do |e| e.signal end @notify_waiter.delete_unless_alive.each do |e| e.notify(['close']) end @bag.delete_unless_alive.each do |e| notify_event('delete', e.value) end end end ## # Notifies all registered listeners for +event+ of a status change of # +tuple+. def notify_event(event, tuple) ev = [event, tuple] @notify_waiter.find_all_template(ev).each do |template| template.notify(ev) end end ## # Creates a thread that scans the tuplespace for expired tuples. def start_keeper return if @keeper && @keeper.alive? @keeper = Thread.new do while true sleep(@period) synchronize do break unless need_keeper? keep_clean end end end end ## # Checks the tuplespace to see if it needs cleaning. def need_keeper? return true if @bag.has_expires? return true if @read_waiter.has_expires? return true if @take_waiter.has_expires? return true if @notify_waiter.has_expires? end end end PK|]88 rinda/ring.rbnu[# # Note: Rinda::Ring API is unstable. # require 'drb/drb' require 'rinda/rinda' require 'thread' module Rinda ## # The default port Ring discovery will use. Ring_PORT = 7647 ## # A RingServer allows a Rinda::TupleSpace to be located via UDP broadcasts. # Service location uses the following steps: # # 1. A RingServer begins listening on the broadcast UDP address. # 2. A RingFinger sends a UDP packet containing the DRb URI where it will # listen for a reply. # 3. The RingServer receives the UDP packet and connects back to the # provided DRb URI with the DRb service. class RingServer include DRbUndumped ## # Advertises +ts+ on the UDP broadcast address at +port+. def initialize(ts, port=Ring_PORT) @ts = ts @soc = UDPSocket.open @soc.bind('', port) @w_service = write_service @r_service = reply_service end ## # Creates a thread that picks up UDP packets and passes them to do_write # for decoding. def write_service Thread.new do loop do msg = @soc.recv(1024) do_write(msg) end end end ## # Extracts the response URI from +msg+ and adds it to TupleSpace where it # will be picked up by +reply_service+ for notification. def do_write(msg) Thread.new do begin tuple, sec = Marshal.load(msg) @ts.write(tuple, sec) rescue end end end ## # Creates a thread that notifies waiting clients from the TupleSpace. def reply_service Thread.new do loop do do_reply end end end ## # Pulls lookup tuples out of the TupleSpace and sends their DRb object the # address of the local TupleSpace. def do_reply tuple = @ts.take([:lookup_ring, nil]) Thread.new { tuple[1].call(@ts) rescue nil} rescue end end ## # RingFinger is used by RingServer clients to discover the RingServer's # TupleSpace. Typically, all a client needs to do is call # RingFinger.primary to retrieve the remote TupleSpace, which it can then # begin using. class RingFinger @@broadcast_list = ['', 'localhost'] @@finger = nil ## # Creates a singleton RingFinger and looks for a RingServer. Returns the # created RingFinger. def self.finger unless @@finger @@finger = self.new @@finger.lookup_ring_any end @@finger end ## # Returns the first advertised TupleSpace. def self.primary finger.primary end ## # Contains all discovered TupleSpaces except for the primary. def self.to_a finger.to_a end ## # The list of addresses where RingFinger will send query packets. attr_accessor :broadcast_list ## # The port that RingFinger will send query packets to. attr_accessor :port ## # Contain the first advertised TupleSpace after lookup_ring_any is called. attr_accessor :primary ## # Creates a new RingFinger that will look for RingServers at +port+ on # the addresses in +broadcast_list+. def initialize(broadcast_list=@@broadcast_list, port=Ring_PORT) @broadcast_list = broadcast_list || ['localhost'] @port = port @primary = nil @rings = [] end ## # Contains all discovered TupleSpaces except for the primary. def to_a @rings end ## # Iterates over all discovered TupleSpaces starting with the primary. def each lookup_ring_any unless @primary return unless @primary yield(@primary) @rings.each { |x| yield(x) } end ## # Looks up RingServers waiting +timeout+ seconds. RingServers will be # given +block+ as a callback, which will be called with the remote # TupleSpace. def lookup_ring(timeout=5, &block) return lookup_ring_any(timeout) unless block_given? msg = Marshal.dump([[:lookup_ring, DRbObject.new(block)], timeout]) @broadcast_list.each do |it| soc = UDPSocket.open begin soc.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true) soc.send(msg, 0, it, @port) rescue nil ensure soc.close end end sleep(timeout) end ## # Returns the first found remote TupleSpace. Any further recovered # TupleSpaces can be found by calling +to_a+. def lookup_ring_any(timeout=5) queue = Queue.new th = Thread.new do self.lookup_ring(timeout) do |ts| queue.push(ts) end queue.push(nil) while it = queue.pop @rings.push(it) end end @primary = queue.pop raise('RingNotFound') if @primary.nil? @primary end end ## # RingProvider uses a RingServer advertised TupleSpace as a name service. # TupleSpace clients can register themselves with the remote TupleSpace and # look up other provided services via the remote TupleSpace. # # Services are registered with a tuple of the format [:name, klass, # DRbObject, description]. class RingProvider ## # Creates a RingProvider that will provide a +klass+ service running on # +front+, with a +description+. +renewer+ is optional. def initialize(klass, front, desc, renewer = nil) @tuple = [:name, klass, front, desc] @renewer = renewer || Rinda::SimpleRenewer.new end ## # Advertises this service on the primary remote TupleSpace. def provide ts = Rinda::RingFinger.primary ts.write(@tuple, @renewer) end end end if __FILE__ == $0 DRb.start_service case ARGV.shift when 's' require 'rinda/tuplespace' ts = Rinda::TupleSpace.new place = Rinda::RingServer.new(ts) $stdin.gets when 'w' finger = Rinda::RingFinger.new(nil) finger.lookup_ring do |ts| p ts ts.write([:hello, :world]) end when 'r' finger = Rinda::RingFinger.new(nil) finger.lookup_ring do |ts| p ts p ts.take([nil, nil]) end end end PK|]C eregex.rbnu[# this is just a proof of concept toy. class RegOr def initialize(re1, re2) @re1 = re1 @re2 = re2 end def =~ (str) @re1 =~ str or @re2 =~ str end end class RegAnd def initialize(re1, re2) @re1 = re1 @re2 = re2 end def =~ (str) @re1 =~ str and @re2 =~ str end end class Regexp def |(other) RegOr.new(self, other) end def &(other) RegAnd.new(self, other) end end if __FILE__ == $0 p "abc" =~ /b/|/c/ p "abc" =~ /b/&/c/ end PK|]>,, pstore.rbnu[# = PStore -- Transactional File Storage for Ruby Objects # # pstore.rb - # originally by matz # documentation by Kev Jackson and James Edward Gray II # # See PStore for documentation. require "fileutils" require "digest/md5" # # PStore implements a file based persistence mechanism based on a Hash. User # code can store hierarchies of Ruby objects (values) into the data store file # by name (keys). An object hierarchy may be just a single object. User code # may later read values back from the data store or even update data, as needed. # # The transactional behavior ensures that any changes succeed or fail together. # This can be used to ensure that the data store is not left in a transitory # state, where some values were updated but others were not. # # Behind the scenes, Ruby objects are stored to the data store file with # Marshal. That carries the usual limitations. Proc objects cannot be # marshalled, for example. # # == Usage example: # # require "pstore" # # # a mock wiki object... # class WikiPage # def initialize( page_name, author, contents ) # @page_name = page_name # @revisions = Array.new # # add_revision(author, contents) # end # # attr_reader :page_name # # def add_revision( author, contents ) # @revisions << { :created => Time.now, # :author => author, # :contents => contents } # end # # def wiki_page_references # [@page_name] + @revisions.last[:contents].scan(/\b(?:[A-Z]+[a-z]+){2,}/) # end # # # ... # end # # # create a new page... # home_page = WikiPage.new( "HomePage", "James Edward Gray II", # "A page about the JoysOfDocumentation..." ) # # # then we want to update page data and the index together, or not at all... # wiki = PStore.new("wiki_pages.pstore") # wiki.transaction do # begin transaction; do all of this or none of it # # store page... # wiki[home_page.page_name] = home_page # # ensure that an index has been created... # wiki[:wiki_index] ||= Array.new # # update wiki index... # wiki[:wiki_index].push(*home_page.wiki_page_references) # end # commit changes to wiki data store file # # ### Some time later... ### # # # read wiki data... # wiki.transaction(true) do # begin read-only transaction, no changes allowed # wiki.roots.each do |data_root_name| # p data_root_name # p wiki[data_root_name] # end # end # class PStore binmode = defined?(File::BINARY) ? File::BINARY : 0 RDWR_ACCESS = File::RDWR | File::CREAT | binmode RD_ACCESS = File::RDONLY | binmode WR_ACCESS = File::WRONLY | File::CREAT | File::TRUNC | binmode # The error type thrown by all PStore methods. class Error < StandardError end # # To construct a PStore object, pass in the _file_ path where you would like # the data to be stored. # def initialize(file) dir = File::dirname(file) unless File::directory? dir raise PStore::Error, format("directory %s does not exist", dir) end if File::exist? file and not File::readable? file raise PStore::Error, format("file %s not readable", file) end @transaction = false @filename = file @abort = false end # Raises PStore::Error if the calling code is not in a PStore#transaction. def in_transaction raise PStore::Error, "not in transaction" unless @transaction end # # Raises PStore::Error if the calling code is not in a PStore#transaction or # if the code is in a read-only PStore#transaction. # def in_transaction_wr() in_transaction() raise PStore::Error, "in read-only transaction" if @rdonly end private :in_transaction, :in_transaction_wr # # Retrieves a value from the PStore file data, by _name_. The hierarchy of # Ruby objects stored under that root _name_ will be returned. # # *WARNING*: This method is only valid in a PStore#transaction. It will # raise PStore::Error if called at any other time. # def [](name) in_transaction @table[name] end # # This method is just like PStore#[], save that you may also provide a # _default_ value for the object. In the event the specified _name_ is not # found in the data store, your _default_ will be returned instead. If you do # not specify a default, PStore::Error will be raised if the object is not # found. # # *WARNING*: This method is only valid in a PStore#transaction. It will # raise PStore::Error if called at any other time. # def fetch(name, default=PStore::Error) in_transaction unless @table.key? name if default==PStore::Error raise PStore::Error, format("undefined root name `%s'", name) else return default end end @table[name] end # # Stores an individual Ruby object or a hierarchy of Ruby objects in the data # store file under the root _name_. Assigning to a _name_ already in the data # store clobbers the old data. # # == Example: # # require "pstore" # # store = PStore.new("data_file.pstore") # store.transaction do # begin transaction # # load some data into the store... # store[:single_object] = "My data..." # store[:obj_heirarchy] = { "Kev Jackson" => ["rational.rb", "pstore.rb"], # "James Gray" => ["erb.rb", "pstore.rb"] } # end # commit changes to data store file # # *WARNING*: This method is only valid in a PStore#transaction and it cannot # be read-only. It will raise PStore::Error if called at any other time. # def []=(name, value) in_transaction_wr() @table[name] = value end # # Removes an object hierarchy from the data store, by _name_. # # *WARNING*: This method is only valid in a PStore#transaction and it cannot # be read-only. It will raise PStore::Error if called at any other time. # def delete(name) in_transaction_wr() @table.delete name end # # Returns the names of all object hierarchies currently in the store. # # *WARNING*: This method is only valid in a PStore#transaction. It will # raise PStore::Error if called at any other time. # def roots in_transaction @table.keys end # # Returns true if the supplied _name_ is currently in the data store. # # *WARNING*: This method is only valid in a PStore#transaction. It will # raise PStore::Error if called at any other time. # def root?(name) in_transaction @table.key? name end # Returns the path to the data store file. def path @filename end # # Ends the current PStore#transaction, committing any changes to the data # store immediately. # # == Example: # # require "pstore" # # store = PStore.new("data_file.pstore") # store.transaction do # begin transaction # # load some data into the store... # store[:one] = 1 # store[:two] = 2 # # store.commit # end transaction here, committing changes # # store[:three] = 3 # this change is never reached # end # # *WARNING*: This method is only valid in a PStore#transaction. It will # raise PStore::Error if called at any other time. # def commit in_transaction @abort = false throw :pstore_abort_transaction end # # Ends the current PStore#transaction, discarding any changes to the data # store. # # == Example: # # require "pstore" # # store = PStore.new("data_file.pstore") # store.transaction do # begin transaction # store[:one] = 1 # this change is not applied, see below... # store[:two] = 2 # this change is not applied, see below... # # store.abort # end transaction here, discard all changes # # store[:three] = 3 # this change is never reached # end # # *WARNING*: This method is only valid in a PStore#transaction. It will # raise PStore::Error if called at any other time. # def abort in_transaction @abort = true throw :pstore_abort_transaction end # # Opens a new transaction for the data store. Code executed inside a block # passed to this method may read and write data to and from the data store # file. # # At the end of the block, changes are committed to the data store # automatically. You may exit the transaction early with a call to either # PStore#commit or PStore#abort. See those methods for details about how # changes are handled. Raising an uncaught Exception in the block is # equivalent to calling PStore#abort. # # If _read_only_ is set to +true+, you will only be allowed to read from the # data store during the transaction and any attempts to change the data will # raise a PStore::Error. # # Note that PStore does not support nested transactions. # def transaction(read_only=false) # :yields: pstore raise PStore::Error, "nested transaction" if @transaction begin @rdonly = read_only @abort = false @transaction = true value = nil new_file = @filename + ".new" content = nil unless read_only file = File.open(@filename, RDWR_ACCESS) file.flock(File::LOCK_EX) commit_new(file) if FileTest.exist?(new_file) content = file.read() else begin file = File.open(@filename, RD_ACCESS) file.flock(File::LOCK_SH) content = (File.open(new_file, RD_ACCESS) {|n| n.read} rescue file.read()) rescue Errno::ENOENT content = "" end end if content != "" @table = load(content) if !read_only size = content.size md5 = Digest::MD5.digest(content) end else @table = {} end content = nil # unreference huge data begin catch(:pstore_abort_transaction) do value = yield(self) end rescue Exception @abort = true raise ensure if !read_only and !@abort tmp_file = @filename + ".tmp" content = dump(@table) if !md5 || size != content.size || md5 != Digest::MD5.digest(content) File.open(tmp_file, WR_ACCESS) {|t| t.write(content)} File.rename(tmp_file, new_file) commit_new(file) end content = nil # unreference huge data end end ensure @table = nil @transaction = false file.close if file end value end # This method is just a wrapped around Marshal.dump. def dump(table) # :nodoc: Marshal::dump(table) end # This method is just a wrapped around Marshal.load. def load(content) # :nodoc: Marshal::load(content) end # This method is just a wrapped around Marshal.load. def load_file(file) # :nodoc: Marshal::load(file) end private # Commits changes to the data store file. def commit_new(f) f.truncate(0) f.rewind new_file = @filename + ".new" File.open(new_file, RD_ACCESS) do |nf| FileUtils.copy_stream(nf, f) end File.unlink(new_file) end end # :enddoc: if __FILE__ == $0 db = PStore.new("/tmp/foo") db.transaction do p db.roots ary = db["root"] = [1,2,3,4] ary[1] = [1,1.5] end 1000.times do db.transaction do db["root"][0] += 1 p db["root"][0] end end db.transaction(true) do p db["root"] end end PK|]1P77 parsearg.rbnu[# # parsearg.rb - parse arguments # $Release Version: $ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Yasuo OHBA(SHL Japan Inc. Technology Dept.) # # -- # # # warn "Warning:#{caller[0].sub(/:in `.*'\z/, '')}: parsearg is deprecated after Ruby 1.8.1; use optparse instead" $RCS_ID=%q$Header$ require "getopts" def printUsageAndExit() if $USAGE eval($USAGE) end exit() end def setParenthesis(ex, opt, c) if opt != "" ex = sprintf("%s$OPT_%s%s", ex, opt, c) else ex = sprintf("%s%s", ex, c) end return ex end def setOrAnd(ex, opt, c) if opt != "" ex = sprintf("%s$OPT_%s %s%s ", ex, opt, c, c) else ex = sprintf("%s %s%s ", ex, c, c) end return ex end def setExpression(ex, opt, op) if !op ex = sprintf("%s$OPT_%s", ex, opt) return ex end case op.chr when "(", ")" ex = setParenthesis(ex, opt, op.chr) when "|", "&" ex = setOrAnd(ex, opt, op.chr) else return nil end return ex end # parseArgs is obsolete. Use OptionParser instead. def parseArgs(argc, nopt, single_opts, *opts) if (noOptions = getopts(single_opts, *opts)) == nil printUsageAndExit() end if nopt ex = nil pos = 0 for o in nopt.split(/[()|&]/) pos += o.length ex = setExpression(ex, o, nopt[pos]) pos += 1 end begin if !eval(ex) printUsageAndExit() end rescue print "Format Error!! : \"" + nopt + "\"\t[parseArgs]\n" exit!(-1) end end if ARGV.length < argc printUsageAndExit() end return noOptions end PK|]u--racc/parser.rbnu[# # $originalId: parser.rb,v 1.8 2006/07/06 11:42:07 aamine Exp $ # # Copyright (c) 1999-2006 Minero Aoki # # This program is free software. # You can distribute/modify this program under the same terms of ruby. # # As a special exception, when this code is copied by Racc # into a Racc output file, you may use that output file # without restriction. # unless defined?(NotImplementedError) NotImplementedError = NotImplementError end module Racc class ParseError < StandardError; end end unless defined?(::ParseError) ParseError = Racc::ParseError end module Racc unless defined?(Racc_No_Extentions) Racc_No_Extentions = false end class Parser Racc_Runtime_Version = '1.4.5' Racc_Runtime_Revision = '$originalRevision: 1.8 $'.split[1] Racc_Runtime_Core_Version_R = '1.4.5' Racc_Runtime_Core_Revision_R = '$originalRevision: 1.8 $'.split[1] begin require 'racc/cparse' # Racc_Runtime_Core_Version_C = (defined in extention) Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split[2] unless new.respond_to?(:_racc_do_parse_c, true) raise LoadError, 'old cparse.so' end if Racc_No_Extentions raise LoadError, 'selecting ruby version of racc runtime core' end Racc_Main_Parsing_Routine = :_racc_do_parse_c Racc_YY_Parse_Method = :_racc_yyparse_c Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C Racc_Runtime_Type = 'c' rescue LoadError Racc_Main_Parsing_Routine = :_racc_do_parse_rb Racc_YY_Parse_Method = :_racc_yyparse_rb Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R Racc_Runtime_Type = 'ruby' end def Parser.racc_runtime_type Racc_Runtime_Type end private def _racc_setup @yydebug = false unless self.class::Racc_debug_parser @yydebug = false unless defined?(@yydebug) if @yydebug @racc_debug_out = $stderr unless defined?(@racc_debug_out) @racc_debug_out ||= $stderr end arg = self.class::Racc_arg arg[13] = true if arg.size < 14 arg end def _racc_init_sysvars @racc_state = [0] @racc_tstack = [] @racc_vstack = [] @racc_t = nil @racc_val = nil @racc_read_next = true @racc_user_yyerror = false @racc_error_status = 0 end ### ### do_parse ### def do_parse __send__(Racc_Main_Parsing_Routine, _racc_setup(), false) end def next_token raise NotImplementedError, "#{self.class}\#next_token is not defined" end def _racc_do_parse_rb(arg, in_debug) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, reduce_n, use_result, * = arg _racc_init_sysvars tok = act = i = nil nerr = 0 catch(:racc_end_parse) { while true if i = action_pointer[@racc_state[-1]] if @racc_read_next if @racc_t != 0 # not EOF tok, @racc_val = next_token() unless tok # EOF @racc_t = 0 else @racc_t = (token_table[tok] or 1) # error token end racc_read_token(@racc_t, tok, @racc_val) if @yydebug @racc_read_next = false end end i += @racc_t unless i >= 0 and act = action_table[i] and action_check[i] == @racc_state[-1] act = action_default[@racc_state[-1]] end else act = action_default[@racc_state[-1]] end while act = _racc_evalact(act, arg) ; end end } end ### ### yyparse ### def yyparse(recv, mid) __send__(Racc_YY_Parse_Method, recv, mid, _racc_setup(), true) end def _racc_yyparse_rb(recv, mid, arg, c_debug) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, reduce_n, use_result, * = arg _racc_init_sysvars tok = nil act = nil i = nil nerr = 0 catch(:racc_end_parse) { until i = action_pointer[@racc_state[-1]] while act = _racc_evalact(action_default[@racc_state[-1]], arg) ; end end recv.__send__(mid) do |tok, val| unless tok @racc_t = 0 else @racc_t = (token_table[tok] or 1) # error token end @racc_val = val @racc_read_next = false i += @racc_t unless i >= 0 and act = action_table[i] and action_check[i] == @racc_state[-1] act = action_default[@racc_state[-1]] end while act = _racc_evalact(act, arg) ; end while not (i = action_pointer[@racc_state[-1]]) or not @racc_read_next or @racc_t == 0 # $ unless i and i += @racc_t and i >= 0 and act = action_table[i] and action_check[i] == @racc_state[-1] act = action_default[@racc_state[-1]] end while act = _racc_evalact(act, arg) ; end end end } end ### ### common ### def _racc_evalact(act, arg) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, reduce_n, use_result, * = arg nerr = 0 # tmp if act > 0 and act < shift_n # # shift # if @racc_error_status > 0 @racc_error_status -= 1 unless @racc_t == 1 # error token end @racc_vstack.push @racc_val @racc_state.push act @racc_read_next = true if @yydebug @racc_tstack.push @racc_t racc_shift @racc_t, @racc_tstack, @racc_vstack end elsif act < 0 and act > -reduce_n # # reduce # code = catch(:racc_jump) { @racc_state.push _racc_do_reduce(arg, act) false } if code case code when 1 # yyerror @racc_user_yyerror = true # user_yyerror return -reduce_n when 2 # yyaccept return shift_n else raise '[Racc Bug] unknown jump code' end end elsif act == shift_n # # accept # racc_accept if @yydebug throw :racc_end_parse, @racc_vstack[0] elsif act == -reduce_n # # error # case @racc_error_status when 0 unless arg[21] # user_yyerror nerr += 1 on_error @racc_t, @racc_val, @racc_vstack end when 3 if @racc_t == 0 # is $ throw :racc_end_parse, nil end @racc_read_next = true end @racc_user_yyerror = false @racc_error_status = 3 while true if i = action_pointer[@racc_state[-1]] i += 1 # error token if i >= 0 and (act = action_table[i]) and action_check[i] == @racc_state[-1] break end end throw :racc_end_parse, nil if @racc_state.size <= 1 @racc_state.pop @racc_vstack.pop if @yydebug @racc_tstack.pop racc_e_pop @racc_state, @racc_tstack, @racc_vstack end end return act else raise "[Racc Bug] unknown action #{act.inspect}" end racc_next_state(@racc_state[-1], @racc_state) if @yydebug nil end def _racc_do_reduce(arg, act) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, reduce_n, use_result, * = arg state = @racc_state vstack = @racc_vstack tstack = @racc_tstack i = act * -3 len = reduce_table[i] reduce_to = reduce_table[i+1] method_id = reduce_table[i+2] void_array = [] tmp_t = tstack[-len, len] if @yydebug tmp_v = vstack[-len, len] tstack[-len, len] = void_array if @yydebug vstack[-len, len] = void_array state[-len, len] = void_array # tstack must be updated AFTER method call if use_result vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) else vstack.push __send__(method_id, tmp_v, vstack) end tstack.push reduce_to racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug k1 = reduce_to - nt_base if i = goto_pointer[k1] i += state[-1] if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 return curstate end end goto_default[k1] end def on_error(t, val, vstack) raise ParseError, sprintf("\nparse error on value %s (%s)", val.inspect, token_to_str(t) || '?') end def yyerror throw :racc_jump, 1 end def yyaccept throw :racc_jump, 2 end def yyerrok @racc_error_status = 0 end # # for debugging output # def racc_read_token(t, tok, val) @racc_debug_out.print 'read ' @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' @racc_debug_out.puts val.inspect @racc_debug_out.puts end def racc_shift(tok, tstack, vstack) @racc_debug_out.puts "shift #{racc_token2str tok}" racc_print_stacks tstack, vstack @racc_debug_out.puts end def racc_reduce(toks, sim, tstack, vstack) out = @racc_debug_out out.print 'reduce ' if toks.empty? out.print ' ' else toks.each {|t| out.print ' ', racc_token2str(t) } end out.puts " --> #{racc_token2str(sim)}" racc_print_stacks tstack, vstack @racc_debug_out.puts end def racc_accept @racc_debug_out.puts 'accept' @racc_debug_out.puts end def racc_e_pop(state, tstack, vstack) @racc_debug_out.puts 'error recovering mode: pop token' racc_print_states state racc_print_stacks tstack, vstack @racc_debug_out.puts end def racc_next_state(curstate, state) @racc_debug_out.puts "goto #{curstate}" racc_print_states state @racc_debug_out.puts end def racc_print_stacks(t, v) out = @racc_debug_out out.print ' [' t.each_index do |i| out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' end out.puts ' ]' end def racc_print_states(s) out = @racc_debug_out out.print ' [' s.each {|st| out.print ' ', st } out.puts ' ]' end def racc_token2str(tok) self.class::Racc_token_to_s_table[tok] or raise "[Racc Bug] can't convert token #{tok} to string" end def token_to_str(t) self.class::Racc_token_to_s_table[t] end end end PK|]y|8XXfind.rbnu[# # find.rb: the Find module for processing all files under a given directory. # # # The +Find+ module supports the top-down traversal of a set of file paths. # # For example, to total the size of all files under your home directory, # ignoring anything in a "dot" directory (e.g. $HOME/.ssh): # # require 'find' # # total_size = 0 # # Find.find(ENV["HOME"]) do |path| # if FileTest.directory?(path) # if File.basename(path)[0] == ?. # Find.prune # Don't look any further into this directory. # else # next # end # else # total_size += FileTest.size(path) # end # end # module Find # # Calls the associated block with the name of every file and directory listed # as arguments, then recursively on their subdirectories, and so on. # # See the +Find+ module documentation for an example. # def find(*paths) # :yield: path paths.collect!{|d| d.dup} while file = paths.shift catch(:prune) do yield file.dup.taint next unless File.exist? file begin if File.lstat(file).directory? then d = Dir.open(file) begin for f in d next if f == "." or f == ".." if File::ALT_SEPARATOR and file =~ /^(?:[\/\\]|[A-Za-z]:[\/\\]?)$/ then f = file + f elsif file == "/" then f = "/" + f else f = File.join(file, f) end paths.unshift f.untaint end ensure d.close end end rescue Errno::ENOENT, Errno::EACCES end end end end # # Skips the current file or directory, restarting the loop with the next # entry. If the current file is a directory, that directory will not be # recursively entered. Meaningful only within the block associated with # Find::find. # # See the +Find+ module documentation for an example. # def prune throw :prune end module_function :find, :prune end PK|]?rK[[ profiler.rbnu[module Profiler__ # internal values @@start = @@stack = @@map = nil PROFILE_PROC = proc{|event, file, line, id, binding, klass| case event when "call", "c-call" now = Process.times[0] @@stack.push [now, 0.0] when "return", "c-return" now = Process.times[0] key = [klass, id] if tick = @@stack.pop data = (@@map[key] ||= [0, 0.0, 0.0, key]) data[0] += 1 cost = now - tick[0] data[1] += cost data[2] += cost - tick[1] @@stack[-1][1] += cost if @@stack[-1] end end } module_function def start_profile @@start = Process.times[0] @@stack = [] @@map = {} set_trace_func PROFILE_PROC end def stop_profile set_trace_func nil end def print_profile(f) stop_profile total = Process.times[0] - @@start if total == 0 then total = 0.01 end data = @@map.values data.sort!{|a,b| b[2] <=> a[2]} sum = 0 f.printf " %% cumulative self self total\n" f.printf " time seconds seconds calls ms/call ms/call name\n" for d in data sum += d[2] f.printf "%6.2f %8.2f %8.2f %8d ", d[2]/total*100, sum, d[2], d[0] f.printf "%8.2f %8.2f %s\n", d[2]*1000/d[0], d[1]*1000/d[0], get_name(*d[3]) end f.printf "%6.2f %8.2f %8.2f %8d ", 0.0, total, 0.0, 1 # ??? f.printf "%8.2f %8.2f %s\n", 0.0, total*1000, "#toplevel" # ??? end def get_name(klass, id) name = klass.to_s || "" if klass.kind_of? Class name += "#" else name += "." end name + id.id2name end private :get_name end PK|] 1wrss.rbnu[# Copyright (c) 2003-2007 Kouhei Sutou. You can redistribute it and/or # modify it under the same terms as Ruby. # # Author:: Kouhei Sutou # Tutorial:: http://www.cozmixng.org/~rwiki/?cmd=view;name=RSS+Parser%3A%3ATutorial.en require 'rss/1.0' require 'rss/2.0' require 'rss/atom' require 'rss/content' require 'rss/dublincore' require 'rss/image' require 'rss/itunes' require 'rss/slash' require 'rss/syndication' require 'rss/taxonomy' require 'rss/trackback' require "rss/maker" PK|]  monitor.rbnu[=begin = monitor.rb Copyright (C) 2001 Shugo Maeda This library is distributed under the terms of the Ruby license. You can freely distribute/modify this library. == example This is a simple example. require 'monitor.rb' buf = [] buf.extend(MonitorMixin) empty_cond = buf.new_cond # consumer Thread.start do loop do buf.synchronize do empty_cond.wait_while { buf.empty? } print buf.shift end end end # producer while line = ARGF.gets buf.synchronize do buf.push(line) empty_cond.signal end end The consumer thread waits for the producer thread to push a line to buf while buf.empty?, and the producer thread (main thread) reads a line from ARGF and push it to buf, then call empty_cond.signal. =end # # Adds monitor functionality to an arbitrary object by mixing the module with # +include+. For example: # # require 'monitor.rb' # # buf = [] # buf.extend(MonitorMixin) # empty_cond = buf.new_cond # # # consumer # Thread.start do # loop do # buf.synchronize do # empty_cond.wait_while { buf.empty? } # print buf.shift # end # end # end # # # producer # while line = ARGF.gets # buf.synchronize do # buf.push(line) # empty_cond.signal # end # end # # The consumer thread waits for the producer thread to push a line # to buf while buf.empty?, and the producer thread (main thread) # reads a line from ARGF and push it to buf, then call # empty_cond.signal. # module MonitorMixin # # FIXME: This isn't documented in Nutshell. # # Since MonitorMixin.new_cond returns a ConditionVariable, and the example # above calls while_wait and signal, this class should be documented. # class ConditionVariable class Timeout < Exception; end # Create a new timer with the argument timeout, and add the # current thread to the list of waiters. Then the thread is # stopped. It will be resumed when a corresponding #signal # occurs. def wait(timeout = nil) @monitor.instance_eval {mon_check_owner()} timer = create_timer(timeout) Thread.critical = true count = @monitor.instance_eval {mon_exit_for_cond()} @waiters.push(Thread.current) begin Thread.stop return true rescue Timeout return false ensure Thread.critical = true begin if timer && timer.alive? Thread.kill(timer) end if @waiters.include?(Thread.current) # interrupted? @waiters.delete(Thread.current) end @monitor.instance_eval {mon_enter_for_cond(count)} ensure Thread.critical = false end end end # call #wait while the supplied block returns +true+. def wait_while while yield wait end end # call #wait until the supplied block returns +true+. def wait_until until yield wait end end # Wake up and run the next waiter def signal @monitor.instance_eval {mon_check_owner()} Thread.critical = true t = @waiters.shift t.wakeup if t Thread.critical = false Thread.pass end # Wake up all the waiters. def broadcast @monitor.instance_eval {mon_check_owner()} Thread.critical = true for t in @waiters t.wakeup end @waiters.clear Thread.critical = false Thread.pass end def count_waiters return @waiters.length end private def initialize(monitor) @monitor = monitor @waiters = [] end def create_timer(timeout) if timeout waiter = Thread.current return Thread.start { Thread.pass sleep(timeout) Thread.critical = true waiter.raise(Timeout.new) } else return nil end end end def self.extend_object(obj) super(obj) obj.instance_eval {mon_initialize()} end # # Attempts to enter exclusive section. Returns +false+ if lock fails. # def mon_try_enter result = false Thread.critical = true if @mon_owner.nil? @mon_owner = Thread.current end if @mon_owner == Thread.current @mon_count += 1 result = true end Thread.critical = false return result end # For backward compatibility alias try_mon_enter mon_try_enter # # Enters exclusive section. # def mon_enter Thread.critical = true mon_acquire(@mon_entering_queue) @mon_count += 1 ensure Thread.critical = false end # # Leaves exclusive section. # def mon_exit mon_check_owner Thread.critical = true @mon_count -= 1 if @mon_count == 0 mon_release end Thread.critical = false Thread.pass end # # Enters exclusive section and executes the block. Leaves the exclusive # section automatically when the block exits. See example under # +MonitorMixin+. # def mon_synchronize mon_enter begin yield ensure mon_exit end end alias synchronize mon_synchronize # # FIXME: This isn't documented in Nutshell. # # Create a new condition variable for this monitor. # This facilitates control of the monitor with #signal and #wait. # def new_cond return ConditionVariable.new(self) end private def initialize(*args) super mon_initialize end # called by initialize method to set defaults for instance variables. def mon_initialize @mon_owner = nil @mon_count = 0 @mon_entering_queue = [] @mon_waiting_queue = [] end # Throw a ThreadError exception if the current thread # does't own the monitor def mon_check_owner if @mon_owner != Thread.current raise ThreadError, "current thread not owner" end end def mon_acquire(queue) while @mon_owner && @mon_owner != Thread.current queue.push(Thread.current) Thread.stop Thread.critical = true end @mon_owner = Thread.current end # mon_release requires Thread.critical == true def mon_release @mon_owner = nil while t = @mon_waiting_queue.shift || @mon_entering_queue.shift if t.alive? t.wakeup return end end end def mon_enter_for_cond(count) mon_acquire(@mon_waiting_queue) @mon_count = count end def mon_exit_for_cond count = @mon_count @mon_count = 0 return count ensure mon_release end end # Monitors provide means of mutual exclusion for Thread programming. # A critical region is created by means of the synchronize method, # which takes a block. # The condition variables (created with #new_cond) may be used # to control the execution of a monitor with #signal and #wait. # # the Monitor class wraps MonitorMixin, and provides aliases # alias try_enter try_mon_enter # alias enter mon_enter # alias exit mon_exit # to access its methods more concisely. class Monitor include MonitorMixin alias try_enter try_mon_enter alias enter mon_enter alias exit mon_exit end # Documentation comments: # - All documentation comes from Nutshell. # - MonitorMixin.new_cond appears in the example, but is not documented in # Nutshell. # - All the internals (internal modules Accessible and Initializable, class # ConditionVariable) appear in RDoc. It might be good to hide them, by # making them private, or marking them :nodoc:, etc. # - The entire example from the RD section at the top is replicated in the RDoc # comment for MonitorMixin. Does the RD section need to remain? # - RDoc doesn't recognise aliases, so we have mon_synchronize documented, but # not synchronize. # - mon_owner is in Nutshell, but appears as an accessor in a separate module # here, so is hard/impossible to RDoc. Some other useful accessors # (mon_count and some queue stuff) are also in this module, and don't appear # directly in the RDoc output. # - in short, it may be worth changing the code layout in this file to make the # documentation easier # Local variables: # mode: Ruby # tab-width: 8 # End: PK|]ln[3[3 complex.rbnu[# # complex.rb - # $Release Version: 0.5 $ # $Revision: 1.3 $ # $Date: 1998/07/08 10:05:28 $ # by Keiju ISHITSUKA(SHL Japan Inc.) # # ---- # # complex.rb implements the Complex class for complex numbers. Additionally, # some methods in other Numeric classes are redefined or added to allow greater # interoperability with Complex numbers. # # Complex numbers can be created in the following manner: # - Complex(a, b) # - Complex.polar(radius, theta) # # Additionally, note the following: # - Complex::I (the mathematical constant i) # - Numeric#im (e.g. 5.im -> 0+5i) # # The following +Math+ module methods are redefined to handle Complex arguments. # They will work as normal with non-Complex arguments. # sqrt exp cos sin tan log log10 # cosh sinh tanh acos asin atan atan2 acosh asinh atanh # # # Numeric is a built-in class on which Fixnum, Bignum, etc., are based. Here # some methods are added so that all number types can be treated to some extent # as Complex numbers. # class Numeric # # Returns a Complex number (0,self). # def im Complex(0, self) end # # The real part of a complex number, i.e. self. # def real self end # # The imaginary part of a complex number, i.e. 0. # def image 0 end alias imag image # # See Complex#arg. # def arg Math.atan2!(0, self) end alias angle arg # # See Complex#polar. # def polar return abs, arg end # # See Complex#conjugate (short answer: returns self). # def conjugate self end alias conj conjugate end # # Creates a Complex number. +a+ and +b+ should be Numeric. The result will be # a+bi. # def Complex(a, b = 0) if b == 0 and (a.kind_of?(Complex) or defined? Complex::Unify) a else Complex.new( a.real-b.imag, a.imag+b.real ) end end # # The complex number class. See complex.rb for an overview. # class Complex < Numeric @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-' undef step undef div, divmod undef floor, truncate, ceil, round def Complex.generic?(other) # :nodoc: other.kind_of?(Integer) or other.kind_of?(Float) or (defined?(Rational) and other.kind_of?(Rational)) end # # Creates a +Complex+ number in terms of +r+ (radius) and +theta+ (angle). # def Complex.polar(r, theta) Complex(r*Math.cos(theta), r*Math.sin(theta)) end # # Creates a +Complex+ number a+bi. # def Complex.new!(a, b=0) new(a,b) end def initialize(a, b) raise TypeError, "non numeric 1st arg `#{a.inspect}'" if !a.kind_of? Numeric raise TypeError, "`#{a.inspect}' for 1st arg" if a.kind_of? Complex raise TypeError, "non numeric 2nd arg `#{b.inspect}'" if !b.kind_of? Numeric raise TypeError, "`#{b.inspect}' for 2nd arg" if b.kind_of? Complex @real = a @image = b end # # Addition with real or complex number. # def + (other) if other.kind_of?(Complex) re = @real + other.real im = @image + other.image Complex(re, im) elsif Complex.generic?(other) Complex(@real + other, @image) else x , y = other.coerce(self) x + y end end # # Subtraction with real or complex number. # def - (other) if other.kind_of?(Complex) re = @real - other.real im = @image - other.image Complex(re, im) elsif Complex.generic?(other) Complex(@real - other, @image) else x , y = other.coerce(self) x - y end end # # Multiplication with real or complex number. # def * (other) if other.kind_of?(Complex) re = @real*other.real - @image*other.image im = @real*other.image + @image*other.real Complex(re, im) elsif Complex.generic?(other) Complex(@real * other, @image * other) else x , y = other.coerce(self) x * y end end # # Division by real or complex number. # def / (other) if other.kind_of?(Complex) self*other.conjugate/other.abs2 elsif Complex.generic?(other) Complex(@real/other, @image/other) else x, y = other.coerce(self) x/y end end def quo(other) Complex(@real.quo(1), @image.quo(1)) / other end # # Raise this complex number to the given (real or complex) power. # def ** (other) if other == 0 return Complex(1) end if other.kind_of?(Complex) r, theta = polar ore = other.real oim = other.image nr = Math.exp!(ore*Math.log!(r) - oim * theta) ntheta = theta*ore + oim*Math.log!(r) Complex.polar(nr, ntheta) elsif other.kind_of?(Integer) if other > 0 x = self z = x n = other - 1 while n != 0 while (div, mod = n.divmod(2) mod == 0) x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image) n = div end z *= x n -= 1 end z else if defined? Rational (Rational(1) / self) ** -other else self ** Float(other) end end elsif Complex.generic?(other) r, theta = polar Complex.polar(r**other, theta*other) else x, y = other.coerce(self) x**y end end # # Remainder after division by a real or complex number. # def % (other) if other.kind_of?(Complex) Complex(@real % other.real, @image % other.image) elsif Complex.generic?(other) Complex(@real % other, @image % other) else x , y = other.coerce(self) x % y end end #-- # def divmod(other) # if other.kind_of?(Complex) # rdiv, rmod = @real.divmod(other.real) # idiv, imod = @image.divmod(other.image) # return Complex(rdiv, idiv), Complex(rmod, rmod) # elsif Complex.generic?(other) # Complex(@real.divmod(other), @image.divmod(other)) # else # x , y = other.coerce(self) # x.divmod(y) # end # end #++ # # Absolute value (aka modulus): distance from the zero point on the complex # plane. # def abs Math.hypot(@real, @image) end # # Square of the absolute value. # def abs2 @real*@real + @image*@image end # # Argument (angle from (1,0) on the complex plane). # def arg Math.atan2!(@image, @real) end alias angle arg # # Returns the absolute value _and_ the argument. # def polar return abs, arg end # # Complex conjugate (z + z.conjugate = 2 * z.real). # def conjugate Complex(@real, -@image) end alias conj conjugate # # Compares the absolute values of the two numbers. # def <=> (other) self.abs <=> other.abs end # # Test for numerical equality (a == a + 0i). # def == (other) if other.kind_of?(Complex) @real == other.real and @image == other.image elsif Complex.generic?(other) @real == other and @image == 0 else other == self end end # # Attempts to coerce +other+ to a Complex number. # def coerce(other) if Complex.generic?(other) return Complex.new!(other), self else super end end # # FIXME # def denominator @real.denominator.lcm(@image.denominator) end # # FIXME # def numerator cd = denominator Complex(@real.numerator*(cd/@real.denominator), @image.numerator*(cd/@image.denominator)) end # # Standard string representation of the complex number. # def to_s if @real != 0 if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1 if @image >= 0 @real.to_s+"+("+@image.to_s+")i" else @real.to_s+"-("+(-@image).to_s+")i" end else if @image >= 0 @real.to_s+"+"+@image.to_s+"i" else @real.to_s+"-"+(-@image).to_s+"i" end end else if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1 "("+@image.to_s+")i" else @image.to_s+"i" end end end # # Returns a hash code for the complex number. # def hash @real.hash ^ @image.hash end # # Returns "Complex(real, image)". # def inspect sprintf("Complex(%s, %s)", @real.inspect, @image.inspect) end # # +I+ is the imaginary number. It exists at point (0,1) on the complex plane. # I = Complex(0,1) # The real part of a complex number. attr :real # The imaginary part of a complex number. attr :image alias imag image end class Integer unless defined?(1.numerator) def numerator() self end def denominator() 1 end def gcd(other) min = self.abs max = other.abs while min > 0 tmp = min min = max % min max = tmp end max end def lcm(other) if self.zero? or other.zero? 0 else (self.div(self.gcd(other)) * other).abs end end end end module Math alias sqrt! sqrt alias exp! exp alias log! log alias log10! log10 alias cos! cos alias sin! sin alias tan! tan alias cosh! cosh alias sinh! sinh alias tanh! tanh alias acos! acos alias asin! asin alias atan! atan alias atan2! atan2 alias acosh! acosh alias asinh! asinh alias atanh! atanh # Redefined to handle a Complex argument. def sqrt(z) if Complex.generic?(z) if z >= 0 sqrt!(z) else Complex(0,sqrt!(-z)) end else if z.image < 0 sqrt(z.conjugate).conjugate else r = z.abs x = z.real Complex( sqrt!((r+x)/2), sqrt!((r-x)/2) ) end end end # Redefined to handle a Complex argument. def exp(z) if Complex.generic?(z) exp!(z) else Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image)) end end # Redefined to handle a Complex argument. def cos(z) if Complex.generic?(z) cos!(z) else Complex(cos!(z.real)*cosh!(z.image), -sin!(z.real)*sinh!(z.image)) end end # Redefined to handle a Complex argument. def sin(z) if Complex.generic?(z) sin!(z) else Complex(sin!(z.real)*cosh!(z.image), cos!(z.real)*sinh!(z.image)) end end # Redefined to handle a Complex argument. def tan(z) if Complex.generic?(z) tan!(z) else sin(z)/cos(z) end end def sinh(z) if Complex.generic?(z) sinh!(z) else Complex( sinh!(z.real)*cos!(z.image), cosh!(z.real)*sin!(z.image) ) end end def cosh(z) if Complex.generic?(z) cosh!(z) else Complex( cosh!(z.real)*cos!(z.image), sinh!(z.real)*sin!(z.image) ) end end def tanh(z) if Complex.generic?(z) tanh!(z) else sinh(z)/cosh(z) end end # Redefined to handle a Complex argument. def log(z) if Complex.generic?(z) and z >= 0 log!(z) else r, theta = z.polar Complex(log!(r.abs), theta) end end # Redefined to handle a Complex argument. def log10(z) if Complex.generic?(z) log10!(z) else log(z)/log!(10) end end def acos(z) if Complex.generic?(z) and z >= -1 and z <= 1 acos!(z) else -1.0.im * log( z + 1.0.im * sqrt(1.0-z*z) ) end end def asin(z) if Complex.generic?(z) and z >= -1 and z <= 1 asin!(z) else -1.0.im * log( 1.0.im * z + sqrt(1.0-z*z) ) end end def atan(z) if Complex.generic?(z) atan!(z) else 1.0.im * log( (1.0.im+z) / (1.0.im-z) ) / 2.0 end end def atan2(y,x) if Complex.generic?(y) and Complex.generic?(x) atan2!(y,x) else -1.0.im * log( (x+1.0.im*y) / sqrt(x*x+y*y) ) end end def acosh(z) if Complex.generic?(z) and z >= 1 acosh!(z) else log( z + sqrt(z*z-1.0) ) end end def asinh(z) if Complex.generic?(z) asinh!(z) else log( z + sqrt(1.0+z*z) ) end end def atanh(z) if Complex.generic?(z) and z >= -1 and z <= 1 atanh!(z) else log( (1.0+z) / (1.0-z) ) / 2.0 end end module_function :sqrt! module_function :sqrt module_function :exp! module_function :exp module_function :log! module_function :log module_function :log10! module_function :log10 module_function :cosh! module_function :cosh module_function :cos! module_function :cos module_function :sinh! module_function :sinh module_function :sin! module_function :sin module_function :tan! module_function :tan module_function :tanh! module_function :tanh module_function :acos! module_function :acos module_function :asin! module_function :asin module_function :atan! module_function :atan module_function :atan2! module_function :atan2 module_function :acosh! module_function :acosh module_function :asinh! module_function :asinh module_function :atanh! module_function :atanh end # Documentation comments: # - source: original (researched from pickaxe) # - a couple of fixme's # - RDoc output for Bignum etc. is a bit short, with nothing but an # (undocumented) alias. No big deal. PK|]3);#;# delegate.rbnu[# = delegate -- Support for the Delegation Pattern # # Documentation by James Edward Gray II and Gavin Sinclair # # == Introduction # # This library provides three different ways to delegate method calls to an # object. The easiest to use is SimpleDelegator. Pass an object to the # constructor and all methods supported by the object will be delegated. This # object can be changed later. # # Going a step further, the top level DelegateClass method allows you to easily # setup delegation through class inheritance. This is considerably more # flexible and thus probably the most common use for this library. # # Finally, if you need full control over the delegation scheme, you can inherit # from the abstract class Delegator and customize as needed. (If you find # yourself needing this control, have a look at _forwardable_, also in the # standard library. It may suit your needs better.) # # == Notes # # Be advised, RDoc will not detect delegated methods. # # delegate.rb provides full-class delegation via the # DelegateClass() method. For single-method delegation via # def_delegator(), see forwardable.rb. # # == Examples # # === SimpleDelegator # # Here's a simple example that takes advantage of the fact that # SimpleDelegator's delegation object can be changed at any time. # # class Stats # def initialize # @source = SimpleDelegator.new([]) # end # # def stats( records ) # @source.__setobj__(records) # # "Elements: #{@source.size}\n" + # " Non-Nil: #{@source.compact.size}\n" + # " Unique: #{@source.uniq.size}\n" # end # end # # s = Stats.new # puts s.stats(%w{James Edward Gray II}) # puts # puts s.stats([1, 2, 3, nil, 4, 5, 1, 2]) # # Prints: # # Elements: 4 # Non-Nil: 4 # Unique: 4 # # Elements: 8 # Non-Nil: 7 # Unique: 6 # # === DelegateClass() # # Here's a sample of use from tempfile.rb. # # A _Tempfile_ object is really just a _File_ object with a few special rules # about storage location and/or when the File should be deleted. That makes for # an almost textbook perfect example of how to use delegation. # # class Tempfile < DelegateClass(File) # # constant and class member data initialization... # # def initialize(basename, tmpdir=Dir::tmpdir) # # build up file path/name in var tmpname... # # @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600) # # # ... # # super(@tmpfile) # # # below this point, all methods of File are supported... # end # # # ... # end # # === Delegator # # SimpleDelegator's implementation serves as a nice example here. # # class SimpleDelegator < Delegator # def initialize(obj) # super # pass obj to Delegator constructor, required # @_sd_obj = obj # store obj for future use # end # # def __getobj__ # @_sd_obj # return object we are delegating to, required # end # # def __setobj__(obj) # @_sd_obj = obj # change delegation object, a feature we're providing # end # # # ... # end # # Delegator is an abstract class used to build delegator pattern objects from # subclasses. Subclasses should redefine \_\_getobj\_\_. For a concrete # implementation, see SimpleDelegator. # class Delegator IgnoreBacktracePat = %r"\A#{Regexp.quote(__FILE__)}:\d+:in `" # # Pass in the _obj_ to delegate method calls to. All methods supported by # _obj_ will be delegated to. # def initialize(obj) preserved = ::Kernel.public_instance_methods(false) preserved -= ["to_s","to_a","inspect","==","=~","==="] for t in self.class.ancestors preserved |= t.public_instance_methods(false) preserved |= t.private_instance_methods(false) preserved |= t.protected_instance_methods(false) break if t == Delegator end preserved << "singleton_method_added" for method in obj.methods next if preserved.include? method begin eval <<-EOS, nil, __FILE__, __LINE__+1 def self.#{method}(*args, &block) begin __getobj__.__send__(:#{method}, *args, &block) ensure $@.delete_if{|s|IgnoreBacktracePat=~s} if $@ end end EOS rescue SyntaxError raise NameError, "invalid identifier %s" % method, caller(4) end end end alias initialize_methods initialize # Handles the magic of delegation through \_\_getobj\_\_. def method_missing(m, *args, &block) target = self.__getobj__ unless target.respond_to?(m) super(m, *args, &block) end target.__send__(m, *args, &block) end # # Checks for a method provided by this the delegate object by fowarding the # call through \_\_getobj\_\_. # def respond_to?(m, include_private = false) return true if super return self.__getobj__.respond_to?(m, include_private) end # # This method must be overridden by subclasses and should return the object # method calls are being delegated to. # def __getobj__ raise NotImplementedError, "need to define `__getobj__'" end # Serialization support for the object returned by \_\_getobj\_\_. def marshal_dump __getobj__ end # Reinitializes delegation from a serialized object. def marshal_load(obj) initialize_methods(obj) __setobj__(obj) end end # # A concrete implementation of Delegator, this class provides the means to # delegate all supported method calls to the object passed into the constructor # and even to change the object being delegated to at a later time with # \_\_setobj\_\_ . # class SimpleDelegator Edward # names.__setobj__(%w{Gavin Sinclair}) # puts names[1] # => Sinclair # def __setobj__(obj) raise ArgumentError, "cannot delegate to self" if self.equal?(obj) @_sd_obj = obj end # Clone support for the object returned by \_\_getobj\_\_. def clone new = super new.__setobj__(__getobj__.clone) new end # Duplication support for the object returned by \_\_getobj\_\_. def dup new = super new.__setobj__(__getobj__.clone) new end end # :stopdoc: # backward compatibility ^_^;;; Delegater = Delegator SimpleDelegater = SimpleDelegator # :startdoc: # # The primary interface to this library. Use to setup delegation when defining # your class. # # class MyClass < DelegateClass( ClassToDelegateTo ) # Step 1 # def initialize # super(obj_of_ClassToDelegateTo) # Step 2 # end # end # def DelegateClass(superclass) klass = Class.new methods = superclass.public_instance_methods(true) methods -= ::Kernel.public_instance_methods(false) methods |= ["to_s","to_a","inspect","==","=~","==="] klass.module_eval { def initialize(obj) # :nodoc: @_dc_obj = obj end def method_missing(m, *args, &block) # :nodoc: unless @_dc_obj.respond_to?(m) super(m, *args, &block) end @_dc_obj.__send__(m, *args, &block) end def respond_to?(m, include_private = false) # :nodoc: return true if super return @_dc_obj.respond_to?(m, include_private) end def __getobj__ # :nodoc: @_dc_obj end def __setobj__(obj) # :nodoc: raise ArgumentError, "cannot delegate to self" if self.equal?(obj) @_dc_obj = obj end def clone # :nodoc: new = super new.__setobj__(__getobj__.clone) new end def dup # :nodoc: new = super new.__setobj__(__getobj__.clone) new end } for method in methods begin klass.module_eval <<-EOS, __FILE__, __LINE__+1 def #{method}(*args, &block) begin @_dc_obj.__send__(:#{method}, *args, &block) ensure $@.delete_if{|s| ::Delegator::IgnoreBacktracePat =~ s} if $@ end end EOS rescue SyntaxError raise NameError, "invalid identifier %s" % method, caller(3) end end return klass end # :enddoc: if __FILE__ == $0 class ExtArray true foo2.error # raise error! end PK|]"HZZ profile.rbnu[require 'profiler' END { Profiler__::print_profile(STDERR) } Profiler__::start_profile PK|]Omkmf.rbnu[# module to create Makefile for extension modules # invoke like: ruby -r mkmf extconf.rb require 'rbconfig' require 'fileutils' require 'shellwords' CONFIG = Config::MAKEFILE_CONFIG ORIG_LIBPATH = ENV['LIB'] CXX_EXT = %w[cc cxx cpp] if /mswin|bccwin|mingw|msdosdjgpp|human|os2/ !~ CONFIG['build_os'] CXX_EXT.concat(%w[C]) end SRC_EXT = %w[c m].concat(CXX_EXT) $static = $config_h = nil $default_static = $static unless defined? $configure_args $configure_args = {} args = CONFIG["configure_args"] if ENV["CONFIGURE_ARGS"] args << " " << ENV["CONFIGURE_ARGS"] end for arg in Shellwords::shellwords(args) arg, val = arg.split('=', 2) next unless arg arg.tr!('_', '-') if arg.sub!(/^(?!--)/, '--') val or next arg.downcase! end next if /^--(?:top|topsrc|src|cur)dir$/ =~ arg $configure_args[arg] = val || true end for arg in ARGV arg, val = arg.split('=', 2) next unless arg arg.tr!('_', '-') if arg.sub!(/^(?!--)/, '--') val or next arg.downcase! end $configure_args[arg] = val || true end end $libdir = CONFIG["libdir"] $rubylibdir = CONFIG["rubylibdir"] $archdir = CONFIG["archdir"] $sitedir = CONFIG["sitedir"] $sitelibdir = CONFIG["sitelibdir"] $sitearchdir = CONFIG["sitearchdir"] $vendordir = CONFIG["vendordir"] $vendorlibdir = CONFIG["vendorlibdir"] $vendorarchdir = CONFIG["vendorarchdir"] $mswin = /mswin/ =~ RUBY_PLATFORM $bccwin = /bccwin/ =~ RUBY_PLATFORM $mingw = /mingw/ =~ RUBY_PLATFORM $cygwin = /cygwin/ =~ RUBY_PLATFORM $human = /human/ =~ RUBY_PLATFORM $netbsd = /netbsd/ =~ RUBY_PLATFORM $os2 = /os2/ =~ RUBY_PLATFORM $beos = /beos/ =~ RUBY_PLATFORM $solaris = /solaris/ =~ RUBY_PLATFORM $dest_prefix_pattern = (File::PATH_SEPARATOR == ';' ? /\A([[:alpha:]]:)?/ : /\A/) # :stopdoc: def config_string(key, config = CONFIG) s = config[key] and !s.empty? and block_given? ? yield(s) : s end def dir_re(dir) Regexp.new('\$(?:\('+dir+'\)|\{'+dir+'\})(?:\$(?:\(target_prefix\)|\{target_prefix\}))?') end INSTALL_DIRS = [ [dir_re('commondir'), "$(RUBYCOMMONDIR)"], [dir_re('sitedir'), "$(RUBYCOMMONDIR)"], [dir_re('vendordir'), "$(RUBYCOMMONDIR)"], [dir_re('rubylibdir'), "$(RUBYLIBDIR)"], [dir_re('archdir'), "$(RUBYARCHDIR)"], [dir_re('sitelibdir'), "$(RUBYLIBDIR)"], [dir_re('vendorlibdir'), "$(RUBYLIBDIR)"], [dir_re('sitearchdir'), "$(RUBYARCHDIR)"], [dir_re('bindir'), "$(BINDIR)"], [dir_re('vendorarchdir'), "$(RUBYARCHDIR)"], ] def install_dirs(target_prefix = nil) if $extout dirs = [ ['BINDIR', '$(extout)/bin'], ['RUBYCOMMONDIR', '$(extout)/common'], ['RUBYLIBDIR', '$(RUBYCOMMONDIR)$(target_prefix)'], ['RUBYARCHDIR', '$(extout)/$(arch)$(target_prefix)'], ['extout', "#$extout"], ['extout_prefix', "#$extout_prefix"], ] elsif $extmk dirs = [ ['BINDIR', '$(bindir)'], ['RUBYCOMMONDIR', '$(rubylibdir)'], ['RUBYLIBDIR', '$(rubylibdir)$(target_prefix)'], ['RUBYARCHDIR', '$(archdir)$(target_prefix)'], ] elsif $configure_args.has_key?('--vendor') dirs = [ ['BINDIR', '$(bindir)'], ['RUBYCOMMONDIR', '$(vendordir)$(target_prefix)'], ['RUBYLIBDIR', '$(vendorlibdir)$(target_prefix)'], ['RUBYARCHDIR', '$(vendorarchdir)$(target_prefix)'], ] else dirs = [ ['BINDIR', '$(bindir)'], ['RUBYCOMMONDIR', '$(sitedir)$(target_prefix)'], ['RUBYLIBDIR', '$(sitelibdir)$(target_prefix)'], ['RUBYARCHDIR', '$(sitearchdir)$(target_prefix)'], ] end dirs << ['target_prefix', (target_prefix ? "/#{target_prefix}" : "")] dirs end def map_dir(dir, map = nil) map ||= INSTALL_DIRS map.inject(dir) {|dir, (orig, new)| dir.gsub(orig, new)} end topdir = File.dirname(libdir = File.dirname(__FILE__)) extdir = File.expand_path("ext", topdir) $extmk = File.expand_path($0)[0, extdir.size+1] == extdir+"/" if not $extmk and File.exist?(($hdrdir = Config::CONFIG["archdir"]) + "/ruby.h") $topdir = $hdrdir elsif File.exist?(($hdrdir = ($top_srcdir ||= topdir)) + "/ruby.h") and File.exist?(($topdir ||= Config::CONFIG["topdir"]) + "/config.h") else abort "mkmf.rb can't find header files for ruby at #{$hdrdir}/ruby.h" end OUTFLAG = CONFIG['OUTFLAG'] CPPOUTFILE = CONFIG['CPPOUTFILE'] CONFTEST_C = "conftest.c" class String # Wraps a string in escaped quotes if it contains whitespace. def quote /\s/ =~ self ? "\"#{self}\"" : "#{self}" end # Generates a string used as cpp macro name. def tr_cpp strip.upcase.tr_s("^A-Z0-9_", "_") end end class Array # Wraps all strings in escaped quotes if they contain whitespace. def quote map {|s| s.quote} end end def rm_f(*files) FileUtils.rm_f(Dir[files.join("\0")]) end # Returns time stamp of the +target+ file if it exists and is newer # than or equal to all of +times+. def modified?(target, times) (t = File.mtime(target)) rescue return nil Array === times or times = [times] t if times.all? {|n| n <= t} end def merge_libs(*libs) libs.inject([]) do |x, y| xy = x & y xn = yn = 0 y = y.inject([]) {|ary, e| ary.last == e ? ary : ary << e} y.each_with_index do |v, yi| if xy.include?(v) xi = [x.index(v), xn].max() x[xi, 1] = y[yn..yi] xn, yn = xi + (yi - yn + 1), yi + 1 end end x.concat(y[yn..-1] || []) end end # This is a custom logging module. It generates an mkmf.log file when you # run your extconf.rb script. This can be useful for debugging unexpected # failures. # # This module and its associated methods are meant for internal use only. # module Logging @log = nil @logfile = 'mkmf.log' @orgerr = $stderr.dup @orgout = $stdout.dup @postpone = 0 @quiet = $extmk def self::open @log ||= File::open(@logfile, 'w') @log.sync = true $stderr.reopen(@log) $stdout.reopen(@log) yield ensure $stderr.reopen(@orgerr) $stdout.reopen(@orgout) end def self::message(*s) @log ||= File::open(@logfile, 'w') @log.sync = true @log.printf(*s) end def self::logfile file @logfile = file if @log and not @log.closed? @log.flush @log.close @log = nil end end def self::postpone tmplog = "mkmftmp#{@postpone += 1}.log" open do log, *save = @log, @logfile, @orgout, @orgerr @log, @logfile, @orgout, @orgerr = nil, tmplog, log, log begin log.print(open {yield}) @log.close File::open(tmplog) {|t| FileUtils.copy_stream(t, log)} ensure @log, @logfile, @orgout, @orgerr = log, *save @postpone -= 1 rm_f tmplog end end end class << self attr_accessor :quiet end end def xsystem command varpat = /\$\((\w+)\)|\$\{(\w+)\}/ if varpat =~ command vars = Hash.new {|h, k| h[k] = ''; ENV[k]} command = command.dup nil while command.gsub!(varpat) {vars[$1||$2]} end Logging::open do puts command.quote system(command) end end def xpopen command, *mode, &block Logging::open do case mode[0] when nil, /^r/ puts "#{command} |" else puts "| #{command}" end IO.popen(command, *mode, &block) end end def log_src(src) src = src.split(/^/) fmt = "%#{src.size.to_s.size}d: %s" Logging::message <<"EOM" checked program was: /* begin */ EOM src.each_with_index {|line, no| Logging::message fmt, no+1, line} Logging::message <<"EOM" /* end */ EOM end def create_tmpsrc(src) src = yield(src) if block_given? src = src.gsub(/[ \t]+$/, '').gsub(/\A\n+|^\n+$/, '').sub(/[^\n]\z/, "\\&\n") open(CONFTEST_C, "wb") do |cfile| cfile.print src end src end def try_do(src, command, &b) src = create_tmpsrc(src, &b) xsystem(command) ensure log_src(src) end def link_command(ldflags, opt="", libpath=$DEFLIBPATH|$LIBPATH) conf = Config::CONFIG.merge('hdrdir' => $hdrdir.quote, 'src' => CONFTEST_C, 'INCFLAGS' => $INCFLAGS, 'CPPFLAGS' => $CPPFLAGS, 'CFLAGS' => "#$CFLAGS", 'ARCH_FLAG' => "#$ARCH_FLAG", 'LDFLAGS' => "#$LDFLAGS #{ldflags}", 'LIBPATH' => libpathflag(libpath), 'LOCAL_LIBS' => "#$LOCAL_LIBS #$libs", 'LIBS' => "#$LIBRUBYARG_STATIC #{opt} #$LIBS") Config::expand(TRY_LINK.dup, conf) end def cc_command(opt="") conf = Config::CONFIG.merge('hdrdir' => $hdrdir.quote, 'srcdir' => $srcdir.quote) Config::expand("$(CC) #$INCFLAGS #$CPPFLAGS #$CFLAGS #$ARCH_FLAG #{opt} -c #{CONFTEST_C}", conf) end def cpp_command(outfile, opt="") conf = Config::CONFIG.merge('hdrdir' => $hdrdir.quote, 'srcdir' => $srcdir.quote) Config::expand("$(CPP) #$INCFLAGS #$CPPFLAGS #$CFLAGS #{opt} #{CONFTEST_C} #{outfile}", conf) end def libpathflag(libpath=$DEFLIBPATH|$LIBPATH) libpath.map{|x| case x when "$(topdir)", /\A\./ LIBPATHFLAG else LIBPATHFLAG+RPATHFLAG end % x.quote }.join end def try_link0(src, opt="", &b) try_do(src, link_command("", opt), &b) end def try_link(src, opt="", &b) try_link0(src, opt, &b) ensure rm_f "conftest*", "c0x32*" end def try_compile(src, opt="", &b) try_do(src, cc_command(opt), &b) ensure rm_f "conftest*" end def try_cpp(src, opt="", &b) try_do(src, cpp_command(CPPOUTFILE, opt), &b) ensure rm_f "conftest*" end def cpp_include(header) if header header = [header] unless header.kind_of? Array header.map {|h| "#include <#{h}>\n"}.join else "" end end def with_cppflags(flags) cppflags = $CPPFLAGS $CPPFLAGS = flags ret = yield ensure $CPPFLAGS = cppflags unless ret end def with_cflags(flags) cflags = $CFLAGS $CFLAGS = flags ret = yield ensure $CFLAGS = cflags unless ret end def with_ldflags(flags) ldflags = $LDFLAGS $LDFLAGS = flags ret = yield ensure $LDFLAGS = ldflags unless ret end def try_static_assert(expr, headers = nil, opt = "", &b) headers = cpp_include(headers) try_compile(< 0", headers, opt) # positive constant elsif try_static_assert("#{const} < 0", headers, opt) neg = true const = "-(#{const})" elsif try_static_assert("#{const} == 0", headers, opt) return 0 else # not a constant return nil end upper = 1 lower = 0 until try_static_assert("#{const} <= #{upper}", headers, opt) lower = upper upper <<= 1 end return nil unless lower while upper > lower + 1 mid = (upper + lower) / 2 if try_static_assert("#{const} > #{mid}", headers, opt) lower = mid else upper = mid end end upper = -upper if neg return upper else src = %{#{COMMON_HEADERS} #{includes} #include /*top*/ int conftest_const = (int)(#{const}); int main() {printf("%d\\n", conftest_const); return 0;} } if try_link0(src, opt, &b) xpopen("./conftest") do |f| return Integer(f.gets) end end end nil end def try_func(func, libs, headers = nil, &b) headers = cpp_include(headers) try_link(<<"SRC", libs, &b) or try_link(<<"SRC", libs, &b) #{COMMON_HEADERS} #{headers} /*top*/ int main() { return 0; } int t() { void ((*volatile p)()); p = (void ((*)()))#{func}; return 0; } SRC #{headers} /*top*/ int main() { return 0; } int t() { #{func}(); return 0; } SRC end def try_var(var, headers = nil, &b) headers = cpp_include(headers) try_compile(<<"SRC", &b) #{COMMON_HEADERS} #{headers} /*top*/ int main() { return 0; } int t() { const volatile void *volatile p; p = &(&#{var})[0]; return 0; } SRC end def egrep_cpp(pat, src, opt = "", &b) src = create_tmpsrc(src, &b) xpopen(cpp_command('', opt)) do |f| if Regexp === pat puts(" ruby -ne 'print if #{pat.inspect}'") f.grep(pat) {|l| puts "#{f.lineno}: #{l}" return true } false else puts(" egrep '#{pat}'") begin stdin = $stdin.dup $stdin.reopen(f) system("egrep", pat) ensure $stdin.reopen(stdin) end end end ensure rm_f "conftest*" log_src(src) end # This is used internally by the have_macro? method. def macro_defined?(macro, src, opt = "", &b) src = src.sub(/[^\n]\z/, "\\&\n") try_compile(src + <<"SRC", opt, &b) /*top*/ #ifndef #{macro} # error >>>>>> #{macro} undefined <<<<<< #endif SRC end def try_run(src, opt = "", &b) if try_link0(src, opt, &b) xsystem("./conftest") else nil end ensure rm_f "conftest*" end def install_files(mfile, ifiles, map = nil, srcprefix = nil) ifiles or return ifiles.empty? and return srcprefix ||= '$(srcdir)' Config::expand(srcdir = srcprefix.dup) dirs = [] path = Hash.new {|h, i| h[i] = dirs.push([i])[-1]} ifiles.each do |files, dir, prefix| dir = map_dir(dir, map) prefix &&= %r|\A#{Regexp.quote(prefix)}/?| if /\A\.\// =~ files # install files which are in current working directory. files = files[2..-1] len = nil else # install files which are under the $(srcdir). files = File.join(srcdir, files) len = srcdir.size end f = nil Dir.glob(files) do |f| f[0..len] = "" if len case File.basename(f) when *$NONINSTALLFILES next end d = File.dirname(f) d.sub!(prefix, "") if prefix d = (d.empty? || d == ".") ? dir : File.join(dir, d) f = File.join(srcprefix, f) if len path[d] << f end unless len or f d = File.dirname(files) d.sub!(prefix, "") if prefix d = (d.empty? || d == ".") ? dir : File.join(dir, d) path[d] << files end end dirs end def install_rb(mfile, dest, srcdir = nil) install_files(mfile, [["lib/**/*.rb", dest, "lib"]], nil, srcdir) end def append_library(libs, lib) # :no-doc: format(LIBARG, lib) + " " + libs end def message(*s) unless Logging.quiet and not $VERBOSE printf(*s) $stdout.flush end end # This emits a string to stdout that allows users to see the results of the # various have* and find* methods as they are tested. # # Internal use only. # def checking_for(m, fmt = nil) f = caller[0][/in `(.*)'$/, 1] and f << ": " #` for vim m = "checking #{/\Acheck/ =~ f ? '' : 'for '}#{m}... " message "%s", m a = r = nil Logging::postpone do r = yield a = (fmt ? fmt % r : r ? "yes" : "no") << "\n" "#{f}#{m}-------------------- #{a}\n" end message(a) Logging::message "--------------------\n\n" r end def checking_message(target, place = nil, opt = nil) [["in", place], ["with", opt]].inject("#{target}") do |msg, (pre, noun)| if noun [[:to_str], [:join, ","], [:to_s]].each do |meth, *args| if noun.respond_to?(meth) break noun = noun.send(meth, *args) end end msg << " #{pre} #{noun}" unless noun.empty? end msg end end # :startdoc: # Returns whether or not +macro+ is defined either in the common header # files or within any +headers+ you provide. # # Any options you pass to +opt+ are passed along to the compiler. # def have_macro(macro, headers = nil, opt = "", &b) checking_for checking_message(macro, headers, opt) do macro_defined?(macro, cpp_include(headers), opt, &b) end end # Returns whether or not the given entry point +func+ can be found within # +lib+. If +func+ is nil, the 'main()' entry point is used by default. # If found, it adds the library to list of libraries to be used when linking # your extension. # # If +headers+ are provided, it will include those header files as the # header files it looks in when searching for +func+. # # The real name of the library to be linked can be altered by # '--with-FOOlib' configuration option. # def have_library(lib, func = nil, headers = nil, &b) func = "main" if !func or func.empty? lib = with_config(lib+'lib', lib) checking_for checking_message("#{func}()", LIBARG%lib) do if COMMON_LIBS.include?(lib) true else libs = append_library($libs, lib) if try_func(func, libs, headers, &b) $libs = libs true else false end end end end # Returns whether or not the entry point +func+ can be found within the library # +lib+ in one of the +paths+ specified, where +paths+ is an array of strings. # If +func+ is nil , then the main() function is used as the entry point. # # If +lib+ is found, then the path it was found on is added to the list of # library paths searched and linked against. # def find_library(lib, func, *paths, &b) func = "main" if !func or func.empty? lib = with_config(lib+'lib', lib) paths = paths.collect {|path| path.split(File::PATH_SEPARATOR)}.flatten checking_for "#{func}() in #{LIBARG%lib}" do libpath = $LIBPATH libs = append_library($libs, lib) begin until r = try_func(func, libs, &b) or paths.empty? $LIBPATH = libpath | [paths.shift] end if r $libs = libs libpath = nil end ensure $LIBPATH = libpath if libpath end r end end # Returns whether or not the function +func+ can be found in the common # header files, or within any +headers+ that you provide. If found, a # macro is passed as a preprocessor constant to the compiler using the # function name, in uppercase, prepended with 'HAVE_'. # # For example, if have_func('foo') returned true, then the HAVE_FOO # preprocessor macro would be passed to the compiler. # def have_func(func, headers = nil, &b) checking_for checking_message("#{func}()", headers) do if try_func(func, $libs, headers, &b) $defs.push(format("-DHAVE_%s", func.tr_cpp)) true else false end end end # Returns whether or not the variable +var+ can be found in the common # header files, or within any +headers+ that you provide. If found, a # macro is passed as a preprocessor constant to the compiler using the # variable name, in uppercase, prepended with 'HAVE_'. # # For example, if have_var('foo') returned true, then the HAVE_FOO # preprocessor macro would be passed to the compiler. # def have_var(var, headers = nil, &b) checking_for checking_message(var, headers) do if try_var(var, headers, &b) $defs.push(format("-DHAVE_%s", var.tr_cpp)) true else false end end end # Returns whether or not the given +header+ file can be found on your system. # If found, a macro is passed as a preprocessor constant to the compiler using # the header file name, in uppercase, prepended with 'HAVE_'. # # For example, if have_header('foo.h') returned true, then the HAVE_FOO_H # preprocessor macro would be passed to the compiler. # def have_header(header, &b) checking_for header do if try_cpp(cpp_include(header), &b) $defs.push(format("-DHAVE_%s", header.tr("a-z./\055", "A-Z___"))) true else false end end end # Instructs mkmf to search for the given +header+ in any of the +paths+ # provided, and returns whether or not it was found in those paths. # # If the header is found then the path it was found on is added to the list # of included directories that are sent to the compiler (via the -I switch). # def find_header(header, *paths) message = checking_message(header, paths) header = cpp_include(header) checking_for message do if try_cpp(header) true else found = false paths.each do |dir| opt = "-I#{dir}".quote if try_cpp(header, opt) $INCFLAGS << " " << opt found = true break end end found end end end # Returns whether or not the struct of type +type+ contains +member+. If # it does not, or the struct type can't be found, then false is returned. You # may optionally specify additional +headers+ in which to look for the struct # (in addition to the common header files). # # If found, a macro is passed as a preprocessor constant to the compiler using # the member name, in uppercase, prepended with 'HAVE_ST_'. # # For example, if have_struct_member('struct foo', 'bar') returned true, then the # HAVE_ST_BAR preprocessor macro would be passed to the compiler. # def have_struct_member(type, member, headers = nil, &b) checking_for checking_message("#{type}.#{member}", headers) do if try_compile(<<"SRC", &b) #{COMMON_HEADERS} #{cpp_include(headers)} /*top*/ int main() { return 0; } int s = (char *)&((#{type}*)0)->#{member} - (char *)0; SRC $defs.push(format("-DHAVE_ST_%s", member.tr_cpp)) true else false end end end def try_type(type, headers = nil, opt = "", &b) if try_compile(<<"SRC", opt, &b) #{COMMON_HEADERS} #{cpp_include(headers)} /*top*/ typedef #{type} conftest_type; int conftestval[sizeof(conftest_type)?1:-1]; SRC $defs.push(format("-DHAVE_TYPE_%s", type.tr_cpp)) true else false end end # Returns whether or not the static type +type+ is defined. You may # optionally pass additional +headers+ to check against in addition to the # common header files. # # You may also pass additional flags to +opt+ which are then passed along to # the compiler. # # If found, a macro is passed as a preprocessor constant to the compiler using # the type name, in uppercase, prepended with 'HAVE_TYPE_'. # # For example, if have_type('foo') returned true, then the HAVE_TYPE_FOO # preprocessor macro would be passed to the compiler. # def have_type(type, headers = nil, opt = "", &b) checking_for checking_message(type, headers, opt) do try_type(type, headers, opt, &b) end end # Returns where the static type +type+ is defined. # # You may also pass additional flags to +opt+ which are then passed along to # the compiler. # # See also +have_type+. # def find_type(type, opt, *headers, &b) opt ||= "" fmt = "not found" def fmt.%(x) x ? x.respond_to?(:join) ? x.join(",") : x : self end checking_for checking_message(type, nil, opt), fmt do headers.find do |h| try_type(type, h, opt, &b) end end end def try_const(const, headers = nil, opt = "", &b) const, type = *const if try_compile(<<"SRC", opt, &b) #{COMMON_HEADERS} #{cpp_include(headers)} /*top*/ typedef #{type || 'int'} conftest_type; conftest_type conftestval = #{type ? '' : '(int)'}#{const}; SRC $defs.push(format("-DHAVE_CONST_%s", const.tr_cpp)) true else false end end # Returns whether or not the constant +const+ is defined. You may # optionally pass the +type+ of +const+ as [const, type], # like as: # # have_const(%w[PTHREAD_MUTEX_INITIALIZER pthread_mutex_t], "pthread.h") # # You may also pass additional +headers+ to check against in addition # to the common header files, and additional flags to +opt+ which are # then passed along to the compiler. # # If found, a macro is passed as a preprocessor constant to the compiler using # the type name, in uppercase, prepended with 'HAVE_CONST_'. # # For example, if have_const('foo') returned true, then the HAVE_CONST_FOO # preprocessor macro would be passed to the compiler. # def have_const(const, headers = nil, opt = "", &b) checking_for checking_message([*const].compact.join(' '), headers, opt) do try_const(const, headers, opt, &b) end end # Returns the size of the given +type+. You may optionally specify additional # +headers+ to search in for the +type+. # # If found, a macro is passed as a preprocessor constant to the compiler using # the type name, in uppercase, prepended with 'SIZEOF_', followed by the type # name, followed by '=X' where 'X' is the actual size. # # For example, if check_sizeof('mystruct') returned 12, then the # SIZEOF_MYSTRUCT=12 preprocessor macro would be passed to the compiler. # def check_sizeof(type, headers = nil, &b) expr = "sizeof(#{type})" fmt = "%d" def fmt.%(x) x ? super : "failed" end checking_for checking_message("size of #{type}", headers), fmt do if size = try_constant(expr, headers, &b) $defs.push(format("-DSIZEOF_%s=%d", type.tr_cpp, size)) size end end end # :stopdoc: # Used internally by the what_type? method to determine if +type+ is a scalar # pointer. def scalar_ptr_type?(type, member = nil, headers = nil, &b) try_compile(<<"SRC", &b) # pointer #{COMMON_HEADERS} #{cpp_include(headers)} /*top*/ volatile #{type} conftestval; int main() { return 0; } int t() {return (int)(1-*(conftestval#{member ? ".#{member}" : ""}));} SRC end # Used internally by the what_type? method to determine if +type+ is a scalar # pointer. def scalar_type?(type, member = nil, headers = nil, &b) try_compile(<<"SRC", &b) # pointer #{COMMON_HEADERS} #{cpp_include(headers)} /*top*/ volatile #{type} conftestval; int main() { return 0; } int t() {return (int)(1-(conftestval#{member ? ".#{member}" : ""}));} SRC end def what_type?(type, member = nil, headers = nil, &b) m = "#{type}" name = type if member m << "." << member name = "(((#{type} *)0)->#{member})" end fmt = "seems %s" def fmt.%(x) x ? super : "unknown" end checking_for checking_message(m, headers), fmt do if scalar_ptr_type?(type, member, headers, &b) if try_static_assert("sizeof(*#{name}) == 1", headers) "string" end elsif scalar_type?(type, member, headers, &b) if try_static_assert("sizeof(#{name}) > sizeof(long)", headers) "long long" elsif try_static_assert("sizeof(#{name}) > sizeof(int)", headers) "long" elsif try_static_assert("sizeof(#{name}) > sizeof(short)", headers) "int" elsif try_static_assert("sizeof(#{name}) > 1", headers) "short" else "char" end end end end # This method is used internally by the find_executable method. # # Internal use only. # def find_executable0(bin, path = nil) ext = config_string('EXEEXT') if File.expand_path(bin) == bin return bin if File.executable?(bin) ext and File.executable?(file = bin + ext) and return file return nil end if path ||= ENV['PATH'] path = path.split(File::PATH_SEPARATOR) else path = %w[/usr/local/bin /usr/ucb /usr/bin /bin] end file = nil path.each do |dir| return file if File.executable?(file = File.join(dir, bin)) return file if ext and File.executable?(file << ext) end nil end # :startdoc: # Searches for the executable +bin+ on +path+. The default path is your # PATH environment variable. If that isn't defined, it will resort to # searching /usr/local/bin, /usr/ucb, /usr/bin and /bin. # # If found, it will return the full path, including the executable name, # of where it was found. # # Note that this method does not actually affect the generated Makefile. # def find_executable(bin, path = nil) checking_for checking_message(bin, path) do find_executable0(bin, path) end end # :stopdoc: def arg_config(config, *defaults, &block) $arg_config << [config, *defaults] defaults << nil if !block and defaults.empty? $configure_args.fetch(config.tr('_', '-'), *defaults, &block) end # :startdoc: # Tests for the presence of a --with-config or --without-config # option. Returns true if the with option is given, false if the without # option is given, and the default value otherwise. # # This can be useful for adding custom definitions, such as debug information. # # Example: # # if with_config("debug") # $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG" # end # def with_config(config, *defaults) config = config.sub(/^--with[-_]/, '') val = arg_config("--with-"+config) do if arg_config("--without-"+config) false elsif block_given? yield(config, *defaults) else break *defaults end end case val when "yes" true when "no" false else val end end # Tests for the presence of an --enable-config or # --disable-config option. Returns true if the enable option is given, # false if the disable option is given, and the default value otherwise. # # This can be useful for adding custom definitions, such as debug information. # # Example: # # if enable_config("debug") # $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG" # end # def enable_config(config, *defaults) if arg_config("--enable-"+config) true elsif arg_config("--disable-"+config) false elsif block_given? yield(config, *defaults) else return *defaults end end # Generates a header file consisting of the various macro definitions generated # by other methods such as have_func and have_header. These are then wrapped in # a custom #ifndef based on the +header+ file name, which defaults to # 'extconf.h'. # # For example: # # # extconf.rb # require 'mkmf' # have_func('realpath') # have_header('sys/utime.h') # create_header # create_makefile('foo') # # The above script would generate the following extconf.h file: # # #ifndef EXTCONF_H # #define EXTCONF_H # #define HAVE_REALPATH 1 # #define HAVE_SYS_UTIME_H 1 # #endif # # Given that the create_header method generates a file based on definitions # set earlier in your extconf.rb file, you will probably want to make this # one of the last methods you call in your script. # def create_header(header = "extconf.h") message "creating %s\n", header sym = header.tr("a-z./\055", "A-Z___") hdr = ["#ifndef #{sym}\n#define #{sym}\n"] for line in $defs case line when /^-D([^=]+)(?:=(.*))?/ hdr << "#define #$1 #{$2 ? Shellwords.shellwords($2)[0] : 1}\n" when /^-U(.*)/ hdr << "#undef #$1\n" end end hdr << "#endif\n" hdr = hdr.join unless (IO.read(header) == hdr rescue false) open(header, "w") do |hfile| hfile.write(hdr) end end $extconf_h = header end # Sets a +target+ name that the user can then use to configure various 'with' # options with on the command line by using that name. For example, if the # target is set to "foo", then the user could use the --with-foo-dir command # line option. # # You may pass along additional 'include' or 'lib' defaults via the +idefault+ # and +ldefault+ parameters, respectively. # # Note that dir_config only adds to the list of places to search for libraries # and include files. It does not link the libraries into your application. # def dir_config(target, idefault=nil, ldefault=nil) if dir = with_config(target + "-dir", (idefault unless ldefault)) defaults = Array === dir ? dir : dir.split(File::PATH_SEPARATOR) idefault = ldefault = nil end idir = with_config(target + "-include", idefault) $arg_config.last[1] ||= "${#{target}-dir}/include" ldir = with_config(target + "-lib", ldefault) $arg_config.last[1] ||= "${#{target}-dir}/lib" idirs = idir ? Array === idir ? idir : idir.split(File::PATH_SEPARATOR) : [] if defaults idirs.concat(defaults.collect {|dir| dir + "/include"}) idir = ([idir] + idirs).compact.join(File::PATH_SEPARATOR) end unless idirs.empty? idirs.collect! {|dir| "-I" + dir} idirs -= Shellwords.shellwords($CPPFLAGS) unless idirs.empty? $CPPFLAGS = (idirs.quote << $CPPFLAGS).join(" ") end end ldirs = ldir ? Array === ldir ? ldir : ldir.split(File::PATH_SEPARATOR) : [] if defaults ldirs.concat(defaults.collect {|dir| dir + "/lib"}) ldir = ([ldir] + ldirs).compact.join(File::PATH_SEPARATOR) end $LIBPATH = ldirs | $LIBPATH [idir, ldir] end # :stopdoc: # Handles meta information about installed libraries. Uses your platform's # pkg-config program if it has one. def pkg_config(pkg) if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig) # iff package specific config command is given get = proc {|opt| `#{pkgconfig} --#{opt}`.chomp} elsif ($PKGCONFIG ||= (pkgconfig = with_config("pkg-config", ("pkg-config" unless CROSS_COMPILING))) && find_executable0(pkgconfig) && pkgconfig) and system("#{$PKGCONFIG} --exists #{pkg}") # default to pkg-config command get = proc {|opt| `#{$PKGCONFIG} --#{opt} #{pkg}`.chomp} elsif find_executable0(pkgconfig = "#{pkg}-config") # default to package specific config command, as a last resort. get = proc {|opt| `#{pkgconfig} --#{opt}`.chomp} end if get cflags = get['cflags'] ldflags = get['libs'] libs = get['libs-only-l'] ldflags = (Shellwords.shellwords(ldflags) - Shellwords.shellwords(libs)).quote.join(" ") $CFLAGS += " " << cflags $LDFLAGS += " " << ldflags $libs += " " << libs Logging::message "package configuration for %s\n", pkg Logging::message "cflags: %s\nldflags: %s\nlibs: %s\n\n", cflags, ldflags, libs [cflags, ldflags, libs] else Logging::message "package configuration for %s is not found\n", pkg nil end end def with_destdir(dir) dir = dir.sub($dest_prefix_pattern, '') /\A\$[\(\{]/ =~ dir ? dir : "$(DESTDIR)"+dir end # Converts forward slashes to backslashes. Aimed at MS Windows. # # Internal use only. # def winsep(s) s.tr('/', '\\') end # Converts native path to format acceptable in Makefile # # Internal use only. # if !CROSS_COMPILING case CONFIG['build_os'] when 'mingw32' def mkintpath(path) # mingw uses make from msys and it needs special care # converts from C:\some\path to /C/some/path path = path.dup path.tr!('\\', '/') path.sub!(/\A([A-Za-z]):(?=\/)/, '/\1') path end end end unless defined?(mkintpath) def mkintpath(path) path end end def configuration(srcdir) mk = [] vpath = %w[$(srcdir) $(topdir) $(hdrdir)] if !CROSS_COMPILING case CONFIG['build_os'] when 'cygwin' if CONFIG['target_os'] != 'cygwin' vpath.each {|p| p.sub!(/.*/, '$(shell cygpath -u \&)')} end when 'msdosdjgpp' CONFIG['PATH_SEPARATOR'] = ';' end end mk << %{ SHELL = /bin/sh #### Start of system configuration section. #### #{ if $extmk "top_srcdir = " + $top_srcdir.sub(%r"\A#{Regexp.quote($topdir)}/", "$(topdir)/") end } srcdir = #{srcdir.gsub(/\$\((srcdir)\)|\$\{(srcdir)\}/) {mkintpath(CONFIG[$1||$2])}.quote} topdir = #{mkintpath($extmk ? CONFIG["topdir"] : $topdir).quote} hdrdir = #{$extmk ? mkintpath(CONFIG["hdrdir"]).quote : '$(topdir)'} VPATH = #{vpath.join(CONFIG['PATH_SEPARATOR'])} } if $extmk mk << "RUBYLIB = -\nRUBYOPT = -rpurelib.rb\n" end if destdir = CONFIG["prefix"][$dest_prefix_pattern, 1] mk << "\nDESTDIR = #{destdir}\n" end CONFIG.each do |key, var| next unless /prefix$/ =~ key mk << "#{key} = #{with_destdir(var)}\n" end CONFIG.each do |key, var| next if /^abs_/ =~ key next unless /^(?:src|top|hdr|(.*))dir$/ =~ key and $1 mk << "#{key} = #{with_destdir(var)}\n" end if !$extmk and !$configure_args.has_key?('--ruby') and sep = config_string('BUILD_FILE_SEPARATOR') sep = ":/=#{sep}" else sep = "" end extconf_h = $extconf_h ? "-DRUBY_EXTCONF_H=\\\"$(RUBY_EXTCONF_H)\\\" " : $defs.join(" ")<<" " mk << %{ CC = #{CONFIG['CC']} LIBRUBY = #{CONFIG['LIBRUBY']} LIBRUBY_A = #{CONFIG['LIBRUBY_A']} LIBRUBYARG_SHARED = #$LIBRUBYARG_SHARED LIBRUBYARG_STATIC = #$LIBRUBYARG_STATIC RUBY_EXTCONF_H = #{$extconf_h} CFLAGS = #{$static ? '' : CONFIG['CCDLFLAGS']} #$CFLAGS #$ARCH_FLAG INCFLAGS = -I. #$INCFLAGS DEFS = #{CONFIG['DEFS']} CPPFLAGS = #{extconf_h}#{$CPPFLAGS} CXXFLAGS = $(CFLAGS) #{CONFIG['CXXFLAGS']} ldflags = #{$LDFLAGS} dldflags = #{$DLDFLAGS} archflag = #{$ARCH_FLAG} DLDFLAGS = $(ldflags) $(dldflags) $(archflag) LDSHARED = #{CONFIG['LDSHARED']} AR = #{CONFIG['AR']} EXEEXT = #{CONFIG['EXEEXT']} RUBY_INSTALL_NAME = #{CONFIG['RUBY_INSTALL_NAME']} RUBY_SO_NAME = #{CONFIG['RUBY_SO_NAME']} arch = #{CONFIG['arch']} sitearch = #{CONFIG['sitearch']} ruby_version = #{Config::CONFIG['ruby_version']} ruby = #{$ruby} RUBY = $(ruby#{sep}) RM = #{config_string('RM') || '$(RUBY) -run -e rm -- -f'} MAKEDIRS = #{config_string('MAKEDIRS') || '@$(RUBY) -run -e mkdir -- -p'} INSTALL = #{config_string('INSTALL') || '@$(RUBY) -run -e install -- -vp'} INSTALL_PROG = #{config_string('INSTALL_PROG') || '$(INSTALL) -m 0755'} INSTALL_DATA = #{config_string('INSTALL_DATA') || '$(INSTALL) -m 0644'} COPY = #{config_string('CP') || '@$(RUBY) -run -e cp -- -v'} #### End of system configuration section. #### preload = #{$preload ? $preload.join(' ') : ''} } if $nmake == ?b mk.each do |x| x.gsub!(/^(MAKEDIRS|INSTALL_(?:PROG|DATA))+\s*=.*\n/) do "!ifndef " + $1 + "\n" + $& + "!endif\n" end end end mk end def dummy_makefile(srcdir) configuration(srcdir) << <>$(INSTALLED_LIST)\n" end end else mfile.puts "Makefile" end mfile.print("install-rb: pre-install-rb install-rb-default\n") mfile.print("install-rb-default: pre-install-rb-default\n") mfile.print("pre-install-rb: Makefile\n") mfile.print("pre-install-rb-default: Makefile\n") for sfx, i in [["-default", [["lib/**/*.rb", "$(RUBYLIBDIR)", "lib"]]], ["", $INSTALLFILES]] files = install_files(mfile, i, nil, srcprefix) or next for dir, *files in files unless dirs.include?(dir) dirs << dir mfile.print "pre-install-rb#{sfx}: #{dir}\n" end files.each do |f| dest = "#{dir}/#{File.basename(f)}" mfile.print("install-rb#{sfx}: #{dest}\n") mfile.print("#{dest}: #{f} #{dir}\n\t$(#{$extout ? 'COPY' : 'INSTALL_DATA'}) ") sep = config_string('BUILD_FILE_SEPARATOR') if sep f = f.gsub("/", sep) sep = ":/="+sep f = f.gsub(/(\$\(\w+)(\))/) {$1+sep+$2} f = f.gsub(/(\$\{\w+)(\})/) {$1+sep+$2} else sep = "" end mfile.print("#{f} $(@D#{sep})\n") if defined?($installed_list) and !$extout mfile.print("\t@echo #{dest}>>$(INSTALLED_LIST)\n") end end end end dirs.unshift(sodir) if target and !dirs.include?(sodir) dirs.each {|dir| mfile.print "#{dir}:\n\t$(MAKEDIRS) $@\n"} mfile.print <<-SITEINSTALL site-install: site-install-so site-install-rb site-install-so: install-so site-install-rb: install-rb SITEINSTALL return unless target mfile.puts SRC_EXT.collect {|ext| ".path.#{ext} = $(VPATH)"} if $nmake == ?b mfile.print ".SUFFIXES: .#{SRC_EXT.join(' .')} .#{$OBJEXT}\n" mfile.print "\n" CXX_EXT.each do |ext| COMPILE_RULES.each do |rule| mfile.printf(rule, ext, $OBJEXT) mfile.printf("\n\t%s\n\n", COMPILE_CXX) end end %w[c].each do |ext| COMPILE_RULES.each do |rule| mfile.printf(rule, ext, $OBJEXT) mfile.printf("\n\t%s\n\n", COMPILE_C) end end mfile.print "$(RUBYARCHDIR)/" if $extout mfile.print "$(DLLIB): " mfile.print "$(DEFFILE) " if makedef mfile.print "$(OBJS) Makefile\n" mfile.print "\t@-$(RM) $@\n" mfile.print "\t@-$(MAKEDIRS) $(@D)\n" if $extout link_so = LINK_SO.gsub(/^/, "\t") mfile.print link_so, "\n\n" unless $static.nil? mfile.print "$(STATIC_LIB): $(OBJS)\n\t" mfile.print "$(AR) #{config_string('ARFLAGS') || 'cru '}$@ $(OBJS)" config_string('RANLIB') do |ranlib| mfile.print "\n\t@-#{ranlib} $(DLLIB) 2> /dev/null || true" end end mfile.print "\n\n" if makedef mfile.print "$(DEFFILE): #{origdef}\n" mfile.print "\t$(RUBY) #{makedef} #{origdef} > $@\n\n" end depend = File.join(srcdir, "depend") if File.exist?(depend) suffixes = [] depout = [] open(depend, "r") do |dfile| mfile.printf "###\n" cont = implicit = nil impconv = proc do COMPILE_RULES.each {|rule| depout << (rule % implicit[0]) << implicit[1]} implicit = nil end ruleconv = proc do |line| if implicit if /\A\t/ =~ line implicit[1] << line next else impconv[] end end if m = /\A\.(\w+)\.(\w+)(?:\s*:)/.match(line) suffixes << m[1] << m[2] implicit = [[m[1], m[2]], [m.post_match]] next elsif RULE_SUBST and /\A(?!\s*\w+\s*=)[$\w][^#]*:/ =~ line line.gsub!(%r"(\s)(?!\.)([^$(){}+=:\s\/\\,]+)(?=\s|\z)") {$1 + RULE_SUBST % $2} end depout << line end while line = dfile.gets() line.gsub!(/\.o\b/, ".#{$OBJEXT}") line.gsub!(/\$\((?:hdr|top)dir\)\/config.h/, $config_h) if $config_h if /(?:^|[^\\])(?:\\\\)*\\$/ =~ line (cont ||= []) << line next elsif cont line = (cont << line).join cont = nil end ruleconv.call(line) end if cont ruleconv.call(cont.join) elsif implicit impconv.call end end unless suffixes.empty? mfile.print ".SUFFIXES: .", suffixes.uniq.join(" ."), "\n\n" end mfile.print "$(OBJS): $(RUBY_EXTCONF_H)\n\n" if $extconf_h mfile.print depout else headers = %w[ruby.h defines.h] if RULE_SUBST headers.each {|h| h.sub!(/.*/) {|*m| RULE_SUBST % m}} end headers << $config_h if $config_h headers << "$(RUBY_EXTCONF_H)" if $extconf_h mfile.print "$(OBJS): ", headers.join(' '), "\n" end $makefile_created = true ensure mfile.close if mfile end # :stopdoc: def init_mkmf(config = CONFIG) $makefile_created = false $arg_config = [] $enable_shared = config['ENABLE_SHARED'] == 'yes' $defs = [] $extconf_h = nil $CFLAGS = with_config("cflags", arg_config("CFLAGS", config["CFLAGS"])).dup $ARCH_FLAG = with_config("arch_flag", arg_config("ARCH_FLAG", config["ARCH_FLAG"])).dup $CPPFLAGS = with_config("cppflags", arg_config("CPPFLAGS", config["CPPFLAGS"])).dup $LDFLAGS = with_config("ldflags", arg_config("LDFLAGS", config["LDFLAGS"])).dup $INCFLAGS = "-I$(topdir) -I$(hdrdir) -I$(srcdir)" $DLDFLAGS = with_config("dldflags", arg_config("DLDFLAGS", config["DLDFLAGS"])).dup $LIBEXT = config['LIBEXT'].dup $OBJEXT = config["OBJEXT"].dup $LIBS = "#{config['LIBS']} #{config['DLDLIBS']}" $LIBRUBYARG = "" $LIBRUBYARG_STATIC = config['LIBRUBYARG_STATIC'] $LIBRUBYARG_SHARED = config['LIBRUBYARG_SHARED'] $DEFLIBPATH = [$extmk ? "$(topdir)" : "$(libdir)"] $DEFLIBPATH.unshift(".") $LIBPATH = [] $INSTALLFILES = [] $NONINSTALLFILES = [/~\z/, /\A#.*#\z/, /\A\.#/, /\.bak\z/i, /\.orig\z/, /\.rej\z/, /\.l[ao]\z/, /\.o\z/] $objs = nil $srcs = nil $libs = "" if $enable_shared or Config.expand(config["LIBRUBY"].dup) != Config.expand(config["LIBRUBY_A"].dup) $LIBRUBYARG = config['LIBRUBYARG'] end $LOCAL_LIBS = "" $cleanfiles = config_string('CLEANFILES') {|s| Shellwords.shellwords(s)} || [] $cleanfiles << "mkmf.log" $distcleanfiles = config_string('DISTCLEANFILES') {|s| Shellwords.shellwords(s)} || [] $extout ||= nil $extout_prefix ||= nil $arg_config.clear dir_config("opt") end FailedMessage = <"} end COMMON_HEADERS = hdr.join("\n") COMMON_LIBS = config_string('COMMON_LIBS', &split) || [] COMPILE_RULES = config_string('COMPILE_RULES', &split) || %w[.%s.%s:] RULE_SUBST = config_string('RULE_SUBST') COMPILE_C = config_string('COMPILE_C') || '$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<' COMPILE_CXX = config_string('COMPILE_CXX') || '$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<' TRY_LINK = config_string('TRY_LINK') || "$(CC) #{OUTFLAG}conftest $(INCFLAGS) $(CPPFLAGS) " \ "$(CFLAGS) $(src) $(LIBPATH) $(LDFLAGS) $(ARCH_FLAG) $(LOCAL_LIBS) $(LIBS)" LINK_SO = config_string('LINK_SO') || if CONFIG["DLEXT"] == $OBJEXT "ld $(DLDFLAGS) -r -o $@ $(OBJS)\n" else "$(LDSHARED) #{OUTFLAG}$@ $(OBJS) " \ "$(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)" end LIBPATHFLAG = config_string('LIBPATHFLAG') || ' -L"%s"' RPATHFLAG = config_string('RPATHFLAG') || '' LIBARG = config_string('LIBARG') || '-l%s' sep = config_string('BUILD_FILE_SEPARATOR') {|sep| ":/=#{sep}" if sep != "/"} || "" CLEANINGS = " clean: @-$(RM) $(CLEANLIBS#{sep}) $(CLEANOBJS#{sep}) $(CLEANFILES#{sep}) distclean: clean @-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log @-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES#{sep}) realclean: distclean " if not $extmk and /\A(extconf|makefile).rb\z/ =~ File.basename($0) END {mkmf_failed($0)} end PK|]H&xsd/codegen.rbnu[# XSD4R - Generating code library # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'xsd/codegen/moduledef' require 'xsd/codegen/classdef' require 'xsd/codegen/methoddef' PK|]@{ژxsd/namedelements.rbnu[# XSD4R - WSDL named element collection. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module XSD class NamedElements include Enumerable def initialize @elements = [] @cache = {} end def dup o = NamedElements.new o.elements = @elements.dup o end def freeze super @elements.freeze self end def empty? size == 0 end def size @elements.size end def [](idx) if idx.is_a?(Numeric) @elements[idx] else @cache[idx] ||= @elements.find { |item| item.name == idx } end end def find_name(name) @elements.find { |item| item.name.name == name } end def keys collect { |element| element.name } end def each @elements.each do |element| yield(element) end end def <<(rhs) @elements << rhs self end def delete(rhs) @elements.delete(rhs) end def +(rhs) o = NamedElements.new o.elements = @elements + rhs.elements o end def concat(rhs) @elements.concat(rhs.elements) self end Empty = NamedElements.new.freeze protected def elements=(rhs) @elements = rhs end def elements @elements end end end PK|]w^^xsd/codegen/commentdef.rbnu[# XSD4R - Generating comment definition code # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' module XSD module CodeGen module CommentDef include GenSupport attr_accessor :comment private def dump_comment if /\A#/ =~ @comment format(@comment) else format(@comment).gsub(/^/, '# ') end end end end end PK|]Sb4;xsd/codegen/moduledef.rbnu[# XSD4R - Generating module definition code # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'xsd/codegen/methoddef' require 'xsd/codegen/commentdef' module XSD module CodeGen class ModuleDef include GenSupport include CommentDef def initialize(name) @name = name @comment = nil @const = [] @code = [] @requirepath = [] @methoddef = [] end def def_require(path) @requirepath << path end def def_const(const, value) unless safeconstname?(const) raise ArgumentError.new("#{const} seems to be unsafe") end @const << [const, value] end def def_code(code) @code << code end def def_method(name, *params) add_method(MethodDef.new(name, *params) { yield if block_given? }, :public) end alias def_publicmethod def_method def def_protectedmethod(name, *params) add_method(MethodDef.new(name, *params) { yield if block_given? }, :protected) end def def_privatemethod(name, *params) add_method(MethodDef.new(name, *params) { yield if block_given? }, :private) end def add_method(m, visibility = :public) @methoddef << [visibility, m] end def dump buf = "" unless @requirepath.empty? buf << dump_requirepath end buf << dump_emptyline unless buf.empty? package = @name.split(/::/)[0..-2] buf << dump_package_def(package) unless package.empty? buf << dump_comment if @comment buf << dump_module_def spacer = false unless @const.empty? buf << dump_emptyline if spacer spacer = true buf << dump_const end unless @code.empty? buf << dump_emptyline if spacer spacer = true buf << dump_code end unless @methoddef.empty? buf << dump_emptyline if spacer spacer = true buf << dump_methods end buf << dump_module_def_end buf << dump_package_def_end(package) unless package.empty? buf.gsub(/^\s+$/, '') end private def dump_requirepath format( @requirepath.collect { |path| %Q(require '#{path}') }.join("\n") ) end def dump_const dump_static( @const.sort.collect { |var, value| %Q(#{var} = #{dump_value(value)}) }.join("\n") ) end def dump_code dump_static(@code.join("\n")) end def dump_static(str) format(str, 2) end def dump_methods methods = {} @methoddef.each do |visibility, method| (methods[visibility] ||= []) << method end str = "" [:public, :protected, :private].each do |visibility| if methods[visibility] str << "\n" unless str.empty? str << visibility.to_s << "\n\n" unless visibility == :public str << methods[visibility].collect { |m| format(m.dump, 2) }.join("\n") end end str end def dump_value(value) if value.respond_to?(:to_src) value.to_src else value end end def dump_package_def(package) format(package.collect { |ele| "module #{ele}" }.join("; ")) + "\n\n" end def dump_package_def_end(package) "\n\n" + format(package.collect { |ele| "end" }.join("; ")) end def dump_module_def name = @name.to_s.split(/::/) format("module #{name.last}") end def dump_module_def_end format("end") end end end end if __FILE__ == $0 require 'xsd/codegen/moduledef' include XSD::CodeGen m = ModuleDef.new("Foo::Bar::HobbitName") m.def_require("foo/bar") m.def_require("baz") m.comment = <<-EOD foo bar baz EOD m.def_method("foo") do <<-EOD foo.bar = 1 baz.each do |ele| ele + 1 end EOD end m.def_method("baz", "qux") #m.def_protectedmethod("aaa") m.def_privatemethod("bbb") puts m.dump end PK|]Y Y xsd/codegen/gensupport.rbnu[# XSD4R - Code generation support # Copyright (C) 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module XSD module CodeGen # from the file 'keywords' in 1.9. KEYWORD = {} %w( __LINE__ __FILE__ BEGIN END alias and begin break case class def defined? do else elsif end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield ).each { |k| KEYWORD[k] = nil } module GenSupport def capitalize(target) target.sub(/^([a-z])/) { $1.tr!('[a-z]', '[A-Z]') } end module_function :capitalize def uncapitalize(target) target.sub(/^([A-Z])/) { $1.tr!('[A-Z]', '[a-z]') } end module_function :uncapitalize def safeconstname(name) safename = name.scan(/[a-zA-Z0-9_]+/).collect { |ele| GenSupport.capitalize(ele) }.join if /^[A-Z]/ !~ safename or keyword?(safename) safename = "C_#{safename}" end safename end module_function :safeconstname def safeconstname?(name) /\A[A-Z][a-zA-Z0-9_]*\z/ =~ name and !keyword?(name) end module_function :safeconstname? def safemethodname(name) safename = name.scan(/[a-zA-Z0-9_]+/).join('_') safename = uncapitalize(safename) if /^[a-z]/ !~ safename safename = "m_#{safename}" end safename end module_function :safemethodname def safemethodname?(name) /\A[a-zA-Z_][a-zA-Z0-9_]*[=!?]?\z/ =~ name end module_function :safemethodname? def safevarname(name) safename = uncapitalize(name.scan(/[a-zA-Z0-9_]+/).join('_')) if /^[a-z]/ !~ safename or keyword?(safename) "v_#{safename}" else safename end end module_function :safevarname def safevarname?(name) /\A[a-z_][a-zA-Z0-9_]*\z/ =~ name and !keyword?(name) end module_function :safevarname? def keyword?(word) KEYWORD.key?(word) end module_function :keyword? def format(str, indent = nil) str = trim_eol(str) str = trim_indent(str) if indent str.gsub(/^/, " " * indent) else str end end private def trim_eol(str) str.collect { |line| line.sub(/\r?\n\z/, "") + "\n" }.join end def trim_indent(str) indent = nil str = str.collect { |line| untab(line) }.join str.each do |line| head = line.index(/\S/) if !head.nil? and (indent.nil? or head < indent) indent = head end end return str unless indent str.collect { |line| line.sub(/^ {0,#{indent}}/, "") }.join end def untab(line, ts = 8) while pos = line.index(/\t/) line = line.sub(/\t/, " " * (ts - (pos % ts))) end line end def dump_emptyline "\n" end end end end PK|]uD<xsd/codegen/methoddef.rbnu[# XSD4R - Generating method definition code # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'xsd/codegen/commentdef' module XSD module CodeGen class MethodDef include GenSupport include CommentDef attr_accessor :definition def initialize(name, *params) unless safemethodname?(name) raise ArgumentError.new("name '#{name}' seems to be unsafe") end @name = name @params = params @comment = nil @definition = yield if block_given? end def dump buf = "" buf << dump_comment if @comment buf << dump_method_def buf << dump_definition if @definition and !@definition.empty? buf << dump_method_def_end buf end private def dump_method_def if @params.empty? format("def #{@name}") else format("def #{@name}(#{@params.join(", ")})") end end def dump_method_def_end format("end") end def dump_definition format(@definition, 2) end end end end PK|]b ))xsd/codegen/classdef.rbnu[# XSD4R - Generating class definition code # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'xsd/codegen/moduledef' require 'xsd/codegen/methoddef' module XSD module CodeGen class ClassDef < ModuleDef include GenSupport def initialize(name, baseclass = nil) super(name) @baseclass = baseclass @classvar = [] @attrdef = [] end def def_classvar(var, value) var = var.sub(/\A@@/, "") unless safevarname?(var) raise ArgumentError.new("#{var} seems to be unsafe") end @classvar << [var, value] end def def_attr(attrname, writable = true, varname = nil) unless safevarname?(varname || attrname) raise ArgumentError.new("#{varname || attrname} seems to be unsafe") end @attrdef << [attrname, writable, varname] end def dump buf = "" unless @requirepath.empty? buf << dump_requirepath end buf << dump_emptyline unless buf.empty? package = @name.split(/::/)[0..-2] buf << dump_package_def(package) unless package.empty? buf << dump_comment if @comment buf << dump_class_def spacer = false unless @classvar.empty? spacer = true buf << dump_classvar end unless @const.empty? buf << dump_emptyline if spacer spacer = true buf << dump_const end unless @code.empty? buf << dump_emptyline if spacer spacer = true buf << dump_code end unless @attrdef.empty? buf << dump_emptyline if spacer spacer = true buf << dump_attributes end unless @methoddef.empty? buf << dump_emptyline if spacer spacer = true buf << dump_methods end buf << dump_class_def_end buf << dump_package_def_end(package) unless package.empty? buf.gsub(/^\s+$/, '') end private def dump_class_def name = @name.to_s.split(/::/) if @baseclass format("class #{name.last} < #{@baseclass}") else format("class #{name.last}") end end def dump_class_def_end str = format("end") end def dump_classvar dump_static( @classvar.collect { |var, value| %Q(@@#{var.sub(/^@@/, "")} = #{dump_value(value)}) }.join("\n") ) end def dump_attributes str = "" @attrdef.each do |attrname, writable, varname| varname ||= attrname if attrname == varname str << format(dump_accessor(attrname, writable), 2) end end @attrdef.each do |attrname, writable, varname| varname ||= attrname if attrname != varname str << "\n" unless str.empty? str << format(dump_attribute(attrname, writable, varname), 2) end end str end def dump_accessor(attrname, writable) if writable "attr_accessor :#{attrname}" else "attr_reader :#{attrname}" end end def dump_attribute(attrname, writable, varname) str = nil mr = MethodDef.new(attrname) mr.definition = "@#{varname}" str = mr.dump if writable mw = MethodDef.new(attrname + "=", 'value') mw.definition = "@#{varname} = value" str << "\n" + mw.dump end str end end end end if __FILE__ == $0 require 'xsd/codegen/classdef' include XSD::CodeGen c = ClassDef.new("Foo::Bar::HobbitName", String) c.def_require("foo/bar") c.comment = <<-EOD foo bar baz EOD c.def_const("FOO", 1) c.def_classvar("@@foo", "var".dump) c.def_classvar("baz", "1".dump) c.def_attr("Foo", true, "foo") c.def_attr("bar") c.def_attr("baz", true) c.def_attr("Foo2", true, "foo2") c.def_attr("foo3", false, "foo3") c.def_method("foo") do <<-EOD foo.bar = 1 \tbaz.each do |ele| \t ele end EOD end c.def_method("baz", "qux") do <<-EOD [1, 2, 3].each do |i| p i end EOD end m = MethodDef.new("qux", "quxx", "quxxx") do <<-EOD p quxx + quxxx EOD end m.comment = "hello world\n123" c.add_method(m) c.def_code <<-EOD Foo.new Bar.z EOD c.def_code <<-EOD Foo.new Bar.z EOD c.def_privatemethod("foo", "baz", "*arg", "&block") puts c.dump end PK|]xsd/mapping.rbnu[# XSD4R - XML Mapping for Ruby # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require "soap/parser" require 'soap/encodingstyle/literalHandler' require "soap/generator" require "soap/mapping" require "soap/mapping/wsdlliteralregistry" module XSD module Mapping MappingRegistry = SOAP::Mapping::WSDLLiteralRegistry.new MappingOpt = {:default_encodingstyle => SOAP::LiteralNamespace} def self.obj2xml(obj, elename = nil, io = nil) if !elename.nil? and !elename.is_a?(XSD::QName) elename = XSD::QName.new(nil, elename) end elename ||= XSD::QName.new(nil, SOAP::Mapping.name2elename(obj.class.to_s)) soap = SOAP::Mapping.obj2soap(obj, MappingRegistry) soap.elename = elename generator = SOAP::SOAPGenerator.new(MappingOpt) generator.generate(soap, io) end def self.xml2obj(stream) parser = SOAP::Parser.new(MappingOpt) soap = parser.parse(stream) SOAP::Mapping.soap2obj(soap, MappingRegistry) end end end PK|]'t``xsd/datatypes.rbnu[# XSD4R - XML Schema Datatype implementation. # Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/charset' require 'uri' ### ## XMLSchamaDatatypes general definitions. # module XSD Namespace = 'http://www.w3.org/2001/XMLSchema' InstanceNamespace = 'http://www.w3.org/2001/XMLSchema-instance' AttrType = 'type' NilValue = 'true' AnyTypeLiteral = 'anyType' AnySimpleTypeLiteral = 'anySimpleType' NilLiteral = 'nil' StringLiteral = 'string' BooleanLiteral = 'boolean' DecimalLiteral = 'decimal' FloatLiteral = 'float' DoubleLiteral = 'double' DurationLiteral = 'duration' DateTimeLiteral = 'dateTime' TimeLiteral = 'time' DateLiteral = 'date' GYearMonthLiteral = 'gYearMonth' GYearLiteral = 'gYear' GMonthDayLiteral = 'gMonthDay' GDayLiteral = 'gDay' GMonthLiteral = 'gMonth' HexBinaryLiteral = 'hexBinary' Base64BinaryLiteral = 'base64Binary' AnyURILiteral = 'anyURI' QNameLiteral = 'QName' NormalizedStringLiteral = 'normalizedString' #3.3.2 token #3.3.3 language #3.3.4 NMTOKEN #3.3.5 NMTOKENS #3.3.6 Name #3.3.7 NCName #3.3.8 ID #3.3.9 IDREF #3.3.10 IDREFS #3.3.11 ENTITY #3.3.12 ENTITIES IntegerLiteral = 'integer' NonPositiveIntegerLiteral = 'nonPositiveInteger' NegativeIntegerLiteral = 'negativeInteger' LongLiteral = 'long' IntLiteral = 'int' ShortLiteral = 'short' ByteLiteral = 'byte' NonNegativeIntegerLiteral = 'nonNegativeInteger' UnsignedLongLiteral = 'unsignedLong' UnsignedIntLiteral = 'unsignedInt' UnsignedShortLiteral = 'unsignedShort' UnsignedByteLiteral = 'unsignedByte' PositiveIntegerLiteral = 'positiveInteger' AttrTypeName = QName.new(InstanceNamespace, AttrType) AttrNilName = QName.new(InstanceNamespace, NilLiteral) AnyTypeName = QName.new(Namespace, AnyTypeLiteral) AnySimpleTypeName = QName.new(Namespace, AnySimpleTypeLiteral) class Error < StandardError; end class ValueSpaceError < Error; end ### ## The base class of all datatypes with Namespace. # class NSDBase @@types = [] attr_accessor :type def self.inherited(klass) @@types << klass end def self.types @@types end def initialize end def init(type) @type = type end end ### ## The base class of XSD datatypes. # class XSDAnySimpleType < NSDBase include XSD Type = QName.new(Namespace, AnySimpleTypeLiteral) # @data represents canonical space (ex. Integer: 123). attr_reader :data # @is_nil represents this data is nil or not. attr_accessor :is_nil def initialize(value = nil) init(Type, value) end # true or raise def check_lexical_format(value) screen_data(value) true end # set accepts a string which follows lexical space (ex. String: "+123"), or # an object which follows canonical space (ex. Integer: 123). def set(value) if value.nil? @is_nil = true @data = nil _set(nil) else @is_nil = false _set(screen_data(value)) end end # to_s creates a string which follows lexical space (ex. String: "123"). def to_s() if @is_nil "" else _to_s end end private def init(type, value) super(type) set(value) end # raises ValueSpaceError if check failed def screen_data(value) value end def _set(value) @data = value end def _to_s @data.to_s end end class XSDNil < XSDAnySimpleType Type = QName.new(Namespace, NilLiteral) Value = 'true' def initialize(value = nil) init(Type, value) end end ### ## Primitive datatypes. # class XSDString < XSDAnySimpleType Type = QName.new(Namespace, StringLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) unless XSD::Charset.is_ces(value, XSD::Charset.encoding) raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end value end end class XSDBoolean < XSDAnySimpleType Type = QName.new(Namespace, BooleanLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) if value.is_a?(String) str = value.strip if str == 'true' || str == '1' true elsif str == 'false' || str == '0' false else raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end else value ? true : false end end end class XSDDecimal < XSDAnySimpleType Type = QName.new(Namespace, DecimalLiteral) def initialize(value = nil) init(Type, value) end def nonzero? (@number != '0') end private def screen_data(d) if d.is_a?(String) # Integer("00012") => 10 in Ruby. d.sub!(/^([+\-]?)0*(?=\d)/, "\\1") end screen_data_str(d) end def screen_data_str(str) /^([+\-]?)(\d*)(?:\.(\d*)?)?$/ =~ str.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end sign = $1 || '+' int_part = $2 frac_part = $3 int_part = '0' if int_part.empty? frac_part = frac_part ? frac_part.sub(/0+$/, '') : '' point = - frac_part.size number = int_part + frac_part # normalize if sign == '+' sign = '' elsif sign == '-' if number == '0' sign = '' end end [sign, point, number] end def _set(data) if data.nil? @sign = @point = @number = @data = nil return end @sign, @point, @number = data @data = _to_s @data.freeze end # 0.0 -> 0; right? def _to_s str = @number.dup if @point.nonzero? str[@number.size + @point, 0] = '.' end @sign + str end end module FloatConstants NaN = 0.0/0.0 POSITIVE_INF = +1.0/0.0 NEGATIVE_INF = -1.0/0.0 POSITIVE_ZERO = +1.0/POSITIVE_INF NEGATIVE_ZERO = -1.0/POSITIVE_INF MIN_POSITIVE_SINGLE = 2.0 ** -149 end class XSDFloat < XSDAnySimpleType include FloatConstants Type = QName.new(Namespace, FloatLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) # "NaN".to_f => 0 in some environment. libc? if value.is_a?(Float) return narrow32bit(value) end str = value.to_s.strip if str == 'NaN' NaN elsif str == 'INF' POSITIVE_INF elsif str == '-INF' NEGATIVE_INF else if /^[+\-\.\deE]+$/ !~ str raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end # Float("-1.4E") might fail on some system. str << '0' if /e$/i =~ str begin return narrow32bit(Float(str)) rescue ArgumentError raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end end end def _to_s if @data.nan? 'NaN' elsif @data.infinite? == 1 'INF' elsif @data.infinite? == -1 '-INF' else sign = XSDFloat.positive?(@data) ? '+' : '-' sign + sprintf("%.10g", @data.abs).sub(/[eE]([+-])?0+/) { 'e' + $1 } end end # Convert to single-precision 32-bit floating point value. def narrow32bit(f) if f.nan? || f.infinite? f elsif f.abs < MIN_POSITIVE_SINGLE XSDFloat.positive?(f) ? POSITIVE_ZERO : NEGATIVE_ZERO else f end end def self.positive?(value) (1 / value) > 0.0 end end # Ruby's Float is double-precision 64-bit floating point value. class XSDDouble < XSDAnySimpleType include FloatConstants Type = QName.new(Namespace, DoubleLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) # "NaN".to_f => 0 in some environment. libc? if value.is_a?(Float) return value end str = value.to_s.strip if str == 'NaN' NaN elsif str == 'INF' POSITIVE_INF elsif str == '-INF' NEGATIVE_INF else begin return Float(str) rescue ArgumentError # '1.4e' cannot be parsed on some architecture. if /e\z/i =~ str begin return Float(str + '0') rescue ArgumentError raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end else raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end end end end def _to_s if @data.nan? 'NaN' elsif @data.infinite? == 1 'INF' elsif @data.infinite? == -1 '-INF' else sign = (1 / @data > 0.0) ? '+' : '-' sign + sprintf("%.16g", @data.abs).sub(/[eE]([+-])?0+/) { 'e' + $1 } end end end class XSDDuration < XSDAnySimpleType Type = QName.new(Namespace, DurationLiteral) attr_accessor :sign attr_accessor :year attr_accessor :month attr_accessor :day attr_accessor :hour attr_accessor :min attr_accessor :sec def initialize(value = nil) init(Type, value) end private def screen_data(value) /^([+\-]?)P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/ =~ value.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end if ($5 and ((!$2 and !$3 and !$4) or (!$6 and !$7 and !$8))) # Should we allow 'PT5S' here? raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end sign = $1 year = $2.to_i month = $3.to_i day = $4.to_i hour = $6.to_i min = $7.to_i sec = $8 ? XSDDecimal.new($8) : 0 [sign, year, month, day, hour, min, sec] end def _set(data) if data.nil? @sign = @year = @month = @day = @hour = @min = @sec = @data = nil return end @sign, @year, @month, @day, @hour, @min, @sec = data @data = _to_s @data.freeze end def _to_s str = '' str << @sign if @sign str << 'P' l = '' l << "#{ @year }Y" if @year.nonzero? l << "#{ @month }M" if @month.nonzero? l << "#{ @day }D" if @day.nonzero? r = '' r << "#{ @hour }H" if @hour.nonzero? r << "#{ @min }M" if @min.nonzero? r << "#{ @sec }S" if @sec.nonzero? str << l if l.empty? str << "0D" end unless r.empty? str << "T" << r end str end end require 'rational' require 'date' module XSDDateTimeImpl SecInDay = 86400 # 24 * 60 * 60 def to_obj(klass) if klass == Time to_time elsif klass == Date to_date elsif klass == DateTime to_datetime else nil end end def to_time begin if @data.offset * SecInDay == Time.now.utc_offset d = @data usec = (d.sec_fraction * SecInDay * 1000000).round Time.local(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec) else d = @data.newof usec = (d.sec_fraction * SecInDay * 1000000).round Time.gm(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec) end rescue ArgumentError nil end end def to_date Date.new0(@data.class.jd_to_ajd(@data.jd, 0, 0), 0, @data.start) end def to_datetime data end def tz2of(str) /^(?:Z|(?:([+\-])(\d\d):(\d\d))?)$/ =~ str sign = $1 hour = $2.to_i min = $3.to_i of = case sign when '+' of = +(hour.to_r * 60 + min) / 1440 # 24 * 60 when '-' of = -(hour.to_r * 60 + min) / 1440 # 24 * 60 else 0 end of end def of2tz(offset) diffmin = offset * 24 * 60 if diffmin.zero? 'Z' else ((diffmin < 0) ? '-' : '+') << format('%02d:%02d', (diffmin.abs / 60.0).to_i, (diffmin.abs % 60.0).to_i) end end def screen_data(t) # convert t to a DateTime as an internal representation. if t.respond_to?(:to_datetime) # 1.9 or later t.to_datetime elsif t.is_a?(DateTime) t elsif t.is_a?(Date) t = screen_data_str(t) t <<= 12 if t.year < 0 t elsif t.is_a?(Time) jd = DateTime.civil_to_jd(t.year, t.mon, t.mday, DateTime::ITALY) fr = DateTime.time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) + t.usec.to_r / 1000000 / SecInDay of = t.utc_offset.to_r / SecInDay DateTime.new0(DateTime.jd_to_ajd(jd, fr, of), of, DateTime::ITALY) else screen_data_str(t) end end def add_tz(s) s + of2tz(@data.offset) end end class XSDDateTime < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, DateTimeLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^([+\-]?\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end if $1 == '0000' raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end year = $1.to_i if year < 0 year += 1 end mon = $2.to_i mday = $3.to_i hour = $4.to_i min = $5.to_i sec = $6.to_i secfrac = $7 zonestr = $8 data = DateTime.civil(year, mon, mday, hour, min, sec, tz2of(zonestr)) if secfrac diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / SecInDay data += diffday # FYI: new0 and jd_to_rjd are not necessary to use if you don't have # exceptional reason. end [data, secfrac] end def _set(data) if data.nil? @data = @secfrac = nil return end @data, @secfrac = data end def _to_s year = (@data.year > 0) ? @data.year : @data.year - 1 s = format('%.4d-%02d-%02dT%02d:%02d:%02d', year, @data.mon, @data.mday, @data.hour, @data.min, @data.sec) if @data.sec_fraction.nonzero? if @secfrac s << ".#{ @secfrac }" else s << sprintf("%.16f", (@data.sec_fraction * SecInDay).to_f).sub(/^0/, '').sub(/0*$/, '') end end add_tz(s) end end class XSDTime < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, TimeLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end hour = $1.to_i min = $2.to_i sec = $3.to_i secfrac = $4 zonestr = $5 data = DateTime.civil(1, 1, 1, hour, min, sec, tz2of(zonestr)) if secfrac diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / SecInDay data += diffday end [data, secfrac] end def _set(data) if data.nil? @data = @secfrac = nil return end @data, @secfrac = data end def _to_s s = format('%02d:%02d:%02d', @data.hour, @data.min, @data.sec) if @data.sec_fraction.nonzero? if @secfrac s << ".#{ @secfrac }" else s << sprintf("%.16f", (@data.sec_fraction * SecInDay).to_f).sub(/^0/, '').sub(/0*$/, '') end end add_tz(s) end end class XSDDate < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, DateLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^([+\-]?\d{4,})-(\d\d)-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end year = $1.to_i if year < 0 year += 1 end mon = $2.to_i mday = $3.to_i zonestr = $4 DateTime.civil(year, mon, mday, 0, 0, 0, tz2of(zonestr)) end def _to_s year = (@data.year > 0) ? @data.year : @data.year - 1 s = format('%.4d-%02d-%02d', year, @data.mon, @data.mday) add_tz(s) end end class XSDGYearMonth < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GYearMonthLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^([+\-]?\d{4,})-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end year = $1.to_i if year < 0 year += 1 end mon = $2.to_i zonestr = $3 DateTime.civil(year, mon, 1, 0, 0, 0, tz2of(zonestr)) end def _to_s year = (@data.year > 0) ? @data.year : @data.year - 1 s = format('%.4d-%02d', year, @data.mon) add_tz(s) end end class XSDGYear < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GYearLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^([+\-]?\d{4,})(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end year = $1.to_i if year < 0 year += 1 end zonestr = $2 DateTime.civil(year, 1, 1, 0, 0, 0, tz2of(zonestr)) end def _to_s year = (@data.year > 0) ? @data.year : @data.year - 1 s = format('%.4d', year) add_tz(s) end end class XSDGMonthDay < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GMonthDayLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^(\d\d)-(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end mon = $1.to_i mday = $2.to_i zonestr = $3 DateTime.civil(1, mon, mday, 0, 0, 0, tz2of(zonestr)) end def _to_s s = format('%02d-%02d', @data.mon, @data.mday) add_tz(s) end end class XSDGDay < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GDayLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end mday = $1.to_i zonestr = $2 DateTime.civil(1, 1, mday, 0, 0, 0, tz2of(zonestr)) end def _to_s s = format('%02d', @data.mday) add_tz(s) end end class XSDGMonth < XSDAnySimpleType include XSDDateTimeImpl Type = QName.new(Namespace, GMonthLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(t) /^(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") end mon = $1.to_i zonestr = $2 DateTime.civil(1, mon, 1, 0, 0, 0, tz2of(zonestr)) end def _to_s s = format('%02d', @data.mon) add_tz(s) end end class XSDHexBinary < XSDAnySimpleType Type = QName.new(Namespace, HexBinaryLiteral) # String in Ruby could be a binary. def initialize(value = nil) init(Type, value) end def set_encoded(value) if /^[0-9a-fA-F]*$/ !~ value raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end @data = String.new(value).strip @is_nil = false end def string [@data].pack("H*") end private def screen_data(value) value.unpack("H*")[0].tr('a-f', 'A-F') end end class XSDBase64Binary < XSDAnySimpleType Type = QName.new(Namespace, Base64BinaryLiteral) # String in Ruby could be a binary. def initialize(value = nil) init(Type, value) end def set_encoded(value) if /^[A-Za-z0-9+\/=]*$/ !~ value raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end @data = String.new(value).strip @is_nil = false end def string @data.unpack("m")[0] end private def screen_data(value) [value].pack("m").strip end end class XSDAnyURI < XSDAnySimpleType Type = QName.new(Namespace, AnyURILiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) begin URI.parse(value.to_s.strip) rescue URI::InvalidURIError raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end end end class XSDQName < XSDAnySimpleType Type = QName.new(Namespace, QNameLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) /^(?:([^:]+):)?([^:]+)$/ =~ value.to_s.strip unless Regexp.last_match raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end prefix = $1 localpart = $2 [prefix, localpart] end def _set(data) if data.nil? @prefix = @localpart = @data = nil return end @prefix, @localpart = data @data = _to_s @data.freeze end def _to_s if @prefix "#{ @prefix }:#{ @localpart }" else "#{ @localpart }" end end end ### ## Derived types # class XSDNormalizedString < XSDString Type = QName.new(Namespace, NormalizedStringLiteral) def initialize(value = nil) init(Type, value) end private def screen_data(value) if /[\t\r\n]/ =~ value raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") end super end end class XSDInteger < XSDDecimal Type = QName.new(Namespace, IntegerLiteral) def initialize(value = nil) init(Type, value) end private def screen_data_str(str) begin data = Integer(str) rescue ArgumentError raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end unless validate(data) raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") end data end def _set(value) @data = value end def _to_s() @data.to_s end def validate(v) max = maxinclusive min = mininclusive (max.nil? or v <= max) and (min.nil? or v >= min) end def maxinclusive nil end def mininclusive nil end PositiveMinInclusive = 1 def positive(v) PositiveMinInclusive <= v end end class XSDNonPositiveInteger < XSDInteger Type = QName.new(Namespace, NonPositiveIntegerLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive 0 end def mininclusive nil end end class XSDNegativeInteger < XSDNonPositiveInteger Type = QName.new(Namespace, NegativeIntegerLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive -1 end def mininclusive nil end end class XSDLong < XSDInteger Type = QName.new(Namespace, LongLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +9223372036854775807 end def mininclusive -9223372036854775808 end end class XSDInt < XSDLong Type = QName.new(Namespace, IntLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +2147483647 end def mininclusive -2147483648 end end class XSDShort < XSDInt Type = QName.new(Namespace, ShortLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +32767 end def mininclusive -32768 end end class XSDByte < XSDShort Type = QName.new(Namespace, ByteLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +127 end def mininclusive -128 end end class XSDNonNegativeInteger < XSDInteger Type = QName.new(Namespace, NonNegativeIntegerLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive nil end def mininclusive 0 end end class XSDUnsignedLong < XSDNonNegativeInteger Type = QName.new(Namespace, UnsignedLongLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +18446744073709551615 end def mininclusive 0 end end class XSDUnsignedInt < XSDUnsignedLong Type = QName.new(Namespace, UnsignedIntLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +4294967295 end def mininclusive 0 end end class XSDUnsignedShort < XSDUnsignedInt Type = QName.new(Namespace, UnsignedShortLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +65535 end def mininclusive 0 end end class XSDUnsignedByte < XSDUnsignedShort Type = QName.new(Namespace, UnsignedByteLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive +255 end def mininclusive 0 end end class XSDPositiveInteger < XSDNonNegativeInteger Type = QName.new(Namespace, PositiveIntegerLiteral) def initialize(value = nil) init(Type, value) end private def maxinclusive nil end def mininclusive 1 end end end PK|]);T__xsd/xmlparser/parser.rbnu[# XSD4R - XML Instance parser library. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/ns' require 'xsd/charset' module XSD module XMLParser class Parser class ParseError < Error; end class FormatDecodeError < ParseError; end class UnknownElementError < FormatDecodeError; end class UnknownAttributeError < FormatDecodeError; end class UnexpectedElementError < FormatDecodeError; end class ElementConstraintError < FormatDecodeError; end @@parser_factory = nil def self.factory @@parser_factory end def self.create_parser(host, opt = {}) @@parser_factory.new(host, opt) end def self.add_factory(factory) if $DEBUG puts "Set #{ factory } as XML processor." end @@parser_factory = factory end public attr_accessor :charset def initialize(host, opt = {}) @host = host @charset = opt[:charset] || nil end def parse(string_or_readable) @textbuf = '' prologue do_parse(string_or_readable) epilogue end private def do_parse(string_or_readable) raise NotImplementError.new( 'Method do_parse must be defined in derived class.') end def start_element(name, attrs) @host.start_element(name, attrs) end def characters(text) @host.characters(text) end def end_element(name) @host.end_element(name) end def prologue end def epilogue end def xmldecl_encoding=(charset) if @charset.nil? @charset = charset else # Definition in a stream (like HTTP) has a priority. p "encoding definition: #{ charset } is ignored." if $DEBUG end end end end end PK|]8v  xsd/xmlparser/xmlscanner.rbnu[# XSD4R - XMLScan XML parser library. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/xmlparser' require 'xmlscan/scanner' module XSD module XMLParser class XMLScanner < XSD::XMLParser::Parser include XMLScan::Visitor def do_parse(string_or_readable) @attrs = {} @curattr = nil @scanner = XMLScan::XMLScanner.new(self) @scanner.kcode = XSD::Charset.charset_str(charset) if charset @scanner.parse(string_or_readable) end def scanner_kcode=(charset) @scanner.kcode = XSD::Charset.charset_str(charset) if charset self.xmldecl_encoding = charset end ENTITY_REF_MAP = { 'lt' => '<', 'gt' => '>', 'amp' => '&', 'quot' => '"', 'apos' => '\'' } def parse_error(msg) raise ParseError.new(msg) end def wellformed_error(msg) raise NotWellFormedError.new(msg) end def valid_error(msg) raise NotValidError.new(msg) end def warning(msg) p msg if $DEBUG end # def on_xmldecl; end def on_xmldecl_version(str) # 1.0 expected. end def on_xmldecl_encoding(str) self.scanner_kcode = str end # def on_xmldecl_standalone(str); end # def on_xmldecl_other(name, value); end # def on_xmldecl_end; end # def on_doctype(root, pubid, sysid); end # def on_prolog_space(str); end # def on_comment(str); end # def on_pi(target, pi); end def on_chardata(str) characters(str) end # def on_cdata(str); end def on_etag(name) end_element(name) end def on_entityref(ref) characters(ENTITY_REF_MAP[ref]) end def on_charref(code) characters([code].pack('U')) end def on_charref_hex(code) on_charref(code) end # def on_start_document; end # def on_end_document; end def on_stag(name) @attrs = {} end def on_attribute(name) @attrs[name] = @curattr = '' end def on_attr_value(str) @curattr << str end def on_attr_entityref(ref) @curattr << ENTITY_REF_MAP[ref] end def on_attr_charref(code) @curattr << [code].pack('U') end def on_attr_charref_hex(code) on_attr_charref(code) end # def on_attribute_end(name); end def on_stag_end_empty(name) on_stag_end(name) on_etag(name) end def on_stag_end(name) start_element(name, @attrs) end add_factory(self) end end end PK|]Vnnxsd/xmlparser/xmlparser.rbnu[# XSD4R - XMLParser XML parser library. # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/xmlparser' require 'xml/parser' module XSD module XMLParser class XMLParser < XSD::XMLParser::Parser class Listener < XML::Parser begin require 'xml/encoding-ja' include XML::Encoding_ja rescue LoadError # uconv may not be installed. end end def do_parse(string_or_readable) # XMLParser passes a String in utf-8. @charset = 'utf-8' @parser = Listener.new @parser.parse(string_or_readable) do |type, name, data| case type when XML::Parser::START_ELEM start_element(name, data) when XML::Parser::END_ELEM end_element(name) when XML::Parser::CDATA characters(data) else raise FormatDecodeError.new("Unexpected XML: #{ type }/#{ name }/#{ data }.") end end end add_factory(self) end end end PK|]hGGxsd/xmlparser/rexmlparser.rbnu[# XSD4R - REXMLParser XML parser library. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/xmlparser' require 'rexml/streamlistener' require 'rexml/document' module XSD module XMLParser class REXMLParser < XSD::XMLParser::Parser include REXML::StreamListener def do_parse(string_or_readable) source = nil source = REXML::SourceFactory.create_from(string_or_readable) source.encoding = charset if charset # Listener passes a String in utf-8. @charset = 'utf-8' REXML::Document.parse_stream(source, self) end def epilogue end def tag_start(name, attrs) start_element(name, attrs) end def tag_end(name) end_element(name) end def text(text) characters(text) end def xmldecl(version, encoding, standalone) # Version should be checked. end add_factory(self) end end end PK|]OGxsd/charset.rbnu[# XSD4R - Charset handling library. # Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module XSD module Charset @internal_encoding = $KCODE class XSDError < StandardError; end class CharsetError < XSDError; end class UnknownCharsetError < CharsetError; end class CharsetConversionError < CharsetError; end public ### ## Maps # EncodingConvertMap = {} def Charset.init EncodingConvertMap[['UTF8', 'X_ISO8859_1']] = Proc.new { |str| str.unpack('U*').pack('C*') } EncodingConvertMap[['X_ISO8859_1', 'UTF8']] = Proc.new { |str| str.unpack('C*').pack('U*') } begin require 'xsd/iconvcharset' @internal_encoding = 'UTF8' sjtag = (/(mswin|bccwin|mingw|cygwin|emx)/ =~ RUBY_PLATFORM) ? 'cp932' : 'shift_jis' EncodingConvertMap[['UTF8', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "utf-8", str) } EncodingConvertMap[['EUC' , 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "euc-jp", str) } EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv(sjtag, "euc-jp", str) } EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv(sjtag, "utf-8", str) } EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", sjtag, str) } EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", sjtag, str) } rescue LoadError begin require 'nkf' EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| NKF.nkf('-sXm0', str) } EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| NKF.nkf('-eXm0', str) } rescue LoadError end begin require 'uconv' @internal_encoding = 'UTF8' EncodingConvertMap[['UTF8', 'EUC' ]] = Uconv.method(:u8toeuc) EncodingConvertMap[['UTF8', 'SJIS']] = Uconv.method(:u8tosjis) EncodingConvertMap[['EUC' , 'UTF8']] = Uconv.method(:euctou8) EncodingConvertMap[['SJIS', 'UTF8']] = Uconv.method(:sjistou8) rescue LoadError end end end self.init CharsetMap = { 'NONE' => 'us-ascii', 'EUC' => 'euc-jp', 'SJIS' => 'shift_jis', 'UTF8' => 'utf-8', 'X_ISO_8859_1' => 'iso-8859-1', 'X_UNKNOWN' => nil, } ### ## handlers # def Charset.encoding @internal_encoding end def Charset.encoding=(encoding) warn("xsd charset is set to #{encoding}") if $DEBUG @internal_encoding = encoding end def Charset.xml_encoding_label charset_label(@internal_encoding) end def Charset.encoding_to_xml(str, charset) encoding_conv(str, @internal_encoding, charset_str(charset)) end def Charset.encoding_from_xml(str, charset) encoding_conv(str, charset_str(charset), @internal_encoding) end def Charset.encoding_conv(str, enc_from, enc_to) if enc_from == enc_to or enc_from == 'NONE' or enc_to == 'NONE' str elsif converter = EncodingConvertMap[[enc_from, enc_to]] converter.call(str) else raise CharsetConversionError.new( "Converter not found: #{enc_from} -> #{enc_to}") end end def Charset.charset_label(encoding) CharsetMap[encoding.upcase] end def Charset.charset_str(label) if CharsetMap.respond_to?(:key) CharsetMap.key(label.downcase) || 'X_UNKNOWN' else CharsetMap.index(label.downcase) || 'X_UNKNOWN' end end # us_ascii = '[\x00-\x7F]' us_ascii = '[\x9\xa\xd\x20-\x7F]' # XML 1.0 restricted. USASCIIRegexp = Regexp.new("\\A#{us_ascii}*\\z", nil, "NONE") twobytes_euc = '(?:[\x8E\xA1-\xFE][\xA1-\xFE])' threebytes_euc = '(?:\x8F[\xA1-\xFE][\xA1-\xFE])' character_euc = "(?:#{us_ascii}|#{twobytes_euc}|#{threebytes_euc})" EUCRegexp = Regexp.new("\\A#{character_euc}*\\z", nil, "NONE") # onebyte_sjis = '[\x00-\x7F\xA1-\xDF]' onebyte_sjis = '[\x9\xa\xd\x20-\x7F\xA1-\xDF]' # XML 1.0 restricted. twobytes_sjis = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])' character_sjis = "(?:#{onebyte_sjis}|#{twobytes_sjis})" SJISRegexp = Regexp.new("\\A#{character_sjis}*\\z", nil, "NONE") # 0xxxxxxx # 110yyyyy 10xxxxxx twobytes_utf8 = '(?:[\xC0-\xDF][\x80-\xBF])' # 1110zzzz 10yyyyyy 10xxxxxx threebytes_utf8 = '(?:[\xE0-\xEF][\x80-\xBF][\x80-\xBF])' # 11110uuu 10uuuzzz 10yyyyyy 10xxxxxx fourbytes_utf8 = '(?:[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF])' character_utf8 = "(?:#{us_ascii}|#{twobytes_utf8}|#{threebytes_utf8}|#{fourbytes_utf8})" UTF8Regexp = Regexp.new("\\A#{character_utf8}*\\z", nil, "NONE") def Charset.is_us_ascii(str) USASCIIRegexp =~ str end def Charset.is_utf8(str) UTF8Regexp =~ str end def Charset.is_euc(str) EUCRegexp =~ str end def Charset.is_sjis(str) SJISRegexp =~ str end def Charset.is_ces(str, code = $KCODE) case code when 'NONE' is_us_ascii(str) when 'UTF8' is_utf8(str) when 'EUC' is_euc(str) when 'SJIS' is_sjis(str) else raise UnknownCharsetError.new("Unknown charset: #{code}") end end end end PK|]o]xsd/xmlparser.rbnu[# XSD4R - XML Instance parser library. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/xmlparser/parser' module XSD module XMLParser def create_parser(host, opt) XSD::XMLParser::Parser.create_parser(host, opt) end module_function :create_parser # $1 is necessary. NSParseRegexp = Regexp.new('^xmlns:?(.*)$') def filter_ns(ns, attrs) return attrs if attrs.nil? or attrs.empty? newattrs = {} attrs.each do |key, value| if (NSParseRegexp =~ key) # '' means 'default namespace'. tag = $1 || '' ns.assign(value, tag) else newattrs[key] = value end end newattrs end module_function :filter_ns end end # Try to load XML processor. loaded = false [ 'xsd/xmlparser/xmlparser', 'xsd/xmlparser/xmlscanner', 'xsd/xmlparser/rexmlparser', ].each do |lib| begin require lib loaded = true break rescue LoadError end end unless loaded raise RuntimeError.new("XML processor module not found.") end PK|]h xsd/qname.rbnu[# XSD4R - XML QName definition. # Copyright (C) 2002, 2003, 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module XSD class QName attr_accessor :namespace attr_accessor :name attr_accessor :source def initialize(namespace = nil, name = nil) @namespace = namespace @name = name @source = nil end def dup_name(name) XSD::QName.new(@namespace, name) end def dump ns = @namespace.nil? ? 'nil' : @namespace.dump name = @name.nil? ? 'nil' : @name.dump "XSD::QName.new(#{ns}, #{name})" end def match(rhs) if rhs.namespace and (rhs.namespace != @namespace) return false end if rhs.name and (rhs.name != @name) return false end true end def ==(rhs) !rhs.nil? and @namespace == rhs.namespace and @name == rhs.name end def ===(rhs) (self == rhs) end def eql?(rhs) (self == rhs) end def hash @namespace.hash ^ @name.hash end def to_s "{#{ namespace }}#{ name }" end def inspect sprintf("#<%s:0x%x %s>", self.class.name, __id__, "{#{ namespace }}#{ name }") end NormalizedNameRegexp = /^\{([^}]*)\}(.*)$/ def parse(str) NormalizedNameRegexp =~ str self.new($1, $2) end EMPTY = QName.new.freeze end end PK|]E+xsd/iconvcharset.rbnu[# XSD4R - Charset handling with iconv. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'iconv' module XSD class IconvCharset def self.safe_iconv(to, from, str) iconv = Iconv.new(to, from) out = "" begin out << iconv.iconv(str) rescue Iconv::IllegalSequence => e out << e.success ch, str = e.failed.split(//, 2) out << '?' warn("Failed to convert #{ch}") retry end return out end end end PK|]r xsd/ns.rbnu[# XSD4R - XML Schema Namespace library # Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' module XSD class NS class Assigner def initialize @count = 0 end def assign(ns) @count += 1 "n#{@count}" end end attr_reader :default_namespace class FormatError < Error; end public def initialize(tag2ns = {}) @tag2ns = tag2ns @assigner = nil @ns2tag = {} @tag2ns.each do |tag, ns| @ns2tag[ns] = tag end @default_namespace = nil end def assign(ns, tag = nil) if (tag == '') @default_namespace = ns tag else @assigner ||= Assigner.new tag ||= @assigner.assign(ns) @ns2tag[ns] = tag @tag2ns[tag] = ns tag end end def assigned?(ns) @default_namespace == ns or @ns2tag.key?(ns) end def assigned_tag?(tag) @tag2ns.key?(tag) end def clone_ns cloned = NS.new(@tag2ns.dup) cloned.assigner = @assigner cloned.assign(@default_namespace, '') if @default_namespace cloned end def name(name) if (name.namespace == @default_namespace) name.name elsif @ns2tag.key?(name.namespace) "#{@ns2tag[name.namespace]}:#{name.name}" else raise FormatError.new("namespace: #{name.namespace} not defined yet") end end def compare(ns, name, rhs) if (ns == @default_namespace) return true if (name == rhs) end @tag2ns.each do |assigned_tag, assigned_ns| if assigned_ns == ns && "#{assigned_tag}:#{name}" == rhs return true end end false end # $1 and $2 are necessary. ParseRegexp = Regexp.new('^([^:]+)(?::(.+))?$') def parse(str, local = false) if ParseRegexp =~ str if (name = $2) and (ns = @tag2ns[$1]) return XSD::QName.new(ns, name) end end XSD::QName.new(local ? nil : @default_namespace, str) end # For local attribute key parsing # # => # {}bar, {urn:a}baz def parse_local(elem) ParseRegexp =~ elem if $2 ns = @tag2ns[$1] name = $2 if !ns raise FormatError.new("unknown namespace qualifier: #{$1}") end elsif $1 ns = nil name = $1 else raise FormatError.new("illegal element format: #{elem}") end XSD::QName.new(ns, name) end def each_ns @ns2tag.each do |ns, tag| yield(ns, tag) end end protected def assigner=(assigner) @assigner = assigner end end end PK|]LYxsd/datatypes1999.rbnu[# XSD4R - XML Schema Datatype 1999 support # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' module XSD Namespace.replace('http://www.w3.org/1999/XMLSchema') InstanceNamespace.replace('http://www.w3.org/1999/XMLSchema-instance') AnyTypeLiteral.replace('ur-type') AnySimpleTypeLiteral.replace('ur-type') NilLiteral.replace('null') NilValue.replace('1') DateTimeLiteral.replace('timeInstant') end PK|]N7NlNlset.rbnu[#!/usr/bin/env ruby #-- # set.rb - defines the Set class #++ # Copyright (c) 2002-2008 Akinori MUSHA # # Documentation by Akinori MUSHA and Gavin Sinclair. # # All rights reserved. You can redistribute and/or modify it under the same # terms as Ruby. # # $Id: set.rb 17051 2008-06-09 09:20:43Z knu $ # # == Overview # # This library provides the Set class, which deals with a collection # of unordered values with no duplicates. It is a hybrid of Array's # intuitive inter-operation facilities and Hash's fast lookup. If you # need to keep values ordered, use the SortedSet class. # # The method +to_set+ is added to Enumerable for convenience. # # See the Set class for an example of usage. # # Set implements a collection of unordered values with no duplicates. # This is a hybrid of Array's intuitive inter-operation facilities and # Hash's fast lookup. # # Several methods accept any Enumerable object (implementing +each+) # for greater flexibility: new, replace, merge, subtract, |, &, -, ^. # # The equality of each couple of elements is determined according to # Object#eql? and Object#hash, since Set uses Hash as storage. # # Finally, if you are using class Set, you can also use Enumerable#to_set # for convenience. # # == Example # # require 'set' # s1 = Set.new [1, 2] # -> # # s2 = [1, 2].to_set # -> # # s1 == s2 # -> true # s1.add("foo") # -> # # s1.merge([2, 6]) # -> # # s1.subset? s2 # -> false # s2.subset? s1 # -> true # # == Contact # # - Akinori MUSHA (current maintainer) # class Set include Enumerable # Creates a new set containing the given objects. def self.[](*ary) new(ary) end # Creates a new set containing the elements of the given enumerable # object. # # If a block is given, the elements of enum are preprocessed by the # given block. def initialize(enum = nil, &block) # :yields: o @hash ||= Hash.new enum.nil? and return if block enum.each { |o| add(block[o]) } else merge(enum) end end # Copy internal hash. def initialize_copy(orig) @hash = orig.instance_eval{@hash}.dup end # Returns the number of elements. def size @hash.size end alias length size # Returns true if the set contains no elements. def empty? @hash.empty? end # Removes all elements and returns self. def clear @hash.clear self end # Replaces the contents of the set with the contents of the given # enumerable object and returns self. def replace(enum) if enum.class == self.class @hash.replace(enum.instance_eval { @hash }) else enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" clear enum.each { |o| add(o) } end self end # Converts the set to an array. The order of elements is uncertain. def to_a @hash.keys end def flatten_merge(set, seen = Set.new) set.each { |e| if e.is_a?(Set) if seen.include?(e_id = e.object_id) raise ArgumentError, "tried to flatten recursive Set" end seen.add(e_id) flatten_merge(e, seen) seen.delete(e_id) else add(e) end } self end protected :flatten_merge # Returns a new set that is a copy of the set, flattening each # containing set recursively. def flatten self.class.new.flatten_merge(self) end # Equivalent to Set#flatten, but replaces the receiver with the # result in place. Returns nil if no modifications were made. def flatten! if detect { |e| e.is_a?(Set) } replace(flatten()) else nil end end # Returns true if the set contains the given object. def include?(o) @hash.include?(o) end alias member? include? # Returns true if the set is a superset of the given set. def superset?(set) set.is_a?(Set) or raise ArgumentError, "value must be a set" return false if size < set.size set.all? { |o| include?(o) } end # Returns true if the set is a proper superset of the given set. def proper_superset?(set) set.is_a?(Set) or raise ArgumentError, "value must be a set" return false if size <= set.size set.all? { |o| include?(o) } end # Returns true if the set is a subset of the given set. def subset?(set) set.is_a?(Set) or raise ArgumentError, "value must be a set" return false if set.size < size all? { |o| set.include?(o) } end # Returns true if the set is a proper subset of the given set. def proper_subset?(set) set.is_a?(Set) or raise ArgumentError, "value must be a set" return false if set.size <= size all? { |o| set.include?(o) } end # Calls the given block once for each element in the set, passing # the element as parameter. Returns an enumerator if no block is # given. def each block_given? or return enum_for(__method__) @hash.each_key { |o| yield(o) } self end # Adds the given object to the set and returns self. Use +merge+ to # add several elements at once. def add(o) @hash[o] = true self end alias << add # Adds the given object to the set and returns self. If the # object is already in the set, returns nil. def add?(o) if include?(o) nil else add(o) end end # Deletes the given object from the set and returns self. Use +subtract+ to # delete several items at once. def delete(o) @hash.delete(o) self end # Deletes the given object from the set and returns self. If the # object is not in the set, returns nil. def delete?(o) if include?(o) delete(o) else nil end end # Deletes every element of the set for which block evaluates to # true, and returns self. def delete_if to_a.each { |o| @hash.delete(o) if yield(o) } self end # Do collect() destructively. def collect! set = self.class.new each { |o| set << yield(o) } replace(set) end alias map! collect! # Equivalent to Set#delete_if, but returns nil if no changes were # made. def reject! n = size delete_if { |o| yield(o) } size == n ? nil : self end # Merges the elements of the given enumerable object to the set and # returns self. def merge(enum) if enum.is_a?(Set) @hash.update(enum.instance_eval { @hash }) else enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" enum.each { |o| add(o) } end self end # Deletes every element that appears in the given enumerable object # and returns self. def subtract(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" enum.each { |o| delete(o) } self end # Returns a new set built by merging the set and the elements of the # given enumerable object. def |(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" dup.merge(enum) end alias + | ## alias union | ## # Returns a new set built by duplicating the set, removing every # element that appears in the given enumerable object. def -(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" dup.subtract(enum) end alias difference - ## # Returns a new set containing elements common to the set and the # given enumerable object. def &(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" n = self.class.new enum.each { |o| n.add(o) if include?(o) } n end alias intersection & ## # Returns a new set containing elements exclusive between the set # and the given enumerable object. (set ^ enum) is equivalent to # ((set | enum) - (set & enum)). def ^(enum) enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" n = Set.new(enum) each { |o| if n.include?(o) then n.delete(o) else n.add(o) end } n end # Returns true if two sets are equal. The equality of each couple # of elements is defined according to Object#eql?. def ==(set) equal?(set) and return true set.is_a?(Set) && size == set.size or return false hash = @hash.dup set.all? { |o| hash.include?(o) } end def hash # :nodoc: @hash.hash end def eql?(o) # :nodoc: return false unless o.is_a?(Set) @hash.eql?(o.instance_eval{@hash}) end # Classifies the set by the return value of the given block and # returns a hash of {value => set of elements} pairs. The block is # called once for each element of the set, passing the element as # parameter. # # e.g.: # # require 'set' # files = Set.new(Dir.glob("*.rb")) # hash = files.classify { |f| File.mtime(f).year } # p hash # => {2000=>#, # # 2001=>#, # # 2002=>#} def classify # :yields: o h = {} each { |i| x = yield(i) (h[x] ||= self.class.new).add(i) } h end # Divides the set into a set of subsets according to the commonality # defined by the given block. # # If the arity of the block is 2, elements o1 and o2 are in common # if block.call(o1, o2) is true. Otherwise, elements o1 and o2 are # in common if block.call(o1) == block.call(o2). # # e.g.: # # require 'set' # numbers = Set[1, 3, 4, 6, 9, 10, 11] # set = numbers.divide { |i,j| (i - j).abs == 1 } # p set # => #, # # #, # # #, # # #}> def divide(&func) if func.arity == 2 require 'tsort' class << dig = {} # :nodoc: include TSort alias tsort_each_node each_key def tsort_each_child(node, &block) fetch(node).each(&block) end end each { |u| dig[u] = a = [] each{ |v| func.call(u, v) and a << v } } set = Set.new() dig.each_strongly_connected_component { |css| set.add(self.class.new(css)) } set else Set.new(classify(&func).values) end end InspectKey = :__inspect_key__ # :nodoc: # Returns a string containing a human-readable representation of the # set. ("#") def inspect ids = (Thread.current[InspectKey] ||= []) if ids.include?(object_id) return sprintf('#<%s: {...}>', self.class.name) end begin ids << object_id return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2]) ensure ids.pop end end def pretty_print(pp) # :nodoc: pp.text sprintf('#<%s: {', self.class.name) pp.nest(1) { pp.seplist(self) { |o| pp.pp o } } pp.text "}>" end def pretty_print_cycle(pp) # :nodoc: pp.text sprintf('#<%s: {%s}>', self.class.name, empty? ? '' : '...') end end # SortedSet implements a set which elements are sorted in order. See Set. class SortedSet < Set @@setup = false class << self def [](*ary) # :nodoc: new(ary) end def setup # :nodoc: @@setup and return module_eval { # a hack to shut up warning alias old_init initialize remove_method :old_init } begin require 'rbtree' module_eval %{ def initialize(*args, &block) @hash = RBTree.new super end } rescue LoadError module_eval %{ def initialize(*args, &block) @keys = nil super end def clear @keys = nil super end def replace(enum) @keys = nil super end def add(o) @keys = nil @hash[o] = true self end alias << add def delete(o) @keys = nil @hash.delete(o) self end def delete_if n = @hash.size super @keys = nil if @hash.size != n self end def merge(enum) @keys = nil super end def each block_given? or return enum_for(__method__) to_a.each { |o| yield(o) } self end def to_a (@keys = @hash.keys).sort! unless @keys @keys end } end @@setup = true end end def initialize(*args, &block) # :nodoc: SortedSet.setup initialize(*args, &block) end end module Enumerable # Makes a set from the enumerable object with given arguments. # Needs to +require "set"+ to use this method. def to_set(klass = Set, *args, &block) klass.new(self, *args, &block) end end # =begin # == RestricedSet class # RestricedSet implements a set with restrictions defined by a given # block. # # === Super class # Set # # === Class Methods # --- RestricedSet::new(enum = nil) { |o| ... } # --- RestricedSet::new(enum = nil) { |rset, o| ... } # Creates a new restricted set containing the elements of the given # enumerable object. Restrictions are defined by the given block. # # If the block's arity is 2, it is called with the RestrictedSet # itself and an object to see if the object is allowed to be put in # the set. # # Otherwise, the block is called with an object to see if the object # is allowed to be put in the set. # # === Instance Methods # --- restriction_proc # Returns the restriction procedure of the set. # # =end # # class RestricedSet < Set # def initialize(*args, &block) # @proc = block or raise ArgumentError, "missing a block" # # if @proc.arity == 2 # instance_eval %{ # def add(o) # @hash[o] = true if @proc.call(self, o) # self # end # alias << add # # def add?(o) # if include?(o) || !@proc.call(self, o) # nil # else # @hash[o] = true # self # end # end # # def replace(enum) # enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" # clear # enum.each { |o| add(o) } # # self # end # # def merge(enum) # enum.is_a?(Enumerable) or raise ArgumentError, "value must be enumerable" # enum.each { |o| add(o) } # # self # end # } # else # instance_eval %{ # def add(o) # if @proc.call(o) # @hash[o] = true # end # self # end # alias << add # # def add?(o) # if include?(o) || !@proc.call(o) # nil # else # @hash[o] = true # self # end # end # } # end # # super(*args) # end # # def restriction_proc # @proc # end # end if $0 == __FILE__ eval DATA.read, nil, $0, __LINE__+4 end __END__ require 'test/unit' class TC_Set < Test::Unit::TestCase def test_aref assert_nothing_raised { Set[] Set[nil] Set[1,2,3] } assert_equal(0, Set[].size) assert_equal(1, Set[nil].size) assert_equal(1, Set[[]].size) assert_equal(1, Set[[nil]].size) set = Set[2,4,6,4] assert_equal(Set.new([2,4,6]), set) end def test_s_new assert_nothing_raised { Set.new() Set.new(nil) Set.new([]) Set.new([1,2]) Set.new('a'..'c') Set.new('XYZ') } assert_raises(ArgumentError) { Set.new(false) } assert_raises(ArgumentError) { Set.new(1) } assert_raises(ArgumentError) { Set.new(1,2) } assert_equal(0, Set.new().size) assert_equal(0, Set.new(nil).size) assert_equal(0, Set.new([]).size) assert_equal(1, Set.new([nil]).size) ary = [2,4,6,4] set = Set.new(ary) ary.clear assert_equal(false, set.empty?) assert_equal(3, set.size) ary = [1,2,3] s = Set.new(ary) { |o| o * 2 } assert_equal([2,4,6], s.sort) end def test_clone set1 = Set.new set2 = set1.clone set1 << 'abc' assert_equal(Set.new, set2) end def test_dup set1 = Set[1,2] set2 = set1.dup assert_not_same(set1, set2) assert_equal(set1, set2) set1.add(3) assert_not_equal(set1, set2) end def test_size assert_equal(0, Set[].size) assert_equal(2, Set[1,2].size) assert_equal(2, Set[1,2,1].size) end def test_empty? assert_equal(true, Set[].empty?) assert_equal(false, Set[1, 2].empty?) end def test_clear set = Set[1,2] ret = set.clear assert_same(set, ret) assert_equal(true, set.empty?) end def test_replace set = Set[1,2] ret = set.replace('a'..'c') assert_same(set, ret) assert_equal(Set['a','b','c'], set) end def test_to_a set = Set[1,2,3,2] ary = set.to_a assert_equal([1,2,3], ary.sort) end def test_flatten # test1 set1 = Set[ 1, Set[ 5, Set[7, Set[0] ], Set[6,2], 1 ], 3, Set[3,4] ] set2 = set1.flatten set3 = Set.new(0..7) assert_not_same(set2, set1) assert_equal(set3, set2) # test2; destructive orig_set1 = set1 set1.flatten! assert_same(orig_set1, set1) assert_equal(set3, set1) # test3; multiple occurrences of a set in an set set1 = Set[1, 2] set2 = Set[set1, Set[set1, 4], 3] assert_nothing_raised { set2.flatten! } assert_equal(Set.new(1..4), set2) # test4; recursion set2 = Set[] set1 = Set[1, set2] set2.add(set1) assert_raises(ArgumentError) { set1.flatten! } # test5; miscellaneous empty = Set[] set = Set[Set[empty, "a"],Set[empty, "b"]] assert_nothing_raised { set.flatten } set1 = empty.merge(Set["no_more", set]) assert_nil(Set.new(0..31).flatten!) x = Set[Set[],Set[1,2]].flatten! y = Set[1,2] assert_equal(x, y) end def test_include? set = Set[1,2,3] assert_equal(true, set.include?(1)) assert_equal(true, set.include?(2)) assert_equal(true, set.include?(3)) assert_equal(false, set.include?(0)) assert_equal(false, set.include?(nil)) set = Set["1",nil,"2",nil,"0","1",false] assert_equal(true, set.include?(nil)) assert_equal(true, set.include?(false)) assert_equal(true, set.include?("1")) assert_equal(false, set.include?(0)) assert_equal(false, set.include?(true)) end def test_superset? set = Set[1,2,3] assert_raises(ArgumentError) { set.superset?() } assert_raises(ArgumentError) { set.superset?(2) } assert_raises(ArgumentError) { set.superset?([2]) } assert_equal(true, set.superset?(Set[])) assert_equal(true, set.superset?(Set[1,2])) assert_equal(true, set.superset?(Set[1,2,3])) assert_equal(false, set.superset?(Set[1,2,3,4])) assert_equal(false, set.superset?(Set[1,4])) assert_equal(true, Set[].superset?(Set[])) end def test_proper_superset? set = Set[1,2,3] assert_raises(ArgumentError) { set.proper_superset?() } assert_raises(ArgumentError) { set.proper_superset?(2) } assert_raises(ArgumentError) { set.proper_superset?([2]) } assert_equal(true, set.proper_superset?(Set[])) assert_equal(true, set.proper_superset?(Set[1,2])) assert_equal(false, set.proper_superset?(Set[1,2,3])) assert_equal(false, set.proper_superset?(Set[1,2,3,4])) assert_equal(false, set.proper_superset?(Set[1,4])) assert_equal(false, Set[].proper_superset?(Set[])) end def test_subset? set = Set[1,2,3] assert_raises(ArgumentError) { set.subset?() } assert_raises(ArgumentError) { set.subset?(2) } assert_raises(ArgumentError) { set.subset?([2]) } assert_equal(true, set.subset?(Set[1,2,3,4])) assert_equal(true, set.subset?(Set[1,2,3])) assert_equal(false, set.subset?(Set[1,2])) assert_equal(false, set.subset?(Set[])) assert_equal(true, Set[].subset?(Set[1])) assert_equal(true, Set[].subset?(Set[])) end def test_proper_subset? set = Set[1,2,3] assert_raises(ArgumentError) { set.proper_subset?() } assert_raises(ArgumentError) { set.proper_subset?(2) } assert_raises(ArgumentError) { set.proper_subset?([2]) } assert_equal(true, set.proper_subset?(Set[1,2,3,4])) assert_equal(false, set.proper_subset?(Set[1,2,3])) assert_equal(false, set.proper_subset?(Set[1,2])) assert_equal(false, set.proper_subset?(Set[])) assert_equal(false, Set[].proper_subset?(Set[])) end def test_each ary = [1,3,5,7,10,20] set = Set.new(ary) ret = set.each { |o| } assert_same(set, ret) e = set.each assert_instance_of(Enumerable::Enumerator, e) assert_nothing_raised { set.each { |o| ary.delete(o) or raise "unexpected element: #{o}" } ary.empty? or raise "forgotten elements: #{ary.join(', ')}" } end def test_add set = Set[1,2,3] ret = set.add(2) assert_same(set, ret) assert_equal(Set[1,2,3], set) ret = set.add?(2) assert_nil(ret) assert_equal(Set[1,2,3], set) ret = set.add(4) assert_same(set, ret) assert_equal(Set[1,2,3,4], set) ret = set.add?(5) assert_same(set, ret) assert_equal(Set[1,2,3,4,5], set) end def test_delete set = Set[1,2,3] ret = set.delete(4) assert_same(set, ret) assert_equal(Set[1,2,3], set) ret = set.delete?(4) assert_nil(ret) assert_equal(Set[1,2,3], set) ret = set.delete(2) assert_equal(set, ret) assert_equal(Set[1,3], set) ret = set.delete?(1) assert_equal(set, ret) assert_equal(Set[3], set) end def test_delete_if set = Set.new(1..10) ret = set.delete_if { |i| i > 10 } assert_same(set, ret) assert_equal(Set.new(1..10), set) set = Set.new(1..10) ret = set.delete_if { |i| i % 3 == 0 } assert_same(set, ret) assert_equal(Set[1,2,4,5,7,8,10], set) end def test_collect! set = Set[1,2,3,'a','b','c',-1..1,2..4] ret = set.collect! { |i| case i when Numeric i * 2 when String i.upcase else nil end } assert_same(set, ret) assert_equal(Set[2,4,6,'A','B','C',nil], set) end def test_reject! set = Set.new(1..10) ret = set.reject! { |i| i > 10 } assert_nil(ret) assert_equal(Set.new(1..10), set) ret = set.reject! { |i| i % 3 == 0 } assert_same(set, ret) assert_equal(Set[1,2,4,5,7,8,10], set) end def test_merge set = Set[1,2,3] ret = set.merge([2,4,6]) assert_same(set, ret) assert_equal(Set[1,2,3,4,6], set) end def test_subtract set = Set[1,2,3] ret = set.subtract([2,4,6]) assert_same(set, ret) assert_equal(Set[1,3], set) end def test_plus set = Set[1,2,3] ret = set + [2,4,6] assert_not_same(set, ret) assert_equal(Set[1,2,3,4,6], ret) end def test_minus set = Set[1,2,3] ret = set - [2,4,6] assert_not_same(set, ret) assert_equal(Set[1,3], ret) end def test_and set = Set[1,2,3,4] ret = set & [2,4,6] assert_not_same(set, ret) assert_equal(Set[2,4], ret) end def test_xor set = Set[1,2,3,4] ret = set ^ [2,4,5,5] assert_not_same(set, ret) assert_equal(Set[1,3,5], ret) end def test_eq set1 = Set[2,3,1] set2 = Set[1,2,3] assert_equal(set1, set1) assert_equal(set1, set2) assert_not_equal(Set[1], [1]) set1 = Class.new(Set)["a", "b"] set2 = Set["a", "b", set1] set1 = set1.add(set1.clone) # assert_equal(set1, set2) # assert_equal(set2, set1) assert_equal(set2, set2.clone) assert_equal(set1.clone, set1) assert_not_equal(Set[Exception.new,nil], Set[Exception.new,Exception.new], "[ruby-dev:26127]") end # def test_hash # end # def test_eql? # end def test_classify set = Set.new(1..10) ret = set.classify { |i| i % 3 } assert_equal(3, ret.size) assert_instance_of(Hash, ret) ret.each_value { |value| assert_instance_of(Set, value) } assert_equal(Set[3,6,9], ret[0]) assert_equal(Set[1,4,7,10], ret[1]) assert_equal(Set[2,5,8], ret[2]) end def test_divide set = Set.new(1..10) ret = set.divide { |i| i % 3 } assert_equal(3, ret.size) n = 0 ret.each { |s| n += s.size } assert_equal(set.size, n) assert_equal(set, ret.flatten) set = Set[7,10,5,11,1,3,4,9,0] ret = set.divide { |a,b| (a - b).abs == 1 } assert_equal(4, ret.size) n = 0 ret.each { |s| n += s.size } assert_equal(set.size, n) assert_equal(set, ret.flatten) ret.each { |s| if s.include?(0) assert_equal(Set[0,1], s) elsif s.include?(3) assert_equal(Set[3,4,5], s) elsif s.include?(7) assert_equal(Set[7], s) elsif s.include?(9) assert_equal(Set[9,10,11], s) else raise "unexpected group: #{s.inspect}" end } end def test_inspect set1 = Set[1] assert_equal('#', set1.inspect) set2 = Set[Set[0], 1, 2, set1] assert_equal(false, set2.inspect.include?('#')) set1.add(set2) assert_equal(true, set1.inspect.include?('#')) end # def test_pretty_print # end # def test_pretty_print_cycle # end end class TC_SortedSet < Test::Unit::TestCase def test_sortedset s = SortedSet[4,5,3,1,2] assert_equal([1,2,3,4,5], s.to_a) prev = nil s.each { |o| assert(prev < o) if prev; prev = o } assert_not_nil(prev) s.map! { |o| -2 * o } assert_equal([-10,-8,-6,-4,-2], s.to_a) prev = nil ret = s.each { |o| assert(prev < o) if prev; prev = o } assert_not_nil(prev) assert_same(s, ret) s = SortedSet.new([2,1,3]) { |o| o * -2 } assert_equal([-6,-4,-2], s.to_a) s = SortedSet.new(['one', 'two', 'three', 'four']) a = [] ret = s.delete_if { |o| a << o; o.start_with?('t') } assert_same(s, ret) assert_equal(['four', 'one'], s.to_a) assert_equal(['four', 'one', 'three', 'two'], a) s = SortedSet.new(['one', 'two', 'three', 'four']) a = [] ret = s.reject! { |o| a << o; o.start_with?('t') } assert_same(s, ret) assert_equal(['four', 'one'], s.to_a) assert_equal(['four', 'one', 'three', 'two'], a) s = SortedSet.new(['one', 'two', 'three', 'four']) a = [] ret = s.reject! { |o| a << o; false } assert_same(nil, ret) assert_equal(['four', 'one', 'three', 'two'], s.to_a) assert_equal(['four', 'one', 'three', 'two'], a) end end class TC_Enumerable < Test::Unit::TestCase def test_to_set ary = [2,5,4,3,2,1,3] set = ary.to_set assert_instance_of(Set, set) assert_equal([1,2,3,4,5], set.sort) set = ary.to_set { |o| o * -2 } assert_instance_of(Set, set) assert_equal([-10,-8,-6,-4,-2], set.sort) set = ary.to_set(SortedSet) assert_instance_of(SortedSet, set) assert_equal([1,2,3,4,5], set.to_a) set = ary.to_set(SortedSet) { |o| o * -2 } assert_instance_of(SortedSet, set) assert_equal([-10,-8,-6,-4,-2], set.sort) end end # class TC_RestricedSet < Test::Unit::TestCase # def test_s_new # assert_raises(ArgumentError) { RestricedSet.new } # # s = RestricedSet.new([-1,2,3]) { |o| o > 0 } # assert_equal([2,3], s.sort) # end # # def test_restriction_proc # s = RestricedSet.new([-1,2,3]) { |o| o > 0 } # # f = s.restriction_proc # assert_instance_of(Proc, f) # assert(f[1]) # assert(!f[0]) # end # # def test_replace # s = RestricedSet.new(-3..3) { |o| o > 0 } # assert_equal([1,2,3], s.sort) # # s.replace([-2,0,3,4,5]) # assert_equal([3,4,5], s.sort) # end # # def test_merge # s = RestricedSet.new { |o| o > 0 } # s.merge(-5..5) # assert_equal([1,2,3,4,5], s.sort) # # s.merge([10,-10,-8,8]) # assert_equal([1,2,3,4,5,8,10], s.sort) # end # end PK|]:digest/sha2.rbnu[#-- # sha2.rb - defines Digest::SHA2 class which wraps up the SHA256, # SHA384, and SHA512 classes. #++ # Copyright (c) 2006 Akinori MUSHA # # All rights reserved. You can redistribute and/or modify it under the same # terms as Ruby. # # $Id: sha2.rb 11708 2007-02-12 23:01:19Z shyouhei $ require 'digest' module Digest # # A meta digest provider class for SHA256, SHA384 and SHA512. # class SHA2 < Digest::Class # call-seq: # Digest::SHA2.new(bitlen = 256) -> digest_obj # # Creates a new SHA2 hash object with a given bit length. def initialize(bitlen = 256) case bitlen when 256 @sha2 = Digest::SHA256.new when 384 @sha2 = Digest::SHA384.new when 512 @sha2 = Digest::SHA512.new else raise ArgumentError, "unsupported bit length: %s" % bitlen.inspect end @bitlen = bitlen end # :nodoc: def reset @sha2.reset self end # :nodoc: def update(str) @sha2.update(str) self end alias << update def finish @sha2.digest! end private :finish def block_length @sha2.block_length end def digest_length @sha2.digest_length end # :nodoc: def initialize_copy(other) @sha2 = other.instance_eval { @sha2.clone } end # :nodoc: def inspect "#<%s:%d %s>" % [self.class.name, @bitlen, hexdigest] end end end PK|]/+rRFF benchmark.rbnu[=begin # # benchmark.rb - a performance benchmarking library # # $Id: benchmark.rb 15425 2008-02-10 15:24:56Z naruse $ # # Created by Gotoken (gotoken@notwork.org). # # Documentation by Gotoken (original RD), Lyle Johnson (RDoc conversion), and # Gavin Sinclair (editing). # =end # == Overview # # The Benchmark module provides methods for benchmarking Ruby code, giving # detailed reports on the time taken for each task. # # The Benchmark module provides methods to measure and report the time # used to execute Ruby code. # # * Measure the time to construct the string given by the expression # "a"*1_000_000: # # require 'benchmark' # # puts Benchmark.measure { "a"*1_000_000 } # # On my machine (FreeBSD 3.2 on P5, 100MHz) this generates: # # 1.166667 0.050000 1.216667 ( 0.571355) # # This report shows the user CPU time, system CPU time, the sum of # the user and system CPU times, and the elapsed real time. The unit # of time is seconds. # # * Do some experiments sequentially using the #bm method: # # require 'benchmark' # # n = 50000 # Benchmark.bm do |x| # x.report { for i in 1..n; a = "1"; end } # x.report { n.times do ; a = "1"; end } # x.report { 1.upto(n) do ; a = "1"; end } # end # # The result: # # user system total real # 1.033333 0.016667 1.016667 ( 0.492106) # 1.483333 0.000000 1.483333 ( 0.694605) # 1.516667 0.000000 1.516667 ( 0.711077) # # * Continuing the previous example, put a label in each report: # # require 'benchmark' # # n = 50000 # Benchmark.bm(7) do |x| # x.report("for:") { for i in 1..n; a = "1"; end } # x.report("times:") { n.times do ; a = "1"; end } # x.report("upto:") { 1.upto(n) do ; a = "1"; end } # end # # The result: # # user system total real # for: 1.050000 0.000000 1.050000 ( 0.503462) # times: 1.533333 0.016667 1.550000 ( 0.735473) # upto: 1.500000 0.016667 1.516667 ( 0.711239) # # # * The times for some benchmarks depend on the order in which items # are run. These differences are due to the cost of memory # allocation and garbage collection. To avoid these discrepancies, # the #bmbm method is provided. For example, to compare ways to # sort an array of floats: # # require 'benchmark' # # array = (1..1000000).map { rand } # # Benchmark.bmbm do |x| # x.report("sort!") { array.dup.sort! } # x.report("sort") { array.dup.sort } # end # # The result: # # Rehearsal ----------------------------------------- # sort! 11.928000 0.010000 11.938000 ( 12.756000) # sort 13.048000 0.020000 13.068000 ( 13.857000) # ------------------------------- total: 25.006000sec # # user system total real # sort! 12.959000 0.010000 12.969000 ( 13.793000) # sort 12.007000 0.000000 12.007000 ( 12.791000) # # # * Report statistics of sequential experiments with unique labels, # using the #benchmark method: # # require 'benchmark' # # n = 50000 # Benchmark.benchmark(" "*7 + CAPTION, 7, FMTSTR, ">total:", ">avg:") do |x| # tf = x.report("for:") { for i in 1..n; a = "1"; end } # tt = x.report("times:") { n.times do ; a = "1"; end } # tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end } # [tf+tt+tu, (tf+tt+tu)/3] # end # # The result: # # user system total real # for: 1.016667 0.016667 1.033333 ( 0.485749) # times: 1.450000 0.016667 1.466667 ( 0.681367) # upto: 1.533333 0.000000 1.533333 ( 0.722166) # >total: 4.000000 0.033333 4.033333 ( 1.889282) # >avg: 1.333333 0.011111 1.344444 ( 0.629761) module Benchmark BENCHMARK_VERSION = "2002-04-25" #:nodoc" def Benchmark::times() # :nodoc: Process::times() end # Invokes the block with a Benchmark::Report object, which # may be used to collect and report on the results of individual # benchmark tests. Reserves label_width leading spaces for # labels on each line. Prints _caption_ at the top of the # report, and uses _fmt_ to format each line. # If the block returns an array of # Benchmark::Tms objects, these will be used to format # additional lines of output. If _label_ parameters are # given, these are used to label these extra lines. # # _Note_: Other methods provide a simpler interface to this one, and are # suitable for nearly all benchmarking requirements. See the examples in # Benchmark, and the #bm and #bmbm methods. # # Example: # # require 'benchmark' # include Benchmark # we need the CAPTION and FMTSTR constants # # n = 50000 # Benchmark.benchmark(" "*7 + CAPTION, 7, FMTSTR, ">total:", ">avg:") do |x| # tf = x.report("for:") { for i in 1..n; a = "1"; end } # tt = x.report("times:") { n.times do ; a = "1"; end } # tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end } # [tf+tt+tu, (tf+tt+tu)/3] # end # # Generates: # # user system total real # for: 1.016667 0.016667 1.033333 ( 0.485749) # times: 1.450000 0.016667 1.466667 ( 0.681367) # upto: 1.533333 0.000000 1.533333 ( 0.722166) # >total: 4.000000 0.033333 4.033333 ( 1.889282) # >avg: 1.333333 0.011111 1.344444 ( 0.629761) # def benchmark(caption = "", label_width = nil, fmtstr = nil, *labels) # :yield: report sync = STDOUT.sync STDOUT.sync = true label_width ||= 0 fmtstr ||= FMTSTR raise ArgumentError, "no block" unless iterator? print caption results = yield(Report.new(label_width, fmtstr)) Array === results and results.grep(Tms).each {|t| print((labels.shift || t.label || "").ljust(label_width), t.format(fmtstr)) } STDOUT.sync = sync end # A simple interface to the #benchmark method, #bm is generates sequential reports # with labels. The parameters have the same meaning as for #benchmark. # # require 'benchmark' # # n = 50000 # Benchmark.bm(7) do |x| # x.report("for:") { for i in 1..n; a = "1"; end } # x.report("times:") { n.times do ; a = "1"; end } # x.report("upto:") { 1.upto(n) do ; a = "1"; end } # end # # Generates: # # user system total real # for: 1.050000 0.000000 1.050000 ( 0.503462) # times: 1.533333 0.016667 1.550000 ( 0.735473) # upto: 1.500000 0.016667 1.516667 ( 0.711239) # def bm(label_width = 0, *labels, &blk) # :yield: report benchmark(" "*label_width + CAPTION, label_width, FMTSTR, *labels, &blk) end # Sometimes benchmark results are skewed because code executed # earlier encounters different garbage collection overheads than # that run later. #bmbm attempts to minimize this effect by running # the tests twice, the first time as a rehearsal in order to get the # runtime environment stable, the second time for # real. GC.start is executed before the start of each of # the real timings; the cost of this is not included in the # timings. In reality, though, there's only so much that #bmbm can # do, and the results are not guaranteed to be isolated from garbage # collection and other effects. # # Because #bmbm takes two passes through the tests, it can # calculate the required label width. # # require 'benchmark' # # array = (1..1000000).map { rand } # # Benchmark.bmbm do |x| # x.report("sort!") { array.dup.sort! } # x.report("sort") { array.dup.sort } # end # # Generates: # # Rehearsal ----------------------------------------- # sort! 11.928000 0.010000 11.938000 ( 12.756000) # sort 13.048000 0.020000 13.068000 ( 13.857000) # ------------------------------- total: 25.006000sec # # user system total real # sort! 12.959000 0.010000 12.969000 ( 13.793000) # sort 12.007000 0.000000 12.007000 ( 12.791000) # # #bmbm yields a Benchmark::Job object and returns an array of # Benchmark::Tms objects. # def bmbm(width = 0, &blk) # :yield: job job = Job.new(width) yield(job) width = job.width sync = STDOUT.sync STDOUT.sync = true # rehearsal print "Rehearsal " puts '-'*(width+CAPTION.length - "Rehearsal ".length) list = [] job.list.each{|label,item| print(label.ljust(width)) res = Benchmark::measure(&item) print res.format() list.push res } sum = Tms.new; list.each{|i| sum += i} ets = sum.format("total: %tsec") printf("%s %s\n\n", "-"*(width+CAPTION.length-ets.length-1), ets) # take print ' '*width, CAPTION list = [] ary = [] job.list.each{|label,item| GC::start print label.ljust(width) res = Benchmark::measure(&item) print res.format() ary.push res list.push [label, res] } STDOUT.sync = sync ary end # # Returns the time used to execute the given block as a # Benchmark::Tms object. # def measure(label = "") # :yield: t0, r0 = Benchmark.times, Time.now yield t1, r1 = Benchmark.times, Time.now Benchmark::Tms.new(t1.utime - t0.utime, t1.stime - t0.stime, t1.cutime - t0.cutime, t1.cstime - t0.cstime, r1.to_f - r0.to_f, label) end # # Returns the elapsed real time used to execute the given block. # def realtime(&blk) # :yield: r0 = Time.now yield r1 = Time.now r1.to_f - r0.to_f end # # A Job is a sequence of labelled blocks to be processed by the # Benchmark.bmbm method. It is of little direct interest to the user. # class Job # :nodoc: # # Returns an initialized Job instance. # Usually, one doesn't call this method directly, as new # Job objects are created by the #bmbm method. # _width_ is a initial value for the label offset used in formatting; # the #bmbm method passes its _width_ argument to this constructor. # def initialize(width) @width = width @list = [] end # # Registers the given label and block pair in the job list. # def item(label = "", &blk) # :yield: raise ArgumentError, "no block" unless block_given? label += ' ' w = label.length @width = w if @width < w @list.push [label, blk] self end alias report item # An array of 2-element arrays, consisting of label and block pairs. attr_reader :list # Length of the widest label in the #list, plus one. attr_reader :width end module_function :benchmark, :measure, :realtime, :bm, :bmbm # # This class is used by the Benchmark.benchmark and Benchmark.bm methods. # It is of little direct interest to the user. # class Report # :nodoc: # # Returns an initialized Report instance. # Usually, one doesn't call this method directly, as new # Report objects are created by the #benchmark and #bm methods. # _width_ and _fmtstr_ are the label offset and # format string used by Tms#format. # def initialize(width = 0, fmtstr = nil) @width, @fmtstr = width, fmtstr end # # Prints the _label_ and measured time for the block, # formatted by _fmt_. See Tms#format for the # formatting rules. # def item(label = "", *fmt, &blk) # :yield: print label.ljust(@width) res = Benchmark::measure(&blk) print res.format(@fmtstr, *fmt) res end alias report item end # # A data object, representing the times associated with a benchmark # measurement. # class Tms CAPTION = " user system total real\n" FMTSTR = "%10.6u %10.6y %10.6t %10.6r\n" # User CPU time attr_reader :utime # System CPU time attr_reader :stime # User CPU time of children attr_reader :cutime # System CPU time of children attr_reader :cstime # Elapsed real time attr_reader :real # Total time, that is _utime_ + _stime_ + _cutime_ + _cstime_ attr_reader :total # Label attr_reader :label # # Returns an initialized Tms object which has # _u_ as the user CPU time, _s_ as the system CPU time, # _cu_ as the children's user CPU time, _cs_ as the children's # system CPU time, _real_ as the elapsed real time and _l_ # as the label. # def initialize(u = 0.0, s = 0.0, cu = 0.0, cs = 0.0, real = 0.0, l = nil) @utime, @stime, @cutime, @cstime, @real, @label = u, s, cu, cs, real, l @total = @utime + @stime + @cutime + @cstime end # # Returns a new Tms object whose times are the sum of the times for this # Tms object, plus the time required to execute the code block (_blk_). # def add(&blk) # :yield: self + Benchmark::measure(&blk) end # # An in-place version of #add. # def add! t = Benchmark::measure(&blk) @utime = utime + t.utime @stime = stime + t.stime @cutime = cutime + t.cutime @cstime = cstime + t.cstime @real = real + t.real self end # # Returns a new Tms object obtained by memberwise summation # of the individual times for this Tms object with those of the other # Tms object. # This method and #/() are useful for taking statistics. # def +(other); memberwise(:+, other) end # # Returns a new Tms object obtained by memberwise subtraction # of the individual times for the other Tms object from those of this # Tms object. # def -(other); memberwise(:-, other) end # # Returns a new Tms object obtained by memberwise multiplication # of the individual times for this Tms object by _x_. # def *(x); memberwise(:*, x) end # # Returns a new Tms object obtained by memberwise division # of the individual times for this Tms object by _x_. # This method and #+() are useful for taking statistics. # def /(x); memberwise(:/, x) end # # Returns the contents of this Tms object as # a formatted string, according to a format string # like that passed to Kernel.format. In addition, #format # accepts the following extensions: # # %u:: Replaced by the user CPU time, as reported by Tms#utime. # %y:: Replaced by the system CPU time, as reported by #stime (Mnemonic: y of "s*y*stem") # %U:: Replaced by the children's user CPU time, as reported by Tms#cutime # %Y:: Replaced by the children's system CPU time, as reported by Tms#cstime # %t:: Replaced by the total CPU time, as reported by Tms#total # %r:: Replaced by the elapsed real time, as reported by Tms#real # %n:: Replaced by the label string, as reported by Tms#label (Mnemonic: n of "*n*ame") # # If _fmtstr_ is not given, FMTSTR is used as default value, detailing the # user, system and real elapsed time. # def format(arg0 = nil, *args) fmtstr = (arg0 || FMTSTR).dup fmtstr.gsub!(/(%[-+\.\d]*)n/){"#{$1}s" % label} fmtstr.gsub!(/(%[-+\.\d]*)u/){"#{$1}f" % utime} fmtstr.gsub!(/(%[-+\.\d]*)y/){"#{$1}f" % stime} fmtstr.gsub!(/(%[-+\.\d]*)U/){"#{$1}f" % cutime} fmtstr.gsub!(/(%[-+\.\d]*)Y/){"#{$1}f" % cstime} fmtstr.gsub!(/(%[-+\.\d]*)t/){"#{$1}f" % total} fmtstr.gsub!(/(%[-+\.\d]*)r/){"(#{$1}f)" % real} arg0 ? Kernel::format(fmtstr, *args) : fmtstr end # # Same as #format. # def to_s format end # # Returns a new 6-element array, consisting of the # label, user CPU time, system CPU time, children's # user CPU time, children's system CPU time and elapsed # real time. # def to_a [@label, @utime, @stime, @cutime, @cstime, @real] end protected def memberwise(op, x) case x when Benchmark::Tms Benchmark::Tms.new(utime.__send__(op, x.utime), stime.__send__(op, x.stime), cutime.__send__(op, x.cutime), cstime.__send__(op, x.cstime), real.__send__(op, x.real) ) else Benchmark::Tms.new(utime.__send__(op, x), stime.__send__(op, x), cutime.__send__(op, x), cstime.__send__(op, x), real.__send__(op, x) ) end end end # The default caption string (heading above the output times). CAPTION = Benchmark::Tms::CAPTION # The default format string used to display times. See also Benchmark::Tms#format. FMTSTR = Benchmark::Tms::FMTSTR end if __FILE__ == $0 include Benchmark n = ARGV[0].to_i.nonzero? || 50000 puts %Q([#{n} times iterations of `a = "1"']) benchmark(" " + CAPTION, 7, FMTSTR) do |x| x.report("for:") {for i in 1..n; a = "1"; end} # Benchmark::measure x.report("times:") {n.times do ; a = "1"; end} x.report("upto:") {1.upto(n) do ; a = "1"; end} end benchmark do [ measure{for i in 1..n; a = "1"; end}, # Benchmark::measure measure{n.times do ; a = "1"; end}, measure{1.upto(n) do ; a = "1"; end} ] end end PK|] & yy expect.rbnu[$expect_verbose = false class IO def expect(pat,timeout=9999999) buf = '' case pat when String e_pat = Regexp.new(Regexp.quote(pat)) when Regexp e_pat = pat end while true if !IO.select([self],nil,nil,timeout) or eof? then result = nil break end c = getc.chr buf << c if $expect_verbose STDOUT.print c STDOUT.flush end if mat=e_pat.match(buf) then result = [buf,*mat.to_a[1..-1]] break end end if block_given? then yield result else return result end nil end end PK|]_QQ open-uri.rbnu[require 'uri' require 'stringio' require 'time' module Kernel private alias open_uri_original_open open # :nodoc: # makes possible to open various resources including URIs. # If the first argument respond to `open' method, # the method is called with the rest arguments. # # If the first argument is a string which begins with xxx://, # it is parsed by URI.parse. If the parsed object respond to `open' method, # the method is called with the rest arguments. # # Otherwise original open is called. # # Since open-uri.rb provides URI::HTTP#open, URI::HTTPS#open and # URI::FTP#open, # Kernel[#.]open can accepts such URIs and strings which begins with # http://, https:// and ftp://. # In these case, the opened file object is extended by OpenURI::Meta. def open(name, *rest, &block) # :doc: if name.respond_to?(:open) name.open(*rest, &block) elsif name.respond_to?(:to_str) && %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ name && (uri = URI.parse(name)).respond_to?(:open) uri.open(*rest, &block) else open_uri_original_open(name, *rest, &block) end end module_function :open end # OpenURI is an easy-to-use wrapper for net/http, net/https and net/ftp. # #== Example # # It is possible to open http/https/ftp URL as usual like opening a file: # # open("http://www.ruby-lang.org/") {|f| # f.each_line {|line| p line} # } # # The opened file has several methods for meta information as follows since # it is extended by OpenURI::Meta. # # open("http://www.ruby-lang.org/en") {|f| # f.each_line {|line| p line} # p f.base_uri # # p f.content_type # "text/html" # p f.charset # "iso-8859-1" # p f.content_encoding # [] # p f.last_modified # Thu Dec 05 02:45:02 UTC 2002 # } # # Additional header fields can be specified by an optional hash argument. # # open("http://www.ruby-lang.org/en/", # "User-Agent" => "Ruby/#{RUBY_VERSION}", # "From" => "foo@bar.invalid", # "Referer" => "http://www.ruby-lang.org/") {|f| # # ... # } # # The environment variables such as http_proxy, https_proxy and ftp_proxy # are in effect by default. :proxy => nil disables proxy. # # open("http://www.ruby-lang.org/en/raa.html", :proxy => nil) {|f| # # ... # } # # URI objects can be opened in a similar way. # # uri = URI.parse("http://www.ruby-lang.org/en/") # uri.open {|f| # # ... # } # # URI objects can be read directly. The returned string is also extended by # OpenURI::Meta. # # str = uri.read # p str.base_uri # # Author:: Tanaka Akira module OpenURI Options = { :proxy => true, :progress_proc => true, :content_length_proc => true, :http_basic_authentication => true, } def OpenURI.check_options(options) # :nodoc: options.each {|k, v| next unless Symbol === k unless Options.include? k raise ArgumentError, "unrecognized option: #{k}" end } end def OpenURI.scan_open_optional_arguments(*rest) # :nodoc: if !rest.empty? && (String === rest.first || Integer === rest.first) mode = rest.shift if !rest.empty? && Integer === rest.first perm = rest.shift end end return mode, perm, rest end def OpenURI.open_uri(name, *rest) # :nodoc: uri = URI::Generic === name ? name : URI.parse(name) mode, perm, rest = OpenURI.scan_open_optional_arguments(*rest) options = rest.shift if !rest.empty? && Hash === rest.first raise ArgumentError.new("extra arguments") if !rest.empty? options ||= {} OpenURI.check_options(options) unless mode == nil || mode == 'r' || mode == 'rb' || mode == File::RDONLY raise ArgumentError.new("invalid access mode #{mode} (#{uri.class} resource is read only.)") end io = open_loop(uri, options) if block_given? begin yield io ensure io.close end else io end end def OpenURI.open_loop(uri, options) # :nodoc: case opt_proxy = options.fetch(:proxy, true) when true find_proxy = lambda {|u| u.find_proxy} when nil, false find_proxy = lambda {|u| nil} when String opt_proxy = URI.parse(opt_proxy) find_proxy = lambda {|u| opt_proxy} when URI::Generic find_proxy = lambda {|u| opt_proxy} else raise ArgumentError.new("Invalid proxy option: #{opt_proxy}") end uri_set = {} buf = nil while true redirect = catch(:open_uri_redirect) { buf = Buffer.new uri.buffer_open(buf, find_proxy.call(uri), options) nil } if redirect if redirect.relative? # Although it violates RFC2616, Location: field may have relative # URI. It is converted to absolute URI using uri as a base URI. redirect = uri + redirect end unless OpenURI.redirectable?(uri, redirect) raise "redirection forbidden: #{uri} -> #{redirect}" end if options.include? :http_basic_authentication # send authentication only for the URI directly specified. options = options.dup options.delete :http_basic_authentication end uri = redirect raise "HTTP redirection loop: #{uri}" if uri_set.include? uri.to_s uri_set[uri.to_s] = true else break end end io = buf.io io.base_uri = uri io end def OpenURI.redirectable?(uri1, uri2) # :nodoc: # This test is intended to forbid a redirection from http://... to # file:///etc/passwd. # However this is ad hoc. It should be extensible/configurable. uri1.scheme.downcase == uri2.scheme.downcase || (/\A(?:http|ftp)\z/i =~ uri1.scheme && /\A(?:http|ftp)\z/i =~ uri2.scheme) end def OpenURI.open_http(buf, target, proxy, options) # :nodoc: if proxy raise "Non-HTTP proxy URI: #{proxy}" if proxy.class != URI::HTTP end if target.userinfo && "1.9.0" <= RUBY_VERSION # don't raise for 1.8 because compatibility. raise ArgumentError, "userinfo not supported. [RFC3986]" end require 'net/http' klass = Net::HTTP if URI::HTTP === target # HTTP or HTTPS if proxy klass = Net::HTTP::Proxy(proxy.host, proxy.port) end target_host = target.host target_port = target.port request_uri = target.request_uri else # FTP over HTTP proxy target_host = proxy.host target_port = proxy.port request_uri = target.to_s end http = klass.new(target_host, target_port) if target.class == URI::HTTPS require 'net/https' http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_PEER store = OpenSSL::X509::Store.new store.set_default_paths http.cert_store = store end header = {} options.each {|k, v| header[k] = v if String === k } resp = nil http.start { req = Net::HTTP::Get.new(request_uri, header) if options.include? :http_basic_authentication user, pass = options[:http_basic_authentication] req.basic_auth user, pass end http.request(req) {|response| resp = response if options[:content_length_proc] && Net::HTTPSuccess === resp if resp.key?('Content-Length') options[:content_length_proc].call(resp['Content-Length'].to_i) else options[:content_length_proc].call(nil) end end resp.read_body {|str| buf << str if options[:progress_proc] && Net::HTTPSuccess === resp options[:progress_proc].call(buf.size) end } } } io = buf.io io.rewind io.status = [resp.code, resp.message] resp.each {|name,value| buf.io.meta_add_field name, value } case resp when Net::HTTPSuccess when Net::HTTPMovedPermanently, # 301 Net::HTTPFound, # 302 Net::HTTPSeeOther, # 303 Net::HTTPTemporaryRedirect # 307 throw :open_uri_redirect, URI.parse(resp['location']) else raise OpenURI::HTTPError.new(io.status.join(' '), io) end end class HTTPError < StandardError def initialize(message, io) super(message) @io = io end attr_reader :io end class Buffer # :nodoc: def initialize @io = StringIO.new @size = 0 end attr_reader :size StringMax = 10240 def <<(str) @io << str @size += str.length if StringIO === @io && StringMax < @size require 'tempfile' io = Tempfile.new('open-uri') io.binmode Meta.init io, @io if @io.respond_to? :meta io << @io.string @io = io end end def io Meta.init @io unless @io.respond_to? :meta @io end end # Mixin for holding meta-information. module Meta def Meta.init(obj, src=nil) # :nodoc: obj.extend Meta obj.instance_eval { @base_uri = nil @meta = {} } if src obj.status = src.status obj.base_uri = src.base_uri src.meta.each {|name, value| obj.meta_add_field(name, value) } end end # returns an Array which consists status code and message. attr_accessor :status # returns a URI which is base of relative URIs in the data. # It may differ from the URI supplied by a user because redirection. attr_accessor :base_uri # returns a Hash which represents header fields. # The Hash keys are downcased for canonicalization. attr_reader :meta def meta_add_field(name, value) # :nodoc: @meta[name.downcase] = value end # returns a Time which represents Last-Modified field. def last_modified if v = @meta['last-modified'] Time.httpdate(v) else nil end end RE_LWS = /[\r\n\t ]+/n RE_TOKEN = %r{[^\x00- ()<>@,;:\\"/\[\]?={}\x7f]+}n RE_QUOTED_STRING = %r{"(?:[\r\n\t !#-\[\]-~\x80-\xff]|\\[\x00-\x7f])*"}n RE_PARAMETERS = %r{(?:;#{RE_LWS}?#{RE_TOKEN}#{RE_LWS}?=#{RE_LWS}?(?:#{RE_TOKEN}|#{RE_QUOTED_STRING})#{RE_LWS}?)*}n def content_type_parse # :nodoc: v = @meta['content-type'] # The last (?:;#{RE_LWS}?)? matches extra ";" which violates RFC2045. if v && %r{\A#{RE_LWS}?(#{RE_TOKEN})#{RE_LWS}?/(#{RE_TOKEN})#{RE_LWS}?(#{RE_PARAMETERS})(?:;#{RE_LWS}?)?\z}no =~ v type = $1.downcase subtype = $2.downcase parameters = [] $3.scan(/;#{RE_LWS}?(#{RE_TOKEN})#{RE_LWS}?=#{RE_LWS}?(?:(#{RE_TOKEN})|(#{RE_QUOTED_STRING}))/no) {|att, val, qval| val = qval.gsub(/[\r\n\t !#-\[\]-~\x80-\xff]+|(\\[\x00-\x7f])/) { $1 ? $1[1,1] : $& } if qval parameters << [att.downcase, val] } ["#{type}/#{subtype}", *parameters] else nil end end # returns "type/subtype" which is MIME Content-Type. # It is downcased for canonicalization. # Content-Type parameters are stripped. def content_type type, *parameters = content_type_parse type || 'application/octet-stream' end # returns a charset parameter in Content-Type field. # It is downcased for canonicalization. # # If charset parameter is not given but a block is given, # the block is called and its result is returned. # It can be used to guess charset. # # If charset parameter and block is not given, # nil is returned except text type in HTTP. # In that case, "iso-8859-1" is returned as defined by RFC2616 3.7.1. def charset type, *parameters = content_type_parse if pair = parameters.assoc('charset') pair.last.downcase elsif block_given? yield elsif type && %r{\Atext/} =~ type && @base_uri && /\Ahttp\z/i =~ @base_uri.scheme "iso-8859-1" # RFC2616 3.7.1 else nil end end # returns a list of encodings in Content-Encoding field # as an Array of String. # The encodings are downcased for canonicalization. def content_encoding v = @meta['content-encoding'] if v && %r{\A#{RE_LWS}?#{RE_TOKEN}#{RE_LWS}?(?:,#{RE_LWS}?#{RE_TOKEN}#{RE_LWS}?)*}o =~ v v.scan(RE_TOKEN).map {|content_coding| content_coding.downcase} else [] end end end # Mixin for HTTP and FTP URIs. module OpenRead # OpenURI::OpenRead#open provides `open' for URI::HTTP and URI::FTP. # # OpenURI::OpenRead#open takes optional 3 arguments as: # OpenURI::OpenRead#open([mode [, perm]] [, options]) [{|io| ... }] # # `mode', `perm' is same as Kernel#open. # # However, `mode' must be read mode because OpenURI::OpenRead#open doesn't # support write mode (yet). # Also `perm' is just ignored because it is meaningful only for file # creation. # # `options' must be a hash. # # Each pairs which key is a string in the hash specify a extra header # field for HTTP. # I.e. it is ignored for FTP without HTTP proxy. # # The hash may include other options which key is a symbol: # # [:proxy] # Synopsis: # :proxy => "http://proxy.foo.com:8000/" # :proxy => URI.parse("http://proxy.foo.com:8000/") # :proxy => true # :proxy => false # :proxy => nil # # If :proxy option is specified, the value should be String, URI, # boolean or nil. # When String or URI is given, it is treated as proxy URI. # When true is given or the option itself is not specified, # environment variable `scheme_proxy' is examined. # `scheme' is replaced by `http', `https' or `ftp'. # When false or nil is given, the environment variables are ignored and # connection will be made to a server directly. # # [:http_basic_authentication] # Synopsis: # :http_basic_authentication=>[user, password] # # If :http_basic_authentication is specified, # the value should be an array which contains 2 strings: # username and password. # It is used for HTTP Basic authentication defined by RFC 2617. # # [:content_length_proc] # Synopsis: # :content_length_proc => lambda {|content_length| ... } # # If :content_length_proc option is specified, the option value procedure # is called before actual transfer is started. # It takes one argument which is expected content length in bytes. # # If two or more transfer is done by HTTP redirection, the procedure # is called only one for a last transfer. # # When expected content length is unknown, the procedure is called with # nil. # It is happen when HTTP response has no Content-Length header. # # [:progress_proc] # Synopsis: # :progress_proc => lambda {|size| ...} # # If :progress_proc option is specified, the proc is called with one # argument each time when `open' gets content fragment from network. # The argument `size' `size' is a accumulated transfered size in bytes. # # If two or more transfer is done by HTTP redirection, the procedure # is called only one for a last transfer. # # :progress_proc and :content_length_proc are intended to be used for # progress bar. # For example, it can be implemented as follows using Ruby/ProgressBar. # # pbar = nil # open("http://...", # :content_length_proc => lambda {|t| # if t && 0 < t # pbar = ProgressBar.new("...", t) # pbar.file_transfer_mode # end # }, # :progress_proc => lambda {|s| # pbar.set s if pbar # }) {|f| ... } # # OpenURI::OpenRead#open returns an IO like object if block is not given. # Otherwise it yields the IO object and return the value of the block. # The IO object is extended with OpenURI::Meta. def open(*rest, &block) OpenURI.open_uri(self, *rest, &block) end # OpenURI::OpenRead#read([options]) reads a content referenced by self and # returns the content as string. # The string is extended with OpenURI::Meta. # The argument `options' is same as OpenURI::OpenRead#open. def read(options={}) self.open(options) {|f| str = f.read Meta.init str, f str } end end end module URI class Generic # returns a proxy URI. # The proxy URI is obtained from environment variables such as http_proxy, # ftp_proxy, no_proxy, etc. # If there is no proper proxy, nil is returned. # # Note that capitalized variables (HTTP_PROXY, FTP_PROXY, NO_PROXY, etc.) # are examined too. # # But http_proxy and HTTP_PROXY is treated specially under CGI environment. # It's because HTTP_PROXY may be set by Proxy: header. # So HTTP_PROXY is not used. # http_proxy is not used too if the variable is case insensitive. # CGI_HTTP_PROXY can be used instead. def find_proxy name = self.scheme.downcase + '_proxy' proxy_uri = nil if name == 'http_proxy' && ENV.include?('REQUEST_METHOD') # CGI? # HTTP_PROXY conflicts with *_proxy for proxy settings and # HTTP_* for header information in CGI. # So it should be careful to use it. pairs = ENV.reject {|k, v| /\Ahttp_proxy\z/i !~ k } case pairs.length when 0 # no proxy setting anyway. proxy_uri = nil when 1 k, v = pairs.shift if k == 'http_proxy' && ENV[k.upcase] == nil # http_proxy is safe to use because ENV is case sensitive. proxy_uri = ENV[name] else proxy_uri = nil end else # http_proxy is safe to use because ENV is case sensitive. proxy_uri = ENV.to_hash[name] end if !proxy_uri # Use CGI_HTTP_PROXY. cf. libwww-perl. proxy_uri = ENV["CGI_#{name.upcase}"] end elsif name == 'http_proxy' unless proxy_uri = ENV[name] if proxy_uri = ENV[name.upcase] warn 'The environment variable HTTP_PROXY is discouraged. Use http_proxy.' end end else proxy_uri = ENV[name] || ENV[name.upcase] end if proxy_uri && self.host require 'socket' begin addr = IPSocket.getaddress(self.host) proxy_uri = nil if /\A127\.|\A::1\z/ =~ addr rescue SocketError end end if proxy_uri proxy_uri = URI.parse(proxy_uri) name = 'no_proxy' if no_proxy = ENV[name] || ENV[name.upcase] no_proxy.scan(/([^:,]*)(?::(\d+))?/) {|host, port| if /(\A|\.)#{Regexp.quote host}\z/i =~ self.host && (!port || self.port == port.to_i) proxy_uri = nil break end } end proxy_uri else nil end end end class HTTP def buffer_open(buf, proxy, options) # :nodoc: OpenURI.open_http(buf, self, proxy, options) end include OpenURI::OpenRead end class FTP def buffer_open(buf, proxy, options) # :nodoc: if proxy OpenURI.open_http(buf, self, proxy, options) return end require 'net/ftp' directories = self.path.split(%r{/}, -1) directories.shift if directories[0] == '' # strip a field before leading slash directories.each {|d| d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") } } unless filename = directories.pop raise ArgumentError, "no filename: #{self.inspect}" end directories.each {|d| if /[\r\n]/ =~ d raise ArgumentError, "invalid directory: #{d.inspect}" end } if /[\r\n]/ =~ filename raise ArgumentError, "invalid filename: #{filename.inspect}" end typecode = self.typecode if typecode && /\A[aid]\z/ !~ typecode raise ArgumentError, "invalid typecode: #{typecode.inspect}" end # The access sequence is defined by RFC 1738 ftp = Net::FTP.open(self.host) # todo: extract user/passwd from .netrc. user = 'anonymous' passwd = nil user, passwd = self.userinfo.split(/:/) if self.userinfo ftp.login(user, passwd) directories.each {|cwd| ftp.voidcmd("CWD #{cwd}") } if typecode # xxx: typecode D is not handled. ftp.voidcmd("TYPE #{typecode.upcase}") end if options[:content_length_proc] options[:content_length_proc].call(ftp.size(filename)) end ftp.retrbinary("RETR #{filename}", 4096) { |str| buf << str options[:progress_proc].call(buf.size) if options[:progress_proc] } ftp.close buf.io.rewind end include OpenURI::OpenRead end end PK|]8Fc  getopts.rbnu[# # getopts.rb - # $Release Version: $ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Yasuo OHBA(SHL Japan Inc. Technology Dept.) # # -- # this is obsolete; use getoptlong # # 2000-03-21 # modified by Minero Aoki # # 2002-03-05 # rewritten by Akinori MUSHA # warn "Warning:#{caller[0].sub(/:in `.*'\z/, '')}: getopts is deprecated after Ruby 1.8.1; use optparse instead" if caller[0] and $VERBOSE $RCS_ID=%q$Header$ # getopts is obsolete. Use GetoptLong. def getopts(single_options, *options) boolopts = {} valopts = {} # # set defaults # single_options.scan(/.:?/) do |opt| if opt.size == 1 boolopts[opt] = false else valopts[opt[0, 1]] = nil end end if single_options options.each do |arg| opt, val = arg.split(':', 2) if val valopts[opt] = val.empty? ? nil : val else boolopts[opt] = false end end # # scan # c = 0 argv = ARGV while arg = argv.shift case arg when /\A--(.*)/ if $1.empty? # xinit -- -bpp 24 break end opt, val = $1.split('=', 2) if opt.size == 1 argv.unshift arg return nil elsif valopts.key? opt # imclean --src +trash valopts[opt] = val || argv.shift or return nil elsif boolopts.key? opt # ruby --verbose boolopts[opt] = true else argv.unshift arg return nil end c += 1 when /\A-(.+)/ opts = $1 until opts.empty? opt = opts.slice!(0, 1) if valopts.key? opt val = opts if val.empty? # ruby -e 'p $:' valopts[opt] = argv.shift or return nil else # cc -ohello ... valopts[opt] = val end c += 1 break elsif boolopts.key? opt boolopts[opt] = true # ruby -h c += 1 else argv.unshift arg return nil end end else argv.unshift arg break end end # # set # $OPT = {} boolopts.each do |opt, val| $OPT[opt] = val sopt = opt.gsub(/[^A-Za-z0-9_]/, '_') eval "$OPT_#{sopt} = val" end valopts.each do |opt, val| $OPT[opt] = val sopt = opt.gsub(/[^A-Za-z0-9_]/, '_') eval "$OPT_#{sopt} = val" end c end PK|]XZFZF logger.rbnu[# logger.rb - simple logging utility # Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi . require 'monitor' # Simple logging utility. # # Author:: NAKAMURA, Hiroshi # Documentation:: NAKAMURA, Hiroshi and Gavin Sinclair # License:: # You can redistribute it and/or modify it under the same terms of Ruby's # license; either the dual license version in 2003, or any later version. # Revision:: $Id: logger.rb 31806 2011-05-30 02:08:57Z nahi $ # # == Description # # The Logger class provides a simple but sophisticated logging utility that # anyone can use because it's included in the Ruby 1.8.x standard library. # # The HOWTOs below give a code-based overview of Logger's usage, but the basic # concept is as follows. You create a Logger object (output to a file or # elsewhere), and use it to log messages. The messages will have varying # levels (+info+, +error+, etc), reflecting their varying importance. The # levels, and their meanings, are: # # +FATAL+:: an unhandleable error that results in a program crash # +ERROR+:: a handleable error condition # +WARN+:: a warning # +INFO+:: generic (useful) information about system operation # +DEBUG+:: low-level information for developers # # So each message has a level, and the Logger itself has a level, which acts # as a filter, so you can control the amount of information emitted from the # logger without having to remove actual messages. # # For instance, in a production system, you may have your logger(s) set to # +INFO+ (or +WARN+ if you don't want the log files growing large with # repetitive information). When you are developing it, though, you probably # want to know about the program's internal state, and would set them to # +DEBUG+. # # === Example # # A simple example demonstrates the above explanation: # # log = Logger.new(STDOUT) # log.level = Logger::WARN # # log.debug("Created logger") # log.info("Program started") # log.warn("Nothing to do!") # # begin # File.each_line(path) do |line| # unless line =~ /^(\w+) = (.*)$/ # log.error("Line in wrong format: #{line}") # end # end # rescue => err # log.fatal("Caught exception; exiting") # log.fatal(err) # end # # Because the Logger's level is set to +WARN+, only the warning, error, and # fatal messages are recorded. The debug and info messages are silently # discarded. # # === Features # # There are several interesting features that Logger provides, like # auto-rolling of log files, setting the format of log messages, and # specifying a program name in conjunction with the message. The next section # shows you how to achieve these things. # # # == HOWTOs # # === How to create a logger # # The options below give you various choices, in more or less increasing # complexity. # # 1. Create a logger which logs messages to STDERR/STDOUT. # # logger = Logger.new(STDERR) # logger = Logger.new(STDOUT) # # 2. Create a logger for the file which has the specified name. # # logger = Logger.new('logfile.log') # # 3. Create a logger for the specified file. # # file = File.open('foo.log', File::WRONLY | File::APPEND) # # To create new (and to remove old) logfile, add File::CREAT like; # # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) # logger = Logger.new(file) # # 4. Create a logger which ages logfile once it reaches a certain size. Leave # 10 "old log files" and each file is about 1,024,000 bytes. # # logger = Logger.new('foo.log', 10, 1024000) # # 5. Create a logger which ages logfile daily/weekly/monthly. # # logger = Logger.new('foo.log', 'daily') # logger = Logger.new('foo.log', 'weekly') # logger = Logger.new('foo.log', 'monthly') # # === How to log a message # # Notice the different methods (+fatal+, +error+, +info+) being used to log # messages of various levels. Other methods in this family are +warn+ and # +debug+. +add+ is used below to log a message of an arbitrary (perhaps # dynamic) level. # # 1. Message in block. # # logger.fatal { "Argument 'foo' not given." } # # 2. Message as a string. # # logger.error "Argument #{ @foo } mismatch." # # 3. With progname. # # logger.info('initialize') { "Initializing..." } # # 4. With severity. # # logger.add(Logger::FATAL) { 'Fatal error!' } # # === How to close a logger # # logger.close # # === Setting severity threshold # # 1. Original interface. # # logger.sev_threshold = Logger::WARN # # 2. Log4r (somewhat) compatible interface. # # logger.level = Logger::INFO # # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN # # # == Format # # Log messages are rendered in the output stream in a certain format. The # default format and a sample are shown below: # # Log format: # SeverityID, [Date Time mSec #pid] SeverityLabel -- ProgName: message # # Log sample: # I, [Wed Mar 03 02:34:24 JST 1999 895701 #19074] INFO -- Main: info. # # You may change the date and time format in this manner: # # logger.datetime_format = "%Y-%m-%d %H:%M:%S" # # e.g. "2004-01-03 00:54:26" # # There is currently no supported way to change the overall format, but you may # have some luck hacking the Format constant. # class Logger VERSION = "1.2.6" ProgName = "#{File.basename(__FILE__)}/#{VERSION}" class Error < RuntimeError; end class ShiftingError < Error; end # Logging severity. module Severity DEBUG = 0 INFO = 1 WARN = 2 ERROR = 3 FATAL = 4 UNKNOWN = 5 end include Severity # Logging severity threshold (e.g. Logger::INFO). attr_accessor :level # Logging program name. attr_accessor :progname # Logging date-time format (string passed to +strftime+). def datetime_format=(datetime_format) @default_formatter.datetime_format = datetime_format end def datetime_format @default_formatter.datetime_format end # Logging formatter. formatter#call is invoked with 4 arguments; severity, # time, progname and msg for each log. Bear in mind that time is a Time and # msg is an Object that user passed and it could not be a String. It is # expected to return a logdev#write-able Object. Default formatter is used # when no formatter is set. attr_accessor :formatter alias sev_threshold level alias sev_threshold= level= # Returns +true+ iff the current severity level allows for the printing of # +DEBUG+ messages. def debug?; @level <= DEBUG; end # Returns +true+ iff the current severity level allows for the printing of # +INFO+ messages. def info?; @level <= INFO; end # Returns +true+ iff the current severity level allows for the printing of # +WARN+ messages. def warn?; @level <= WARN; end # Returns +true+ iff the current severity level allows for the printing of # +ERROR+ messages. def error?; @level <= ERROR; end # Returns +true+ iff the current severity level allows for the printing of # +FATAL+ messages. def fatal?; @level <= FATAL; end # # === Synopsis # # Logger.new(name, shift_age = 7, shift_size = 1048576) # Logger.new(name, shift_age = 'weekly') # # === Args # # +logdev+:: # The log device. This is a filename (String) or IO object (typically # +STDOUT+, +STDERR+, or an open file). # +shift_age+:: # Number of old log files to keep, *or* frequency of rotation (+daily+, # +weekly+ or +monthly+). # +shift_size+:: # Maximum logfile size (only applies when +shift_age+ is a number). # # === Description # # Create an instance. # def initialize(logdev, shift_age = 0, shift_size = 1048576) @progname = nil @level = DEBUG @default_formatter = Formatter.new @formatter = nil @logdev = nil if logdev @logdev = LogDevice.new(logdev, :shift_age => shift_age, :shift_size => shift_size) end end # # === Synopsis # # Logger#add(severity, message = nil, progname = nil) { ... } # # === Args # # +severity+:: # Severity. Constants are defined in Logger namespace: +DEBUG+, +INFO+, # +WARN+, +ERROR+, +FATAL+, or +UNKNOWN+. # +message+:: # The log message. A String or Exception. # +progname+:: # Program name string. Can be omitted. Treated as a message if no +message+ and # +block+ are given. # +block+:: # Can be omitted. Called to get a message string if +message+ is nil. # # === Return # # +true+ if successful, +false+ otherwise. # # When the given severity is not high enough (for this particular logger), log # no message, and return +true+. # # === Description # # Log a message if the given severity is high enough. This is the generic # logging method. Users will be more inclined to use #debug, #info, #warn, # #error, and #fatal. # # Message format: +message+ can be any object, but it has to be # converted to a String in order to log it. Generally, +inspect+ is used # if the given object is not a String. # A special case is an +Exception+ object, which will be printed in detail, # including message, class, and backtrace. See #msg2str for the # implementation if required. # # === Bugs # # * Logfile is not locked. # * Append open does not need to lock file. # * But on the OS which supports multi I/O, records possibly be mixed. # def add(severity, message = nil, progname = nil, &block) severity ||= UNKNOWN if @logdev.nil? or severity < @level return true end progname ||= @progname if message.nil? if block_given? message = yield else message = progname progname = @progname end end @logdev.write( format_message(format_severity(severity), Time.now, progname, message)) true end alias log add # # Dump given message to the log device without any formatting. If no log # device exists, return +nil+. # def <<(msg) unless @logdev.nil? @logdev.write(msg) end end # # Log a +DEBUG+ message. # # See #info for more information. # def debug(progname = nil, &block) add(DEBUG, nil, progname, &block) end # # Log an +INFO+ message. # # The message can come either from the +progname+ argument or the +block+. If # both are provided, then the +block+ is used as the message, and +progname+ # is used as the program name. # # === Examples # # logger.info("MainApp") { "Received connection from #{ip}" } # # ... # logger.info "Waiting for input from user" # # ... # logger.info { "User typed #{input}" } # # You'll probably stick to the second form above, unless you want to provide a # program name (which you can do with Logger#progname= as well). # # === Return # # See #add. # def info(progname = nil, &block) add(INFO, nil, progname, &block) end # # Log a +WARN+ message. # # See #info for more information. # def warn(progname = nil, &block) add(WARN, nil, progname, &block) end # # Log an +ERROR+ message. # # See #info for more information. # def error(progname = nil, &block) add(ERROR, nil, progname, &block) end # # Log a +FATAL+ message. # # See #info for more information. # def fatal(progname = nil, &block) add(FATAL, nil, progname, &block) end # # Log an +UNKNOWN+ message. This will be printed no matter what the logger # level. # # See #info for more information. # def unknown(progname = nil, &block) add(UNKNOWN, nil, progname, &block) end # # Close the logging device. # def close @logdev.close if @logdev end private # Severity label for logging. (max 5 char) SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY) def format_severity(severity) SEV_LABEL[severity] || 'ANY' end def format_message(severity, datetime, progname, msg) (@formatter || @default_formatter).call(severity, datetime, progname, msg) end class Formatter Format = "%s, [%s#%d] %5s -- %s: %s\n" attr_accessor :datetime_format def initialize @datetime_format = nil end def call(severity, time, progname, msg) Format % [severity[0..0], format_datetime(time), $$, severity, progname, msg2str(msg)] end private def format_datetime(time) if @datetime_format.nil? time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec else time.strftime(@datetime_format) end end def msg2str(msg) case msg when ::String msg when ::Exception "#{ msg.message } (#{ msg.class })\n" << (msg.backtrace || []).join("\n") else msg.inspect end end end class LogDevice attr_reader :dev attr_reader :filename class LogDeviceMutex include MonitorMixin end def initialize(log = nil, opt = {}) @dev = @filename = @shift_age = @shift_size = nil @mutex = LogDeviceMutex.new if log.respond_to?(:write) and log.respond_to?(:close) @dev = log else @dev = open_logfile(log) @dev.sync = true @filename = log @shift_age = opt[:shift_age] || 7 @shift_size = opt[:shift_size] || 1048576 end end def write(message) @mutex.synchronize do if @shift_age and @dev.respond_to?(:stat) begin check_shift_log rescue raise Logger::ShiftingError.new("Shifting failed. #{$!}") end end @dev.write(message) end end def close @mutex.synchronize do @dev.close end end private def open_logfile(filename) if (FileTest.exist?(filename)) open(filename, (File::WRONLY | File::APPEND)) else create_logfile(filename) end end def create_logfile(filename) logdev = open(filename, (File::WRONLY | File::APPEND | File::CREAT)) logdev.sync = true add_log_header(logdev) logdev end def add_log_header(file) file.write( "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName] ) end SiD = 24 * 60 * 60 def check_shift_log if @shift_age.is_a?(Integer) # Note: always returns false if '0'. if @filename && (@shift_age > 0) && (@dev.stat.size > @shift_size) shift_log_age end else now = Time.now if @dev.stat.mtime <= previous_period_end(now) shift_log_period(now) end end end def shift_log_age (@shift_age-3).downto(0) do |i| if FileTest.exist?("#{@filename}.#{i}") File.rename("#{@filename}.#{i}", "#{@filename}.#{i+1}") end end @dev.close File.rename("#{@filename}", "#{@filename}.0") @dev = create_logfile(@filename) return true end def shift_log_period(now) postfix = previous_period_end(now).strftime("%Y%m%d") # YYYYMMDD age_file = "#{@filename}.#{postfix}" if FileTest.exist?(age_file) raise RuntimeError.new("'#{ age_file }' already exists.") end @dev.close File.rename("#{@filename}", age_file) @dev = create_logfile(@filename) return true end def previous_period_end(now) case @shift_age when /^daily$/ eod(now - 1 * SiD) when /^weekly$/ eod(now - ((now.wday + 1) * SiD)) when /^monthly$/ eod(now - now.mday * SiD) else now end end def eod(t) Time.mktime(t.year, t.month, t.mday, 23, 59, 59) end end # # == Description # # Application -- Add logging support to your application. # # == Usage # # 1. Define your application class as a sub-class of this class. # 2. Override 'run' method in your class to do many things. # 3. Instantiate it and invoke 'start'. # # == Example # # class FooApp < Application # def initialize(foo_app, application_specific, arguments) # super('FooApp') # Name of the application. # end # # def run # ... # log(WARN, 'warning', 'my_method1') # ... # @log.error('my_method2') { 'Error!' } # ... # end # end # # status = FooApp.new(....).start # class Application include Logger::Severity attr_reader :appname attr_reader :logdev # # == Synopsis # # Application.new(appname = '') # # == Args # # +appname+:: Name of the application. # # == Description # # Create an instance. Log device is +STDERR+ by default. This can be # changed with #set_log. # def initialize(appname = nil) @appname = appname @log = Logger.new(STDERR) @log.progname = @appname @level = @log.level end # # Start the application. Return the status code. # def start status = -1 begin log(INFO, "Start of #{ @appname }.") status = run rescue log(FATAL, "Detected an exception. Stopping ... #{$!} (#{$!.class})\n" << $@.join("\n")) ensure log(INFO, "End of #{ @appname }. (status: #{ status.to_s })") end status end # # Sets the log device for this application. See the class Logger for an # explanation of the arguments. # def set_log(logdev, shift_age = 0, shift_size = 1024000) @log = Logger.new(logdev, shift_age, shift_size) @log.progname = @appname @log.level = @level end def log=(logdev) set_log(logdev) end # # Set the logging threshold, just like Logger#level=. # def level=(level) @level = level @log.level = @level end # # See Logger#add. This application's +appname+ is used. # def log(severity, message = nil, &block) @log.add(severity, message, @appname, &block) if @log end private def run raise RuntimeError.new('Method run must be defined in the derived class.') end end end PK|]y3 3 test/unit/util/observable.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/procwrapper' module Test module Unit module Util # This is a utility class that allows anything mixing # it in to notify a set of listeners about interesting # events. module Observable # We use this for defaults since nil might mean something NOTHING = "NOTHING/#{__id__}" # Adds the passed proc as a listener on the # channel indicated by channel_name. listener_key # is used to remove the listener later; if none is # specified, the proc itself is used. # # Whatever is used as the listener_key is # returned, making it very easy to use the proc # itself as the listener_key: # # listener = add_listener("Channel") { ... } # remove_listener("Channel", listener) def add_listener(channel_name, listener_key=NOTHING, &listener) # :yields: value unless(block_given?) raise ArgumentError.new("No callback was passed as a listener") end key = listener_key if (listener_key == NOTHING) listener_key = listener key = ProcWrapper.new(listener) end channels[channel_name] ||= {} channels[channel_name][key] = listener return listener_key end # Removes the listener indicated by listener_key # from the channel indicated by # channel_name. Returns the registered proc, or # nil if none was found. def remove_listener(channel_name, listener_key) channel = channels[channel_name] return nil unless (channel) key = listener_key if (listener_key.instance_of?(Proc)) key = ProcWrapper.new(listener_key) end if (channel.has_key?(key)) return channel.delete(key) end return nil end # Calls all the procs registered on the channel # indicated by channel_name. If value is # specified, it is passed in to the procs, # otherwise they are called with no arguments. # #-- # # Perhaps this should be private? Would it ever # make sense for an external class to call this # method directly? def notify_listeners(channel_name, *arguments) channel = channels[channel_name] return 0 unless (channel) listeners = channel.values listeners.each { |listener| listener.call(*arguments) } return listeners.size end private def channels @channels ||= {} return @channels end end end end end PK|]}hUUtest/unit/util/procwrapper.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit module Util # Allows the storage of a Proc passed through '&' in a # hash. # # Note: this may be inefficient, since the hash being # used is not necessarily very good. In Observable, # efficiency is not too important, since the hash is # only accessed when adding and removing listeners, # not when notifying. class ProcWrapper # Creates a new wrapper for a_proc. def initialize(a_proc) @a_proc = a_proc @hash = a_proc.inspect.sub(/^(#<#{a_proc.class}:)/){''}.sub(/(>)$/){''}.hex end def hash return @hash end def ==(other) case(other) when ProcWrapper return @a_proc == other.to_proc else return super end end alias :eql? :== def to_proc return @a_proc end end end end end PK|]!test/unit/util/backtracefilter.rbnu[module Test module Unit module Util module BacktraceFilter TESTUNIT_FILE_SEPARATORS = %r{[\\/:]} TESTUNIT_PREFIX = __FILE__.split(TESTUNIT_FILE_SEPARATORS)[0..-3] TESTUNIT_RB_FILE = /\.rb\Z/ def filter_backtrace(backtrace, prefix=nil) return ["No backtrace"] unless(backtrace) split_p = if(prefix) prefix.split(TESTUNIT_FILE_SEPARATORS) else TESTUNIT_PREFIX end match = proc do |e| split_e = e.split(TESTUNIT_FILE_SEPARATORS)[0, split_p.size] next false unless(split_e[0..-2] == split_p[0..-2]) split_e[-1].sub(TESTUNIT_RB_FILE, '') == split_p[-1] end return backtrace unless(backtrace.detect(&match)) found_prefix = false new_backtrace = backtrace.reverse.reject do |e| if(match[e]) found_prefix = true true elsif(found_prefix) false else true end end.reverse new_backtrace = (new_backtrace.empty? ? backtrace : new_backtrace) new_backtrace = new_backtrace.reject(&match) new_backtrace.empty? ? backtrace : new_backtrace end end end end end PK|]ݮ?3G3Gtest/unit/assertions.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/assertionfailederror' require 'test/unit/util/backtracefilter' module Test module Unit ## # Test::Unit::Assertions contains the standard Test::Unit assertions. # Assertions is included in Test::Unit::TestCase. # # To include it in your own code and use its functionality, you simply # need to rescue Test::Unit::AssertionFailedError. Additionally you may # override add_assertion to get notified whenever an assertion is made. # # Notes: # * The message to each assertion, if given, will be propagated with the # failure. # * It is easy to add your own assertions based on assert_block(). # # = Example Custom Assertion # # def deny(boolean, message = nil) # message = build_message message, ' is not false or nil.', boolean # assert_block message do # not boolean # end # end module Assertions ## # The assertion upon which all other assertions are based. Passes if the # block yields true. # # Example: # assert_block "Couldn't do the thing" do # do_the_thing # end public def assert_block(message="assert_block failed.") # :yields: _wrap_assertion do if (! yield) raise AssertionFailedError.new(message.to_s) end end end ## # Asserts that +boolean+ is not false or nil. # # Example: # assert [1, 2].include?(5) public def assert(boolean, message=nil) _wrap_assertion do assert_block("assert should not be called with a block.") { !block_given? } assert_block(build_message(message, " is not true.", boolean)) { boolean } end end ## # Passes if +expected+ == +actual. # # Note that the ordering of arguments is important, since a helpful # error message is generated when this one fails that tells you the # values of expected and actual. # # Example: # assert_equal 'MY STRING', 'my string'.upcase public def assert_equal(expected, actual, message=nil) full_message = build_message(message, < expected but was . EOT assert_block(full_message) { expected == actual } end private def _check_exception_class(args) # :nodoc: args.partition do |klass| next if klass.instance_of?(Module) assert(Exception >= klass, "Should expect a class of exception, #{klass}") true end end private def _expected_exception?(actual_exception, exceptions, modules) # :nodoc: exceptions.include?(actual_exception.class) or modules.any? {|mod| actual_exception.is_a?(mod)} end ## # Passes if the block raises one of the given exceptions. # # Example: # assert_raise RuntimeError, LoadError do # raise 'Boom!!!' # end public def assert_raise(*args) _wrap_assertion do if Module === args.last message = "" else message = args.pop end exceptions, modules = _check_exception_class(args) expected = args.size == 1 ? args.first : args actual_exception = nil full_message = build_message(message, " exception expected but none was thrown.", expected) assert_block(full_message) do begin yield rescue Exception => actual_exception break end false end full_message = build_message(message, " exception expected but was\n?", expected, actual_exception) assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)} actual_exception end end ## # Alias of assert_raise. # # Will be deprecated in 1.9, and removed in 2.0. public def assert_raises(*args, &block) assert_raise(*args, &block) end ## # Passes if +object+ .instance_of? +klass+ # # Example: # assert_instance_of String, 'foo' public def assert_instance_of(klass, object, message="") _wrap_assertion do assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument") full_message = build_message(message, < expected to be an instance of but was . EOT assert_block(full_message){object.instance_of?(klass)} end end ## # Passes if +object+ is nil. # # Example: # assert_nil [1, 2].uniq! public def assert_nil(object, message="") assert_equal(nil, object, message) end ## # Passes if +object+ .kind_of? +klass+ # # Example: # assert_kind_of Object, 'foo' public def assert_kind_of(klass, object, message="") _wrap_assertion do assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.") full_message = build_message(message, "\nexpected to be kind_of\\?\n but was\n.", object, klass, object.class) assert_block(full_message){object.kind_of?(klass)} end end ## # Passes if +object+ .respond_to? +method+ # # Example: # assert_respond_to 'bugbear', :slice public def assert_respond_to(object, method, message="") _wrap_assertion do full_message = build_message(nil, "\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to\\?(:to_str).", method) assert_block(full_message) do method.kind_of?(Symbol) || method.respond_to?(:to_str) end full_message = build_message(message, < of type expected to respond_to\\?. EOT assert_block(full_message) { object.respond_to?(method) } end end ## # Passes if +string+ =~ +pattern+. # # Example: # assert_match(/\d+/, 'five, 6, seven') public def assert_match(pattern, string, message="") _wrap_assertion do pattern = case(pattern) when String Regexp.new(Regexp.escape(pattern)) else pattern end full_message = build_message(message, " expected to be =~\n.", string, pattern) assert_block(full_message) { string =~ pattern } end end ## # Passes if +actual+ .equal? +expected+ (i.e. they are the same # instance). # # Example: # o = Object.new # assert_same o, o public def assert_same(expected, actual, message="") full_message = build_message(message, < with id expected to be equal\\? to with id . EOT assert_block(full_message) { actual.equal?(expected) } end ## # Compares the +object1+ with +object2+ using +operator+. # # Passes if object1.__send__(operator, object2) is true. # # Example: # assert_operator 5, :>=, 4 public def assert_operator(object1, operator, object2, message="") _wrap_assertion do full_message = build_message(nil, "\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator) assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)} full_message = build_message(message, < expected to be ? . EOT assert_block(full_message) { object1.__send__(operator, object2) } end end ## # Passes if block does not raise an exception. # # Example: # assert_nothing_raised do # [1, 2].uniq # end public def assert_nothing_raised(*args) _wrap_assertion do if Module === args.last message = "" else message = args.pop end exceptions, modules = _check_exception_class(args) begin yield rescue Exception => e if ((args.empty? && !e.instance_of?(AssertionFailedError)) || _expected_exception?(e, exceptions, modules)) assert_block(build_message(message, "Exception raised:\n?", e)){false} else raise end end nil end end ## # Flunk always fails. # # Example: # flunk 'Not done testing yet.' public def flunk(message="Flunked") assert_block(build_message(message)){false} end ## # Passes if ! +actual+ .equal? +expected+ # # Example: # assert_not_same Object.new, Object.new public def assert_not_same(expected, actual, message="") full_message = build_message(message, < with id expected to not be equal\\? to with id . EOT assert_block(full_message) { !actual.equal?(expected) } end ## # Passes if +expected+ != +actual+ # # Example: # assert_not_equal 'some string', 5 public def assert_not_equal(expected, actual, message="") full_message = build_message(message, " expected to be != to\n.", expected, actual) assert_block(full_message) { expected != actual } end ## # Passes if ! +object+ .nil? # # Example: # assert_not_nil '1 two 3'.sub!(/two/, '2') public def assert_not_nil(object, message="") full_message = build_message(message, " expected to not be nil.", object) assert_block(full_message){!object.nil?} end ## # Passes if +regexp+ !~ +string+ # # Example: # assert_no_match(/two/, 'one 2 three') public def assert_no_match(regexp, string, message="") _wrap_assertion do assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.") full_message = build_message(message, " expected to not match\n.", regexp, string) assert_block(full_message) { regexp !~ string } end end UncaughtThrow = {NameError => /^uncaught throw \`(.+)\'$/, ThreadError => /^uncaught throw \`(.+)\' in thread /} #` ## # Passes if the block throws +expected_symbol+ # # Example: # assert_throws :done do # throw :done # end public def assert_throws(expected_symbol, message="", &proc) _wrap_assertion do assert_instance_of(Symbol, expected_symbol, "assert_throws expects the symbol that should be thrown for its first argument") assert_block("Should have passed a block to assert_throws."){block_given?} caught = true begin catch(expected_symbol) do proc.call caught = false end full_message = build_message(message, " should have been thrown.", expected_symbol) assert_block(full_message){caught} rescue NameError, ThreadError => error if UncaughtThrow[error.class] !~ error.message raise error end full_message = build_message(message, " expected to be thrown but\n was thrown.", expected_symbol, $1.intern) flunk(full_message) end end end ## # Passes if block does not throw anything. # # Example: # assert_nothing_thrown do # [1, 2].uniq # end public def assert_nothing_thrown(message="", &proc) _wrap_assertion do assert(block_given?, "Should have passed a block to assert_nothing_thrown") begin proc.call rescue NameError, ThreadError => error if UncaughtThrow[error.class] !~ error.message raise error end full_message = build_message(message, " was thrown when nothing was expected", $1.intern) flunk(full_message) end assert(true, "Expected nothing to be thrown") end end ## # Passes if +expected_float+ and +actual_float+ are equal # within +delta+ tolerance. # # Example: # assert_in_delta 0.05, (50000.0 / 10**6), 0.00001 public def assert_in_delta(expected_float, actual_float, delta, message="") _wrap_assertion do {expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name| assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not") end assert_operator(delta, :>=, 0.0, "The delta should not be negative") full_message = build_message(message, < and expected to be within of each other. EOT assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f } end end ## # Passes if the method send returns a true value. # # +send_array+ is composed of: # * A receiver # * A method # * Arguments to the method # # Example: # assert_send [[1, 2], :include?, 4] public def assert_send(send_array, message="") _wrap_assertion do assert_instance_of(Array, send_array, "assert_send requires an array of send information") assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name") full_message = build_message(message, < expected to respond to with a true value. EOT assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) } end end ## # Builds a failure message. +head+ is added before the +template+ and # +arguments+ replaces the '?'s positionally in the template. public def build_message(head, template=nil, *arguments) template &&= template.chomp return AssertionMessage.new(head, template, arguments) end private def _wrap_assertion @_assertion_wrapped ||= false unless (@_assertion_wrapped) @_assertion_wrapped = true begin add_assertion return yield ensure @_assertion_wrapped = false end else return yield end end ## # Called whenever an assertion is made. Define this in classes that # include Test::Unit::Assertions to record assertion counts. private def add_assertion end ## # Select whether or not to use the pretty-printer. If this option is set # to false before any assertions are made, pp.rb will not be required. public def self.use_pp=(value) AssertionMessage.use_pp = value end # :stopdoc: class AssertionMessage @use_pp = true class << self attr_accessor :use_pp end class Literal def initialize(value) @value = value end def inspect @value.to_s end end class Template def self.create(string) parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : []) self.new(parts) end attr_reader :count def initialize(parts) @parts = parts @count = parts.find_all{|e| e == '?'}.size end def result(parameters) raise "The number of parameters does not match the number of substitutions." if(parameters.size != count) params = parameters.dup @parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('') end end def self.literal(value) Literal.new(value) end include Util::BacktraceFilter def initialize(head, template_string, parameters) @head = head @template_string = template_string @parameters = parameters end def convert(object) case object when Exception < Message: <#{convert(object.message)}> ---Backtrace--- #{filter_backtrace(object.backtrace).join("\n")} --------------- EOM else if(self.class.use_pp) begin require 'pp' rescue LoadError self.class.use_pp = false return object.inspect end unless(defined?(PP)) PP.pp(object, '').chomp else object.inspect end end end def template @template ||= Template.create(@template_string) end def add_period(string) (string =~ /\.\Z/ ? string : string + '.') end def to_s message_parts = [] if (@head) head = @head.to_s unless(head.empty?) message_parts << add_period(head) end end tail = template.result(@parameters.collect{|e| convert(e)}) message_parts << tail unless(tail.empty?) message_parts.join("\n") end end # :startdoc: end end end PK|]K4test/unit/testresult.rbnu[#-- # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/observable' module Test module Unit # Collects Test::Unit::Failure and Test::Unit::Error so that # they can be displayed to the user. To this end, observers # can be added to it, allowing the dynamic updating of, say, a # UI. class TestResult include Util::Observable CHANGED = "CHANGED" FAULT = "FAULT" attr_reader(:run_count, :assertion_count) # Constructs a new, empty TestResult. def initialize @run_count, @assertion_count = 0, 0 @failures, @errors = Array.new, Array.new end # Records a test run. def add_run @run_count += 1 notify_listeners(CHANGED, self) end # Records a Test::Unit::Failure. def add_failure(failure) @failures << failure notify_listeners(FAULT, failure) notify_listeners(CHANGED, self) end # Records a Test::Unit::Error. def add_error(error) @errors << error notify_listeners(FAULT, error) notify_listeners(CHANGED, self) end # Records an individual assertion. def add_assertion @assertion_count += 1 notify_listeners(CHANGED, self) end # Returns a string contain the recorded runs, assertions, # failures and errors in this TestResult. def to_s "#{run_count} tests, #{assertion_count} assertions, #{failure_count} failures, #{error_count} errors" end # Returns whether or not this TestResult represents # successful completion. def passed? return @failures.empty? && @errors.empty? end # Returns the number of failures this TestResult has # recorded. def failure_count return @failures.size end # Returns the number of errors this TestResult has # recorded. def error_count return @errors.size end end end end PK|]test/unit/error.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/util/backtracefilter' module Test module Unit # Encapsulates an error in a test. Created by # Test::Unit::TestCase when it rescues an exception thrown # during the processing of a test. class Error include Util::BacktraceFilter attr_reader(:test_name, :exception) SINGLE_CHARACTER = 'E' # Creates a new Error with the given test_name and # exception. def initialize(test_name, exception) @test_name = test_name @exception = exception end # Returns a single character representation of an error. def single_character_display SINGLE_CHARACTER end # Returns the message associated with the error. def message "#{@exception.class.name}: #{@exception.message}" end # Returns a brief version of the error description. def short_display "#@test_name: #{message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display backtrace = filter_backtrace(@exception.backtrace).join("\n ") "Error:\n#@test_name:\n#{message}\n #{backtrace}" end # Overridden to return long_display. def to_s long_display end end end end PK|]Fӥtest/unit/testsuite.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # A collection of tests which can be #run. # # Note: It is easy to confuse a TestSuite instance with # something that has a static suite method; I know because _I_ # have trouble keeping them straight. Think of something that # has a suite method as simply providing a way to get a # meaningful TestSuite instance. class TestSuite attr_reader :name, :tests STARTED = name + "::STARTED" FINISHED = name + "::FINISHED" # Creates a new TestSuite with the given name. def initialize(name="Unnamed TestSuite") @name = name @tests = [] end # Runs the tests and/or suites contained in this # TestSuite. def run(result, &progress_block) yield(STARTED, name) @tests.each do |test| test.run(result, &progress_block) end yield(FINISHED, name) end # Adds the test to the suite. def <<(test) @tests << test self end def delete(test) @tests.delete(test) end # Retuns the rolled up number of tests in this suite; # i.e. if the suite contains other suites, it counts the # tests within those suites, not the suites themselves. def size total_size = 0 @tests.each { |test| total_size += test.size } total_size end def empty? tests.empty? end # Overridden to return the name given the suite at # creation. def to_s @name end # It's handy to be able to compare TestSuite instances. def ==(other) return false unless(other.kind_of?(self.class)) return false unless(@name == other.name) @tests == other.tests end end end end PK|]xtest/unit/testcase.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/assertions' require 'test/unit/failure' require 'test/unit/error' require 'test/unit/testsuite' require 'test/unit/assertionfailederror' require 'test/unit/util/backtracefilter' module Test module Unit # Ties everything together. If you subclass and add your own # test methods, it takes care of making them into tests and # wrapping those tests into a suite. It also does the # nitty-gritty of actually running an individual test and # collecting its results into a Test::Unit::TestResult object. class TestCase include Assertions include Util::BacktraceFilter attr_reader :method_name STARTED = name + "::STARTED" FINISHED = name + "::FINISHED" ## # These exceptions are not caught by #run. PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt, SystemExit] # Creates a new instance of the fixture for running the # test represented by test_method_name. def initialize(test_method_name) unless(respond_to?(test_method_name) and (method(test_method_name).arity == 0 || method(test_method_name).arity == -1)) throw :invalid_test end @method_name = test_method_name @test_passed = true end # Rolls up all of the test* methods in the fixture into # one suite, creating a new instance of the fixture for # each method. def self.suite method_names = public_instance_methods(true) tests = method_names.delete_if {|method_name| method_name !~ /^test./} suite = TestSuite.new(name) tests.sort.each do |test| catch(:invalid_test) do suite << new(test) end end if (suite.empty?) catch(:invalid_test) do suite << new("default_test") end end return suite end # Runs the individual test method represented by this # instance of the fixture, collecting statistics, failures # and errors in result. def run(result) yield(STARTED, name) @_result = result begin setup __send__(@method_name) rescue AssertionFailedError => e add_failure(e.message, e.backtrace) rescue Exception raise if PASSTHROUGH_EXCEPTIONS.include? $!.class add_error($!) ensure begin teardown rescue AssertionFailedError => e add_failure(e.message, e.backtrace) rescue Exception raise if PASSTHROUGH_EXCEPTIONS.include? $!.class add_error($!) end end result.add_run yield(FINISHED, name) end # Called before every test method runs. Can be used # to set up fixture information. def setup end # Called after every test method runs. Can be used to tear # down fixture information. def teardown end def default_test flunk("No tests were specified") end # Returns whether this individual test passed or # not. Primarily for use in teardown so that artifacts # can be left behind if the test fails. def passed? return @test_passed end private :passed? def size 1 end def add_assertion @_result.add_assertion end private :add_assertion def add_failure(message, all_locations=caller()) @test_passed = false @_result.add_failure(Failure.new(name, filter_backtrace(all_locations), message)) end private :add_failure def add_error(exception) @test_passed = false @_result.add_error(Error.new(name, exception)) end private :add_error # Returns a human-readable name for the specific test that # this instance of TestCase represents. def name "#{@method_name}(#{self.class.name})" end # Overridden to return #name. def to_s name end # It's handy to be able to compare TestCase instances. def ==(other) return false unless(other.kind_of?(self.class)) return false unless(@method_name == other.method_name) self.class == other.class end end end end PK|]aAmVVtest/unit/autorunner.rbnu[require 'test/unit' require 'test/unit/ui/testrunnerutilities' require 'optparse' module Test module Unit class AutoRunner def self.run(force_standalone=false, default_dir=nil, argv=ARGV, &block) r = new(force_standalone || standalone?, &block) r.base = default_dir r.process_args(argv) r.run end def self.standalone? return false unless("-e" == $0) ObjectSpace.each_object(Class) do |klass| return false if(klass < TestCase) end true end RUNNERS = { :console => proc do |r| require 'test/unit/ui/console/testrunner' Test::Unit::UI::Console::TestRunner end, :gtk => proc do |r| require 'test/unit/ui/gtk/testrunner' Test::Unit::UI::GTK::TestRunner end, :gtk2 => proc do |r| require 'test/unit/ui/gtk2/testrunner' Test::Unit::UI::GTK2::TestRunner end, :fox => proc do |r| require 'test/unit/ui/fox/testrunner' Test::Unit::UI::Fox::TestRunner end, :tk => proc do |r| require 'test/unit/ui/tk/testrunner' Test::Unit::UI::Tk::TestRunner end, } OUTPUT_LEVELS = [ [:silent, UI::SILENT], [:progress, UI::PROGRESS_ONLY], [:normal, UI::NORMAL], [:verbose, UI::VERBOSE], ] COLLECTORS = { :objectspace => proc do |r| require 'test/unit/collector/objectspace' c = Collector::ObjectSpace.new c.filter = r.filters c.collect($0.sub(/\.rb\Z/, '')) end, :dir => proc do |r| require 'test/unit/collector/dir' c = Collector::Dir.new c.filter = r.filters c.pattern.concat(r.pattern) if(r.pattern) c.exclude.concat(r.exclude) if(r.exclude) c.base = r.base $:.push(r.base) if r.base c.collect(*(r.to_run.empty? ? ['.'] : r.to_run)) end, } attr_reader :suite attr_accessor :output_level, :filters, :to_run, :pattern, :exclude, :base, :workdir attr_writer :runner, :collector def initialize(standalone) Unit.run = true @standalone = standalone @runner = RUNNERS[:console] @collector = COLLECTORS[(standalone ? :dir : :objectspace)] @filters = [] @to_run = [] @output_level = UI::NORMAL @workdir = nil yield(self) if(block_given?) end def process_args(args = ARGV) begin options.order!(args) {|arg| @to_run << arg} rescue OptionParser::ParseError => e puts e puts options $! = nil abort else @filters << proc{false} unless(@filters.empty?) end not @to_run.empty? end def options @options ||= OptionParser.new do |o| o.banner = "Test::Unit automatic runner." o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]" o.on o.on('-r', '--runner=RUNNER', RUNNERS, "Use the given RUNNER.", "(" + keyword_display(RUNNERS) + ")") do |r| @runner = r end if(@standalone) o.on('-b', '--basedir=DIR', "Base directory of test suites.") do |b| @base = b end o.on('-w', '--workdir=DIR', "Working directory to run tests.") do |w| @workdir = w end o.on('-a', '--add=TORUN', Array, "Add TORUN to the list of things to run;", "can be a file or a directory.") do |a| @to_run.concat(a) end @pattern = [] o.on('-p', '--pattern=PATTERN', Regexp, "Match files to collect against PATTERN.") do |e| @pattern << e end @exclude = [] o.on('-x', '--exclude=PATTERN', Regexp, "Ignore files to collect against PATTERN.") do |e| @exclude << e end end o.on('-n', '--name=NAME', String, "Runs tests matching NAME.", "(patterns may be used).") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) case n when Regexp @filters << proc{|t| n =~ t.method_name ? true : nil} else @filters << proc{|t| n == t.method_name ? true : nil} end end o.on('-t', '--testcase=TESTCASE', String, "Runs tests in TestCases matching TESTCASE.", "(patterns may be used).") do |n| n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n) case n when Regexp @filters << proc{|t| n =~ t.class.name ? true : nil} else @filters << proc{|t| n == t.class.name ? true : nil} end end o.on('-I', "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]", "Appends directory list to $LOAD_PATH.") do |dirs| $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR)) end o.on('-v', '--verbose=[LEVEL]', OUTPUT_LEVELS, "Set the output level (default is verbose).", "(" + keyword_display(OUTPUT_LEVELS) + ")") do |l| @output_level = l || UI::VERBOSE end o.on('--', "Stop processing options so that the", "remaining options will be passed to the", "test."){o.terminate} o.on('-h', '--help', 'Display this help.'){puts o; exit} o.on_tail o.on_tail('Deprecated options:') o.on_tail('--console', 'Console runner (use --runner).') do warn("Deprecated option (--console).") @runner = RUNNERS[:console] end o.on_tail('--gtk', 'GTK runner (use --runner).') do warn("Deprecated option (--gtk).") @runner = RUNNERS[:gtk] end o.on_tail('--fox', 'Fox runner (use --runner).') do warn("Deprecated option (--fox).") @runner = RUNNERS[:fox] end o.on_tail end end def keyword_display(array) list = array.collect {|e, *| e.to_s} Array === array or list.sort! list.collect {|e| e.sub(/^(.)([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')}.join(", ") end def run @suite = @collector[self] result = @runner[self] or return false Dir.chdir(@workdir) if @workdir result.run(@suite, @output_level).passed? end end end end PK|]=!n n test/unit/collector/dir.rbnu[require 'test/unit/testsuite' require 'test/unit/collector' module Test module Unit module Collector class Dir include Collector attr_reader :pattern, :exclude attr_accessor :base def initialize(dir=::Dir, file=::File, object_space=::ObjectSpace, req=nil) super() @dir = dir @file = file @object_space = object_space @req = req @pattern = [/\btest_.*\.rb\Z/m] @exclude = [] end def collect(*from) basedir = @base $:.push(basedir) if basedir if(from.empty?) recursive_collect('.', find_test_cases) elsif(from.size == 1) recursive_collect(from.first, find_test_cases) else suites = [] from.each do |f| suite = recursive_collect(f, find_test_cases) suites << suite unless(suite.tests.empty?) end suite = TestSuite.new("[#{from.join(', ')}]") sort(suites).each{|s| suite << s} suite end ensure $:.delete_at($:.rindex(basedir)) if basedir end def find_test_cases(ignore=[]) cases = [] @object_space.each_object(Class) do |c| cases << c if(c < TestCase && !ignore.include?(c)) end ignore.concat(cases) cases end def recursive_collect(name, already_gathered) sub_suites = [] path = realdir(name) if @file.directory?(path) dir_name = name unless name == '.' @dir.entries(path).each do |e| next if(e == '.' || e == '..') e_name = dir_name ? @file.join(dir_name, e) : e if @file.directory?(realdir(e_name)) next if /\ACVS\z/ =~ e sub_suite = recursive_collect(e_name, already_gathered) sub_suites << sub_suite unless(sub_suite.empty?) else next if /~\z/ =~ e_name or /\A\.\#/ =~ e if @pattern and !@pattern.empty? next unless @pattern.any? {|pat| pat =~ e_name} end if @exclude and !@exclude.empty? next if @exclude.any? {|pat| pat =~ e_name} end collect_file(e_name, sub_suites, already_gathered) end end else collect_file(name, sub_suites, already_gathered) end suite = TestSuite.new(@file.basename(name)) sort(sub_suites).each{|s| suite << s} suite end def collect_file(name, suites, already_gathered) dir = @file.dirname(@file.expand_path(name, @base)) $:.unshift(dir) if(@req) @req.require(name) else require(name) end find_test_cases(already_gathered).each{|t| add_suite(suites, t.suite)} ensure $:.delete_at($:.rindex(dir)) if(dir) end def realdir(path) if @base @file.join(@base, path) else path end end end end end end PK|]++"test/unit/collector/objectspace.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/collector' module Test module Unit module Collector class ObjectSpace include Collector NAME = 'collected from the ObjectSpace' def initialize(source=::ObjectSpace) super() @source = source end def collect(name=NAME) suite = TestSuite.new(name) sub_suites = [] @source.each_object(Class) do |klass| if(Test::Unit::TestCase > klass) add_suite(sub_suites, klass.suite) end end sort(sub_suites).each{|s| suite << s} suite end end end end end PK|] J))!test/unit/assertionfailederror.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # Thrown by Test::Unit::Assertions when an assertion fails. class AssertionFailedError < StandardError end end end PK|]&&test/unit/failure.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit # Encapsulates a test failure. Created by Test::Unit::TestCase # when an assertion fails. class Failure attr_reader :test_name, :location, :message SINGLE_CHARACTER = 'F' # Creates a new Failure with the given location and # message. def initialize(test_name, location, message) @test_name = test_name @location = location @message = message end # Returns a single character representation of a failure. def single_character_display SINGLE_CHARACTER end # Returns a brief version of the error description. def short_display "#@test_name: #{@message.split("\n")[0]}" end # Returns a verbose version of the error description. def long_display location_display = if(location.size == 1) location[0].sub(/\A(.+:\d+).*/, ' [\\1]') else "\n [#{location.join("\n ")}]" end "Failure:\n#@test_name#{location_display}:\n#@message" end # Overridden to return long_display. def to_s long_display end end end end PK|]\~!~!test/unit/ui/fox/testrunner.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'fox' require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/testrunnerutilities' include Fox module Test module Unit module UI module Fox # Runs a Test::Unit::TestSuite in a Fox UI. Obviously, # this one requires you to have Fox # (http://www.fox-toolkit.org/fox.html) and the Ruby # Fox extension (http://fxruby.sourceforge.net/) # installed. class TestRunner extend TestRunnerUtilities RED_STYLE = FXRGBA(0xFF,0,0,0xFF) #0xFF000000 GREEN_STYLE = FXRGBA(0,0xFF,0,0xFF) #0x00FF0000 # Creates a new TestRunner for running the passed # suite. def initialize(suite, output_level = NORMAL) if (suite.respond_to?(:suite)) @suite = suite.suite else @suite = suite end @result = nil @red = false end # Begins the test run. def start setup_ui setup_mediator attach_to_mediator start_ui @result end def setup_mediator @mediator = TestRunnerMediator.new(@suite) suite_name = @suite.to_s if ( @suite.kind_of?(Module) ) suite_name = @suite.name end @suite_name_entry.text = suite_name end def attach_to_mediator @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui)) @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestResult::CHANGED, &method(:result_changed)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) end def start_ui @application.create @window.show(PLACEMENT_SCREEN) @application.addTimeout(1) do @mediator.run_suite end @application.run end def stop @application.exit(0) end def reset_ui(count) @test_progress_bar.barColor = GREEN_STYLE @test_progress_bar.total = count @test_progress_bar.progress = 0 @red = false @test_count_label.text = "0" @assertion_count_label.text = "0" @failure_count_label.text = "0" @error_count_label.text = "0" @fault_list.clearItems end def add_fault(fault) if ( ! @red ) @test_progress_bar.barColor = RED_STYLE @red = true end item = FaultListItem.new(fault) @fault_list.appendItem(item) end def show_fault(fault) raw_show_fault(fault.long_display) end def raw_show_fault(string) @detail_text.setText(string) end def clear_fault raw_show_fault("") end def result_changed(result) @test_progress_bar.progress = result.run_count @test_count_label.text = result.run_count.to_s @assertion_count_label.text = result.assertion_count.to_s @failure_count_label.text = result.failure_count.to_s @error_count_label.text = result.error_count.to_s # repaint now! @info_panel.repaint @application.flush end def started(result) @result = result output_status("Started...") end def test_started(test_name) output_status("Running #{test_name}...") end def finished(elapsed_time) output_status("Finished in #{elapsed_time} seconds") end def output_status(string) @status_entry.text = string @status_entry.repaint end def setup_ui @application = create_application create_tooltip(@application) @window = create_window(@application) @status_entry = create_entry(@window) main_panel = create_main_panel(@window) suite_panel = create_suite_panel(main_panel) create_label(suite_panel, "Suite:") @suite_name_entry = create_entry(suite_panel) create_button(suite_panel, "&Run\tRun the current suite", proc { @mediator.run_suite }) @test_progress_bar = create_progress_bar(main_panel) @info_panel = create_info_panel(main_panel) create_label(@info_panel, "Tests:") @test_count_label = create_label(@info_panel, "0") create_label(@info_panel, "Assertions:") @assertion_count_label = create_label(@info_panel, "0") create_label(@info_panel, "Failures:") @failure_count_label = create_label(@info_panel, "0") create_label(@info_panel, "Errors:") @error_count_label = create_label(@info_panel, "0") list_panel = create_list_panel(main_panel) @fault_list = create_fault_list(list_panel) detail_panel = create_detail_panel(main_panel) @detail_text = create_text(detail_panel) end def create_application app = FXApp.new("TestRunner", "Test::Unit") app.init([]) app end def create_window(app) FXMainWindow.new(app, "Test::Unit TestRunner", nil, nil, DECOR_ALL, 0, 0, 450) end def create_tooltip(app) FXTooltip.new(app) end def create_main_panel(parent) panel = FXVerticalFrame.new(parent, LAYOUT_FILL_X | LAYOUT_FILL_Y) panel.vSpacing = 10 panel end def create_suite_panel(parent) FXHorizontalFrame.new(parent, LAYOUT_SIDE_LEFT | LAYOUT_FILL_X) end def create_button(parent, text, action) FXButton.new(parent, text).connect(SEL_COMMAND, &action) end def create_progress_bar(parent) FXProgressBar.new(parent, nil, 0, PROGRESSBAR_NORMAL | LAYOUT_FILL_X) end def create_info_panel(parent) FXMatrix.new(parent, 1, MATRIX_BY_ROWS | LAYOUT_FILL_X) end def create_label(parent, text) FXLabel.new(parent, text, nil, JUSTIFY_CENTER_X | LAYOUT_FILL_COLUMN) end def create_list_panel(parent) FXHorizontalFrame.new(parent, LAYOUT_FILL_X | FRAME_SUNKEN | FRAME_THICK) end def create_fault_list(parent) list = FXList.new(parent, 10, nil, 0, LIST_SINGLESELECT | LAYOUT_FILL_X) #, 0, 0, 0, 150) list.connect(SEL_COMMAND) do |sender, sel, ptr| if sender.retrieveItem(sender.currentItem).selected? show_fault(sender.retrieveItem(sender.currentItem).fault) else clear_fault end end list end def create_detail_panel(parent) FXHorizontalFrame.new(parent, LAYOUT_FILL_X | LAYOUT_FILL_Y | FRAME_SUNKEN | FRAME_THICK) end def create_text(parent) FXText.new(parent, nil, 0, TEXT_READONLY | LAYOUT_FILL_X | LAYOUT_FILL_Y) end def create_entry(parent) entry = FXTextField.new(parent, 30, nil, 0, TEXTFIELD_NORMAL | LAYOUT_SIDE_BOTTOM | LAYOUT_FILL_X) entry.disable entry end end class FaultListItem < FXListItem attr_reader(:fault) def initialize(fault) super(fault.short_display) @fault = fault end end end end end end if __FILE__ == $0 Test::Unit::UI::Fox::TestRunner.start_command_line_test end PK|]2>>test/unit/ui/gtk2/testrunner.rbnu[#-- # # Author:: Kenta MURATA. # Copyright:: Copyright (c) 2000-2002 Kenta MURATA. All rights reserved. # License:: Ruby license. require "gtk2" require "test/unit/ui/testrunnermediator" require "test/unit/ui/testrunnerutilities" module Test module Unit module UI module GTK2 Gtk.init class EnhancedLabel < Gtk::Label def set_text(text) super(text.gsub(/\n\t/, "\n ")) end end class FaultList < Gtk::TreeView def initialize @faults = [] @model = Gtk::ListStore.new(String, String) super(@model) column = Gtk::TreeViewColumn.new column.visible = false append_column(column) renderer = Gtk::CellRendererText.new column = Gtk::TreeViewColumn.new("Failures", renderer, {:text => 1}) append_column(column) selection.mode = Gtk::SELECTION_SINGLE set_rules_hint(true) set_headers_visible(false) end # def initialize def add_fault(fault) @faults.push(fault) iter = @model.append iter.set_value(0, (@faults.length - 1).to_s) iter.set_value(1, fault.short_display) end # def add_fault(fault) def get_fault(iter) @faults[iter.get_value(0).to_i] end # def get_fault def clear model.clear end # def clear end class TestRunner extend TestRunnerUtilities def lazy_initialize(symbol) if !instance_eval("defined?(@#{symbol})") then yield end return instance_eval("@#{symbol}") end private :lazy_initialize def status_entry lazy_initialize(:status_entry) do @status_entry = Gtk::Entry.new @status_entry.editable = false end end private :status_entry def status_panel lazy_initialize(:status_panel) do @status_panel = Gtk::HBox.new @status_panel.border_width = 10 @status_panel.pack_start(status_entry, true, true, 0) end end private :status_panel def fault_detail_label lazy_initialize(:fault_detail_label) do @fault_detail_label = EnhancedLabel.new("") # style = Gtk::Style.new # font = Gdk::Font. # font_load("-*-Courier 10 Pitch-medium-r-normal--*-120-*-*-*-*-*-*") # style.set_font(font) # @fault_detail_label.style = style @fault_detail_label.justify = Gtk::JUSTIFY_LEFT @fault_detail_label.wrap = false end end private :fault_detail_label def inner_detail_sub_panel lazy_initialize(:inner_detail_sub_panel) do @inner_detail_sub_panel = Gtk::HBox.new @inner_detail_sub_panel.pack_start(fault_detail_label, false, false, 0) end end private :inner_detail_sub_panel def outer_detail_sub_panel lazy_initialize(:outer_detail_sub_panel) do @outer_detail_sub_panel = Gtk::VBox.new @outer_detail_sub_panel.pack_start(inner_detail_sub_panel, false, false, 0) end end private :outer_detail_sub_panel def detail_scrolled_window lazy_initialize(:detail_scrolled_window) do @detail_scrolled_window = Gtk::ScrolledWindow.new @detail_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) @detail_scrolled_window. set_size_request(400, @detail_scrolled_window.allocation.height) @detail_scrolled_window.add_with_viewport(outer_detail_sub_panel) end end private :detail_scrolled_window def detail_panel lazy_initialize(:detail_panel) do @detail_panel = Gtk::HBox.new @detail_panel.border_width = 10 @detail_panel.pack_start(detail_scrolled_window, true, true, 0) end end private :detail_panel def fault_list lazy_initialize(:fault_list) do @fault_list = FaultList.new end end private :fault_list def list_scrolled_window lazy_initialize(:list_scrolled_window) do @list_scrolled_window = Gtk::ScrolledWindow.new @list_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) @list_scrolled_window. set_size_request(@list_scrolled_window.allocation.width, 150) @list_scrolled_window.add_with_viewport(fault_list) end end private :list_scrolled_window def list_panel lazy_initialize(:list_panel) do @list_panel = Gtk::HBox.new @list_panel.border_width = 10 @list_panel.pack_start(list_scrolled_window, true, true, 0) end end private :list_panel def error_count_label lazy_initialize(:error_count_label) do @error_count_label = Gtk::Label.new("0") @error_count_label.justify = Gtk::JUSTIFY_LEFT end end private :error_count_label def failure_count_label lazy_initialize(:failure_count_label) do @failure_count_label = Gtk::Label.new("0") @failure_count_label.justify = Gtk::JUSTIFY_LEFT end end private :failure_count_label def assertion_count_label lazy_initialize(:assertion_count_label) do @assertion_count_label = Gtk::Label.new("0") @assertion_count_label.justify = Gtk::JUSTIFY_LEFT end end private :assertion_count_label def run_count_label lazy_initialize(:run_count_label) do @run_count_label = Gtk::Label.new("0") @run_count_label.justify = Gtk::JUSTIFY_LEFT end end private :run_count_label def info_panel lazy_initialize(:info_panel) do @info_panel = Gtk::HBox.new(false, 0) @info_panel.border_width = 10 @info_panel.pack_start(Gtk::Label.new("Runs:"), false, false, 0) @info_panel.pack_start(run_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Assertions:"), false, false, 0) @info_panel.pack_start(assertion_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Failures:"), false, false, 0) @info_panel.pack_start(failure_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Errors:"), false, false, 0) @info_panel.pack_start(error_count_label, true, false, 0) end end # def info_panel private :info_panel def green_style lazy_initialize(:green_style) do @green_style = Gtk::Style.new @green_style.set_bg(Gtk::STATE_PRELIGHT, 0x0000, 0xFFFF, 0x0000) end end # def green_style private :green_style def red_style lazy_initialize(:red_style) do @red_style = Gtk::Style.new @red_style.set_bg(Gtk::STATE_PRELIGHT, 0xFFFF, 0x0000, 0x0000) end end # def red_style private :red_style def test_progress_bar lazy_initialize(:test_progress_bar) { @test_progress_bar = Gtk::ProgressBar.new @test_progress_bar.fraction = 0.0 @test_progress_bar. set_size_request(@test_progress_bar.allocation.width, info_panel.size_request[1]) @test_progress_bar.style = green_style } end # def test_progress_bar private :test_progress_bar def progress_panel lazy_initialize(:progress_panel) do @progress_panel = Gtk::HBox.new(false, 10) @progress_panel.border_width = 10 @progress_panel.pack_start(test_progress_bar, true, true, 0) end end # def progress_panel def run_button lazy_initialize(:run_button) do @run_button = Gtk::Button.new("Run") end end # def run_button def suite_name_entry lazy_initialize(:suite_name_entry) do @suite_name_entry = Gtk::Entry.new @suite_name_entry.editable = false end end # def suite_name_entry private :suite_name_entry def suite_panel lazy_initialize(:suite_panel) do @suite_panel = Gtk::HBox.new(false, 10) @suite_panel.border_width = 10 @suite_panel.pack_start(Gtk::Label.new("Suite:"), false, false, 0) @suite_panel.pack_start(suite_name_entry, true, true, 0) @suite_panel.pack_start(run_button, false, false, 0) end end # def suite_panel private :suite_panel def main_panel lazy_initialize(:main_panel) do @main_panel = Gtk::VBox.new(false, 0) @main_panel.pack_start(suite_panel, false, false, 0) @main_panel.pack_start(progress_panel, false, false, 0) @main_panel.pack_start(info_panel, false, false, 0) @main_panel.pack_start(list_panel, false, false, 0) @main_panel.pack_start(detail_panel, true, true, 0) @main_panel.pack_start(status_panel, false, false, 0) end end # def main_panel private :main_panel def main_window lazy_initialize(:main_window) do @main_window = Gtk::Window.new(Gtk::Window::TOPLEVEL) @main_window.set_title("Test::Unit TestRunner") @main_window.set_default_size(800, 600) @main_window.set_resizable(true) @main_window.add(main_panel) end end # def main_window private :main_window def setup_ui main_window.signal_connect("destroy", nil) { stop } main_window.show_all fault_list.selection.signal_connect("changed", nil) do |selection, data| if selection.selected then show_fault(fault_list.get_fault(selection.selected)) else clear_fault end end end # def setup_ui private :setup_ui def output_status(string) status_entry.set_text(string) end # def output_status(string) private :output_status def finished(elapsed_time) test_progress_bar.fraction = 1.0 output_status("Finished in #{elapsed_time} seconds") end # def finished(elapsed_time) private :finished def test_started(test_name) output_status("Running #{test_name}...") end # def test_started(test_name) private :test_started def started(result) @result = result output_status("Started...") end # def started(result) private :started def test_finished(result) test_progress_bar.fraction += 1.0 / @count end # def test_finished(result) def result_changed(result) run_count_label.label = result.run_count.to_s assertion_count_label.label = result.assertion_count.to_s failure_count_label.label = result.failure_count.to_s error_count_label.label = result.error_count.to_s end # def result_changed(result) private :result_changed def clear_fault raw_show_fault("") end # def clear_fault private :clear_fault def raw_show_fault(string) fault_detail_label.set_text(string) outer_detail_sub_panel.queue_resize end # def raw_show_fault(string) private :raw_show_fault def show_fault(fault) raw_show_fault(fault.long_display) end # def show_fault(fault) private :show_fault def add_fault(fault) if not @red then test_progress_bar.style = red_style @red = true end fault_list.add_fault(fault) end # def add_fault(fault) private :add_fault def reset_ui(count) test_progress_bar.style = green_style test_progress_bar.fraction = 0.0 @count = count + 1 @red = false run_count_label.set_text("0") assertion_count_label.set_text("0") failure_count_label.set_text("0") error_count_label.set_text("0") fault_list.clear end # def reset_ui(count) private :reset_ui def stop Gtk.main_quit end # def stop private :stop def run_test @runner.raise(@restart_signal) end private :run_test def start_ui @viewer.run running = false begin loop do if (running ^= true) run_button.child.text = "Stop" @mediator.run_suite else run_button.child.text = "Run" @viewer.join break end end rescue @restart_signal retry rescue end end # def start_ui private :start_ui def attach_to_mediator run_button.signal_connect("clicked", nil) { run_test } @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestResult::CHANGED, &method(:result_changed)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED, &method(:test_finished)) end # def attach_to_mediator private :attach_to_mediator def setup_mediator @mediator = TestRunnerMediator.new(@suite) suite_name = @suite.to_s if @suite.kind_of?(Module) then suite_name = @suite.name end suite_name_entry.set_text(suite_name) end # def setup_mediator private :setup_mediator def start setup_mediator setup_ui attach_to_mediator start_ui @result end # def start def initialize(suite, output_level = NORMAL) if suite.respond_to?(:suite) then @suite = suite.suite else @suite = suite end @result = nil @runner = Thread.current @restart_signal = Class.new(Exception) @viewer = Thread.start do @runner.join rescue @runner.run Gtk.main end @viewer.join rescue nil # wait deadlock to handshake end # def initialize(suite) end # class TestRunner end # module GTK2 end # module UI end # module Unit end # module Test PK|]`Dc"c"test/unit/ui/tk/testrunner.rbnu[#-- # # Original Author:: Nathaniel Talbott. # Author:: Kazuhiro NISHIYAMA. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # Copyright:: Copyright (c) 2003 Kazuhiro NISHIYAMA. All rights reserved. # License:: Ruby license. require 'tk' require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/testrunnerutilities' module Test module Unit module UI module Tk # Runs a Test::Unit::TestSuite in a Tk UI. Obviously, # this one requires you to have Tk # and the Ruby Tk extension installed. class TestRunner extend TestRunnerUtilities # Creates a new TestRunner for running the passed # suite. def initialize(suite, output_level = NORMAL) if (suite.respond_to?(:suite)) @suite = suite.suite else @suite = suite end @result = nil @red = false @fault_detail_list = [] @runner = Thread.current @restart_signal = Class.new(Exception) @viewer = Thread.start do @runner.join rescue @runner.run ::Tk.mainloop end @viewer.join rescue nil # wait deadlock to handshake end # Begins the test run. def start setup_ui setup_mediator attach_to_mediator start_ui @result end private def setup_mediator @mediator = TestRunnerMediator.new(@suite) suite_name = @suite.to_s if ( @suite.kind_of?(Module) ) suite_name = @suite.name end @suite_name_entry.value = suite_name end def attach_to_mediator @run_button.command(method(:run_test)) @fault_list.bind('ButtonPress-1', proc{|y| fault = @fault_detail_list[@fault_list.nearest(y)] if fault show_fault(fault) end }, '%y') @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui)) @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestResult::CHANGED, &method(:result_changed)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) end def run_test @runner.raise(@restart_signal) end def start_ui @viewer.run running = false begin loop do if (running ^= true) @run_button.configure('text'=>'Stop') @mediator.run_suite else @run_button.configure('text'=>'Run') @viewer.join break end end rescue @restart_signal retry rescue end end def stop ::Tk.exit end def reset_ui(count) @test_total_count = count.to_f @test_progress_bar.configure('background'=>'green') @test_progress_bar.place('relwidth'=>(count.zero? ? 0 : 0/count)) @red = false @test_count_label.value = 0 @assertion_count_label.value = 0 @failure_count_label.value = 0 @error_count_label.value = 0 @fault_list.delete(0, 'end') @fault_detail_list = [] clear_fault end def add_fault(fault) if ( ! @red ) @test_progress_bar.configure('background'=>'red') @red = true end @fault_detail_list.push fault @fault_list.insert('end', fault.short_display) end def show_fault(fault) raw_show_fault(fault.long_display) end def raw_show_fault(string) @detail_text.value = string end def clear_fault raw_show_fault("") end def result_changed(result) @test_count_label.value = result.run_count @test_progress_bar.place('relwidth'=>result.run_count/@test_total_count) @assertion_count_label.value = result.assertion_count @failure_count_label.value = result.failure_count @error_count_label.value = result.error_count end def started(result) @result = result output_status("Started...") end def test_started(test_name) output_status("Running #{test_name}...") end def finished(elapsed_time) output_status("Finished in #{elapsed_time} seconds") end def output_status(string) @status_entry.value = string end def setup_ui @status_entry = TkVariable.new l = TkLabel.new(nil, 'textvariable'=>@status_entry, 'relief'=>'sunken') l.pack('side'=>'bottom', 'fill'=>'x') suite_frame = TkFrame.new.pack('fill'=>'x') @run_button = TkButton.new(suite_frame, 'text'=>'Run') @run_button.pack('side'=>'right') TkLabel.new(suite_frame, 'text'=>'Suite:').pack('side'=>'left') @suite_name_entry = TkVariable.new l = TkLabel.new(suite_frame, 'textvariable'=>@suite_name_entry, 'relief'=>'sunken') l.pack('side'=>'left', 'fill'=>'x', 'expand'=>true) f = TkFrame.new(nil, 'relief'=>'sunken', 'borderwidth'=>3, 'height'=>20).pack('fill'=>'x', 'padx'=>1) @test_progress_bar = TkFrame.new(f, 'background'=>'green').place('anchor'=>'nw', 'relwidth'=>0.0, 'relheight'=>1.0) info_frame = TkFrame.new.pack('fill'=>'x') @test_count_label = create_count_label(info_frame, 'Tests:') @assertion_count_label = create_count_label(info_frame, 'Assertions:') @failure_count_label = create_count_label(info_frame, 'Failures:') @error_count_label = create_count_label(info_frame, 'Errors:') if (::Tk.info('command', TkPanedWindow::TkCommandNames[0]) != "") # use panedwindow paned_frame = TkPanedWindow.new("orient"=>"vertical").pack('fill'=>'both', 'expand'=>true) fault_list_frame = TkFrame.new(paned_frame) detail_frame = TkFrame.new(paned_frame) paned_frame.add(fault_list_frame, detail_frame) else # no panedwindow paned_frame = nil fault_list_frame = TkFrame.new.pack('fill'=>'both', 'expand'=>true) detail_frame = TkFrame.new.pack('fill'=>'both', 'expand'=>true) end TkGrid.rowconfigure(fault_list_frame, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(fault_list_frame, 0, 'weight'=>1, 'minsize'=>0) fault_scrollbar_y = TkScrollbar.new(fault_list_frame) fault_scrollbar_x = TkScrollbar.new(fault_list_frame) @fault_list = TkListbox.new(fault_list_frame) @fault_list.yscrollbar(fault_scrollbar_y) @fault_list.xscrollbar(fault_scrollbar_x) TkGrid.rowconfigure(detail_frame, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(detail_frame, 0, 'weight'=>1, 'minsize'=>0) ::Tk.grid(@fault_list, fault_scrollbar_y, 'sticky'=>'news') ::Tk.grid(fault_scrollbar_x, 'sticky'=>'news') detail_scrollbar_y = TkScrollbar.new(detail_frame) detail_scrollbar_x = TkScrollbar.new(detail_frame) @detail_text = TkText.new(detail_frame, 'height'=>10, 'wrap'=>'none') { bindtags(bindtags - [TkText]) } @detail_text.yscrollbar(detail_scrollbar_y) @detail_text.xscrollbar(detail_scrollbar_x) ::Tk.grid(@detail_text, detail_scrollbar_y, 'sticky'=>'news') ::Tk.grid(detail_scrollbar_x, 'sticky'=>'news') # rubber-style pane if paned_frame ::Tk.update @height = paned_frame.winfo_height paned_frame.bind('Configure', proc{|h| paned_frame.sash_place(0, 0, paned_frame.sash_coord(0)[1] * h / @height) @height = h }, '%h') end end def create_count_label(parent, label) TkLabel.new(parent, 'text'=>label).pack('side'=>'left', 'expand'=>true) v = TkVariable.new(0) TkLabel.new(parent, 'textvariable'=>v).pack('side'=>'left', 'expand'=>true) v end end end end end end if __FILE__ == $0 Test::Unit::UI::Tk::TestRunner.start_command_line_test end PK|]K#test/unit/ui/testrunnerutilities.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module Test module Unit module UI SILENT = 0 PROGRESS_ONLY = 1 NORMAL = 2 VERBOSE = 3 # Provides some utilities common to most, if not all, # TestRunners. # #-- # # Perhaps there ought to be a TestRunner superclass? There # seems to be a decent amount of shared code between test # runners. module TestRunnerUtilities # Creates a new TestRunner and runs the suite. def run(suite, output_level=NORMAL) return new(suite, output_level).start end # Takes care of the ARGV parsing and suite # determination necessary for running one of the # TestRunners from the command line. def start_command_line_test if ARGV.empty? puts "You should supply the name of a test suite file to the runner" exit end require ARGV[0].gsub(/.+::/, '') new(eval(ARGV[0])).start end end end end end PK|]9977test/unit/ui/gtk/testrunner.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'gtk' require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/testrunnerutilities' module Test module Unit module UI module GTK # Runs a Test::Unit::TestSuite in a Gtk UI. Obviously, # this one requires you to have Gtk # (http://www.gtk.org/) and the Ruby Gtk extension # (http://ruby-gnome.sourceforge.net/) installed. class TestRunner extend TestRunnerUtilities # Creates a new TestRunner for running the passed # suite. def initialize(suite, output_level = NORMAL) if (suite.respond_to?(:suite)) @suite = suite.suite else @suite = suite end @result = nil @runner = Thread.current @restart_signal = Class.new(Exception) @viewer = Thread.start do @runner.join rescue @runner.run Gtk.main end @viewer.join rescue nil # wait deadlock to handshake end # Begins the test run. def start setup_mediator setup_ui attach_to_mediator start_ui @result end private def setup_mediator @mediator = TestRunnerMediator.new(@suite) suite_name = @suite.to_s if ( @suite.kind_of?(Module) ) suite_name = @suite.name end suite_name_entry.set_text(suite_name) end def attach_to_mediator run_button.signal_connect("clicked", nil, &method(:run_test)) @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui)) @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestResult::CHANGED, &method(:result_changed)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED, &method(:test_finished)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) end def run_test(*) @runner.raise(@restart_signal) end def start_ui @viewer.run running = false begin loop do if (running ^= true) run_button.child.text = "Stop" @mediator.run_suite else run_button.child.text = "Run" @viewer.join break end end rescue @restart_signal retry rescue end end def stop(*) Gtk.main_quit end def reset_ui(count) test_progress_bar.set_style(green_style) test_progress_bar.configure(0, 0, count) @red = false run_count_label.set_text("0") assertion_count_label.set_text("0") failure_count_label.set_text("0") error_count_label.set_text("0") fault_list.remove_items(fault_list.children) end def add_fault(fault) if ( ! @red ) test_progress_bar.set_style(red_style) @red = true end item = FaultListItem.new(fault) item.show fault_list.append_items([item]) end def show_fault(fault) raw_show_fault(fault.long_display) end def raw_show_fault(string) fault_detail_label.set_text(string) outer_detail_sub_panel.queue_resize end def clear_fault raw_show_fault("") end def result_changed(result) run_count_label.set_text(result.run_count.to_s) assertion_count_label.set_text(result.assertion_count.to_s) failure_count_label.set_text(result.failure_count.to_s) error_count_label.set_text(result.error_count.to_s) end def started(result) @result = result output_status("Started...") end def test_started(test_name) output_status("Running #{test_name}...") end def test_finished(test_name) test_progress_bar.set_value(test_progress_bar.get_value + 1) end def finished(elapsed_time) output_status("Finished in #{elapsed_time} seconds") end def output_status(string) status_entry.set_text(string) end def setup_ui main_window.signal_connect("destroy", nil, &method(:stop)) main_window.show_all fault_list.signal_connect("select-child", nil) { | list, item, data | show_fault(item.fault) } fault_list.signal_connect("unselect-child", nil) { clear_fault } @red = false end def main_window lazy_initialize(:main_window) { @main_window = Gtk::Window.new(Gtk::WINDOW_TOPLEVEL) @main_window.set_title("Test::Unit TestRunner") @main_window.set_usize(800, 600) @main_window.set_uposition(20, 20) @main_window.set_policy(true, true, false) @main_window.add(main_panel) } end def main_panel lazy_initialize(:main_panel) { @main_panel = Gtk::VBox.new(false, 0) @main_panel.pack_start(suite_panel, false, false, 0) @main_panel.pack_start(progress_panel, false, false, 0) @main_panel.pack_start(info_panel, false, false, 0) @main_panel.pack_start(list_panel, false, false, 0) @main_panel.pack_start(detail_panel, true, true, 0) @main_panel.pack_start(status_panel, false, false, 0) } end def suite_panel lazy_initialize(:suite_panel) { @suite_panel = Gtk::HBox.new(false, 10) @suite_panel.border_width(10) @suite_panel.pack_start(Gtk::Label.new("Suite:"), false, false, 0) @suite_panel.pack_start(suite_name_entry, true, true, 0) @suite_panel.pack_start(run_button, false, false, 0) } end def suite_name_entry lazy_initialize(:suite_name_entry) { @suite_name_entry = Gtk::Entry.new @suite_name_entry.set_editable(false) } end def run_button lazy_initialize(:run_button) { @run_button = Gtk::Button.new("Run") } end def progress_panel lazy_initialize(:progress_panel) { @progress_panel = Gtk::HBox.new(false, 10) @progress_panel.border_width(10) @progress_panel.pack_start(test_progress_bar, true, true, 0) } end def test_progress_bar lazy_initialize(:test_progress_bar) { @test_progress_bar = EnhancedProgressBar.new @test_progress_bar.set_usize(@test_progress_bar.allocation.width, info_panel.size_request.height) @test_progress_bar.set_style(green_style) } end def green_style lazy_initialize(:green_style) { @green_style = Gtk::Style.new @green_style.set_bg(Gtk::STATE_PRELIGHT, 0x0000, 0xFFFF, 0x0000) } end def red_style lazy_initialize(:red_style) { @red_style = Gtk::Style.new @red_style.set_bg(Gtk::STATE_PRELIGHT, 0xFFFF, 0x0000, 0x0000) } end def info_panel lazy_initialize(:info_panel) { @info_panel = Gtk::HBox.new(false, 0) @info_panel.border_width(10) @info_panel.pack_start(Gtk::Label.new("Runs:"), false, false, 0) @info_panel.pack_start(run_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Assertions:"), false, false, 0) @info_panel.pack_start(assertion_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Failures:"), false, false, 0) @info_panel.pack_start(failure_count_label, true, false, 0) @info_panel.pack_start(Gtk::Label.new("Errors:"), false, false, 0) @info_panel.pack_start(error_count_label, true, false, 0) } end def run_count_label lazy_initialize(:run_count_label) { @run_count_label = Gtk::Label.new("0") @run_count_label.set_justify(Gtk::JUSTIFY_LEFT) } end def assertion_count_label lazy_initialize(:assertion_count_label) { @assertion_count_label = Gtk::Label.new("0") @assertion_count_label.set_justify(Gtk::JUSTIFY_LEFT) } end def failure_count_label lazy_initialize(:failure_count_label) { @failure_count_label = Gtk::Label.new("0") @failure_count_label.set_justify(Gtk::JUSTIFY_LEFT) } end def error_count_label lazy_initialize(:error_count_label) { @error_count_label = Gtk::Label.new("0") @error_count_label.set_justify(Gtk::JUSTIFY_LEFT) } end def list_panel lazy_initialize(:list_panel) { @list_panel = Gtk::HBox.new @list_panel.border_width(10) @list_panel.pack_start(list_scrolled_window, true, true, 0) } end def list_scrolled_window lazy_initialize(:list_scrolled_window) { @list_scrolled_window = Gtk::ScrolledWindow.new @list_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) @list_scrolled_window.set_usize(@list_scrolled_window.allocation.width, 150) @list_scrolled_window.add_with_viewport(fault_list) } end def fault_list lazy_initialize(:fault_list) { @fault_list = Gtk::List.new } end def detail_panel lazy_initialize(:detail_panel) { @detail_panel = Gtk::HBox.new @detail_panel.border_width(10) @detail_panel.pack_start(detail_scrolled_window, true, true, 0) } end def detail_scrolled_window lazy_initialize(:detail_scrolled_window) { @detail_scrolled_window = Gtk::ScrolledWindow.new @detail_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) @detail_scrolled_window.set_usize(400, @detail_scrolled_window.allocation.height) @detail_scrolled_window.add_with_viewport(outer_detail_sub_panel) } end def outer_detail_sub_panel lazy_initialize(:outer_detail_sub_panel) { @outer_detail_sub_panel = Gtk::VBox.new @outer_detail_sub_panel.pack_start(inner_detail_sub_panel, false, false, 0) } end def inner_detail_sub_panel lazy_initialize(:inner_detail_sub_panel) { @inner_detail_sub_panel = Gtk::HBox.new @inner_detail_sub_panel.pack_start(fault_detail_label, false, false, 0) } end def fault_detail_label lazy_initialize(:fault_detail_label) { @fault_detail_label = EnhancedLabel.new("") style = Gtk::Style.new font = Gdk::Font.font_load("-*-Courier New-medium-r-normal--*-120-*-*-*-*-*-*") begin style.set_font(font) rescue ArgumentError; end @fault_detail_label.set_style(style) @fault_detail_label.set_justify(Gtk::JUSTIFY_LEFT) @fault_detail_label.set_line_wrap(false) } end def status_panel lazy_initialize(:status_panel) { @status_panel = Gtk::HBox.new @status_panel.border_width(10) @status_panel.pack_start(status_entry, true, true, 0) } end def status_entry lazy_initialize(:status_entry) { @status_entry = Gtk::Entry.new @status_entry.set_editable(false) } end def lazy_initialize(symbol) if (!instance_eval("defined?(@#{symbol.to_s})")) yield end return instance_eval("@" + symbol.to_s) end end class EnhancedProgressBar < Gtk::ProgressBar def set_style(style) super hide show end end class EnhancedLabel < Gtk::Label def set_text(text) super(text.gsub(/\n\t/, "\n" + (" " * 4))) end end class FaultListItem < Gtk::ListItem attr_reader(:fault) def initialize(fault) super(fault.short_display) @fault = fault end end end end end end if __FILE__ == $0 Test::Unit::UI::GTK::TestRunner.start_command_line_test end PK|]o/"test/unit/ui/console/testrunner.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/ui/testrunnermediator' require 'test/unit/ui/testrunnerutilities' module Test module Unit module UI module Console # Runs a Test::Unit::TestSuite on the console. class TestRunner extend TestRunnerUtilities # Creates a new TestRunner for running the passed # suite. If quiet_mode is true, the output while # running is limited to progress dots, errors and # failures, and the final result. io specifies # where runner output should go to; defaults to # STDOUT. def initialize(suite, output_level=NORMAL, io=STDOUT) if (suite.respond_to?(:suite)) @suite = suite.suite else @suite = suite end @output_level = output_level @io = io @already_outputted = false @faults = [] end # Begins the test run. def start setup_mediator attach_to_mediator return start_mediator end private def setup_mediator @mediator = create_mediator(@suite) suite_name = @suite.to_s if ( @suite.kind_of?(Module) ) suite_name = @suite.name end output("Loaded suite #{suite_name}") end def create_mediator(suite) return TestRunnerMediator.new(suite) end def attach_to_mediator @mediator.add_listener(TestResult::FAULT, &method(:add_fault)) @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started)) @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished)) @mediator.add_listener(TestCase::STARTED, &method(:test_started)) @mediator.add_listener(TestCase::FINISHED, &method(:test_finished)) end def start_mediator return @mediator.run_suite end def add_fault(fault) @faults << fault output_single(fault.single_character_display, PROGRESS_ONLY) @already_outputted = true end def started(result) @result = result output("Started") end def finished(elapsed_time) nl output("Finished in #{elapsed_time} seconds.") @faults.each_with_index do |fault, index| nl output("%3d) %s" % [index + 1, fault.long_display]) end nl output(@result) end def test_started(name) output_single(name + ": ", VERBOSE) end def test_finished(name) output_single(".", PROGRESS_ONLY) unless (@already_outputted) nl(VERBOSE) @already_outputted = false end def nl(level=NORMAL) output("", level) end def output(something, level=NORMAL) @io.puts(something) if (output?(level)) @io.flush end def output_single(something, level=NORMAL) @io.write(something) if (output?(level)) @io.flush end def output?(level) level <= @output_level end end end end end end if __FILE__ == $0 Test::Unit::UI::Console::TestRunner.start_command_line_test end PK|] 000"test/unit/ui/testrunnermediator.rbnu[#-- # # Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit' require 'test/unit/util/observable' require 'test/unit/testresult' module Test module Unit module UI # Provides an interface to write any given UI against, # hopefully making it easy to write new UIs. class TestRunnerMediator RESET = name + "::RESET" STARTED = name + "::STARTED" FINISHED = name + "::FINISHED" include Util::Observable # Creates a new TestRunnerMediator initialized to run # the passed suite. def initialize(suite) @suite = suite end # Runs the suite the TestRunnerMediator was created # with. def run_suite Unit.run = true begin_time = Time.now notify_listeners(RESET, @suite.size) result = create_result notify_listeners(STARTED, result) result_listener = result.add_listener(TestResult::CHANGED) do |updated_result| notify_listeners(TestResult::CHANGED, updated_result) end fault_listener = result.add_listener(TestResult::FAULT) do |fault| notify_listeners(TestResult::FAULT, fault) end @suite.run(result) do |channel, value| notify_listeners(channel, value) end result.remove_listener(TestResult::FAULT, fault_listener) result.remove_listener(TestResult::CHANGED, result_listener) end_time = Time.now elapsed_time = end_time - begin_time notify_listeners(FINISHED, elapsed_time) #"Finished in #{elapsed_time} seconds.") return result end private # A factory method to create the result the mediator # should run with. Can be overridden by subclasses if # one wants to use a different result. def create_result return TestResult.new end end end end end PK|]2Viitest/unit/collector.rbnu[module Test module Unit module Collector def initialize @filters = [] end def filter=(filters) @filters = case(filters) when Proc [filters] when Array filters end end def add_suite(destination, suite) to_delete = suite.tests.find_all{|t| !include?(t)} to_delete.each{|t| suite.delete(t)} destination << suite unless(suite.size == 0) end def include?(test) return true if(@filters.empty?) @filters.each do |filter| result = filter[test] if(result.nil?) next elsif(!result) return false else return true end end true end def sort(suites) suites.sort_by{|s| s.name} end end end end PK|]$q+q+ test/unit.rbnu[require 'test/unit/testcase' require 'test/unit/autorunner' module Test # :nodoc: # # = Test::Unit - Ruby Unit Testing Framework # # == Introduction # # Unit testing is making waves all over the place, largely due to the # fact that it is a core practice of XP. While XP is great, unit testing # has been around for a long time and has always been a good idea. One # of the keys to good unit testing, though, is not just writing tests, # but having tests. What's the difference? Well, if you just _write_ a # test and throw it away, you have no guarantee that something won't # change later which breaks your code. If, on the other hand, you _have_ # tests (obviously you have to write them first), and run them as often # as possible, you slowly build up a wall of things that cannot break # without you immediately knowing about it. This is when unit testing # hits its peak usefulness. # # Enter Test::Unit, a framework for unit testing in Ruby, helping you to # design, debug and evaluate your code by making it easy to write and # have tests for it. # # # == Notes # # Test::Unit has grown out of and superceded Lapidary. # # # == Feedback # # I like (and do my best to practice) XP, so I value early releases, # user feedback, and clean, simple, expressive code. There is always # room for improvement in everything I do, and Test::Unit is no # exception. Please, let me know what you think of Test::Unit as it # stands, and what you'd like to see expanded/changed/improved/etc. If # you find a bug, let me know ASAP; one good way to let me know what the # bug is is to submit a new test that catches it :-) Also, I'd love to # hear about any successes you have with Test::Unit, and any # documentation you might add will be greatly appreciated. My contact # info is below. # # # == Contact Information # # A lot of discussion happens about Ruby in general on the ruby-talk # mailing list (http://www.ruby-lang.org/en/ml.html), and you can ask # any questions you might have there. I monitor the list, as do many # other helpful Rubyists, and you're sure to get a quick answer. Of # course, you're also welcome to email me (Nathaniel Talbott) directly # at mailto:testunit@talbott.ws, and I'll do my best to help you out. # # # == Credits # # I'd like to thank... # # Matz, for a great language! # # Masaki Suketa, for his work on RubyUnit, which filled a vital need in # the Ruby world for a very long time. I'm also grateful for his help in # polishing Test::Unit and getting the RubyUnit compatibility layer # right. His graciousness in allowing Test::Unit to supercede RubyUnit # continues to be a challenge to me to be more willing to defer my own # rights. # # Ken McKinlay, for his interest and work on unit testing, and for his # willingness to dialog about it. He was also a great help in pointing # out some of the holes in the RubyUnit compatibility layer. # # Dave Thomas, for the original idea that led to the extremely simple # "require 'test/unit'", plus his code to improve it even more by # allowing the selection of tests from the command-line. Also, without # RDoc, the documentation for Test::Unit would stink a lot more than it # does now. # # Everyone who's helped out with bug reports, feature ideas, # encouragement to continue, etc. It's a real privilege to be a part of # the Ruby community. # # The guys at RoleModel Software, for putting up with me repeating, "But # this would be so much easier in Ruby!" whenever we're coding in Java. # # My Creator, for giving me life, and giving it more abundantly. # # # == License # # Test::Unit is copyright (c) 2000-2003 Nathaniel Talbott. It is free # software, and is distributed under the Ruby license. See the COPYING # file in the standard Ruby distribution for details. # # # == Warranty # # This software is provided "as is" and without any express or # implied warranties, including, without limitation, the implied # warranties of merchantibility and fitness for a particular # purpose. # # # == Author # # Nathaniel Talbott. # Copyright (c) 2000-2003, Nathaniel Talbott # # ---- # # = Usage # # The general idea behind unit testing is that you write a _test_ # _method_ that makes certain _assertions_ about your code, working # against a _test_ _fixture_. A bunch of these _test_ _methods_ are # bundled up into a _test_ _suite_ and can be run any time the # developer wants. The results of a run are gathered in a _test_ # _result_ and displayed to the user through some UI. So, lets break # this down and see how Test::Unit provides each of these necessary # pieces. # # # == Assertions # # These are the heart of the framework. Think of an assertion as a # statement of expected outcome, i.e. "I assert that x should be equal # to y". If, when the assertion is executed, it turns out to be # correct, nothing happens, and life is good. If, on the other hand, # your assertion turns out to be false, an error is propagated with # pertinent information so that you can go back and make your # assertion succeed, and, once again, life is good. For an explanation # of the current assertions, see Test::Unit::Assertions. # # # == Test Method & Test Fixture # # Obviously, these assertions have to be called within a context that # knows about them and can do something meaningful with their # pass/fail value. Also, it's handy to collect a bunch of related # tests, each test represented by a method, into a common test class # that knows how to run them. The tests will be in a separate class # from the code they're testing for a couple of reasons. First of all, # it allows your code to stay uncluttered with test code, making it # easier to maintain. Second, it allows the tests to be stripped out # for deployment, since they're really there for you, the developer, # and your users don't need them. Third, and most importantly, it # allows you to set up a common test fixture for your tests to run # against. # # What's a test fixture? Well, tests do not live in a vacuum; rather, # they're run against the code they are testing. Often, a collection # of tests will run against a common set of data, also called a # fixture. If they're all bundled into the same test class, they can # all share the setting up and tearing down of that data, eliminating # unnecessary duplication and making it much easier to add related # tests. # # Test::Unit::TestCase wraps up a collection of test methods together # and allows you to easily set up and tear down the same test fixture # for each test. This is done by overriding #setup and/or #teardown, # which will be called before and after each test method that is # run. The TestCase also knows how to collect the results of your # assertions into a Test::Unit::TestResult, which can then be reported # back to you... but I'm getting ahead of myself. To write a test, # follow these steps: # # * Make sure Test::Unit is in your library path. # * require 'test/unit' in your test script. # * Create a class that subclasses Test::Unit::TestCase. # * Add a method that begins with "test" to your class. # * Make assertions in your test method. # * Optionally define #setup and/or #teardown to set up and/or tear # down your common test fixture. # * You can now run your test as you would any other Ruby # script... try it and see! # # A really simple test might look like this (#setup and #teardown are # commented out to indicate that they are completely optional): # # require 'test/unit' # # class TC_MyTest < Test::Unit::TestCase # # def setup # # end # # # def teardown # # end # # def test_fail # assert(false, 'Assertion was false.') # end # end # # # == Test Runners # # So, now you have this great test class, but you still need a way to # run it and view any failures that occur during the run. This is # where Test::Unit::UI::Console::TestRunner (and others, such as # Test::Unit::UI::GTK::TestRunner) comes into play. The console test # runner is automatically invoked for you if you require 'test/unit' # and simply run the file. To use another runner, or to manually # invoke a runner, simply call its run class method and pass in an # object that responds to the suite message with a # Test::Unit::TestSuite. This can be as simple as passing in your # TestCase class (which has a class suite method). It might look # something like this: # # require 'test/unit/ui/console/testrunner' # Test::Unit::UI::Console::TestRunner.run(TC_MyTest) # # # == Test Suite # # As more and more unit tests accumulate for a given project, it # becomes a real drag running them one at a time, and it also # introduces the potential to overlook a failing test because you # forget to run it. Suddenly it becomes very handy that the # TestRunners can take any object that returns a Test::Unit::TestSuite # in response to a suite method. The TestSuite can, in turn, contain # other TestSuites or individual tests (typically created by a # TestCase). In other words, you can easily wrap up a group of # TestCases and TestSuites like this: # # require 'test/unit/testsuite' # require 'tc_myfirsttests' # require 'tc_moretestsbyme' # require 'ts_anothersetoftests' # # class TS_MyTests # def self.suite # suite = Test::Unit::TestSuite.new # suite << TC_MyFirstTests.suite # suite << TC_MoreTestsByMe.suite # suite << TS_AnotherSetOfTests.suite # return suite # end # end # Test::Unit::UI::Console::TestRunner.run(TS_MyTests) # # Now, this is a bit cumbersome, so Test::Unit does a little bit more # for you, by wrapping these up automatically when you require # 'test/unit'. What does this mean? It means you could write the above # test case like this instead: # # require 'test/unit' # require 'tc_myfirsttests' # require 'tc_moretestsbyme' # require 'ts_anothersetoftests' # # Test::Unit is smart enough to find all the test cases existing in # the ObjectSpace and wrap them up into a suite for you. It then runs # the dynamic suite using the console TestRunner. # # # == Questions? # # I'd really like to get feedback from all levels of Ruby # practitioners about typos, grammatical errors, unclear statements, # missing points, etc., in this document (or any other). # module Unit # Set true when Test::Unit has run. If set to true Test::Unit # will not automatically run at exit. def self.run=(flag) @run = flag end # Already tests have run? def self.run? @run ||= false end end end at_exit do unless $! || Test::Unit.run? Kernel.exit Test::Unit::AutoRunner.run end end PK|]-!~aacsv.rbnu[# CSV -- module for generating/parsing CSV data. # Copyright (C) 2000-2004 NAKAMURA, Hiroshi . # $Id: csv.rb 11708 2007-02-12 23:01:19Z shyouhei $ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. class CSV class IllegalFormatError < RuntimeError; end # deprecated class Cell < String def initialize(data = "", is_null = false) super(is_null ? "" : data) end def data to_s end end # deprecated class Row < Array end # Open a CSV formatted file for reading or writing. # # For reading. # # EXAMPLE 1 # CSV.open('csvfile.csv', 'r') do |row| # p row # end # # EXAMPLE 2 # reader = CSV.open('csvfile.csv', 'r') # row1 = reader.shift # row2 = reader.shift # if row2.empty? # p 'row2 not find.' # end # reader.close # # ARGS # filename: filename to parse. # col_sep: Column separator. ?, by default. If you want to separate # fields with semicolon, give ?; here. # row_sep: Row separator. nil by default. nil means "\r\n or \n". If you # want to separate records with \r, give ?\r here. # # RETURNS # reader instance. To get parse result, see CSV::Reader#each. # # # For writing. # # EXAMPLE 1 # CSV.open('csvfile.csv', 'w') do |writer| # writer << ['r1c1', 'r1c2'] # writer << ['r2c1', 'r2c2'] # writer << [nil, nil] # end # # EXAMPLE 2 # writer = CSV.open('csvfile.csv', 'w') # writer << ['r1c1', 'r1c2'] << ['r2c1', 'r2c2'] << [nil, nil] # writer.close # # ARGS # filename: filename to generate. # col_sep: Column separator. ?, by default. If you want to separate # fields with semicolon, give ?; here. # row_sep: Row separator. nil by default. nil means "\r\n or \n". If you # want to separate records with \r, give ?\r here. # # RETURNS # writer instance. See CSV::Writer#<< and CSV::Writer#add_row to know how # to generate CSV string. # def CSV.open(path, mode, fs = nil, rs = nil, &block) if mode == 'r' or mode == 'rb' open_reader(path, mode, fs, rs, &block) elsif mode == 'w' or mode == 'wb' open_writer(path, mode, fs, rs, &block) else raise ArgumentError.new("'mode' must be 'r', 'rb', 'w', or 'wb'") end end def CSV.foreach(path, rs = nil, &block) open_reader(path, 'r', ',', rs, &block) end def CSV.read(path, length = nil, offset = nil) CSV.parse(IO.read(path, length, offset)) end def CSV.readlines(path, rs = nil) reader = open_reader(path, 'r', ',', rs) begin reader.collect { |row| row } ensure reader.close end end def CSV.generate(path, fs = nil, rs = nil, &block) open_writer(path, 'w', fs, rs, &block) end # Parse lines from given string or stream. Return rows as an Array of Arrays. def CSV.parse(str_or_readable, fs = nil, rs = nil, &block) if File.exist?(str_or_readable) STDERR.puts("CSV.parse(filename) is deprecated." + " Use CSV.open(filename, 'r') instead.") return open_reader(str_or_readable, 'r', fs, rs, &block) end if block CSV::Reader.parse(str_or_readable, fs, rs) do |row| yield(row) end nil else CSV::Reader.create(str_or_readable, fs, rs).collect { |row| row } end end # Parse a line from given string. Bear in mind it parses ONE LINE. Rest of # the string is ignored for example "a,b\r\nc,d" => ['a', 'b'] and the # second line 'c,d' is ignored. # # If you don't know whether a target string to parse is exactly 1 line or # not, use CSV.parse_row instead of this method. def CSV.parse_line(src, fs = nil, rs = nil) fs ||= ',' if fs.is_a?(Fixnum) fs = fs.chr end if !rs.nil? and rs.is_a?(Fixnum) rs = rs.chr end idx = 0 res_type = :DT_COLSEP row = [] begin while res_type == :DT_COLSEP res_type, idx, cell = parse_body(src, idx, fs, rs) row << cell end rescue IllegalFormatError return [] end row end # Create a line from cells. each cell is stringified by to_s. def CSV.generate_line(row, fs = nil, rs = nil) if row.size == 0 return '' end fs ||= ',' if fs.is_a?(Fixnum) fs = fs.chr end if !rs.nil? and rs.is_a?(Fixnum) rs = rs.chr end res_type = :DT_COLSEP result_str = '' idx = 0 while true generate_body(row[idx], result_str, fs, rs) idx += 1 if (idx == row.size) break end generate_separator(:DT_COLSEP, result_str, fs, rs) end result_str end # Parse a line from string. Consider using CSV.parse_line instead. # To parse lines in CSV string, see EXAMPLE below. # # EXAMPLE # src = "a,b\r\nc,d\r\ne,f" # idx = 0 # begin # parsed = [] # parsed_cells, idx = CSV.parse_row(src, idx, parsed) # puts "Parsed #{ parsed_cells } cells." # p parsed # end while parsed_cells > 0 # # ARGS # src: a CSV data to be parsed. Must respond '[](idx)'. # src[](idx) must return a char. (Not a string such as 'a', but 97). # src[](idx_out_of_bounds) must return nil. A String satisfies this # requirement. # idx: index of parsing location of 'src'. 0 origin. # out_dev: buffer for parsed cells. Must respond '<<(aString)'. # col_sep: Column separator. ?, by default. If you want to separate # fields with semicolon, give ?; here. # row_sep: Row separator. nil by default. nil means "\r\n or \n". If you # want to separate records with \r, give ?\r here. # # RETURNS # parsed_cells: num of parsed cells. # idx: index of next parsing location of 'src'. # def CSV.parse_row(src, idx, out_dev, fs = nil, rs = nil) fs ||= ',' if fs.is_a?(Fixnum) fs = fs.chr end if !rs.nil? and rs.is_a?(Fixnum) rs = rs.chr end idx_backup = idx parsed_cells = 0 res_type = :DT_COLSEP begin while res_type != :DT_ROWSEP res_type, idx, cell = parse_body(src, idx, fs, rs) if res_type == :DT_EOS if idx == idx_backup #((parsed_cells == 0) and cell.nil?) return 0, 0 end res_type = :DT_ROWSEP end parsed_cells += 1 out_dev << cell end rescue IllegalFormatError return 0, 0 end return parsed_cells, idx end # Convert a line from cells data to string. Consider using CSV.generate_line # instead. To generate multi-row CSV string, see EXAMPLE below. # # EXAMPLE # row1 = ['a', 'b'] # row2 = ['c', 'd'] # row3 = ['e', 'f'] # src = [row1, row2, row3] # buf = '' # src.each do |row| # parsed_cells = CSV.generate_row(row, 2, buf) # puts "Created #{ parsed_cells } cells." # end # p buf # # ARGS # src: an Array of String to be converted to CSV string. Must respond to # 'size' and '[](idx)'. src[idx] must return String. # cells: num of cells in a line. # out_dev: buffer for generated CSV string. Must respond to '<<(string)'. # col_sep: Column separator. ?, by default. If you want to separate # fields with semicolon, give ?; here. # row_sep: Row separator. nil by default. nil means "\r\n or \n". If you # want to separate records with \r, give ?\r here. # # RETURNS # parsed_cells: num of converted cells. # def CSV.generate_row(src, cells, out_dev, fs = nil, rs = nil) fs ||= ',' if fs.is_a?(Fixnum) fs = fs.chr end if !rs.nil? and rs.is_a?(Fixnum) rs = rs.chr end src_size = src.size if (src_size == 0) if cells == 0 generate_separator(:DT_ROWSEP, out_dev, fs, rs) end return 0 end res_type = :DT_COLSEP parsed_cells = 0 generate_body(src[parsed_cells], out_dev, fs, rs) parsed_cells += 1 while ((parsed_cells < cells) and (parsed_cells != src_size)) generate_separator(:DT_COLSEP, out_dev, fs, rs) generate_body(src[parsed_cells], out_dev, fs, rs) parsed_cells += 1 end if (parsed_cells == cells) generate_separator(:DT_ROWSEP, out_dev, fs, rs) else generate_separator(:DT_COLSEP, out_dev, fs, rs) end parsed_cells end # Private class methods. class << self private def open_reader(path, mode, fs, rs, &block) file = File.open(path, mode) if block begin CSV::Reader.parse(file, fs, rs) do |row| yield(row) end ensure file.close end nil else reader = CSV::Reader.create(file, fs, rs) reader.close_on_terminate reader end end def open_writer(path, mode, fs, rs, &block) file = File.open(path, mode) if block begin CSV::Writer.generate(file, fs, rs) do |writer| yield(writer) end ensure file.close end nil else writer = CSV::Writer.create(file, fs, rs) writer.close_on_terminate writer end end def parse_body(src, idx, fs, rs) fs_str = fs fs_size = fs_str.size rs_str = rs || "\n" rs_size = rs_str.size fs_idx = rs_idx = 0 cell = Cell.new state = :ST_START quoted = cr = false c = nil last_idx = idx while c = src[idx] unless quoted fschar = (c == fs_str[fs_idx]) rschar = (c == rs_str[rs_idx]) # simple 1 char backtrack if !fschar and c == fs_str[0] fs_idx = 0 fschar = true if state == :ST_START state = :ST_DATA elsif state == :ST_QUOTE raise IllegalFormatError end end if !rschar and c == rs_str[0] rs_idx = 0 rschar = true if state == :ST_START state = :ST_DATA elsif state == :ST_QUOTE raise IllegalFormatError end end end if c == ?" fs_idx = rs_idx = 0 if cr raise IllegalFormatError end cell << src[last_idx, (idx - last_idx)] last_idx = idx if state == :ST_DATA if quoted last_idx += 1 quoted = false state = :ST_QUOTE else raise IllegalFormatError end elsif state == :ST_QUOTE cell << c.chr last_idx += 1 quoted = true state = :ST_DATA else # :ST_START quoted = true last_idx += 1 state = :ST_DATA end elsif fschar or rschar if fschar fs_idx += 1 end if rschar rs_idx += 1 end sep = nil if fs_idx == fs_size if state == :ST_START and rs_idx > 0 and fs_idx < rs_idx state = :ST_DATA end cell << src[last_idx, (idx - last_idx - (fs_size - 1))] last_idx = idx fs_idx = rs_idx = 0 if cr raise IllegalFormatError end sep = :DT_COLSEP elsif rs_idx == rs_size if state == :ST_START and fs_idx > 0 and rs_idx < fs_idx state = :ST_DATA end if !(rs.nil? and cr) cell << src[last_idx, (idx - last_idx - (rs_size - 1))] last_idx = idx end fs_idx = rs_idx = 0 sep = :DT_ROWSEP end if sep if state == :ST_DATA return sep, idx + 1, cell; elsif state == :ST_QUOTE return sep, idx + 1, cell; else # :ST_START return sep, idx + 1, nil end end elsif rs.nil? and c == ?\r # special \r treatment for backward compatibility fs_idx = rs_idx = 0 if cr raise IllegalFormatError end cell << src[last_idx, (idx - last_idx)] last_idx = idx if quoted state = :ST_DATA else cr = true end else fs_idx = rs_idx = 0 if state == :ST_DATA or state == :ST_START if cr raise IllegalFormatError end state = :ST_DATA else # :ST_QUOTE raise IllegalFormatError end end idx += 1 end if state == :ST_START if fs_idx > 0 or rs_idx > 0 state = :ST_DATA else return :DT_EOS, idx, nil end elsif quoted raise IllegalFormatError elsif cr raise IllegalFormatError end cell << src[last_idx, (idx - last_idx)] last_idx = idx return :DT_EOS, idx, cell end def generate_body(cell, out_dev, fs, rs) if cell.nil? # empty else cell = cell.to_s row_data = cell.dup if (row_data.gsub!('"', '""') or row_data.index(fs) or (rs and row_data.index(rs)) or (/[\r\n]/ =~ row_data) or (cell.empty?)) out_dev << '"' << row_data << '"' else out_dev << row_data end end end def generate_separator(type, out_dev, fs, rs) case type when :DT_COLSEP out_dev << fs when :DT_ROWSEP out_dev << (rs || "\n") end end end # CSV formatted string/stream reader. # # EXAMPLE # read CSV lines untill the first column is 'stop'. # # CSV::Reader.parse(File.open('bigdata', 'rb')) do |row| # p row # break if !row[0].is_null && row[0].data == 'stop' # end # class Reader include Enumerable # Parse CSV data and get lines. Given block is called for each parsed row. # Block value is always nil. Rows are not cached for performance reason. def Reader.parse(str_or_readable, fs = ',', rs = nil, &block) reader = Reader.create(str_or_readable, fs, rs) if block reader.each do |row| yield(row) end reader.close nil else reader end end # Returns reader instance. def Reader.create(str_or_readable, fs = ',', rs = nil) case str_or_readable when IO IOReader.new(str_or_readable, fs, rs) when String StringReader.new(str_or_readable, fs, rs) else IOReader.new(str_or_readable, fs, rs) end end def each while true row = [] parsed_cells = get_row(row) if parsed_cells == 0 break end yield(row) end nil end def shift row = [] parsed_cells = get_row(row) row end def close terminate end private def initialize(dev) raise RuntimeError.new('Do not instanciate this class directly.') end def get_row(row) raise NotImplementedError.new('Method get_row must be defined in a derived class.') end def terminate # Define if needed. end end class StringReader < Reader def initialize(string, fs = ',', rs = nil) @fs = fs @rs = rs @dev = string @idx = 0 if @dev[0, 3] == "\xef\xbb\xbf" @idx += 3 end end private def get_row(row) parsed_cells, next_idx = CSV.parse_row(@dev, @idx, row, @fs, @rs) if parsed_cells == 0 and next_idx == 0 and @idx != @dev.size raise IllegalFormatError.new end @idx = next_idx parsed_cells end end class IOReader < Reader def initialize(io, fs = ',', rs = nil) @io = io @fs = fs @rs = rs @dev = CSV::IOBuf.new(@io) @idx = 0 if @dev[0] == 0xef and @dev[1] == 0xbb and @dev[2] == 0xbf @idx += 3 end @close_on_terminate = false end # Tell this reader to close the IO when terminated (Triggered by invoking # CSV::IOReader#close). def close_on_terminate @close_on_terminate = true end private def get_row(row) parsed_cells, next_idx = CSV.parse_row(@dev, @idx, row, @fs, @rs) if parsed_cells == 0 and next_idx == 0 and !@dev.is_eos? raise IllegalFormatError.new end dropped = @dev.drop(next_idx) @idx = next_idx - dropped parsed_cells end def terminate if @close_on_terminate @io.close end if @dev @dev.close end end end # CSV formatted string/stream writer. # # EXAMPLE # Write rows to 'csvout' file. # # outfile = File.open('csvout', 'wb') # CSV::Writer.generate(outfile) do |csv| # csv << ['c1', nil, '', '"', "\r\n", 'c2'] # ... # end # # outfile.close # class Writer # Given block is called with the writer instance. str_or_writable must # handle '<<(string)'. def Writer.generate(str_or_writable, fs = ',', rs = nil, &block) writer = Writer.create(str_or_writable, fs, rs) if block yield(writer) writer.close nil else writer end end # str_or_writable must handle '<<(string)'. def Writer.create(str_or_writable, fs = ',', rs = nil) BasicWriter.new(str_or_writable, fs, rs) end # dump CSV stream to the device. argument must be an Array of String. def <<(row) CSV.generate_row(row, row.size, @dev, @fs, @rs) self end alias add_row << def close terminate end private def initialize(dev) raise RuntimeError.new('Do not instanciate this class directly.') end def terminate # Define if needed. end end class BasicWriter < Writer def initialize(str_or_writable, fs = ',', rs = nil) @fs = fs @rs = rs @dev = str_or_writable @close_on_terminate = false end # Tell this writer to close the IO when terminated (Triggered by invoking # CSV::BasicWriter#close). def close_on_terminate @close_on_terminate = true end private def terminate if @close_on_terminate @dev.close end end end private # Buffered stream. # # EXAMPLE 1 -- an IO. # class MyBuf < StreamBuf # # Do initialize myself before a super class. Super class might call my # # method 'read'. (Could be awful for C++ user. :-) # def initialize(s) # @s = s # super() # end # # # define my own 'read' method. # # CAUTION: Returning nil means EnfOfStream. # def read(size) # @s.read(size) # end # # # release buffers. in Ruby which has GC, you do not have to call this... # def terminate # @s = nil # super() # end # end # # buf = MyBuf.new(STDIN) # my_str = '' # p buf[0, 0] # => '' (null string) # p buf[0] # => 97 (char code of 'a') # p buf[0, 1] # => 'a' # my_str = buf[0, 5] # p my_str # => 'abcde' (5 chars) # p buf[0, 6] # => "abcde\n" (6 chars) # p buf[0, 7] # => "abcde\n" (6 chars) # p buf.drop(3) # => 3 (dropped chars) # p buf.get(0, 2) # => 'de' (2 chars) # p buf.is_eos? # => false (is not EOS here) # p buf.drop(5) # => 3 (dropped chars) # p buf.is_eos? # => true (is EOS here) # p buf[0] # => nil (is EOS here) # # EXAMPLE 2 -- String. # This is a conceptual example. No pros with this. # # class StrBuf < StreamBuf # def initialize(s) # @str = s # @idx = 0 # super() # end # # def read(size) # str = @str[@idx, size] # @idx += str.size # str # end # end # class StreamBuf # get a char or a partial string from the stream. # idx: index of a string to specify a start point of a string to get. # unlike String instance, idx < 0 returns nil. # n: size of a string to get. # returns char at idx if n == nil. # returns a partial string, from idx to (idx + n) if n != nil. at EOF, # the string size could not equal to arg n. def [](idx, n = nil) if idx < 0 return nil end if (idx_is_eos?(idx)) if n and (@offset + idx == buf_size(@cur_buf)) # Like a String, 'abc'[4, 1] returns nil and # 'abc'[3, 1] returns '' not nil. return '' else return nil end end my_buf = @cur_buf my_offset = @offset next_idx = idx while (my_offset + next_idx >= buf_size(my_buf)) if (my_buf == @buf_tail_idx) unless add_buf break end end next_idx = my_offset + next_idx - buf_size(my_buf) my_buf += 1 my_offset = 0 end loc = my_offset + next_idx if !n return @buf_list[my_buf][loc] # Fixnum of char code. elsif (loc + n - 1 < buf_size(my_buf)) return @buf_list[my_buf][loc, n] # String. else # should do loop insted of (tail) recursive call... res = @buf_list[my_buf][loc, BufSize] size_added = buf_size(my_buf) - loc if size_added > 0 idx += size_added n -= size_added ret = self[idx, n] if ret res << ret end end return res end end alias get [] # drop a string from the stream. # returns dropped size. at EOF, dropped size might not equals to arg n. # Once you drop the head of the stream, access to the dropped part via [] # or get returns nil. def drop(n) if is_eos? return 0 end size_dropped = 0 while (n > 0) if !@is_eos or (@cur_buf != @buf_tail_idx) if (@offset + n < buf_size(@cur_buf)) size_dropped += n @offset += n n = 0 else size = buf_size(@cur_buf) - @offset size_dropped += size n -= size @offset = 0 unless rel_buf unless add_buf break end @cur_buf = @buf_tail_idx end end end end size_dropped end def is_eos? return idx_is_eos?(0) end # WARN: Do not instantiate this class directly. Define your own class # which derives this class and define 'read' instance method. def initialize @buf_list = [] @cur_buf = @buf_tail_idx = -1 @offset = 0 @is_eos = false add_buf @cur_buf = @buf_tail_idx end protected def terminate while (rel_buf); end end # protected method 'read' must be defined in derived classes. # CAUTION: Returning a string which size is not equal to 'size' means # EnfOfStream. When it is not at EOS, you must block the callee, try to # read and return the sized string. def read(size) # raise EOFError raise NotImplementedError.new('Method read must be defined in a derived class.') end private def buf_size(idx) @buf_list[idx].size end def add_buf if @is_eos return false end begin str_read = read(BufSize) rescue EOFError str_read = nil rescue terminate raise end if str_read.nil? @is_eos = true @buf_list.push('') @buf_tail_idx += 1 false else @buf_list.push(str_read) @buf_tail_idx += 1 true end end def rel_buf if (@cur_buf < 0) return false end @buf_list[@cur_buf] = nil if (@cur_buf == @buf_tail_idx) @cur_buf = -1 return false else @cur_buf += 1 return true end end def idx_is_eos?(idx) (@is_eos and ((@cur_buf < 0) or (@cur_buf == @buf_tail_idx))) end BufSize = 1024 * 8 end # Buffered IO. # # EXAMPLE # # File 'bigdata' could be a giga-byte size one! # buf = CSV::IOBuf.new(File.open('bigdata', 'rb')) # CSV::Reader.new(buf).each do |row| # p row # break if row[0].data == 'admin' # end # class IOBuf < StreamBuf def initialize(s) @s = s super() end def close terminate end private def read(size) @s.read(size) end def terminate super() end end end PK|]P EEEcgi/session.rbnu[# # cgi/session.rb - session support for cgi scripts # # Copyright (C) 2001 Yukihiro "Matz" Matsumoto # Copyright (C) 2000 Network Applied Communication Laboratory, Inc. # Copyright (C) 2000 Information-technology Promotion Agency, Japan # # Author: Yukihiro "Matz" Matsumoto # # Documentation: William Webber (william@williamwebber.com) # # == Overview # # This file provides the +CGI::Session+ class, which provides session # support for CGI scripts. A session is a sequence of HTTP requests # and responses linked together and associated with a single client. # Information associated with the session is stored # on the server between requests. A session id is passed between client # and server with every request and response, transparently # to the user. This adds state information to the otherwise stateless # HTTP request/response protocol. # # See the documentation to the +CGI::Session+ class for more details # and examples of usage. See cgi.rb for the +CGI+ class itself. require 'cgi' require 'tmpdir' class CGI # Class representing an HTTP session. See documentation for the file # cgi/session.rb for an introduction to HTTP sessions. # # == Lifecycle # # A CGI::Session instance is created from a CGI object. By default, # this CGI::Session instance will start a new session if none currently # exists, or continue the current session for this client if one does # exist. The +new_session+ option can be used to either always or # never create a new session. See #new() for more details. # # #delete() deletes a session from session storage. It # does not however remove the session id from the client. If the client # makes another request with the same id, the effect will be to start # a new session with the old session's id. # # == Setting and retrieving session data. # # The Session class associates data with a session as key-value pairs. # This data can be set and retrieved by indexing the Session instance # using '[]', much the same as hashes (although other hash methods # are not supported). # # When session processing has been completed for a request, the # session should be closed using the close() method. This will # store the session's state to persistent storage. If you want # to store the session's state to persistent storage without # finishing session processing for this request, call the update() # method. # # == Storing session state # # The caller can specify what form of storage to use for the session's # data with the +database_manager+ option to CGI::Session::new. The # following storage classes are provided as part of the standard library: # # CGI::Session::FileStore:: stores data as plain text in a flat file. Only # works with String data. This is the default # storage type. # CGI::Session::MemoryStore:: stores data in an in-memory hash. The data # only persists for as long as the current ruby # interpreter instance does. # CGI::Session::PStore:: stores data in Marshalled format. Provided by # cgi/session/pstore.rb. Supports data of any type, # and provides file-locking and transaction support. # # Custom storage types can also be created by defining a class with # the following methods: # # new(session, options) # restore # returns hash of session data. # update # close # delete # # Changing storage type mid-session does not work. Note in particular # that by default the FileStore and PStore session data files have the # same name. If your application switches from one to the other without # making sure that filenames will be different # and clients still have old sessions lying around in cookies, then # things will break nastily! # # == Maintaining the session id. # # Most session state is maintained on the server. However, a session # id must be passed backwards and forwards between client and server # to maintain a reference to this session state. # # The simplest way to do this is via cookies. The CGI::Session class # provides transparent support for session id communication via cookies # if the client has cookies enabled. # # If the client has cookies disabled, the session id must be included # as a parameter of all requests sent by the client to the server. The # CGI::Session class in conjunction with the CGI class will transparently # add the session id as a hidden input field to all forms generated # using the CGI#form() HTML generation method. No built-in support is # provided for other mechanisms, such as URL re-writing. The caller is # responsible for extracting the session id from the session_id # attribute and manually encoding it in URLs and adding it as a hidden # input to HTML forms created by other mechanisms. Also, session expiry # is not automatically handled. # # == Examples of use # # === Setting the user's name # # require 'cgi' # require 'cgi/session' # require 'cgi/session/pstore' # provides CGI::Session::PStore # # cgi = CGI.new("html4") # # session = CGI::Session.new(cgi, # 'database_manager' => CGI::Session::PStore, # use PStore # 'session_key' => '_rb_sess_id', # custom session key # 'session_expires' => Time.now + 30 * 60, # 30 minute timeout # 'prefix' => 'pstore_sid_') # PStore option # if cgi.has_key?('user_name') and cgi['user_name'] != '' # # coerce to String: cgi[] returns the # # string-like CGI::QueryExtension::Value # session['user_name'] = cgi['user_name'].to_s # elsif !session['user_name'] # session['user_name'] = "guest" # end # session.close # # === Creating a new session safely # # require 'cgi' # require 'cgi/session' # # cgi = CGI.new("html4") # # # We make sure to delete an old session if one exists, # # not just to free resources, but to prevent the session # # from being maliciously hijacked later on. # begin # session = CGI::Session.new(cgi, 'new_session' => false) # session.delete # rescue ArgumentError # if no old session # end # session = CGI::Session.new(cgi, 'new_session' => true) # session.close # class Session class NoSession < RuntimeError #:nodoc: end # The id of this session. attr_reader :session_id, :new_session def Session::callback(dbman) #:nodoc: Proc.new{ dbman[0].close unless dbman.empty? } end # Create a new session id. # # The session id is an MD5 hash based upon the time, # a random number, and a constant string. This routine # is used internally for automatically generated # session ids. def create_new_id require 'securerandom' begin session_id = SecureRandom.hex(16) rescue NotImplementedError require 'digest/md5' md5 = Digest::MD5::new now = Time::now md5.update(now.to_s) md5.update(String(now.usec)) md5.update(String(rand(0))) md5.update(String($$)) md5.update('foobar') session_id = md5.hexdigest end session_id end private :create_new_id # Create a new CGI::Session object for +request+. # # +request+ is an instance of the +CGI+ class (see cgi.rb). # +option+ is a hash of options for initialising this # CGI::Session instance. The following options are # recognised: # # session_key:: the parameter name used for the session id. # Defaults to '_session_id'. # session_id:: the session id to use. If not provided, then # it is retrieved from the +session_key+ parameter # of the request, or automatically generated for # a new session. # new_session:: if true, force creation of a new session. If not set, # a new session is only created if none currently # exists. If false, a new session is never created, # and if none currently exists and the +session_id+ # option is not set, an ArgumentError is raised. # database_manager:: the name of the class providing storage facilities # for session state persistence. Built-in support # is provided for +FileStore+ (the default), # +MemoryStore+, and +PStore+ (from # cgi/session/pstore.rb). See the documentation for # these classes for more details. # # The following options are also recognised, but only apply if the # session id is stored in a cookie. # # session_expires:: the time the current session expires, as a # +Time+ object. If not set, the session will terminate # when the user's browser is closed. # session_domain:: the hostname domain for which this session is valid. # If not set, defaults to the hostname of the server. # session_secure:: if +true+, this session will only work over HTTPS. # session_path:: the path for which this session applies. Defaults # to the directory of the CGI script. # # +option+ is also passed on to the session storage class initializer; see # the documentation for each session storage class for the options # they support. # # The retrieved or created session is automatically added to +request+ # as a cookie, and also to its +output_hidden+ table, which is used # to add hidden input elements to forms. # # *WARNING* the +output_hidden+ # fields are surrounded by a
    tag in HTML 4 generation, which # is _not_ invisible on many browsers; you may wish to disable the # use of fieldsets with code similar to the following # (see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/37805) # # cgi = CGI.new("html4") # class << cgi # undef_method :fieldset # end # def initialize(request, option={}) @new_session = false session_key = option['session_key'] || '_session_id' session_id = option['session_id'] unless session_id if option['new_session'] session_id = create_new_id @new_session = true end end unless session_id if request.key?(session_key) session_id = request[session_key] session_id = session_id.read if session_id.respond_to?(:read) end unless session_id session_id, = request.cookies[session_key] end unless session_id unless option.fetch('new_session', true) raise ArgumentError, "session_key `%s' should be supplied"%session_key end session_id = create_new_id @new_session = true end end @session_id = session_id dbman = option['database_manager'] || FileStore begin @dbman = dbman::new(self, option) rescue NoSession unless option.fetch('new_session', true) raise ArgumentError, "invalid session_id `%s'"%session_id end session_id = @session_id = create_new_id unless session_id @new_session = true retry end request.instance_eval do @output_hidden = {session_key => session_id} unless option['no_hidden'] @output_cookies = [ Cookie::new("name" => session_key, "value" => session_id, "expires" => option['session_expires'], "domain" => option['session_domain'], "secure" => option['session_secure'], "path" => if option['session_path'] then option['session_path'] elsif ENV["SCRIPT_NAME"] then File::dirname(ENV["SCRIPT_NAME"]) else "" end) ] unless option['no_cookies'] end @dbprot = [@dbman] ObjectSpace::define_finalizer(self, Session::callback(@dbprot)) end # Retrieve the session data for key +key+. def [](key) @data ||= @dbman.restore @data[key] end # Set the session date for key +key+. def []=(key, val) @write_lock ||= true @data ||= @dbman.restore @data[key] = val end # Store session data on the server. For some session storage types, # this is a no-op. def update @dbman.update end # Store session data on the server and close the session storage. # For some session storage types, this is a no-op. def close @dbman.close @dbprot.clear end # Delete the session from storage. Also closes the storage. # # Note that the session's data is _not_ automatically deleted # upon the session expiring. def delete @dbman.delete @dbprot.clear end # File-based session storage class. # # Implements session storage as a flat file of 'key=value' values. # This storage type only works directly with String values; the # user is responsible for converting other types to Strings when # storing and from Strings when retrieving. class FileStore # Create a new FileStore instance. # # This constructor is used internally by CGI::Session. The # user does not generally need to call it directly. # # +session+ is the session for which this instance is being # created. The session id must only contain alphanumeric # characters; automatically generated session ids observe # this requirement. # # +option+ is a hash of options for the initializer. The # following options are recognised: # # tmpdir:: the directory to use for storing the FileStore # file. Defaults to Dir::tmpdir (generally "/tmp" # on Unix systems). # prefix:: the prefix to add to the session id when generating # the filename for this session's FileStore file. # Defaults to the empty string. # suffix:: the prefix to add to the session id when generating # the filename for this session's FileStore file. # Defaults to the empty string. # # This session's FileStore file will be created if it does # not exist, or opened if it does. def initialize(session, option={}) dir = option['tmpdir'] || Dir::tmpdir prefix = option['prefix'] || '' suffix = option['suffix'] || '' id = session.session_id require 'digest/md5' md5 = Digest::MD5.hexdigest(id)[0,16] @path = dir+"/"+prefix+md5+suffix if File::exist? @path @hash = nil else unless session.new_session raise CGI::Session::NoSession, "uninitialized session" end @hash = {} end end # Restore session state from the session's FileStore file. # # Returns the session state as a hash. def restore unless @hash @hash = {} begin lockf = File.open(@path+".lock", "r") lockf.flock File::LOCK_SH f = File.open(@path, 'r') for line in f line.chomp! k, v = line.split('=',2) @hash[CGI::unescape(k)] = CGI::unescape(v) end ensure f.close unless f.nil? lockf.close if lockf end end @hash end # Save session state to the session's FileStore file. def update return unless @hash begin lockf = File.open(@path+".lock", File::CREAT|File::RDWR, 0600) lockf.flock File::LOCK_EX f = File.open(@path+".new", File::CREAT|File::TRUNC|File::WRONLY, 0600) for k,v in @hash f.printf "%s=%s\n", CGI::escape(k), CGI::escape(String(v)) end f.close File.rename @path+".new", @path ensure f.close if f and !f.closed? lockf.close if lockf end end # Update and close the session's FileStore file. def close update end # Close and delete the session's FileStore file. def delete File::unlink @path+".lock" rescue nil File::unlink @path+".new" rescue nil File::unlink @path rescue Errno::ENOENT end end # In-memory session storage class. # # Implements session storage as a global in-memory hash. Session # data will only persist for as long as the ruby interpreter # instance does. class MemoryStore GLOBAL_HASH_TABLE = {} #:nodoc: # Create a new MemoryStore instance. # # +session+ is the session this instance is associated with. # +option+ is a list of initialisation options. None are # currently recognised. def initialize(session, option=nil) @session_id = session.session_id unless GLOBAL_HASH_TABLE.key?(@session_id) unless session.new_session raise CGI::Session::NoSession, "uninitialized session" end GLOBAL_HASH_TABLE[@session_id] = {} end end # Restore session state. # # Returns session data as a hash. def restore GLOBAL_HASH_TABLE[@session_id] end # Update session state. # # A no-op. def update # don't need to update; hash is shared end # Close session storage. # # A no-op. def close # don't need to close end # Delete the session state. def delete GLOBAL_HASH_TABLE.delete(@session_id) end end end end PK|]T#p4 4 cgi/session/pstore.rbnu[# # cgi/session/pstore.rb - persistent storage of marshalled session data # # Documentation: William Webber (william@williamwebber.com) # # == Overview # # This file provides the CGI::Session::PStore class, which builds # persistent of session data on top of the pstore library. See # cgi/session.rb for more details on session storage managers. require 'cgi/session' require 'pstore' class CGI class Session # PStore-based session storage class. # # This builds upon the top-level PStore class provided by the # library file pstore.rb. Session data is marshalled and stored # in a file. File locking and transaction services are provided. class PStore # Create a new CGI::Session::PStore instance # # This constructor is used internally by CGI::Session. The # user does not generally need to call it directly. # # +session+ is the session for which this instance is being # created. The session id must only contain alphanumeric # characters; automatically generated session ids observe # this requirement. # # +option+ is a hash of options for the initializer. The # following options are recognised: # # tmpdir:: the directory to use for storing the PStore # file. Defaults to Dir::tmpdir (generally "/tmp" # on Unix systems). # prefix:: the prefix to add to the session id when generating # the filename for this session's PStore file. # Defaults to the empty string. # # This session's PStore file will be created if it does # not exist, or opened if it does. def initialize(session, option={}) dir = option['tmpdir'] || Dir::tmpdir prefix = option['prefix'] || '' id = session.session_id require 'digest/md5' md5 = Digest::MD5.hexdigest(id)[0,16] path = dir+"/"+prefix+md5 path.untaint if File::exist?(path) @hash = nil else unless session.new_session raise CGI::Session::NoSession, "uninitialized session" end @hash = {} end @p = ::PStore.new(path) @p.transaction do |p| File.chmod(0600, p.path) end end # Restore session state from the session's PStore file. # # Returns the session state as a hash. def restore unless @hash @p.transaction do @hash = @p['hash'] || {} end end @hash end # Save session state to the session's PStore file. def update @p.transaction do @p['hash'] = @hash end end # Update and close the session's PStore file. def close update end # Close and delete the session's PStore file. def delete path = @p.path File::unlink path end end end end if $0 == __FILE__ # :enddoc: STDIN.reopen("/dev/null") cgi = CGI.new session = CGI::Session.new(cgi, 'database_manager' => CGI::Session::PStore) session['key'] = {'k' => 'v'} puts session['key'].class fail unless Hash === session['key'] puts session['key'].inspect fail unless session['key'].inspect == '{"k"=>"v"}' end PK|]^f%++ webrick.rbnu[# # WEBrick -- WEB server toolkit. # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: webrick.rb,v 1.12 2002/10/01 17:16:31 gotoyuzo Exp $ require 'webrick/compat.rb' require 'webrick/version.rb' require 'webrick/config.rb' require 'webrick/log.rb' require 'webrick/server.rb' require 'webrick/utils.rb' require 'webrick/accesslog' require 'webrick/htmlutils.rb' require 'webrick/httputils.rb' require 'webrick/cookie.rb' require 'webrick/httpversion.rb' require 'webrick/httpstatus.rb' require 'webrick/httprequest.rb' require 'webrick/httpresponse.rb' require 'webrick/httpserver.rb' require 'webrick/httpservlet.rb' require 'webrick/httpauth.rb' PK|]/7lOO parsedate.rbnu[# # = parsedate.rb: Parses dates # # Author:: Tadayoshi Funaba # Documentation:: Konrad Meyer # # ParseDate munches on a date and turns it into an array of values. # # # ParseDate converts a date into an array of values. # For example: # # require 'parsedate' # # ParseDate.parsedate "Tuesday, July 6th, 2007, 18:35:20 UTC" # # => [2007, 7, 6, 18, 35, 20, "UTC", 2] # # The order is of the form [year, month, day of month, hour, minute, second, # timezone, day of the week]. require 'date/format' module ParseDate # # Parse a string representation of a date into values. # For example: # # require 'parsedate' # # ParseDate.parsedate "Tuesday, July 5th, 2007, 18:35:20 UTC" # # => [2007, 7, 5, 18, 35, 20, "UTC", 2] # # The order is of the form [year, month, day of month, hour, minute, # second, timezone, day of week]. # # ParseDate.parsedate can also take a second argument, +comp+, which # is a boolean telling the method to compensate for dates with years # expressed as two digits. Example: # # require 'parsedate' # # ParseDate.parsedate "Mon Dec 25 00 06:53:24 UTC", true # # => [2000, 12, 25, 6, 53, 24, "UTC", 1] # def parsedate(str, comp=false) Date._parse(str, comp). values_at(:year, :mon, :mday, :hour, :min, :sec, :zone, :wday) end module_function :parsedate end PK|]}date2.rbnu[# date2 was overridden by date. # To be precise, date was overridden by date2, # and date2 was renamed to date. require 'date' PK|]8 observer.rbnu[# # observer.rb implements the _Observer_ object-oriented design pattern. The # following documentation is copied, with modifications, from "Programming # Ruby", by Hunt and Thomas; http://www.rubycentral.com/book/lib_patterns.html. # # == About # # The Observer pattern, also known as Publish/Subscribe, provides a simple # mechanism for one object to inform a set of interested third-party objects # when its state changes. # # == Mechanism # # In the Ruby implementation, the notifying class mixes in the +Observable+ # module, which provides the methods for managing the associated observer # objects. # # The observers must implement the +update+ method to receive notifications. # # The observable object must: # * assert that it has +changed+ # * call +notify_observers+ # # == Example # # The following example demonstrates this nicely. A +Ticker+, when run, # continually receives the stock +Price+ for its +@symbol+. A +Warner+ is a # general observer of the price, and two warners are demonstrated, a +WarnLow+ # and a +WarnHigh+, which print a warning if the price is below or above their # set limits, respectively. # # The +update+ callback allows the warners to run without being explicitly # called. The system is set up with the +Ticker+ and several observers, and the # observers do their duty without the top-level code having to interfere. # # Note that the contract between publisher and subscriber (observable and # observer) is not declared or enforced. The +Ticker+ publishes a time and a # price, and the warners receive that. But if you don't ensure that your # contracts are correct, nothing else can warn you. # # require "observer" # # class Ticker ### Periodically fetch a stock price. # include Observable # # def initialize(symbol) # @symbol = symbol # end # # def run # lastPrice = nil # loop do # price = Price.fetch(@symbol) # print "Current price: #{price}\n" # if price != lastPrice # changed # notify observers # lastPrice = price # notify_observers(Time.now, price) # end # sleep 1 # end # end # end # # class Price ### A mock class to fetch a stock price (60 - 140). # def Price.fetch(symbol) # 60 + rand(80) # end # end # # class Warner ### An abstract observer of Ticker objects. # def initialize(ticker, limit) # @limit = limit # ticker.add_observer(self) # end # end # # class WarnLow < Warner # def update(time, price) # callback for observer # if price < @limit # print "--- #{time.to_s}: Price below #@limit: #{price}\n" # end # end # end # # class WarnHigh < Warner # def update(time, price) # callback for observer # if price > @limit # print "+++ #{time.to_s}: Price above #@limit: #{price}\n" # end # end # end # # ticker = Ticker.new("MSFT") # WarnLow.new(ticker, 80) # WarnHigh.new(ticker, 120) # ticker.run # # Produces: # # Current price: 83 # Current price: 75 # --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 75 # Current price: 90 # Current price: 134 # +++ Sun Jun 09 00:10:25 CDT 2002: Price above 120: 134 # Current price: 134 # Current price: 112 # Current price: 79 # --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 79 # # Implements the Observable design pattern as a mixin so that other objects can # be notified of changes in state. See observer.rb for details and an example. # module Observable # # Add +observer+ as an observer on this object. +observer+ will now receive # notifications. # def add_observer(observer) @observer_peers = [] unless defined? @observer_peers unless observer.respond_to? :update raise NoMethodError, "observer needs to respond to `update'" end @observer_peers.push observer end # # Delete +observer+ as an observer on this object. It will no longer receive # notifications. # def delete_observer(observer) @observer_peers.delete observer if defined? @observer_peers end # # Delete all observers associated with this object. # def delete_observers @observer_peers.clear if defined? @observer_peers end # # Return the number of observers associated with this object. # def count_observers if defined? @observer_peers @observer_peers.size else 0 end end # # Set the changed state of this object. Notifications will be sent only if # the changed +state+ is +true+. # def changed(state=true) @observer_state = state end # # Query the changed state of this object. # def changed? if defined? @observer_state and @observer_state true else false end end # # If this object's changed state is +true+, invoke the update method in each # currently associated observer in turn, passing it the given arguments. The # changed state is then set to +false+. # def notify_observers(*arg) if defined? @observer_state and @observer_state if defined? @observer_peers for i in @observer_peers.dup i.update(*arg) end end @observer_state = false end end end PK|]}ޢf f generator.rbnu[#!/usr/bin/env ruby #-- # $Idaemons: /home/cvs/rb/generator.rb,v 1.8 2001/10/03 08:54:32 knu Exp $ # $RoughId: generator.rb,v 1.10 2003/10/14 19:36:58 knu Exp $ # $Id: generator.rb 15954 2008-04-10 10:52:50Z knu $ #++ # # = generator.rb: convert an internal iterator to an external one # # Copyright (c) 2001,2003 Akinori MUSHA # # All rights reserved. You can redistribute and/or modify it under # the same terms as Ruby. # # == Overview # # This library provides the Generator class, which converts an # internal iterator (i.e. an Enumerable object) to an external # iterator. In that form, you can roll many iterators independently. # # The SyncEnumerator class, which is implemented using Generator, # makes it easy to roll many Enumerable objects synchronously. # # See the respective classes for examples of usage. # # Generator converts an internal iterator (i.e. an Enumerable object) # to an external iterator. # # Note that it is not very fast since it is implemented using # continuations, which are currently slow. # # == Example # # require 'generator' # # # Generator from an Enumerable object # g = Generator.new(['A', 'B', 'C', 'Z']) # # while g.next? # puts g.next # end # # # Generator from a block # g = Generator.new { |g| # for i in 'A'..'C' # g.yield i # end # # g.yield 'Z' # } # # # The same result as above # while g.next? # puts g.next # end # class Generator include Enumerable # Creates a new generator either from an Enumerable object or from a # block. # # In the former, block is ignored even if given. # # In the latter, the given block is called with the generator # itself, and expected to call the +yield+ method for each element. def initialize(enum = nil, &block) if enum @block = proc { |g| enum.each { |x| g.yield x } } else @block = block end @index = 0 @queue = [] @cont_next = @cont_yield = @cont_endp = nil if @cont_next = callcc { |c| c } @block.call(self) @cont_endp.call(nil) if @cont_endp end self end # Yields an element to the generator. def yield(value) if @cont_yield = callcc { |c| c } @queue << value @cont_next.call(nil) end self end # Returns true if the generator has reached the end. def end?() if @cont_endp = callcc { |c| c } @cont_yield.nil? && @queue.empty? else @queue.empty? end end # Returns true if the generator has not reached the end yet. def next?() !end? end # Returns the current index (position) counting from zero. def index() @index end # Returns the current index (position) counting from zero. def pos() @index end # Returns the element at the current position and moves forward. def next() if end? raise EOFError, "no more elements available" end if @cont_next = callcc { |c| c } @cont_yield.call(nil) if @cont_yield end @index += 1 @queue.shift end # Returns the element at the current position. def current() if @queue.empty? raise EOFError, "no more elements available" end @queue.first end # Rewinds the generator. def rewind() initialize(nil, &@block) if @index.nonzero? self end # Rewinds the generator and enumerates the elements. def each rewind until end? yield self.next end self end end class Enumerable::Enumerator def __generator @generator ||= Generator.new(self) end private :__generator # call-seq: # e.next => object # # Returns the next object in the enumerator, and move the internal # position forward. When the position reached at the end, internal # position is rewinded then StopIteration is raised. # # Note that enumeration sequence by next method does not affect other # non-external enumeration methods, unless underlying iteration # methods itself has side-effect, e.g. IO#each_line. # # Caution: This feature internally uses Generator, which uses callcc # to stop and resume enumeration to fetch each value. Use with care # and be aware of the performance loss. def next g = __generator return g.next unless g.end? g.rewind raise StopIteration, 'iteration reached at end' end # call-seq: # e.rewind => e # # Rewinds the enumeration sequence by the next method. def rewind __generator.rewind self end end # # SyncEnumerator creates an Enumerable object from multiple Enumerable # objects and enumerates them synchronously. # # == Example # # require 'generator' # # s = SyncEnumerator.new([1,2,3], ['a', 'b', 'c']) # # # Yields [1, 'a'], [2, 'b'], and [3,'c'] # s.each { |row| puts row.join(', ') } # class SyncEnumerator include Enumerable # Creates a new SyncEnumerator which enumerates rows of given # Enumerable objects. def initialize(*enums) @gens = enums.map { |e| Generator.new(e) } end # Returns the number of enumerated Enumerable objects, i.e. the size # of each row. def size @gens.size end # Returns the number of enumerated Enumerable objects, i.e. the size # of each row. def length @gens.length end # Returns true if the given nth Enumerable object has reached the # end. If no argument is given, returns true if any of the # Enumerable objects has reached the end. def end?(i = nil) if i.nil? @gens.detect { |g| g.end? } ? true : false else @gens[i].end? end end # Enumerates rows of the Enumerable objects. def each @gens.each { |g| g.rewind } loop do count = 0 ret = @gens.map { |g| if g.end? count += 1 nil else g.next end } if count == @gens.size break end yield ret end self end end if $0 == __FILE__ eval DATA.read, nil, $0, __LINE__+4 end __END__ require 'test/unit' class TC_Generator < Test::Unit::TestCase def test_block1 g = Generator.new { |g| # no yield's } assert_equal(0, g.pos) assert_raises(EOFError) { g.current } end def test_block2 g = Generator.new { |g| for i in 'A'..'C' g.yield i end g.yield 'Z' } assert_equal(0, g.pos) assert_equal('A', g.current) assert_equal(true, g.next?) assert_equal(0, g.pos) assert_equal('A', g.current) assert_equal(0, g.pos) assert_equal('A', g.next) assert_equal(1, g.pos) assert_equal(true, g.next?) assert_equal(1, g.pos) assert_equal('B', g.current) assert_equal(1, g.pos) assert_equal('B', g.next) assert_equal(g, g.rewind) assert_equal(0, g.pos) assert_equal('A', g.current) assert_equal(true, g.next?) assert_equal(0, g.pos) assert_equal('A', g.current) assert_equal(0, g.pos) assert_equal('A', g.next) assert_equal(1, g.pos) assert_equal(true, g.next?) assert_equal(1, g.pos) assert_equal('B', g.current) assert_equal(1, g.pos) assert_equal('B', g.next) assert_equal(2, g.pos) assert_equal(true, g.next?) assert_equal(2, g.pos) assert_equal('C', g.current) assert_equal(2, g.pos) assert_equal('C', g.next) assert_equal(3, g.pos) assert_equal(true, g.next?) assert_equal(3, g.pos) assert_equal('Z', g.current) assert_equal(3, g.pos) assert_equal('Z', g.next) assert_equal(4, g.pos) assert_equal(false, g.next?) assert_raises(EOFError) { g.next } end def test_each a = [5, 6, 7, 8, 9] g = Generator.new(a) i = 0 g.each { |x| assert_equal(a[i], x) i += 1 break if i == 3 } assert_equal(3, i) i = 0 g.each { |x| assert_equal(a[i], x) i += 1 } assert_equal(5, i) end end class TC_SyncEnumerator < Test::Unit::TestCase def test_each r = ['a'..'f', 1..10, 10..20] ra = r.map { |x| x.to_a } a = (0...(ra.map {|x| x.size}.max)).map { |i| ra.map { |x| x[i] } } s = SyncEnumerator.new(*r) i = 0 s.each { |x| assert_equal(a[i], x) i += 1 break if i == 3 } assert_equal(3, i) i = 0 s.each { |x| assert_equal(a[i], x) i += 1 } assert_equal(a.size, i) end end PK|]̛&&cgi.rbnu[# # cgi.rb - cgi support library # # Copyright (C) 2000 Network Applied Communication Laboratory, Inc. # # Copyright (C) 2000 Information-technology Promotion Agency, Japan # # Author: Wakou Aoyama # # Documentation: Wakou Aoyama (RDoc'd and embellished by William Webber) # # == Overview # # The Common Gateway Interface (CGI) is a simple protocol # for passing an HTTP request from a web server to a # standalone program, and returning the output to the web # browser. Basically, a CGI program is called with the # parameters of the request passed in either in the # environment (GET) or via $stdin (POST), and everything # it prints to $stdout is returned to the client. # # This file holds the +CGI+ class. This class provides # functionality for retrieving HTTP request parameters, # managing cookies, and generating HTML output. See the # class documentation for more details and examples of use. # # The file cgi/session.rb provides session management # functionality; see that file for more details. # # See http://www.w3.org/CGI/ for more information on the CGI # protocol. raise "Please, use ruby 1.5.4 or later." if RUBY_VERSION < "1.5.4" require 'English' # CGI class. See documentation for the file cgi.rb for an overview # of the CGI protocol. # # == Introduction # # CGI is a large class, providing several categories of methods, many of which # are mixed in from other modules. Some of the documentation is in this class, # some in the modules CGI::QueryExtension and CGI::HtmlExtension. See # CGI::Cookie for specific information on handling cookies, and cgi/session.rb # (CGI::Session) for information on sessions. # # For queries, CGI provides methods to get at environmental variables, # parameters, cookies, and multipart request data. For responses, CGI provides # methods for writing output and generating HTML. # # Read on for more details. Examples are provided at the bottom. # # == Queries # # The CGI class dynamically mixes in parameter and cookie-parsing # functionality, environmental variable access, and support for # parsing multipart requests (including uploaded files) from the # CGI::QueryExtension module. # # === Environmental Variables # # The standard CGI environmental variables are available as read-only # attributes of a CGI object. The following is a list of these variables: # # # AUTH_TYPE HTTP_HOST REMOTE_IDENT # CONTENT_LENGTH HTTP_NEGOTIATE REMOTE_USER # CONTENT_TYPE HTTP_PRAGMA REQUEST_METHOD # GATEWAY_INTERFACE HTTP_REFERER SCRIPT_NAME # HTTP_ACCEPT HTTP_USER_AGENT SERVER_NAME # HTTP_ACCEPT_CHARSET PATH_INFO SERVER_PORT # HTTP_ACCEPT_ENCODING PATH_TRANSLATED SERVER_PROTOCOL # HTTP_ACCEPT_LANGUAGE QUERY_STRING SERVER_SOFTWARE # HTTP_CACHE_CONTROL REMOTE_ADDR # HTTP_FROM REMOTE_HOST # # # For each of these variables, there is a corresponding attribute with the # same name, except all lower case and without a preceding HTTP_. # +content_length+ and +server_port+ are integers; the rest are strings. # # === Parameters # # The method #params() returns a hash of all parameters in the request as # name/value-list pairs, where the value-list is an Array of one or more # values. The CGI object itself also behaves as a hash of parameter names # to values, but only returns a single value (as a String) for each # parameter name. # # For instance, suppose the request contains the parameter # "favourite_colours" with the multiple values "blue" and "green". The # following behaviour would occur: # # cgi.params["favourite_colours"] # => ["blue", "green"] # cgi["favourite_colours"] # => "blue" # # If a parameter does not exist, the former method will return an empty # array, the latter an empty string. The simplest way to test for existence # of a parameter is by the #has_key? method. # # === Cookies # # HTTP Cookies are automatically parsed from the request. They are available # from the #cookies() accessor, which returns a hash from cookie name to # CGI::Cookie object. # # === Multipart requests # # If a request's method is POST and its content type is multipart/form-data, # then it may contain uploaded files. These are stored by the QueryExtension # module in the parameters of the request. The parameter name is the name # attribute of the file input field, as usual. However, the value is not # a string, but an IO object, either an IOString for small files, or a # Tempfile for larger ones. This object also has the additional singleton # methods: # # #local_path():: the path of the uploaded file on the local filesystem # #original_filename():: the name of the file on the client computer # #content_type():: the content type of the file # # == Responses # # The CGI class provides methods for sending header and content output to # the HTTP client, and mixes in methods for programmatic HTML generation # from CGI::HtmlExtension and CGI::TagMaker modules. The precise version of HTML # to use for HTML generation is specified at object creation time. # # === Writing output # # The simplest way to send output to the HTTP client is using the #out() method. # This takes the HTTP headers as a hash parameter, and the body content # via a block. The headers can be generated as a string using the #header() # method. The output stream can be written directly to using the #print() # method. # # === Generating HTML # # Each HTML element has a corresponding method for generating that # element as a String. The name of this method is the same as that # of the element, all lowercase. The attributes of the element are # passed in as a hash, and the body as a no-argument block that evaluates # to a String. The HTML generation module knows which elements are # always empty, and silently drops any passed-in body. It also knows # which elements require matching closing tags and which don't. However, # it does not know what attributes are legal for which elements. # # There are also some additional HTML generation methods mixed in from # the CGI::HtmlExtension module. These include individual methods for the # different types of form inputs, and methods for elements that commonly # take particular attributes where the attributes can be directly specified # as arguments, rather than via a hash. # # == Examples of use # # === Get form values # # require "cgi" # cgi = CGI.new # value = cgi['field_name'] # <== value string for 'field_name' # # if not 'field_name' included, then return "". # fields = cgi.keys # <== array of field names # # # returns true if form has 'field_name' # cgi.has_key?('field_name') # cgi.has_key?('field_name') # cgi.include?('field_name') # # CAUTION! cgi['field_name'] returned an Array with the old # cgi.rb(included in ruby 1.6) # # === Get form values as hash # # require "cgi" # cgi = CGI.new # params = cgi.params # # cgi.params is a hash. # # cgi.params['new_field_name'] = ["value"] # add new param # cgi.params['field_name'] = ["new_value"] # change value # cgi.params.delete('field_name') # delete param # cgi.params.clear # delete all params # # # === Save form values to file # # require "pstore" # db = PStore.new("query.db") # db.transaction do # db["params"] = cgi.params # end # # # === Restore form values from file # # require "pstore" # db = PStore.new("query.db") # db.transaction do # cgi.params = db["params"] # end # # # === Get multipart form values # # require "cgi" # cgi = CGI.new # value = cgi['field_name'] # <== value string for 'field_name' # value.read # <== body of value # value.local_path # <== path to local file of value # value.original_filename # <== original filename of value # value.content_type # <== content_type of value # # and value has StringIO or Tempfile class methods. # # === Get cookie values # # require "cgi" # cgi = CGI.new # values = cgi.cookies['name'] # <== array of 'name' # # if not 'name' included, then return []. # names = cgi.cookies.keys # <== array of cookie names # # and cgi.cookies is a hash. # # === Get cookie objects # # require "cgi" # cgi = CGI.new # for name, cookie in cgi.cookies # cookie.expires = Time.now + 30 # end # cgi.out("cookie" => cgi.cookies) {"string"} # # cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... } # # require "cgi" # cgi = CGI.new # cgi.cookies['name'].expires = Time.now + 30 # cgi.out("cookie" => cgi.cookies['name']) {"string"} # # === Print http header and html string to $DEFAULT_OUTPUT ($>) # # require "cgi" # cgi = CGI.new("html3") # add HTML generation methods # cgi.out() do # cgi.html() do # cgi.head{ cgi.title{"TITLE"} } + # cgi.body() do # cgi.form() do # cgi.textarea("get_text") + # cgi.br + # cgi.submit # end + # cgi.pre() do # CGI::escapeHTML( # "params: " + cgi.params.inspect + "\n" + # "cookies: " + cgi.cookies.inspect + "\n" + # ENV.collect() do |key, value| # key + " --> " + value + "\n" # end.join("") # ) # end # end # end # end # # # add HTML generation methods # CGI.new("html3") # html3.2 # CGI.new("html4") # html4.01 (Strict) # CGI.new("html4Tr") # html4.01 Transitional # CGI.new("html4Fr") # html4.01 Frameset # class CGI # :stopdoc: # String for carriage return CR = "\015" # String for linefeed LF = "\012" # Standard internet newline sequence EOL = CR + LF REVISION = '$Id: cgi.rb 26086 2009-12-14 02:40:07Z shyouhei $' #:nodoc: NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM) # Path separators in different environments. PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'} # HTTP status codes. HTTP_STATUS = { "OK" => "200 OK", "PARTIAL_CONTENT" => "206 Partial Content", "MULTIPLE_CHOICES" => "300 Multiple Choices", "MOVED" => "301 Moved Permanently", "REDIRECT" => "302 Found", "NOT_MODIFIED" => "304 Not Modified", "BAD_REQUEST" => "400 Bad Request", "AUTH_REQUIRED" => "401 Authorization Required", "FORBIDDEN" => "403 Forbidden", "NOT_FOUND" => "404 Not Found", "METHOD_NOT_ALLOWED" => "405 Method Not Allowed", "NOT_ACCEPTABLE" => "406 Not Acceptable", "LENGTH_REQUIRED" => "411 Length Required", "PRECONDITION_FAILED" => "412 Precondition Failed", "SERVER_ERROR" => "500 Internal Server Error", "NOT_IMPLEMENTED" => "501 Method Not Implemented", "BAD_GATEWAY" => "502 Bad Gateway", "VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates" } # Abbreviated day-of-week names specified by RFC 822 RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ] # Abbreviated month names specified by RFC 822 RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ] # :startdoc: def env_table ENV end def stdinput $stdin end def stdoutput $DEFAULT_OUTPUT end private :env_table, :stdinput, :stdoutput # URL-encode a string. # url_encoded_string = CGI::escape("'Stop!' said Fred") # # => "%27Stop%21%27+said+Fred" def CGI::escape(string) string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do '%' + $1.unpack('H2' * $1.size).join('%').upcase end.tr(' ', '+') end # URL-decode a string. # string = CGI::unescape("%27Stop%21%27+said+Fred") # # => "'Stop!' said Fred" def CGI::unescape(string) string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do [$1.delete('%')].pack('H*') end end # Escape special characters in HTML, namely &\"<> # CGI::escapeHTML('Usage: foo "bar" ') # # => "Usage: foo "bar" <baz>" def CGI::escapeHTML(string) string.gsub(/&/n, '&').gsub(/\"/n, '"').gsub(/>/n, '>').gsub(/ "Usage: foo \"bar\" " def CGI::unescapeHTML(string) string.gsub(/&(amp|quot|gt|lt|\#[0-9]+|\#x[0-9A-Fa-f]+);/n) do match = $1.dup case match when 'amp' then '&' when 'quot' then '"' when 'gt' then '>' when 'lt' then '<' when /\A#0*(\d+)\z/n then if Integer($1) < 256 Integer($1).chr else if Integer($1) < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U) [Integer($1)].pack("U") else "&##{$1};" end end when /\A#x([0-9a-f]+)\z/ni then if $1.hex < 128 $1.hex.chr else if $1.hex < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U) [$1.hex].pack("U") else "&#x#{$1};" end end else "&#{match};" end end end # Escape only the tags of certain HTML elements in +string+. # # Takes an element or elements or array of elements. Each element # is specified by the name of the element, without angle brackets. # This matches both the start and the end tag of that element. # The attribute list of the open tag will also be escaped (for # instance, the double-quotes surrounding attribute values). # # print CGI::escapeElement('
    ', "A", "IMG") # # "
    <A HREF="url"></A>" # # print CGI::escapeElement('
    ', ["A", "IMG"]) # # "
    <A HREF="url"></A>" def CGI::escapeElement(string, *elements) elements = elements[0] if elements[0].kind_of?(Array) unless elements.empty? string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do CGI::escapeHTML($&) end else string end end # Undo escaping such as that done by CGI::escapeElement() # # print CGI::unescapeElement( # CGI::escapeHTML('
    '), "A", "IMG") # # "<BR>" # # print CGI::unescapeElement( # CGI::escapeHTML('
    '), ["A", "IMG"]) # # "<BR>" def CGI::unescapeElement(string, *elements) elements = elements[0] if elements[0].kind_of?(Array) unless elements.empty? string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do CGI::unescapeHTML($&) end else string end end # Format a +Time+ object as a String using the format specified by RFC 1123. # # CGI::rfc1123_date(Time.now) # # Sat, 01 Jan 2000 00:00:00 GMT def CGI::rfc1123_date(time) t = time.clone.gmtime return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year, t.hour, t.min, t.sec) end # Create an HTTP header block as a string. # # Includes the empty line that ends the header block. # # +options+ can be a string specifying the Content-Type (defaults # to text/html), or a hash of header key/value pairs. The following # header keys are recognized: # # type:: the Content-Type header. Defaults to "text/html" # charset:: the charset of the body, appended to the Content-Type header. # nph:: a boolean value. If true, prepend protocol string and status code, and # date; and sets default values for "server" and "connection" if not # explicitly set. # status:: the HTTP status code, returned as the Status header. See the # list of available status codes below. # server:: the server software, returned as the Server header. # connection:: the connection type, returned as the Connection header (for # instance, "close". # length:: the length of the content that will be sent, returned as the # Content-Length header. # language:: the language of the content, returned as the Content-Language # header. # expires:: the time on which the current content expires, as a +Time+ # object, returned as the Expires header. # cookie:: a cookie or cookies, returned as one or more Set-Cookie headers. # The value can be the literal string of the cookie; a CGI::Cookie # object; an Array of literal cookie strings or Cookie objects; or a # hash all of whose values are literal cookie strings or Cookie objects. # These cookies are in addition to the cookies held in the # @output_cookies field. # # Other header lines can also be set; they are appended as key: value. # # header # # Content-Type: text/html # # header("text/plain") # # Content-Type: text/plain # # header("nph" => true, # "status" => "OK", # == "200 OK" # # "status" => "200 GOOD", # "server" => ENV['SERVER_SOFTWARE'], # "connection" => "close", # "type" => "text/html", # "charset" => "iso-2022-jp", # # Content-Type: text/html; charset=iso-2022-jp # "length" => 103, # "language" => "ja", # "expires" => Time.now + 30, # "cookie" => [cookie1, cookie2], # "my_header1" => "my_value" # "my_header2" => "my_value") # # The status codes are: # # "OK" --> "200 OK" # "PARTIAL_CONTENT" --> "206 Partial Content" # "MULTIPLE_CHOICES" --> "300 Multiple Choices" # "MOVED" --> "301 Moved Permanently" # "REDIRECT" --> "302 Found" # "NOT_MODIFIED" --> "304 Not Modified" # "BAD_REQUEST" --> "400 Bad Request" # "AUTH_REQUIRED" --> "401 Authorization Required" # "FORBIDDEN" --> "403 Forbidden" # "NOT_FOUND" --> "404 Not Found" # "METHOD_NOT_ALLOWED" --> "405 Method Not Allowed" # "NOT_ACCEPTABLE" --> "406 Not Acceptable" # "LENGTH_REQUIRED" --> "411 Length Required" # "PRECONDITION_FAILED" --> "412 Precondition Failed" # "SERVER_ERROR" --> "500 Internal Server Error" # "NOT_IMPLEMENTED" --> "501 Method Not Implemented" # "BAD_GATEWAY" --> "502 Bad Gateway" # "VARIANT_ALSO_VARIES" --> "506 Variant Also Negotiates" # # This method does not perform charset conversion. # def header(options = "text/html") buf = "" case options when String options = { "type" => options } when Hash options = options.dup end unless options.has_key?("type") options["type"] = "text/html" end if options.has_key?("charset") options["type"] += "; charset=" + options.delete("charset") end options.delete("nph") if defined?(MOD_RUBY) if options.delete("nph") or (/IIS\/(\d+)/n.match(env_table['SERVER_SOFTWARE']) and $1.to_i < 5) buf += (env_table["SERVER_PROTOCOL"] or "HTTP/1.0") + " " + (HTTP_STATUS[options["status"]] or options["status"] or "200 OK") + EOL + "Date: " + CGI::rfc1123_date(Time.now) + EOL unless options.has_key?("server") options["server"] = (env_table['SERVER_SOFTWARE'] or "") end unless options.has_key?("connection") options["connection"] = "close" end options.delete("status") end if options.has_key?("status") buf += "Status: " + (HTTP_STATUS[options["status"]] or options["status"]) + EOL options.delete("status") end if options.has_key?("server") buf += "Server: " + options.delete("server") + EOL end if options.has_key?("connection") buf += "Connection: " + options.delete("connection") + EOL end buf += "Content-Type: " + options.delete("type") + EOL if options.has_key?("length") buf += "Content-Length: " + options.delete("length").to_s + EOL end if options.has_key?("language") buf += "Content-Language: " + options.delete("language") + EOL end if options.has_key?("expires") buf += "Expires: " + CGI::rfc1123_date( options.delete("expires") ) + EOL end if options.has_key?("cookie") if options["cookie"].kind_of?(String) or options["cookie"].kind_of?(Cookie) buf += "Set-Cookie: " + options.delete("cookie").to_s + EOL elsif options["cookie"].kind_of?(Array) options.delete("cookie").each{|cookie| buf += "Set-Cookie: " + cookie.to_s + EOL } elsif options["cookie"].kind_of?(Hash) options.delete("cookie").each_value{|cookie| buf += "Set-Cookie: " + cookie.to_s + EOL } end end if @output_cookies for cookie in @output_cookies buf += "Set-Cookie: " + cookie.to_s + EOL end end options.each{|key, value| buf += key + ": " + value.to_s + EOL } if defined?(MOD_RUBY) table = Apache::request.headers_out buf.scan(/([^:]+): (.+)#{EOL}/n){ |name, value| warn sprintf("name:%s value:%s\n", name, value) if $DEBUG case name when 'Set-Cookie' table.add(name, value) when /^status$/ni Apache::request.status_line = value Apache::request.status = value.to_i when /^content-type$/ni Apache::request.content_type = value when /^content-encoding$/ni Apache::request.content_encoding = value when /^location$/ni if Apache::request.status == 200 Apache::request.status = 302 end Apache::request.headers_out[name] = value else Apache::request.headers_out[name] = value end } Apache::request.send_http_header '' else buf + EOL end end # header() # Print an HTTP header and body to $DEFAULT_OUTPUT ($>) # # The header is provided by +options+, as for #header(). # The body of the document is that returned by the passed- # in block. This block takes no arguments. It is required. # # cgi = CGI.new # cgi.out{ "string" } # # Content-Type: text/html # # Content-Length: 6 # # # # string # # cgi.out("text/plain") { "string" } # # Content-Type: text/plain # # Content-Length: 6 # # # # string # # cgi.out("nph" => true, # "status" => "OK", # == "200 OK" # "server" => ENV['SERVER_SOFTWARE'], # "connection" => "close", # "type" => "text/html", # "charset" => "iso-2022-jp", # # Content-Type: text/html; charset=iso-2022-jp # "language" => "ja", # "expires" => Time.now + (3600 * 24 * 30), # "cookie" => [cookie1, cookie2], # "my_header1" => "my_value", # "my_header2" => "my_value") { "string" } # # Content-Length is automatically calculated from the size of # the String returned by the content block. # # If ENV['REQUEST_METHOD'] == "HEAD", then only the header # is outputted (the content block is still required, but it # is ignored). # # If the charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then # the content is converted to this charset, and the language is set # to "ja". def out(options = "text/html") # :yield: options = { "type" => options } if options.kind_of?(String) content = yield if options.has_key?("charset") require "nkf" case options["charset"] when /iso-2022-jp/ni content = NKF::nkf('-m0 -x -j', content) options["language"] = "ja" unless options.has_key?("language") when /euc-jp/ni content = NKF::nkf('-m0 -x -e', content) options["language"] = "ja" unless options.has_key?("language") when /shift_jis/ni content = NKF::nkf('-m0 -x -s', content) options["language"] = "ja" unless options.has_key?("language") end end options["length"] = content.length.to_s output = stdoutput output.binmode if defined? output.binmode output.print header(options) output.print content unless "HEAD" == env_table['REQUEST_METHOD'] end # Print an argument or list of arguments to the default output stream # # cgi = CGI.new # cgi.print # default: cgi.print == $DEFAULT_OUTPUT.print def print(*options) stdoutput.print(*options) end require "delegate" # Class representing an HTTP cookie. # # In addition to its specific fields and methods, a Cookie instance # is a delegator to the array of its values. # # See RFC 2965. # # == Examples of use # cookie1 = CGI::Cookie::new("name", "value1", "value2", ...) # cookie1 = CGI::Cookie::new("name" => "name", "value" => "value") # cookie1 = CGI::Cookie::new('name' => 'name', # 'value' => ['value1', 'value2', ...], # 'path' => 'path', # optional # 'domain' => 'domain', # optional # 'expires' => Time.now, # optional # 'secure' => true # optional # ) # # cgi.out("cookie" => [cookie1, cookie2]) { "string" } # # name = cookie1.name # values = cookie1.value # path = cookie1.path # domain = cookie1.domain # expires = cookie1.expires # secure = cookie1.secure # # cookie1.name = 'name' # cookie1.value = ['value1', 'value2', ...] # cookie1.path = 'path' # cookie1.domain = 'domain' # cookie1.expires = Time.now + 30 # cookie1.secure = true class Cookie < DelegateClass(Array) # Create a new CGI::Cookie object. # # The contents of the cookie can be specified as a +name+ and one # or more +value+ arguments. Alternatively, the contents can # be specified as a single hash argument. The possible keywords of # this hash are as follows: # # name:: the name of the cookie. Required. # value:: the cookie's value or list of values. # path:: the path for which this cookie applies. Defaults to the # base directory of the CGI script. # domain:: the domain for which this cookie applies. # expires:: the time at which this cookie expires, as a +Time+ object. # secure:: whether this cookie is a secure cookie or not (default to # false). Secure cookies are only transmitted to HTTPS # servers. # # These keywords correspond to attributes of the cookie object. def initialize(name = "", *value) if name.kind_of?(String) @name = name @value = value %r|^(.*/)|.match(ENV["SCRIPT_NAME"]) @path = ($1 or "") @secure = false return super(@value) end options = name unless options.has_key?("name") raise ArgumentError, "`name' required" end @name = options["name"] @value = Array(options["value"]) # simple support for IE if options["path"] @path = options["path"] else %r|^(.*/)|.match(ENV["SCRIPT_NAME"]) @path = ($1 or "") end @domain = options["domain"] @expires = options["expires"] @secure = options["secure"] == true ? true : false super(@value) end attr_accessor("name", "path", "domain", "expires") attr_reader("secure", "value") # Set whether the Cookie is a secure cookie or not. # # +val+ must be a boolean. def secure=(val) @secure = val if val == true or val == false @secure end def value=(val) @value.replace(Array(val)) end # Convert the Cookie to its string representation. def to_s buf = "" buf += @name + '=' buf += @value.map { |v| CGI::escape(v) }.join("&") if @domain buf += '; domain=' + @domain end if @path buf += '; path=' + @path end if @expires buf += '; expires=' + CGI::rfc1123_date(@expires) end if @secure == true buf += '; secure' end buf end end # class Cookie # Parse a raw cookie string into a hash of cookie-name=>Cookie # pairs. # # cookies = CGI::Cookie::parse("raw_cookie_string") # # { "name1" => cookie1, "name2" => cookie2, ... } # def Cookie::parse(raw_cookie) cookies = Hash.new([]) return cookies unless raw_cookie raw_cookie.split(/[;,]\s?/).each do |pairs| name, values = pairs.split('=',2) next unless name and values name = CGI::unescape(name) values ||= "" values = values.split('&').collect{|v| CGI::unescape(v) } if cookies.has_key?(name) values = cookies[name].value + values end cookies[name] = Cookie::new(name, *values) end cookies end # Parse an HTTP query string into a hash of key=>value pairs. # # params = CGI::parse("query_string") # # {"name1" => ["value1", "value2", ...], # # "name2" => ["value1", "value2", ...], ... } # def CGI::parse(query) params = Hash.new([].freeze) query.split(/[&;]/n).each do |pairs| key, value = pairs.split('=',2).collect{|v| CGI::unescape(v) } if params.has_key?(key) params[key].push(value) else params[key] = [value] end end params end # Mixin module. It provides the follow functionality groups: # # 1. Access to CGI environment variables as methods. See # documentation to the CGI class for a list of these variables. # # 2. Access to cookies, including the cookies attribute. # # 3. Access to parameters, including the params attribute, and overloading # [] to perform parameter value lookup by key. # # 4. The initialize_query method, for initialising the above # mechanisms, handling multipart forms, and allowing the # class to be used in "offline" mode. # module QueryExtension %w[ CONTENT_LENGTH SERVER_PORT ].each do |env| define_method(env.sub(/^HTTP_/n, '').downcase) do (val = env_table[env]) && Integer(val) end end %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env| define_method(env.sub(/^HTTP_/n, '').downcase) do env_table[env] end end # Get the raw cookies as a string. def raw_cookie env_table["HTTP_COOKIE"] end # Get the raw RFC2965 cookies as a string. def raw_cookie2 env_table["HTTP_COOKIE2"] end # Get the cookies as a hash of cookie-name=>Cookie pairs. attr_accessor("cookies") # Get the parameters as a hash of name=>values pairs, where # values is an Array. attr("params") # Set all the parameters. def params=(hash) @params.clear @params.update(hash) end def read_multipart(boundary, content_length) params = Hash.new([]) boundary = "--" + boundary quoted_boundary = Regexp.quote(boundary, "n") buf = "" bufsize = 10 * 1024 boundary_end="" # start multipart/form-data stdinput.binmode if defined? stdinput.binmode boundary_size = boundary.size + EOL.size content_length -= boundary_size status = stdinput.read(boundary_size) if nil == status raise EOFError, "no content body" elsif boundary + EOL != status raise EOFError, "bad content body" end loop do head = nil if 10240 < content_length require "tempfile" body = Tempfile.new("CGI") else begin require "stringio" body = StringIO.new rescue LoadError require "tempfile" body = Tempfile.new("CGI") end end body.binmode if defined? body.binmode until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf) if (not head) and /#{EOL}#{EOL}/n.match(buf) buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do head = $1.dup "" end next end if head and ( (EOL + boundary + EOL).size < buf.size ) body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)] buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = "" end c = if bufsize < content_length stdinput.read(bufsize) else stdinput.read(content_length) end if c.nil? || c.empty? raise EOFError, "bad content body" end buf.concat(c) content_length -= c.size end buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do body.print $1 if "--" == $2 content_length = -1 end boundary_end = $2.dup "" end body.rewind /Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/ni.match(head) filename = ($1 or $2 or "") if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and (not /MSIE/ni.match(env_table['HTTP_USER_AGENT'])) filename = CGI::unescape(filename) end /Content-Type: ([^\s]*)/ni.match(head) content_type = ($1 or "") (class << body; self; end).class_eval do alias local_path path define_method(:original_filename) {filename.dup.taint} define_method(:content_type) {content_type.dup.taint} end /Content-Disposition:.* name="?([^\";\s]*)"?/ni.match(head) name = $1.dup if params.has_key?(name) params[name].push(body) else params[name] = [body] end break if buf.size == 0 break if content_length == -1 end raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/ params end # read_multipart private :read_multipart # offline mode. read name=value pairs on standard input. def read_from_cmdline require "shellwords" string = unless ARGV.empty? ARGV.join(' ') else if STDIN.tty? STDERR.print( %|(offline mode: enter name=value pairs on standard input)\n| ) end array = readlines rescue nil if not array.nil? array.join(' ').gsub(/\n/n, '') else "" end end.gsub(/\\=/n, '%3D').gsub(/\\&/n, '%26') words = Shellwords.shellwords(string) if words.find{|x| /=/n.match(x) } words.join('&') else words.join('+') end end private :read_from_cmdline # Initialize the data from the query. # # Handles multipart forms (in particular, forms that involve file uploads). # Reads query parameters in the @params field, and cookies into @cookies. def initialize_query() if ("POST" == env_table['REQUEST_METHOD']) and %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(env_table['CONTENT_TYPE']) boundary = $1.dup @multipart = true @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH'])) else @multipart = false @params = CGI::parse( case env_table['REQUEST_METHOD'] when "GET", "HEAD" if defined?(MOD_RUBY) Apache::request.args or "" else env_table['QUERY_STRING'] or "" end when "POST" stdinput.binmode if defined? stdinput.binmode stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or '' else read_from_cmdline end ) end @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or env_table['COOKIE'])) end private :initialize_query def multipart? @multipart end module Value # :nodoc: def set_params(params) @params = params end def [](idx, *args) if args.size == 0 warn "#{caller(1)[0]}:CAUTION! cgi['key'] == cgi.params['key'][0]; if want Array, use cgi.params['key']" @params[idx] else super[idx,*args] end end def first warn "#{caller(1)[0]}:CAUTION! cgi['key'] == cgi.params['key'][0]; if want Array, use cgi.params['key']" self end alias last first def to_a @params || [self] end alias to_ary to_a # to be rhs of multiple assignment end # Get the value for the parameter with a given key. # # If the parameter has multiple values, only the first will be # retrieved; use #params() to get the array of values. def [](key) params = @params[key] return '' unless params value = params[0] if @multipart if value return value elsif defined? StringIO StringIO.new("") else Tempfile.new("CGI") end else str = if value then value.dup else "" end str.extend(Value) str.set_params(params) str end end # Return all parameter keys as an array. def keys(*args) @params.keys(*args) end # Returns true if a given parameter key exists in the query. def has_key?(*args) @params.has_key?(*args) end alias key? has_key? alias include? has_key? end # QueryExtension # Prettify (indent) an HTML string. # # +string+ is the HTML string to indent. +shift+ is the indentation # unit to use; it defaults to two spaces. # # print CGI::pretty("") # # # # # # # # # # print CGI::pretty("", "\t") # # # # # # # # # def CGI::pretty(string, shift = " ") lines = string.gsub(/(?!\A)<(?:.|\n)*?>/n, "\n\\0").gsub(/<(?:.|\n)*?>(?!\n)/n, "\\0\n") end_pos = 0 while end_pos = lines.index(/^<\/(\w+)/n, end_pos) element = $1.dup start_pos = lines.rindex(/^\s*<#{element}/ni, end_pos) lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/n, "\n" + shift) + "__" end lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/n, '\1') end # Base module for HTML-generation mixins. # # Provides methods for code generation for tags following # the various DTD element types. module TagMaker # :nodoc: # Generate code for an element with required start and end tags. # # - - def nn_element_def(element) nOE_element_def(element, <<-END) if block_given? yield.to_s else "" end + "" END end # Generate code for an empty element. # # - O EMPTY def nOE_element_def(element, append = nil) s = <<-END "<#{element.upcase}" + attributes.collect{|name, value| next unless value " " + CGI::escapeHTML(name) + if true == value "" else '="' + CGI::escapeHTML(value) + '"' end }.to_s + ">" END s.sub!(/\Z/, " +") << append if append s end # Generate code for an element for which the end (and possibly the # start) tag is optional. # # O O or - O def nO_element_def(element) nOE_element_def(element, <<-END) if block_given? yield.to_s + "" else "" end END end end # TagMaker # # Mixin module providing HTML generation methods. # # For example, # cgi.a("http://www.example.com") { "Example" } # # => "Example" # # Modules Http3, Http4, etc., contain more basic HTML-generation methods # (:title, :center, etc.). # # See class CGI for a detailed example. # module HtmlExtension # Generate an Anchor element as a string. # # +href+ can either be a string, giving the URL # for the HREF attribute, or it can be a hash of # the element's attributes. # # The body of the element is the string returned by the no-argument # block passed in. # # a("http://www.example.com") { "Example" } # # => "Example" # # a("HREF" => "http://www.example.com", "TARGET" => "_top") { "Example" } # # => "Example" # def a(href = "") # :yield: attributes = if href.kind_of?(String) { "HREF" => href } else href end if block_given? super(attributes){ yield } else super(attributes) end end # Generate a Document Base URI element as a String. # # +href+ can either by a string, giving the base URL for the HREF # attribute, or it can be a has of the element's attributes. # # The passed-in no-argument block is ignored. # # base("http://www.example.com/cgi") # # => "" def base(href = "") # :yield: attributes = if href.kind_of?(String) { "HREF" => href } else href end if block_given? super(attributes){ yield } else super(attributes) end end # Generate a BlockQuote element as a string. # # +cite+ can either be a string, give the URI for the source of # the quoted text, or a hash, giving all attributes of the element, # or it can be omitted, in which case the element has no attributes. # # The body is provided by the passed-in no-argument block # # blockquote("http://www.example.com/quotes/foo.html") { "Foo!" } # #=> "
    Foo!
    def blockquote(cite = nil) # :yield: attributes = if cite.kind_of?(String) { "CITE" => cite } else cite or "" end if block_given? super(attributes){ yield } else super(attributes) end end # Generate a Table Caption element as a string. # # +align+ can be a string, giving the alignment of the caption # (one of top, bottom, left, or right). It can be a hash of # all the attributes of the element. Or it can be omitted. # # The body of the element is provided by the passed-in no-argument block. # # caption("left") { "Capital Cities" } # # => Capital Cities def caption(align = nil) # :yield: attributes = if align.kind_of?(String) { "ALIGN" => align } else align or "" end if block_given? super(attributes){ yield } else super(attributes) end end # Generate a Checkbox Input element as a string. # # The attributes of the element can be specified as three arguments, # +name+, +value+, and +checked+. +checked+ is a boolean value; # if true, the CHECKED attribute will be included in the element. # # Alternatively, the attributes can be specified as a hash. # # checkbox("name") # # = checkbox("NAME" => "name") # # checkbox("name", "value") # # = checkbox("NAME" => "name", "VALUE" => "value") # # checkbox("name", "value", true) # # = checkbox("NAME" => "name", "VALUE" => "value", "CHECKED" => true) def checkbox(name = "", value = nil, checked = nil) attributes = if name.kind_of?(String) { "TYPE" => "checkbox", "NAME" => name, "VALUE" => value, "CHECKED" => checked } else name["TYPE"] = "checkbox" name end input(attributes) end # Generate a sequence of checkbox elements, as a String. # # The checkboxes will all have the same +name+ attribute. # Each checkbox is followed by a label. # There will be one checkbox for each value. Each value # can be specified as a String, which will be used both # as the value of the VALUE attribute and as the label # for that checkbox. A single-element array has the # same effect. # # Each value can also be specified as a three-element array. # The first element is the VALUE attribute; the second is the # label; and the third is a boolean specifying whether this # checkbox is CHECKED. # # Each value can also be specified as a two-element # array, by omitting either the value element (defaults # to the same as the label), or the boolean checked element # (defaults to false). # # checkbox_group("name", "foo", "bar", "baz") # # foo # # bar # # baz # # checkbox_group("name", ["foo"], ["bar", true], "baz") # # foo # # bar # # baz # # checkbox_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz") # # Foo # # Bar # # Baz # # checkbox_group("NAME" => "name", # "VALUES" => ["foo", "bar", "baz"]) # # checkbox_group("NAME" => "name", # "VALUES" => [["foo"], ["bar", true], "baz"]) # # checkbox_group("NAME" => "name", # "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"]) def checkbox_group(name = "", *values) if name.kind_of?(Hash) values = name["VALUES"] name = name["NAME"] end values.collect{|value| if value.kind_of?(String) checkbox(name, value) + value else if value[value.size - 1] == true checkbox(name, value[0], true) + value[value.size - 2] else checkbox(name, value[0]) + value[value.size - 1] end end }.to_s end # Generate an File Upload Input element as a string. # # The attributes of the element can be specified as three arguments, # +name+, +size+, and +maxlength+. +maxlength+ is the maximum length # of the file's _name_, not of the file's _contents_. # # Alternatively, the attributes can be specified as a hash. # # See #multipart_form() for forms that include file uploads. # # file_field("name") # # # # file_field("name", 40) # # # # file_field("name", 40, 100) # # # # file_field("NAME" => "name", "SIZE" => 40) # # def file_field(name = "", size = 20, maxlength = nil) attributes = if name.kind_of?(String) { "TYPE" => "file", "NAME" => name, "SIZE" => size.to_s } else name["TYPE"] = "file" name end attributes["MAXLENGTH"] = maxlength.to_s if maxlength input(attributes) end # Generate a Form element as a string. # # +method+ should be either "get" or "post", and defaults to the latter. # +action+ defaults to the current CGI script name. +enctype+ # defaults to "application/x-www-form-urlencoded". # # Alternatively, the attributes can be specified as a hash. # # See also #multipart_form() for forms that include file uploads. # # form{ "string" } # #
    string
    # # form("get") { "string" } # #
    string
    # # form("get", "url") { "string" } # #
    string
    # # form("METHOD" => "post", "ENCTYPE" => "enctype") { "string" } # #
    string
    def form(method = "post", action = script_name, enctype = "application/x-www-form-urlencoded") attributes = if method.kind_of?(String) { "METHOD" => method, "ACTION" => action, "ENCTYPE" => enctype } else unless method.has_key?("METHOD") method["METHOD"] = "post" end unless method.has_key?("ENCTYPE") method["ENCTYPE"] = enctype end method end if block_given? body = yield else body = "" end if @output_hidden body += @output_hidden.collect{|k,v| "" }.to_s end super(attributes){body} end # Generate a Hidden Input element as a string. # # The attributes of the element can be specified as two arguments, # +name+ and +value+. # # Alternatively, the attributes can be specified as a hash. # # hidden("name") # # # # hidden("name", "value") # # # # hidden("NAME" => "name", "VALUE" => "reset", "ID" => "foo") # # def hidden(name = "", value = nil) attributes = if name.kind_of?(String) { "TYPE" => "hidden", "NAME" => name, "VALUE" => value } else name["TYPE"] = "hidden" name end input(attributes) end # Generate a top-level HTML element as a string. # # The attributes of the element are specified as a hash. The # pseudo-attribute "PRETTY" can be used to specify that the generated # HTML string should be indented. "PRETTY" can also be specified as # a string as the sole argument to this method. The pseudo-attribute # "DOCTYPE", if given, is used as the leading DOCTYPE SGML tag; it # should include the entire text of this tag, including angle brackets. # # The body of the html element is supplied as a block. # # html{ "string" } # # string # # html("LANG" => "ja") { "string" } # # string # # html("DOCTYPE" => false) { "string" } # # string # # html("DOCTYPE" => '') { "string" } # # string # # html("PRETTY" => " ") { "" } # # # # # # # # # # # # html("PRETTY" => "\t") { "" } # # # # # # # # # # # # html("PRETTY") { "" } # # = html("PRETTY" => " ") { "" } # # html(if $VERBOSE then "PRETTY" end) { "HTML string" } # def html(attributes = {}) # :yield: if nil == attributes attributes = {} elsif "PRETTY" == attributes attributes = { "PRETTY" => true } end pretty = attributes.delete("PRETTY") pretty = " " if true == pretty buf = "" if attributes.has_key?("DOCTYPE") if attributes["DOCTYPE"] buf += attributes.delete("DOCTYPE") else attributes.delete("DOCTYPE") end else buf += doctype end if block_given? buf += super(attributes){ yield } else buf += super(attributes) end if pretty CGI::pretty(buf, pretty) else buf end end # Generate an Image Button Input element as a string. # # +src+ is the URL of the image to use for the button. +name+ # is the input name. +alt+ is the alternative text for the image. # # Alternatively, the attributes can be specified as a hash. # # image_button("url") # # # # image_button("url", "name", "string") # # # # image_button("SRC" => "url", "ATL" => "strng") # # def image_button(src = "", name = nil, alt = nil) attributes = if src.kind_of?(String) { "TYPE" => "image", "SRC" => src, "NAME" => name, "ALT" => alt } else src["TYPE"] = "image" src["SRC"] ||= "" src end input(attributes) end # Generate an Image element as a string. # # +src+ is the URL of the image. +alt+ is the alternative text for # the image. +width+ is the width of the image, and +height+ is # its height. # # Alternatively, the attributes can be specified as a hash. # # img("src", "alt", 100, 50) # # alt # # img("SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50) # # alt def img(src = "", alt = "", width = nil, height = nil) attributes = if src.kind_of?(String) { "SRC" => src, "ALT" => alt } else src end attributes["WIDTH"] = width.to_s if width attributes["HEIGHT"] = height.to_s if height super(attributes) end # Generate a Form element with multipart encoding as a String. # # Multipart encoding is used for forms that include file uploads. # # +action+ is the action to perform. +enctype+ is the encoding # type, which defaults to "multipart/form-data". # # Alternatively, the attributes can be specified as a hash. # # multipart_form{ "string" } # #
    string
    # # multipart_form("url") { "string" } # #
    string
    def multipart_form(action = nil, enctype = "multipart/form-data") attributes = if action == nil { "METHOD" => "post", "ENCTYPE" => enctype } elsif action.kind_of?(String) { "METHOD" => "post", "ACTION" => action, "ENCTYPE" => enctype } else unless action.has_key?("METHOD") action["METHOD"] = "post" end unless action.has_key?("ENCTYPE") action["ENCTYPE"] = enctype end action end if block_given? form(attributes){ yield } else form(attributes) end end # Generate a Password Input element as a string. # # +name+ is the name of the input field. +value+ is its default # value. +size+ is the size of the input field display. +maxlength+ # is the maximum length of the inputted password. # # Alternatively, attributes can be specified as a hash. # # password_field("name") # # # # password_field("name", "value") # # # # password_field("password", "value", 80, 200) # # # # password_field("NAME" => "name", "VALUE" => "value") # # def password_field(name = "", value = nil, size = 40, maxlength = nil) attributes = if name.kind_of?(String) { "TYPE" => "password", "NAME" => name, "VALUE" => value, "SIZE" => size.to_s } else name["TYPE"] = "password" name end attributes["MAXLENGTH"] = maxlength.to_s if maxlength input(attributes) end # Generate a Select element as a string. # # +name+ is the name of the element. The +values+ are the options that # can be selected from the Select menu. Each value can be a String or # a one, two, or three-element Array. If a String or a one-element # Array, this is both the value of that option and the text displayed for # it. If a three-element Array, the elements are the option value, displayed # text, and a boolean value specifying whether this option starts as selected. # The two-element version omits either the option value (defaults to the same # as the display text) or the boolean selected specifier (defaults to false). # # The attributes and options can also be specified as a hash. In this # case, options are specified as an array of values as described above, # with the hash key of "VALUES". # # popup_menu("name", "foo", "bar", "baz") # # # # popup_menu("name", ["foo"], ["bar", true], "baz") # # # # popup_menu("name", ["1", "Foo"], ["2", "Bar", true], "Baz") # # # # popup_menu("NAME" => "name", "SIZE" => 2, "MULTIPLE" => true, # "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"]) # # def popup_menu(name = "", *values) if name.kind_of?(Hash) values = name["VALUES"] size = name["SIZE"].to_s if name["SIZE"] multiple = name["MULTIPLE"] name = name["NAME"] else size = nil multiple = nil end select({ "NAME" => name, "SIZE" => size, "MULTIPLE" => multiple }){ values.collect{|value| if value.kind_of?(String) option({ "VALUE" => value }){ value } else if value[value.size - 1] == true option({ "VALUE" => value[0], "SELECTED" => true }){ value[value.size - 2] } else option({ "VALUE" => value[0] }){ value[value.size - 1] } end end }.to_s } end # Generates a radio-button Input element. # # +name+ is the name of the input field. +value+ is the value of # the field if checked. +checked+ specifies whether the field # starts off checked. # # Alternatively, the attributes can be specified as a hash. # # radio_button("name", "value") # # # # radio_button("name", "value", true) # # # # radio_button("NAME" => "name", "VALUE" => "value", "ID" => "foo") # # def radio_button(name = "", value = nil, checked = nil) attributes = if name.kind_of?(String) { "TYPE" => "radio", "NAME" => name, "VALUE" => value, "CHECKED" => checked } else name["TYPE"] = "radio" name end input(attributes) end # Generate a sequence of radio button Input elements, as a String. # # This works the same as #checkbox_group(). However, it is not valid # to have more than one radiobutton in a group checked. # # radio_group("name", "foo", "bar", "baz") # # foo # # bar # # baz # # radio_group("name", ["foo"], ["bar", true], "baz") # # foo # # bar # # baz # # radio_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz") # # Foo # # Bar # # Baz # # radio_group("NAME" => "name", # "VALUES" => ["foo", "bar", "baz"]) # # radio_group("NAME" => "name", # "VALUES" => [["foo"], ["bar", true], "baz"]) # # radio_group("NAME" => "name", # "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"]) def radio_group(name = "", *values) if name.kind_of?(Hash) values = name["VALUES"] name = name["NAME"] end values.collect{|value| if value.kind_of?(String) radio_button(name, value) + value else if value[value.size - 1] == true radio_button(name, value[0], true) + value[value.size - 2] else radio_button(name, value[0]) + value[value.size - 1] end end }.to_s end # Generate a reset button Input element, as a String. # # This resets the values on a form to their initial values. +value+ # is the text displayed on the button. +name+ is the name of this button. # # Alternatively, the attributes can be specified as a hash. # # reset # # # # reset("reset") # # # # reset("VALUE" => "reset", "ID" => "foo") # # def reset(value = nil, name = nil) attributes = if (not value) or value.kind_of?(String) { "TYPE" => "reset", "VALUE" => value, "NAME" => name } else value["TYPE"] = "reset" value end input(attributes) end alias scrolling_list popup_menu # Generate a submit button Input element, as a String. # # +value+ is the text to display on the button. +name+ is the name # of the input. # # Alternatively, the attributes can be specified as a hash. # # submit # # # # submit("ok") # # # # submit("ok", "button1") # # # # submit("VALUE" => "ok", "NAME" => "button1", "ID" => "foo") # # def submit(value = nil, name = nil) attributes = if (not value) or value.kind_of?(String) { "TYPE" => "submit", "VALUE" => value, "NAME" => name } else value["TYPE"] = "submit" value end input(attributes) end # Generate a text field Input element, as a String. # # +name+ is the name of the input field. +value+ is its initial # value. +size+ is the size of the input area. +maxlength+ # is the maximum length of input accepted. # # Alternatively, the attributes can be specified as a hash. # # text_field("name") # # # # text_field("name", "value") # # # # text_field("name", "value", 80) # # # # text_field("name", "value", 80, 200) # # # # text_field("NAME" => "name", "VALUE" => "value") # # def text_field(name = "", value = nil, size = 40, maxlength = nil) attributes = if name.kind_of?(String) { "TYPE" => "text", "NAME" => name, "VALUE" => value, "SIZE" => size.to_s } else name["TYPE"] = "text" name end attributes["MAXLENGTH"] = maxlength.to_s if maxlength input(attributes) end # Generate a TextArea element, as a String. # # +name+ is the name of the textarea. +cols+ is the number of # columns and +rows+ is the number of rows in the display. # # Alternatively, the attributes can be specified as a hash. # # The body is provided by the passed-in no-argument block # # textarea("name") # # = textarea("NAME" => "name", "COLS" => 70, "ROWS" => 10) # # textarea("name", 40, 5) # # = textarea("NAME" => "name", "COLS" => 40, "ROWS" => 5) def textarea(name = "", cols = 70, rows = 10) # :yield: attributes = if name.kind_of?(String) { "NAME" => name, "COLS" => cols.to_s, "ROWS" => rows.to_s } else name end if block_given? super(attributes){ yield } else super(attributes) end end end # HtmlExtension # Mixin module for HTML version 3 generation methods. module Html3 # :nodoc: # The DOCTYPE declaration for this version of HTML def doctype %|| end # Initialise the HTML generation methods for this version. def element_init extend TagMaker methods = "" # - - for element in %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG DFN CODE SAMP KBD VAR CITE FONT ADDRESS DIV center MAP APPLET PRE XMP LISTING DL OL UL DIR MENU SELECT table TITLE STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM BLOCKQUOTE CAPTION ] methods += <<-BEGIN + nn_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end # - O EMPTY for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT ISINDEX META ] methods += <<-BEGIN + nOE_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end # O O or - O for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD LI OPTION tr th td ] methods += <<-BEGIN + nO_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end eval(methods) end end # Html3 # Mixin module for HTML version 4 generation methods. module Html4 # :nodoc: # The DOCTYPE declaration for this version of HTML def doctype %|| end # Initialise the HTML generation methods for this version. def element_init extend TagMaker methods = "" # - - for element in %w[ TT I B BIG SMALL EM STRONG DFN CODE SAMP KBD VAR CITE ABBR ACRONYM SUB SUP SPAN BDO ADDRESS DIV MAP OBJECT H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL LABEL SELECT OPTGROUP FIELDSET LEGEND BUTTON TABLE TITLE STYLE SCRIPT NOSCRIPT TEXTAREA FORM A BLOCKQUOTE CAPTION ] methods += <<-BEGIN + nn_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end # - O EMPTY for element in %w[ IMG BASE BR AREA LINK PARAM HR INPUT COL META ] methods += <<-BEGIN + nOE_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end # O O or - O for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY COLGROUP TR TH TD HEAD] methods += <<-BEGIN + nO_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end eval(methods) end end # Html4 # Mixin module for HTML version 4 transitional generation methods. module Html4Tr # :nodoc: # The DOCTYPE declaration for this version of HTML def doctype %|| end # Initialise the HTML generation methods for this version. def element_init extend TagMaker methods = "" # - - for element in %w[ TT I B U S STRIKE BIG SMALL EM STRONG DFN CODE SAMP KBD VAR CITE ABBR ACRONYM FONT SUB SUP SPAN BDO ADDRESS DIV CENTER MAP OBJECT APPLET H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL DIR MENU LABEL SELECT OPTGROUP FIELDSET LEGEND BUTTON TABLE IFRAME NOFRAMES TITLE STYLE SCRIPT NOSCRIPT TEXTAREA FORM A BLOCKQUOTE CAPTION ] methods += <<-BEGIN + nn_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end # - O EMPTY for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT COL ISINDEX META ] methods += <<-BEGIN + nOE_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end # O O or - O for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY COLGROUP TR TH TD HEAD ] methods += <<-BEGIN + nO_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end eval(methods) end end # Html4Tr # Mixin module for generating HTML version 4 with framesets. module Html4Fr # :nodoc: # The DOCTYPE declaration for this version of HTML def doctype %|| end # Initialise the HTML generation methods for this version. def element_init methods = "" # - - for element in %w[ FRAMESET ] methods += <<-BEGIN + nn_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end # - O EMPTY for element in %w[ FRAME ] methods += <<-BEGIN + nOE_element_def(element) + <<-END def #{element.downcase}(attributes = {}) BEGIN end END end eval(methods) end end # Html4Fr # Creates a new CGI instance. # # +type+ specifies which version of HTML to load the HTML generation # methods for. The following versions of HTML are supported: # # html3:: HTML 3.x # html4:: HTML 4.0 # html4Tr:: HTML 4.0 Transitional # html4Fr:: HTML 4.0 with Framesets # # If not specified, no HTML generation methods will be loaded. # # If the CGI object is not created in a standard CGI call environment # (that is, it can't locate REQUEST_METHOD in its environment), then # it will run in "offline" mode. In this mode, it reads its parameters # from the command line or (failing that) from standard input. Otherwise, # cookies and other parameters are parsed automatically from the standard # CGI locations, which varies according to the REQUEST_METHOD. def initialize(type = "query") if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE") Apache.request.setup_cgi_env end extend QueryExtension @multipart = false if defined?(CGI_PARAMS) warn "do not use CGI_PARAMS and CGI_COOKIES" @params = CGI_PARAMS.dup @cookies = CGI_COOKIES.dup else initialize_query() # set @params, @cookies end @output_cookies = nil @output_hidden = nil case type when "html3" extend Html3 element_init() extend HtmlExtension when "html4" extend Html4 element_init() extend HtmlExtension when "html4Tr" extend Html4Tr element_init() extend HtmlExtension when "html4Fr" extend Html4Tr element_init() extend Html4Fr element_init() extend HtmlExtension end end end # class CGI PK|]OGR~R~time.rbnu[ # # == Introduction # # This library extends the Time class: # * conversion between date string and time object. # * date-time defined by RFC 2822 # * HTTP-date defined by RFC 2616 # * dateTime defined by XML Schema Part 2: Datatypes (ISO 8601) # * various formats handled by Date._parse (string to time only) # # == Design Issues # # === Specialized interface # # This library provides methods dedicated to special purposes: # * RFC 2822, RFC 2616 and XML Schema. # * They makes usual life easier. # # === Doesn't depend on strftime # # This library doesn't use +strftime+. Especially #rfc2822 doesn't depend # on +strftime+ because: # # * %a and %b are locale sensitive # # Since they are locale sensitive, they may be replaced to # invalid weekday/month name in some locales. # Since ruby-1.6 doesn't invoke setlocale by default, # the problem doesn't arise until some external library invokes setlocale. # Ruby/GTK is the example of such library. # # * %z is not portable # # %z is required to generate zone in date-time of RFC 2822 # but it is not portable. # # == Revision Information # # $Id$ # require 'parsedate' # # Implements the extensions to the Time class that are described in the # documentation for the time.rb library. # class Time class << Time ZoneOffset = { 'UTC' => 0, # ISO 8601 'Z' => 0, # RFC 822 'UT' => 0, 'GMT' => 0, 'EST' => -5, 'EDT' => -4, 'CST' => -6, 'CDT' => -5, 'MST' => -7, 'MDT' => -6, 'PST' => -8, 'PDT' => -7, # Following definition of military zones is original one. # See RFC 1123 and RFC 2822 for the error in RFC 822. 'A' => +1, 'B' => +2, 'C' => +3, 'D' => +4, 'E' => +5, 'F' => +6, 'G' => +7, 'H' => +8, 'I' => +9, 'K' => +10, 'L' => +11, 'M' => +12, 'N' => -1, 'O' => -2, 'P' => -3, 'Q' => -4, 'R' => -5, 'S' => -6, 'T' => -7, 'U' => -8, 'V' => -9, 'W' => -10, 'X' => -11, 'Y' => -12, } def zone_offset(zone, year=self.now.year) off = nil zone = zone.upcase if /\A([+-])(\d\d):?(\d\d)\z/ =~ zone off = ($1 == '-' ? -1 : 1) * ($2.to_i * 60 + $3.to_i) * 60 elsif /\A[+-]\d\d\z/ =~ zone off = zone.to_i * 3600 elsif ZoneOffset.include?(zone) off = ZoneOffset[zone] * 3600 elsif ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false) off = t.utc_offset elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false) off = t.utc_offset end off end def zone_utc?(zone) # * +0000 means localtime. [RFC 2822] # * GMT is a localtime abbreviation in Europe/London, etc. if /\A(?:-00:00|-0000|-00|UTC|Z|UT)\z/i =~ zone true else false end end private :zone_utc? LeapYearMonthDays = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] CommonYearMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] def month_days(y, m) if ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0) LeapYearMonthDays[m-1] else CommonYearMonthDays[m-1] end end private :month_days def apply_offset(year, mon, day, hour, min, sec, off) if off < 0 off = -off off, o = off.divmod(60) if o != 0 then sec += o; o, sec = sec.divmod(60); off += o end off, o = off.divmod(60) if o != 0 then min += o; o, min = min.divmod(60); off += o end off, o = off.divmod(24) if o != 0 then hour += o; o, hour = hour.divmod(24); off += o end if off != 0 day += off if month_days(year, mon) < day mon += 1 if 12 < mon mon = 1 year += 1 end day = 1 end end elsif 0 < off off, o = off.divmod(60) if o != 0 then sec -= o; o, sec = sec.divmod(60); off -= o end off, o = off.divmod(60) if o != 0 then min -= o; o, min = min.divmod(60); off -= o end off, o = off.divmod(24) if o != 0 then hour -= o; o, hour = hour.divmod(24); off -= o end if off != 0 then day -= off if day < 1 mon -= 1 if mon < 1 year -= 1 mon = 12 end day = month_days(year, mon) end end end return year, mon, day, hour, min, sec end private :apply_offset def make_time(year, mon, day, hour, min, sec, sec_fraction, zone, now) usec = nil usec = (sec_fraction * 1000000).to_i if sec_fraction if now begin break if year; year = now.year break if mon; mon = now.mon break if day; day = now.day break if hour; hour = now.hour break if min; min = now.min break if sec; sec = now.sec break if sec_fraction; usec = now.tv_usec end until true end year ||= 1970 mon ||= 1 day ||= 1 hour ||= 0 min ||= 0 sec ||= 0 usec ||= 0 off = nil off = zone_offset(zone, year) if zone if off year, mon, day, hour, min, sec = apply_offset(year, mon, day, hour, min, sec, off) t = self.utc(year, mon, day, hour, min, sec, usec) t.localtime if !zone_utc?(zone) t else self.local(year, mon, day, hour, min, sec, usec) end end private :make_time # # Parses +date+ using Date._parse and converts it to a Time object. # # If a block is given, the year described in +date+ is converted by the # block. For example: # # Time.parse(...) {|y| y < 100 ? (y >= 69 ? y + 1900 : y + 2000) : y} # # If the upper components of the given time are broken or missing, they are # supplied with those of +now+. For the lower components, the minimum # values (1 or 0) are assumed if broken or missing. For example: # # # Suppose it is "Thu Nov 29 14:33:20 GMT 2001" now and # # your timezone is GMT: # Time.parse("16:30") #=> Thu Nov 29 16:30:00 GMT 2001 # Time.parse("7/23") #=> Mon Jul 23 00:00:00 GMT 2001 # Time.parse("Aug 31") #=> Fri Aug 31 00:00:00 GMT 2001 # # Since there are numerous conflicts among locally defined timezone # abbreviations all over the world, this method is not made to # understand all of them. For example, the abbreviation "CST" is # used variously as: # # -06:00 in America/Chicago, # -05:00 in America/Havana, # +08:00 in Asia/Harbin, # +09:30 in Australia/Darwin, # +10:30 in Australia/Adelaide, # etc. # # Based on the fact, this method only understands the timezone # abbreviations described in RFC 822 and the system timezone, in the # order named. (i.e. a definition in RFC 822 overrides the system # timezone definition.) The system timezone is taken from # Time.local(year, 1, 1).zone and # Time.local(year, 7, 1).zone. # If the extracted timezone abbreviation does not match any of them, # it is ignored and the given time is regarded as a local time. # # ArgumentError is raised if Date._parse cannot extract information from # +date+ or Time class cannot represent specified date. # # This method can be used as fail-safe for other parsing methods as: # # Time.rfc2822(date) rescue Time.parse(date) # Time.httpdate(date) rescue Time.parse(date) # Time.xmlschema(date) rescue Time.parse(date) # # A failure for Time.parse should be checked, though. # def parse(date, now=self.now) d = Date._parse(date, false) year = d[:year] year = yield(year) if year && block_given? make_time(year, d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now) end MonthValue = { 'JAN' => 1, 'FEB' => 2, 'MAR' => 3, 'APR' => 4, 'MAY' => 5, 'JUN' => 6, 'JUL' => 7, 'AUG' => 8, 'SEP' => 9, 'OCT' =>10, 'NOV' =>11, 'DEC' =>12 } # # Parses +date+ as date-time defined by RFC 2822 and converts it to a Time # object. The format is identical to the date format defined by RFC 822 and # updated by RFC 1123. # # ArgumentError is raised if +date+ is not compliant with RFC 2822 # or Time class cannot represent specified date. # # See #rfc2822 for more information on this format. # def rfc2822(date) if /\A\s* (?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*,\s*)? (\d{1,2})\s+ (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+ (\d{2,})\s+ (\d{2})\s* :\s*(\d{2})\s* (?::\s*(\d{2}))?\s+ ([+-]\d{4}| UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-IK-Z])/ix =~ date # Since RFC 2822 permit comments, the regexp has no right anchor. day = $1.to_i mon = MonthValue[$2.upcase] year = $3.to_i hour = $4.to_i min = $5.to_i sec = $6 ? $6.to_i : 0 zone = $7 # following year completion is compliant with RFC 2822. year = if year < 50 2000 + year elsif year < 1000 1900 + year else year end year, mon, day, hour, min, sec = apply_offset(year, mon, day, hour, min, sec, zone_offset(zone)) t = self.utc(year, mon, day, hour, min, sec) t.localtime if !zone_utc?(zone) t else raise ArgumentError.new("not RFC 2822 compliant date: #{date.inspect}") end end alias rfc822 rfc2822 # # Parses +date+ as HTTP-date defined by RFC 2616 and converts it to a Time # object. # # ArgumentError is raised if +date+ is not compliant with RFC 2616 or Time # class cannot represent specified date. # # See #httpdate for more information on this format. # def httpdate(date) if /\A\s* (?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\x20 (\d{2})\x20 (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\x20 (\d{4})\x20 (\d{2}):(\d{2}):(\d{2})\x20 GMT \s*\z/ix =~ date self.rfc2822(date) elsif /\A\s* (?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday),\x20 (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d)\x20 (\d\d):(\d\d):(\d\d)\x20 GMT \s*\z/ix =~ date self.parse(date) elsif /\A\s* (?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\x20 (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\x20 (\d\d|\x20\d)\x20 (\d\d):(\d\d):(\d\d)\x20 (\d{4}) \s*\z/ix =~ date self.utc($6.to_i, MonthValue[$1.upcase], $2.to_i, $3.to_i, $4.to_i, $5.to_i) else raise ArgumentError.new("not RFC 2616 compliant date: #{date.inspect}") end end # # Parses +date+ as dateTime defined by XML Schema and converts it to a Time # object. The format is restricted version of the format defined by ISO # 8601. # # ArgumentError is raised if +date+ is not compliant with the format or Time # class cannot represent specified date. # # See #xmlschema for more information on this format. # def xmlschema(date) if /\A\s* (-?\d+)-(\d\d)-(\d\d) T (\d\d):(\d\d):(\d\d) (\.\d*)? (Z|[+-]\d\d:\d\d)? \s*\z/ix =~ date year = $1.to_i mon = $2.to_i day = $3.to_i hour = $4.to_i min = $5.to_i sec = $6.to_i usec = 0 usec = ($7[1..-1] + '000000')[0,6].to_i if $7 if $8 zone = $8 year, mon, day, hour, min, sec = apply_offset(year, mon, day, hour, min, sec, zone_offset(zone)) self.utc(year, mon, day, hour, min, sec, usec) else self.local(year, mon, day, hour, min, sec, usec) end else raise ArgumentError.new("invalid date: #{date.inspect}") end end alias iso8601 xmlschema end # class << self # # Returns a string which represents the time as date-time defined by RFC 2822: # # day-of-week, DD month-name CCYY hh:mm:ss zone # # where zone is [+-]hhmm. # # If +self+ is a UTC time, -0000 is used as zone. # def rfc2822 sprintf('%s, %02d %s %d %02d:%02d:%02d ', RFC2822_DAY_NAME[wday], day, RFC2822_MONTH_NAME[mon-1], year, hour, min, sec) + if utc? '-0000' else off = utc_offset sign = off < 0 ? '-' : '+' sprintf('%s%02d%02d', sign, *(off.abs / 60).divmod(60)) end end alias rfc822 rfc2822 RFC2822_DAY_NAME = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ] RFC2822_MONTH_NAME = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] # # Returns a string which represents the time as rfc1123-date of HTTP-date # defined by RFC 2616: # # day-of-week, DD month-name CCYY hh:mm:ss GMT # # Note that the result is always UTC (GMT). # def httpdate t = dup.utc sprintf('%s, %02d %s %d %02d:%02d:%02d GMT', RFC2822_DAY_NAME[t.wday], t.day, RFC2822_MONTH_NAME[t.mon-1], t.year, t.hour, t.min, t.sec) end # # Returns a string which represents the time as dateTime defined by XML # Schema: # # CCYY-MM-DDThh:mm:ssTZD # CCYY-MM-DDThh:mm:ss.sssTZD # # where TZD is Z or [+-]hh:mm. # # If self is a UTC time, Z is used as TZD. [+-]hh:mm is used otherwise. # # +fractional_seconds+ specifies a number of digits of fractional seconds. # Its default value is 0. # def xmlschema(fraction_digits=0) sprintf('%d-%02d-%02dT%02d:%02d:%02d', year, mon, day, hour, min, sec) + if fraction_digits == 0 '' elsif fraction_digits <= 6 '.' + sprintf('%06d', usec)[0, fraction_digits] else '.' + sprintf('%06d', usec) + '0' * (fraction_digits - 6) end + if utc? 'Z' else off = utc_offset sign = off < 0 ? '-' : '+' sprintf('%s%02d:%02d', sign, *(off.abs / 60).divmod(60)) end end alias iso8601 xmlschema end if __FILE__ == $0 require 'test/unit' class TimeExtentionTest < Test::Unit::TestCase # :nodoc: def test_rfc822 assert_equal(Time.utc(1976, 8, 26, 14, 30) + 4 * 3600, Time.rfc2822("26 Aug 76 14:30 EDT")) assert_equal(Time.utc(1976, 8, 27, 9, 32) + 7 * 3600, Time.rfc2822("27 Aug 76 09:32 PDT")) end def test_rfc2822 assert_equal(Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600, Time.rfc2822("Fri, 21 Nov 1997 09:55:06 -0600")) assert_equal(Time.utc(2003, 7, 1, 10, 52, 37) - 2 * 3600, Time.rfc2822("Tue, 1 Jul 2003 10:52:37 +0200")) assert_equal(Time.utc(1997, 11, 21, 10, 1, 10) + 6 * 3600, Time.rfc2822("Fri, 21 Nov 1997 10:01:10 -0600")) assert_equal(Time.utc(1997, 11, 21, 11, 0, 0) + 6 * 3600, Time.rfc2822("Fri, 21 Nov 1997 11:00:00 -0600")) assert_equal(Time.utc(1997, 11, 24, 14, 22, 1) + 8 * 3600, Time.rfc2822("Mon, 24 Nov 1997 14:22:01 -0800")) begin Time.at(-1) rescue ArgumentError # ignore else assert_equal(Time.utc(1969, 2, 13, 23, 32, 54) + 3 * 3600 + 30 * 60, Time.rfc2822("Thu, 13 Feb 1969 23:32:54 -0330")) assert_equal(Time.utc(1969, 2, 13, 23, 32, 0) + 3 * 3600 + 30 * 60, Time.rfc2822(" Thu, 13 Feb 1969 23:32 -0330 (Newfoundland Time)")) end assert_equal(Time.utc(1997, 11, 21, 9, 55, 6), Time.rfc2822("21 Nov 97 09:55:06 GMT")) assert_equal(Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600, Time.rfc2822("Fri, 21 Nov 1997 09 : 55 : 06 -0600")) assert_raise(ArgumentError) { # inner comment is not supported. Time.rfc2822("Fri, 21 Nov 1997 09(comment): 55 : 06 -0600") } end def test_rfc2616 t = Time.utc(1994, 11, 6, 8, 49, 37) assert_equal(t, Time.httpdate("Sun, 06 Nov 1994 08:49:37 GMT")) assert_equal(t, Time.httpdate("Sunday, 06-Nov-94 08:49:37 GMT")) assert_equal(t, Time.httpdate("Sun Nov 6 08:49:37 1994")) assert_equal(Time.utc(1995, 11, 15, 6, 25, 24), Time.httpdate("Wed, 15 Nov 1995 06:25:24 GMT")) assert_equal(Time.utc(1995, 11, 15, 4, 58, 8), Time.httpdate("Wed, 15 Nov 1995 04:58:08 GMT")) assert_equal(Time.utc(1994, 11, 15, 8, 12, 31), Time.httpdate("Tue, 15 Nov 1994 08:12:31 GMT")) assert_equal(Time.utc(1994, 12, 1, 16, 0, 0), Time.httpdate("Thu, 01 Dec 1994 16:00:00 GMT")) assert_equal(Time.utc(1994, 10, 29, 19, 43, 31), Time.httpdate("Sat, 29 Oct 1994 19:43:31 GMT")) assert_equal(Time.utc(1994, 11, 15, 12, 45, 26), Time.httpdate("Tue, 15 Nov 1994 12:45:26 GMT")) assert_equal(Time.utc(1999, 12, 31, 23, 59, 59), Time.httpdate("Fri, 31 Dec 1999 23:59:59 GMT")) end def test_rfc3339 t = Time.utc(1985, 4, 12, 23, 20, 50, 520000) s = "1985-04-12T23:20:50.52Z" assert_equal(t, Time.iso8601(s)) assert_equal(s, t.iso8601(2)) t = Time.utc(1996, 12, 20, 0, 39, 57) s = "1996-12-19T16:39:57-08:00" assert_equal(t, Time.iso8601(s)) # There is no way to generate time string with arbitrary timezone. s = "1996-12-20T00:39:57Z" assert_equal(t, Time.iso8601(s)) assert_equal(s, t.iso8601) t = Time.utc(1990, 12, 31, 23, 59, 60) s = "1990-12-31T23:59:60Z" assert_equal(t, Time.iso8601(s)) # leap second is representable only if timezone file has it. s = "1990-12-31T15:59:60-08:00" assert_equal(t, Time.iso8601(s)) begin Time.at(-1) rescue ArgumentError # ignore else t = Time.utc(1937, 1, 1, 11, 40, 27, 870000) s = "1937-01-01T12:00:27.87+00:20" assert_equal(t, Time.iso8601(s)) end end # http://www.w3.org/TR/xmlschema-2/ def test_xmlschema assert_equal(Time.utc(1999, 5, 31, 13, 20, 0) + 5 * 3600, Time.xmlschema("1999-05-31T13:20:00-05:00")) assert_equal(Time.local(2000, 1, 20, 12, 0, 0), Time.xmlschema("2000-01-20T12:00:00")) assert_equal(Time.utc(2000, 1, 20, 12, 0, 0), Time.xmlschema("2000-01-20T12:00:00Z")) assert_equal(Time.utc(2000, 1, 20, 12, 0, 0) - 12 * 3600, Time.xmlschema("2000-01-20T12:00:00+12:00")) assert_equal(Time.utc(2000, 1, 20, 12, 0, 0) + 13 * 3600, Time.xmlschema("2000-01-20T12:00:00-13:00")) assert_equal(Time.utc(2000, 3, 4, 23, 0, 0) - 3 * 3600, Time.xmlschema("2000-03-04T23:00:00+03:00")) assert_equal(Time.utc(2000, 3, 4, 20, 0, 0), Time.xmlschema("2000-03-04T20:00:00Z")) assert_equal(Time.local(2000, 1, 15, 0, 0, 0), Time.xmlschema("2000-01-15T00:00:00")) assert_equal(Time.local(2000, 2, 15, 0, 0, 0), Time.xmlschema("2000-02-15T00:00:00")) assert_equal(Time.local(2000, 1, 15, 12, 0, 0), Time.xmlschema("2000-01-15T12:00:00")) assert_equal(Time.utc(2000, 1, 16, 12, 0, 0), Time.xmlschema("2000-01-16T12:00:00Z")) assert_equal(Time.local(2000, 1, 1, 12, 0, 0), Time.xmlschema("2000-01-01T12:00:00")) assert_equal(Time.utc(1999, 12, 31, 23, 0, 0), Time.xmlschema("1999-12-31T23:00:00Z")) assert_equal(Time.local(2000, 1, 16, 12, 0, 0), Time.xmlschema("2000-01-16T12:00:00")) assert_equal(Time.local(2000, 1, 16, 0, 0, 0), Time.xmlschema("2000-01-16T00:00:00")) assert_equal(Time.utc(2000, 1, 12, 12, 13, 14), Time.xmlschema("2000-01-12T12:13:14Z")) assert_equal(Time.utc(2001, 4, 17, 19, 23, 17, 300000), Time.xmlschema("2001-04-17T19:23:17.3Z")) end def test_encode_xmlschema t = Time.utc(2001, 4, 17, 19, 23, 17, 300000) assert_equal("2001-04-17T19:23:17Z", t.xmlschema) assert_equal("2001-04-17T19:23:17.3Z", t.xmlschema(1)) assert_equal("2001-04-17T19:23:17.300000Z", t.xmlschema(6)) assert_equal("2001-04-17T19:23:17.3000000Z", t.xmlschema(7)) t = Time.utc(2001, 4, 17, 19, 23, 17, 123456) assert_equal("2001-04-17T19:23:17.1234560Z", t.xmlschema(7)) assert_equal("2001-04-17T19:23:17.123456Z", t.xmlschema(6)) assert_equal("2001-04-17T19:23:17.12345Z", t.xmlschema(5)) assert_equal("2001-04-17T19:23:17.1Z", t.xmlschema(1)) begin Time.at(-1) rescue ArgumentError # ignore else t = Time.utc(1960, 12, 31, 23, 0, 0, 123456) assert_equal("1960-12-31T23:00:00.123456Z", t.xmlschema(6)) end assert_equal(249, Time.xmlschema("2008-06-05T23:49:23.000249+09:00").usec) end def test_completion now = Time.local(2001,11,29,21,26,35) assert_equal(Time.local( 2001,11,29,21,12), Time.parse("2001/11/29 21:12", now)) assert_equal(Time.local( 2001,11,29), Time.parse("2001/11/29", now)) assert_equal(Time.local( 2001,11,29), Time.parse( "11/29", now)) #assert_equal(Time.local(2001,11,1), Time.parse("Nov", now)) assert_equal(Time.local( 2001,11,29,10,22), Time.parse( "10:22", now)) end def test_invalid # They were actually used in some web sites. assert_raise(ArgumentError) { Time.httpdate("1 Dec 2001 10:23:57 GMT") } assert_raise(ArgumentError) { Time.httpdate("Sat, 1 Dec 2001 10:25:42 GMT") } assert_raise(ArgumentError) { Time.httpdate("Sat, 1-Dec-2001 10:53:55 GMT") } assert_raise(ArgumentError) { Time.httpdate("Saturday, 01-Dec-2001 10:15:34 GMT") } assert_raise(ArgumentError) { Time.httpdate("Saturday, 01-Dec-101 11:10:07 GMT") } assert_raise(ArgumentError) { Time.httpdate("Fri, 30 Nov 2001 21:30:00 JST") } # They were actually used in some mails. assert_raise(ArgumentError) { Time.rfc2822("01-5-20") } assert_raise(ArgumentError) { Time.rfc2822("7/21/00") } assert_raise(ArgumentError) { Time.rfc2822("2001-8-28") } assert_raise(ArgumentError) { Time.rfc2822("00-5-6 1:13:06") } assert_raise(ArgumentError) { Time.rfc2822("2001-9-27 9:36:49") } assert_raise(ArgumentError) { Time.rfc2822("2000-12-13 11:01:11") } assert_raise(ArgumentError) { Time.rfc2822("2001/10/17 04:29:55") } assert_raise(ArgumentError) { Time.rfc2822("9/4/2001 9:23:19 PM") } assert_raise(ArgumentError) { Time.rfc2822("01 Nov 2001 09:04:31") } assert_raise(ArgumentError) { Time.rfc2822("13 Feb 2001 16:4 GMT") } assert_raise(ArgumentError) { Time.rfc2822("01 Oct 00 5:41:19 PM") } assert_raise(ArgumentError) { Time.rfc2822("2 Jul 00 00:51:37 JST") } assert_raise(ArgumentError) { Time.rfc2822("01 11 2001 06:55:57 -0500") } assert_raise(ArgumentError) { Time.rfc2822("18 \343\366\356\341\370 2000") } assert_raise(ArgumentError) { Time.rfc2822("Fri, Oct 2001 18:53:32") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 2 Nov 2001 03:47:54") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 27 Jul 2001 11.14.14 +0200") } assert_raise(ArgumentError) { Time.rfc2822("Thu, 2 Nov 2000 04:13:53 -600") } assert_raise(ArgumentError) { Time.rfc2822("Wed, 5 Apr 2000 22:57:09 JST") } assert_raise(ArgumentError) { Time.rfc2822("Mon, 11 Sep 2000 19:47:33 00000") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 28 Apr 2000 20:40:47 +-900") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 19 Jan 2001 8:15:36 AM -0500") } assert_raise(ArgumentError) { Time.rfc2822("Thursday, Sep 27 2001 7:42:35 AM EST") } assert_raise(ArgumentError) { Time.rfc2822("3/11/2001 1:31:57 PM Pacific Daylight Time") } assert_raise(ArgumentError) { Time.rfc2822("Mi, 28 Mrz 2001 11:51:36") } assert_raise(ArgumentError) { Time.rfc2822("P, 30 sept 2001 23:03:14") } assert_raise(ArgumentError) { Time.rfc2822("fr, 11 aug 2000 18:39:22") } assert_raise(ArgumentError) { Time.rfc2822("Fr, 21 Sep 2001 17:44:03 -1000") } assert_raise(ArgumentError) { Time.rfc2822("Mo, 18 Jun 2001 19:21:40 -1000") } assert_raise(ArgumentError) { Time.rfc2822("l\366, 12 aug 2000 18:53:20") } assert_raise(ArgumentError) { Time.rfc2822("l\366, 26 maj 2001 00:15:58") } assert_raise(ArgumentError) { Time.rfc2822("Dom, 30 Sep 2001 17:36:30") } assert_raise(ArgumentError) { Time.rfc2822("%&, 31 %2/ 2000 15:44:47 -0500") } assert_raise(ArgumentError) { Time.rfc2822("dom, 26 ago 2001 03:57:07 -0300") } assert_raise(ArgumentError) { Time.rfc2822("ter, 04 set 2001 16:27:58 -0300") } assert_raise(ArgumentError) { Time.rfc2822("Wen, 3 oct 2001 23:17:49 -0400") } assert_raise(ArgumentError) { Time.rfc2822("Wen, 3 oct 2001 23:17:49 -0400") } assert_raise(ArgumentError) { Time.rfc2822("ele, 11 h: 2000 12:42:15 -0500") } assert_raise(ArgumentError) { Time.rfc2822("Tue, 14 Aug 2001 3:55:3 +0200") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 25 Aug 2000 9:3:48 +0800") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 1 Dec 2000 0:57:50 EST") } assert_raise(ArgumentError) { Time.rfc2822("Mon, 7 May 2001 9:39:51 +0200") } assert_raise(ArgumentError) { Time.rfc2822("Wed, 1 Aug 2001 16:9:15 +0200") } assert_raise(ArgumentError) { Time.rfc2822("Wed, 23 Aug 2000 9:17:36 +0800") } assert_raise(ArgumentError) { Time.rfc2822("Fri, 11 Aug 2000 10:4:42 +0800") } assert_raise(ArgumentError) { Time.rfc2822("Sat, 15 Sep 2001 13:22:2 +0300") } assert_raise(ArgumentError) { Time.rfc2822("Wed,16 \276\305\324\302 2001 20:06:25 +0800") } assert_raise(ArgumentError) { Time.rfc2822("Wed,7 \312\256\322\273\324\302 2001 23:47:22 +0800") } assert_raise(ArgumentError) { Time.rfc2822("=?iso-8859-1?Q?(=C5=DA),?= 10 2 2001 23:32:26 +0900 (JST)") } assert_raise(ArgumentError) { Time.rfc2822("\307\341\314\343\332\311, 30 \344\346\335\343\310\321 2001 10:01:06") } assert_raise(ArgumentError) { Time.rfc2822("=?iso-8859-1?Q?(=BF=E5),?= 12 =?iso-8859-1?Q?9=B7=EE?= 2001 14:52:41\n+0900 (JST)") } end def test_zone_0000 assert_equal(true, Time.parse("2000-01-01T00:00:00Z").utc?) assert_equal(true, Time.parse("2000-01-01T00:00:00-00:00").utc?) assert_equal(false, Time.parse("2000-01-01T00:00:00+00:00").utc?) assert_equal(false, Time.parse("Sat, 01 Jan 2000 00:00:00 GMT").utc?) assert_equal(true, Time.parse("Sat, 01 Jan 2000 00:00:00 -0000").utc?) assert_equal(false, Time.parse("Sat, 01 Jan 2000 00:00:00 +0000").utc?) assert_equal(false, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 GMT").utc?) assert_equal(true, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 -0000").utc?) assert_equal(false, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 +0000").utc?) assert_equal(true, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 UTC").utc?) end def test_parse_leap_second t = Time.utc(1998,12,31,23,59,59) assert_equal(t, Time.parse("Thu Dec 31 23:59:59 UTC 1998")) assert_equal(t, Time.parse("Fri Dec 31 23:59:59 -0000 1998"));t.localtime assert_equal(t, Time.parse("Fri Jan 1 08:59:59 +0900 1999")) assert_equal(t, Time.parse("Fri Jan 1 00:59:59 +0100 1999")) assert_equal(t, Time.parse("Fri Dec 31 23:59:59 +0000 1998")) assert_equal(t, Time.parse("Fri Dec 31 22:59:59 -0100 1998"));t.utc t += 1 assert_equal(t, Time.parse("Thu Dec 31 23:59:60 UTC 1998")) assert_equal(t, Time.parse("Fri Dec 31 23:59:60 -0000 1998"));t.localtime assert_equal(t, Time.parse("Fri Jan 1 08:59:60 +0900 1999")) assert_equal(t, Time.parse("Fri Jan 1 00:59:60 +0100 1999")) assert_equal(t, Time.parse("Fri Dec 31 23:59:60 +0000 1998")) assert_equal(t, Time.parse("Fri Dec 31 22:59:60 -0100 1998"));t.utc t += 1 if t.sec == 60 assert_equal(t, Time.parse("Thu Jan 1 00:00:00 UTC 1999")) assert_equal(t, Time.parse("Fri Jan 1 00:00:00 -0000 1999"));t.localtime assert_equal(t, Time.parse("Fri Jan 1 09:00:00 +0900 1999")) assert_equal(t, Time.parse("Fri Jan 1 01:00:00 +0100 1999")) assert_equal(t, Time.parse("Fri Jan 1 00:00:00 +0000 1999")) assert_equal(t, Time.parse("Fri Dec 31 23:00:00 -0100 1998")) end def test_rfc2822_leap_second t = Time.utc(1998,12,31,23,59,59) assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:59 UTC")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 -0000"));t.localtime assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 08:59:59 +0900")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:59:59 +0100")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 +0000")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:59 -0100"));t.utc t += 1 assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:60 UTC")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 -0000"));t.localtime assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 08:59:60 +0900")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:59:60 +0100")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 +0000")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:60 -0100"));t.utc t += 1 if t.sec == 60 assert_equal(t, Time.rfc2822("Thu, 1 Jan 1999 00:00:00 UTC")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:00:00 -0000"));t.localtime assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 09:00:00 +0900")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 01:00:00 +0100")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:00:00 +0000")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:00:00 -0100")) end def test_xmlschema_leap_second t = Time.utc(1998,12,31,23,59,59) assert_equal(t, Time.xmlschema("1998-12-31T23:59:59Z")) assert_equal(t, Time.xmlschema("1998-12-31T23:59:59-00:00"));t.localtime assert_equal(t, Time.xmlschema("1999-01-01T08:59:59+09:00")) assert_equal(t, Time.xmlschema("1999-01-01T00:59:59+01:00")) assert_equal(t, Time.xmlschema("1998-12-31T23:59:59+00:00")) assert_equal(t, Time.xmlschema("1998-12-31T22:59:59-01:00"));t.utc t += 1 assert_equal(t, Time.xmlschema("1998-12-31T23:59:60Z")) assert_equal(t, Time.xmlschema("1998-12-31T23:59:60-00:00"));t.localtime assert_equal(t, Time.xmlschema("1999-01-01T08:59:60+09:00")) assert_equal(t, Time.xmlschema("1999-01-01T00:59:60+01:00")) assert_equal(t, Time.xmlschema("1998-12-31T23:59:60+00:00")) assert_equal(t, Time.xmlschema("1998-12-31T22:59:60-01:00"));t.utc t += 1 if t.sec == 60 assert_equal(t, Time.xmlschema("1999-01-01T00:00:00Z")) assert_equal(t, Time.xmlschema("1999-01-01T00:00:00-00:00"));t.localtime assert_equal(t, Time.xmlschema("1999-01-01T09:00:00+09:00")) assert_equal(t, Time.xmlschema("1999-01-01T01:00:00+01:00")) assert_equal(t, Time.xmlschema("1999-01-01T00:00:00+00:00")) assert_equal(t, Time.xmlschema("1998-12-31T23:00:00-01:00")) end def test_ruby_talk_152866 t = Time::xmlschema('2005-08-30T22:48:00-07:00') assert_equal(31, t.day) assert_equal(8, t.mon) end def test_parse_fraction assert_equal(500000, Time.parse("2000-01-01T00:00:00.5+00:00").tv_usec) end end end PK|]{7NN importenv.rbnu[# importenv.rb -- imports environment variables as global variables, Perlish ;( # # Usage: # # require 'importenv' # p $USER # $USER = "matz" # p ENV["USER"] warn "Warning:#{caller[0].sub(/:in `.*'\z/, '')}: importenv is deprecated after Ruby 1.8.1 (no replacement)" for k,v in ENV next unless /^[a-zA-Z][_a-zA-Z0-9]*/ =~ k eval <O1uri.rbnu[# # URI support for Ruby # # Author:: Akira Yamada # Documentation:: Akira Yamada , Dmitry V. Sabanin # License:: # Copyright (c) 2001 akira yamada # You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id: uri.rb 16038 2008-04-15 09:41:47Z kazu $ # # See URI for documentation # module URI # :stopdoc: VERSION_CODE = '000911'.freeze VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze # :startdoc: end require 'uri/common' require 'uri/generic' require 'uri/ftp' require 'uri/http' require 'uri/https' require 'uri/ldap' require 'uri/ldaps' require 'uri/mailto' PK|]ܽdate.rbnu[# # date.rb - date and time library # # Author: Tadayoshi Funaba 1998-2010 # # Documentation: William Webber # #-- # $Id: date.rb,v 2.37 2008-01-17 20:16:31+09 tadf Exp $ #++ # # == Overview # # This file provides two classes for working with # dates and times. # # The first class, Date, represents dates. # It works with years, months, weeks, and days. # See the Date class documentation for more details. # # The second, DateTime, extends Date to include hours, # minutes, seconds, and fractions of a second. It # provides basic support for time zones. See the # DateTime class documentation for more details. # # === Ways of calculating the date. # # In common usage, the date is reckoned in years since or # before the Common Era (CE/BCE, also known as AD/BC), then # as a month and day-of-the-month within the current year. # This is known as the *Civil* *Date*, and abbreviated # as +civil+ in the Date class. # # Instead of year, month-of-the-year, and day-of-the-month, # the date can also be reckoned in terms of year and # day-of-the-year. This is known as the *Ordinal* *Date*, # and is abbreviated as +ordinal+ in the Date class. (Note # that referring to this as the Julian date is incorrect.) # # The date can also be reckoned in terms of year, week-of-the-year, # and day-of-the-week. This is known as the *Commercial* # *Date*, and is abbreviated as +commercial+ in the # Date class. The commercial week runs Monday (day-of-the-week # 1) to Sunday (day-of-the-week 7), in contrast to the civil # week which runs Sunday (day-of-the-week 0) to Saturday # (day-of-the-week 6). The first week of the commercial year # starts on the Monday on or before January 1, and the commercial # year itself starts on this Monday, not January 1. # # For scientific purposes, it is convenient to refer to a date # simply as a day count, counting from an arbitrary initial # day. The date first chosen for this was January 1, 4713 BCE. # A count of days from this date is the *Julian* *Day* *Number* # or *Julian* *Date*, which is abbreviated as +jd+ in the # Date class. This is in local time, and counts from midnight # on the initial day. The stricter usage is in UTC, and counts # from midday on the initial day. This is referred to in the # Date class as the *Astronomical* *Julian* *Day* *Number*, and # abbreviated as +ajd+. In the Date class, the Astronomical # Julian Day Number includes fractional days. # # Another absolute day count is the *Modified* *Julian* *Day* # *Number*, which takes November 17, 1858 as its initial day. # This is abbreviated as +mjd+ in the Date class. There # is also an *Astronomical* *Modified* *Julian* *Day* *Number*, # which is in UTC and includes fractional days. This is # abbreviated as +amjd+ in the Date class. Like the Modified # Julian Day Number (and unlike the Astronomical Julian # Day Number), it counts from midnight. # # Alternative calendars such as the Chinese Lunar Calendar, # the Islamic Calendar, or the French Revolutionary Calendar # are not supported by the Date class; nor are calendars that # are based on an Era different from the Common Era, such as # the Japanese Imperial Calendar or the Republic of China # Calendar. # # === Calendar Reform # # The standard civil year is 365 days long. However, the # solar year is fractionally longer than this. To account # for this, a *leap* *year* is occasionally inserted. This # is a year with 366 days, the extra day falling on February 29. # In the early days of the civil calendar, every fourth # year without exception was a leap year. This way of # reckoning leap years is the *Julian* *Calendar*. # # However, the solar year is marginally shorter than 365 1/4 # days, and so the *Julian* *Calendar* gradually ran slow # over the centuries. To correct this, every 100th year # (but not every 400th year) was excluded as a leap year. # This way of reckoning leap years, which we use today, is # the *Gregorian* *Calendar*. # # The Gregorian Calendar was introduced at different times # in different regions. The day on which it was introduced # for a particular region is the *Day* *of* *Calendar* # *Reform* for that region. This is abbreviated as +sg+ # (for Start of Gregorian calendar) in the Date class. # # Two such days are of particular # significance. The first is October 15, 1582, which was # the Day of Calendar Reform for Italy and most Catholic # countries. The second is September 14, 1752, which was # the Day of Calendar Reform for England and its colonies # (including what is now the United States). These two # dates are available as the constants Date::ITALY and # Date::ENGLAND, respectively. (By comparison, Germany and # Holland, less Catholic than Italy but less stubborn than # England, changed over in 1698; Sweden in 1753; Russia not # till 1918, after the Revolution; and Greece in 1923. Many # Orthodox churches still use the Julian Calendar. A complete # list of Days of Calendar Reform can be found at # http://www.polysyllabic.com/GregConv.html.) # # Switching from the Julian to the Gregorian calendar # involved skipping a number of days to make up for the # accumulated lag, and the later the switch was (or is) # done, the more days need to be skipped. So in 1582 in Italy, # 4th October was followed by 15th October, skipping 10 days; in 1752 # in England, 2nd September was followed by 14th September, skipping # 11 days; and if I decided to switch from Julian to Gregorian # Calendar this midnight, I would go from 27th July 2003 (Julian) # today to 10th August 2003 (Gregorian) tomorrow, skipping # 13 days. The Date class is aware of this gap, and a supposed # date that would fall in the middle of it is regarded as invalid. # # The Day of Calendar Reform is relevant to all date representations # involving years. It is not relevant to the Julian Day Numbers, # except for converting between them and year-based representations. # # In the Date and DateTime classes, the Day of Calendar Reform or # +sg+ can be specified a number of ways. First, it can be as # the Julian Day Number of the Day of Calendar Reform. Second, # it can be using the constants Date::ITALY or Date::ENGLAND; these # are in fact the Julian Day Numbers of the Day of Calendar Reform # of the respective regions. Third, it can be as the constant # Date::JULIAN, which means to always use the Julian Calendar. # Finally, it can be as the constant Date::GREGORIAN, which means # to always use the Gregorian Calendar. # # Note: in the Julian Calendar, New Years Day was March 25. The # Date class does not follow this convention. # # === Time Zones # # DateTime objects support a simple representation # of time zones. Time zones are represented as an offset # from UTC, as a fraction of a day. This offset is the # how much local time is later (or earlier) than UTC. # UTC offset 0 is centred on England (also known as GMT). # As you travel east, the offset increases until you # reach the dateline in the middle of the Pacific Ocean; # as you travel west, the offset decreases. This offset # is abbreviated as +of+ in the Date class. # # This simple representation of time zones does not take # into account the common practice of Daylight Savings # Time or Summer Time. # # Most DateTime methods return the date and the # time in local time. The two exceptions are # #ajd() and #amjd(), which return the date and time # in UTC time, including fractional days. # # The Date class does not support time zone offsets, in that # there is no way to create a Date object with a time zone. # However, methods of the Date class when used by a # DateTime instance will use the time zone offset of this # instance. # # == Examples of use # # === Print out the date of every Sunday between two dates. # # def print_sundays(d1, d2) # d1 +=1 while (d1.wday != 0) # d1.step(d2, 7) do |date| # puts "#{Date::MONTHNAMES[date.mon]} #{date.day}" # end # end # # print_sundays(Date::civil(2003, 4, 8), Date::civil(2003, 5, 23)) # # === Calculate how many seconds to go till midnight on New Year's Day. # # def secs_to_new_year(now = DateTime::now()) # new_year = DateTime.new(now.year + 1, 1, 1) # dif = new_year - now # hours, mins, secs, ignore_fractions = Date::day_fraction_to_time(dif) # return hours * 60 * 60 + mins * 60 + secs # end # # puts secs_to_new_year() require 'rational' require 'date/format' # Class representing a date. # # See the documentation to the file date.rb for an overview. # # Internally, the date is represented as an Astronomical # Julian Day Number, +ajd+. The Day of Calendar Reform, +sg+, is # also stored, for conversions to other date formats. (There # is also an +of+ field for a time zone offset, but this # is only for the use of the DateTime subclass.) # # A new Date object is created using one of the object creation # class methods named after the corresponding date format, and the # arguments appropriate to that date format; for instance, # Date::civil() (aliased to Date::new()) with year, month, # and day-of-month, or Date::ordinal() with year and day-of-year. # All of these object creation class methods also take the # Day of Calendar Reform as an optional argument. # # Date objects are immutable once created. # # Once a Date has been created, date values # can be retrieved for the different date formats supported # using instance methods. For instance, #mon() gives the # Civil month, #cwday() gives the Commercial day of the week, # and #yday() gives the Ordinal day of the year. Date values # can be retrieved in any format, regardless of what format # was used to create the Date instance. # # The Date class includes the Comparable module, allowing # date objects to be compared and sorted, ranges of dates # to be created, and so forth. class Date include Comparable # Full month names, in English. Months count from 1 to 12; a # month's numerical representation indexed into this array # gives the name of that month (hence the first element is nil). MONTHNAMES = [nil] + %w(January February March April May June July August September October November December) # Full names of days of the week, in English. Days of the week # count from 0 to 6 (except in the commercial week); a day's numerical # representation indexed into this array gives the name of that day. DAYNAMES = %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday) # Abbreviated month names, in English. ABBR_MONTHNAMES = [nil] + %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) # Abbreviated day names, in English. ABBR_DAYNAMES = %w(Sun Mon Tue Wed Thu Fri Sat) [MONTHNAMES, DAYNAMES, ABBR_MONTHNAMES, ABBR_DAYNAMES].each do |xs| xs.each{|x| x.freeze unless x.nil?}.freeze end class Infinity < Numeric # :nodoc: include Comparable def initialize(d=1) @d = d <=> 0 end def d() @d end protected :d def zero? () false end def finite? () false end def infinite? () d.nonzero? end def nan? () d.zero? end def abs() self.class.new end def -@ () self.class.new(-d) end def +@ () self.class.new(+d) end def <=> (other) case other when Infinity; return d <=> other.d when Numeric; return d else begin l, r = other.coerce(self) return l <=> r rescue NoMethodError end end nil end def coerce(other) case other when Numeric; return -d, d else super end end end # The Julian Day Number of the Day of Calendar Reform for Italy # and the Catholic countries. ITALY = 2299161 # 1582-10-15 # The Julian Day Number of the Day of Calendar Reform for England # and her Colonies. ENGLAND = 2361222 # 1752-09-14 # A constant used to indicate that a Date should always use the # Julian calendar. JULIAN = Infinity.new # A constant used to indicate that a Date should always use the # Gregorian calendar. GREGORIAN = -Infinity.new HALF_DAYS_IN_DAY = Rational(1, 2) # :nodoc: HOURS_IN_DAY = Rational(1, 24) # :nodoc: MINUTES_IN_DAY = Rational(1, 1440) # :nodoc: SECONDS_IN_DAY = Rational(1, 86400) # :nodoc: MILLISECONDS_IN_DAY = Rational(1, 86400*10**3) # :nodoc: NANOSECONDS_IN_DAY = Rational(1, 86400*10**9) # :nodoc: MILLISECONDS_IN_SECOND = Rational(1, 10**3) # :nodoc: NANOSECONDS_IN_SECOND = Rational(1, 10**9) # :nodoc: MJD_EPOCH_IN_AJD = Rational(4800001, 2) # 1858-11-17 # :nodoc: UNIX_EPOCH_IN_AJD = Rational(4881175, 2) # 1970-01-01 # :nodoc: MJD_EPOCH_IN_CJD = 2400001 # :nodoc: UNIX_EPOCH_IN_CJD = 2440588 # :nodoc: LD_EPOCH_IN_CJD = 2299160 # :nodoc: # Does a given Julian Day Number fall inside the old-style (Julian) # calendar? # # +jd+ is the Julian Day Number in question. +sg+ may be Date::GREGORIAN, # in which case the answer is false; it may be Date::JULIAN, in which case # the answer is true; or it may a number representing the Day of # Calendar Reform. Date::ENGLAND and Date::ITALY are two possible such # days. def self.julian? (jd, sg) case sg when Numeric jd < sg else if $VERBOSE warn("#{caller.shift.sub(/:in .*/, '')}: " \ "warning: do not use non-numerical object as julian day number anymore") end not sg end end # Does a given Julian Day Number fall inside the new-style (Gregorian) # calendar? # # The reverse of self.os? See the documentation for that method for # more details. def self.gregorian? (jd, sg) !julian?(jd, sg) end def self.fix_style(jd, sg) # :nodoc: if julian?(jd, sg) then JULIAN else GREGORIAN end end private_class_method :fix_style # Convert an Ordinal Date to a Julian Day Number. # # +y+ and +d+ are the year and day-of-year to convert. # +sg+ specifies the Day of Calendar Reform. # # Returns the corresponding Julian Day Number. def self.ordinal_to_jd(y, d, sg=GREGORIAN) civil_to_jd(y, 1, d, sg) end # Convert a Julian Day Number to an Ordinal Date. # # +jd+ is the Julian Day Number to convert. # +sg+ specifies the Day of Calendar Reform. # # Returns the corresponding Ordinal Date as # [year, day_of_year] def self.jd_to_ordinal(jd, sg=GREGORIAN) y = jd_to_civil(jd, sg)[0] doy = jd - civil_to_jd(y - 1, 12, 31, fix_style(jd, sg)) return y, doy end # Convert a Civil Date to a Julian Day Number. # +y+, +m+, and +d+ are the year, month, and day of the # month. +sg+ specifies the Day of Calendar Reform. # # Returns the corresponding Julian Day Number. def self.civil_to_jd(y, m, d, sg=GREGORIAN) if m <= 2 y -= 1 m += 12 end a = (y / 100.0).floor b = 2 - a + (a / 4.0).floor jd = (365.25 * (y + 4716)).floor + (30.6001 * (m + 1)).floor + d + b - 1524 if julian?(jd, sg) jd -= b end jd end # Convert a Julian Day Number to a Civil Date. +jd+ is # the Julian Day Number. +sg+ specifies the Day of # Calendar Reform. # # Returns the corresponding [year, month, day_of_month] # as a three-element array. def self.jd_to_civil(jd, sg=GREGORIAN) if julian?(jd, sg) a = jd else x = ((jd - 1867216.25) / 36524.25).floor a = jd + 1 + x - (x / 4.0).floor end b = a + 1524 c = ((b - 122.1) / 365.25).floor d = (365.25 * c).floor e = ((b - d) / 30.6001).floor dom = b - d - (30.6001 * e).floor if e <= 13 m = e - 1 y = c - 4716 else m = e - 13 y = c - 4715 end return y, m, dom end # Convert a Commercial Date to a Julian Day Number. # # +y+, +w+, and +d+ are the (commercial) year, week of the year, # and day of the week of the Commercial Date to convert. # +sg+ specifies the Day of Calendar Reform. def self.commercial_to_jd(y, w, d, ns=GREGORIAN) jd = civil_to_jd(y, 1, 4, ns) (jd - (((jd - 1) + 1) % 7)) + 7 * (w - 1) + (d - 1) end # Convert a Julian Day Number to a Commercial Date # # +jd+ is the Julian Day Number to convert. # +sg+ specifies the Day of Calendar Reform. # # Returns the corresponding Commercial Date as # [commercial_year, week_of_year, day_of_week] def self.jd_to_commercial(jd, sg=GREGORIAN) ns = fix_style(jd, sg) a = jd_to_civil(jd - 3, ns)[0] y = if jd >= commercial_to_jd(a + 1, 1, 1, ns) then a + 1 else a end w = 1 + ((jd - commercial_to_jd(y, 1, 1, ns)) / 7).floor d = (jd + 1) % 7 d = 7 if d == 0 return y, w, d end def self.weeknum_to_jd(y, w, d, f=0, ns=GREGORIAN) # :nodoc: a = civil_to_jd(y, 1, 1, ns) + 6 (a - ((a - f) + 1) % 7 - 7) + 7 * w + d end def self.jd_to_weeknum(jd, f=0, sg=GREGORIAN) # :nodoc: ns = fix_style(jd, sg) y, m, d = jd_to_civil(jd, ns) a = civil_to_jd(y, 1, 1, ns) + 6 w, d = (jd - (a - ((a - f) + 1) % 7) + 7).divmod(7) return y, w, d end private_class_method :weeknum_to_jd, :jd_to_weeknum # Convert an Astronomical Julian Day Number to a (civil) Julian # Day Number. # # +ajd+ is the Astronomical Julian Day Number to convert. # +of+ is the offset from UTC as a fraction of a day (defaults to 0). # # Returns the (civil) Julian Day Number as [day_number, # fraction] where +fraction+ is always 1/2. def self.ajd_to_jd(ajd, of=0) (ajd + of + HALF_DAYS_IN_DAY).divmod(1) end # Convert a (civil) Julian Day Number to an Astronomical Julian # Day Number. # # +jd+ is the Julian Day Number to convert, and +fr+ is a # fractional day. # +of+ is the offset from UTC as a fraction of a day (defaults to 0). # # Returns the Astronomical Julian Day Number as a single # numeric value. def self.jd_to_ajd(jd, fr, of=0) jd + fr - of - HALF_DAYS_IN_DAY end # Convert a fractional day +fr+ to [hours, minutes, seconds, # fraction_of_a_second] def self.day_fraction_to_time(fr) ss, fr = fr.divmod(SECONDS_IN_DAY) # 4p h, ss = ss.divmod(3600) min, s = ss.divmod(60) return h, min, s, fr end # Convert an +h+ hour, +min+ minutes, +s+ seconds period # to a fractional day. begin Rational(Rational(1, 2), 2) # a challenge def self.time_to_day_fraction(h, min, s) Rational(h * 3600 + min * 60 + s, 86400) # 4p end rescue def self.time_to_day_fraction(h, min, s) if Integer === h && Integer === min && Integer === s Rational(h * 3600 + min * 60 + s, 86400) # 4p else (h * 3600 + min * 60 + s).to_r/86400 # 4p end end end # Convert an Astronomical Modified Julian Day Number to an # Astronomical Julian Day Number. def self.amjd_to_ajd(amjd) amjd + MJD_EPOCH_IN_AJD end # Convert an Astronomical Julian Day Number to an # Astronomical Modified Julian Day Number. def self.ajd_to_amjd(ajd) ajd - MJD_EPOCH_IN_AJD end # Convert a Modified Julian Day Number to a Julian # Day Number. def self.mjd_to_jd(mjd) mjd + MJD_EPOCH_IN_CJD end # Convert a Julian Day Number to a Modified Julian Day # Number. def self.jd_to_mjd(jd) jd - MJD_EPOCH_IN_CJD end # Convert a count of the number of days since the adoption # of the Gregorian Calendar (in Italy) to a Julian Day Number. def self.ld_to_jd(ld) ld + LD_EPOCH_IN_CJD end # Convert a Julian Day Number to the number of days since # the adoption of the Gregorian Calendar (in Italy). def self.jd_to_ld(jd) jd - LD_EPOCH_IN_CJD end # Convert a Julian Day Number to the day of the week. # # Sunday is day-of-week 0; Saturday is day-of-week 6. def self.jd_to_wday(jd) (jd + 1) % 7 end # Is a year a leap year in the Julian calendar? # # All years divisible by 4 are leap years in the Julian calendar. def self.julian_leap? (y) y % 4 == 0 end # Is a year a leap year in the Gregorian calendar? # # All years divisible by 4 are leap years in the Gregorian calendar, # except for years divisible by 100 and not by 400. def self.gregorian_leap? (y) y % 4 == 0 && y % 100 != 0 || y % 400 == 0 end class << self; alias_method :leap?, :gregorian_leap? end class << self; alias_method :new!, :new end # Is +jd+ a valid Julian Day Number? # # If it is, returns it. In fact, any value is treated as a valid # Julian Day Number. def self.valid_jd? (jd, sg=ITALY) jd end # Do the year +y+ and day-of-year +d+ make a valid Ordinal Date? # Returns the corresponding Julian Day Number if they do, or # nil if they don't. # # +d+ can be a negative number, in which case it counts backwards # from the end of the year (-1 being the last day of the year). # No year wraparound is performed, however, so valid values of # +d+ are -365 .. -1, 1 .. 365 on a non-leap-year, # -366 .. -1, 1 .. 366 on a leap year. # A date falling in the period skipped in the Day of Calendar Reform # adjustment is not valid. # # +sg+ specifies the Day of Calendar Reform. def self.valid_ordinal? (y, d, sg=ITALY) if d < 0 ny, = (y + 1).divmod(1) jd = ordinal_to_jd(ny, d + 1, sg) ns = fix_style(jd, sg) return unless [y] == jd_to_ordinal(jd, sg)[0..0] return unless [ny, 1] == jd_to_ordinal(jd - d, ns) else jd = ordinal_to_jd(y, d, sg) return unless [y, d] == jd_to_ordinal(jd, sg) end jd end # Do year +y+, month +m+, and day-of-month +d+ make a # valid Civil Date? Returns the corresponding Julian # Day Number if they do, nil if they don't. # # +m+ and +d+ can be negative, in which case they count # backwards from the end of the year and the end of the # month respectively. No wraparound is performed, however, # and invalid values cause an ArgumentError to be raised. # A date falling in the period skipped in the Day of Calendar # Reform adjustment is not valid. # # +sg+ specifies the Day of Calendar Reform. def self.valid_civil? (y, m, d, sg=ITALY) if m < 0 m += 13 end if d < 0 ny, nm = (y * 12 + m).divmod(12) nm, = (nm + 1).divmod(1) jd = civil_to_jd(ny, nm, d + 1, sg) ns = fix_style(jd, sg) return unless [y, m] == jd_to_civil(jd, sg)[0..1] return unless [ny, nm, 1] == jd_to_civil(jd - d, ns) else jd = civil_to_jd(y, m, d, sg) return unless [y, m, d] == jd_to_civil(jd, sg) end jd end class << self; alias_method :valid_date?, :valid_civil? end # Do year +y+, week-of-year +w+, and day-of-week +d+ make a # valid Commercial Date? Returns the corresponding Julian # Day Number if they do, nil if they don't. # # Monday is day-of-week 1; Sunday is day-of-week 7. # # +w+ and +d+ can be negative, in which case they count # backwards from the end of the year and the end of the # week respectively. No wraparound is performed, however, # and invalid values cause an ArgumentError to be raised. # A date falling in the period skipped in the Day of Calendar # Reform adjustment is not valid. # # +sg+ specifies the Day of Calendar Reform. def self.valid_commercial? (y, w, d, sg=ITALY) if d < 0 d += 8 end if w < 0 ny, nw, nd = jd_to_commercial(commercial_to_jd(y + 1, 1, 1) + w * 7) return unless ny == y w = nw end jd = commercial_to_jd(y, w, d) return unless gregorian?(jd, sg) return unless [y, w, d] == jd_to_commercial(jd) jd end def self.valid_weeknum? (y, w, d, f, sg=ITALY) # :nodoc: if d < 0 d += 7 end if w < 0 ny, nw, nd, nf = jd_to_weeknum(weeknum_to_jd(y + 1, 1, f, f) + w * 7, f) return unless ny == y w = nw end jd = weeknum_to_jd(y, w, d, f) return unless gregorian?(jd, sg) return unless [y, w, d] == jd_to_weeknum(jd, f) jd end private_class_method :valid_weeknum? # Do hour +h+, minute +min+, and second +s+ constitute a valid time? # # If they do, returns their value as a fraction of a day. If not, # returns nil. # # The 24-hour clock is used. Negative values of +h+, +min+, and # +sec+ are treating as counting backwards from the end of the # next larger unit (e.g. a +min+ of -2 is treated as 58). No # wraparound is performed. def self.valid_time? (h, min, s) h += 24 if h < 0 min += 60 if min < 0 s += 60 if s < 0 return unless ((0...24) === h && (0...60) === min && (0...60) === s) || (24 == h && 0 == min && 0 == s) time_to_day_fraction(h, min, s) end # Create a new Date object from a Julian Day Number. # # +jd+ is the Julian Day Number; if not specified, it defaults to # 0. # +sg+ specifies the Day of Calendar Reform. def self.jd(jd=0, sg=ITALY) jd = valid_jd?(jd, sg) new!(jd_to_ajd(jd, 0, 0), 0, sg) end # Create a new Date object from an Ordinal Date, specified # by year +y+ and day-of-year +d+. +d+ can be negative, # in which it counts backwards from the end of the year. # No year wraparound is performed, however. An invalid # value for +d+ results in an ArgumentError being raised. # # +y+ defaults to -4712, and +d+ to 1; this is Julian Day # Number day 0. # # +sg+ specifies the Day of Calendar Reform. def self.ordinal(y=-4712, d=1, sg=ITALY) unless jd = valid_ordinal?(y, d, sg) raise ArgumentError, 'invalid date' end new!(jd_to_ajd(jd, 0, 0), 0, sg) end # Create a new Date object for the Civil Date specified by # year +y+, month +m+, and day-of-month +d+. # # +m+ and +d+ can be negative, in which case they count # backwards from the end of the year and the end of the # month respectively. No wraparound is performed, however, # and invalid values cause an ArgumentError to be raised. # can be negative # # +y+ defaults to -4712, +m+ to 1, and +d+ to 1; this is # Julian Day Number day 0. # # +sg+ specifies the Day of Calendar Reform. def self.civil(y=-4712, m=1, d=1, sg=ITALY) unless jd = valid_civil?(y, m, d, sg) raise ArgumentError, 'invalid date' end new!(jd_to_ajd(jd, 0, 0), 0, sg) end class << self; alias_method :new, :civil end # Create a new Date object for the Commercial Date specified by # year +y+, week-of-year +w+, and day-of-week +d+. # # Monday is day-of-week 1; Sunday is day-of-week 7. # # +w+ and +d+ can be negative, in which case they count # backwards from the end of the year and the end of the # week respectively. No wraparound is performed, however, # and invalid values cause an ArgumentError to be raised. # # +y+ defaults to 1582, +w+ to 41, and +d+ to 5, the Day of # Calendar Reform for Italy and the Catholic countries. # # +sg+ specifies the Day of Calendar Reform. def self.commercial(y=1582, w=41, d=5, sg=ITALY) unless jd = valid_commercial?(y, w, d, sg) raise ArgumentError, 'invalid date' end new!(jd_to_ajd(jd, 0, 0), 0, sg) end def self.weeknum(y=1582, w=41, d=5, f=0, sg=ITALY) # :nodoc: unless jd = valid_weeknum?(y, w, d, f, sg) raise ArgumentError, 'invalid date' end new!(jd_to_ajd(jd, 0, 0), 0, sg) end private_class_method :weeknum def self.rewrite_frags(elem) # :nodoc: elem ||= {} if seconds = elem[:seconds] d, fr = seconds.divmod(86400) h, fr = fr.divmod(3600) min, fr = fr.divmod(60) s, fr = fr.divmod(1) elem[:jd] = UNIX_EPOCH_IN_CJD + d elem[:hour] = h elem[:min] = min elem[:sec] = s elem[:sec_fraction] = fr elem.delete(:seconds) elem.delete(:offset) end elem end private_class_method :rewrite_frags def self.complete_frags(elem) # :nodoc: i = 0 g = [[:time, [:hour, :min, :sec]], [nil, [:jd]], [:ordinal, [:year, :yday, :hour, :min, :sec]], [:civil, [:year, :mon, :mday, :hour, :min, :sec]], [:commercial, [:cwyear, :cweek, :cwday, :hour, :min, :sec]], [:wday, [:wday, :hour, :min, :sec]], [:wnum0, [:year, :wnum0, :wday, :hour, :min, :sec]], [:wnum1, [:year, :wnum1, :wday, :hour, :min, :sec]], [nil, [:cwyear, :cweek, :wday, :hour, :min, :sec]], [nil, [:year, :wnum0, :cwday, :hour, :min, :sec]], [nil, [:year, :wnum1, :cwday, :hour, :min, :sec]]]. collect{|k, a| e = elem.values_at(*a).compact; [k, a, e]}. select{|k, a, e| e.size > 0}. sort_by{|k, a, e| [e.size, i -= 1]}.last d = nil if g && g[0] && (g[1].size - g[2].size) != 0 d ||= Date.today case g[0] when :ordinal elem[:year] ||= d.year elem[:yday] ||= 1 when :civil g[1].each do |e| break if elem[e] elem[e] = d.__send__(e) end elem[:mon] ||= 1 elem[:mday] ||= 1 when :commercial g[1].each do |e| break if elem[e] elem[e] = d.__send__(e) end elem[:cweek] ||= 1 elem[:cwday] ||= 1 when :wday elem[:jd] ||= (d - d.wday + elem[:wday]).jd when :wnum0 g[1].each do |e| break if elem[e] elem[e] = d.__send__(e) end elem[:wnum0] ||= 0 elem[:wday] ||= 0 when :wnum1 g[1].each do |e| break if elem[e] elem[e] = d.__send__(e) end elem[:wnum1] ||= 0 elem[:wday] ||= 0 end end if g && g[0] == :time if self <= DateTime d ||= Date.today elem[:jd] ||= d.jd end end elem[:hour] ||= 0 elem[:min] ||= 0 elem[:sec] ||= 0 elem[:sec] = [elem[:sec], 59].min elem end private_class_method :complete_frags def self.valid_date_frags?(elem, sg) # :nodoc: catch :jd do a = elem.values_at(:jd) if a.all? if jd = valid_jd?(*(a << sg)) throw :jd, jd end end a = elem.values_at(:year, :yday) if a.all? if jd = valid_ordinal?(*(a << sg)) throw :jd, jd end end a = elem.values_at(:year, :mon, :mday) if a.all? if jd = valid_civil?(*(a << sg)) throw :jd, jd end end a = elem.values_at(:cwyear, :cweek, :cwday) if a[2].nil? && elem[:wday] a[2] = elem[:wday].nonzero? || 7 end if a.all? if jd = valid_commercial?(*(a << sg)) throw :jd, jd end end a = elem.values_at(:year, :wnum0, :wday) if a[2].nil? && elem[:cwday] a[2] = elem[:cwday] % 7 end if a.all? if jd = valid_weeknum?(*(a << 0 << sg)) throw :jd, jd end end a = elem.values_at(:year, :wnum1, :wday) if a[2] a[2] = (a[2] - 1) % 7 end if a[2].nil? && elem[:cwday] a[2] = (elem[:cwday] - 1) % 7 end if a.all? if jd = valid_weeknum?(*(a << 1 << sg)) throw :jd, jd end end end end private_class_method :valid_date_frags? def self.valid_time_frags? (elem) # :nodoc: h, min, s = elem.values_at(:hour, :min, :sec) valid_time?(h, min, s) end private_class_method :valid_time_frags? def self.new_by_frags(elem, sg) # :nodoc: elem = rewrite_frags(elem) elem = complete_frags(elem) unless jd = valid_date_frags?(elem, sg) raise ArgumentError, 'invalid date' end new!(jd_to_ajd(jd, 0, 0), 0, sg) end private_class_method :new_by_frags # Create a new Date object by parsing from a String # according to a specified format. # # +str+ is a String holding a date representation. # +fmt+ is the format that the date is in. See # date/format.rb for details on supported formats. # # The default +str+ is '-4712-01-01', and the default # +fmt+ is '%F', which means Year-Month-Day_of_Month. # This gives Julian Day Number day 0. # # +sg+ specifies the Day of Calendar Reform. # # An ArgumentError will be raised if +str+ cannot be # parsed. def self.strptime(str='-4712-01-01', fmt='%F', sg=ITALY) elem = _strptime(str, fmt) new_by_frags(elem, sg) end # Create a new Date object by parsing from a String, # without specifying the format. # # +str+ is a String holding a date representation. # +comp+ specifies whether to interpret 2-digit years # as 19XX (>= 69) or 20XX (< 69); the default is not to. # The method will attempt to parse a date from the String # using various heuristics; see #_parse in date/format.rb # for more details. If parsing fails, an ArgumentError # will be raised. # # The default +str+ is '-4712-01-01'; this is Julian # Day Number day 0. # # +sg+ specifies the Day of Calendar Reform. def self.parse(str='-4712-01-01', comp=false, sg=ITALY) elem = _parse(str, comp) new_by_frags(elem, sg) end class << self def once(*ids) # :nodoc: for id in ids module_eval <<-"end;" alias_method :__#{id.to_i}__, :#{id.to_s} private :__#{id.to_i}__ def #{id.to_s}(*args, &block) (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0] end end; end end private :once end # *NOTE* this is the documentation for the method new!(). If # you are reading this as the documentation for new(), that is # because rdoc doesn't fully support the aliasing of the # initialize() method. # new() is in # fact an alias for #civil(): read the documentation for that # method instead. # # Create a new Date object. # # +ajd+ is the Astronomical Julian Day Number. # +of+ is the offset from UTC as a fraction of a day. # Both default to 0. # # +sg+ specifies the Day of Calendar Reform to use for this # Date object. # # Using one of the factory methods such as Date::civil is # generally easier and safer. def initialize(ajd=0, of=0, sg=ITALY) @ajd, @of, @sg = ajd, of, sg end # Get the date as an Astronomical Julian Day Number. def ajd() @ajd end # Get the date as an Astronomical Modified Julian Day Number. def amjd() self.class.ajd_to_amjd(@ajd) end once :amjd # Get the date as a Julian Day Number. def jd() self.class.ajd_to_jd(@ajd, @of)[0] end # Get any fractional day part of the date. def day_fraction() self.class.ajd_to_jd(@ajd, @of)[1] end # Get the date as a Modified Julian Day Number. def mjd() self.class.jd_to_mjd(jd) end # Get the date as the number of days since the Day of Calendar # Reform (in Italy and the Catholic countries). def ld() self.class.jd_to_ld(jd) end once :jd, :day_fraction, :mjd, :ld # Get the date as a Civil Date, [year, month, day_of_month] def civil() self.class.jd_to_civil(jd, @sg) end # :nodoc: # Get the date as an Ordinal Date, [year, day_of_year] def ordinal() self.class.jd_to_ordinal(jd, @sg) end # :nodoc: # Get the date as a Commercial Date, [year, week_of_year, day_of_week] def commercial() self.class.jd_to_commercial(jd, @sg) end # :nodoc: def weeknum0() self.class.__send__(:jd_to_weeknum, jd, 0, @sg) end # :nodoc: def weeknum1() self.class.__send__(:jd_to_weeknum, jd, 1, @sg) end # :nodoc: once :civil, :ordinal, :commercial, :weeknum0, :weeknum1 private :civil, :ordinal, :commercial, :weeknum0, :weeknum1 # Get the year of this date. def year() civil[0] end # Get the day-of-the-year of this date. # # January 1 is day-of-the-year 1 def yday() ordinal[1] end # Get the month of this date. # # January is month 1. def mon() civil[1] end # Get the day-of-the-month of this date. def mday() civil[2] end alias_method :month, :mon alias_method :day, :mday def wnum0() weeknum0[1] end # :nodoc: def wnum1() weeknum1[1] end # :nodoc: private :wnum0, :wnum1 # Get the time of this date as [hours, minutes, seconds, # fraction_of_a_second] def time() self.class.day_fraction_to_time(day_fraction) end # :nodoc: once :time private :time # Get the hour of this date. def hour() time[0] end # Get the minute of this date. def min() time[1] end # Get the second of this date. def sec() time[2] end # Get the fraction-of-a-second of this date. The unit is in days. # I do NOT recommend you to use this method. def sec_fraction() time[3] end =begin alias_method :minute, :min alias_method :second, :sec alias_method :second_fraction, :sec_fraction =end private :hour, :min, :sec, :sec_fraction # :minute, :second, :second_fraction def zone() strftime('%:z') end private :zone # Get the commercial year of this date. See *Commercial* *Date* # in the introduction for how this differs from the normal year. def cwyear() commercial[0] end # Get the commercial week of the year of this date. def cweek() commercial[1] end # Get the commercial day of the week of this date. Monday is # commercial day-of-week 1; Sunday is commercial day-of-week 7. def cwday() commercial[2] end # Get the week day of this date. Sunday is day-of-week 0; # Saturday is day-of-week 6. def wday() self.class.jd_to_wday(jd) end once :wday =begin MONTHNAMES.each_with_index do |n, i| if n define_method(n.downcase + '?'){mon == i} end end DAYNAMES.each_with_index do |n, i| define_method(n.downcase + '?'){wday == i} end =end # Is the current date old-style (Julian Calendar)? def julian? () self.class.julian?(jd, @sg) end # Is the current date new-style (Gregorian Calendar)? def gregorian? () self.class.gregorian?(jd, @sg) end once :julian?, :gregorian? def fix_style # :nodoc: if julian? then self.class::JULIAN else self.class::GREGORIAN end end private :fix_style # Is this a leap year? def leap? self.class.jd_to_civil(self.class.civil_to_jd(year, 3, 1, fix_style) - 1, fix_style)[-1] == 29 end once :leap? # When is the Day of Calendar Reform for this Date object? def start() @sg end # Create a copy of this Date object using a new Day of Calendar Reform. def new_start(sg=self.class::ITALY) self.class.new!(@ajd, @of, sg) end # Create a copy of this Date object that uses the Italian/Catholic # Day of Calendar Reform. def italy() new_start(self.class::ITALY) end # Create a copy of this Date object that uses the English/Colonial # Day of Calendar Reform. def england() new_start(self.class::ENGLAND) end # Create a copy of this Date object that always uses the Julian # Calendar. def julian() new_start(self.class::JULIAN) end # Create a copy of this Date object that always uses the Gregorian # Calendar. def gregorian() new_start(self.class::GREGORIAN) end def offset() @of end def new_offset(of=0) if String === of of = Rational(zone_to_diff(of) || 0, 86400) end self.class.new!(@ajd, of, @sg) end private :offset, :new_offset # Return a new Date object that is +n+ days later than the # current one. # # +n+ may be a negative value, in which case the new Date # is earlier than the current one; however, #-() might be # more intuitive. # # If +n+ is not a Numeric, a TypeError will be thrown. In # particular, two Dates cannot be added to each other. def + (n) case n when Numeric; return self.class.new!(@ajd + n, @of, @sg) end raise TypeError, 'expected numeric' end # If +x+ is a Numeric value, create a new Date object that is # +x+ days earlier than the current one. # # If +x+ is a Date, return the number of days between the # two dates; or, more precisely, how many days later the current # date is than +x+. # # If +x+ is neither Numeric nor a Date, a TypeError is raised. def - (x) case x when Numeric; return self.class.new!(@ajd - x, @of, @sg) when Date; return @ajd - x.ajd end raise TypeError, 'expected numeric or date' end # Compare this date with another date. # # +other+ can also be a Numeric value, in which case it is # interpreted as an Astronomical Julian Day Number. # # Comparison is by Astronomical Julian Day Number, including # fractional days. This means that both the time and the # timezone offset are taken into account when comparing # two DateTime instances. When comparing a DateTime instance # with a Date instance, the time of the latter will be # considered as falling on midnight UTC. def <=> (other) case other when Numeric; return @ajd <=> other when Date; return @ajd <=> other.ajd end nil end # The relationship operator for Date. # # Compares dates by Julian Day Number. When comparing # two DateTime instances, or a DateTime with a Date, # the instances will be regarded as equivalent if they # fall on the same date in local time. def === (other) case other when Numeric; return jd == other when Date; return jd == other.jd end false end def next_day(n=1) self + n end # def prev_day(n=1) self - n end private :next_day # Return a new Date one day after this one. def next() next_day end alias_method :succ, :next # Return a new Date object that is +n+ months later than # the current one. # # If the day-of-the-month of the current Date is greater # than the last day of the target month, the day-of-the-month # of the returned Date will be the last day of the target month. def >> (n) y, m = (year * 12 + (mon - 1) + n).divmod(12) m, = (m + 1) .divmod(1) d = mday until jd2 = self.class.valid_civil?(y, m, d, fix_style) d -= 1 raise ArgumentError, 'invalid date' unless d > 0 end self + (jd2 - jd) end # Return a new Date object that is +n+ months earlier than # the current one. # # If the day-of-the-month of the current Date is greater # than the last day of the target month, the day-of-the-month # of the returned Date will be the last day of the target month. def << (n) self >> -n end =begin def next_month(n=1) self >> n end def prev_month(n=1) self << n end def next_year(n=1) self >> n * 12 end def prev_year(n=1) self << n * 12 end =end # require 'enumerator' # Step the current date forward +step+ days at a # time (or backward, if +step+ is negative) until # we reach +limit+ (inclusive), yielding the resultant # date at each step. def step(limit, step=1) # :yield: date =begin if step.zero? raise ArgumentError, "step can't be 0" end =end =begin unless block_given? return to_enum(:step, limit, step) end =end da = self op = %w(- <= >=)[step <=> 0] while da.__send__(op, limit) yield da da += step end self end # Step forward one day at a time until we reach +max+ # (inclusive), yielding each date as we go. def upto(max, &block) # :yield: date step(max, +1, &block) end # Step backward one day at a time until we reach +min+ # (inclusive), yielding each date as we go. def downto(min, &block) # :yield: date step(min, -1, &block) end # Is this Date equal to +other+? # # +other+ must both be a Date object, and represent the same date. def eql? (other) Date === other && self == other end # Calculate a hash value for this date. def hash() @ajd.hash end # Return internal object state as a programmer-readable string. def inspect() format('#<%s: %s,%s,%s>', self.class, @ajd, @of, @sg) end # Return the date as a human-readable string. # # The format used is YYYY-MM-DD. def to_s() format('%.4d-%02d-%02d', year, mon, mday) end # 4p # Dump to Marshal format. def _dump(limit) Marshal.dump([@ajd, @of, @sg], -1) end # def self._load(str) new!(*Marshal.load(str)) end # Load from Marshal format. def self._load(str) a = Marshal.load(str) if a.size == 2 ajd, sg = a of = 0 ajd -= 1.to_r/2 else ajd, of, sg = a end new!(ajd, of, sg) end end # Class representing a date and time. # # See the documentation to the file date.rb for an overview. # # DateTime objects are immutable once created. # # == Other methods. # # The following methods are defined in Date, but declared private # there. They are made public in DateTime. They are documented # here. # # === hour() # # Get the hour-of-the-day of the time. This is given # using the 24-hour clock, counting from midnight. The first # hour after midnight is hour 0; the last hour of the day is # hour 23. # # === min() # # Get the minute-of-the-hour of the time. # # === sec() # # Get the second-of-the-minute of the time. # # === sec_fraction() # # Get the fraction of a second of the time. This is returned as # a +Rational+. The unit is in days. # I do NOT recommend you to use this method. # # === zone() # # Get the time zone as a String. This is representation of the # time offset such as "+1000", not the true time-zone name. # # === offset() # # Get the time zone offset as a fraction of a day. This is returned # as a +Rational+. # # === new_offset(of=0) # # Create a new DateTime object, identical to the current one, except # with a new time zone offset of +of+. +of+ is the new offset from # UTC as a fraction of a day. # class DateTime < Date # Create a new DateTime object corresponding to the specified # Julian Day Number +jd+ and hour +h+, minute +min+, second +s+. # # The 24-hour clock is used. Negative values of +h+, +min+, and # +sec+ are treating as counting backwards from the end of the # next larger unit (e.g. a +min+ of -2 is treated as 58). No # wraparound is performed. If an invalid time portion is specified, # an ArgumentError is raised. # # +of+ is the offset from UTC as a fraction of a day (defaults to 0). # +sg+ specifies the Day of Calendar Reform. # # All day/time values default to 0. def self.jd(jd=0, h=0, min=0, s=0, of=0, sg=ITALY) unless (jd = valid_jd?(jd, sg)) && (fr = valid_time?(h, min, s)) raise ArgumentError, 'invalid date' end if String === of of = Rational(zone_to_diff(of) || 0, 86400) end new!(jd_to_ajd(jd, fr, of), of, sg) end # Create a new DateTime object corresponding to the specified # Ordinal Date and hour +h+, minute +min+, second +s+. # # The 24-hour clock is used. Negative values of +h+, +min+, and # +sec+ are treating as counting backwards from the end of the # next larger unit (e.g. a +min+ of -2 is treated as 58). No # wraparound is performed. If an invalid time portion is specified, # an ArgumentError is raised. # # +of+ is the offset from UTC as a fraction of a day (defaults to 0). # +sg+ specifies the Day of Calendar Reform. # # +y+ defaults to -4712, and +d+ to 1; this is Julian Day Number # day 0. The time values default to 0. def self.ordinal(y=-4712, d=1, h=0, min=0, s=0, of=0, sg=ITALY) unless (jd = valid_ordinal?(y, d, sg)) && (fr = valid_time?(h, min, s)) raise ArgumentError, 'invalid date' end if String === of of = Rational(zone_to_diff(of) || 0, 86400) end new!(jd_to_ajd(jd, fr, of), of, sg) end # Create a new DateTime object corresponding to the specified # Civil Date and hour +h+, minute +min+, second +s+. # # The 24-hour clock is used. Negative values of +h+, +min+, and # +sec+ are treating as counting backwards from the end of the # next larger unit (e.g. a +min+ of -2 is treated as 58). No # wraparound is performed. If an invalid time portion is specified, # an ArgumentError is raised. # # +of+ is the offset from UTC as a fraction of a day (defaults to 0). # +sg+ specifies the Day of Calendar Reform. # # +y+ defaults to -4712, +m+ to 1, and +d+ to 1; this is Julian Day # Number day 0. The time values default to 0. def self.civil(y=-4712, m=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY) unless (jd = valid_civil?(y, m, d, sg)) && (fr = valid_time?(h, min, s)) raise ArgumentError, 'invalid date' end if String === of of = Rational(zone_to_diff(of) || 0, 86400) end new!(jd_to_ajd(jd, fr, of), of, sg) end class << self; alias_method :new, :civil end # Create a new DateTime object corresponding to the specified # Commercial Date and hour +h+, minute +min+, second +s+. # # The 24-hour clock is used. Negative values of +h+, +min+, and # +sec+ are treating as counting backwards from the end of the # next larger unit (e.g. a +min+ of -2 is treated as 58). No # wraparound is performed. If an invalid time portion is specified, # an ArgumentError is raised. # # +of+ is the offset from UTC as a fraction of a day (defaults to 0). # +sg+ specifies the Day of Calendar Reform. # # +y+ defaults to 1582, +w+ to 41, and +d+ to 5; this is the Day of # Calendar Reform for Italy and the Catholic countries. # The time values default to 0. def self.commercial(y=1582, w=41, d=5, h=0, min=0, s=0, of=0, sg=ITALY) unless (jd = valid_commercial?(y, w, d, sg)) && (fr = valid_time?(h, min, s)) raise ArgumentError, 'invalid date' end if String === of of = Rational(zone_to_diff(of) || 0, 86400) end new!(jd_to_ajd(jd, fr, of), of, sg) end def self.weeknum(y=1582, w=41, d=5, f=0, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc: unless (jd = valid_weeknum?(y, w, d, f, sg)) && (fr = valid_time?(h, min, s)) raise ArgumentError, 'invalid date' end if String === of of = Rational(zone_to_diff(of) || 0, 86400) end new!(jd_to_ajd(jd, fr, of), of, sg) end private_class_method :weeknum def self.new_by_frags(elem, sg) # :nodoc: elem = rewrite_frags(elem) elem = complete_frags(elem) unless (jd = valid_date_frags?(elem, sg)) && (fr = valid_time_frags?(elem)) raise ArgumentError, 'invalid date' end fr += (elem[:sec_fraction] || 0) / 86400 of = Rational(elem[:offset] || 0, 86400) new!(jd_to_ajd(jd, fr, of), of, sg) end private_class_method :new_by_frags # Create a new DateTime object by parsing from a String # according to a specified format. # # +str+ is a String holding a date-time representation. # +fmt+ is the format that the date-time is in. See # date/format.rb for details on supported formats. # # The default +str+ is '-4712-01-01T00:00:00+00:00', and the default # +fmt+ is '%FT%T%z'. This gives midnight on Julian Day Number day 0. # # +sg+ specifies the Day of Calendar Reform. # # An ArgumentError will be raised if +str+ cannot be # parsed. def self.strptime(str='-4712-01-01T00:00:00+00:00', fmt='%FT%T%z', sg=ITALY) elem = _strptime(str, fmt) new_by_frags(elem, sg) end # Create a new DateTime object by parsing from a String, # without specifying the format. # # +str+ is a String holding a date-time representation. # +comp+ specifies whether to interpret 2-digit years # as 19XX (>= 69) or 20XX (< 69); the default is not to. # The method will attempt to parse a date-time from the String # using various heuristics; see #_parse in date/format.rb # for more details. If parsing fails, an ArgumentError # will be raised. # # The default +str+ is '-4712-01-01T00:00:00+00:00'; this is Julian # Day Number day 0. # # +sg+ specifies the Day of Calendar Reform. def self.parse(str='-4712-01-01T00:00:00+00:00', comp=false, sg=ITALY) elem = _parse(str, comp) new_by_frags(elem, sg) end public :hour, :min, :sec, :sec_fraction, :zone, :offset, :new_offset # :minute, :second, :second_fraction def to_s # 4p format('%.4d-%02d-%02dT%02d:%02d:%02d%s', year, mon, mday, hour, min, sec, zone) end end class Time # def to_time() getlocal end def to_date jd = Date.civil_to_jd(year, mon, mday, Date::ITALY) Date.new!(Date.jd_to_ajd(jd, 0, 0), 0, Date::ITALY) end def to_datetime jd = DateTime.civil_to_jd(year, mon, mday, DateTime::ITALY) fr = DateTime.time_to_day_fraction(hour, min, [sec, 59].min) + Rational(usec, 86400_000_000) of = Rational(utc_offset, 86400) DateTime.new!(DateTime.jd_to_ajd(jd, fr, of), of, DateTime::ITALY) end private :to_date, :to_datetime end class Date =begin def to_time() Time.local(year, mon, mday) end def to_date() self end def to_datetime() DateTime.new!(self.class.jd_to_ajd(jd, 0, 0), @of, @sg) end =end # Create a new Date object representing today. # # +sg+ specifies the Day of Calendar Reform. def self.today(sg=ITALY) t = Time.now jd = civil_to_jd(t.year, t.mon, t.mday, sg) new!(jd_to_ajd(jd, 0, 0), 0, sg) end # Create a new DateTime object representing the current time. # # +sg+ specifies the Day of Calendar Reform. def self.now(sg=ITALY) t = Time.now jd = civil_to_jd(t.year, t.mon, t.mday, sg) fr = time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) + Rational(t.usec, 86400_000_000) of = Rational(t.utc_offset, 86400) new!(jd_to_ajd(jd, fr, of), of, sg) end private_class_method :now end class DateTime < Date =begin def to_time d = new_offset(0) d.instance_eval do Time.utc(year, mon, mday, hour, min, sec, (sec_fraction * 86400000000).to_i) end. getlocal end def to_date() Date.new!(self.class.jd_to_ajd(jd, 0, 0), 0, @sg) end def to_datetime() self end =end private_class_method :today public_class_method :now end class Date class << self def deprecated_class_method_alias(old, new) # :nodoc: module_eval <<-"end;" class << self def #{old}(*args, &block) if $VERBOSE warn("\#{caller.shift.sub(/:in .*/, '')}: " \ "warning: \#{self}::#{old} is deprecated; " \ "use \#{self}::#{new}") end #{new}(*args, &block) end end end; end private :deprecated_class_method_alias def deprecated_alias(old, new) # :nodoc: module_eval <<-"end;" def #{old}(*args, &block) if $VERBOSE warn("\#{caller.shift.sub(/:in .*/, '')}: " \ "warning: \#{self.class}\##{old} is deprecated; " \ "use \#{self.class}\##{new}") end #{new}(*args, &block) end end; end private :deprecated_alias end [ %w(os? julian?), %w(ns? gregorian?), %w(exist1? valid_jd?), %w(exist2? valid_ordinal?), %w(exist3? valid_date?), %w(exist? valid_date?), %w(existw? valid_commercial?), %w(new0 new!), %w(new1 jd), %w(new2 ordinal), %w(new3 new), %w(neww commercial) ].each do |old, new| deprecated_class_method_alias(old, new) end [ %w(os? julian?), %w(ns? gregorian?), %w(sg start), %w(newsg new_start), %w(of offset), %w(newof new_offset) ].each do |old, new| deprecated_alias(old, new) end private :of, :newof end class DateTime < Date public :of, :newof end PK|]ԌI  kconv.rbnu[# # kconv.rb - Kanji Converter. # # $Id: kconv.rb 11708 2007-02-12 23:01:19Z shyouhei $ # # ---- # # kconv.rb implements the Kconv class for Kanji Converter. Additionally, # some methods in String classes are added to allow easy conversion. # require 'nkf' # # Kanji Converter for Ruby. # module Kconv # # Public Constants # #Constant of Encoding # Auto-Detect AUTO = NKF::AUTO # ISO-2022-JP JIS = NKF::JIS # EUC-JP EUC = NKF::EUC # Shift_JIS SJIS = NKF::SJIS # BINARY BINARY = NKF::BINARY # NOCONV NOCONV = NKF::NOCONV # ASCII ASCII = NKF::ASCII # UTF-8 UTF8 = NKF::UTF8 # UTF-16 UTF16 = NKF::UTF16 # UTF-32 UTF32 = NKF::UTF32 # UNKNOWN UNKNOWN = NKF::UNKNOWN # # Private Constants # # Revision of kconv.rb REVISION = %q$Revision: 11708 $ #Regexp of Encoding # Regexp of Shift_JIS string (private constant) RegexpShiftjis = /\A(?: [\x00-\x7f\xa1-\xdf] | [\x81-\x9f\xe0-\xfc][\x40-\x7e\x80-\xfc] )*\z/nx # Regexp of EUC-JP string (private constant) RegexpEucjp = /\A(?: [\x00-\x7f] | \x8e [\xa1-\xdf] | \x8f [\xa1-\xfe] [\xa1-\xfe] | [\xa1-\xfe] [\xa1-\xfe] )*\z/nx # Regexp of UTF-8 string (private constant) RegexpUtf8 = /\A(?: [\x00-\x7f] | [\xc2-\xdf] [\x80-\xbf] | \xe0 [\xa0-\xbf] [\x80-\xbf] | [\xe1-\xef] [\x80-\xbf] [\x80-\xbf] | \xf0 [\x90-\xbf] [\x80-\xbf] [\x80-\xbf] | [\xf1-\xf3] [\x80-\xbf] [\x80-\xbf] [\x80-\xbf] | \xf4 [\x80-\x8f] [\x80-\xbf] [\x80-\xbf] )*\z/nx # # Public Methods # # call-seq: # Kconv.kconv(str, out_code, in_code = Kconv::AUTO) # # Convert str to out_code. # out_code and in_code are given as constants of Kconv. # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want to decode them, use NKF.nkf. def kconv(str, out_code, in_code = AUTO) opt = '-' case in_code when ::NKF::JIS opt << 'J' when ::NKF::EUC opt << 'E' when ::NKF::SJIS opt << 'S' when ::NKF::UTF8 opt << 'W' when ::NKF::UTF16 opt << 'W16' end case out_code when ::NKF::JIS opt << 'j' when ::NKF::EUC opt << 'e' when ::NKF::SJIS opt << 's' when ::NKF::UTF8 opt << 'w' when ::NKF::UTF16 opt << 'w16' when ::NKF::NOCONV return str end opt = '' if opt == '-' ::NKF::nkf(opt, str) end module_function :kconv # # Encode to # # call-seq: # Kconv.tojis(str) -> string # # Convert str to ISO-2022-JP # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-jxm0', str). def tojis(str) ::NKF::nkf('-jm', str) end module_function :tojis # call-seq: # Kconv.toeuc(str) -> string # # Convert str to EUC-JP # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-exm0', str). def toeuc(str) ::NKF::nkf('-em', str) end module_function :toeuc # call-seq: # Kconv.tosjis(str) -> string # # Convert str to Shift_JIS # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-sxm0', str). def tosjis(str) ::NKF::nkf('-sm', str) end module_function :tosjis # call-seq: # Kconv.toutf8(str) -> string # # Convert str to UTF-8 # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-wxm0', str). def toutf8(str) ::NKF::nkf('-wm', str) end module_function :toutf8 # call-seq: # Kconv.toutf16(str) -> string # # Convert str to UTF-16 # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-w16xm0', str). def toutf16(str) ::NKF::nkf('-w16m', str) end module_function :toutf16 # # guess # # call-seq: # Kconv.guess(str) -> integer # # Guess input encoding by NKF.guess2 def guess(str) ::NKF::guess(str) end module_function :guess # call-seq: # Kconv.guess_old(str) -> integer # # Guess input encoding by NKF.guess1 def guess_old(str) ::NKF::guess1(str) end module_function :guess_old # # isEncoding # # call-seq: # Kconv.iseuc(str) -> obj or nil # # Returns whether input encoding is EUC-JP or not. # # *Note* don't expect this return value is MatchData. def iseuc(str) RegexpEucjp.match( str ) end module_function :iseuc # call-seq: # Kconv.issjis(str) -> obj or nil # # Returns whether input encoding is Shift_JIS or not. # # *Note* don't expect this return value is MatchData. def issjis(str) RegexpShiftjis.match( str ) end module_function :issjis # call-seq: # Kconv.isutf8(str) -> obj or nil # # Returns whether input encoding is UTF-8 or not. # # *Note* don't expect this return value is MatchData. def isutf8(str) RegexpUtf8.match( str ) end module_function :isutf8 end class String # call-seq: # String#kconv(out_code, in_code = Kconv::AUTO) # # Convert self to out_code. # out_code and in_code are given as constants of Kconv. # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want to decode them, use NKF.nkf. def kconv(out_code, in_code=Kconv::AUTO) Kconv::kconv(self, out_code, in_code) end # # to Encoding # # call-seq: # String#tojis -> string # # Convert self to ISO-2022-JP # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-jxm0', str). def tojis; Kconv.tojis(self) end # call-seq: # String#toeuc -> string # # Convert self to EUC-JP # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-exm0', str). def toeuc; Kconv.toeuc(self) end # call-seq: # String#tosjis -> string # # Convert self to Shift_JIS # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-sxm0', str). def tosjis; Kconv.tosjis(self) end # call-seq: # String#toutf8 -> string # # Convert self to UTF-8 # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-wxm0', str). def toutf8; Kconv.toutf8(self) end # call-seq: # String#toutf16 -> string # # Convert self to UTF-16 # # *Note* # This method decode MIME encoded string and # convert halfwidth katakana to fullwidth katakana. # If you don't want it, use NKF.nkf('-w16xm0', str). def toutf16; Kconv.toutf16(self) end # # is Encoding # # call-seq: # String#iseuc -> obj or nil # # Returns whether self's encoding is EUC-JP or not. # # *Note* don't expect this return value is MatchData. def iseuc; Kconv.iseuc(self) end # call-seq: # String#issjis -> obj or nil # # Returns whether self's encoding is Shift_JIS or not. # # *Note* don't expect this return value is MatchData. def issjis; Kconv.issjis(self) end # call-seq: # String#isutf8 -> obj or nil # # Returns whether self's encoding is UTF-8 or not. # # *Note* don't expect this return value is MatchData. def isutf8; Kconv.isutf8(self) end end PK|]"g00jcode.rbnu[# jcode.rb - ruby code to handle japanese (EUC/SJIS) string if $VERBOSE && $KCODE == "NONE" warn "Warning: $KCODE is NONE." end $vsave, $VERBOSE = $VERBOSE, false class String warn "feel free for some warnings:\n" if $VERBOSE def _regex_quote(str) str.gsub(/(\\[\[\]\-\\])|\\(.)|([\[\]\\])/) do $1 || $2 || '\\' + $3 end end private :_regex_quote PATTERN_SJIS = '[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]' PATTERN_EUC = '[\xa1-\xfe][\xa1-\xfe]' PATTERN_UTF8 = '[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf]' RE_SJIS = Regexp.new(PATTERN_SJIS, 0, 'n') RE_EUC = Regexp.new(PATTERN_EUC, 0, 'n') RE_UTF8 = Regexp.new(PATTERN_UTF8, 0, 'n') SUCC = {} SUCC['s'] = Hash.new(1) for i in 0 .. 0x3f SUCC['s'][i.chr] = 0x40 - i end SUCC['s']["\x7e"] = 0x80 - 0x7e SUCC['s']["\xfd"] = 0x100 - 0xfd SUCC['s']["\xfe"] = 0x100 - 0xfe SUCC['s']["\xff"] = 0x100 - 0xff SUCC['e'] = Hash.new(1) for i in 0 .. 0xa0 SUCC['e'][i.chr] = 0xa1 - i end SUCC['e']["\xfe"] = 2 SUCC['u'] = Hash.new(1) for i in 0 .. 0x7f SUCC['u'][i.chr] = 0x80 - i end SUCC['u']["\xbf"] = 0x100 - 0xbf def mbchar? case $KCODE[0] when ?s, ?S self =~ RE_SJIS when ?e, ?E self =~ RE_EUC when ?u, ?U self =~ RE_UTF8 else nil end end def end_regexp case $KCODE[0] when ?s, ?S /#{PATTERN_SJIS}$/on when ?e, ?E /#{PATTERN_EUC}$/on when ?u, ?U /#{PATTERN_UTF8}$/on else /.$/on end end alias original_succ! succ! private :original_succ! alias original_succ succ private :original_succ def succ! reg = end_regexp if $KCODE != 'NONE' && self =~ reg succ_table = SUCC[$KCODE[0,1].downcase] begin self[-1] += succ_table[self[-1]] self[-2] += 1 if self[-1] == 0 end while self !~ reg self else original_succ! end end def succ str = self.dup str.succ! or str end private def _expand_ch str a = [] str.scan(/(?:\\(.)|([^\\]))-(?:\\(.)|([^\\]))|(?:\\(.)|(.))/m) do from = $1 || $2 to = $3 || $4 one = $5 || $6 if one a.push one elsif from.length != to.length next elsif from.length == 1 from[0].upto(to[0]) { |c| a.push c.chr } else from.upto(to) { |c| a.push c } end end a end def expand_ch_hash from, to h = {} afrom = _expand_ch(from) ato = _expand_ch(to) afrom.each_with_index do |x,i| h[x] = ato[i] || ato[-1] end h end HashCache = {} TrPatternCache = {} DeletePatternCache = {} SqueezePatternCache = {} public def tr!(from, to) return nil if from == "" return self.delete!(from) if to == "" pattern = TrPatternCache[from] ||= /[#{_regex_quote(from)}]/ if from[0] == ?^ last = /.$/.match(to)[0] self.gsub!(pattern, last) else h = HashCache[from + "1-0" + to] ||= expand_ch_hash(from, to) self.gsub!(pattern) do |c| h[c] end end end def tr(from, to) (str = self.dup).tr!(from, to) or str end def delete!(del) return nil if del == "" self.gsub!(DeletePatternCache[del] ||= /[#{_regex_quote(del)}]+/, '') end def delete(del) (str = self.dup).delete!(del) or str end def squeeze!(del=nil) return nil if del == "" pattern = if del SqueezePatternCache[del] ||= /([#{_regex_quote(del)}])\1+/ else /(.|\n)\1+/ end self.gsub!(pattern, '\1') end def squeeze(del=nil) (str = self.dup).squeeze!(del) or str end def tr_s!(from, to) return self.delete!(from) if to.length == 0 pattern = SqueezePatternCache[from] ||= /([#{_regex_quote(from)}])\1*/ if from[0] == ?^ last = /.$/.match(to)[0] self.gsub!(pattern, last) else h = HashCache[from + "1-0" + to] ||= expand_ch_hash(from, to) self.gsub!(pattern) do h[$1] end end end def tr_s(from, to) (str = self.dup).tr_s!(from,to) or str end def chop! self.gsub!(/(?:.|\r?\n)\z/, '') end def chop (str = self.dup).chop! or str end def jlength self.gsub(/[^\Wa-zA-Z_\d]/, ' ').length end alias jsize jlength def jcount(str) self.delete("^#{str}").jlength end def each_char if block_given? scan(/./m) do |x| yield x end else scan(/./m) end end end $VERBOSE = $vsave PK|]g## mailread.rbnu[# The Mail class represents an internet mail message (as per RFC822, RFC2822) # with headers and a body. class Mail # Create a new Mail where +f+ is either a stream which responds to gets(), # or a path to a file. If +f+ is a path it will be opened. # # The whole message is read so it can be made available through the #header, # #[] and #body methods. # # The "From " line is ignored if the mail is in mbox format. def initialize(f) unless defined? f.gets f = open(f, "r") opened = true end @header = {} @body = [] begin while line = f.gets() line.chop! next if /^From /=~line # skip From-line break if /^$/=~line # end of header if /^(\S+?):\s*(.*)/=~line (attr = $1).capitalize! @header[attr] = $2 elsif attr line.sub!(/^\s*/, '') @header[attr] += "\n" + line end end return unless line while line = f.gets() break if /^From /=~line @body.push(line) end ensure f.close if opened end end # Return the headers as a Hash. def header return @header end # Return the message body as an Array of lines def body return @body end # Return the header corresponding to +field+. # # Matching is case-insensitive. def [](field) @header[field.capitalize] end end PK|]Q rubyunit.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'runit/testcase' require 'test/unit' PK|]_&ݧforwardable.rbnu[# = forwardable - Support for the Delegation Pattern # # $Release Version: 1.1$ # $Revision: 16857 $ # $Date: 2008-06-06 17:05:24 +0900 (Fri, 06 Jun 2008) $ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # # Documentation by James Edward Gray II and Gavin Sinclair # # == Introduction # # This library allows you delegate method calls to an object, on a method by # method basis. You can use Forwardable to setup this delegation at the class # level, or SingleForwardable to handle it at the object level. # # == Notes # # Be advised, RDoc will not detect delegated methods. # # forwardable.rb provides single-method delegation via the # def_delegator() and def_delegators() methods. For full-class # delegation via DelegateClass(), see delegate.rb. # # == Examples # # === Forwardable # # Forwardable makes building a new class based on existing work, with a proper # interface, almost trivial. We want to rely on what has come before obviously, # but with delegation we can take just the methods we need and even rename them # as appropriate. In many cases this is preferable to inheritance, which gives # us the entire old interface, even if much of it isn't needed. # # class Queue # extend Forwardable # # def initialize # @q = [ ] # prepare delegate object # end # # # setup preferred interface, enq() and deq()... # def_delegator :@q, :push, :enq # def_delegator :@q, :shift, :deq # # # support some general Array methods that fit Queues well # def_delegators :@q, :clear, :first, :push, :shift, :size # end # # q = Queue.new # q.enq 1, 2, 3, 4, 5 # q.push 6 # # q.shift # => 1 # while q.size > 0 # puts q.deq # end # # q.enq "Ruby", "Perl", "Python" # puts q.first # q.clear # puts q.first # # Prints: # # 2 # 3 # 4 # 5 # 6 # Ruby # nil # # === SingleForwardable # # printer = String.new # printer.extend SingleForwardable # prepare object for delegation # printer.def_delegator "STDOUT", "puts" # add delegation for STDOUT.puts() # printer.puts "Howdy!" # # Prints: # # Howdy! # # The Forwardable module provides delegation of specified # methods to a designated object, using the methods #def_delegator # and #def_delegators. # # For example, say you have a class RecordCollection which # contains an array @records. You could provide the lookup method # #record_number(), which simply calls #[] on the @records # array, like this: # # class RecordCollection # extend Forwardable # def_delegator :@records, :[], :record_number # end # # Further, if you wish to provide the methods #size, #<<, and #map, # all of which delegate to @records, this is how you can do it: # # class RecordCollection # # extend Forwardable, but we did that above # def_delegators :@records, :size, :<<, :map # end # # Also see the example at forwardable.rb. # module Forwardable @debug = nil class< # # This library is distributed under the terms of the Ruby license. # You can freely distribute/modify this library. # # Documentation: Shugo Maeda, with RDoc conversion and overview by William # Webber. # # See Net::IMAP for documentation. # require "socket" require "monitor" require "digest/md5" begin require "openssl" rescue LoadError end module Net # # Net::IMAP implements Internet Message Access Protocol (IMAP) client # functionality. The protocol is described in [IMAP]. # # == IMAP Overview # # An IMAP client connects to a server, and then authenticates # itself using either #authenticate() or #login(). Having # authenticated itself, there is a range of commands # available to it. Most work with mailboxes, which may be # arranged in an hierarchical namespace, and each of which # contains zero or more messages. How this is implemented on # the server is implementation-dependent; on a UNIX server, it # will frequently be implemented as a files in mailbox format # within a hierarchy of directories. # # To work on the messages within a mailbox, the client must # first select that mailbox, using either #select() or (for # read-only access) #examine(). Once the client has successfully # selected a mailbox, they enter _selected_ state, and that # mailbox becomes the _current_ mailbox, on which mail-item # related commands implicitly operate. # # Messages have two sorts of identifiers: message sequence # numbers, and UIDs. # # Message sequence numbers number messages within a mail box # from 1 up to the number of items in the mail box. If new # message arrives during a session, it receives a sequence # number equal to the new size of the mail box. If messages # are expunged from the mailbox, remaining messages have their # sequence numbers "shuffled down" to fill the gaps. # # UIDs, on the other hand, are permanently guaranteed not to # identify another message within the same mailbox, even if # the existing message is deleted. UIDs are required to # be assigned in ascending (but not necessarily sequential) # order within a mailbox; this means that if a non-IMAP client # rearranges the order of mailitems within a mailbox, the # UIDs have to be reassigned. An IMAP client cannot thus # rearrange message orders. # # == Examples of Usage # # === List sender and subject of all recent messages in the default mailbox # # imap = Net::IMAP.new('mail.example.com') # imap.authenticate('LOGIN', 'joe_user', 'joes_password') # imap.examine('INBOX') # imap.search(["RECENT"]).each do |message_id| # envelope = imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"] # puts "#{envelope.from[0].name}: \t#{envelope.subject}" # end # # === Move all messages from April 2003 from "Mail/sent-mail" to "Mail/sent-apr03" # # imap = Net::IMAP.new('mail.example.com') # imap.authenticate('LOGIN', 'joe_user', 'joes_password') # imap.select('Mail/sent-mail') # if not imap.list('Mail/', 'sent-apr03') # imap.create('Mail/sent-apr03') # end # imap.search(["BEFORE", "30-Apr-2003", "SINCE", "1-Apr-2003"]).each do |message_id| # imap.copy(message_id, "Mail/sent-apr03") # imap.store(message_id, "+FLAGS", [:Deleted]) # end # imap.expunge # # == Thread Safety # # Net::IMAP supports concurrent threads. For example, # # imap = Net::IMAP.new("imap.foo.net", "imap2") # imap.authenticate("cram-md5", "bar", "password") # imap.select("inbox") # fetch_thread = Thread.start { imap.fetch(1..-1, "UID") } # search_result = imap.search(["BODY", "hello"]) # fetch_result = fetch_thread.value # imap.disconnect # # This script invokes the FETCH command and the SEARCH command concurrently. # # == Errors # # An IMAP server can send three different types of responses to indicate # failure: # # NO:: the attempted command could not be successfully completed. For # instance, the username/password used for logging in are incorrect; # the selected mailbox does not exists; etc. # # BAD:: the request from the client does not follow the server's # understanding of the IMAP protocol. This includes attempting # commands from the wrong client state; for instance, attempting # to perform a SEARCH command without having SELECTed a current # mailbox. It can also signal an internal server # failure (such as a disk crash) has occurred. # # BYE:: the server is saying goodbye. This can be part of a normal # logout sequence, and can be used as part of a login sequence # to indicate that the server is (for some reason) unwilling # to accept our connection. As a response to any other command, # it indicates either that the server is shutting down, or that # the server is timing out the client connection due to inactivity. # # These three error response are represented by the errors # Net::IMAP::NoResponseError, Net::IMAP::BadResponseError, and # Net::IMAP::ByeResponseError, all of which are subclasses of # Net::IMAP::ResponseError. Essentially, all methods that involve # sending a request to the server can generate one of these errors. # Only the most pertinent instances have been documented below. # # Because the IMAP class uses Sockets for communication, its methods # are also susceptible to the various errors that can occur when # working with sockets. These are generally represented as # Errno errors. For instance, any method that involves sending a # request to the server and/or receiving a response from it could # raise an Errno::EPIPE error if the network connection unexpectedly # goes down. See the socket(7), ip(7), tcp(7), socket(2), connect(2), # and associated man pages. # # Finally, a Net::IMAP::DataFormatError is thrown if low-level data # is found to be in an incorrect format (for instance, when converting # between UTF-8 and UTF-16), and Net::IMAP::ResponseParseError is # thrown if a server response is non-parseable. # # # == References # # [[IMAP]] # M. Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", # RFC 2060, December 1996. (Note: since obsoleted by RFC 3501) # # [[LANGUAGE-TAGS]] # Alvestrand, H., "Tags for the Identification of # Languages", RFC 1766, March 1995. # # [[MD5]] # Myers, J., and M. Rose, "The Content-MD5 Header Field", RFC # 1864, October 1995. # # [[MIME-IMB]] # Freed, N., and N. Borenstein, "MIME (Multipurpose Internet # Mail Extensions) Part One: Format of Internet Message Bodies", RFC # 2045, November 1996. # # [[RFC-822]] # Crocker, D., "Standard for the Format of ARPA Internet Text # Messages", STD 11, RFC 822, University of Delaware, August 1982. # # [[RFC-2087]] # Myers, J., "IMAP4 QUOTA extension", RFC 2087, January 1997. # # [[RFC-2086]] # Myers, J., "IMAP4 ACL extension", RFC 2086, January 1997. # # [[RFC-2195]] # Klensin, J., Catoe, R., and Krumviede, P., "IMAP/POP AUTHorize Extension # for Simple Challenge/Response", RFC 2195, September 1997. # # [[SORT-THREAD-EXT]] # Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - SORT and THREAD # Extensions", draft-ietf-imapext-sort, May 2003. # # [[OSSL]] # http://www.openssl.org # # [[RSSL]] # http://savannah.gnu.org/projects/rubypki # # [[UTF7]] # Goldsmith, D. and Davis, M., "UTF-7: A Mail-Safe Transformation Format of # Unicode", RFC 2152, May 1997. # class IMAP include MonitorMixin if defined?(OpenSSL) include OpenSSL include SSL end # Returns an initial greeting response from the server. attr_reader :greeting # Returns recorded untagged responses. For example: # # imap.select("inbox") # p imap.responses["EXISTS"][-1] # #=> 2 # p imap.responses["UIDVALIDITY"][-1] # #=> 968263756 attr_reader :responses # Returns all response handlers. attr_reader :response_handlers # The thread to receive exceptions. attr_accessor :client_thread # Flag indicating a message has been seen SEEN = :Seen # Flag indicating a message has been answered ANSWERED = :Answered # Flag indicating a message has been flagged for special or urgent # attention FLAGGED = :Flagged # Flag indicating a message has been marked for deletion. This # will occur when the mailbox is closed or expunged. DELETED = :Deleted # Flag indicating a message is only a draft or work-in-progress version. DRAFT = :Draft # Flag indicating that the message is "recent", meaning that this # session is the first session in which the client has been notified # of this message. RECENT = :Recent # Flag indicating that a mailbox context name cannot contain # children. NOINFERIORS = :Noinferiors # Flag indicating that a mailbox is not selected. NOSELECT = :Noselect # Flag indicating that a mailbox has been marked "interesting" by # the server; this commonly indicates that the mailbox contains # new messages. MARKED = :Marked # Flag indicating that the mailbox does not contains new messages. UNMARKED = :Unmarked # Returns the debug mode. def self.debug return @@debug end # Sets the debug mode. def self.debug=(val) return @@debug = val end # Adds an authenticator for Net::IMAP#authenticate. +auth_type+ # is the type of authentication this authenticator supports # (for instance, "LOGIN"). The +authenticator+ is an object # which defines a process() method to handle authentication with # the server. See Net::IMAP::LoginAuthenticator and # Net::IMAP::CramMD5Authenticator for examples. # # If +auth_type+ refers to an existing authenticator, it will be # replaced by the new one. def self.add_authenticator(auth_type, authenticator) @@authenticators[auth_type] = authenticator end # Disconnects from the server. def disconnect begin # try to call SSL::SSLSocket#io. @sock.io.shutdown rescue NoMethodError # @sock is not an SSL::SSLSocket. @sock.shutdown end @receiver_thread.join @sock.close end # Returns true if disconnected from the server. def disconnected? return @sock.closed? end # Sends a CAPABILITY command, and returns an array of # capabilities that the server supports. Each capability # is a string. See [IMAP] for a list of possible # capabilities. # # Note that the Net::IMAP class does not modify its # behaviour according to the capabilities of the server; # it is up to the user of the class to ensure that # a certain capability is supported by a server before # using it. def capability synchronize do send_command("CAPABILITY") return @responses.delete("CAPABILITY")[-1] end end # Sends a NOOP command to the server. It does nothing. def noop send_command("NOOP") end # Sends a LOGOUT command to inform the server that the client is # done with the connection. def logout send_command("LOGOUT") end # Sends an AUTHENTICATE command to authenticate the client. # The +auth_type+ parameter is a string that represents # the authentication mechanism to be used. Currently Net::IMAP # supports authentication mechanisms: # # LOGIN:: login using cleartext user and password. # CRAM-MD5:: login with cleartext user and encrypted password # (see [RFC-2195] for a full description). This # mechanism requires that the server have the user's # password stored in clear-text password. # # For both these mechanisms, there should be two +args+: username # and (cleartext) password. A server may not support one or other # of these mechanisms; check #capability() for a capability of # the form "AUTH=LOGIN" or "AUTH=CRAM-MD5". # # Authentication is done using the appropriate authenticator object: # see @@authenticators for more information on plugging in your own # authenticator. # # For example: # # imap.authenticate('LOGIN', user, password) # # A Net::IMAP::NoResponseError is raised if authentication fails. def authenticate(auth_type, *args) auth_type = auth_type.upcase unless @@authenticators.has_key?(auth_type) raise ArgumentError, format('unknown auth type - "%s"', auth_type) end authenticator = @@authenticators[auth_type].new(*args) send_command("AUTHENTICATE", auth_type) do |resp| if resp.instance_of?(ContinuationRequest) data = authenticator.process(resp.data.text.unpack("m")[0]) s = [data].pack("m").gsub(/\n/, "") send_string_data(s) put_string(CRLF) end end end # Sends a LOGIN command to identify the client and carries # the plaintext +password+ authenticating this +user+. Note # that, unlike calling #authenticate() with an +auth_type+ # of "LOGIN", #login() does *not* use the login authenticator. # # A Net::IMAP::NoResponseError is raised if authentication fails. def login(user, password) send_command("LOGIN", user, password) end # Sends a SELECT command to select a +mailbox+ so that messages # in the +mailbox+ can be accessed. # # After you have selected a mailbox, you may retrieve the # number of items in that mailbox from @responses["EXISTS"][-1], # and the number of recent messages from @responses["RECENT"][-1]. # Note that these values can change if new messages arrive # during a session; see #add_response_handler() for a way of # detecting this event. # # A Net::IMAP::NoResponseError is raised if the mailbox does not # exist or is for some reason non-selectable. def select(mailbox) synchronize do @responses.clear send_command("SELECT", mailbox) end end # Sends a EXAMINE command to select a +mailbox+ so that messages # in the +mailbox+ can be accessed. Behaves the same as #select(), # except that the selected +mailbox+ is identified as read-only. # # A Net::IMAP::NoResponseError is raised if the mailbox does not # exist or is for some reason non-examinable. def examine(mailbox) synchronize do @responses.clear send_command("EXAMINE", mailbox) end end # Sends a CREATE command to create a new +mailbox+. # # A Net::IMAP::NoResponseError is raised if a mailbox with that name # cannot be created. def create(mailbox) send_command("CREATE", mailbox) end # Sends a DELETE command to remove the +mailbox+. # # A Net::IMAP::NoResponseError is raised if a mailbox with that name # cannot be deleted, either because it does not exist or because the # client does not have permission to delete it. def delete(mailbox) send_command("DELETE", mailbox) end # Sends a RENAME command to change the name of the +mailbox+ to # +newname+. # # A Net::IMAP::NoResponseError is raised if a mailbox with the # name +mailbox+ cannot be renamed to +newname+ for whatever # reason; for instance, because +mailbox+ does not exist, or # because there is already a mailbox with the name +newname+. def rename(mailbox, newname) send_command("RENAME", mailbox, newname) end # Sends a SUBSCRIBE command to add the specified +mailbox+ name to # the server's set of "active" or "subscribed" mailboxes as returned # by #lsub(). # # A Net::IMAP::NoResponseError is raised if +mailbox+ cannot be # subscribed to, for instance because it does not exist. def subscribe(mailbox) send_command("SUBSCRIBE", mailbox) end # Sends a UNSUBSCRIBE command to remove the specified +mailbox+ name # from the server's set of "active" or "subscribed" mailboxes. # # A Net::IMAP::NoResponseError is raised if +mailbox+ cannot be # unsubscribed from, for instance because the client is not currently # subscribed to it. def unsubscribe(mailbox) send_command("UNSUBSCRIBE", mailbox) end # Sends a LIST command, and returns a subset of names from # the complete set of all names available to the client. # +refname+ provides a context (for instance, a base directory # in a directory-based mailbox hierarchy). +mailbox+ specifies # a mailbox or (via wildcards) mailboxes under that context. # Two wildcards may be used in +mailbox+: '*', which matches # all characters *including* the hierarchy delimiter (for instance, # '/' on a UNIX-hosted directory-based mailbox hierarchy); and '%', # which matches all characters *except* the hierarchy delimiter. # # If +refname+ is empty, +mailbox+ is used directly to determine # which mailboxes to match. If +mailbox+ is empty, the root # name of +refname+ and the hierarchy delimiter are returned. # # The return value is an array of +Net::IMAP::MailboxList+. For example: # # imap.create("foo/bar") # imap.create("foo/baz") # p imap.list("", "foo/%") # #=> [#, \\ # #, \\ # #] def list(refname, mailbox) synchronize do send_command("LIST", refname, mailbox) return @responses.delete("LIST") end end # Sends the GETQUOTAROOT command along with specified +mailbox+. # This command is generally available to both admin and user. # If mailbox exists, returns an array containing objects of # Net::IMAP::MailboxQuotaRoot and Net::IMAP::MailboxQuota. def getquotaroot(mailbox) synchronize do send_command("GETQUOTAROOT", mailbox) result = [] result.concat(@responses.delete("QUOTAROOT")) result.concat(@responses.delete("QUOTA")) return result end end # Sends the GETQUOTA command along with specified +mailbox+. # If this mailbox exists, then an array containing a # Net::IMAP::MailboxQuota object is returned. This # command generally is only available to server admin. def getquota(mailbox) synchronize do send_command("GETQUOTA", mailbox) return @responses.delete("QUOTA") end end # Sends a SETQUOTA command along with the specified +mailbox+ and # +quota+. If +quota+ is nil, then quota will be unset for that # mailbox. Typically one needs to be logged in as server admin # for this to work. The IMAP quota commands are described in # [RFC-2087]. def setquota(mailbox, quota) if quota.nil? data = '()' else data = '(STORAGE ' + quota.to_s + ')' end send_command("SETQUOTA", mailbox, RawData.new(data)) end # Sends the SETACL command along with +mailbox+, +user+ and the # +rights+ that user is to have on that mailbox. If +rights+ is nil, # then that user will be stripped of any rights to that mailbox. # The IMAP ACL commands are described in [RFC-2086]. def setacl(mailbox, user, rights) if rights.nil? send_command("SETACL", mailbox, user, "") else send_command("SETACL", mailbox, user, rights) end end # Send the GETACL command along with specified +mailbox+. # If this mailbox exists, an array containing objects of # Net::IMAP::MailboxACLItem will be returned. def getacl(mailbox) synchronize do send_command("GETACL", mailbox) return @responses.delete("ACL")[-1] end end # Sends a LSUB command, and returns a subset of names from the set # of names that the user has declared as being "active" or # "subscribed". +refname+ and +mailbox+ are interpreted as # for #list(). # The return value is an array of +Net::IMAP::MailboxList+. def lsub(refname, mailbox) synchronize do send_command("LSUB", refname, mailbox) return @responses.delete("LSUB") end end # Sends a STATUS command, and returns the status of the indicated # +mailbox+. +attr+ is a list of one or more attributes that # we are request the status of. Supported attributes include: # # MESSAGES:: the number of messages in the mailbox. # RECENT:: the number of recent messages in the mailbox. # UNSEEN:: the number of unseen messages in the mailbox. # # The return value is a hash of attributes. For example: # # p imap.status("inbox", ["MESSAGES", "RECENT"]) # #=> {"RECENT"=>0, "MESSAGES"=>44} # # A Net::IMAP::NoResponseError is raised if status values # for +mailbox+ cannot be returned, for instance because it # does not exist. def status(mailbox, attr) synchronize do send_command("STATUS", mailbox, attr) return @responses.delete("STATUS")[-1].attr end end # Sends a APPEND command to append the +message+ to the end of # the +mailbox+. The optional +flags+ argument is an array of # flags to initially passing to the new message. The optional # +date_time+ argument specifies the creation time to assign to the # new message; it defaults to the current time. # For example: # # imap.append("inbox", <:: a set of message sequence numbers. ',' indicates # an interval, ':' indicates a range. For instance, # '2,10:12,15' means "2,10,11,12,15". # # BEFORE :: messages with an internal date strictly before # . The date argument has a format similar # to 8-Aug-2002. # # BODY :: messages that contain within their body. # # CC :: messages containing in their CC field. # # FROM :: messages that contain in their FROM field. # # NEW:: messages with the \Recent, but not the \Seen, flag set. # # NOT :: negate the following search key. # # OR :: "or" two search keys together. # # ON :: messages with an internal date exactly equal to , # which has a format similar to 8-Aug-2002. # # SINCE :: messages with an internal date on or after . # # SUBJECT :: messages with in their subject. # # TO :: messages with in their TO field. # # For example: # # p imap.search(["SUBJECT", "hello", "NOT", "NEW"]) # #=> [1, 6, 7, 8] def search(keys, charset = nil) return search_internal("SEARCH", keys, charset) end # As for #search(), but returns unique identifiers. def uid_search(keys, charset = nil) return search_internal("UID SEARCH", keys, charset) end # Sends a FETCH command to retrieve data associated with a message # in the mailbox. The +set+ parameter is a number or an array of # numbers or a Range object. The number is a message sequence # number. +attr+ is a list of attributes to fetch; see the # documentation for Net::IMAP::FetchData for a list of valid # attributes. # The return value is an array of Net::IMAP::FetchData. For example: # # p imap.fetch(6..8, "UID") # #=> [#98}>, \\ # #99}>, \\ # #100}>] # p imap.fetch(6, "BODY[HEADER.FIELDS (SUBJECT)]") # #=> [#"Subject: test\r\n\r\n"}>] # data = imap.uid_fetch(98, ["RFC822.SIZE", "INTERNALDATE"])[0] # p data.seqno # #=> 6 # p data.attr["RFC822.SIZE"] # #=> 611 # p data.attr["INTERNALDATE"] # #=> "12-Oct-2000 22:40:59 +0900" # p data.attr["UID"] # #=> 98 def fetch(set, attr) return fetch_internal("FETCH", set, attr) end # As for #fetch(), but +set+ contains unique identifiers. def uid_fetch(set, attr) return fetch_internal("UID FETCH", set, attr) end # Sends a STORE command to alter data associated with messages # in the mailbox, in particular their flags. The +set+ parameter # is a number or an array of numbers or a Range object. Each number # is a message sequence number. +attr+ is the name of a data item # to store: 'FLAGS' means to replace the message's flag list # with the provided one; '+FLAGS' means to add the provided flags; # and '-FLAGS' means to remove them. +flags+ is a list of flags. # # The return value is an array of Net::IMAP::FetchData. For example: # # p imap.store(6..8, "+FLAGS", [:Deleted]) # #=> [#[:Seen, :Deleted]}>, \\ # #[:Seen, :Deleted]}>, \\ # #[:Seen, :Deleted]}>] def store(set, attr, flags) return store_internal("STORE", set, attr, flags) end # As for #store(), but +set+ contains unique identifiers. def uid_store(set, attr, flags) return store_internal("UID STORE", set, attr, flags) end # Sends a COPY command to copy the specified message(s) to the end # of the specified destination +mailbox+. The +set+ parameter is # a number or an array of numbers or a Range object. The number is # a message sequence number. def copy(set, mailbox) copy_internal("COPY", set, mailbox) end # As for #copy(), but +set+ contains unique identifiers. def uid_copy(set, mailbox) copy_internal("UID COPY", set, mailbox) end # Sends a SORT command to sort messages in the mailbox. # Returns an array of message sequence numbers. For example: # # p imap.sort(["FROM"], ["ALL"], "US-ASCII") # #=> [1, 2, 3, 5, 6, 7, 8, 4, 9] # p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII") # #=> [6, 7, 8, 1] # # See [SORT-THREAD-EXT] for more details. def sort(sort_keys, search_keys, charset) return sort_internal("SORT", sort_keys, search_keys, charset) end # As for #sort(), but returns an array of unique identifiers. def uid_sort(sort_keys, search_keys, charset) return sort_internal("UID SORT", sort_keys, search_keys, charset) end # Adds a response handler. For example, to detect when # the server sends us a new EXISTS response (which normally # indicates new messages being added to the mail box), # you could add the following handler after selecting the # mailbox. # # imap.add_response_handler { |resp| # if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "EXISTS" # puts "Mailbox now has #{resp.data} messages" # end # } # def add_response_handler(handler = Proc.new) @response_handlers.push(handler) end # Removes the response handler. def remove_response_handler(handler) @response_handlers.delete(handler) end # As for #search(), but returns message sequence numbers in threaded # format, as a Net::IMAP::ThreadMember tree. The supported algorithms # are: # # ORDEREDSUBJECT:: split into single-level threads according to subject, # ordered by date. # REFERENCES:: split into threads by parent/child relationships determined # by which message is a reply to which. # # Unlike #search(), +charset+ is a required argument. US-ASCII # and UTF-8 are sample values. # # See [SORT-THREAD-EXT] for more details. def thread(algorithm, search_keys, charset) return thread_internal("THREAD", algorithm, search_keys, charset) end # As for #thread(), but returns unique identifiers instead of # message sequence numbers. def uid_thread(algorithm, search_keys, charset) return thread_internal("UID THREAD", algorithm, search_keys, charset) end # Decode a string from modified UTF-7 format to UTF-8. # # UTF-7 is a 7-bit encoding of Unicode [UTF7]. IMAP uses a # slightly modified version of this to encode mailbox names # containing non-ASCII characters; see [IMAP] section 5.1.3. # # Net::IMAP does _not_ automatically encode and decode # mailbox names to and from utf7. def self.decode_utf7(s) return s.gsub(/&(.*?)-/n) { if $1.empty? "&" else base64 = $1.tr(",", "/") x = base64.length % 4 if x > 0 base64.concat("=" * (4 - x)) end u16tou8(base64.unpack("m")[0]) end } end # Encode a string from UTF-8 format to modified UTF-7. def self.encode_utf7(s) return s.gsub(/(&)|([^\x20-\x7e]+)/u) { |x| if $1 "&-" else base64 = [u8tou16(x)].pack("m") "&" + base64.delete("=\n").tr("/", ",") + "-" end } end private CRLF = "\r\n" # :nodoc: PORT = 143 # :nodoc: @@debug = false @@authenticators = {} # Creates a new Net::IMAP object and connects it to the specified # +port+ (143 by default) on the named +host+. If +usessl+ is true, # then an attempt will # be made to use SSL (now TLS) to connect to the server. For this # to work OpenSSL [OSSL] and the Ruby OpenSSL [RSSL] # extensions need to be installed. The +certs+ parameter indicates # the path or file containing the CA cert of the server, and the # +verify+ parameter is for the OpenSSL verification callback. # # The most common errors are: # # Errno::ECONNREFUSED:: connection refused by +host+ or an intervening # firewall. # Errno::ETIMEDOUT:: connection timed out (possibly due to packets # being dropped by an intervening firewall). # Errno::ENETUNREACH:: there is no route to that network. # SocketError:: hostname not known or other socket error. # Net::IMAP::ByeResponseError:: we connected to the host, but they # immediately said goodbye to us. def initialize(host, port = PORT, usessl = false, certs = nil, verify = false) super() @host = host @port = port @tag_prefix = "RUBY" @tagno = 0 @parser = ResponseParser.new @sock = TCPSocket.open(host, port) if usessl unless defined?(OpenSSL) raise "SSL extension not installed" end @usessl = true # verify the server. context = SSLContext::new() context.ca_file = certs if certs && FileTest::file?(certs) context.ca_path = certs if certs && FileTest::directory?(certs) context.verify_mode = VERIFY_PEER if verify if defined?(VerifyCallbackProc) context.verify_callback = VerifyCallbackProc end @sock = SSLSocket.new(@sock, context) @sock.sync_close = true @sock.connect # start ssl session. @sock.post_connection_check(@host) if verify else @usessl = false end @responses = Hash.new([].freeze) @tagged_responses = {} @response_handlers = [] @response_arrival = new_cond @continuation_request = nil @logout_command_tag = nil @debug_output_bol = true @exception = nil @greeting = get_response if @greeting.name == "BYE" @sock.close raise ByeResponseError, @greeting.raw_data end @client_thread = Thread.current @receiver_thread = Thread.start { receive_responses } end def receive_responses while true synchronize do @exception = nil end begin resp = get_response rescue Exception => e synchronize do @sock.close unless @sock.closed? @exception = e end break end unless resp synchronize do @exception = EOFError.new("end of file reached") end break end begin synchronize do case resp when TaggedResponse @tagged_responses[resp.tag] = resp @response_arrival.broadcast if resp.tag == @logout_command_tag return end when UntaggedResponse record_response(resp.name, resp.data) if resp.data.instance_of?(ResponseText) && (code = resp.data.code) record_response(code.name, code.data) end if resp.name == "BYE" && @logout_command_tag.nil? @sock.close @exception = ByeResponseError.new(resp.raw_data) @response_arrival.broadcast return end when ContinuationRequest @continuation_request = resp @response_arrival.broadcast end @response_handlers.each do |handler| handler.call(resp) end end rescue Exception => e @exception = e synchronize do @response_arrival.broadcast end end end synchronize do @response_arrival.broadcast end end def get_tagged_response(tag) until @tagged_responses.key?(tag) raise @exception if @exception @response_arrival.wait end return pick_up_tagged_response(tag) end def pick_up_tagged_response(tag) resp = @tagged_responses.delete(tag) case resp.name when /\A(?:NO)\z/ni raise NoResponseError, resp.data.text when /\A(?:BAD)\z/ni raise BadResponseError, resp.data.text else return resp end end def get_response buff = "" while true s = @sock.gets(CRLF) break unless s buff.concat(s) if /\{(\d+)\}\r\n/n =~ s s = @sock.read($1.to_i) buff.concat(s) else break end end return nil if buff.length == 0 if @@debug $stderr.print(buff.gsub(/^/n, "S: ")) end return @parser.parse(buff) end def record_response(name, data) unless @responses.has_key?(name) @responses[name] = [] end @responses[name].push(data) end def send_command(cmd, *args, &block) synchronize do tag = Thread.current[:net_imap_tag] = generate_tag put_string(tag + " " + cmd) args.each do |i| put_string(" ") send_data(i) end put_string(CRLF) if cmd == "LOGOUT" @logout_command_tag = tag end if block add_response_handler(block) end begin return get_tagged_response(tag) ensure if block remove_response_handler(block) end end end end def generate_tag @tagno += 1 return format("%s%04d", @tag_prefix, @tagno) end def put_string(str) @sock.print(str) if @@debug if @debug_output_bol $stderr.print("C: ") end $stderr.print(str.gsub(/\n(?!\z)/n, "\nC: ")) if /\r\n\z/n.match(str) @debug_output_bol = true else @debug_output_bol = false end end end def send_data(data) case data when nil put_string("NIL") when String send_string_data(data) when Integer send_number_data(data) when Array send_list_data(data) when Time send_time_data(data) when Symbol send_symbol_data(data) else data.send_data(self) end end def send_string_data(str) case str when "" put_string('""') when /[\x80-\xff\r\n]/n # literal send_literal(str) when /[(){ \x00-\x1f\x7f%*"\\]/n # quoted string send_quoted_string(str) else put_string(str) end end def send_quoted_string(str) put_string('"' + str.gsub(/["\\]/n, "\\\\\\&") + '"') end def send_literal(str) put_string("{" + str.length.to_s + "}" + CRLF) while @continuation_request.nil? && !@tagged_responses.key?(Thread.current[:net_imap_tag]) @response_arrival.wait raise @exception if @exception end if @continuation_request.nil? pick_up_tagged_response(Thread.current[:net_imap_tag]) raise ResponseError.new("expected continuation request") end @continuation_request = nil put_string(str) end def send_number_data(num) if num < 0 || num >= 4294967296 raise DataFormatError, num.to_s end put_string(num.to_s) end def send_list_data(list) put_string("(") first = true list.each do |i| if first first = false else put_string(" ") end send_data(i) end put_string(")") end DATE_MONTH = %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) def send_time_data(time) t = time.dup.gmtime s = format('"%2d-%3s-%4d %02d:%02d:%02d +0000"', t.day, DATE_MONTH[t.month - 1], t.year, t.hour, t.min, t.sec) put_string(s) end def send_symbol_data(symbol) put_string("\\" + symbol.to_s) end def search_internal(cmd, keys, charset) if keys.instance_of?(String) keys = [RawData.new(keys)] else normalize_searching_criteria(keys) end synchronize do if charset send_command(cmd, "CHARSET", charset, *keys) else send_command(cmd, *keys) end return @responses.delete("SEARCH")[-1] end end def fetch_internal(cmd, set, attr) case attr when String then attr = RawData.new(attr) when Array then attr = attr.map { |arg| arg.is_a?(String) ? RawData.new(arg) : arg } end synchronize do @responses.delete("FETCH") send_command(cmd, MessageSet.new(set), attr) return @responses.delete("FETCH") end end def store_internal(cmd, set, attr, flags) if attr.instance_of?(String) attr = RawData.new(attr) end synchronize do @responses.delete("FETCH") send_command(cmd, MessageSet.new(set), attr, flags) return @responses.delete("FETCH") end end def copy_internal(cmd, set, mailbox) send_command(cmd, MessageSet.new(set), mailbox) end def sort_internal(cmd, sort_keys, search_keys, charset) if search_keys.instance_of?(String) search_keys = [RawData.new(search_keys)] else normalize_searching_criteria(search_keys) end normalize_searching_criteria(search_keys) synchronize do send_command(cmd, sort_keys, charset, *search_keys) return @responses.delete("SORT")[-1] end end def thread_internal(cmd, algorithm, search_keys, charset) if search_keys.instance_of?(String) search_keys = [RawData.new(search_keys)] else normalize_searching_criteria(search_keys) end normalize_searching_criteria(search_keys) send_command(cmd, algorithm, charset, *search_keys) return @responses.delete("THREAD")[-1] end def normalize_searching_criteria(keys) keys.collect! do |i| case i when -1, Range, Array MessageSet.new(i) else i end end end def self.u16tou8(s) len = s.length if len < 2 return "" end buf = "" i = 0 while i < len c = s[i] << 8 | s[i + 1] i += 2 if c == 0xfeff next elsif c < 0x0080 buf.concat(c) elsif c < 0x0800 b2 = c & 0x003f b1 = c >> 6 buf.concat(b1 | 0xc0) buf.concat(b2 | 0x80) elsif c >= 0xdc00 && c < 0xe000 raise DataFormatError, "invalid surrogate detected" elsif c >= 0xd800 && c < 0xdc00 if i + 2 > len raise DataFormatError, "invalid surrogate detected" end low = s[i] << 8 | s[i + 1] i += 2 if low < 0xdc00 || low > 0xdfff raise DataFormatError, "invalid surrogate detected" end c = (((c & 0x03ff)) << 10 | (low & 0x03ff)) + 0x10000 b4 = c & 0x003f b3 = (c >> 6) & 0x003f b2 = (c >> 12) & 0x003f b1 = c >> 18; buf.concat(b1 | 0xf0) buf.concat(b2 | 0x80) buf.concat(b3 | 0x80) buf.concat(b4 | 0x80) else # 0x0800-0xffff b3 = c & 0x003f b2 = (c >> 6) & 0x003f b1 = c >> 12 buf.concat(b1 | 0xe0) buf.concat(b2 | 0x80) buf.concat(b3 | 0x80) end end return buf end private_class_method :u16tou8 def self.u8tou16(s) len = s.length buf = "" i = 0 while i < len c = s[i] if (c & 0x80) == 0 buf.concat(0x00) buf.concat(c) i += 1 elsif (c & 0xe0) == 0xc0 && len >= 2 && (s[i + 1] & 0xc0) == 0x80 if c == 0xc0 || c == 0xc1 raise DataFormatError, format("non-shortest UTF-8 sequence (%02x)", c) end u = ((c & 0x1f) << 6) | (s[i + 1] & 0x3f) buf.concat(u >> 8) buf.concat(u & 0x00ff) i += 2 elsif (c & 0xf0) == 0xe0 && i + 2 < len && (s[i + 1] & 0xc0) == 0x80 && (s[i + 2] & 0xc0) == 0x80 if c == 0xe0 && s[i + 1] < 0xa0 raise DataFormatError, format("non-shortest UTF-8 sequence (%02x)", c) end u = ((c & 0x0f) << 12) | ((s[i + 1] & 0x3f) << 6) | (s[i + 2] & 0x3f) # surrogate chars if u >= 0xd800 && u <= 0xdfff raise DataFormatError, format("none-UTF-16 char detected (%04x)", u) end buf.concat(u >> 8) buf.concat(u & 0x00ff) i += 3 elsif (c & 0xf8) == 0xf0 && i + 3 < len && (s[i + 1] & 0xc0) == 0x80 && (s[i + 2] & 0xc0) == 0x80 && (s[i + 3] & 0xc0) == 0x80 if c == 0xf0 && s[i + 1] < 0x90 raise DataFormatError, format("non-shortest UTF-8 sequence (%02x)", c) end u = ((c & 0x07) << 18) | ((s[i + 1] & 0x3f) << 12) | ((s[i + 2] & 0x3f) << 6) | (s[i + 3] & 0x3f) if u < 0x10000 buf.concat(u >> 8) buf.concat(u & 0x00ff) elsif u < 0x110000 high = ((u - 0x10000) >> 10) | 0xd800 low = (u & 0x03ff) | 0xdc00 buf.concat(high >> 8) buf.concat(high & 0x00ff) buf.concat(low >> 8) buf.concat(low & 0x00ff) else raise DataFormatError, format("none-UTF-16 char detected (%04x)", u) end i += 4 else raise DataFormatError, format("illegal UTF-8 sequence (%02x)", c) end end return buf end private_class_method :u8tou16 class RawData # :nodoc: def send_data(imap) imap.send(:put_string, @data) end private def initialize(data) @data = data end end class Atom # :nodoc: def send_data(imap) imap.send(:put_string, @data) end private def initialize(data) @data = data end end class QuotedString # :nodoc: def send_data(imap) imap.send(:send_quoted_string, @data) end private def initialize(data) @data = data end end class Literal # :nodoc: def send_data(imap) imap.send(:send_literal, @data) end private def initialize(data) @data = data end end class MessageSet # :nodoc: def send_data(imap) imap.send(:put_string, format_internal(@data)) end private def initialize(data) @data = data end def format_internal(data) case data when "*" return data when Integer ensure_nz_number(data) if data == -1 return "*" else return data.to_s end when Range return format_internal(data.first) + ":" + format_internal(data.last) when Array return data.collect {|i| format_internal(i)}.join(",") when ThreadMember return data.seqno.to_s + ":" + data.children.collect {|i| format_internal(i).join(",")} else raise DataFormatError, data.inspect end end def ensure_nz_number(num) if num < -1 || num == 0 || num >= 4294967296 msg = "nz_number must be non-zero unsigned 32-bit integer: " + num.inspect raise DataFormatError, msg end end end # Net::IMAP::ContinuationRequest represents command continuation requests. # # The command continuation request response is indicated by a "+" token # instead of a tag. This form of response indicates that the server is # ready to accept the continuation of a command from the client. The # remainder of this response is a line of text. # # continue_req ::= "+" SPACE (resp_text / base64) # # ==== Fields: # # data:: Returns the data (Net::IMAP::ResponseText). # # raw_data:: Returns the raw data string. ContinuationRequest = Struct.new(:data, :raw_data) # Net::IMAP::UntaggedResponse represents untagged responses. # # Data transmitted by the server to the client and status responses # that do not indicate command completion are prefixed with the token # "*", and are called untagged responses. # # response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye / # mailbox_data / message_data / capability_data) # # ==== Fields: # # name:: Returns the name such as "FLAGS", "LIST", "FETCH".... # # data:: Returns the data such as an array of flag symbols, # a (()) object.... # # raw_data:: Returns the raw data string. UntaggedResponse = Struct.new(:name, :data, :raw_data) # Net::IMAP::TaggedResponse represents tagged responses. # # The server completion result response indicates the success or # failure of the operation. It is tagged with the same tag as the # client command which began the operation. # # response_tagged ::= tag SPACE resp_cond_state CRLF # # tag ::= 1* # # resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text # # ==== Fields: # # tag:: Returns the tag. # # name:: Returns the name. the name is one of "OK", "NO", "BAD". # # data:: Returns the data. See (()). # # raw_data:: Returns the raw data string. # TaggedResponse = Struct.new(:tag, :name, :data, :raw_data) # Net::IMAP::ResponseText represents texts of responses. # The text may be prefixed by the response code. # # resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text) # ;; text SHOULD NOT begin with "[" or "=" # # ==== Fields: # # code:: Returns the response code. See (()). # # text:: Returns the text. # ResponseText = Struct.new(:code, :text) # # Net::IMAP::ResponseCode represents response codes. # # resp_text_code ::= "ALERT" / "PARSE" / # "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" / # "READ-ONLY" / "READ-WRITE" / "TRYCREATE" / # "UIDVALIDITY" SPACE nz_number / # "UNSEEN" SPACE nz_number / # atom [SPACE 1*] # # ==== Fields: # # name:: Returns the name such as "ALERT", "PERMANENTFLAGS", "UIDVALIDITY".... # # data:: Returns the data if it exists. # ResponseCode = Struct.new(:name, :data) # Net::IMAP::MailboxList represents contents of the LIST response. # # mailbox_list ::= "(" #("\Marked" / "\Noinferiors" / # "\Noselect" / "\Unmarked" / flag_extension) ")" # SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox # # ==== Fields: # # attr:: Returns the name attributes. Each name attribute is a symbol # capitalized by String#capitalize, such as :Noselect (not :NoSelect). # # delim:: Returns the hierarchy delimiter # # name:: Returns the mailbox name. # MailboxList = Struct.new(:attr, :delim, :name) # Net::IMAP::MailboxQuota represents contents of GETQUOTA response. # This object can also be a response to GETQUOTAROOT. In the syntax # specification below, the delimiter used with the "#" construct is a # single space (SPACE). # # quota_list ::= "(" #quota_resource ")" # # quota_resource ::= atom SPACE number SPACE number # # quota_response ::= "QUOTA" SPACE astring SPACE quota_list # # ==== Fields: # # mailbox:: The mailbox with the associated quota. # # usage:: Current storage usage of mailbox. # # quota:: Quota limit imposed on mailbox. # MailboxQuota = Struct.new(:mailbox, :usage, :quota) # Net::IMAP::MailboxQuotaRoot represents part of the GETQUOTAROOT # response. (GETQUOTAROOT can also return Net::IMAP::MailboxQuota.) # # quotaroot_response ::= "QUOTAROOT" SPACE astring *(SPACE astring) # # ==== Fields: # # mailbox:: The mailbox with the associated quota. # # quotaroots:: Zero or more quotaroots that effect the quota on the # specified mailbox. # MailboxQuotaRoot = Struct.new(:mailbox, :quotaroots) # Net::IMAP::MailboxACLItem represents response from GETACL. # # acl_data ::= "ACL" SPACE mailbox *(SPACE identifier SPACE rights) # # identifier ::= astring # # rights ::= astring # # ==== Fields: # # user:: Login name that has certain rights to the mailbox # that was specified with the getacl command. # # rights:: The access rights the indicated user has to the # mailbox. # MailboxACLItem = Struct.new(:user, :rights) # Net::IMAP::StatusData represents contents of the STATUS response. # # ==== Fields: # # mailbox:: Returns the mailbox name. # # attr:: Returns a hash. Each key is one of "MESSAGES", "RECENT", "UIDNEXT", # "UIDVALIDITY", "UNSEEN". Each value is a number. # StatusData = Struct.new(:mailbox, :attr) # Net::IMAP::FetchData represents contents of the FETCH response. # # ==== Fields: # # seqno:: Returns the message sequence number. # (Note: not the unique identifier, even for the UID command response.) # # attr:: Returns a hash. Each key is a data item name, and each value is # its value. # # The current data items are: # # [BODY] # A form of BODYSTRUCTURE without extension data. # [BODY[
    ]<>] # A string expressing the body contents of the specified section. # [BODYSTRUCTURE] # An object that describes the [MIME-IMB] body structure of a message. # See Net::IMAP::BodyTypeBasic, Net::IMAP::BodyTypeText, # Net::IMAP::BodyTypeMessage, Net::IMAP::BodyTypeMultipart. # [ENVELOPE] # A Net::IMAP::Envelope object that describes the envelope # structure of a message. # [FLAGS] # A array of flag symbols that are set for this message. flag symbols # are capitalized by String#capitalize. # [INTERNALDATE] # A string representing the internal date of the message. # [RFC822] # Equivalent to BODY[]. # [RFC822.HEADER] # Equivalent to BODY.PEEK[HEADER]. # [RFC822.SIZE] # A number expressing the [RFC-822] size of the message. # [RFC822.TEXT] # Equivalent to BODY[TEXT]. # [UID] # A number expressing the unique identifier of the message. # FetchData = Struct.new(:seqno, :attr) # Net::IMAP::Envelope represents envelope structures of messages. # # ==== Fields: # # date:: Returns a string that represents the date. # # subject:: Returns a string that represents the subject. # # from:: Returns an array of Net::IMAP::Address that represents the from. # # sender:: Returns an array of Net::IMAP::Address that represents the sender. # # reply_to:: Returns an array of Net::IMAP::Address that represents the reply-to. # # to:: Returns an array of Net::IMAP::Address that represents the to. # # cc:: Returns an array of Net::IMAP::Address that represents the cc. # # bcc:: Returns an array of Net::IMAP::Address that represents the bcc. # # in_reply_to:: Returns a string that represents the in-reply-to. # # message_id:: Returns a string that represents the message-id. # Envelope = Struct.new(:date, :subject, :from, :sender, :reply_to, :to, :cc, :bcc, :in_reply_to, :message_id) # # Net::IMAP::Address represents electronic mail addresses. # # ==== Fields: # # name:: Returns the phrase from [RFC-822] mailbox. # # route:: Returns the route from [RFC-822] route-addr. # # mailbox:: nil indicates end of [RFC-822] group. # If non-nil and host is nil, returns [RFC-822] group name. # Otherwise, returns [RFC-822] local-part # # host:: nil indicates [RFC-822] group syntax. # Otherwise, returns [RFC-822] domain name. # Address = Struct.new(:name, :route, :mailbox, :host) # # Net::IMAP::ContentDisposition represents Content-Disposition fields. # # ==== Fields: # # dsp_type:: Returns the disposition type. # # param:: Returns a hash that represents parameters of the Content-Disposition # field. # ContentDisposition = Struct.new(:dsp_type, :param) # Net::IMAP::ThreadMember represents a thread-node returned # by Net::IMAP#thread # # ==== Fields: # # seqno:: The sequence number of this message. # # children:: an array of Net::IMAP::ThreadMember objects for mail # items that are children of this in the thread. # ThreadMember = Struct.new(:seqno, :children) # Net::IMAP::BodyTypeBasic represents basic body structures of messages. # # ==== Fields: # # media_type:: Returns the content media type name as defined in [MIME-IMB]. # # subtype:: Returns the content subtype name as defined in [MIME-IMB]. # # param:: Returns a hash that represents parameters as defined in [MIME-IMB]. # # content_id:: Returns a string giving the content id as defined in [MIME-IMB]. # # description:: Returns a string giving the content description as defined in # [MIME-IMB]. # # encoding:: Returns a string giving the content transfer encoding as defined in # [MIME-IMB]. # # size:: Returns a number giving the size of the body in octets. # # md5:: Returns a string giving the body MD5 value as defined in [MD5]. # # disposition:: Returns a Net::IMAP::ContentDisposition object giving # the content disposition. # # language:: Returns a string or an array of strings giving the body # language value as defined in [LANGUAGE-TAGS]. # # extension:: Returns extension data. # # multipart?:: Returns false. # class BodyTypeBasic < Struct.new(:media_type, :subtype, :param, :content_id, :description, :encoding, :size, :md5, :disposition, :language, :extension) def multipart? return false end # Obsolete: use +subtype+ instead. Calling this will # generate a warning message to +stderr+, then return # the value of +subtype+. def media_subtype $stderr.printf("warning: media_subtype is obsolete.\n") $stderr.printf(" use subtype instead.\n") return subtype end end # Net::IMAP::BodyTypeText represents TEXT body structures of messages. # # ==== Fields: # # lines:: Returns the size of the body in text lines. # # And Net::IMAP::BodyTypeText has all fields of Net::IMAP::BodyTypeBasic. # class BodyTypeText < Struct.new(:media_type, :subtype, :param, :content_id, :description, :encoding, :size, :lines, :md5, :disposition, :language, :extension) def multipart? return false end # Obsolete: use +subtype+ instead. Calling this will # generate a warning message to +stderr+, then return # the value of +subtype+. def media_subtype $stderr.printf("warning: media_subtype is obsolete.\n") $stderr.printf(" use subtype instead.\n") return subtype end end # Net::IMAP::BodyTypeMessage represents MESSAGE/RFC822 body structures of messages. # # ==== Fields: # # envelope:: Returns a Net::IMAP::Envelope giving the envelope structure. # # body:: Returns an object giving the body structure. # # And Net::IMAP::BodyTypeMessage has all methods of Net::IMAP::BodyTypeText. # class BodyTypeMessage < Struct.new(:media_type, :subtype, :param, :content_id, :description, :encoding, :size, :envelope, :body, :lines, :md5, :disposition, :language, :extension) def multipart? return false end # Obsolete: use +subtype+ instead. Calling this will # generate a warning message to +stderr+, then return # the value of +subtype+. def media_subtype $stderr.printf("warning: media_subtype is obsolete.\n") $stderr.printf(" use subtype instead.\n") return subtype end end # Net::IMAP::BodyTypeMultipart represents multipart body structures # of messages. # # ==== Fields: # # media_type:: Returns the content media type name as defined in [MIME-IMB]. # # subtype:: Returns the content subtype name as defined in [MIME-IMB]. # # parts:: Returns multiple parts. # # param:: Returns a hash that represents parameters as defined in [MIME-IMB]. # # disposition:: Returns a Net::IMAP::ContentDisposition object giving # the content disposition. # # language:: Returns a string or an array of strings giving the body # language value as defined in [LANGUAGE-TAGS]. # # extension:: Returns extension data. # # multipart?:: Returns true. # class BodyTypeMultipart < Struct.new(:media_type, :subtype, :parts, :param, :disposition, :language, :extension) def multipart? return true end # Obsolete: use +subtype+ instead. Calling this will # generate a warning message to +stderr+, then return # the value of +subtype+. def media_subtype $stderr.printf("warning: media_subtype is obsolete.\n") $stderr.printf(" use subtype instead.\n") return subtype end end class ResponseParser # :nodoc: def parse(str) @str = str @pos = 0 @lex_state = EXPR_BEG @token = nil return response end private EXPR_BEG = :EXPR_BEG EXPR_DATA = :EXPR_DATA EXPR_TEXT = :EXPR_TEXT EXPR_RTEXT = :EXPR_RTEXT EXPR_CTEXT = :EXPR_CTEXT T_SPACE = :SPACE T_NIL = :NIL T_NUMBER = :NUMBER T_ATOM = :ATOM T_QUOTED = :QUOTED T_LPAR = :LPAR T_RPAR = :RPAR T_BSLASH = :BSLASH T_STAR = :STAR T_LBRA = :LBRA T_RBRA = :RBRA T_LITERAL = :LITERAL T_PLUS = :PLUS T_PERCENT = :PERCENT T_CRLF = :CRLF T_EOF = :EOF T_TEXT = :TEXT BEG_REGEXP = /\G(?:\ (?# 1: SPACE )( +)|\ (?# 2: NIL )(NIL)(?=[\x80-\xff(){ \x00-\x1f\x7f%*"\\\[\]+])|\ (?# 3: NUMBER )(\d+)(?=[\x80-\xff(){ \x00-\x1f\x7f%*"\\\[\]+])|\ (?# 4: ATOM )([^\x80-\xff(){ \x00-\x1f\x7f%*"\\\[\]+]+)|\ (?# 5: QUOTED )"((?:[^\x00\r\n"\\]|\\["\\])*)"|\ (?# 6: LPAR )(\()|\ (?# 7: RPAR )(\))|\ (?# 8: BSLASH )(\\)|\ (?# 9: STAR )(\*)|\ (?# 10: LBRA )(\[)|\ (?# 11: RBRA )(\])|\ (?# 12: LITERAL )\{(\d+)\}\r\n|\ (?# 13: PLUS )(\+)|\ (?# 14: PERCENT )(%)|\ (?# 15: CRLF )(\r\n)|\ (?# 16: EOF )(\z))/ni DATA_REGEXP = /\G(?:\ (?# 1: SPACE )( )|\ (?# 2: NIL )(NIL)|\ (?# 3: NUMBER )(\d+)|\ (?# 4: QUOTED )"((?:[^\x00\r\n"\\]|\\["\\])*)"|\ (?# 5: LITERAL )\{(\d+)\}\r\n|\ (?# 6: LPAR )(\()|\ (?# 7: RPAR )(\)))/ni TEXT_REGEXP = /\G(?:\ (?# 1: TEXT )([^\x00\r\n]*))/ni RTEXT_REGEXP = /\G(?:\ (?# 1: LBRA )(\[)|\ (?# 2: TEXT )([^\x00\r\n]*))/ni CTEXT_REGEXP = /\G(?:\ (?# 1: TEXT )([^\x00\r\n\]]*))/ni Token = Struct.new(:symbol, :value) def response token = lookahead case token.symbol when T_PLUS result = continue_req when T_STAR result = response_untagged else result = response_tagged end match(T_CRLF) match(T_EOF) return result end def continue_req match(T_PLUS) match(T_SPACE) return ContinuationRequest.new(resp_text, @str) end def response_untagged match(T_STAR) match(T_SPACE) token = lookahead if token.symbol == T_NUMBER return numeric_response elsif token.symbol == T_ATOM case token.value when /\A(?:OK|NO|BAD|BYE|PREAUTH)\z/ni return response_cond when /\A(?:FLAGS)\z/ni return flags_response when /\A(?:LIST|LSUB)\z/ni return list_response when /\A(?:QUOTA)\z/ni return getquota_response when /\A(?:QUOTAROOT)\z/ni return getquotaroot_response when /\A(?:ACL)\z/ni return getacl_response when /\A(?:SEARCH|SORT)\z/ni return search_response when /\A(?:THREAD)\z/ni return thread_response when /\A(?:STATUS)\z/ni return status_response when /\A(?:CAPABILITY)\z/ni return capability_response else return text_response end else parse_error("unexpected token %s", token.symbol) end end def response_tagged tag = atom match(T_SPACE) token = match(T_ATOM) name = token.value.upcase match(T_SPACE) return TaggedResponse.new(tag, name, resp_text, @str) end def response_cond token = match(T_ATOM) name = token.value.upcase match(T_SPACE) return UntaggedResponse.new(name, resp_text, @str) end def numeric_response n = number match(T_SPACE) token = match(T_ATOM) name = token.value.upcase case name when "EXISTS", "RECENT", "EXPUNGE" return UntaggedResponse.new(name, n, @str) when "FETCH" shift_token match(T_SPACE) data = FetchData.new(n, msg_att) return UntaggedResponse.new(name, data, @str) end end def msg_att match(T_LPAR) attr = {} while true token = lookahead case token.symbol when T_RPAR shift_token break when T_SPACE shift_token token = lookahead end case token.value when /\A(?:ENVELOPE)\z/ni name, val = envelope_data when /\A(?:FLAGS)\z/ni name, val = flags_data when /\A(?:INTERNALDATE)\z/ni name, val = internaldate_data when /\A(?:RFC822(?:\.HEADER|\.TEXT)?)\z/ni name, val = rfc822_text when /\A(?:RFC822\.SIZE)\z/ni name, val = rfc822_size when /\A(?:BODY(?:STRUCTURE)?)\z/ni name, val = body_data when /\A(?:UID)\z/ni name, val = uid_data else parse_error("unknown attribute `%s'", token.value) end attr[name] = val end return attr end def envelope_data token = match(T_ATOM) name = token.value.upcase match(T_SPACE) return name, envelope end def envelope @lex_state = EXPR_DATA token = lookahead if token.symbol == T_NIL shift_token result = nil else match(T_LPAR) date = nstring match(T_SPACE) subject = nstring match(T_SPACE) from = address_list match(T_SPACE) sender = address_list match(T_SPACE) reply_to = address_list match(T_SPACE) to = address_list match(T_SPACE) cc = address_list match(T_SPACE) bcc = address_list match(T_SPACE) in_reply_to = nstring match(T_SPACE) message_id = nstring match(T_RPAR) result = Envelope.new(date, subject, from, sender, reply_to, to, cc, bcc, in_reply_to, message_id) end @lex_state = EXPR_BEG return result end def flags_data token = match(T_ATOM) name = token.value.upcase match(T_SPACE) return name, flag_list end def internaldate_data token = match(T_ATOM) name = token.value.upcase match(T_SPACE) token = match(T_QUOTED) return name, token.value end def rfc822_text token = match(T_ATOM) name = token.value.upcase match(T_SPACE) return name, nstring end def rfc822_size token = match(T_ATOM) name = token.value.upcase match(T_SPACE) return name, number end def body_data token = match(T_ATOM) name = token.value.upcase token = lookahead if token.symbol == T_SPACE shift_token return name, body end name.concat(section) token = lookahead if token.symbol == T_ATOM name.concat(token.value) shift_token end match(T_SPACE) data = nstring return name, data end def body @lex_state = EXPR_DATA token = lookahead if token.symbol == T_NIL shift_token result = nil else match(T_LPAR) token = lookahead if token.symbol == T_LPAR result = body_type_mpart else result = body_type_1part end match(T_RPAR) end @lex_state = EXPR_BEG return result end def body_type_1part token = lookahead case token.value when /\A(?:TEXT)\z/ni return body_type_text when /\A(?:MESSAGE)\z/ni return body_type_msg else return body_type_basic end end def body_type_basic mtype, msubtype = media_type token = lookahead if token.symbol == T_RPAR return BodyTypeBasic.new(mtype, msubtype) end match(T_SPACE) param, content_id, desc, enc, size = body_fields md5, disposition, language, extension = body_ext_1part return BodyTypeBasic.new(mtype, msubtype, param, content_id, desc, enc, size, md5, disposition, language, extension) end def body_type_text mtype, msubtype = media_type match(T_SPACE) param, content_id, desc, enc, size = body_fields match(T_SPACE) lines = number md5, disposition, language, extension = body_ext_1part return BodyTypeText.new(mtype, msubtype, param, content_id, desc, enc, size, lines, md5, disposition, language, extension) end def body_type_msg mtype, msubtype = media_type match(T_SPACE) param, content_id, desc, enc, size = body_fields match(T_SPACE) env = envelope match(T_SPACE) b = body match(T_SPACE) lines = number md5, disposition, language, extension = body_ext_1part return BodyTypeMessage.new(mtype, msubtype, param, content_id, desc, enc, size, env, b, lines, md5, disposition, language, extension) end def body_type_mpart parts = [] while true token = lookahead if token.symbol == T_SPACE shift_token break end parts.push(body) end mtype = "MULTIPART" msubtype = case_insensitive_string param, disposition, language, extension = body_ext_mpart return BodyTypeMultipart.new(mtype, msubtype, parts, param, disposition, language, extension) end def media_type mtype = case_insensitive_string match(T_SPACE) msubtype = case_insensitive_string return mtype, msubtype end def body_fields param = body_fld_param match(T_SPACE) content_id = nstring match(T_SPACE) desc = nstring match(T_SPACE) enc = case_insensitive_string match(T_SPACE) size = number return param, content_id, desc, enc, size end def body_fld_param token = lookahead if token.symbol == T_NIL shift_token return nil end match(T_LPAR) param = {} while true token = lookahead case token.symbol when T_RPAR shift_token break when T_SPACE shift_token end name = case_insensitive_string match(T_SPACE) val = string param[name] = val end return param end def body_ext_1part token = lookahead if token.symbol == T_SPACE shift_token else return nil end md5 = nstring token = lookahead if token.symbol == T_SPACE shift_token else return md5 end disposition = body_fld_dsp token = lookahead if token.symbol == T_SPACE shift_token else return md5, disposition end language = body_fld_lang token = lookahead if token.symbol == T_SPACE shift_token else return md5, disposition, language end extension = body_extensions return md5, disposition, language, extension end def body_ext_mpart token = lookahead if token.symbol == T_SPACE shift_token else return nil end param = body_fld_param token = lookahead if token.symbol == T_SPACE shift_token else return param end disposition = body_fld_dsp match(T_SPACE) language = body_fld_lang token = lookahead if token.symbol == T_SPACE shift_token else return param, disposition, language end extension = body_extensions return param, disposition, language, extension end def body_fld_dsp token = lookahead if token.symbol == T_NIL shift_token return nil end match(T_LPAR) dsp_type = case_insensitive_string match(T_SPACE) param = body_fld_param match(T_RPAR) return ContentDisposition.new(dsp_type, param) end def body_fld_lang token = lookahead if token.symbol == T_LPAR shift_token result = [] while true token = lookahead case token.symbol when T_RPAR shift_token return result when T_SPACE shift_token end result.push(case_insensitive_string) end else lang = nstring if lang return lang.upcase else return lang end end end def body_extensions result = [] while true token = lookahead case token.symbol when T_RPAR return result when T_SPACE shift_token end result.push(body_extension) end end def body_extension token = lookahead case token.symbol when T_LPAR shift_token result = body_extensions match(T_RPAR) return result when T_NUMBER return number else return nstring end end def section str = "" token = match(T_LBRA) str.concat(token.value) token = match(T_ATOM, T_NUMBER, T_RBRA) if token.symbol == T_RBRA str.concat(token.value) return str end str.concat(token.value) token = lookahead if token.symbol == T_SPACE shift_token str.concat(token.value) token = match(T_LPAR) str.concat(token.value) while true token = lookahead case token.symbol when T_RPAR str.concat(token.value) shift_token break when T_SPACE shift_token str.concat(token.value) end str.concat(format_string(astring)) end end token = match(T_RBRA) str.concat(token.value) return str end def format_string(str) case str when "" return '""' when /[\x80-\xff\r\n]/n # literal return "{" + str.length.to_s + "}" + CRLF + str when /[(){ \x00-\x1f\x7f%*"\\]/n # quoted string return '"' + str.gsub(/["\\]/n, "\\\\\\&") + '"' else # atom return str end end def uid_data token = match(T_ATOM) name = token.value.upcase match(T_SPACE) return name, number end def text_response token = match(T_ATOM) name = token.value.upcase match(T_SPACE) @lex_state = EXPR_TEXT token = match(T_TEXT) @lex_state = EXPR_BEG return UntaggedResponse.new(name, token.value) end def flags_response token = match(T_ATOM) name = token.value.upcase match(T_SPACE) return UntaggedResponse.new(name, flag_list, @str) end def list_response token = match(T_ATOM) name = token.value.upcase match(T_SPACE) return UntaggedResponse.new(name, mailbox_list, @str) end def mailbox_list attr = flag_list match(T_SPACE) token = match(T_QUOTED, T_NIL) if token.symbol == T_NIL delim = nil else delim = token.value end match(T_SPACE) name = astring return MailboxList.new(attr, delim, name) end def getquota_response # If quota never established, get back # `NO Quota root does not exist'. # If quota removed, get `()' after the # folder spec with no mention of `STORAGE'. token = match(T_ATOM) name = token.value.upcase match(T_SPACE) mailbox = astring match(T_SPACE) match(T_LPAR) token = lookahead case token.symbol when T_RPAR shift_token data = MailboxQuota.new(mailbox, nil, nil) return UntaggedResponse.new(name, data, @str) when T_ATOM shift_token match(T_SPACE) token = match(T_NUMBER) usage = token.value match(T_SPACE) token = match(T_NUMBER) quota = token.value match(T_RPAR) data = MailboxQuota.new(mailbox, usage, quota) return UntaggedResponse.new(name, data, @str) else parse_error("unexpected token %s", token.symbol) end end def getquotaroot_response # Similar to getquota, but only admin can use getquota. token = match(T_ATOM) name = token.value.upcase match(T_SPACE) mailbox = astring quotaroots = [] while true token = lookahead break unless token.symbol == T_SPACE shift_token quotaroots.push(astring) end data = MailboxQuotaRoot.new(mailbox, quotaroots) return UntaggedResponse.new(name, data, @str) end def getacl_response token = match(T_ATOM) name = token.value.upcase match(T_SPACE) mailbox = astring data = [] token = lookahead if token.symbol == T_SPACE shift_token while true token = lookahead case token.symbol when T_CRLF break when T_SPACE shift_token end user = astring match(T_SPACE) rights = astring ##XXX data.push([user, rights]) data.push(MailboxACLItem.new(user, rights)) end end return UntaggedResponse.new(name, data, @str) end def search_response token = match(T_ATOM) name = token.value.upcase token = lookahead if token.symbol == T_SPACE shift_token data = [] while true token = lookahead case token.symbol when T_CRLF break when T_SPACE shift_token end data.push(number) end else data = [] end return UntaggedResponse.new(name, data, @str) end def thread_response token = match(T_ATOM) name = token.value.upcase token = lookahead if token.symbol == T_SPACE threads = [] while true shift_token token = lookahead case token.symbol when T_LPAR threads << thread_branch(token) when T_CRLF break end end else # no member threads = [] end return UntaggedResponse.new(name, threads, @str) end def thread_branch(token) rootmember = nil lastmember = nil while true shift_token # ignore first T_LPAR token = lookahead case token.symbol when T_NUMBER # new member newmember = ThreadMember.new(number, []) if rootmember.nil? rootmember = newmember else lastmember.children << newmember end lastmember = newmember when T_SPACE # do nothing when T_LPAR if rootmember.nil? # dummy member lastmember = rootmember = ThreadMember.new(nil, []) end lastmember.children << thread_branch(token) when T_RPAR break end end return rootmember end def status_response token = match(T_ATOM) name = token.value.upcase match(T_SPACE) mailbox = astring match(T_SPACE) match(T_LPAR) attr = {} while true token = lookahead case token.symbol when T_RPAR shift_token break when T_SPACE shift_token end token = match(T_ATOM) key = token.value.upcase match(T_SPACE) val = number attr[key] = val end data = StatusData.new(mailbox, attr) return UntaggedResponse.new(name, data, @str) end def capability_response token = match(T_ATOM) name = token.value.upcase match(T_SPACE) data = [] while true token = lookahead case token.symbol when T_CRLF break when T_SPACE shift_token end data.push(atom.upcase) end return UntaggedResponse.new(name, data, @str) end def resp_text @lex_state = EXPR_RTEXT token = lookahead if token.symbol == T_LBRA code = resp_text_code else code = nil end token = match(T_TEXT) @lex_state = EXPR_BEG return ResponseText.new(code, token.value) end def resp_text_code @lex_state = EXPR_BEG match(T_LBRA) token = match(T_ATOM) name = token.value.upcase case name when /\A(?:ALERT|PARSE|READ-ONLY|READ-WRITE|TRYCREATE|NOMODSEQ)\z/n result = ResponseCode.new(name, nil) when /\A(?:PERMANENTFLAGS)\z/n match(T_SPACE) result = ResponseCode.new(name, flag_list) when /\A(?:UIDVALIDITY|UIDNEXT|UNSEEN)\z/n match(T_SPACE) result = ResponseCode.new(name, number) else token = lookahead if token.symbol == T_SPACE shift_token @lex_state = EXPR_CTEXT token = match(T_TEXT) @lex_state = EXPR_BEG result = ResponseCode.new(name, token.value) else result = ResponseCode.new(name, nil) end end match(T_RBRA) @lex_state = EXPR_RTEXT return result end def address_list token = lookahead if token.symbol == T_NIL shift_token return nil else result = [] match(T_LPAR) while true token = lookahead case token.symbol when T_RPAR shift_token break when T_SPACE shift_token end result.push(address) end return result end end ADDRESS_REGEXP = /\G\ (?# 1: NAME )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)") \ (?# 2: ROUTE )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)") \ (?# 3: MAILBOX )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)") \ (?# 4: HOST )(?:NIL|"((?:[^\x80-\xff\x00\r\n"\\]|\\["\\])*)")\ \)/ni def address match(T_LPAR) if @str.index(ADDRESS_REGEXP, @pos) # address does not include literal. @pos = $~.end(0) name = $1 route = $2 mailbox = $3 host = $4 for s in [name, route, mailbox, host] if s s.gsub!(/\\(["\\])/n, "\\1") end end else name = nstring match(T_SPACE) route = nstring match(T_SPACE) mailbox = nstring match(T_SPACE) host = nstring match(T_RPAR) end return Address.new(name, route, mailbox, host) end # def flag_list # result = [] # match(T_LPAR) # while true # token = lookahead # case token.symbol # when T_RPAR # shift_token # break # when T_SPACE # shift_token # end # result.push(flag) # end # return result # end # def flag # token = lookahead # if token.symbol == T_BSLASH # shift_token # token = lookahead # if token.symbol == T_STAR # shift_token # return token.value.intern # else # return atom.intern # end # else # return atom # end # end FLAG_REGEXP = /\ (?# FLAG )\\([^\x80-\xff(){ \x00-\x1f\x7f%"\\]+)|\ (?# ATOM )([^\x80-\xff(){ \x00-\x1f\x7f%*"\\]+)/n def flag_list if @str.index(/\(([^)]*)\)/ni, @pos) @pos = $~.end(0) return $1.scan(FLAG_REGEXP).collect { |flag, atom| atom || flag.capitalize.intern } else parse_error("invalid flag list") end end def nstring token = lookahead if token.symbol == T_NIL shift_token return nil else return string end end def astring token = lookahead if string_token?(token) return string else return atom end end def string token = lookahead if token.symbol == T_NIL shift_token return nil end token = match(T_QUOTED, T_LITERAL) return token.value end STRING_TOKENS = [T_QUOTED, T_LITERAL, T_NIL] def string_token?(token) return STRING_TOKENS.include?(token.symbol) end def case_insensitive_string token = lookahead if token.symbol == T_NIL shift_token return nil end token = match(T_QUOTED, T_LITERAL) return token.value.upcase end def atom result = "" while true token = lookahead if atom_token?(token) result.concat(token.value) shift_token else if result.empty? parse_error("unexpected token %s", token.symbol) else return result end end end end ATOM_TOKENS = [ T_ATOM, T_NUMBER, T_NIL, T_LBRA, T_RBRA, T_PLUS ] def atom_token?(token) return ATOM_TOKENS.include?(token.symbol) end def number token = lookahead if token.symbol == T_NIL shift_token return nil end token = match(T_NUMBER) return token.value.to_i end def nil_atom match(T_NIL) return nil end def match(*args) token = lookahead unless args.include?(token.symbol) parse_error('unexpected token %s (expected %s)', token.symbol.id2name, args.collect {|i| i.id2name}.join(" or ")) end shift_token return token end def lookahead unless @token @token = next_token end return @token end def shift_token @token = nil end def next_token case @lex_state when EXPR_BEG if @str.index(BEG_REGEXP, @pos) @pos = $~.end(0) if $1 return Token.new(T_SPACE, $+) elsif $2 return Token.new(T_NIL, $+) elsif $3 return Token.new(T_NUMBER, $+) elsif $4 return Token.new(T_ATOM, $+) elsif $5 return Token.new(T_QUOTED, $+.gsub(/\\(["\\])/n, "\\1")) elsif $6 return Token.new(T_LPAR, $+) elsif $7 return Token.new(T_RPAR, $+) elsif $8 return Token.new(T_BSLASH, $+) elsif $9 return Token.new(T_STAR, $+) elsif $10 return Token.new(T_LBRA, $+) elsif $11 return Token.new(T_RBRA, $+) elsif $12 len = $+.to_i val = @str[@pos, len] @pos += len return Token.new(T_LITERAL, val) elsif $13 return Token.new(T_PLUS, $+) elsif $14 return Token.new(T_PERCENT, $+) elsif $15 return Token.new(T_CRLF, $+) elsif $16 return Token.new(T_EOF, $+) else parse_error("[Net::IMAP BUG] BEG_REGEXP is invalid") end else @str.index(/\S*/n, @pos) parse_error("unknown token - %s", $&.dump) end when EXPR_DATA if @str.index(DATA_REGEXP, @pos) @pos = $~.end(0) if $1 return Token.new(T_SPACE, $+) elsif $2 return Token.new(T_NIL, $+) elsif $3 return Token.new(T_NUMBER, $+) elsif $4 return Token.new(T_QUOTED, $+.gsub(/\\(["\\])/n, "\\1")) elsif $5 len = $+.to_i val = @str[@pos, len] @pos += len return Token.new(T_LITERAL, val) elsif $6 return Token.new(T_LPAR, $+) elsif $7 return Token.new(T_RPAR, $+) else parse_error("[Net::IMAP BUG] DATA_REGEXP is invalid") end else @str.index(/\S*/n, @pos) parse_error("unknown token - %s", $&.dump) end when EXPR_TEXT if @str.index(TEXT_REGEXP, @pos) @pos = $~.end(0) if $1 return Token.new(T_TEXT, $+) else parse_error("[Net::IMAP BUG] TEXT_REGEXP is invalid") end else @str.index(/\S*/n, @pos) parse_error("unknown token - %s", $&.dump) end when EXPR_RTEXT if @str.index(RTEXT_REGEXP, @pos) @pos = $~.end(0) if $1 return Token.new(T_LBRA, $+) elsif $2 return Token.new(T_TEXT, $+) else parse_error("[Net::IMAP BUG] RTEXT_REGEXP is invalid") end else @str.index(/\S*/n, @pos) parse_error("unknown token - %s", $&.dump) end when EXPR_CTEXT if @str.index(CTEXT_REGEXP, @pos) @pos = $~.end(0) if $1 return Token.new(T_TEXT, $+) else parse_error("[Net::IMAP BUG] CTEXT_REGEXP is invalid") end else @str.index(/\S*/n, @pos) #/ parse_error("unknown token - %s", $&.dump) end else parse_error("illegal @lex_state - %s", @lex_state.inspect) end end def parse_error(fmt, *args) if IMAP.debug $stderr.printf("@str: %s\n", @str.dump) $stderr.printf("@pos: %d\n", @pos) $stderr.printf("@lex_state: %s\n", @lex_state) if @token $stderr.printf("@token.symbol: %s\n", @token.symbol) $stderr.printf("@token.value: %s\n", @token.value.inspect) end end raise ResponseParseError, format(fmt, *args) end end # Authenticator for the "LOGIN" authentication type. See # #authenticate(). class LoginAuthenticator def process(data) case @state when STATE_USER @state = STATE_PASSWORD return @user when STATE_PASSWORD return @password end end private STATE_USER = :USER STATE_PASSWORD = :PASSWORD def initialize(user, password) @user = user @password = password @state = STATE_USER end end add_authenticator "LOGIN", LoginAuthenticator # Authenticator for the "CRAM-MD5" authentication type. See # #authenticate(). class CramMD5Authenticator def process(challenge) digest = hmac_md5(challenge, @password) return @user + " " + digest end private def initialize(user, password) @user = user @password = password end def hmac_md5(text, key) if key.length > 64 key = Digest::MD5.digest(key) end k_ipad = key + "\0" * (64 - key.length) k_opad = key + "\0" * (64 - key.length) for i in 0..63 k_ipad[i] ^= 0x36 k_opad[i] ^= 0x5c end digest = Digest::MD5.digest(k_ipad + text) return Digest::MD5.hexdigest(k_opad + digest) end end add_authenticator "CRAM-MD5", CramMD5Authenticator # Superclass of IMAP errors. class Error < StandardError end # Error raised when data is in the incorrect format. class DataFormatError < Error end # Error raised when a response from the server is non-parseable. class ResponseParseError < Error end # Superclass of all errors used to encapsulate "fail" responses # from the server. class ResponseError < Error end # Error raised upon a "NO" response from the server, indicating # that the client command could not be completed successfully. class NoResponseError < ResponseError end # Error raised upon a "BAD" response from the server, indicating # that the client command violated the IMAP protocol, or an internal # server failure has occurred. class BadResponseError < ResponseError end # Error raised upon a "BYE" response from the server, indicating # that the client is not being allowed to login, or has been timed # out due to inactivity. class ByeResponseError < ResponseError end end end if __FILE__ == $0 # :enddoc: require "getoptlong" $stdout.sync = true $port = nil $user = ENV["USER"] || ENV["LOGNAME"] $auth = "login" $ssl = false def usage $stderr.print < --help print this message --port=PORT specifies port --user=USER specifies user --auth=AUTH specifies auth type --ssl use ssl EOF end def get_password print "password: " system("stty", "-echo") begin return gets.chop ensure system("stty", "echo") print "\n" end end def get_command printf("%s@%s> ", $user, $host) if line = gets return line.strip.split(/\s+/) else return nil end end parser = GetoptLong.new parser.set_options(['--debug', GetoptLong::NO_ARGUMENT], ['--help', GetoptLong::NO_ARGUMENT], ['--port', GetoptLong::REQUIRED_ARGUMENT], ['--user', GetoptLong::REQUIRED_ARGUMENT], ['--auth', GetoptLong::REQUIRED_ARGUMENT], ['--ssl', GetoptLong::NO_ARGUMENT]) begin parser.each_option do |name, arg| case name when "--port" $port = arg when "--user" $user = arg when "--auth" $auth = arg when "--ssl" $ssl = true when "--debug" Net::IMAP.debug = true when "--help" usage exit(1) end end rescue usage exit(1) end $host = ARGV.shift unless $host usage exit(1) end $port ||= $ssl ? 993 : 143 imap = Net::IMAP.new($host, $port, $ssl) begin password = get_password imap.authenticate($auth, $user, password) while true cmd, *args = get_command break unless cmd begin case cmd when "list" for mbox in imap.list("", args[0] || "*") if mbox.attr.include?(Net::IMAP::NOSELECT) prefix = "!" elsif mbox.attr.include?(Net::IMAP::MARKED) prefix = "*" else prefix = " " end print prefix, mbox.name, "\n" end when "select" imap.select(args[0] || "inbox") print "ok\n" when "close" imap.close print "ok\n" when "summary" unless messages = imap.responses["EXISTS"][-1] puts "not selected" next end if messages > 0 for data in imap.fetch(1..-1, ["ENVELOPE"]) print data.seqno, ": ", data.attr["ENVELOPE"].subject, "\n" end else puts "no message" end when "fetch" if args[0] data = imap.fetch(args[0].to_i, ["RFC822.HEADER", "RFC822.TEXT"])[0] puts data.attr["RFC822.HEADER"] puts data.attr["RFC822.TEXT"] else puts "missing argument" end when "logout", "exit", "quit" break when "help", "?" print <. # # Documented by William Webber and Minero Aoki. # # This program is free software. You can re-distribute and/or # modify this program under the same terms as Ruby itself, # Ruby Distribute License. # # NOTE: You can find Japanese version of this document at: # http://www.ruby-lang.org/ja/man/html/net_pop.html # # $Id: pop.rb 29903 2010-11-24 07:38:32Z shyouhei $ # # See Net::POP3 for documentation. # require 'net/protocol' require 'digest/md5' require 'timeout' begin require "openssl/ssl" rescue LoadError end module Net # Non-authentication POP3 protocol error # (reply code "-ERR", except authentication). class POPError < ProtocolError; end # POP3 authentication error. class POPAuthenticationError < ProtoAuthError; end # Unexpected response from the server. class POPBadResponse < POPError; end # # = Net::POP3 # # == What is This Library? # # This library provides functionality for retrieving # email via POP3, the Post Office Protocol version 3. For details # of POP3, see [RFC1939] (http://www.ietf.org/rfc/rfc1939.txt). # # == Examples # # === Retrieving Messages # # This example retrieves messages from the server and deletes them # on the server. # # Messages are written to files named 'inbox/1', 'inbox/2', .... # Replace 'pop.example.com' with your POP3 server address, and # 'YourAccount' and 'YourPassword' with the appropriate account # details. # # require 'net/pop' # # pop = Net::POP3.new('pop.example.com') # pop.start('YourAccount', 'YourPassword') # (1) # if pop.mails.empty? # puts 'No mail.' # else # i = 0 # pop.each_mail do |m| # or "pop.mails.each ..." # (2) # File.open("inbox/#{i}", 'w') do |f| # f.write m.pop # end # m.delete # i += 1 # end # puts "#{pop.mails.size} mails popped." # end # pop.finish # (3) # # 1. Call Net::POP3#start and start POP session. # 2. Access messages by using POP3#each_mail and/or POP3#mails. # 3. Close POP session by calling POP3#finish or use the block form of #start. # # === Shortened Code # # The example above is very verbose. You can shorten the code by using # some utility methods. First, the block form of Net::POP3.start can # be used instead of POP3.new, POP3#start and POP3#finish. # # require 'net/pop' # # Net::POP3.start('pop.example.com', 110, # 'YourAccount', 'YourPassword') do |pop| # if pop.mails.empty? # puts 'No mail.' # else # i = 0 # pop.each_mail do |m| # or "pop.mails.each ..." # File.open("inbox/#{i}", 'w') do |f| # f.write m.pop # end # m.delete # i += 1 # end # puts "#{pop.mails.size} mails popped." # end # end # # POP3#delete_all is an alternative for #each_mail and #delete. # # require 'net/pop' # # Net::POP3.start('pop.example.com', 110, # 'YourAccount', 'YourPassword') do |pop| # if pop.mails.empty? # puts 'No mail.' # else # i = 1 # pop.delete_all do |m| # File.open("inbox/#{i}", 'w') do |f| # f.write m.pop # end # i += 1 # end # end # end # # And here is an even shorter example. # # require 'net/pop' # # i = 0 # Net::POP3.delete_all('pop.example.com', 110, # 'YourAccount', 'YourPassword') do |m| # File.open("inbox/#{i}", 'w') do |f| # f.write m.pop # end # i += 1 # end # # === Memory Space Issues # # All the examples above get each message as one big string. # This example avoids this. # # require 'net/pop' # # i = 1 # Net::POP3.delete_all('pop.example.com', 110, # 'YourAccount', 'YourPassword') do |m| # File.open("inbox/#{i}", 'w') do |f| # m.pop do |chunk| # get a message little by little. # f.write chunk # end # i += 1 # end # end # # === Using APOP # # The net/pop library supports APOP authentication. # To use APOP, use the Net::APOP class instead of the Net::POP3 class. # You can use the utility method, Net::POP3.APOP(). For example: # # require 'net/pop' # # # Use APOP authentication if $isapop == true # pop = Net::POP3.APOP($is_apop).new('apop.example.com', 110) # pop.start(YourAccount', 'YourPassword') do |pop| # # Rest of the code is the same. # end # # === Fetch Only Selected Mail Using 'UIDL' POP Command # # If your POP server provides UIDL functionality, # you can grab only selected mails from the POP server. # e.g. # # def need_pop?( id ) # # determine if we need pop this mail... # end # # Net::POP3.start('pop.example.com', 110, # 'Your account', 'Your password') do |pop| # pop.mails.select { |m| need_pop?(m.unique_id) }.each do |m| # do_something(m.pop) # end # end # # The POPMail#unique_id() method returns the unique-id of the message as a # String. Normally the unique-id is a hash of the message. # class POP3 < Protocol Revision = %q$Revision: 29903 $.split[1] # # Class Parameters # def POP3.default_port default_pop3_port() end # The default port for POP3 connections, port 110 def POP3.default_pop3_port 110 end # The default port for POP3S connections, port 995 def POP3.default_pop3s_port 995 end def POP3.socket_type #:nodoc: obsolete Net::InternetMessageIO end # # Utilities # # Returns the APOP class if +isapop+ is true; otherwise, returns # the POP class. For example: # # # Example 1 # pop = Net::POP3::APOP($is_apop).new(addr, port) # # # Example 2 # Net::POP3::APOP($is_apop).start(addr, port) do |pop| # .... # end # def POP3.APOP(isapop) isapop ? APOP : POP3 end # Starts a POP3 session and iterates over each POPMail object, # yielding it to the +block+. # This method is equivalent to: # # Net::POP3.start(address, port, account, password) do |pop| # pop.each_mail do |m| # yield m # end # end # # This method raises a POPAuthenticationError if authentication fails. # # === Example # # Net::POP3.foreach('pop.example.com', 110, # 'YourAccount', 'YourPassword') do |m| # file.write m.pop # m.delete if $DELETE # end # def POP3.foreach(address, port = nil, account = nil, password = nil, isapop = false, &block) # :yields: message start(address, port, account, password, isapop) {|pop| pop.each_mail(&block) } end # Starts a POP3 session and deletes all messages on the server. # If a block is given, each POPMail object is yielded to it before # being deleted. # # This method raises a POPAuthenticationError if authentication fails. # # === Example # # Net::POP3.delete_all('pop.example.com', 110, # 'YourAccount', 'YourPassword') do |m| # file.write m.pop # end # def POP3.delete_all(address, port = nil, account = nil, password = nil, isapop = false, &block) start(address, port, account, password, isapop) {|pop| pop.delete_all(&block) } end # Opens a POP3 session, attempts authentication, and quits. # # This method raises POPAuthenticationError if authentication fails. # # === Example: normal POP3 # # Net::POP3.auth_only('pop.example.com', 110, # 'YourAccount', 'YourPassword') # # === Example: APOP # # Net::POP3.auth_only('pop.example.com', 110, # 'YourAccount', 'YourPassword', true) # def POP3.auth_only(address, port = nil, account = nil, password = nil, isapop = false) new(address, port, isapop).auth_only account, password end # Starts a pop3 session, attempts authentication, and quits. # This method must not be called while POP3 session is opened. # This method raises POPAuthenticationError if authentication fails. def auth_only(account, password) raise IOError, 'opening previously opened POP session' if started? start(account, password) { ; } end # # SSL # @ssl_params = nil # call-seq: # Net::POP.enable_ssl(params = {}) # # Enable SSL for all new instances. # +params+ is passed to OpenSSL::SSLContext#set_params. def POP3.enable_ssl(*args) @ssl_params = create_ssl_params(*args) end def POP3.create_ssl_params(verify_or_params = {}, certs = nil) begin params = verify_or_params.to_hash rescue NoMethodError params = {} params[:verify_mode] = verify_or_params if certs if File.file?(certs) params[:ca_file] = certs elsif File.directory?(certs) params[:ca_path] = certs end end end return params end # Disable SSL for all new instances. def POP3.disable_ssl @ssl_params = nil end def POP3.ssl_params return @ssl_params end def POP3.use_ssl? return !@ssl_params.nil? end def POP3.verify return @ssl_params[:verify_mode] end def POP3.certs return @ssl_params[:ca_file] || @ssl_params[:ca_path] end # # Session management # # Creates a new POP3 object and open the connection. Equivalent to # # Net::POP3.new(address, port, isapop).start(account, password) # # If +block+ is provided, yields the newly-opened POP3 object to it, # and automatically closes it at the end of the session. # # === Example # # Net::POP3.start(addr, port, account, password) do |pop| # pop.each_mail do |m| # file.write m.pop # m.delete # end # end # def POP3.start(address, port = nil, account = nil, password = nil, isapop = false, &block) # :yield: pop new(address, port, isapop).start(account, password, &block) end # Creates a new POP3 object. # # +address+ is the hostname or ip address of your POP3 server. # # The optional +port+ is the port to connect to. # # The optional +isapop+ specifies whether this connection is going # to use APOP authentication; it defaults to +false+. # # This method does *not* open the TCP connection. def initialize(addr, port = nil, isapop = false) @address = addr @ssl_params = POP3.ssl_params @port = port @apop = isapop @command = nil @socket = nil @started = false @open_timeout = 30 @read_timeout = 60 @debug_output = nil @mails = nil @n_mails = nil @n_bytes = nil end # Does this instance use APOP authentication? def apop? @apop end # does this instance use SSL? def use_ssl? return !@ssl_params.nil? end # call-seq: # Net::POP#enable_ssl(params = {}) # # Enables SSL for this instance. Must be called before the connection is # established to have any effect. # +params[:port]+ is port to establish the SSL connection on; Defaults to 995. # +params+ (except :port) is passed to OpenSSL::SSLContext#set_params. def enable_ssl(verify_or_params = {}, certs = nil, port = nil) begin @ssl_params = verify_or_params.to_hash.dup @port = @ssl_params.delete(:port) || @port rescue NoMethodError @ssl_params = POP3.create_ssl_params(verify_or_params, certs) @port = port || @port end end def disable_ssl @ssl_params = nil end # Provide human-readable stringification of class state. def inspect "#<#{self.class} #{@address}:#{@port} open=#{@started}>" end # *WARNING*: This method causes a serious security hole. # Use this method only for debugging. # # Set an output stream for debugging. # # === Example # # pop = Net::POP.new(addr, port) # pop.set_debug_output $stderr # pop.start(account, passwd) do |pop| # .... # end # def set_debug_output(arg) @debug_output = arg end # The address to connect to. attr_reader :address # The port number to connect to. def port return @port || (use_ssl? ? POP3.default_pop3s_port : POP3.default_pop3_port) end # Seconds to wait until a connection is opened. # If the POP3 object cannot open a connection within this time, # it raises a TimeoutError exception. attr_accessor :open_timeout # Seconds to wait until reading one block (by one read(1) call). # If the POP3 object cannot complete a read() within this time, # it raises a TimeoutError exception. attr_reader :read_timeout # Set the read timeout. def read_timeout=(sec) @command.socket.read_timeout = sec if @command @read_timeout = sec end # +true+ if the POP3 session has started. def started? @started end alias active? started? #:nodoc: obsolete # Starts a POP3 session. # # When called with block, gives a POP3 object to the block and # closes the session after block call finishes. # # This method raises a POPAuthenticationError if authentication fails. def start(account, password) # :yield: pop raise IOError, 'POP session already started' if @started if block_given? begin do_start account, password return yield(self) ensure do_finish end else do_start account, password return self end end def do_start(account, password) s = timeout(@open_timeout) { TCPSocket.open(@address, port) } if use_ssl? raise 'openssl library not installed' unless defined?(OpenSSL) context = OpenSSL::SSL::SSLContext.new context.set_params(@ssl_params) s = OpenSSL::SSL::SSLSocket.new(s, context) s.sync_close = true s.connect if context.verify_mode != OpenSSL::SSL::VERIFY_NONE s.post_connection_check(@address) end end @socket = InternetMessageIO.new(s) logging "POP session started: #{@address}:#{@port} (#{@apop ? 'APOP' : 'POP'})" @socket.read_timeout = @read_timeout @socket.debug_output = @debug_output on_connect @command = POP3Command.new(@socket) if apop? @command.apop account, password else @command.auth account, password end @started = true ensure # Authentication failed, clean up connection. unless @started s.close if s and not s.closed? @socket = nil @command = nil end end private :do_start def on_connect end private :on_connect # Finishes a POP3 session and closes TCP connection. def finish raise IOError, 'POP session not yet started' unless started? do_finish end def do_finish @mails = nil @n_mails = nil @n_bytes = nil @command.quit if @command ensure @started = false @command = nil @socket.close if @socket and not @socket.closed? @socket = nil end private :do_finish def command raise IOError, 'POP session not opened yet' \ if not @socket or @socket.closed? @command end private :command # # POP protocol wrapper # # Returns the number of messages on the POP server. def n_mails return @n_mails if @n_mails @n_mails, @n_bytes = command().stat @n_mails end # Returns the total size in bytes of all the messages on the POP server. def n_bytes return @n_bytes if @n_bytes @n_mails, @n_bytes = command().stat @n_bytes end # Returns an array of Net::POPMail objects, representing all the # messages on the server. This array is renewed when the session # restarts; otherwise, it is fetched from the server the first time # this method is called (directly or indirectly) and cached. # # This method raises a POPError if an error occurs. def mails return @mails.dup if @mails if n_mails() == 0 # some popd raises error for LIST on the empty mailbox. @mails = [] return [] end @mails = command().list.map {|num, size| POPMail.new(num, size, self, command()) } @mails.dup end # Yields each message to the passed-in block in turn. # Equivalent to: # # pop3.mails.each do |popmail| # .... # end # # This method raises a POPError if an error occurs. def each_mail(&block) # :yield: message mails().each(&block) end alias each each_mail # Deletes all messages on the server. # # If called with a block, yields each message in turn before deleting it. # # === Example # # n = 1 # pop.delete_all do |m| # File.open("inbox/#{n}") do |f| # f.write m.pop # end # n += 1 # end # # This method raises a POPError if an error occurs. # def delete_all # :yield: message mails().each do |m| yield m if block_given? m.delete unless m.deleted? end end # Resets the session. This clears all "deleted" marks from messages. # # This method raises a POPError if an error occurs. def reset command().rset mails().each do |m| m.instance_eval { @deleted = false } end end def set_all_uids #:nodoc: internal use only (called from POPMail#uidl) uidl = command().uidl @mails.each {|m| m.uid = uidl[m.number] } end def logging(msg) @debug_output << msg + "\n" if @debug_output end end # class POP3 # class aliases POP = POP3 POPSession = POP3 POP3Session = POP3 # # This class is equivalent to POP3, except that it uses APOP authentication. # class APOP < POP3 # Always returns true. def apop? true end end # class aliases APOPSession = APOP # # This class represents a message which exists on the POP server. # Instances of this class are created by the POP3 class; they should # not be directly created by the user. # class POPMail def initialize(num, len, pop, cmd) #:nodoc: @number = num @length = len @pop = pop @command = cmd @deleted = false @uid = nil end # The sequence number of the message on the server. attr_reader :number # The length of the message in octets. attr_reader :length alias size length # Provide human-readable stringification of class state. def inspect "#<#{self.class} #{@number}#{@deleted ? ' deleted' : ''}>" end # # This method fetches the message. If called with a block, the # message is yielded to the block one chunk at a time. If called # without a block, the message is returned as a String. The optional # +dest+ argument will be prepended to the returned String; this # argument is essentially obsolete. # # === Example without block # # POP3.start('pop.example.com', 110, # 'YourAccount, 'YourPassword') do |pop| # n = 1 # pop.mails.each do |popmail| # File.open("inbox/#{n}", 'w') do |f| # f.write popmail.pop # end # popmail.delete # n += 1 # end # end # # === Example with block # # POP3.start('pop.example.com', 110, # 'YourAccount, 'YourPassword') do |pop| # n = 1 # pop.mails.each do |popmail| # File.open("inbox/#{n}", 'w') do |f| # popmail.pop do |chunk| #### # f.write chunk # end # end # n += 1 # end # end # # This method raises a POPError if an error occurs. # def pop( dest = '', &block ) # :yield: message_chunk if block_given? @command.retr(@number, &block) nil else @command.retr(@number) do |chunk| dest << chunk end dest end end alias all pop #:nodoc: obsolete alias mail pop #:nodoc: obsolete # Fetches the message header and +lines+ lines of body. # # The optional +dest+ argument is obsolete. # # This method raises a POPError if an error occurs. def top(lines, dest = '') @command.top(@number, lines) do |chunk| dest << chunk end dest end # Fetches the message header. # # The optional +dest+ argument is obsolete. # # This method raises a POPError if an error occurs. def header(dest = '') top(0, dest) end # Marks a message for deletion on the server. Deletion does not # actually occur until the end of the session; deletion may be # cancelled for _all_ marked messages by calling POP3#reset(). # # This method raises a POPError if an error occurs. # # === Example # # POP3.start('pop.example.com', 110, # 'YourAccount, 'YourPassword') do |pop| # n = 1 # pop.mails.each do |popmail| # File.open("inbox/#{n}", 'w') do |f| # f.write popmail.pop # end # popmail.delete #### # n += 1 # end # end # def delete @command.dele @number @deleted = true end alias delete! delete #:nodoc: obsolete # True if the mail has been deleted. def deleted? @deleted end # Returns the unique-id of the message. # Normally the unique-id is a hash string of the message. # # This method raises a POPError if an error occurs. def unique_id return @uid if @uid @pop.set_all_uids @uid end alias uidl unique_id def uid=(uid) #:nodoc: internal use only @uid = uid end end # class POPMail class POP3Command #:nodoc: internal use only def initialize(sock) @socket = sock @error_occured = false res = check_response(critical { recv_response() }) @apop_stamp = res.slice(/<[!-~]+@[!-~]+>/) end def inspect "#<#{self.class} socket=#{@socket}>" end def auth(account, password) check_response_auth(critical { check_response_auth(get_response('USER %s', account)) get_response('PASS %s', password) }) end def apop(account, password) raise POPAuthenticationError, 'not APOP server; cannot login' \ unless @apop_stamp check_response_auth(critical { get_response('APOP %s %s', account, Digest::MD5.hexdigest(@apop_stamp + password)) }) end def list critical { getok 'LIST' list = [] @socket.each_list_item do |line| m = /\A(\d+)[ \t]+(\d+)/.match(line) or raise POPBadResponse, "bad response: #{line}" list.push [m[1].to_i, m[2].to_i] end return list } end def stat res = check_response(critical { get_response('STAT') }) m = /\A\+OK\s+(\d+)\s+(\d+)/.match(res) or raise POPBadResponse, "wrong response format: #{res}" [m[1].to_i, m[2].to_i] end def rset check_response(critical { get_response('RSET') }) end def top(num, lines = 0, &block) critical { getok('TOP %d %d', num, lines) @socket.each_message_chunk(&block) } end def retr(num, &block) critical { getok('RETR %d', num) @socket.each_message_chunk(&block) } end def dele(num) check_response(critical { get_response('DELE %d', num) }) end def uidl(num = nil) if num res = check_response(critical { get_response('UIDL %d', num) }) return res.split(/ /)[1] else critical { getok('UIDL') table = {} @socket.each_list_item do |line| num, uid = line.split table[num.to_i] = uid end return table } end end def quit check_response(critical { get_response('QUIT') }) end private def getok(fmt, *fargs) @socket.writeline sprintf(fmt, *fargs) check_response(recv_response()) end def get_response(fmt, *fargs) @socket.writeline sprintf(fmt, *fargs) recv_response() end def recv_response @socket.readline end def check_response(res) raise POPError, res unless /\A\+OK/i =~ res res end def check_response_auth(res) raise POPAuthenticationError, res unless /\A\+OK/i =~ res res end def critical return '+OK dummy ok response' if @error_occured begin return yield() rescue Exception @error_occured = true raise end end end # class POP3Command end # module Net PK|]e;V;V net/ftp.rbnu[# # = net/ftp.rb - FTP Client Library # # Written by Shugo Maeda . # # Documentation by Gavin Sinclair, sourced from "Programming Ruby" (Hunt/Thomas) # and "Ruby In a Nutshell" (Matsumoto), used with permission. # # This library is distributed under the terms of the Ruby license. # You can freely distribute/modify this library. # # It is included in the Ruby standard library. # # See the Net::FTP class for an overview. # require "socket" require "monitor" module Net # :stopdoc: class FTPError < StandardError; end class FTPReplyError < FTPError; end class FTPTempError < FTPError; end class FTPPermError < FTPError; end class FTPProtoError < FTPError; end # :startdoc: # # This class implements the File Transfer Protocol. If you have used a # command-line FTP program, and are familiar with the commands, you will be # able to use this class easily. Some extra features are included to take # advantage of Ruby's style and strengths. # # == Example # # require 'net/ftp' # # === Example 1 # # ftp = Net::FTP.new('ftp.netlab.co.jp') # ftp.login # files = ftp.chdir('pub/lang/ruby/contrib') # files = ftp.list('n*') # ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024) # ftp.close # # === Example 2 # # Net::FTP.open('ftp.netlab.co.jp') do |ftp| # ftp.login # files = ftp.chdir('pub/lang/ruby/contrib') # files = ftp.list('n*') # ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024) # end # # == Major Methods # # The following are the methods most likely to be useful to users: # - FTP.open # - #getbinaryfile # - #gettextfile # - #putbinaryfile # - #puttextfile # - #chdir # - #nlst # - #size # - #rename # - #delete # class FTP include MonitorMixin # :stopdoc: FTP_PORT = 21 CRLF = "\r\n" DEFAULT_BLOCKSIZE = 4096 # :startdoc: # When +true+, transfers are performed in binary mode. Default: +true+. attr_accessor :binary # When +true+, the connection is in passive mode. Default: +false+. attr_accessor :passive # When +true+, all traffic to and from the server is written # to +$stdout+. Default: +false+. attr_accessor :debug_mode # Sets or retrieves the +resume+ status, which decides whether incomplete # transfers are resumed or restarted. Default: +false+. attr_accessor :resume # The server's welcome message. attr_reader :welcome # The server's last response code. attr_reader :last_response_code alias lastresp last_response_code # The server's last response. attr_reader :last_response # # A synonym for FTP.new, but with a mandatory host parameter. # # If a block is given, it is passed the +FTP+ object, which will be closed # when the block finishes, or when an exception is raised. # def FTP.open(host, user = nil, passwd = nil, acct = nil) if block_given? ftp = new(host, user, passwd, acct) begin yield ftp ensure ftp.close end else new(host, user, passwd, acct) end end # # Creates and returns a new +FTP+ object. If a +host+ is given, a connection # is made. Additionally, if the +user+ is given, the given user name, # password, and (optionally) account are used to log in. See #login. # def initialize(host = nil, user = nil, passwd = nil, acct = nil) super() @binary = true @passive = false @debug_mode = false @resume = false if host connect(host) if user login(user, passwd, acct) end end end # Obsolete def return_code $stderr.puts("warning: Net::FTP#return_code is obsolete and do nothing") return "\n" end # Obsolete def return_code=(s) $stderr.puts("warning: Net::FTP#return_code= is obsolete and do nothing") end def open_socket(host, port) if defined? SOCKSSocket and ENV["SOCKS_SERVER"] @passive = true return SOCKSSocket.open(host, port) else return TCPSocket.open(host, port) end end private :open_socket # # Establishes an FTP connection to host, optionally overriding the default # port. If the environment variable +SOCKS_SERVER+ is set, sets up the # connection through a SOCKS proxy. Raises an exception (typically # Errno::ECONNREFUSED) if the connection cannot be established. # def connect(host, port = FTP_PORT) if @debug_mode print "connect: ", host, ", ", port, "\n" end synchronize do @sock = open_socket(host, port) voidresp end end # # WRITEME or make private # def set_socket(sock, get_greeting = true) synchronize do @sock = sock if get_greeting voidresp end end end def sanitize(s) if s =~ /^PASS /i return s[0, 5] + "*" * (s.length - 5) else return s end end private :sanitize def putline(line) if @debug_mode print "put: ", sanitize(line), "\n" end line = line + CRLF @sock.write(line) end private :putline def getline line = @sock.readline # if get EOF, raise EOFError line.sub!(/(\r\n|\n|\r)\z/n, "") if @debug_mode print "get: ", sanitize(line), "\n" end return line end private :getline def getmultiline line = getline buff = line if line[3] == ?- code = line[0, 3] begin line = getline buff << "\n" << line end until line[0, 3] == code and line[3] != ?- end return buff << "\n" end private :getmultiline def getresp @last_response = getmultiline @last_response_code = @last_response[0, 3] case @last_response_code when /\A[123]/ return @last_response when /\A4/ raise FTPTempError, @last_response when /\A5/ raise FTPPermError, @last_response else raise FTPProtoError, @last_response end end private :getresp def voidresp resp = getresp if resp[0] != ?2 raise FTPReplyError, resp end end private :voidresp # # Sends a command and returns the response. # def sendcmd(cmd) synchronize do putline(cmd) return getresp end end # # Sends a command and expect a response beginning with '2'. # def voidcmd(cmd) synchronize do putline(cmd) voidresp end end def sendport(host, port) af = (@sock.peeraddr)[0] if af == "AF_INET" cmd = "PORT " + (host.split(".") + port.divmod(256)).join(",") elsif af == "AF_INET6" cmd = sprintf("EPRT |2|%s|%d|", host, port) else raise FTPProtoError, host end voidcmd(cmd) end private :sendport def makeport sock = TCPServer.open(@sock.addr[3], 0) port = sock.addr[1] host = sock.addr[3] resp = sendport(host, port) return sock end private :makeport def makepasv if @sock.peeraddr[0] == "AF_INET" host, port = parse227(sendcmd("PASV")) else host, port = parse229(sendcmd("EPSV")) # host, port = parse228(sendcmd("LPSV")) end return host, port end private :makepasv def transfercmd(cmd, rest_offset = nil) if @passive host, port = makepasv conn = open_socket(host, port) if @resume and rest_offset resp = sendcmd("REST " + rest_offset.to_s) if resp[0] != ?3 raise FTPReplyError, resp end end resp = sendcmd(cmd) # skip 2XX for some ftp servers resp = getresp if resp[0] == ?2 if resp[0] != ?1 raise FTPReplyError, resp end else sock = makeport if @resume and rest_offset resp = sendcmd("REST " + rest_offset.to_s) if resp[0] != ?3 raise FTPReplyError, resp end end resp = sendcmd(cmd) # skip 2XX for some ftp servers resp = getresp if resp[0] == ?2 if resp[0] != ?1 raise FTPReplyError, resp end conn = sock.accept sock.close end return conn end private :transfercmd def getaddress thishost = Socket.gethostname rescue "" if not thishost.index(".") thishost = Socket.gethostbyname(thishost)[0] rescue "" end if ENV.has_key?("LOGNAME") realuser = ENV["LOGNAME"] elsif ENV.has_key?("USER") realuser = ENV["USER"] else realuser = "anonymous" end return realuser + "@" + thishost end private :getaddress # # Logs in to the remote host. The session must have been previously # connected. If +user+ is the string "anonymous" and the +password+ is # +nil+, a password of user@host is synthesized. If the +acct+ # parameter is not +nil+, an FTP ACCT command is sent following the # successful login. Raises an exception on error (typically # Net::FTPPermError). # def login(user = "anonymous", passwd = nil, acct = nil) if user == "anonymous" and passwd == nil passwd = getaddress end resp = "" synchronize do resp = sendcmd('USER ' + user) if resp[0] == ?3 raise FTPReplyError, resp if passwd.nil? resp = sendcmd('PASS ' + passwd) end if resp[0] == ?3 raise FTPReplyError, resp if acct.nil? resp = sendcmd('ACCT ' + acct) end end if resp[0] != ?2 raise FTPReplyError, resp end @welcome = resp end # # Puts the connection into binary (image) mode, issues the given command, # and fetches the data returned, passing it to the associated block in # chunks of +blocksize+ characters. Note that +cmd+ is a server command # (such as "RETR myfile"). # def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data synchronize do voidcmd("TYPE I") conn = transfercmd(cmd, rest_offset) loop do data = conn.read(blocksize) break if data == nil yield(data) end conn.close voidresp end end # # Puts the connection into ASCII (text) mode, issues the given command, and # passes the resulting data, one line at a time, to the associated block. If # no block is given, prints the lines. Note that +cmd+ is a server command # (such as "RETR myfile"). # def retrlines(cmd) # :yield: line synchronize do voidcmd("TYPE A") conn = transfercmd(cmd) loop do line = conn.gets break if line == nil if line[-2, 2] == CRLF line = line[0 .. -3] elsif line[-1] == ?\n line = line[0 .. -2] end yield(line) end conn.close voidresp end end # # Puts the connection into binary (image) mode, issues the given server-side # command (such as "STOR myfile"), and sends the contents of the file named # +file+ to the server. If the optional block is given, it also passes it # the data, in chunks of +blocksize+ characters. # def storbinary(cmd, file, blocksize, rest_offset = nil, &block) # :yield: data if rest_offset file.seek(rest_offset, IO::SEEK_SET) end synchronize do voidcmd("TYPE I") conn = transfercmd(cmd, rest_offset) loop do buf = file.read(blocksize) break if buf == nil conn.write(buf) yield(buf) if block end conn.close voidresp end end # # Puts the connection into ASCII (text) mode, issues the given server-side # command (such as "STOR myfile"), and sends the contents of the file # named +file+ to the server, one line at a time. If the optional block is # given, it also passes it the lines. # def storlines(cmd, file, &block) # :yield: line synchronize do voidcmd("TYPE A") conn = transfercmd(cmd) loop do buf = file.gets break if buf == nil if buf[-2, 2] != CRLF buf = buf.chomp + CRLF end conn.write(buf) yield(buf) if block end conn.close voidresp end end # # Retrieves +remotefile+ in binary mode, storing the result in +localfile+. # If a block is supplied, it is passed the retrieved data in +blocksize+ # chunks. # def getbinaryfile(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data if @resume rest_offset = File.size?(localfile) f = open(localfile, "a") else rest_offset = nil f = open(localfile, "w") end begin f.binmode retrbinary("RETR " + remotefile, blocksize, rest_offset) do |data| f.write(data) yield(data) if block end ensure f.close end end # # Retrieves +remotefile+ in ASCII (text) mode, storing the result in # +localfile+. If a block is supplied, it is passed the retrieved data one # line at a time. # def gettextfile(remotefile, localfile = File.basename(remotefile), &block) # :yield: line f = open(localfile, "w") begin retrlines("RETR " + remotefile) do |line| f.puts(line) yield(line) if block end ensure f.close end end # # Retrieves +remotefile+ in whatever mode the session is set (text or # binary). See #gettextfile and #getbinaryfile. # def get(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data unless @binary gettextfile(remotefile, localfile, &block) else getbinaryfile(remotefile, localfile, blocksize, &block) end end # # Transfers +localfile+ to the server in binary mode, storing the result in # +remotefile+. If a block is supplied, calls it, passing in the transmitted # data in +blocksize+ chunks. # def putbinaryfile(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data if @resume begin rest_offset = size(remotefile) rescue Net::FTPPermError rest_offset = nil end else rest_offset = nil end f = open(localfile) begin f.binmode storbinary("STOR " + remotefile, f, blocksize, rest_offset, &block) ensure f.close end end # # Transfers +localfile+ to the server in ASCII (text) mode, storing the result # in +remotefile+. If callback or an associated block is supplied, calls it, # passing in the transmitted data one line at a time. # def puttextfile(localfile, remotefile = File.basename(localfile), &block) # :yield: line f = open(localfile) begin storlines("STOR " + remotefile, f, &block) ensure f.close end end # # Transfers +localfile+ to the server in whatever mode the session is set # (text or binary). See #puttextfile and #putbinaryfile. # def put(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block) unless @binary puttextfile(localfile, remotefile, &block) else putbinaryfile(localfile, remotefile, blocksize, &block) end end # # Sends the ACCT command. TODO: more info. # def acct(account) cmd = "ACCT " + account voidcmd(cmd) end # # Returns an array of filenames in the remote directory. # def nlst(dir = nil) cmd = "NLST" if dir cmd = cmd + " " + dir end files = [] retrlines(cmd) do |line| files.push(line) end return files end # # Returns an array of file information in the directory (the output is like # `ls -l`). If a block is given, it iterates through the listing. # def list(*args, &block) # :yield: line cmd = "LIST" args.each do |arg| cmd = cmd + " " + arg end if block retrlines(cmd, &block) else lines = [] retrlines(cmd) do |line| lines << line end return lines end end alias ls list alias dir list # # Renames a file on the server. # def rename(fromname, toname) resp = sendcmd("RNFR " + fromname) if resp[0] != ?3 raise FTPReplyError, resp end voidcmd("RNTO " + toname) end # # Deletes a file on the server. # def delete(filename) resp = sendcmd("DELE " + filename) if resp[0, 3] == "250" return elsif resp[0] == ?5 raise FTPPermError, resp else raise FTPReplyError, resp end end # # Changes the (remote) directory. # def chdir(dirname) if dirname == ".." begin voidcmd("CDUP") return rescue FTPPermError => e if e.message[0, 3] != "500" raise e end end end cmd = "CWD " + dirname voidcmd(cmd) end # # Returns the size of the given (remote) filename. # def size(filename) voidcmd("TYPE I") resp = sendcmd("SIZE " + filename) if resp[0, 3] != "213" raise FTPReplyError, resp end return resp[3..-1].strip.to_i end MDTM_REGEXP = /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/ # :nodoc: # # Returns the last modification time of the (remote) file. If +local+ is # +true+, it is returned as a local time, otherwise it's a UTC time. # def mtime(filename, local = false) str = mdtm(filename) ary = str.scan(MDTM_REGEXP)[0].collect {|i| i.to_i} return local ? Time.local(*ary) : Time.gm(*ary) end # # Creates a remote directory. # def mkdir(dirname) resp = sendcmd("MKD " + dirname) return parse257(resp) end # # Removes a remote directory. # def rmdir(dirname) voidcmd("RMD " + dirname) end # # Returns the current remote directory. # def pwd resp = sendcmd("PWD") return parse257(resp) end alias getdir pwd # # Returns system information. # def system resp = sendcmd("SYST") if resp[0, 3] != "215" raise FTPReplyError, resp end return resp[4 .. -1] end # # Aborts the previous command (ABOR command). # def abort line = "ABOR" + CRLF print "put: ABOR\n" if @debug_mode @sock.send(line, Socket::MSG_OOB) resp = getmultiline unless ["426", "226", "225"].include?(resp[0, 3]) raise FTPProtoError, resp end return resp end # # Returns the status (STAT command). # def status line = "STAT" + CRLF print "put: STAT\n" if @debug_mode @sock.send(line, Socket::MSG_OOB) return getresp end # # Issues the MDTM command. TODO: more info. # def mdtm(filename) resp = sendcmd("MDTM " + filename) if resp[0, 3] == "213" return resp[3 .. -1].strip end end # # Issues the HELP command. # def help(arg = nil) cmd = "HELP" if arg cmd = cmd + " " + arg end sendcmd(cmd) end # # Exits the FTP session. # def quit voidcmd("QUIT") end # # Issues a NOOP command. # def noop voidcmd("NOOP") end # # Issues a SITE command. # def site(arg) cmd = "SITE " + arg voidcmd(cmd) end # # Closes the connection. Further operations are impossible until you open # a new connection with #connect. # def close @sock.close if @sock and not @sock.closed? end # # Returns +true+ iff the connection is closed. # def closed? @sock == nil or @sock.closed? end def parse227(resp) if resp[0, 3] != "227" raise FTPReplyError, resp end left = resp.index("(") right = resp.index(")") if left == nil or right == nil raise FTPProtoError, resp end numbers = resp[left + 1 .. right - 1].split(",") if numbers.length != 6 raise FTPProtoError, resp end host = numbers[0, 4].join(".") port = (numbers[4].to_i << 8) + numbers[5].to_i return host, port end private :parse227 def parse228(resp) if resp[0, 3] != "228" raise FTPReplyError, resp end left = resp.index("(") right = resp.index(")") if left == nil or right == nil raise FTPProtoError, resp end numbers = resp[left + 1 .. right - 1].split(",") if numbers[0] == "4" if numbers.length != 9 || numbers[1] != "4" || numbers[2 + 4] != "2" raise FTPProtoError, resp end host = numbers[2, 4].join(".") port = (numbers[7].to_i << 8) + numbers[8].to_i elsif numbers[0] == "6" if numbers.length != 21 || numbers[1] != "16" || numbers[2 + 16] != "2" raise FTPProtoError, resp end v6 = ["", "", "", "", "", "", "", ""] for i in 0 .. 7 v6[i] = sprintf("%02x%02x", numbers[(i * 2) + 2].to_i, numbers[(i * 2) + 3].to_i) end host = v6[0, 8].join(":") port = (numbers[19].to_i << 8) + numbers[20].to_i end return host, port end private :parse228 def parse229(resp) if resp[0, 3] != "229" raise FTPReplyError, resp end left = resp.index("(") right = resp.index(")") if left == nil or right == nil raise FTPProtoError, resp end numbers = resp[left + 1 .. right - 1].split(resp[left + 1, 1]) if numbers.length != 4 raise FTPProtoError, resp end port = numbers[3].to_i host = (@sock.peeraddr())[3] return host, port end private :parse229 def parse257(resp) if resp[0, 3] != "257" raise FTPReplyError, resp end if resp[3, 2] != ' "' return "" end dirname = "" i = 5 n = resp.length while i < n c = resp[i, 1] i = i + 1 if c == '"' if i > n or resp[i, 1] != '"' break end i = i + 1 end dirname = dirname + c end return dirname end private :parse257 end end # Documentation comments: # - sourced from pickaxe and nutshell, with improvements (hopefully) # - three methods should be private (search WRITEME) # - two methods need more information (search TODO) PK|]^/Yapp net/smtp.rbnu[# = net/smtp.rb # # Copyright (c) 1999-2007 Yukihiro Matsumoto. # # Copyright (c) 1999-2007 Minero Aoki. # # Written & maintained by Minero Aoki . # # Documented by William Webber and Minero Aoki. # # This program is free software. You can re-distribute and/or # modify this program under the same terms as Ruby itself. # # NOTE: You can find Japanese version of this document at: # http://www.ruby-lang.org/ja/man/html/net_smtp.html # # $Id: smtp.rb 28208 2010-06-08 06:14:59Z shyouhei $ # # See Net::SMTP for documentation. # require 'net/protocol' require 'digest/md5' require 'timeout' begin require 'openssl' rescue LoadError end module Net # Module mixed in to all SMTP error classes module SMTPError # This *class* is a module for backward compatibility. # In later release, this module becomes a class. end # Represents an SMTP authentication error. class SMTPAuthenticationError < ProtoAuthError include SMTPError end # Represents SMTP error code 420 or 450, a temporary error. class SMTPServerBusy < ProtoServerError include SMTPError end # Represents an SMTP command syntax error (error code 500) class SMTPSyntaxError < ProtoSyntaxError include SMTPError end # Represents a fatal SMTP error (error code 5xx, except for 500) class SMTPFatalError < ProtoFatalError include SMTPError end # Unexpected reply code returned from server. class SMTPUnknownError < ProtoUnknownError include SMTPError end # Command is not supported on server. class SMTPUnsupportedCommand < ProtocolError include SMTPError end # # = Net::SMTP # # == What is This Library? # # This library provides functionality to send internet # mail via SMTP, the Simple Mail Transfer Protocol. For details of # SMTP itself, see [RFC2821] (http://www.ietf.org/rfc/rfc2821.txt). # # == What is This Library NOT? # # This library does NOT provide functions to compose internet mails. # You must create them by yourself. If you want better mail support, # try RubyMail or TMail. You can get both libraries from RAA. # (http://www.ruby-lang.org/en/raa.html) # # FYI: the official documentation on internet mail is: [RFC2822] (http://www.ietf.org/rfc/rfc2822.txt). # # == Examples # # === Sending Messages # # You must open a connection to an SMTP server before sending messages. # The first argument is the address of your SMTP server, and the second # argument is the port number. Using SMTP.start with a block is the simplest # way to do this. This way, the SMTP connection is closed automatically # after the block is executed. # # require 'net/smtp' # Net::SMTP.start('your.smtp.server', 25) do |smtp| # # Use the SMTP object smtp only in this block. # end # # Replace 'your.smtp.server' with your SMTP server. Normally # your system manager or internet provider supplies a server # for you. # # Then you can send messages. # # msgstr = < # To: Destination Address # Subject: test message # Date: Sat, 23 Jun 2001 16:26:43 +0900 # Message-Id: # # This is a test message. # END_OF_MESSAGE # # require 'net/smtp' # Net::SMTP.start('your.smtp.server', 25) do |smtp| # smtp.send_message msgstr, # 'your@mail.address', # 'his_addess@example.com' # end # # === Closing the Session # # You MUST close the SMTP session after sending messages, by calling # the #finish method: # # # using SMTP#finish # smtp = Net::SMTP.start('your.smtp.server', 25) # smtp.send_message msgstr, 'from@address', 'to@address' # smtp.finish # # You can also use the block form of SMTP.start/SMTP#start. This closes # the SMTP session automatically: # # # using block form of SMTP.start # Net::SMTP.start('your.smtp.server', 25) do |smtp| # smtp.send_message msgstr, 'from@address', 'to@address' # end # # I strongly recommend this scheme. This form is simpler and more robust. # # === HELO domain # # In almost all situations, you must provide a third argument # to SMTP.start/SMTP#start. This is the domain name which you are on # (the host to send mail from). It is called the "HELO domain". # The SMTP server will judge whether it should send or reject # the SMTP session by inspecting the HELO domain. # # Net::SMTP.start('your.smtp.server', 25, # 'mail.from.domain') { |smtp| ... } # # === SMTP Authentication # # The Net::SMTP class supports three authentication schemes; # PLAIN, LOGIN and CRAM MD5. (SMTP Authentication: [RFC2554]) # To use SMTP authentication, pass extra arguments to # SMTP.start/SMTP#start. # # # PLAIN # Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain', # 'Your Account', 'Your Password', :plain) # # LOGIN # Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain', # 'Your Account', 'Your Password', :login) # # # CRAM MD5 # Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain', # 'Your Account', 'Your Password', :cram_md5) # class SMTP Revision = %q$Revision: 28208 $.split[1] # The default SMTP port number, 25. def SMTP.default_port 25 end # The default mail submission port number, 587. def SMTP.default_submission_port 587 end # The default SMTPS port number, 465. def SMTP.default_tls_port 465 end class << self alias default_ssl_port default_tls_port end def SMTP.default_ssl_context OpenSSL::SSL::SSLContext.new end # # Creates a new Net::SMTP object. # # +address+ is the hostname or ip address of your SMTP # server. +port+ is the port to connect to; it defaults to # port 25. # # This method does not open the TCP connection. You can use # SMTP.start instead of SMTP.new if you want to do everything # at once. Otherwise, follow SMTP.new with SMTP#start. # def initialize(address, port = nil) @address = address @port = (port || SMTP.default_port) @esmtp = true @capabilities = nil @socket = nil @started = false @open_timeout = 30 @read_timeout = 60 @error_occured = false @debug_output = nil @tls = false @starttls = false @ssl_context = nil end # Provide human-readable stringification of class state. def inspect "#<#{self.class} #{@address}:#{@port} started=#{@started}>" end # +true+ if the SMTP object uses ESMTP (which it does by default). def esmtp? @esmtp end # # Set whether to use ESMTP or not. This should be done before # calling #start. Note that if #start is called in ESMTP mode, # and the connection fails due to a ProtocolError, the SMTP # object will automatically switch to plain SMTP mode and # retry (but not vice versa). # def esmtp=(bool) @esmtp = bool end alias esmtp esmtp? # true if server advertises STARTTLS. # You cannot get valid value before opening SMTP session. def capable_starttls? capable?('STARTTLS') end def capable?(key) return nil unless @capabilities @capabilities[key] ? true : false end private :capable? # true if server advertises AUTH PLAIN. # You cannot get valid value before opening SMTP session. def capable_plain_auth? auth_capable?('PLAIN') end # true if server advertises AUTH LOGIN. # You cannot get valid value before opening SMTP session. def capable_login_auth? auth_capable?('LOGIN') end # true if server advertises AUTH CRAM-MD5. # You cannot get valid value before opening SMTP session. def capable_cram_md5_auth? auth_capable?('CRAM-MD5') end def auth_capable?(type) return nil unless @capabilities return false unless @capabilities['AUTH'] @capabilities['AUTH'].include?(type) end private :auth_capable? # Returns supported authentication methods on this server. # You cannot get valid value before opening SMTP session. def capable_auth_types return [] unless @capabilities return [] unless @capabilities['AUTH'] @capabilities['AUTH'] end # true if this object uses SMTP/TLS (SMTPS). def tls? @tls end alias ssl? tls? # Enables SMTP/TLS (SMTPS: SMTP over direct TLS connection) for # this object. Must be called before the connection is established # to have any effect. +context+ is a OpenSSL::SSL::SSLContext object. def enable_tls(context = SMTP.default_ssl_context) raise 'openssl library not installed' unless defined?(OpenSSL) raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @starttls @tls = true @ssl_context = context end alias enable_ssl enable_tls # Disables SMTP/TLS for this object. Must be called before the # connection is established to have any effect. def disable_tls @tls = false @ssl_context = nil end alias disable_ssl disable_tls # Returns truth value if this object uses STARTTLS. # If this object always uses STARTTLS, returns :always. # If this object uses STARTTLS when the server support TLS, returns :auto. def starttls? @starttls end # true if this object uses STARTTLS. def starttls_always? @starttls == :always end # true if this object uses STARTTLS when server advertises STARTTLS. def starttls_auto? @starttls == :auto end # Enables SMTP/TLS (STARTTLS) for this object. # +context+ is a OpenSSL::SSL::SSLContext object. def enable_starttls(context = SMTP.default_ssl_context) raise 'openssl library not installed' unless defined?(OpenSSL) raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @tls @starttls = :always @ssl_context = context end # Enables SMTP/TLS (STARTTLS) for this object if server accepts. # +context+ is a OpenSSL::SSL::SSLContext object. def enable_starttls_auto(context = SMTP.default_ssl_context) raise 'openssl library not installed' unless defined?(OpenSSL) raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @tls @starttls = :auto @ssl_context = context end # Disables SMTP/TLS (STARTTLS) for this object. Must be called # before the connection is established to have any effect. def disable_starttls @starttls = false @ssl_context = nil end # The address of the SMTP server to connect to. attr_reader :address # The port number of the SMTP server to connect to. attr_reader :port # Seconds to wait while attempting to open a connection. # If the connection cannot be opened within this time, a # TimeoutError is raised. attr_accessor :open_timeout # Seconds to wait while reading one block (by one read(2) call). # If the read(2) call does not complete within this time, a # TimeoutError is raised. attr_reader :read_timeout # Set the number of seconds to wait until timing-out a read(2) # call. def read_timeout=(sec) @socket.read_timeout = sec if @socket @read_timeout = sec end # # WARNING: This method causes serious security holes. # Use this method for only debugging. # # Set an output stream for debug logging. # You must call this before #start. # # # example # smtp = Net::SMTP.new(addr, port) # smtp.set_debug_output $stderr # smtp.start do |smtp| # .... # end # def debug_output=(arg) @debug_output = arg end alias set_debug_output debug_output= # # SMTP session control # # # Creates a new Net::SMTP object and connects to the server. # # This method is equivalent to: # # Net::SMTP.new(address, port).start(helo_domain, account, password, authtype) # # === Example # # Net::SMTP.start('your.smtp.server') do |smtp| # smtp.send_message msgstr, 'from@example.com', ['dest@example.com'] # end # # === Block Usage # # If called with a block, the newly-opened Net::SMTP object is yielded # to the block, and automatically closed when the block finishes. If called # without a block, the newly-opened Net::SMTP object is returned to # the caller, and it is the caller's responsibility to close it when # finished. # # === Parameters # # +address+ is the hostname or ip address of your smtp server. # # +port+ is the port to connect to; it defaults to port 25. # # +helo+ is the _HELO_ _domain_ provided by the client to the # server (see overview comments); it defaults to 'localhost.localdomain'. # # The remaining arguments are used for SMTP authentication, if required # or desired. +user+ is the account name; +secret+ is your password # or other authentication token; and +authtype+ is the authentication # type, one of :plain, :login, or :cram_md5. See the discussion of # SMTP Authentication in the overview notes. # # === Errors # # This method may raise: # # * Net::SMTPAuthenticationError # * Net::SMTPServerBusy # * Net::SMTPSyntaxError # * Net::SMTPFatalError # * Net::SMTPUnknownError # * IOError # * TimeoutError # def SMTP.start(address, port = nil, helo = 'localhost.localdomain', user = nil, secret = nil, authtype = nil, &block) # :yield: smtp new(address, port).start(helo, user, secret, authtype, &block) end # +true+ if the SMTP session has been started. def started? @started end # # Opens a TCP connection and starts the SMTP session. # # === Parameters # # +helo+ is the _HELO_ _domain_ that you'll dispatch mails from; see # the discussion in the overview notes. # # If both of +user+ and +secret+ are given, SMTP authentication # will be attempted using the AUTH command. +authtype+ specifies # the type of authentication to attempt; it must be one of # :login, :plain, and :cram_md5. See the notes on SMTP Authentication # in the overview. # # === Block Usage # # When this methods is called with a block, the newly-started SMTP # object is yielded to the block, and automatically closed after # the block call finishes. Otherwise, it is the caller's # responsibility to close the session when finished. # # === Example # # This is very similar to the class method SMTP.start. # # require 'net/smtp' # smtp = Net::SMTP.new('smtp.mail.server', 25) # smtp.start(helo_domain, account, password, authtype) do |smtp| # smtp.send_message msgstr, 'from@example.com', ['dest@example.com'] # end # # The primary use of this method (as opposed to SMTP.start) # is probably to set debugging (#set_debug_output) or ESMTP # (#esmtp=), which must be done before the session is # started. # # === Errors # # If session has already been started, an IOError will be raised. # # This method may raise: # # * Net::SMTPAuthenticationError # * Net::SMTPServerBusy # * Net::SMTPSyntaxError # * Net::SMTPFatalError # * Net::SMTPUnknownError # * IOError # * TimeoutError # def start(helo = 'localhost.localdomain', user = nil, secret = nil, authtype = nil) # :yield: smtp if block_given? begin do_start helo, user, secret, authtype return yield(self) ensure do_finish end else do_start helo, user, secret, authtype return self end end # Finishes the SMTP session and closes TCP connection. # Raises IOError if not started. def finish raise IOError, 'not yet started' unless started? do_finish end private def do_start(helo_domain, user, secret, authtype) raise IOError, 'SMTP session already started' if @started if user or secret check_auth_method(authtype || DEFAULT_AUTH_TYPE) check_auth_args user, secret end s = timeout(@open_timeout) { TCPSocket.open(@address, @port) } logging "Connection opened: #{@address}:#{@port}" @socket = new_internet_message_io(tls? ? tlsconnect(s) : s) check_response critical { recv_response() } do_helo helo_domain if starttls_always? or (capable_starttls? and starttls_auto?) unless capable_starttls? raise SMTPUnsupportedCommand, "STARTTLS is not supported on this server" end starttls @socket = new_internet_message_io(tlsconnect(s)) # helo response may be different after STARTTLS do_helo helo_domain end authenticate user, secret, (authtype || DEFAULT_AUTH_TYPE) if user @started = true ensure unless @started # authentication failed, cancel connection. s.close if s and not s.closed? @socket = nil end end def tlsconnect(s) s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) logging "TLS connection started" s.sync_close = true s.connect if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE s.post_connection_check(@address) end s end def new_internet_message_io(s) io = InternetMessageIO.new(s) io.read_timeout = @read_timeout io.debug_output = @debug_output io end def do_helo(helo_domain) res = @esmtp ? ehlo(helo_domain) : helo(helo_domain) @capabilities = res.capabilities rescue SMTPError if @esmtp @esmtp = false @error_occured = false retry end raise end def do_finish quit if @socket and not @socket.closed? and not @error_occured ensure @started = false @error_occured = false @socket.close if @socket and not @socket.closed? @socket = nil end # # Message Sending # public # # Sends +msgstr+ as a message. Single CR ("\r") and LF ("\n") found # in the +msgstr+, are converted into the CR LF pair. You cannot send a # binary message with this method. +msgstr+ should include both # the message headers and body. # # +from_addr+ is a String representing the source mail address. # # +to_addr+ is a String or Strings or Array of Strings, representing # the destination mail address or addresses. # # === Example # # Net::SMTP.start('smtp.example.com') do |smtp| # smtp.send_message msgstr, # 'from@example.com', # ['dest@example.com', 'dest2@example.com'] # end # # === Errors # # This method may raise: # # * Net::SMTPServerBusy # * Net::SMTPSyntaxError # * Net::SMTPFatalError # * Net::SMTPUnknownError # * IOError # * TimeoutError # def send_message(msgstr, from_addr, *to_addrs) raise IOError, 'closed session' unless @socket mailfrom from_addr rcptto_list(to_addrs) {data msgstr} end alias send_mail send_message alias sendmail send_message # obsolete # # Opens a message writer stream and gives it to the block. # The stream is valid only in the block, and has these methods: # # puts(str = ''):: outputs STR and CR LF. # print(str):: outputs STR. # printf(fmt, *args):: outputs sprintf(fmt,*args). # write(str):: outputs STR and returns the length of written bytes. # <<(str):: outputs STR and returns self. # # If a single CR ("\r") or LF ("\n") is found in the message, # it is converted to the CR LF pair. You cannot send a binary # message with this method. # # === Parameters # # +from_addr+ is a String representing the source mail address. # # +to_addr+ is a String or Strings or Array of Strings, representing # the destination mail address or addresses. # # === Example # # Net::SMTP.start('smtp.example.com', 25) do |smtp| # smtp.open_message_stream('from@example.com', ['dest@example.com']) do |f| # f.puts 'From: from@example.com' # f.puts 'To: dest@example.com' # f.puts 'Subject: test message' # f.puts # f.puts 'This is a test message.' # end # end # # === Errors # # This method may raise: # # * Net::SMTPServerBusy # * Net::SMTPSyntaxError # * Net::SMTPFatalError # * Net::SMTPUnknownError # * IOError # * TimeoutError # def open_message_stream(from_addr, *to_addrs, &block) # :yield: stream raise IOError, 'closed session' unless @socket mailfrom from_addr rcptto_list(to_addrs) {data(&block)} end alias ready open_message_stream # obsolete # # Authentication # public DEFAULT_AUTH_TYPE = :plain def authenticate(user, secret, authtype = DEFAULT_AUTH_TYPE) check_auth_method authtype check_auth_args user, secret send auth_method(authtype), user, secret end def auth_plain(user, secret) check_auth_args user, secret res = critical { get_response('AUTH PLAIN ' + base64_encode("\0#{user}\0#{secret}")) } check_auth_response res res end def auth_login(user, secret) check_auth_args user, secret res = critical { check_auth_continue get_response('AUTH LOGIN') check_auth_continue get_response(base64_encode(user)) get_response(base64_encode(secret)) } check_auth_response res res end def auth_cram_md5(user, secret) check_auth_args user, secret res = critical { res0 = get_response('AUTH CRAM-MD5') check_auth_continue res0 crammed = cram_md5_response(secret, res0.cram_md5_challenge) get_response(base64_encode("#{user} #{crammed}")) } check_auth_response res res end private def check_auth_method(type) unless respond_to?(auth_method(type), true) raise ArgumentError, "wrong authentication type #{type}" end end def auth_method(type) "auth_#{type.to_s.downcase}".intern end def check_auth_args(user, secret) unless user raise ArgumentError, 'SMTP-AUTH requested but missing user name' end unless secret raise ArgumentError, 'SMTP-AUTH requested but missing secret phrase' end end def base64_encode(str) # expects "str" may not become too long [str].pack('m').gsub(/\s+/, '') end IMASK = 0x36 OMASK = 0x5c # CRAM-MD5: [RFC2195] def cram_md5_response(secret, challenge) tmp = Digest::MD5.digest(cram_secret(secret, IMASK) + challenge) Digest::MD5.hexdigest(cram_secret(secret, OMASK) + tmp) end CRAM_BUFSIZE = 64 def cram_secret(secret, mask) secret = Digest::MD5.digest(secret) if secret.size > CRAM_BUFSIZE buf = secret.ljust(CRAM_BUFSIZE, "\0") 0.upto(buf.size - 1) do |i| buf[i] = (buf[i].ord ^ mask).chr end buf end # # SMTP command dispatcher # public def starttls getok('STARTTLS') end def helo(domain) getok("HELO #{domain}") end def ehlo(domain) getok("EHLO #{domain}") end def mailfrom(from_addr) if $SAFE > 0 raise SecurityError, 'tainted from_addr' if from_addr.tainted? end getok("MAIL FROM:<#{from_addr}>") end def rcptto_list(to_addrs) raise ArgumentError, 'mail destination not given' if to_addrs.empty? ok_users = [] unknown_users = [] to_addrs.flatten.each do |addr| begin rcptto addr rescue SMTPAuthenticationError unknown_users << addr.dump else ok_users << addr end end raise ArgumentError, 'mail destination not given' if ok_users.empty? ret = yield unless unknown_users.empty? raise SMTPAuthenticationError, "failed to deliver for #{unknown_users.join(', ')}" end ret end def rcptto(to_addr) if $SAFE > 0 raise SecurityError, 'tainted to_addr' if to_addr.tainted? end getok("RCPT TO:<#{to_addr}>") end # This method sends a message. # If +msgstr+ is given, sends it as a message. # If block is given, yield a message writer stream. # You must write message before the block is closed. # # # Example 1 (by string) # smtp.data(< # Documentation:: William Webber and Wakou Aoyama # # This file holds the class Net::Telnet, which provides client-side # telnet functionality. # # For documentation, see Net::Telnet. # require "socket" require "delegate" require "timeout" require "English" module Net # # == Net::Telnet # # Provides telnet client functionality. # # This class also has, through delegation, all the methods of a # socket object (by default, a +TCPSocket+, but can be set by the # +Proxy+ option to new()). This provides methods such as # close() to end the session and sysread() to read # data directly from the host, instead of via the waitfor() # mechanism. Note that if you do use sysread() directly # when in telnet mode, you should probably pass the output through # preprocess() to extract telnet command sequences. # # == Overview # # The telnet protocol allows a client to login remotely to a user # account on a server and execute commands via a shell. The equivalent # is done by creating a Net::Telnet class with the +Host+ option # set to your host, calling #login() with your user and password, # issuing one or more #cmd() calls, and then calling #close() # to end the session. The #waitfor(), #print(), #puts(), and # #write() methods, which #cmd() is implemented on top of, are # only needed if you are doing something more complicated. # # A Net::Telnet object can also be used to connect to non-telnet # services, such as SMTP or HTTP. In this case, you normally # want to provide the +Port+ option to specify the port to # connect to, and set the +Telnetmode+ option to false to prevent # the client from attempting to interpret telnet command sequences. # Generally, #login() will not work with other protocols, and you # have to handle authentication yourself. # # For some protocols, it will be possible to specify the +Prompt+ # option once when you create the Telnet object and use #cmd() calls; # for others, you will have to specify the response sequence to # look for as the Match option to every #cmd() call, or call # #puts() and #waitfor() directly; for yet others, you will have # to use #sysread() instead of #waitfor() and parse server # responses yourself. # # It is worth noting that when you create a new Net::Telnet object, # you can supply a proxy IO channel via the Proxy option. This # can be used to attach the Telnet object to other Telnet objects, # to already open sockets, or to any read-write IO object. This # can be useful, for instance, for setting up a test fixture for # unit testing. # # == Examples # # === Log in and send a command, echoing all output to stdout # # localhost = Net::Telnet::new("Host" => "localhost", # "Timeout" => 10, # "Prompt" => /[$%#>] \z/n) # localhost.login("username", "password") { |c| print c } # localhost.cmd("command") { |c| print c } # localhost.close # # # === Check a POP server to see if you have mail # # pop = Net::Telnet::new("Host" => "your_destination_host_here", # "Port" => 110, # "Telnetmode" => false, # "Prompt" => /^\+OK/n) # pop.cmd("user " + "your_username_here") { |c| print c } # pop.cmd("pass " + "your_password_here") { |c| print c } # pop.cmd("list") { |c| print c } # # == References # # There are a large number of RFCs relevant to the Telnet protocol. # RFCs 854-861 define the base protocol. For a complete listing # of relevant RFCs, see # http://www.omnifarious.org/~hopper/technical/telnet-rfc.html # class Telnet < SimpleDelegator # :stopdoc: IAC = 255.chr # "\377" # "\xff" # interpret as command DONT = 254.chr # "\376" # "\xfe" # you are not to use option DO = 253.chr # "\375" # "\xfd" # please, you use option WONT = 252.chr # "\374" # "\xfc" # I won't use option WILL = 251.chr # "\373" # "\xfb" # I will use option SB = 250.chr # "\372" # "\xfa" # interpret as subnegotiation GA = 249.chr # "\371" # "\xf9" # you may reverse the line EL = 248.chr # "\370" # "\xf8" # erase the current line EC = 247.chr # "\367" # "\xf7" # erase the current character AYT = 246.chr # "\366" # "\xf6" # are you there AO = 245.chr # "\365" # "\xf5" # abort output--but let prog finish IP = 244.chr # "\364" # "\xf4" # interrupt process--permanently BREAK = 243.chr # "\363" # "\xf3" # break DM = 242.chr # "\362" # "\xf2" # data mark--for connect. cleaning NOP = 241.chr # "\361" # "\xf1" # nop SE = 240.chr # "\360" # "\xf0" # end sub negotiation EOR = 239.chr # "\357" # "\xef" # end of record (transparent mode) ABORT = 238.chr # "\356" # "\xee" # Abort process SUSP = 237.chr # "\355" # "\xed" # Suspend process EOF = 236.chr # "\354" # "\xec" # End of file SYNCH = 242.chr # "\362" # "\xf2" # for telfunc calls OPT_BINARY = 0.chr # "\000" # "\x00" # Binary Transmission OPT_ECHO = 1.chr # "\001" # "\x01" # Echo OPT_RCP = 2.chr # "\002" # "\x02" # Reconnection OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead OPT_NAMS = 4.chr # "\004" # "\x04" # Approx Message Size Negotiation OPT_STATUS = 5.chr # "\005" # "\x05" # Status OPT_TM = 6.chr # "\006" # "\x06" # Timing Mark OPT_RCTE = 7.chr # "\a" # "\x07" # Remote Controlled Trans and Echo OPT_NAOL = 8.chr # "\010" # "\x08" # Output Line Width OPT_NAOP = 9.chr # "\t" # "\x09" # Output Page Size OPT_NAOCRD = 10.chr # "\n" # "\x0a" # Output Carriage-Return Disposition OPT_NAOHTS = 11.chr # "\v" # "\x0b" # Output Horizontal Tab Stops OPT_NAOHTD = 12.chr # "\f" # "\x0c" # Output Horizontal Tab Disposition OPT_NAOFFD = 13.chr # "\r" # "\x0d" # Output Formfeed Disposition OPT_NAOVTS = 14.chr # "\016" # "\x0e" # Output Vertical Tabstops OPT_NAOVTD = 15.chr # "\017" # "\x0f" # Output Vertical Tab Disposition OPT_NAOLFD = 16.chr # "\020" # "\x10" # Output Linefeed Disposition OPT_XASCII = 17.chr # "\021" # "\x11" # Extended ASCII OPT_LOGOUT = 18.chr # "\022" # "\x12" # Logout OPT_BM = 19.chr # "\023" # "\x13" # Byte Macro OPT_DET = 20.chr # "\024" # "\x14" # Data Entry Terminal OPT_SUPDUP = 21.chr # "\025" # "\x15" # SUPDUP OPT_SUPDUPOUTPUT = 22.chr # "\026" # "\x16" # SUPDUP Output OPT_SNDLOC = 23.chr # "\027" # "\x17" # Send Location OPT_TTYPE = 24.chr # "\030" # "\x18" # Terminal Type OPT_EOR = 25.chr # "\031" # "\x19" # End of Record OPT_TUID = 26.chr # "\032" # "\x1a" # TACACS User Identification OPT_OUTMRK = 27.chr # "\e" # "\x1b" # Output Marking OPT_TTYLOC = 28.chr # "\034" # "\x1c" # Terminal Location Number OPT_3270REGIME = 29.chr # "\035" # "\x1d" # Telnet 3270 Regime OPT_X3PAD = 30.chr # "\036" # "\x1e" # X.3 PAD OPT_NAWS = 31.chr # "\037" # "\x1f" # Negotiate About Window Size OPT_TSPEED = 32.chr # " " # "\x20" # Terminal Speed OPT_LFLOW = 33.chr # "!" # "\x21" # Remote Flow Control OPT_LINEMODE = 34.chr # "\"" # "\x22" # Linemode OPT_XDISPLOC = 35.chr # "#" # "\x23" # X Display Location OPT_OLD_ENVIRON = 36.chr # "$" # "\x24" # Environment Option OPT_AUTHENTICATION = 37.chr # "%" # "\x25" # Authentication Option OPT_ENCRYPT = 38.chr # "&" # "\x26" # Encryption Option OPT_NEW_ENVIRON = 39.chr # "'" # "\x27" # New Environment Option OPT_EXOPL = 255.chr # "\377" # "\xff" # Extended-Options-List NULL = "\000" CR = "\015" LF = "\012" EOL = CR + LF REVISION = '$Id: telnet.rb 16458 2008-05-18 15:02:36Z knu $' # :startdoc: # # Creates a new Net::Telnet object. # # Attempts to connect to the host (unless the Proxy option is # provided: see below). If a block is provided, it is yielded # status messages on the attempt to connect to the server, of # the form: # # Trying localhost... # Connected to localhost. # # +options+ is a hash of options. The following example lists # all options and their default values. # # host = Net::Telnet::new( # "Host" => "localhost", # default: "localhost" # "Port" => 23, # default: 23 # "Binmode" => false, # default: false # "Output_log" => "output_log", # default: nil (no output) # "Dump_log" => "dump_log", # default: nil (no output) # "Prompt" => /[$%#>] \z/n, # default: /[$%#>] \z/n # "Telnetmode" => true, # default: true # "Timeout" => 10, # default: 10 # # if ignore timeout then set "Timeout" to false. # "Waittime" => 0, # default: 0 # "Proxy" => proxy # default: nil # # proxy is Net::Telnet or IO object # ) # # The options have the following meanings: # # Host:: the hostname or IP address of the host to connect to, as a String. # Defaults to "localhost". # # Port:: the port to connect to. Defaults to 23. # # Binmode:: if false (the default), newline substitution is performed. # Outgoing LF is # converted to CRLF, and incoming CRLF is converted to LF. If # true, this substitution is not performed. This value can # also be set with the #binmode() method. The # outgoing conversion only applies to the #puts() and #print() # methods, not the #write() method. The precise nature of # the newline conversion is also affected by the telnet options # SGA and BIN. # # Output_log:: the name of the file to write connection status messages # and all received traffic to. In the case of a proper # Telnet session, this will include the client input as # echoed by the host; otherwise, it only includes server # responses. Output is appended verbatim to this file. # By default, no output log is kept. # # Dump_log:: as for Output_log, except that output is written in hexdump # format (16 bytes per line as hex pairs, followed by their # printable equivalent), with connection status messages # preceded by '#', sent traffic preceded by '>', and # received traffic preceded by '<'. By default, not dump log # is kept. # # Prompt:: a regular expression matching the host's command-line prompt # sequence. This is needed by the Telnet class to determine # when the output from a command has finished and the host is # ready to receive a new command. By default, this regular # expression is /[$%#>] \z/n. # # Telnetmode:: a boolean value, true by default. In telnet mode, # traffic received from the host is parsed for special # command sequences, and these sequences are escaped # in outgoing traffic sent using #puts() or #print() # (but not #write()). If you are using the Net::Telnet # object to connect to a non-telnet service (such as # SMTP or POP), this should be set to "false" to prevent # undesired data corruption. This value can also be set # by the #telnetmode() method. # # Timeout:: the number of seconds to wait before timing out both the # initial attempt to connect to host (in this constructor), # and all attempts to read data from the host (in #waitfor(), # #cmd(), and #login()). Exceeding this timeout causes a # TimeoutError to be raised. The default value is 10 seconds. # You can disable the timeout by setting this value to false. # In this case, the connect attempt will eventually timeout # on the underlying connect(2) socket call with an # Errno::ETIMEDOUT error (but generally only after a few # minutes), but other attempts to read data from the host # will hand indefinitely if no data is forthcoming. # # Waittime:: the amount of time to wait after seeing what looks like a # prompt (that is, received data that matches the Prompt # option regular expression) to see if more data arrives. # If more data does arrive in this time, Net::Telnet assumes # that what it saw was not really a prompt. This is to try to # avoid false matches, but it can also lead to missing real # prompts (if, for instance, a background process writes to # the terminal soon after the prompt is displayed). By # default, set to 0, meaning not to wait for more data. # # Proxy:: a proxy object to used instead of opening a direct connection # to the host. Must be either another Net::Telnet object or # an IO object. If it is another Net::Telnet object, this # instance will use that one's socket for communication. If an # IO object, it is used directly for communication. Any other # kind of object will cause an error to be raised. # def initialize(options) # :yield: mesg @options = options @options["Host"] = "localhost" unless @options.has_key?("Host") @options["Port"] = 23 unless @options.has_key?("Port") @options["Prompt"] = /[$%#>] \z/n unless @options.has_key?("Prompt") @options["Timeout"] = 10 unless @options.has_key?("Timeout") @options["Waittime"] = 0 unless @options.has_key?("Waittime") unless @options.has_key?("Binmode") @options["Binmode"] = false else unless (true == @options["Binmode"] or false == @options["Binmode"]) raise ArgumentError, "Binmode option must be true or false" end end unless @options.has_key?("Telnetmode") @options["Telnetmode"] = true else unless (true == @options["Telnetmode"] or false == @options["Telnetmode"]) raise ArgumentError, "Telnetmode option must be true or false" end end @telnet_option = { "SGA" => false, "BINARY" => false } if @options.has_key?("Output_log") @log = File.open(@options["Output_log"], 'a+') @log.sync = true @log.binmode end if @options.has_key?("Dump_log") @dumplog = File.open(@options["Dump_log"], 'a+') @dumplog.sync = true @dumplog.binmode def @dumplog.log_dump(dir, x) # :nodoc: len = x.length addr = 0 offset = 0 while 0 < len if len < 16 line = x[offset, len] else line = x[offset, 16] end hexvals = line.unpack('H*')[0] hexvals += ' ' * (32 - hexvals.length) hexvals = format("%s %s %s %s " * 4, *hexvals.unpack('a2' * 16)) line = line.gsub(/[\000-\037\177-\377]/n, '.') printf "%s 0x%5.5x: %s%s\n", dir, addr, hexvals, line addr += 16 offset += 16 len -= 16 end print "\n" end end if @options.has_key?("Proxy") if @options["Proxy"].kind_of?(Net::Telnet) @sock = @options["Proxy"].sock elsif @options["Proxy"].kind_of?(IO) @sock = @options["Proxy"] else raise "Error: Proxy must be an instance of Net::Telnet or IO." end else message = "Trying " + @options["Host"] + "...\n" yield(message) if block_given? @log.write(message) if @options.has_key?("Output_log") @dumplog.log_dump('#', message) if @options.has_key?("Dump_log") begin if @options["Timeout"] == false @sock = TCPSocket.open(@options["Host"], @options["Port"]) else timeout(@options["Timeout"]) do @sock = TCPSocket.open(@options["Host"], @options["Port"]) end end rescue TimeoutError raise TimeoutError, "timed out while opening a connection to the host" rescue @log.write($ERROR_INFO.to_s + "\n") if @options.has_key?("Output_log") @dumplog.log_dump('#', $ERROR_INFO.to_s + "\n") if @options.has_key?("Dump_log") raise end @sock.sync = true @sock.binmode message = "Connected to " + @options["Host"] + ".\n" yield(message) if block_given? @log.write(message) if @options.has_key?("Output_log") @dumplog.log_dump('#', message) if @options.has_key?("Dump_log") end super(@sock) end # initialize # The socket the Telnet object is using. Note that this object becomes # a delegate of the Telnet object, so normally you invoke its methods # directly on the Telnet object. attr :sock # Set telnet command interpretation on (+mode+ == true) or off # (+mode+ == false), or return the current value (+mode+ not # provided). It should be on for true telnet sessions, off if # using Net::Telnet to connect to a non-telnet service such # as SMTP. def telnetmode(mode = nil) case mode when nil @options["Telnetmode"] when true, false @options["Telnetmode"] = mode else raise ArgumentError, "argument must be true or false, or missing" end end # Turn telnet command interpretation on (true) or off (false). It # should be on for true telnet sessions, off if using Net::Telnet # to connect to a non-telnet service such as SMTP. def telnetmode=(mode) if (true == mode or false == mode) @options["Telnetmode"] = mode else raise ArgumentError, "argument must be true or false" end end # Turn newline conversion on (+mode+ == false) or off (+mode+ == true), # or return the current value (+mode+ is not specified). def binmode(mode = nil) case mode when nil @options["Binmode"] when true, false @options["Binmode"] = mode else raise ArgumentError, "argument must be true or false" end end # Turn newline conversion on (false) or off (true). def binmode=(mode) if (true == mode or false == mode) @options["Binmode"] = mode else raise ArgumentError, "argument must be true or false" end end # Preprocess received data from the host. # # Performs newline conversion and detects telnet command sequences. # Called automatically by #waitfor(). You should only use this # method yourself if you have read input directly using sysread() # or similar, and even then only if in telnet mode. def preprocess(string) # combine CR+NULL into CR string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"] # combine EOL into "\n" string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"] string.gsub(/#{IAC}( [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]| [#{DO}#{DONT}#{WILL}#{WONT}] [#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}]| #{SB}[^#{IAC}]*#{IAC}#{SE} )/xno) do if IAC == $1 # handle escaped IAC characters IAC elsif AYT == $1 # respond to "IAC AYT" (are you there) self.write("nobody here but us pigeons" + EOL) '' elsif DO[0] == $1[0] # respond to "IAC DO x" if OPT_BINARY[0] == $1[1] @telnet_option["BINARY"] = true self.write(IAC + WILL + OPT_BINARY) else self.write(IAC + WONT + $1[1..1]) end '' elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x" self.write(IAC + WONT + $1[1..1]) '' elsif WILL[0] == $1[0] # respond to "IAC WILL x" if OPT_BINARY[0] == $1[1] self.write(IAC + DO + OPT_BINARY) elsif OPT_ECHO[0] == $1[1] self.write(IAC + DO + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = true self.write(IAC + DO + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' elsif WONT[0] == $1[0] # respond to "IAC WON'T x" if OPT_ECHO[0] == $1[1] self.write(IAC + DONT + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = false self.write(IAC + DONT + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' else '' end end end # preprocess # Read data from the host until a certain sequence is matched. # # If a block is given, the received data will be yielded as it # is read in (not necessarily all in one go), or nil if EOF # occurs before any data is received. Whether a block is given # or not, all data read will be returned in a single string, or again # nil if EOF occurs before any data is received. Note that # received data includes the matched sequence we were looking for. # # +options+ can be either a regular expression or a hash of options. # If a regular expression, this specifies the data to wait for. # If a hash, this can specify the following options: # # Match:: a regular expression, specifying the data to wait for. # Prompt:: as for Match; used only if Match is not specified. # String:: as for Match, except a string that will be converted # into a regular expression. Used only if Match and # Prompt are not specified. # Timeout:: the number of seconds to wait for data from the host # before raising a TimeoutError. If set to false, # no timeout will occur. If not specified, the # Timeout option value specified when this instance # was created will be used, or, failing that, the # default value of 10 seconds. # Waittime:: the number of seconds to wait after matching against # the input data to see if more data arrives. If more # data arrives within this time, we will judge ourselves # not to have matched successfully, and will continue # trying to match. If not specified, the Waittime option # value specified when this instance was created will be # used, or, failing that, the default value of 0 seconds, # which means not to wait for more input. # FailEOF:: if true, when the remote end closes the connection then an # EOFError will be raised. Otherwise, defaults to the old # behaviour that the function will return whatever data # has been received already, or nil if nothing was received. # def waitfor(options) # :yield: recvdata time_out = @options["Timeout"] waittime = @options["Waittime"] fail_eof = @options["FailEOF"] if options.kind_of?(Hash) prompt = if options.has_key?("Match") options["Match"] elsif options.has_key?("Prompt") options["Prompt"] elsif options.has_key?("String") Regexp.new( Regexp.quote(options["String"]) ) end time_out = options["Timeout"] if options.has_key?("Timeout") waittime = options["Waittime"] if options.has_key?("Waittime") fail_eof = options["FailEOF"] if options.has_key?("FailEOF") else prompt = options end if time_out == false time_out = nil end line = '' buf = '' rest = '' until(prompt === line and not IO::select([@sock], nil, nil, waittime)) unless IO::select([@sock], nil, nil, time_out) raise TimeoutError, "timed out while waiting for more data" end begin c = @sock.readpartial(1024 * 1024) @dumplog.log_dump('<', c) if @options.has_key?("Dump_log") if @options["Telnetmode"] c = rest + c if Integer(c.rindex(/#{IAC}#{SE}/no)) < Integer(c.rindex(/#{IAC}#{SB}/no)) buf = preprocess(c[0 ... c.rindex(/#{IAC}#{SB}/no)]) rest = c[c.rindex(/#{IAC}#{SB}/no) .. -1] elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) || c.rindex(/\r\z/no) buf = preprocess(c[0 ... pt]) rest = c[pt .. -1] else buf = preprocess(c) rest = '' end else # Not Telnetmode. # # We cannot use preprocess() on this data, because that # method makes some Telnetmode-specific assumptions. buf = rest + c rest = '' unless @options["Binmode"] if pt = buf.rindex(/\r\z/no) buf = buf[0 ... pt] rest = buf[pt .. -1] end buf.gsub!(/#{EOL}/no, "\n") end end @log.print(buf) if @options.has_key?("Output_log") line += buf yield buf if block_given? rescue EOFError # End of file reached raise if fail_eof if line == '' line = nil yield nil if block_given? end break end end line end # Write +string+ to the host. # # Does not perform any conversions on +string+. Will log +string+ to the # dumplog, if the Dump_log option is set. def write(string) length = string.length while 0 < length IO::select(nil, [@sock]) @dumplog.log_dump('>', string[-length..-1]) if @options.has_key?("Dump_log") length -= @sock.syswrite(string[-length..-1]) end end # Sends a string to the host. # # This does _not_ automatically append a newline to the string. Embedded # newlines may be converted and telnet command sequences escaped # depending upon the values of telnetmode, binmode, and telnet options # set by the host. def print(string) string = string.gsub(/#{IAC}/no, IAC + IAC) if @options["Telnetmode"] if @options["Binmode"] self.write(string) else if @telnet_option["BINARY"] and @telnet_option["SGA"] # IAC WILL SGA IAC DO BIN send EOL --> CR self.write(string.gsub(/\n/n, CR)) elsif @telnet_option["SGA"] # IAC WILL SGA send EOL --> CR+NULL self.write(string.gsub(/\n/n, CR + NULL)) else # NONE send EOL --> CR+LF self.write(string.gsub(/\n/n, EOL)) end end end # Sends a string to the host. # # Same as #print(), but appends a newline to the string. def puts(string) self.print(string + "\n") end # Send a command to the host. # # More exactly, sends a string to the host, and reads in all received # data until is sees the prompt or other matched sequence. # # If a block is given, the received data will be yielded to it as # it is read in. Whether a block is given or not, the received data # will be return as a string. Note that the received data includes # the prompt and in most cases the host's echo of our command. # # +options+ is either a String, specified the string or command to # send to the host; or it is a hash of options. If a hash, the # following options can be specified: # # String:: the command or other string to send to the host. # Match:: a regular expression, the sequence to look for in # the received data before returning. If not specified, # the Prompt option value specified when this instance # was created will be used, or, failing that, the default # prompt of /[$%#>] \z/n. # Timeout:: the seconds to wait for data from the host before raising # a Timeout error. If not specified, the Timeout option # value specified when this instance was created will be # used, or, failing that, the default value of 10 seconds. # # The command or other string will have the newline sequence appended # to it. def cmd(options) # :yield: recvdata match = @options["Prompt"] time_out = @options["Timeout"] if options.kind_of?(Hash) string = options["String"] match = options["Match"] if options.has_key?("Match") time_out = options["Timeout"] if options.has_key?("Timeout") else string = options end self.puts(string) if block_given? waitfor({"Prompt" => match, "Timeout" => time_out}){|c| yield c } else waitfor({"Prompt" => match, "Timeout" => time_out}) end end # Login to the host with a given username and password. # # The username and password can either be provided as two string # arguments in that order, or as a hash with keys "Name" and # "Password". # # This method looks for the strings "login" and "Password" from the # host to determine when to send the username and password. If the # login sequence does not follow this pattern (for instance, you # are connecting to a service other than telnet), you will need # to handle login yourself. # # The password can be omitted, either by only # provided one String argument, which will be used as the username, # or by providing a has that has no "Password" key. In this case, # the method will not look for the "Password:" prompt; if it is # sent, it will have to be dealt with by later calls. # # The method returns all data received during the login process from # the host, including the echoed username but not the password (which # the host should not echo). If a block is passed in, this received # data is also yielded to the block as it is received. def login(options, password = nil) # :yield: recvdata login_prompt = /[Ll]ogin[: ]*\z/n password_prompt = /[Pp]ass(?:word|phrase)[: ]*\z/n if options.kind_of?(Hash) username = options["Name"] password = options["Password"] login_prompt = options["LoginPrompt"] if options["LoginPrompt"] password_prompt = options["PasswordPrompt"] if options["PasswordPrompt"] else username = options end if block_given? line = waitfor(login_prompt){|c| yield c } if password line += cmd({"String" => username, "Match" => password_prompt}){|c| yield c } line += cmd(password){|c| yield c } else line += cmd(username){|c| yield c } end else line = waitfor(login_prompt) if password line += cmd({"String" => username, "Match" => password_prompt}) line += cmd(password) else line += cmd(username) end end line end end # class Telnet end # module Net PK|]f net/http.rbnu[# # = net/http.rb # # Copyright (c) 1999-2006 Yukihiro Matsumoto # Copyright (c) 1999-2006 Minero Aoki # Copyright (c) 2001 GOTOU Yuuzou # # Written and maintained by Minero Aoki . # HTTPS support added by GOTOU Yuuzou . # # This file is derived from "http-access.rb". # # Documented by Minero Aoki; converted to RDoc by William Webber. # # This program is free software. You can re-distribute and/or # modify this program under the same terms of ruby itself --- # Ruby Distribution License or GNU General Public License. # # See Net::HTTP for an overview and examples. # # NOTE: You can find Japanese version of this document here: # http://www.ruby-lang.org/ja/man/?cmd=view;name=net%2Fhttp.rb # #-- # $Id: http.rb 29865 2010-11-22 07:22:19Z shyouhei $ #++ require 'net/protocol' require 'uri' module Net #:nodoc: # :stopdoc: class HTTPBadResponse < StandardError; end class HTTPHeaderSyntaxError < StandardError; end # :startdoc: # == What Is This Library? # # This library provides your program functions to access WWW # documents via HTTP, Hyper Text Transfer Protocol version 1.1. # For details of HTTP, refer [RFC2616] # (http://www.ietf.org/rfc/rfc2616.txt). # # == Examples # # === Getting Document From WWW Server # # Example #1: Simple GET+print # # require 'net/http' # Net::HTTP.get_print 'www.example.com', '/index.html' # # Example #2: Simple GET+print by URL # # require 'net/http' # require 'uri' # Net::HTTP.get_print URI.parse('http://www.example.com/index.html') # # Example #3: More generic GET+print # # require 'net/http' # require 'uri' # # url = URI.parse('http://www.example.com/index.html') # res = Net::HTTP.start(url.host, url.port) {|http| # http.get('/index.html') # } # puts res.body # # Example #4: More generic GET+print # # require 'net/http' # # url = URI.parse('http://www.example.com/index.html') # req = Net::HTTP::Get.new(url.path) # res = Net::HTTP.start(url.host, url.port) {|http| # http.request(req) # } # puts res.body # # === Posting Form Data # # require 'net/http' # require 'uri' # # #1: Simple POST # res = Net::HTTP.post_form(URI.parse('http://www.example.com/search.cgi'), # {'q'=>'ruby', 'max'=>'50'}) # puts res.body # # #2: POST with basic authentication # res = Net::HTTP.post_form(URI.parse('http://jack:pass@www.example.com/todo.cgi'), # {'from'=>'2005-01-01', 'to'=>'2005-03-31'}) # puts res.body # # #3: Detailed control # url = URI.parse('http://www.example.com/todo.cgi') # req = Net::HTTP::Post.new(url.path) # req.basic_auth 'jack', 'pass' # req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';') # res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) } # case res # when Net::HTTPSuccess, Net::HTTPRedirection # # OK # else # res.error! # end # # === Accessing via Proxy # # Net::HTTP.Proxy creates http proxy class. It has same # methods of Net::HTTP but its instances always connect to # proxy, instead of given host. # # require 'net/http' # # proxy_addr = 'your.proxy.host' # proxy_port = 8080 # : # Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|http| # # always connect to your.proxy.addr:8080 # : # } # # Since Net::HTTP.Proxy returns Net::HTTP itself when proxy_addr is nil, # there's no need to change code if there's proxy or not. # # There are two additional parameters in Net::HTTP.Proxy which allow to # specify proxy user name and password: # # Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil) # # You may use them to work with authorization-enabled proxies: # # require 'net/http' # require 'uri' # # proxy_host = 'your.proxy.host' # proxy_port = 8080 # uri = URI.parse(ENV['http_proxy']) # proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo # Net::HTTP::Proxy(proxy_host, proxy_port, # proxy_user, proxy_pass).start('www.example.com') {|http| # # always connect to your.proxy.addr:8080 using specified username and password # : # } # # Note that net/http never rely on HTTP_PROXY environment variable. # If you want to use proxy, set it explicitly. # # === Following Redirection # # require 'net/http' # require 'uri' # # def fetch(uri_str, limit = 10) # # You should choose better exception. # raise ArgumentError, 'HTTP redirect too deep' if limit == 0 # # response = Net::HTTP.get_response(URI.parse(uri_str)) # case response # when Net::HTTPSuccess then response # when Net::HTTPRedirection then fetch(response['location'], limit - 1) # else # response.error! # end # end # # print fetch('http://www.ruby-lang.org') # # Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class. # All HTTPResponse objects belong to its own response class which # indicate HTTP result status. For details of response classes, # see section "HTTP Response Classes". # # === Basic Authentication # # require 'net/http' # # Net::HTTP.start('www.example.com') {|http| # req = Net::HTTP::Get.new('/secret-page.html') # req.basic_auth 'account', 'password' # response = http.request(req) # print response.body # } # # === HTTP Request Classes # # Here is HTTP request class hierarchy. # # Net::HTTPRequest # Net::HTTP::Get # Net::HTTP::Head # Net::HTTP::Post # Net::HTTP::Put # Net::HTTP::Proppatch # Net::HTTP::Lock # Net::HTTP::Unlock # Net::HTTP::Options # Net::HTTP::Propfind # Net::HTTP::Delete # Net::HTTP::Move # Net::HTTP::Copy # Net::HTTP::Mkcol # Net::HTTP::Trace # # === HTTP Response Classes # # Here is HTTP response class hierarchy. # All classes are defined in Net module. # # HTTPResponse # HTTPUnknownResponse # HTTPInformation # 1xx # HTTPContinue # 100 # HTTPSwitchProtocl # 101 # HTTPSuccess # 2xx # HTTPOK # 200 # HTTPCreated # 201 # HTTPAccepted # 202 # HTTPNonAuthoritativeInformation # 203 # HTTPNoContent # 204 # HTTPResetContent # 205 # HTTPPartialContent # 206 # HTTPRedirection # 3xx # HTTPMultipleChoice # 300 # HTTPMovedPermanently # 301 # HTTPFound # 302 # HTTPSeeOther # 303 # HTTPNotModified # 304 # HTTPUseProxy # 305 # HTTPTemporaryRedirect # 307 # HTTPClientError # 4xx # HTTPBadRequest # 400 # HTTPUnauthorized # 401 # HTTPPaymentRequired # 402 # HTTPForbidden # 403 # HTTPNotFound # 404 # HTTPMethodNotAllowed # 405 # HTTPNotAcceptable # 406 # HTTPProxyAuthenticationRequired # 407 # HTTPRequestTimeOut # 408 # HTTPConflict # 409 # HTTPGone # 410 # HTTPLengthRequired # 411 # HTTPPreconditionFailed # 412 # HTTPRequestEntityTooLarge # 413 # HTTPRequestURITooLong # 414 # HTTPUnsupportedMediaType # 415 # HTTPRequestedRangeNotSatisfiable # 416 # HTTPExpectationFailed # 417 # HTTPServerError # 5xx # HTTPInternalServerError # 500 # HTTPNotImplemented # 501 # HTTPBadGateway # 502 # HTTPServiceUnavailable # 503 # HTTPGatewayTimeOut # 504 # HTTPVersionNotSupported # 505 # # == Switching Net::HTTP versions # # You can use net/http.rb 1.1 features (bundled with Ruby 1.6) # by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2 # allows you to use 1.2 features again. # # # example # Net::HTTP.start {|http1| ...(http1 has 1.2 features)... } # # Net::HTTP.version_1_1 # Net::HTTP.start {|http2| ...(http2 has 1.1 features)... } # # Net::HTTP.version_1_2 # Net::HTTP.start {|http3| ...(http3 has 1.2 features)... } # # This function is NOT thread-safe. # class HTTP < Protocol # :stopdoc: Revision = %q$Revision: 29865 $.split[1] HTTPVersion = '1.1' @newimpl = true # :startdoc: # Turns on net/http 1.2 (ruby 1.8) features. # Defaults to ON in ruby 1.8. # # I strongly recommend to call this method always. # # require 'net/http' # Net::HTTP.version_1_2 # def HTTP.version_1_2 @newimpl = true end # Turns on net/http 1.1 (ruby 1.6) features. # Defaults to OFF in ruby 1.8. def HTTP.version_1_1 @newimpl = false end # true if net/http is in version 1.2 mode. # Defaults to true. def HTTP.version_1_2? @newimpl end # true if net/http is in version 1.1 compatible mode. # Defaults to true. def HTTP.version_1_1? not @newimpl end class << HTTP alias is_version_1_1? version_1_1? #:nodoc: alias is_version_1_2? version_1_2? #:nodoc: end # # short cut methods # # # Get body from target and output it to +$stdout+. The # target can either be specified as (+uri+), or as # (+host+, +path+, +port+ = 80); so: # # Net::HTTP.get_print URI.parse('http://www.example.com/index.html') # # or: # # Net::HTTP.get_print 'www.example.com', '/index.html' # def HTTP.get_print(uri_or_host, path = nil, port = nil) get_response(uri_or_host, path, port) {|res| res.read_body do |chunk| $stdout.print chunk end } nil end # Send a GET request to the target and return the response # as a string. The target can either be specified as # (+uri+), or as (+host+, +path+, +port+ = 80); so: # # print Net::HTTP.get(URI.parse('http://www.example.com/index.html')) # # or: # # print Net::HTTP.get('www.example.com', '/index.html') # def HTTP.get(uri_or_host, path = nil, port = nil) get_response(uri_or_host, path, port).body end # Send a GET request to the target and return the response # as a Net::HTTPResponse object. The target can either be specified as # (+uri+), or as (+host+, +path+, +port+ = 80); so: # # res = Net::HTTP.get_response(URI.parse('http://www.example.com/index.html')) # print res.body # # or: # # res = Net::HTTP.get_response('www.example.com', '/index.html') # print res.body # def HTTP.get_response(uri_or_host, path = nil, port = nil, &block) if path host = uri_or_host new(host, port || HTTP.default_port).start {|http| return http.request_get(path, &block) } else uri = uri_or_host new(uri.host, uri.port).start {|http| return http.request_get(uri.request_uri, &block) } end end # Posts HTML form data to the +URL+. # Form data must be represented as a Hash of String to String, e.g: # # { "cmd" => "search", "q" => "ruby", "max" => "50" } # # This method also does Basic Authentication iff +URL+.user exists. # # Example: # # require 'net/http' # require 'uri' # # HTTP.post_form URI.parse('http://www.example.com/search.cgi'), # { "q" => "ruby", "max" => "50" } # def HTTP.post_form(url, params) req = Post.new(url.path) req.form_data = params req.basic_auth url.user, url.password if url.user new(url.host, url.port).start {|http| http.request(req) } end # # HTTP session management # # The default port to use for HTTP requests; defaults to 80. def HTTP.default_port http_default_port() end # The default port to use for HTTP requests; defaults to 80. def HTTP.http_default_port 80 end # The default port to use for HTTPS requests; defaults to 443. def HTTP.https_default_port 443 end def HTTP.socket_type #:nodoc: obsolete BufferedIO end # creates a new Net::HTTP object and opens its TCP connection and # HTTP session. If the optional block is given, the newly # created Net::HTTP object is passed to it and closed when the # block finishes. In this case, the return value of this method # is the return value of the block. If no block is given, the # return value of this method is the newly created Net::HTTP object # itself, and the caller is responsible for closing it upon completion. def HTTP.start(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil, &block) # :yield: +http+ new(address, port, p_addr, p_port, p_user, p_pass).start(&block) end class << HTTP alias newobj new end # Creates a new Net::HTTP object. # If +proxy_addr+ is given, creates an Net::HTTP object with proxy support. # This method does not open the TCP connection. def HTTP.new(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil) h = Proxy(p_addr, p_port, p_user, p_pass).newobj(address, port) h.instance_eval { @newimpl = ::Net::HTTP.version_1_2? } h end # Creates a new Net::HTTP object for the specified +address+. # This method does not open the TCP connection. def initialize(address, port = nil) @address = address @port = (port || HTTP.default_port) @curr_http_version = HTTPVersion @seems_1_0_server = false @close_on_empty_response = false @socket = nil @started = false @open_timeout = nil @read_timeout = 60 @debug_output = nil @use_ssl = false @ssl_context = nil end def inspect "#<#{self.class} #{@address}:#{@port} open=#{started?}>" end # *WARNING* This method causes serious security hole. # Never use this method in production code. # # Set an output stream for debugging. # # http = Net::HTTP.new # http.set_debug_output $stderr # http.start { .... } # def set_debug_output(output) warn 'Net::HTTP#set_debug_output called after HTTP started' if started? @debug_output = output end # The host name to connect to. attr_reader :address # The port number to connect to. attr_reader :port # Seconds to wait until connection is opened. # If the HTTP object cannot open a connection in this many seconds, # it raises a TimeoutError exception. attr_accessor :open_timeout # Seconds to wait until reading one block (by one read(2) call). # If the HTTP object cannot open a connection in this many seconds, # it raises a TimeoutError exception. attr_reader :read_timeout # Setter for the read_timeout attribute. def read_timeout=(sec) @socket.read_timeout = sec if @socket @read_timeout = sec end # returns true if the HTTP session is started. def started? @started end alias active? started? #:nodoc: obsolete attr_accessor :close_on_empty_response # returns true if use SSL/TLS with HTTP. def use_ssl? false # redefined in net/https end # Opens TCP connection and HTTP session. # # When this method is called with block, gives a HTTP object # to the block and closes the TCP connection / HTTP session # after the block executed. # # When called with a block, returns the return value of the # block; otherwise, returns self. # def start # :yield: http raise IOError, 'HTTP session already opened' if @started if block_given? begin do_start return yield(self) ensure do_finish end end do_start self end def do_start connect @started = true end private :do_start def connect D "opening connection to #{conn_address()}..." s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) } D "opened" if use_ssl? unless @ssl_context.verify_mode warn "warning: peer certificate won't be verified in this SSL session" @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE end s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) s.sync_close = true end @socket = BufferedIO.new(s) @socket.read_timeout = @read_timeout @socket.debug_output = @debug_output if use_ssl? if proxy? @socket.writeline sprintf('CONNECT %s:%s HTTP/%s', @address, @port, HTTPVersion) @socket.writeline "Host: #{@address}:#{@port}" if proxy_user credential = ["#{proxy_user}:#{proxy_pass}"].pack('m') credential.delete!("\r\n") @socket.writeline "Proxy-Authorization: Basic #{credential}" end @socket.writeline '' HTTPResponse.read_new(@socket).value end s.connect if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE s.post_connection_check(@address) end end on_connect end private :connect def on_connect end private :on_connect # Finishes HTTP session and closes TCP connection. # Raises IOError if not started. def finish raise IOError, 'HTTP session not yet started' unless started? do_finish end def do_finish @started = false @socket.close if @socket and not @socket.closed? @socket = nil end private :do_finish # # proxy # public # no proxy @is_proxy_class = false @proxy_addr = nil @proxy_port = nil @proxy_user = nil @proxy_pass = nil # Creates an HTTP proxy class. # Arguments are address/port of proxy host and username/password # if authorization on proxy server is required. # You can replace the HTTP class with created proxy class. # # If ADDRESS is nil, this method returns self (Net::HTTP). # # # Example # proxy_class = Net::HTTP::Proxy('proxy.example.com', 8080) # : # proxy_class.start('www.ruby-lang.org') {|http| # # connecting proxy.foo.org:8080 # : # } # def HTTP.Proxy(p_addr, p_port = nil, p_user = nil, p_pass = nil) return self unless p_addr delta = ProxyDelta proxyclass = Class.new(self) proxyclass.module_eval { include delta # with proxy @is_proxy_class = true @proxy_address = p_addr @proxy_port = p_port || default_port() @proxy_user = p_user @proxy_pass = p_pass } proxyclass end class << HTTP # returns true if self is a class which was created by HTTP::Proxy. def proxy_class? @is_proxy_class end attr_reader :proxy_address attr_reader :proxy_port attr_reader :proxy_user attr_reader :proxy_pass end # True if self is a HTTP proxy class. def proxy? self.class.proxy_class? end # Address of proxy host. If self does not use a proxy, nil. def proxy_address self.class.proxy_address end # Port number of proxy host. If self does not use a proxy, nil. def proxy_port self.class.proxy_port end # User name for accessing proxy. If self does not use a proxy, nil. def proxy_user self.class.proxy_user end # User password for accessing proxy. If self does not use a proxy, nil. def proxy_pass self.class.proxy_pass end alias proxyaddr proxy_address #:nodoc: obsolete alias proxyport proxy_port #:nodoc: obsolete private # without proxy def conn_address address() end def conn_port port() end def edit_path(path) path end module ProxyDelta #:nodoc: internal use only private def conn_address proxy_address() end def conn_port proxy_port() end def edit_path(path) use_ssl? ? path : "http://#{addr_port()}#{path}" end end # # HTTP operations # public # Gets data from +path+ on the connected-to host. # +header+ must be a Hash like { 'Accept' => '*/*', ... }. # # In version 1.1 (ruby 1.6), this method returns a pair of objects, # a Net::HTTPResponse object and the entity body string. # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse # object. # # If called with a block, yields each fragment of the # entity body in turn as a string as it is read from # the socket. Note that in this case, the returned response # object will *not* contain a (meaningful) body. # # +dest+ argument is obsolete. # It still works but you must not use it. # # In version 1.1, this method might raise an exception for # 3xx (redirect). In this case you can get a HTTPResponse object # by "anException.response". # # In version 1.2, this method never raises exception. # # # version 1.1 (bundled with Ruby 1.6) # response, body = http.get('/index.html') # # # version 1.2 (bundled with Ruby 1.8 or later) # response = http.get('/index.html') # # # using block # File.open('result.txt', 'w') {|f| # http.get('/~foo/') do |str| # f.write str # end # } # def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+ res = nil request(Get.new(path, initheader)) {|r| r.read_body dest, &block res = r } unless @newimpl res.value return res, res.body end res end # Gets only the header from +path+ on the connected-to host. # +header+ is a Hash like { 'Accept' => '*/*', ... }. # # This method returns a Net::HTTPResponse object. # # In version 1.1, this method might raise an exception for # 3xx (redirect). On the case you can get a HTTPResponse object # by "anException.response". # In version 1.2, this method never raises an exception. # # response = nil # Net::HTTP.start('some.www.server', 80) {|http| # response = http.head('/index.html') # } # p response['content-type'] # def head(path, initheader = nil) res = request(Head.new(path, initheader)) res.value unless @newimpl res end # Posts +data+ (must be a String) to +path+. +header+ must be a Hash # like { 'Accept' => '*/*', ... }. # # In version 1.1 (ruby 1.6), this method returns a pair of objects, a # Net::HTTPResponse object and an entity body string. # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse object. # # If called with a block, yields each fragment of the # entity body in turn as a string as it are read from # the socket. Note that in this case, the returned response # object will *not* contain a (meaningful) body. # # +dest+ argument is obsolete. # It still works but you must not use it. # # In version 1.1, this method might raise an exception for # 3xx (redirect). In this case you can get an HTTPResponse object # by "anException.response". # In version 1.2, this method never raises exception. # # # version 1.1 # response, body = http.post('/cgi-bin/search.rb', 'query=foo') # # # version 1.2 # response = http.post('/cgi-bin/search.rb', 'query=foo') # # # using block # File.open('result.txt', 'w') {|f| # http.post('/cgi-bin/search.rb', 'query=foo') do |str| # f.write str # end # } # # You should set Content-Type: header field for POST. # If no Content-Type: field given, this method uses # "application/x-www-form-urlencoded" by default. # def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+ res = nil request(Post.new(path, initheader), data) {|r| r.read_body dest, &block res = r } unless @newimpl res.value return res, res.body end res end def put(path, data, initheader = nil) #:nodoc: res = request(Put.new(path, initheader), data) res.value unless @newimpl res end # Sends a PROPPATCH request to the +path+ and gets a response, # as an HTTPResponse object. def proppatch(path, body, initheader = nil) request(Proppatch.new(path, initheader), body) end # Sends a LOCK request to the +path+ and gets a response, # as an HTTPResponse object. def lock(path, body, initheader = nil) request(Lock.new(path, initheader), body) end # Sends a UNLOCK request to the +path+ and gets a response, # as an HTTPResponse object. def unlock(path, body, initheader = nil) request(Unlock.new(path, initheader), body) end # Sends a OPTIONS request to the +path+ and gets a response, # as an HTTPResponse object. def options(path, initheader = nil) request(Options.new(path, initheader)) end # Sends a PROPFIND request to the +path+ and gets a response, # as an HTTPResponse object. def propfind(path, body = nil, initheader = {'Depth' => '0'}) request(Propfind.new(path, initheader), body) end # Sends a DELETE request to the +path+ and gets a response, # as an HTTPResponse object. def delete(path, initheader = {'Depth' => 'Infinity'}) request(Delete.new(path, initheader)) end # Sends a MOVE request to the +path+ and gets a response, # as an HTTPResponse object. def move(path, initheader = nil) request(Move.new(path, initheader)) end # Sends a COPY request to the +path+ and gets a response, # as an HTTPResponse object. def copy(path, initheader = nil) request(Copy.new(path, initheader)) end # Sends a MKCOL request to the +path+ and gets a response, # as an HTTPResponse object. def mkcol(path, body = nil, initheader = nil) request(Mkcol.new(path, initheader), body) end # Sends a TRACE request to the +path+ and gets a response, # as an HTTPResponse object. def trace(path, initheader = nil) request(Trace.new(path, initheader)) end # Sends a GET request to the +path+ and gets a response, # as an HTTPResponse object. # # When called with a block, yields an HTTPResponse object. # The body of this response will not have been read yet; # the caller can process it using HTTPResponse#read_body, # if desired. # # Returns the response. # # This method never raises Net::* exceptions. # # response = http.request_get('/index.html') # # The entity body is already read here. # p response['content-type'] # puts response.body # # # using block # http.request_get('/index.html') {|response| # p response['content-type'] # response.read_body do |str| # read body now # print str # end # } # def request_get(path, initheader = nil, &block) # :yield: +response+ request(Get.new(path, initheader), &block) end # Sends a HEAD request to the +path+ and gets a response, # as an HTTPResponse object. # # Returns the response. # # This method never raises Net::* exceptions. # # response = http.request_head('/index.html') # p response['content-type'] # def request_head(path, initheader = nil, &block) request(Head.new(path, initheader), &block) end # Sends a POST request to the +path+ and gets a response, # as an HTTPResponse object. # # When called with a block, yields an HTTPResponse object. # The body of this response will not have been read yet; # the caller can process it using HTTPResponse#read_body, # if desired. # # Returns the response. # # This method never raises Net::* exceptions. # # # example # response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...') # p response.status # puts response.body # body is already read # # # using block # http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response| # p response.status # p response['content-type'] # response.read_body do |str| # read body now # print str # end # } # def request_post(path, data, initheader = nil, &block) # :yield: +response+ request Post.new(path, initheader), data, &block end def request_put(path, data, initheader = nil, &block) #:nodoc: request Put.new(path, initheader), data, &block end alias get2 request_get #:nodoc: obsolete alias head2 request_head #:nodoc: obsolete alias post2 request_post #:nodoc: obsolete alias put2 request_put #:nodoc: obsolete # Sends an HTTP request to the HTTP server. # This method also sends DATA string if DATA is given. # # Returns a HTTPResponse object. # # This method never raises Net::* exceptions. # # response = http.send_request('GET', '/index.html') # puts response.body # def send_request(name, path, data = nil, header = nil) r = HTTPGenericRequest.new(name,(data ? true : false),true,path,header) request r, data end # Sends an HTTPRequest object REQUEST to the HTTP server. # This method also sends DATA string if REQUEST is a post/put request. # Giving DATA for get/head request causes ArgumentError. # # When called with a block, yields an HTTPResponse object. # The body of this response will not have been read yet; # the caller can process it using HTTPResponse#read_body, # if desired. # # Returns a HTTPResponse object. # # This method never raises Net::* exceptions. # def request(req, body = nil, &block) # :yield: +response+ unless started? start { req['connection'] ||= 'close' return request(req, body, &block) } end if proxy_user() unless use_ssl? req.proxy_basic_auth proxy_user(), proxy_pass() end end req.set_body_internal body begin begin_transport req req.exec @socket, @curr_http_version, edit_path(req.path) begin res = HTTPResponse.read_new(@socket) end while res.kind_of?(HTTPContinue) res.reading_body(@socket, req.response_body_permitted?) { yield res if block_given? } end_transport req, res rescue => exception D "Conn close because of error #{exception}" @socket.close if @socket and not @socket.closed? raise exception end res end private def begin_transport(req) if @socket.closed? connect end if @seems_1_0_server req['connection'] ||= 'close' end if not req.response_body_permitted? and @close_on_empty_response req['connection'] ||= 'close' end req['host'] ||= addr_port() end def end_transport(req, res) @curr_http_version = res.http_version if not res.body and @close_on_empty_response D 'Conn close' @socket.close elsif keep_alive?(req, res) D 'Conn keep-alive' if @socket.closed? D 'Conn (but seems 1.0 server)' @seems_1_0_server = true end else D 'Conn close' @socket.close end end def keep_alive?(req, res) return false if /close/i =~ req['connection'].to_s return false if @seems_1_0_server return true if /keep-alive/i =~ res['connection'].to_s return false if /close/i =~ res['connection'].to_s return true if /keep-alive/i =~ res['proxy-connection'].to_s return false if /close/i =~ res['proxy-connection'].to_s (@curr_http_version == '1.1') end # # utils # private def addr_port if use_ssl? address() + (port == HTTP.https_default_port ? '' : ":#{port()}") else address() + (port == HTTP.http_default_port ? '' : ":#{port()}") end end def D(msg) return unless @debug_output @debug_output << msg @debug_output << "\n" end end HTTPSession = HTTP # # Header module. # # Provides access to @header in the mixed-into class as a hash-like # object, except with case-insensitive keys. Also provides # methods for accessing commonly-used header values in a more # convenient format. # module HTTPHeader def initialize_http_header(initheader) @header = {} return unless initheader initheader.each do |key, value| warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE @header[key.downcase] = [value.strip] end end def size #:nodoc: obsolete @header.size end alias length size #:nodoc: obsolete # Returns the header field corresponding to the case-insensitive key. # For example, a key of "Content-Type" might return "text/html" def [](key) a = @header[key.downcase] or return nil a.join(', ') end # Sets the header field corresponding to the case-insensitive key. def []=(key, val) unless val @header.delete key.downcase return val end @header[key.downcase] = [val] end # [Ruby 1.8.3] # Adds header field instead of replace. # Second argument +val+ must be a String. # See also #[]=, #[] and #get_fields. # # request.add_field 'X-My-Header', 'a' # p request['X-My-Header'] #=> "a" # p request.get_fields('X-My-Header') #=> ["a"] # request.add_field 'X-My-Header', 'b' # p request['X-My-Header'] #=> "a, b" # p request.get_fields('X-My-Header') #=> ["a", "b"] # request.add_field 'X-My-Header', 'c' # p request['X-My-Header'] #=> "a, b, c" # p request.get_fields('X-My-Header') #=> ["a", "b", "c"] # def add_field(key, val) if @header.key?(key.downcase) @header[key.downcase].push val else @header[key.downcase] = [val] end end # [Ruby 1.8.3] # Returns an array of header field strings corresponding to the # case-insensitive +key+. This method allows you to get duplicated # header fields without any processing. See also #[]. # # p response.get_fields('Set-Cookie') # #=> ["session=al98axx; expires=Fri, 31-Dec-1999 23:58:23", # "query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"] # p response['Set-Cookie'] # #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23" # def get_fields(key) return nil unless @header[key.downcase] @header[key.downcase].dup end # Returns the header field corresponding to the case-insensitive key. # Returns the default value +args+, or the result of the block, or nil, # if there's no header field named key. See Hash#fetch def fetch(key, *args, &block) #:yield: +key+ a = @header.fetch(key.downcase, *args, &block) a.join(', ') end # Iterates for each header names and values. def each_header #:yield: +key+, +value+ @header.each do |k,va| yield k, va.join(', ') end end alias each each_header # Iterates for each header names. def each_name(&block) #:yield: +key+ @header.each_key(&block) end alias each_key each_name # Iterates for each capitalized header names. def each_capitalized_name(&block) #:yield: +key+ @header.each_key do |k| yield capitalize(k) end end # Iterates for each header values. def each_value #:yield: +value+ @header.each_value do |va| yield va.join(', ') end end # Removes a header field. def delete(key) @header.delete(key.downcase) end # true if +key+ header exists. def key?(key) @header.key?(key.downcase) end # Returns a Hash consist of header names and values. def to_hash @header.dup end # As for #each_header, except the keys are provided in capitalized form. def each_capitalized @header.each do |k,v| yield capitalize(k), v.join(', ') end end alias canonical_each each_capitalized def capitalize(name) name.split(/-/).map {|s| s.capitalize }.join('-') end private :capitalize # Returns an Array of Range objects which represents Range: header field, # or +nil+ if there is no such header. def range return nil unless @header['range'] self['Range'].split(/,/).map {|spec| m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or raise HTTPHeaderSyntaxError, "wrong Range: #{spec}" d1 = m[1].to_i d2 = m[2].to_i if m[1] and m[2] then d1..d2 elsif m[1] then d1..-1 elsif m[2] then -d2..-1 else raise HTTPHeaderSyntaxError, 'range is not specified' end } end # Set Range: header from Range (arg r) or beginning index and # length from it (arg idx&len). # # req.range = (0..1023) # req.set_range 0, 1023 # def set_range(r, e = nil) unless r @header.delete 'range' return r end r = (r...r+e) if e case r when Numeric n = r.to_i rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}") when Range first = r.first last = r.last last -= 1 if r.exclude_end? if last == -1 rangestr = (first > 0 ? "#{first}-" : "-#{-first}") else raise HTTPHeaderSyntaxError, 'range.first is negative' if first < 0 raise HTTPHeaderSyntaxError, 'range.last is negative' if last < 0 raise HTTPHeaderSyntaxError, 'must be .first < .last' if first > last rangestr = "#{first}-#{last}" end else raise TypeError, 'Range/Integer is required' end @header['range'] = ["bytes=#{rangestr}"] r end alias range= set_range # Returns an Integer object which represents the Content-Length: header field # or +nil+ if that field is not provided. def content_length return nil unless key?('Content-Length') len = self['Content-Length'].slice(/\d+/) or raise HTTPHeaderSyntaxError, 'wrong Content-Length format' len.to_i end def content_length=(len) unless len @header.delete 'content-length' return nil end @header['content-length'] = [len.to_i.to_s] end # Returns "true" if the "transfer-encoding" header is present and # set to "chunked". This is an HTTP/1.1 feature, allowing the # the content to be sent in "chunks" without at the outset # stating the entire content length. def chunked? return false unless @header['transfer-encoding'] field = self['Transfer-Encoding'] (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false end # Returns a Range object which represents Content-Range: header field. # This indicates, for a partial entity body, where this fragment # fits inside the full entity body, as range of byte offsets. def content_range return nil unless @header['content-range'] m = %ri.match(self['Content-Range']) or raise HTTPHeaderSyntaxError, 'wrong Content-Range format' m[1].to_i .. m[2].to_i end # The length of the range represented in Content-Range: header. def range_length r = content_range() or return nil r.end - r.begin + 1 end # Returns a content type string such as "text/html". # This method returns nil if Content-Type: header field does not exist. def content_type return nil unless main_type() if sub_type() then "#{main_type()}/#{sub_type()}" else main_type() end end # Returns a content type string such as "text". # This method returns nil if Content-Type: header field does not exist. def main_type return nil unless @header['content-type'] self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip end # Returns a content type string such as "html". # This method returns nil if Content-Type: header field does not exist # or sub-type is not given (e.g. "Content-Type: text"). def sub_type return nil unless @header['content-type'] main, sub = *self['Content-Type'].split(';').first.to_s.split('/') return nil unless sub sub.strip end # Returns content type parameters as a Hash as like # {"charset" => "iso-2022-jp"}. def type_params result = {} list = self['Content-Type'].to_s.split(';') list.shift list.each do |param| k, v = *param.split('=', 2) result[k.strip] = v.strip end result end # Set Content-Type: header field by +type+ and +params+. # +type+ must be a String, +params+ must be a Hash. def set_content_type(type, params = {}) @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')] end alias content_type= set_content_type # Set header fields and a body from HTML form data. # +params+ should be a Hash containing HTML form data. # Optional argument +sep+ means data record separator. # # This method also set Content-Type: header field to # application/x-www-form-urlencoded. def set_form_data(params, sep = '&') self.body = params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join(sep) self.content_type = 'application/x-www-form-urlencoded' end alias form_data= set_form_data def urlencode(str) str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) } end private :urlencode # Set the Authorization: header for "Basic" authorization. def basic_auth(account, password) @header['authorization'] = [basic_encode(account, password)] end # Set Proxy-Authorization: header for "Basic" authorization. def proxy_basic_auth(account, password) @header['proxy-authorization'] = [basic_encode(account, password)] end def basic_encode(account, password) 'Basic ' + ["#{account}:#{password}"].pack('m').delete("\r\n") end private :basic_encode end # # Parent of HTTPRequest class. Do not use this directly; use # a subclass of HTTPRequest. # # Mixes in the HTTPHeader module. # class HTTPGenericRequest include HTTPHeader BUFSIZE = 16*1024 def initialize(m, reqbody, resbody, path, initheader = nil) @method = m @request_has_body = reqbody @response_has_body = resbody raise ArgumentError, "HTTP request path is empty" if path.empty? @path = path initialize_http_header initheader self['Accept'] ||= '*/*' @body = nil @body_stream = nil end attr_reader :method attr_reader :path def inspect "\#<#{self.class} #{@method}>" end def request_body_permitted? @request_has_body end def response_body_permitted? @response_has_body end def body_exist? warn "Net::HTTPRequest#body_exist? is obsolete; use response_body_permitted?" if $VERBOSE response_body_permitted? end attr_reader :body def body=(str) @body = str @body_stream = nil str end attr_reader :body_stream def body_stream=(input) @body = nil @body_stream = input input end def set_body_internal(str) #:nodoc: internal use only raise ArgumentError, "both of body argument and HTTPRequest#body set" if str and (@body or @body_stream) self.body = str if str end # # write # def exec(sock, ver, path) #:nodoc: internal use only if @body send_request_with_body sock, ver, path, @body elsif @body_stream send_request_with_body_stream sock, ver, path, @body_stream else write_header sock, ver, path end end private def send_request_with_body(sock, ver, path, body) self.content_length = body.length delete 'Transfer-Encoding' supply_default_content_type write_header sock, ver, path sock.write body end def send_request_with_body_stream(sock, ver, path, f) unless content_length() or chunked? raise ArgumentError, "Content-Length not given and Transfer-Encoding is not `chunked'" end supply_default_content_type write_header sock, ver, path if chunked? while s = f.read(BUFSIZE) sock.write(sprintf("%x\r\n", s.length) << s << "\r\n") end sock.write "0\r\n\r\n" else while s = f.read(BUFSIZE) sock.write s end end end def supply_default_content_type return if content_type() warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE set_content_type 'application/x-www-form-urlencoded' end def write_header(sock, ver, path) buf = "#{@method} #{path} HTTP/#{ver}\r\n" each_capitalized do |k,v| buf << "#{k}: #{v}\r\n" end buf << "\r\n" sock.write buf end end # # HTTP request class. This class wraps request header and entity path. # You *must* use its subclass, Net::HTTP::Get, Post, Head. # class HTTPRequest < HTTPGenericRequest # Creates HTTP request object. def initialize(path, initheader = nil) super self.class::METHOD, self.class::REQUEST_HAS_BODY, self.class::RESPONSE_HAS_BODY, path, initheader end end class HTTP # reopen # # HTTP 1.1 methods --- RFC2616 # class Get < HTTPRequest METHOD = 'GET' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end class Head < HTTPRequest METHOD = 'HEAD' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = false end class Post < HTTPRequest METHOD = 'POST' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Put < HTTPRequest METHOD = 'PUT' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Delete < HTTPRequest METHOD = 'DELETE' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end class Options < HTTPRequest METHOD = 'OPTIONS' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = false end class Trace < HTTPRequest METHOD = 'TRACE' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end # # WebDAV methods --- RFC2518 # class Propfind < HTTPRequest METHOD = 'PROPFIND' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Proppatch < HTTPRequest METHOD = 'PROPPATCH' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Mkcol < HTTPRequest METHOD = 'MKCOL' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Copy < HTTPRequest METHOD = 'COPY' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end class Move < HTTPRequest METHOD = 'MOVE' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end class Lock < HTTPRequest METHOD = 'LOCK' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Unlock < HTTPRequest METHOD = 'UNLOCK' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end end ### ### Response ### # HTTP exception class. # You must use its subclasses. module HTTPExceptions def initialize(msg, res) #:nodoc: super msg @response = res end attr_reader :response alias data response #:nodoc: obsolete end class HTTPError < ProtocolError include HTTPExceptions end class HTTPRetriableError < ProtoRetriableError include HTTPExceptions end class HTTPServerException < ProtoServerError # We cannot use the name "HTTPServerError", it is the name of the response. include HTTPExceptions end class HTTPFatalError < ProtoFatalError include HTTPExceptions end # HTTP response class. This class wraps response header and entity. # Mixes in the HTTPHeader module, which provides access to response # header values both via hash-like methods and individual readers. # Note that each possible HTTP response code defines its own # HTTPResponse subclass. These are listed below. # All classes are # defined under the Net module. Indentation indicates inheritance. # # xxx HTTPResponse # # 1xx HTTPInformation # 100 HTTPContinue # 101 HTTPSwitchProtocol # # 2xx HTTPSuccess # 200 HTTPOK # 201 HTTPCreated # 202 HTTPAccepted # 203 HTTPNonAuthoritativeInformation # 204 HTTPNoContent # 205 HTTPResetContent # 206 HTTPPartialContent # # 3xx HTTPRedirection # 300 HTTPMultipleChoice # 301 HTTPMovedPermanently # 302 HTTPFound # 303 HTTPSeeOther # 304 HTTPNotModified # 305 HTTPUseProxy # 307 HTTPTemporaryRedirect # # 4xx HTTPClientError # 400 HTTPBadRequest # 401 HTTPUnauthorized # 402 HTTPPaymentRequired # 403 HTTPForbidden # 404 HTTPNotFound # 405 HTTPMethodNotAllowed # 406 HTTPNotAcceptable # 407 HTTPProxyAuthenticationRequired # 408 HTTPRequestTimeOut # 409 HTTPConflict # 410 HTTPGone # 411 HTTPLengthRequired # 412 HTTPPreconditionFailed # 413 HTTPRequestEntityTooLarge # 414 HTTPRequestURITooLong # 415 HTTPUnsupportedMediaType # 416 HTTPRequestedRangeNotSatisfiable # 417 HTTPExpectationFailed # # 5xx HTTPServerError # 500 HTTPInternalServerError # 501 HTTPNotImplemented # 502 HTTPBadGateway # 503 HTTPServiceUnavailable # 504 HTTPGatewayTimeOut # 505 HTTPVersionNotSupported # # xxx HTTPUnknownResponse # class HTTPResponse # true if the response has body. def HTTPResponse.body_permitted? self::HAS_BODY end def HTTPResponse.exception_type # :nodoc: internal use only self::EXCEPTION_TYPE end end # reopened after # :stopdoc: class HTTPUnknownResponse < HTTPResponse HAS_BODY = true EXCEPTION_TYPE = HTTPError end class HTTPInformation < HTTPResponse # 1xx HAS_BODY = false EXCEPTION_TYPE = HTTPError end class HTTPSuccess < HTTPResponse # 2xx HAS_BODY = true EXCEPTION_TYPE = HTTPError end class HTTPRedirection < HTTPResponse # 3xx HAS_BODY = true EXCEPTION_TYPE = HTTPRetriableError end class HTTPClientError < HTTPResponse # 4xx HAS_BODY = true EXCEPTION_TYPE = HTTPServerException # for backward compatibility end class HTTPServerError < HTTPResponse # 5xx HAS_BODY = true EXCEPTION_TYPE = HTTPFatalError # for backward compatibility end class HTTPContinue < HTTPInformation # 100 HAS_BODY = false end class HTTPSwitchProtocol < HTTPInformation # 101 HAS_BODY = false end class HTTPOK < HTTPSuccess # 200 HAS_BODY = true end class HTTPCreated < HTTPSuccess # 201 HAS_BODY = true end class HTTPAccepted < HTTPSuccess # 202 HAS_BODY = true end class HTTPNonAuthoritativeInformation < HTTPSuccess # 203 HAS_BODY = true end class HTTPNoContent < HTTPSuccess # 204 HAS_BODY = false end class HTTPResetContent < HTTPSuccess # 205 HAS_BODY = false end class HTTPPartialContent < HTTPSuccess # 206 HAS_BODY = true end class HTTPMultipleChoice < HTTPRedirection # 300 HAS_BODY = true end class HTTPMovedPermanently < HTTPRedirection # 301 HAS_BODY = true end class HTTPFound < HTTPRedirection # 302 HAS_BODY = true end HTTPMovedTemporarily = HTTPFound class HTTPSeeOther < HTTPRedirection # 303 HAS_BODY = true end class HTTPNotModified < HTTPRedirection # 304 HAS_BODY = false end class HTTPUseProxy < HTTPRedirection # 305 HAS_BODY = false end # 306 unused class HTTPTemporaryRedirect < HTTPRedirection # 307 HAS_BODY = true end class HTTPBadRequest < HTTPClientError # 400 HAS_BODY = true end class HTTPUnauthorized < HTTPClientError # 401 HAS_BODY = true end class HTTPPaymentRequired < HTTPClientError # 402 HAS_BODY = true end class HTTPForbidden < HTTPClientError # 403 HAS_BODY = true end class HTTPNotFound < HTTPClientError # 404 HAS_BODY = true end class HTTPMethodNotAllowed < HTTPClientError # 405 HAS_BODY = true end class HTTPNotAcceptable < HTTPClientError # 406 HAS_BODY = true end class HTTPProxyAuthenticationRequired < HTTPClientError # 407 HAS_BODY = true end class HTTPRequestTimeOut < HTTPClientError # 408 HAS_BODY = true end class HTTPConflict < HTTPClientError # 409 HAS_BODY = true end class HTTPGone < HTTPClientError # 410 HAS_BODY = true end class HTTPLengthRequired < HTTPClientError # 411 HAS_BODY = true end class HTTPPreconditionFailed < HTTPClientError # 412 HAS_BODY = true end class HTTPRequestEntityTooLarge < HTTPClientError # 413 HAS_BODY = true end class HTTPRequestURITooLong < HTTPClientError # 414 HAS_BODY = true end HTTPRequestURITooLarge = HTTPRequestURITooLong class HTTPUnsupportedMediaType < HTTPClientError # 415 HAS_BODY = true end class HTTPRequestedRangeNotSatisfiable < HTTPClientError # 416 HAS_BODY = true end class HTTPExpectationFailed < HTTPClientError # 417 HAS_BODY = true end class HTTPInternalServerError < HTTPServerError # 500 HAS_BODY = true end class HTTPNotImplemented < HTTPServerError # 501 HAS_BODY = true end class HTTPBadGateway < HTTPServerError # 502 HAS_BODY = true end class HTTPServiceUnavailable < HTTPServerError # 503 HAS_BODY = true end class HTTPGatewayTimeOut < HTTPServerError # 504 HAS_BODY = true end class HTTPVersionNotSupported < HTTPServerError # 505 HAS_BODY = true end # :startdoc: class HTTPResponse # reopen CODE_CLASS_TO_OBJ = { '1' => HTTPInformation, '2' => HTTPSuccess, '3' => HTTPRedirection, '4' => HTTPClientError, '5' => HTTPServerError } CODE_TO_OBJ = { '100' => HTTPContinue, '101' => HTTPSwitchProtocol, '200' => HTTPOK, '201' => HTTPCreated, '202' => HTTPAccepted, '203' => HTTPNonAuthoritativeInformation, '204' => HTTPNoContent, '205' => HTTPResetContent, '206' => HTTPPartialContent, '300' => HTTPMultipleChoice, '301' => HTTPMovedPermanently, '302' => HTTPFound, '303' => HTTPSeeOther, '304' => HTTPNotModified, '305' => HTTPUseProxy, '307' => HTTPTemporaryRedirect, '400' => HTTPBadRequest, '401' => HTTPUnauthorized, '402' => HTTPPaymentRequired, '403' => HTTPForbidden, '404' => HTTPNotFound, '405' => HTTPMethodNotAllowed, '406' => HTTPNotAcceptable, '407' => HTTPProxyAuthenticationRequired, '408' => HTTPRequestTimeOut, '409' => HTTPConflict, '410' => HTTPGone, '411' => HTTPLengthRequired, '412' => HTTPPreconditionFailed, '413' => HTTPRequestEntityTooLarge, '414' => HTTPRequestURITooLong, '415' => HTTPUnsupportedMediaType, '416' => HTTPRequestedRangeNotSatisfiable, '417' => HTTPExpectationFailed, '500' => HTTPInternalServerError, '501' => HTTPNotImplemented, '502' => HTTPBadGateway, '503' => HTTPServiceUnavailable, '504' => HTTPGatewayTimeOut, '505' => HTTPVersionNotSupported } class << HTTPResponse def read_new(sock) #:nodoc: internal use only httpv, code, msg = read_status_line(sock) res = response_class(code).new(httpv, code, msg) each_response_header(sock) do |k,v| res.add_field k, v end res end private def read_status_line(sock) str = sock.readline m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/in.match(str) or raise HTTPBadResponse, "wrong status line: #{str.dump}" m.captures end def response_class(code) CODE_TO_OBJ[code] or CODE_CLASS_TO_OBJ[code[0,1]] or HTTPUnknownResponse end def each_response_header(sock) while true line = sock.readuntil("\n", true).sub(/\s+\z/, '') break if line.empty? m = /\A([^:]+):\s*/.match(line) or raise HTTPBadResponse, 'wrong header line format' yield m[1], m.post_match end end end # next is to fix bug in RDoc, where the private inside class << self # spills out. public include HTTPHeader def initialize(httpv, code, msg) #:nodoc: internal use only @http_version = httpv @code = code @message = msg initialize_http_header nil @body = nil @read = false end # The HTTP version supported by the server. attr_reader :http_version # HTTP result code string. For example, '302'. You can also # determine the response type by which response subclass the # response object is an instance of. attr_reader :code # HTTP result message. For example, 'Not Found'. attr_reader :message alias msg message # :nodoc: obsolete def inspect "#<#{self.class} #{@code} #{@message} readbody=#{@read}>" end # For backward compatibility. # To allow Net::HTTP 1.1 style assignment # e.g. # response, body = Net::HTTP.get(....) # def to_ary warn "net/http.rb: warning: Net::HTTP v1.1 style assignment found at #{caller(1)[0]}; use `response = http.get(...)' instead." if $VERBOSE res = self.dup class << res undef to_ary end [res, res.body] end # # response <-> exception relationship # def code_type #:nodoc: self.class end def error! #:nodoc: raise error_type().new(@code + ' ' + @message.dump, self) end def error_type #:nodoc: self.class::EXCEPTION_TYPE end # Raises HTTP error if the response is not 2xx. def value error! unless self.kind_of?(HTTPSuccess) end # # header (for backward compatibility only; DO NOT USE) # def response #:nodoc: warn "#{caller(1)[0]}: warning: HTTPResponse#response is obsolete" if $VERBOSE self end def header #:nodoc: warn "#{caller(1)[0]}: warning: HTTPResponse#header is obsolete" if $VERBOSE self end def read_header #:nodoc: warn "#{caller(1)[0]}: warning: HTTPResponse#read_header is obsolete" if $VERBOSE self end # # body # def reading_body(sock, reqmethodallowbody) #:nodoc: internal use only @socket = sock @body_exist = reqmethodallowbody && self.class.body_permitted? begin yield self.body # ensure to read body ensure @socket = nil end end # Gets entity body. If the block given, yields it to +block+. # The body is provided in fragments, as it is read in from the socket. # # Calling this method a second or subsequent time will return the # already read string. # # http.request_get('/index.html') {|res| # puts res.read_body # } # # http.request_get('/index.html') {|res| # p res.read_body.object_id # 538149362 # p res.read_body.object_id # 538149362 # } # # # using iterator # http.request_get('/index.html') {|res| # res.read_body do |segment| # print segment # end # } # def read_body(dest = nil, &block) if @read raise IOError, "#{self.class}\#read_body called twice" if dest or block return @body end to = procdest(dest, block) stream_check if @body_exist read_body_0 to @body = to else @body = nil end @read = true @body end # Returns the entity body. # # Calling this method a second or subsequent time will return the # already read string. # # http.request_get('/index.html') {|res| # puts res.body # } # # http.request_get('/index.html') {|res| # p res.body.object_id # 538149362 # p res.body.object_id # 538149362 # } # def body read_body() end alias entity body #:nodoc: obsolete private def read_body_0(dest) if chunked? read_chunked dest return end clen = content_length() if clen @socket.read clen, dest, true # ignore EOF return end clen = range_length() if clen @socket.read clen, dest return end @socket.read_all dest end def read_chunked(dest) len = nil total = 0 while true line = @socket.readline hexlen = line.slice(/[0-9a-fA-F]+/) or raise HTTPBadResponse, "wrong chunk size line: #{line}" len = hexlen.hex break if len == 0 @socket.read len, dest; total += len @socket.read 2 # \r\n end until @socket.readline.empty? # none end end def stream_check raise IOError, 'attempt to read body out of block' if @socket.closed? end def procdest(dest, block) raise ArgumentError, 'both arg and block given for HTTP method' \ if dest and block if block ReadAdapter.new(block) else dest || '' end end end # :enddoc: #-- # for backward compatibility class HTTP ProxyMod = ProxyDelta end module NetPrivate HTTPRequest = ::Net::HTTPRequest end HTTPInformationCode = HTTPInformation HTTPSuccessCode = HTTPSuccess HTTPRedirectionCode = HTTPRedirection HTTPRetriableCode = HTTPRedirection HTTPClientErrorCode = HTTPClientError HTTPFatalErrorCode = HTTPClientError HTTPServerErrorCode = HTTPServerError HTTPResponceReceiver = HTTPResponse end # module Net PK|]@ net/ftptls.rbnu[=begin = $RCSfile$ -- SSL/TLS enhancement for Net::HTTP. = Info 'OpenSSL for Ruby 2' project Copyright (C) 2003 Blaz Grilc All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Requirements = Version $Id: ftptls.rb 13657 2007-10-08 11:16:54Z gotoyuzo $ = Notes Tested on FreeBSD 5-CURRENT and 4-STABLE - ruby 1.6.8 (2003-01-17) [i386-freebsd5] - OpenSSL 0.9.7a Feb 19 2003 - ruby-openssl-0.2.0.p0 tested on ftp server: glftpd 1.30 =end require 'socket' require 'openssl' require 'net/ftp' module Net class FTPTLS < FTP def connect(host, port=FTP_PORT) @hostname = host super end def login(user = "anonymous", passwd = nil, acct = nil) store = OpenSSL::X509::Store.new store.set_default_paths ctx = OpenSSL::SSL::SSLContext.new('SSLv23') ctx.cert_store = store ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER ctx.key = nil ctx.cert = nil voidcmd("AUTH TLS") @sock = OpenSSL::SSL::SSLSocket.new(@sock, ctx) @sock.connect @sock.post_connection_check(@hostname) super(user, passwd, acct) voidcmd("PBSZ 0") end end end PK|]/;  net/https.rbnu[=begin = $RCSfile$ -- SSL/TLS enhancement for Net::HTTP. == Info 'OpenSSL for Ruby 2' project Copyright (C) 2001 GOTOU Yuuzou All rights reserved. == Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) == Requirements This program requires Net 1.2.0 or higher version. You can get it from RAA or Ruby's CVS repository. == Version $Id: https.rb 16857 2008-06-06 08:05:24Z knu $ 2001-11-06: Contiributed to Ruby/OpenSSL project. 2004-03-06: Some code is merged in to net/http. == Example Here is a simple HTTP client: require 'net/http' require 'uri' uri = URI.parse(ARGV[0] || 'http://localhost/') http = Net::HTTP.new(uri.host, uri.port) http.start { http.request_get(uri.path) {|res| print res.body } } It can be replaced by the following code: require 'net/https' require 'uri' uri = URI.parse(ARGV[0] || 'https://localhost/') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true if uri.scheme == "https" # enable SSL/TLS http.start { http.request_get(uri.path) {|res| print res.body } } == class Net::HTTP === Instance Methods : use_ssl? returns true if use SSL/TLS with HTTP. : use_ssl=((|true_or_false|)) sets use_ssl. : peer_cert return the X.509 certificates the server presented. : key, key=((|key|)) Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object. (This method is appeared in Michal Rokos's OpenSSL extension.) : cert, cert=((|cert|)) Sets an OpenSSL::X509::Certificate object as client certificate (This method is appeared in Michal Rokos's OpenSSL extension). : ca_file, ca_file=((|path|)) Sets path of a CA certification file in PEM format. The file can contrain several CA certificats. : ca_path, ca_path=((|path|)) Sets path of a CA certification directory containing certifications in PEM format. : verify_mode, verify_mode=((|mode|)) Sets the flags for server the certification verification at begining of SSL/TLS session. OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable. : verify_callback, verify_callback=((|proc|)) Sets the verify callback for the server certification verification. : verify_depth, verify_depth=((|num|)) Sets the maximum depth for the certificate chain verification. : cert_store, cert_store=((|store|)) Sets the X509::Store to verify peer certificate. : ssl_timeout, ssl_timeout=((|sec|)) Sets the SSL timeout seconds. =end require 'net/http' require 'openssl' module Net class HTTP remove_method :use_ssl? def use_ssl? @use_ssl end # For backward compatibility. alias use_ssl use_ssl? # Turn on/off SSL. # This flag must be set before starting session. # If you change use_ssl value after session started, # a Net::HTTP object raises IOError. def use_ssl=(flag) flag = (flag ? true : false) raise IOError, "use_ssl value changed, but session already started" \ if started? and @use_ssl != flag if flag and not @ssl_context @ssl_context = OpenSSL::SSL::SSLContext.new end @use_ssl = flag end def self.ssl_context_accessor(name) module_eval(<<-End, __FILE__, __LINE__ + 1) def #{name} return nil unless @ssl_context @ssl_context.#{name} end def #{name}=(val) @ssl_context ||= OpenSSL::SSL::SSLContext.new @ssl_context.#{name} = val end End end ssl_context_accessor :key ssl_context_accessor :cert ssl_context_accessor :ca_file ssl_context_accessor :ca_path ssl_context_accessor :verify_mode ssl_context_accessor :verify_callback ssl_context_accessor :verify_depth ssl_context_accessor :cert_store def ssl_timeout return nil unless @ssl_context @ssl_context.timeout end def ssl_timeout=(sec) raise ArgumentError, 'Net::HTTP#ssl_timeout= called but use_ssl=false' \ unless use_ssl? @ssl_context ||= OpenSSL::SSL::SSLContext.new @ssl_context.timeout = sec end # For backward compatibility alias timeout= ssl_timeout= def peer_cert return nil if not use_ssl? or not @socket @socket.io.peer_cert end end end PK|]w;`net/protocol.rbnu[# # = net/protocol.rb # #-- # Copyright (c) 1999-2005 Yukihiro Matsumoto # Copyright (c) 1999-2005 Minero Aoki # # written and maintained by Minero Aoki # # This program is free software. You can re-distribute and/or # modify this program under the same terms as Ruby itself, # Ruby Distribute License or GNU General Public License. # # $Id: protocol.rb 12092 2007-03-19 02:39:22Z aamine $ #++ # # WARNING: This file is going to remove. # Do not rely on the implementation written in this file. # require 'socket' require 'timeout' module Net # :nodoc: class Protocol #:nodoc: internal use only private def Protocol.protocol_param(name, val) module_eval(<<-End, __FILE__, __LINE__ + 1) def #{name} #{val} end End end end class ProtocolError < StandardError; end class ProtoSyntaxError < ProtocolError; end class ProtoFatalError < ProtocolError; end class ProtoUnknownError < ProtocolError; end class ProtoServerError < ProtocolError; end class ProtoAuthError < ProtocolError; end class ProtoCommandError < ProtocolError; end class ProtoRetriableError < ProtocolError; end ProtocRetryError = ProtoRetriableError class BufferedIO #:nodoc: internal use only def initialize(io) @io = io @read_timeout = 60 @debug_output = nil @rbuf = '' end attr_reader :io attr_accessor :read_timeout attr_accessor :debug_output def inspect "#<#{self.class} io=#{@io}>" end def closed? @io.closed? end def close @io.close end # # Read # public def read(len, dest = '', ignore_eof = false) LOG "reading #{len} bytes..." read_bytes = 0 begin while read_bytes + @rbuf.size < len dest << (s = rbuf_consume(@rbuf.size)) read_bytes += s.size rbuf_fill end dest << (s = rbuf_consume(len - read_bytes)) read_bytes += s.size rescue EOFError raise unless ignore_eof end LOG "read #{read_bytes} bytes" dest end def read_all(dest = '') LOG 'reading all...' read_bytes = 0 begin while true dest << (s = rbuf_consume(@rbuf.size)) read_bytes += s.size rbuf_fill end rescue EOFError ; end LOG "read #{read_bytes} bytes" dest end def readuntil(terminator, ignore_eof = false) begin until idx = @rbuf.index(terminator) rbuf_fill end return rbuf_consume(idx + terminator.size) rescue EOFError raise unless ignore_eof return rbuf_consume(@rbuf.size) end end def readline readuntil("\n").chop end private BUFSIZE = 1024 * 16 def rbuf_fill timeout(@read_timeout) { @rbuf << @io.sysread(BUFSIZE) } end def rbuf_consume(len) s = @rbuf.slice!(0, len) @debug_output << %Q[-> #{s.dump}\n] if @debug_output s end # # Write # public def write(str) writing { write0 str } end def writeline(str) writing { write0 str + "\r\n" } end private def writing @written_bytes = 0 @debug_output << '<- ' if @debug_output yield @debug_output << "\n" if @debug_output bytes = @written_bytes @written_bytes = nil bytes end def write0(str) @debug_output << str.dump if @debug_output len = @io.write(str) @written_bytes += len len end # # Logging # private def LOG_off @save_debug_out = @debug_output @debug_output = nil end def LOG_on @debug_output = @save_debug_out end def LOG(msg) return unless @debug_output @debug_output << msg + "\n" end end class InternetMessageIO < BufferedIO #:nodoc: internal use only def InternetMessageIO.old_open(addr, port, open_timeout = nil, read_timeout = nil, debug_output = nil) debug_output << "opening connection to #{addr}...\n" if debug_output s = timeout(open_timeout) { TCPsocket.new(addr, port) } io = new(s) io.read_timeout = read_timeout io.debug_output = debug_output io end def initialize(io) super @wbuf = nil end # # Read # def each_message_chunk LOG 'reading message...' LOG_off() read_bytes = 0 while (line = readuntil("\r\n")) != ".\r\n" read_bytes += line.size yield line.sub(/\A\./, '') end LOG_on() LOG "read message (#{read_bytes} bytes)" end # *library private* (cannot handle 'break') def each_list_item while (str = readuntil("\r\n")) != ".\r\n" yield str.chop end end def write_message_0(src) prev = @written_bytes each_crlf_line(src) do |line| write0 line.sub(/\A\./, '..') end @written_bytes - prev end # # Write # def write_message(src) LOG "writing message from #{src.class}" LOG_off() len = writing { using_each_crlf_line { write_message_0 src } } LOG_on() LOG "wrote #{len} bytes" len end def write_message_by_block(&block) LOG 'writing message from block' LOG_off() len = writing { using_each_crlf_line { begin block.call(WriteAdapter.new(self, :write_message_0)) rescue LocalJumpError # allow `break' from writer block end } } LOG_on() LOG "wrote #{len} bytes" len end private def using_each_crlf_line @wbuf = '' yield if not @wbuf.empty? # unterminated last line write0 @wbuf.chomp + "\r\n" elsif @written_bytes == 0 # empty src write0 "\r\n" end write0 ".\r\n" @wbuf = nil end def each_crlf_line(src) buffer_filling(@wbuf, src) do while line = @wbuf.slice!(/\A.*(?:\n|\r\n|\r(?!\z))/n) yield line.chomp("\n") + "\r\n" end end end def buffer_filling(buf, src) case src when String # for speeding up. 0.step(src.size - 1, 1024) do |i| buf << src[i, 1024] yield end when File # for speeding up. while s = src.read(1024) buf << s yield end else # generic reader src.each do |s| buf << s yield if buf.size > 1024 end yield unless buf.empty? end end end # # The writer adapter class # class WriteAdapter def initialize(socket, method) @socket = socket @method_id = method end def inspect "#<#{self.class} socket=#{@socket.inspect}>" end def write(str) @socket.__send__(@method_id, str) end alias print write def <<(str) write str self end def puts(str = '') write str.chomp("\n") + "\n" end def printf(*args) write sprintf(*args) end end class ReadAdapter #:nodoc: internal use only def initialize(block) @block = block end def inspect "#<#{self.class}>" end def <<(str) call_block(str, &@block) if @block end private # This method is needed because @block must be called by yield, # not Proc#call. You can see difference when using `break' in # the block. def call_block(str) yield str end end module NetPrivate #:nodoc: obsolete Socket = ::Net::InternetMessageIO end end # module Net PK|]QCCnet/telnets.rbnu[=begin = $RCSfile$ -- SSL/TLS enhancement for Net::Telnet. = Info 'OpenSSL for Ruby 2' project Copyright (C) 2001 GOTOU YUUZOU All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id: telnets.rb 13657 2007-10-08 11:16:54Z gotoyuzo $ 2001/11/06: Contiributed to Ruby/OpenSSL project. == class Net::Telnet This class will initiate SSL/TLS session automaticaly if the server sent OPT_STARTTLS. Some options are added for SSL/TLS. host = Net::Telnet::new({ "Host" => "localhost", "Port" => "telnets", ## follows are new options. 'CertFile' => "user.crt", 'KeyFile' => "user.key", 'CAFile' => "/some/where/certs/casert.pem", 'CAPath' => "/some/where/caserts", 'VerifyMode' => SSL::VERIFY_PEER, 'VerifyCallback' => verify_proc }) Or, the new options ('Cert', 'Key' and 'CACert') are available from Michal Rokos's OpenSSL module. cert_data = File.open("user.crt"){|io| io.read } pkey_data = File.open("user.key"){|io| io.read } cacert_data = File.open("your_ca.pem"){|io| io.read } host = Net::Telnet::new({ "Host" => "localhost", "Port" => "telnets", 'Cert' => OpenSSL::X509::Certificate.new(cert_data) 'Key' => OpenSSL::PKey::RSA.new(pkey_data) 'CACert' => OpenSSL::X509::Certificate.new(cacert_data) 'CAFile' => "/some/where/certs/casert.pem", 'CAPath' => "/some/where/caserts", 'VerifyMode' => SSL::VERIFY_PEER, 'VerifyCallback' => verify_proc }) This class is expected to be a superset of usual Net::Telnet. =end require "net/telnet" require "openssl" module Net class Telnet attr_reader :ssl OPT_STARTTLS = 46.chr # "\056" # "\x2e" # Start TLS TLS_FOLLOWS = 1.chr # "\001" # "\x01" # FOLLOWS (for STARTTLS) alias preprocess_orig preprocess def ssl?; @ssl; end def preprocess(string) # combine CR+NULL into CR string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"] # combine EOL into "\n" string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"] string.gsub(/#{IAC}( [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]| [#{DO}#{DONT}#{WILL}#{WONT}][#{OPT_BINARY}-#{OPT_EXOPL}]| #{SB}[#{OPT_BINARY}-#{OPT_EXOPL}] (#{IAC}#{IAC}|[^#{IAC}])+#{IAC}#{SE} )/xno) do if IAC == $1 # handle escaped IAC characters IAC elsif AYT == $1 # respond to "IAC AYT" (are you there) self.write("nobody here but us pigeons" + EOL) '' elsif DO[0] == $1[0] # respond to "IAC DO x" if OPT_BINARY[0] == $1[1] @telnet_option["BINARY"] = true self.write(IAC + WILL + OPT_BINARY) elsif OPT_STARTTLS[0] == $1[1] self.write(IAC + WILL + OPT_STARTTLS) self.write(IAC + SB + OPT_STARTTLS + TLS_FOLLOWS + IAC + SE) else self.write(IAC + WONT + $1[1..1]) end '' elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x" self.write(IAC + WONT + $1[1..1]) '' elsif WILL[0] == $1[0] # respond to "IAC WILL x" if OPT_BINARY[0] == $1[1] self.write(IAC + DO + OPT_BINARY) elsif OPT_ECHO[0] == $1[1] self.write(IAC + DO + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = true self.write(IAC + DO + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' elsif WONT[0] == $1[0] # respond to "IAC WON'T x" if OPT_ECHO[0] == $1[1] self.write(IAC + DONT + OPT_ECHO) elsif OPT_SGA[0] == $1[1] @telnet_option["SGA"] = false self.write(IAC + DONT + OPT_SGA) else self.write(IAC + DONT + $1[1..1]) end '' elsif SB[0] == $1[0] # respond to "IAC SB xxx IAC SE" if OPT_STARTTLS[0] == $1[1] && TLS_FOLLOWS[0] == $2[0] @sock = OpenSSL::SSL::SSLSocket.new(@sock) @sock.cert = @options['Cert'] unless @sock.cert @sock.key = @options['Key'] unless @sock.key @sock.ca_cert = @options['CACert'] @sock.ca_file = @options['CAFile'] @sock.ca_path = @options['CAPath'] @sock.timeout = @options['Timeout'] @sock.verify_mode = @options['VerifyMode'] @sock.verify_callback = @options['VerifyCallback'] @sock.verify_depth = @options['VerifyDepth'] @sock.connect if @options['VerifyMode'] != OpenSSL::SSL::VERIFY_NONE @sock.post_connection_check(@options['Host']) end @ssl = true end '' else '' end end end # preprocess alias waitfor_org waitfor def waitfor(options) time_out = @options["Timeout"] waittime = @options["Waittime"] if options.kind_of?(Hash) prompt = if options.has_key?("Match") options["Match"] elsif options.has_key?("Prompt") options["Prompt"] elsif options.has_key?("String") Regexp.new( Regexp.quote(options["String"]) ) end time_out = options["Timeout"] if options.has_key?("Timeout") waittime = options["Waittime"] if options.has_key?("Waittime") else prompt = options end if time_out == false time_out = nil end line = '' buf = '' @rest = '' unless @rest until(prompt === line and not IO::select([@sock], nil, nil, waittime)) unless IO::select([@sock], nil, nil, time_out) raise TimeoutError, "timed-out; wait for the next data" end begin c = @rest + @sock.sysread(1024 * 1024) @dumplog.log_dump('<', c) if @options.has_key?("Dump_log") if @options["Telnetmode"] pos = 0 catch(:next){ while true case c[pos] when IAC[0] case c[pos+1] when DO[0], DONT[0], WILL[0], WONT[0] throw :next unless c[pos+2] pos += 3 when SB[0] ret = detect_sub_negotiation(c, pos) throw :next unless ret pos = ret when nil throw :next else pos += 2 end when nil throw :next else pos += 1 end end } buf = preprocess(c[0...pos]) @rest = c[pos..-1] end @log.print(buf) if @options.has_key?("Output_log") line.concat(buf) yield buf if block_given? rescue EOFError # End of file reached if line == '' line = nil yield nil if block_given? end break end end line end private def detect_sub_negotiation(data, pos) return nil if data.length < pos+6 # IAC SB x param IAC SE pos += 3 while true case data[pos] when IAC[0] if data[pos+1] == SE[0] pos += 2 return pos else pos += 2 end when nil return nil else pos += 1 end end end end end PK|]8`XXsync.rbnu[# # sync.rb - 2 phase lock with counter # $Release Version: 1.0$ # $Revision: 22457 $ # $Date: 2009-02-20 01:41:12 +0900 (Fri, 20 Feb 2009) $ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # Sync_m, Synchronizer_m # Usage: # obj.extend(Sync_m) # or # class Foo # include Sync_m # : # end # # Sync_m#sync_mode # Sync_m#sync_locked?, locked? # Sync_m#sync_shared?, shared? # Sync_m#sync_exclusive?, sync_exclusive? # Sync_m#sync_try_lock, try_lock # Sync_m#sync_lock, lock # Sync_m#sync_unlock, unlock # # Sync, Synchronicer: # include Sync_m # Usage: # sync = Sync.new # # Sync#mode # Sync#locked? # Sync#shared? # Sync#exclusive? # Sync#try_lock(mode) -- mode = :EX, :SH, :UN # Sync#lock(mode) -- mode = :EX, :SH, :UN # Sync#unlock # Sync#synchronize(mode) {...} # # unless defined? Thread fail "Thread not available for this ruby interpreter" end module Sync_m RCS_ID='-$Header$-' # lock mode UN = :UN SH = :SH EX = :EX # exceptions class Err < StandardError def Err.Fail(*opt) Thread.critical = false fail self, sprintf(self::Message, *opt) end class UnknownLocker < Err Message = "Thread(%s) not locked." def UnknownLocker.Fail(th) super(th.inspect) end end class LockModeFailer < Err Message = "Unknown lock mode(%s)" def LockModeFailer.Fail(mode) if mode.id2name mode = id2name end super(mode) end end end def Sync_m.define_aliases(cl) cl.module_eval %q{ alias locked? sync_locked? alias shared? sync_shared? alias exclusive? sync_exclusive? alias lock sync_lock alias unlock sync_unlock alias try_lock sync_try_lock alias synchronize sync_synchronize } end def Sync_m.append_features(cl) super unless cl.instance_of?(Module) # do nothing for Modules # make aliases and include the proper module. define_aliases(cl) end end def Sync_m.extend_object(obj) super obj.sync_extended end def sync_extended unless (defined? locked? and defined? shared? and defined? exclusive? and defined? lock and defined? unlock and defined? try_lock and defined? synchronize) Sync_m.define_aliases(class< 0 for k, v in sync_upgrade_waiting sync_sh_locker[k] = v end wait = sync_upgrade_waiting self.sync_upgrade_waiting = [] Thread.critical = false for w, v in wait w.run end else wait = sync_waiting self.sync_waiting = [] Thread.critical = false for w in wait w.run end end end Thread.critical = false self end def sync_synchronize(mode = EX) begin sync_lock(mode) yield ensure sync_unlock end end attr :sync_mode, true attr :sync_waiting, true attr :sync_upgrade_waiting, true attr :sync_sh_locker, true attr :sync_ex_locker, true attr :sync_ex_count, true private def sync_initialize @sync_mode = UN @sync_waiting = [] @sync_upgrade_waiting = [] @sync_sh_locker = Hash.new @sync_ex_locker = nil @sync_ex_count = 0 end def initialize(*args) sync_initialize super end def sync_try_lock_sub(m) case m when SH case sync_mode when UN self.sync_mode = m sync_sh_locker[Thread.current] = 1 ret = true when SH count = 0 unless count = sync_sh_locker[Thread.current] sync_sh_locker[Thread.current] = count + 1 ret = true when EX # in EX mode, lock will upgrade to EX lock if sync_ex_locker == Thread.current self.sync_ex_count = sync_ex_count + 1 ret = true else ret = false end end when EX if sync_mode == UN or sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current) self.sync_mode = m self.sync_ex_locker = Thread.current self.sync_ex_count = 1 ret = true elsif sync_mode == EX && sync_ex_locker == Thread.current self.sync_ex_count = sync_ex_count + 1 ret = true else ret = false end else Thread.critical = false Err::LockModeFailer.Fail mode end return ret end end Synchronizer_m = Sync_m class Sync #Sync_m.extend_class self include Sync_m def initialize super end end Synchronizer = Sync PK|]{aCC readbytes.rbnu[# TruncatedDataError is raised when IO#readbytes fails to read enough data. class TruncatedDataErrorto/from. # def syscopy(from, to) to = catname(from, to) fmode = stat(from).mode tpath = to not_exist = !exist?(tpath) from = open(from, "rb") to = open(to, "wb") begin while true to.syswrite from.sysread(BUFSIZE) end rescue EOFError ret = true rescue ret = false ensure to.close from.close end chmod(fmode, tpath) if not_exist ret end # # Copies a file +from+ to +to+ using #syscopy. If +to+ is a directory, # copies +from+ to to/from. If +verbose+ is true, from -> to # is printed. # def copy(from, to, verbose = false) $stderr.print from, " -> ", catname(from, to), "\n" if verbose syscopy from, to end alias cp copy # # Moves a file +from+ to +to+ using #syscopy. If +to+ is a directory, # copies from +from+ to to/from. If +verbose+ is true, from -> # to is printed. # def move(from, to, verbose = false) to = catname(from, to) $stderr.print from, " -> ", to, "\n" if verbose if RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw/ and file? to unlink to end fstat = stat(from) begin rename from, to rescue begin symlink readlink(from), to and unlink from rescue from_stat = stat(from) syscopy from, to and unlink from utime(from_stat.atime, from_stat.mtime, to) begin chown(fstat.uid, fstat.gid, to) rescue end end end end alias mv move # # Returns +true+ if and only if the contents of files +from+ and +to+ are # identical. If +verbose+ is +true+, from <=> to is printed. # def compare(from, to, verbose = false) $stderr.print from, " <=> ", to, "\n" if verbose return false if stat(from).size != stat(to).size from = open(from, "rb") to = open(to, "rb") ret = false fr = tr = '' begin while fr == tr fr = from.read(BUFSIZE) if fr tr = to.read(fr.size) else ret = to.read(BUFSIZE) ret = !ret || ret.length == 0 break end end rescue ret = false ensure to.close from.close end ret end alias cmp compare # # Removes a list of files. Each parameter should be the name of the file to # delete. If the last parameter isn't a String, verbose mode will be enabled. # Returns the number of files deleted. # def safe_unlink(*files) verbose = if files[-1].is_a? String then false else files.pop end files.each do |file| begin unlink file $stderr.print "removing ", file, "\n" if verbose rescue Errno::EACCES # for Windows continue if symlink? file begin mode = stat(file).mode o_chmod mode | 0200, file unlink file $stderr.print "removing ", file, "\n" if verbose rescue o_chmod mode, file rescue nil end rescue end end end alias rm_f safe_unlink # # Creates a directory and all its parent directories. # For example, # # File.makedirs '/usr/lib/ruby' # # causes the following directories to be made, if they do not exist. # * /usr # * /usr/lib # * /usr/lib/ruby # # You can pass several directories, each as a parameter. If the last # parameter isn't a String, verbose mode will be enabled. # def makedirs(*dirs) verbose = if dirs[-1].is_a? String then false else dirs.pop end mode = 0755 for dir in dirs parent = dirname(dir) next if parent == dir or directory? dir makedirs parent unless directory? parent $stderr.print "mkdir ", dir, "\n" if verbose if basename(dir) != "" begin Dir.mkdir dir, mode rescue SystemCallError raise unless directory? dir end end end end alias mkpath makedirs alias o_chmod chmod vsave, $VERBOSE = $VERBOSE, false # # Changes permission bits on +files+ to the bit pattern represented # by +mode+. If the last parameter isn't a String, verbose mode will # be enabled. # # File.chmod 0755, 'somecommand' # File.chmod 0644, 'my.rb', 'your.rb', true # def chmod(mode, *files) verbose = if files[-1].is_a? String then false else files.pop end $stderr.printf "chmod %04o %s\n", mode, files.join(" ") if verbose o_chmod mode, *files end $VERBOSE = vsave # # If +src+ is not the same as +dest+, copies it and changes the permission # mode to +mode+. If +dest+ is a directory, destination is dest/src. # If +mode+ is not set, default is used. If +verbose+ is set to true, the # name of each file copied will be printed. # def install(from, to, mode = nil, verbose = false) to = catname(from, to) unless exist? to and cmp from, to safe_unlink to if exist? to cp from, to, verbose chmod mode, to, verbose if mode end end end # vi:set sw=2: PK|]G,rr tempfile.rbnu[# # tempfile - manipulates temporary files # # $Id: tempfile.rb 16127 2008-04-21 09:43:44Z knu $ # require 'delegate' require 'tmpdir' # A class for managing temporary files. This library is written to be # thread safe. class Tempfile < DelegateClass(File) MAX_TRY = 10 @@cleanlist = [] # Creates a temporary file of mode 0600 in the temporary directory, # opens it with mode "w+", and returns a Tempfile object which # represents the created temporary file. A Tempfile object can be # treated just like a normal File object. # # The basename parameter is used to determine the name of a # temporary file. If an Array is given, the first element is used # as prefix string and the second as suffix string, respectively. # Otherwise it is treated as prefix string. # # If tmpdir is omitted, the temporary directory is determined by # Dir::tmpdir provided by 'tmpdir.rb'. # When $SAFE > 0 and the given tmpdir is tainted, it uses # /tmp. (Note that ENV values are tainted by default) def initialize(basename, tmpdir=Dir::tmpdir) if $SAFE > 0 and tmpdir.tainted? tmpdir = '/tmp' end lock = nil n = failure = 0 begin Thread.critical = true begin tmpname = File.join(tmpdir, make_tmpname(basename, n)) lock = tmpname + '.lock' n += 1 end while @@cleanlist.include?(tmpname) or File.exist?(lock) or File.exist?(tmpname) Dir.mkdir(lock) rescue failure += 1 retry if failure < MAX_TRY raise "cannot generate tempfile `%s'" % tmpname ensure Thread.critical = false end @data = [tmpname] @clean_proc = Tempfile.callback(@data) ObjectSpace.define_finalizer(self, @clean_proc) @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600) @tmpname = tmpname @@cleanlist << @tmpname @data[1] = @tmpfile @data[2] = @@cleanlist super(@tmpfile) # Now we have all the File/IO methods defined, you must not # carelessly put bare puts(), etc. after this. Dir.rmdir(lock) end def make_tmpname(basename, n) case basename when Array prefix, suffix = *basename else prefix, suffix = basename, '' end t = Time.now.strftime("%Y%m%d") path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-#{n}#{suffix}" end private :make_tmpname # Opens or reopens the file with mode "r+". def open @tmpfile.close if @tmpfile @tmpfile = File.open(@tmpname, 'r+') @data[1] = @tmpfile __setobj__(@tmpfile) end def _close # :nodoc: @tmpfile.close if @tmpfile @tmpfile = nil @data[1] = nil if @data end protected :_close # Closes the file. If the optional flag is true, unlinks the file # after closing. # # If you don't explicitly unlink the temporary file, the removal # will be delayed until the object is finalized. def close(unlink_now=false) if unlink_now close! else _close end end # Closes and unlinks the file. def close! _close @clean_proc.call ObjectSpace.undefine_finalizer(self) @data = @tmpname = nil end # Unlinks the file. On UNIX-like systems, it is often a good idea # to unlink a temporary file immediately after creating and opening # it, because it leaves other programs zero chance to access the # file. def unlink # keep this order for thread safeness begin File.unlink(@tmpname) if File.exist?(@tmpname) @@cleanlist.delete(@tmpname) @data = @tmpname = nil ObjectSpace.undefine_finalizer(self) rescue Errno::EACCES # may not be able to unlink on Windows; just ignore end end alias delete unlink # Returns the full path name of the temporary file. def path @tmpname end # Returns the size of the temporary file. As a side effect, the IO # buffer is flushed before determining the size. def size if @tmpfile @tmpfile.flush @tmpfile.stat.size else 0 end end alias length size class << self def callback(data) # :nodoc: pid = $$ lambda{ if pid == $$ path, tmpfile, cleanlist = *data print "removing ", path, "..." if $DEBUG tmpfile.close if tmpfile # keep this order for thread safeness File.unlink(path) if File.exist?(path) cleanlist.delete(path) if cleanlist print "done\n" if $DEBUG end } end # If no block is given, this is a synonym for new(). # # If a block is given, it will be passed tempfile as an argument, # and the tempfile will automatically be closed when the block # terminates. In this case, open() returns nil. def open(*args) tempfile = new(*args) if block_given? begin yield(tempfile) ensure tempfile.close end nil else tempfile end end end end if __FILE__ == $0 # $DEBUG = true f = Tempfile.new("foo") f.print("foo\n") f.close f.open p f.gets # => "foo\n" f.close! end PK|]!{ { base64.rbnu[# # = base64.rb: methods for base64-encoding and -decoding stings # # Author:: Yukihiro Matsumoto # Documentation:: Dave Thomas and Gavin Sinclair # # Until Ruby 1.8.1, these methods were defined at the top-level. Now # they are in the Base64 module but included in the top-level, where # their usage is deprecated. # # See Base64 for documentation. # require "kconv" # The Base64 module provides for the encoding (#encode64) and decoding # (#decode64) of binary data using a Base64 representation. # # The following particular features are also provided: # - encode into lines of a given length (#b64encode) # - decode the special format specified in RFC2047 for the # representation of email headers (decode_b) # # == Example # # A simple encoding and decoding. # # require "base64" # # enc = Base64.encode64('Send reinforcements') # # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n" # plain = Base64.decode64(enc) # # -> "Send reinforcements" # # The purpose of using base64 to encode data is that it translates any # binary data into purely printable characters. It is specified in # RFC 2045 (http://www.faqs.org/rfcs/rfc2045.html). module Base64 module_function # Returns the Base64-decoded version of +str+. # # require 'base64' # str = 'VGhpcyBpcyBsaW5lIG9uZQpUaGlzIG' + # 'lzIGxpbmUgdHdvClRoaXMgaXMgbGlu' + # 'ZSB0aHJlZQpBbmQgc28gb24uLi4K' # puts Base64.decode64(str) # # Generates: # # This is line one # This is line two # This is line three # And so on... def decode64(str) str.unpack("m")[0] end # Decodes text formatted using a subset of RFC2047 (the one used for # mime-encoding mail headers). # # Only supports an encoding type of 'b' (base 64), and only supports # the character sets ISO-2022-JP and SHIFT_JIS (so the only two # encoded word sequences recognized are =?ISO-2022-JP?B?...= and # =?SHIFT_JIS?B?...=). Recognition of these sequences is case # insensitive. def decode_b(str) str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/i) { decode64($1) } str = Kconv::toeuc(str) str.gsub!(/=\?SHIFT_JIS\?B\?([!->@-~]+)\?=/i) { decode64($1) } str = Kconv::toeuc(str) str.gsub!(/\n/, ' ') str.gsub!(/\0/, '') str end # Returns the Base64-encoded version of +str+. # # require 'base64' # Base64.b64encode("Now is the time for all good coders\nto learn Ruby") # # Generates: # # Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g # UnVieQ== def encode64(bin) [bin].pack("m") end # _Prints_ the Base64 encoded version of +bin+ (a +String+) in lines of # +len+ (default 60) characters. # # require 'base64' # data = "Now is the time for all good coders\nto learn Ruby" # Base64.b64encode(data) # # Generates: # # Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g # UnVieQ== def b64encode(bin, len = 60) encode64(bin).scan(/.{1,#{len}}/) do print $&, "\n" end end module Deprecated # :nodoc: include Base64 for m in Base64.private_instance_methods(false) module_eval %{ def #{m}(*args) warn("\#{caller(1)[0]}: #{m} is deprecated; use Base64.#{m} instead") super end } end end end include Base64::Deprecated PK|]|| optparse.rbnu[# # optparse.rb - command-line option analysis with the OptionParser class. # # Author:: Nobu Nakada # Documentation:: Nobu Nakada and Gavin Sinclair. # # See OptionParser for documentation. # # == Developer Documentation (not for RDoc output) # # === Class tree # # - OptionParser:: front end # - OptionParser::Switch:: each switches # - OptionParser::List:: options list # - OptionParser::ParseError:: errors on parsing # - OptionParser::AmbiguousOption # - OptionParser::NeedlessArgument # - OptionParser::MissingArgument # - OptionParser::InvalidOption # - OptionParser::InvalidArgument # - OptionParser::AmbiguousArgument # # === Object relationship diagram # # +--------------+ # | OptionParser |<>-----+ # +--------------+ | +--------+ # | ,-| Switch | # on_head -------->+---------------+ / +--------+ # accept/reject -->| List |<|>- # | |<|>- +----------+ # on ------------->+---------------+ `-| argument | # : : | class | # +---------------+ |==========| # on_tail -------->| | |pattern | # +---------------+ |----------| # OptionParser.accept ->| DefaultList | |converter | # reject |(shared between| +----------+ # | all instances)| # +---------------+ # # == OptionParser # # === Introduction # # OptionParser is a class for command-line option analysis. It is much more # advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented # solution. # # === Features # # 1. The argument specification and the code to handle it are written in the # same place. # 2. It can output an option summary; you don't need to maintain this string # separately. # 3. Optional and mandatory arguments are specified very gracefully. # 4. Arguments can be automatically converted to a specified class. # 5. Arguments can be restricted to a certain set. # # All of these features are demonstrated in the examples below. # # === Minimal example # # require 'optparse' # # options = {} # OptionParser.new do |opts| # opts.banner = "Usage: example.rb [options]" # # opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| # options[:verbose] = v # end # end.parse! # # p options # p ARGV # # === Complete example # # The following example is a complete Ruby program. You can run it and see the # effect of specifying various options. This is probably the best way to learn # the features of +optparse+. # # require 'optparse' # require 'optparse/time' # require 'ostruct' # require 'pp' # # class OptparseExample # # CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary] # CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" } # # # # # Return a structure describing the options. # # # def self.parse(args) # # The options specified on the command line will be collected in *options*. # # We set default values here. # options = OpenStruct.new # options.library = [] # options.inplace = false # options.encoding = "utf8" # options.transfer_type = :auto # options.verbose = false # # opts = OptionParser.new do |opts| # opts.banner = "Usage: example.rb [options]" # # opts.separator "" # opts.separator "Specific options:" # # # Mandatory argument. # opts.on("-r", "--require LIBRARY", # "Require the LIBRARY before executing your script") do |lib| # options.library << lib # end # # # Optional argument; multi-line description. # opts.on("-i", "--inplace [EXTENSION]", # "Edit ARGV files in place", # " (make backup if EXTENSION supplied)") do |ext| # options.inplace = true # options.extension = ext || '' # options.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot. # end # # # Cast 'delay' argument to a Float. # opts.on("--delay N", Float, "Delay N seconds before executing") do |n| # options.delay = n # end # # # Cast 'time' argument to a Time object. # opts.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time| # options.time = time # end # # # Cast to octal integer. # opts.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger, # "Specify record separator (default \\0)") do |rs| # options.record_separator = rs # end # # # List of arguments. # opts.on("--list x,y,z", Array, "Example 'list' of arguments") do |list| # options.list = list # end # # # Keyword completion. We are specifying a specific set of arguments (CODES # # and CODE_ALIASES - notice the latter is a Hash), and the user may provide # # the shortest unambiguous text. # code_list = (CODE_ALIASES.keys + CODES).join(',') # opts.on("--code CODE", CODES, CODE_ALIASES, "Select encoding", # " (#{code_list})") do |encoding| # options.encoding = encoding # end # # # Optional argument with keyword completion. # opts.on("--type [TYPE]", [:text, :binary, :auto], # "Select transfer type (text, binary, auto)") do |t| # options.transfer_type = t # end # # # Boolean switch. # opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| # options.verbose = v # end # # opts.separator "" # opts.separator "Common options:" # # # No argument, shows at tail. This will print an options summary. # # Try it and see! # opts.on_tail("-h", "--help", "Show this message") do # puts opts # exit # end # # # Another typical switch to print the version. # opts.on_tail("--version", "Show version") do # puts OptionParser::Version.join('.') # exit # end # end # # opts.parse!(args) # options # end # parse() # # end # class OptparseExample # # options = OptparseExample.parse(ARGV) # pp options # # === Further documentation # # The above examples should be enough to learn how to use this class. If you # have any questions, email me (gsinclair@soyabean.com.au) and I will update # this document. # class OptionParser # :stopdoc: RCSID = %w$Id: optparse.rb 22469 2009-02-20 11:43:35Z shyouhei $[1..-1].each {|s| s.freeze}.freeze Version = (RCSID[1].split('.').collect {|s| s.to_i}.extend(Comparable).freeze if RCSID[1]) LastModified = (Time.gm(*RCSID[2, 2].join('-').scan(/\d+/).collect {|s| s.to_i}) if RCSID[2]) Release = RCSID[2] NoArgument = [NO_ARGUMENT = :NONE, nil].freeze RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze # :startdoc: # # Keyword completion module. This allows partial arguments to be specified # and resolved against a list of acceptable values. # module Completion def complete(key, icase = false, pat = nil) pat ||= Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase) canon, sw, k, v, cn = nil candidates = [] each do |k, *v| (if Regexp === k kn = nil k === key else kn = defined?(k.id2name) ? k.id2name : k pat === kn end) or next v << k if v.empty? candidates << [k, v, kn] end candidates = candidates.sort_by {|k, v, kn| kn.size} if candidates.size == 1 canon, sw, * = candidates[0] elsif candidates.size > 1 canon, sw, cn = candidates.shift candidates.each do |k, v, kn| next if sw == v if String === cn and String === kn if cn.rindex(kn, 0) canon, sw, cn = k, v, kn next elsif kn.rindex(cn, 0) next end end throw :ambiguous, key end end if canon block_given? or return key, *sw yield(key, *sw) end end def convert(opt = nil, val = nil, *) val end end # # Map from option/keyword string to object with completion. # class OptionMap < Hash include Completion end # # Individual switch class. Not important to the user. # # Defined within Switch are several Switch-derived classes: NoArgument, # RequiredArgument, etc. # class Switch attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block # # Guesses argument style from +arg+. Returns corresponding # OptionParser::Switch class (OptionalArgument, etc.). # def self.guess(arg) case arg when "" t = self when /\A=?\[/ t = Switch::OptionalArgument when /\A\s+\[/ t = Switch::PlacedArgument else t = Switch::RequiredArgument end self >= t or incompatible_argument_styles(arg, t) t end def self.incompatible_argument_styles(arg, t) raise ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}" end def self.pattern NilClass end def initialize(pattern = nil, conv = nil, short = nil, long = nil, arg = nil, desc = ([] if short or long), block = Proc.new) raise if Array === pattern @pattern, @conv, @short, @long, @arg, @desc, @block = pattern, conv, short, long, arg, desc, block end # # Parses +arg+ and returns rest of +arg+ and matched portion to the # argument pattern. Yields when the pattern doesn't match substring. # def parse_arg(arg) pattern or return nil, arg unless m = pattern.match(arg) yield(InvalidArgument, arg) return arg, nil end if String === m m = [s = m] else m = m.to_a s = m[0] return nil, m unless String === s end raise InvalidArgument, arg unless arg.rindex(s, 0) return nil, m if s.length == arg.length yield(InvalidArgument, arg) # didn't match whole arg return arg[s.length..-1], m end private :parse_arg # # Parses argument, converts and returns +arg+, +block+ and result of # conversion. Yields at semi-error condition instead of raising an # exception. # def conv_arg(arg, val = nil) if conv val = conv.call(*val) else val = proc {|val| val}.call(*val) end return arg, block, val end private :conv_arg # # Produces the summary text. Each line of the summary is yielded to the # block (without newline). # # +sdone+:: Already summarized short style options keyed hash. # +ldone+:: Already summarized long style options keyed hash. # +width+:: Width of left side (option part). In other words, the right # side (description part) starts after +width+ columns. # +max+:: Maximum width of left side -> the options are filled within # +max+ columns. # +indent+:: Prefix string indents all summarized lines. # def summarize(sdone = [], ldone = [], width = 1, max = width - 1, indent = "") sopts, lopts, s = [], [], nil @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long return if sopts.empty? and lopts.empty? # completely hidden left = [sopts.join(', ')] right = desc.dup while s = lopts.shift l = left[-1].length + s.length l += arg.length if left.size == 1 && arg l < max or sopts.empty? or left << '' left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << s end left[0] << arg if arg mlen = left.collect {|s| s.length}.max.to_i while mlen > width and l = left.shift mlen = left.collect {|s| s.length}.max.to_i if l.length == mlen yield(indent + l) end while begin l = left.shift; r = right.shift; l or r end l = l.to_s.ljust(width) + ' ' + r if r and !r.empty? yield(indent + l) end self end def add_banner(to) # :nodoc: unless @short or @long s = desc.join to << " [" + s + "]..." unless s.empty? end to end def match_nonswitch?(str) # :nodoc: @pattern =~ str unless @short or @long end # # Main name of the switch. # def switch_name (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '') end # # Switch that takes no arguments. # class NoArgument < self # # Raises an exception if any arguments given. # def parse(arg, argv) yield(NeedlessArgument, arg) if arg conv_arg(arg) end def self.incompatible_argument_styles(*) end def self.pattern Object end end # # Switch that takes an argument. # class RequiredArgument < self # # Raises an exception if argument is not present. # def parse(arg, argv) unless arg raise MissingArgument if argv.empty? arg = argv.shift end conv_arg(*parse_arg(arg) {|*exc| raise(*exc)}) end end # # Switch that can omit argument. # class OptionalArgument < self # # Parses argument if given, or uses default value. # def parse(arg, argv, &error) if arg conv_arg(*parse_arg(arg, &error)) else conv_arg(arg) end end end # # Switch that takes an argument, which does not begin with '-'. # class PlacedArgument < self # # Returns nil if argument is not present or begins with '-'. # def parse(arg, argv, &error) if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0])) return nil, block, nil end opt = (val = parse_arg(val, &error))[1] val = conv_arg(*val) if opt and !arg argv.shift else val[0] = nil end val end end end # # Simple option list providing mapping from short and/or long option # string to OptionParser::Switch and mapping from acceptable argument to # matching pattern and converter pair. Also provides summary feature. # class List # Map from acceptable argument types to pattern and converter pairs. attr_reader :atype # Map from short style option switches to actual switch objects. attr_reader :short # Map from long style option switches to actual switch objects. attr_reader :long # List of all switches and summary string. attr_reader :list # # Just initializes all instance variables. # def initialize @atype = {} @short = OptionMap.new @long = OptionMap.new @list = [] end # # See OptionParser.accept. # def accept(t, pat = /.*/nm, &block) if pat pat.respond_to?(:match) or raise TypeError, "has no `match'" else pat = t if t.respond_to?(:match) end unless block block = pat.method(:convert).to_proc if pat.respond_to?(:convert) end @atype[t] = [pat, block] end # # See OptionParser.reject. # def reject(t) @atype.delete(t) end # # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+. # # +sw+:: OptionParser::Switch instance to be added. # +sopts+:: Short style option list. # +lopts+:: Long style option list. # +nlopts+:: Negated long style options list. # def update(sw, sopts, lopts, nsw = nil, nlopts = nil) o = nil sopts.each {|o| @short[o] = sw} if sopts lopts.each {|o| @long[o] = sw} if lopts nlopts.each {|o| @long[o] = nsw} if nsw and nlopts used = @short.invert.update(@long.invert) @list.delete_if {|o| Switch === o and !used[o]} end private :update # # Inserts +switch+ at the head of the list, and associates short, long # and negated long options. Arguments are: # # +switch+:: OptionParser::Switch instance to be inserted. # +short_opts+:: List of short style options. # +long_opts+:: List of long style options. # +nolong_opts+:: List of long style options with "no-" prefix. # # prepend(switch, short_opts, long_opts, nolong_opts) # def prepend(*args) update(*args) @list.unshift(args[0]) end # # Appends +switch+ at the tail of the list, and associates short, long # and negated long options. Arguments are: # # +switch+:: OptionParser::Switch instance to be inserted. # +short_opts+:: List of short style options. # +long_opts+:: List of long style options. # +nolong_opts+:: List of long style options with "no-" prefix. # # append(switch, short_opts, long_opts, nolong_opts) # def append(*args) update(*args) @list.push(args[0]) end # # Searches +key+ in +id+ list. The result is returned or yielded if a # block is given. If it isn't found, nil is returned. # def search(id, key) if list = __send__(id) val = list.fetch(key) {return nil} block_given? ? yield(val) : val end end # # Searches list +id+ for +opt+ and the optional patterns for completion # +pat+. If +icase+ is true, the search is case insensitive. The result # is returned or yielded if a block is given. If it isn't found, nil is # returned. # def complete(id, opt, icase = false, *pat, &block) __send__(id).complete(opt, icase, *pat, &block) end # # Iterates over each option, passing the option to the +block+. # def each_option(&block) list.each(&block) end # # Creates the summary table, passing each line to the +block+ (without # newline). The arguments +args+ are passed along to the summarize # method which is called on every option. # def summarize(*args, &block) sum = [] list.reverse_each do |opt| if opt.respond_to?(:summarize) # perhaps OptionParser::Switch s = [] opt.summarize(*args) {|l| s << l} sum.concat(s.reverse) elsif !opt or opt.empty? sum << "" elsif opt.respond_to?(:each_line) sum.concat([*opt.each_line].reverse) else sum.concat([*opt.each].reverse) end end sum.reverse_each(&block) end def add_banner(to) # :nodoc: list.each do |opt| if opt.respond_to?(:add_banner) opt.add_banner(to) end end to end end # # Hash with completion search feature. See OptionParser::Completion. # class CompletingHash < Hash include Completion # # Completion for hash key. # def match(key) return key, *fetch(key) { raise AmbiguousArgument, catch(:ambiguous) {return complete(key)} } end end # :stopdoc: # # Enumeration of acceptable argument styles. Possible values are: # # NO_ARGUMENT:: The switch takes no arguments. (:NONE) # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED) # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL) # # Use like --switch=argument (long style) or -Xargument (short style). For # short style, only portion matched to argument pattern is dealed as # argument. # ArgumentStyle = {} NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument} RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument} OptionalArgument.each {|el| ArgumentStyle[el] = Switch::OptionalArgument} ArgumentStyle.freeze # # Switches common used such as '--', and also provides default # argument classes # DefaultList = List.new DefaultList.short['-'] = Switch::NoArgument.new {} DefaultList.long[''] = Switch::NoArgument.new {throw :terminate} # # Default options for ARGV, which never appear in option summary. # Officious = {} # # --help # Shows option summary. # Officious['help'] = proc do |parser| Switch::NoArgument.new do puts parser.help exit end end # # --version # Shows version string if Version is defined. # Officious['version'] = proc do |parser| Switch::OptionalArgument.new do |pkg| if pkg begin require 'optparse/version' rescue LoadError else show_version(*pkg.split(/,/)) or abort("#{parser.program_name}: no version found in package #{pkg}") exit end end v = parser.ver or abort("#{parser.program_name}: version unknown") puts v exit end end # :startdoc: # # Class methods # # # Initializes a new instance and evaluates the optional block in context # of the instance. Arguments +args+ are passed to #new, see there for # description of parameters. # # This method is *deprecated*, its behavior corresponds to the older #new # method. # def self.with(*args, &block) opts = new(*args) opts.instance_eval(&block) opts end # # Returns an incremented value of +default+ according to +arg+. # def self.inc(arg, default = nil) case arg when Integer arg.nonzero? when nil default.to_i + 1 end end def inc(*args) self.class.inc(*args) end # # Initializes the instance and yields itself if called with a block. # # +banner+:: Banner message. # +width+:: Summary width. # +indent+:: Summary indent. # def initialize(banner = nil, width = 32, indent = ' ' * 4) @stack = [DefaultList, List.new, List.new] @program_name = nil @banner = banner @summary_width = width @summary_indent = indent @default_argv = ARGV add_officious yield self if block_given? end def add_officious # :nodoc: list = base() Officious.each do |opt, block| list.long[opt] ||= block.call(self) end end # # Terminates option parsing. Optional parameter +arg+ is a string pushed # back to be the first non-option argument. # def terminate(arg = nil) self.class.terminate(arg) end def self.terminate(arg = nil) throw :terminate, arg end @stack = [DefaultList] def self.top() DefaultList end # # Directs to accept specified class +t+. The argument string is passed to # the block in which it should be converted to the desired class. # # +t+:: Argument class specifier, any object including Class. # +pat+:: Pattern for argument, defaults to +t+ if it responds to match. # # accept(t, pat, &block) # def accept(*args, &blk) top.accept(*args, &blk) end # # See #accept. # def self.accept(*args, &blk) top.accept(*args, &blk) end # # Directs to reject specified class argument. # # +t+:: Argument class specifier, any object including Class. # # reject(t) # def reject(*args, &blk) top.reject(*args, &blk) end # # See #reject. # def self.reject(*args, &blk) top.reject(*args, &blk) end # # Instance methods # # Heading banner preceding summary. attr_writer :banner # Program name to be emitted in error message and default banner, # defaults to $0. attr_writer :program_name # Width for option list portion of summary. Must be Numeric. attr_accessor :summary_width # Indentation for summary. Must be String (or have + String method). attr_accessor :summary_indent # Strings to be parsed in default. attr_accessor :default_argv # # Heading banner preceding summary. # def banner unless @banner @banner = "Usage: #{program_name} [options]" visit(:add_banner, @banner) end @banner end # # Program name to be emitted in error message and default banner, defaults # to $0. # def program_name @program_name || File.basename($0, '.*') end # for experimental cascading :-) alias set_banner banner= alias set_program_name program_name= alias set_summary_width summary_width= alias set_summary_indent summary_indent= # Version attr_writer :version # Release code attr_writer :release # # Version # def version @version || (defined?(::Version) && ::Version) end # # Release code # def release @release || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE) end # # Returns version string from program_name, version and release. # def ver if v = version str = "#{program_name} #{[v].join('.')}" str << " (#{v})" if v = release str end end def warn(mesg = $!) super("#{program_name}: #{mesg}") end def abort(mesg = $!) super("#{program_name}: #{mesg}") end # # Subject of #on / #on_head, #accept / #reject # def top @stack[-1] end # # Subject of #on_tail. # def base @stack[1] end # # Pushes a new List. # def new @stack.push(List.new) if block_given? yield self else self end end # # Removes the last List. # def remove @stack.pop end # # Puts option summary into +to+ and returns +to+. Yields each line if # a block is given. # # +to+:: Output destination, which must have method <<. Defaults to []. # +width+:: Width of left side, defaults to @summary_width. # +max+:: Maximum length allowed for left side, defaults to +width+ - 1. # +indent+:: Indentation, defaults to @summary_indent. # def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk) blk ||= proc {|l| to << (l.index($/, -1) ? l : l + $/)} visit(:summarize, {}, {}, width, max, indent, &blk) to end # # Returns option summary string. # def help; summarize(banner.to_s.sub(/\n?\z/, "\n")) end alias to_s help # # Returns option summary list. # def to_a; summarize(banner.to_a.dup) end # # Checks if an argument is given twice, in which case an ArgumentError is # raised. Called from OptionParser#switch only. # # +obj+:: New argument. # +prv+:: Previously specified argument. # +msg+:: Exception message. # def notwice(obj, prv, msg) unless !prv or prv == obj begin raise ArgumentError, "argument #{msg} given twice: #{obj}" rescue $@[0, 2] = nil raise end end obj end private :notwice # # Creates an OptionParser::Switch from the parameters. The parsed argument # value is passed to the given block, where it can be processed. # # See at the beginning of OptionParser for some full examples. # # +opts+ can include the following elements: # # [Argument style:] # One of the following: # :NONE, :REQUIRED, :OPTIONAL # # [Argument pattern:] # Acceptable option argument format, must be pre-defined with # OptionParser.accept or OptionParser#accept, or Regexp. This can appear # once or assigned as String if not present, otherwise causes an # ArgumentError. Examples: # Float, Time, Array # # [Possible argument values:] # Hash or Array. # [:text, :binary, :auto] # %w[iso-2022-jp shift_jis euc-jp utf8 binary] # { "jis" => "iso-2022-jp", "sjis" => "shift_jis" } # # [Long style switch:] # Specifies a long style switch which takes a mandatory, optional or no # argument. It's a string of the following form: # "--switch=MANDATORY" or "--switch MANDATORY" # "--switch[=OPTIONAL]" # "--switch" # # [Short style switch:] # Specifies short style switch which takes a mandatory, optional or no # argument. It's a string of the following form: # "-xMANDATORY" # "-x[OPTIONAL]" # "-x" # There is also a special form which matches character range (not full # set of regular expression): # "-[a-z]MANDATORY" # "-[a-z][OPTIONAL]" # "-[a-z]" # # [Argument style and description:] # Instead of specifying mandatory or optional arguments directly in the # switch parameter, this separate parameter can be used. # "=MANDATORY" # "=[OPTIONAL]" # # [Description:] # Description string for the option. # "Run verbosely" # # [Handler:] # Handler for the parsed argument value. Either give a block or pass a # Proc or Method as an argument. # def make_switch(opts, block = nil) short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], [] ldesc, sdesc, desc, arg = [], [], [] default_style = Switch::NoArgument default_pattern = nil klass = nil o = nil n, q, a = nil opts.each do |o| # argument class next if search(:atype, o) do |pat, c| klass = notwice(o, klass, 'type') if not_style and not_style != Switch::NoArgument not_pattern, not_conv = pat, c else default_pattern, conv = pat, c end end # directly specified pattern(any object possible to match) if !(String === o) and o.respond_to?(:match) pattern = notwice(o, pattern, 'pattern') conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert) next end # anything others case o when Proc, Method block = notwice(o, block, 'block') when Array, Hash case pattern when CompletingHash when nil pattern = CompletingHash.new conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert) else raise ArgumentError, "argument pattern given twice" end o.each {|(o, *v)| pattern[o] = v.fetch(0) {o}} when Module raise ArgumentError, "unsupported argument type: #{o}" when *ArgumentStyle.keys style = notwice(ArgumentStyle[o], style, 'style') when /^--no-([^\[\]=\s]*)(.+)?/ q, a = $1, $2 o = notwice(a ? Object : TrueClass, klass, 'type') not_pattern, not_conv = search(:atype, o) unless not_style not_style = (not_style || default_style).guess(arg = a) if a default_style = Switch::NoArgument default_pattern, conv = search(:atype, FalseClass) unless default_pattern ldesc << "--no-#{q}" long << 'no-' + (q = q.downcase) nolong << q when /^--\[no-\]([^\[\]=\s]*)(.+)?/ q, a = $1, $2 o = notwice(a ? Object : TrueClass, klass, 'type') if a default_style = default_style.guess(arg = a) default_pattern, conv = search(:atype, o) unless default_pattern end ldesc << "--[no-]#{q}" long << (o = q.downcase) not_pattern, not_conv = search(:atype, FalseClass) unless not_style not_style = Switch::NoArgument nolong << 'no-' + o when /^--([^\[\]=\s]*)(.+)?/ q, a = $1, $2 if a o = notwice(NilClass, klass, 'type') default_style = default_style.guess(arg = a) default_pattern, conv = search(:atype, o) unless default_pattern end ldesc << "--#{q}" long << (o = q.downcase) when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/ q, a = $1, $2 o = notwice(Object, klass, 'type') if a default_style = default_style.guess(arg = a) default_pattern, conv = search(:atype, o) unless default_pattern end sdesc << "-#{q}" short << Regexp.new(q) when /^-(.)(.+)?/ q, a = $1, $2 if a o = notwice(NilClass, klass, 'type') default_style = default_style.guess(arg = a) default_pattern, conv = search(:atype, o) unless default_pattern end sdesc << "-#{q}" short << q when /^=/ style = notwice(default_style.guess(arg = o), style, 'style') default_pattern, conv = search(:atype, Object) unless default_pattern else desc.push(o) end end default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern if !(short.empty? and long.empty?) s = (style || default_style).new(pattern || default_pattern, conv, sdesc, ldesc, arg, desc, block) elsif !block raise ArgumentError, "no switch given" if style or pattern s = desc else short << pattern s = (style || default_style).new(pattern, conv, nil, nil, arg, desc, block) end return s, short, long, (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style), nolong end def define(*opts, &block) top.append(*(sw = make_switch(opts, block))) sw[0] end # # Add option switch and handler. See #make_switch for an explanation of # parameters. # def on(*opts, &block) define(*opts, &block) self end alias def_option define def define_head(*opts, &block) top.prepend(*(sw = make_switch(opts, block))) sw[0] end # # Add option switch like with #on, but at head of summary. # def on_head(*opts, &block) define_head(*opts, &block) self end alias def_head_option define_head def define_tail(*opts, &block) base.append(*(sw = make_switch(opts, block))) sw[0] end # # Add option switch like with #on, but at tail of summary. # def on_tail(*opts, &block) define_tail(*opts, &block) self end alias def_tail_option define_tail # # Add separator in summary. # def separator(string) top.append(string, nil, nil) end # # Parses command line arguments +argv+ in order. When a block is given, # each non-option argument is yielded. # # Returns the rest of +argv+ left unparsed. # def order(*argv, &block) argv = argv[0].dup if argv.size == 1 and Array === argv[0] order!(argv, &block) end # # Same as #order, but removes switches destructively. # def order!(argv = default_argv, &nonopt) parse_in_order(argv, &nonopt) end def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc: opt, arg, sw, val, rest = nil nonopt ||= proc {|arg| throw :terminate, arg} argv.unshift(arg) if arg = catch(:terminate) { while arg = argv.shift case arg # long option when /\A--([^=]*)(?:=(.*))?/nm opt, rest = $1, $2 begin sw, = complete(:long, opt, true) rescue ParseError raise $!.set_option(arg, true) end begin opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)} val = cb.call(val) if cb setter.call(sw.switch_name, val) if setter rescue ParseError raise $!.set_option(arg, rest) end # short option when /\A-(.)((=).*|.+)?/nm opt, has_arg, eq, val, rest = $1, $3, $3, $2, $2 begin sw, = search(:short, opt) unless sw begin sw, = complete(:short, opt) # short option matched. val = arg.sub(/\A-/, '') has_arg = true rescue InvalidOption # if no short options match, try completion with long # options. sw, = complete(:long, opt) eq ||= !rest end end rescue ParseError raise $!.set_option(arg, true) end begin opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq} raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}" argv.unshift(opt) if opt and (opt = opt.sub(/\A-*/, '-')) != '-' val = cb.call(val) if cb setter.call(sw.switch_name, val) if setter rescue ParseError raise $!.set_option(arg, arg.length > 2) end # non-option argument else catch(:prune) do visit(:each_option) do |sw| sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg) end nonopt.call(arg) end end end nil } visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern} argv end private :parse_in_order # # Parses command line arguments +argv+ in permutation mode and returns # list of non-option arguments. # def permute(*argv) argv = argv[0].dup if argv.size == 1 and Array === argv[0] permute!(argv) end # # Same as #permute, but removes switches destructively. # def permute!(argv = default_argv) nonopts = [] arg = nil order!(argv) {|arg| nonopts << arg} argv[0, 0] = nonopts argv end # # Parses command line arguments +argv+ in order when environment variable # POSIXLY_CORRECT is set, and in permutation mode otherwise. # def parse(*argv) argv = argv[0].dup if argv.size == 1 and Array === argv[0] parse!(argv) end # # Same as #parse, but removes switches destructively. # def parse!(argv = default_argv) if ENV.include?('POSIXLY_CORRECT') order!(argv) else permute!(argv) end end # # Wrapper method for getopts.rb. # # params = ARGV.getopts("ab:", "foo", "bar:") # # params[:a] = true # -a # # params[:b] = "1" # -b1 # # params[:foo] = "1" # --foo # # params[:bar] = "x" # --bar x # def getopts(*args) argv = Array === args.first ? args.shift : default_argv single_options, *long_options = *args result = {} single_options.scan(/(.)(:)?/) do |opt, val| if val result[opt] = nil define("-#{opt} VAL") else result[opt] = false define("-#{opt}") end end if single_options long_options.each do |arg| opt, val = arg.split(':', 2) if val result[opt] = val.empty? ? nil : val define("--#{opt} VAL") else result[opt] = false define("--#{opt}") end end parse_in_order(argv, result.method(:[]=)) result end # # See #getopts. # def self.getopts(*args) new.getopts(*args) end # # Traverses @stack, sending each element method +id+ with +args+ and # +block+. # def visit(id, *args, &block) el = nil @stack.reverse_each do |el| el.send(id, *args, &block) end nil end private :visit # # Searches +key+ in @stack for +id+ hash and returns or yields the result. # def search(id, key) block_given = block_given? visit(:search, id, key) do |k| return block_given ? yield(k) : k end end private :search # # Completes shortened long style option switch and returns pair of # canonical switch and switch descriptor OptionParser::Switch. # # +id+:: Searching table. # +opt+:: Searching key. # +icase+:: Search case insensitive if true. # +pat+:: Optional pattern for completion. # def complete(typ, opt, icase = false, *pat) if pat.empty? search(typ, opt) {|sw| return [sw, opt]} # exact match or... end raise AmbiguousOption, catch(:ambiguous) { visit(:complete, typ, opt, icase, *pat) {|opt, *sw| return sw} raise InvalidOption, opt } end private :complete # # Loads options from file names as +filename+. Does nothing when the file # is not present. Returns whether successfully loaded. # # +filename+ defaults to basename of the program without suffix in a # directory ~/.options. # def load(filename = nil) begin filename ||= File.expand_path(File.basename($0, '.*'), '~/.options') rescue return false end begin parse(*IO.readlines(filename).each {|s| s.chomp!}) true rescue Errno::ENOENT, Errno::ENOTDIR false end end # # Parses environment variable +env+ or its uppercase with splitting like a # shell. # # +env+ defaults to the basename of the program. # def environment(env = File.basename($0, '.*')) env = ENV[env] || ENV[env.upcase] or return require 'shellwords' parse(*Shellwords.shellwords(env)) end # # Acceptable argument classes # # # Any string and no conversion. This is fall-back. # accept(Object) {|s,|s or s.nil?} accept(NilClass) {|s,|s} # # Any non-empty string, and no conversion. # accept(String, /.+/nm) {|s,*|s} # # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal # for 0x, and decimal for others; with optional sign prefix. Converts to # Integer. # decimal = '\d+(?:_\d+)*' binary = 'b[01]+(?:_[01]+)*' hex = 'x[\da-f]+(?:_[\da-f]+)*' octal = "0(?:[0-7]*(?:_[0-7]+)*|#{binary}|#{hex})" integer = "#{octal}|#{decimal}" accept(Integer, %r"\A[-+]?(?:#{integer})"io) {|s,| Integer(s) if s} # # Float number format, and converts to Float. # float = "(?:#{decimal}(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?" floatpat = %r"\A[-+]?#{float}"io accept(Float, floatpat) {|s,| s.to_f if s} # # Generic numeric format, converts to Integer for integer format, Float # for float format. # accept(Numeric, %r"\A[-+]?(?:#{octal}|#{float})"io) {|s,| eval(s) if s} # # Decimal integer format, to be converted to Integer. # DecimalInteger = /\A[-+]?#{decimal}/io accept(DecimalInteger) {|s,| s.to_i if s} # # Ruby/C like octal/hexadecimal/binary integer format, to be converted to # Integer. # OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))/io accept(OctalInteger) {|s,| s.oct if s} # # Decimal integer/float number format, to be converted to Integer for # integer format, Float for float format. # DecimalNumeric = floatpat # decimal integer is allowed as float also. accept(DecimalNumeric) {|s,| eval(s) if s} # # Boolean switch, which means whether it is present or not, whether it is # absent or not with prefix no-, or it takes an argument # yes/no/true/false/+/-. # yesno = CompletingHash.new %w[- no false].each {|el| yesno[el] = false} %w[+ yes true].each {|el| yesno[el] = true} yesno['nil'] = false # shoud be nil? accept(TrueClass, yesno) {|arg, val| val == nil or val} # # Similar to TrueClass, but defaults to false. # accept(FalseClass, yesno) {|arg, val| val != nil and val} # # List of strings separated by ",". # accept(Array) do |s,| if s s = s.split(',').collect {|s| s unless s.empty?} end s end # # Regular expression with options. # accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o| f = 0 if o f |= Regexp::IGNORECASE if /i/ =~ o f |= Regexp::MULTILINE if /m/ =~ o f |= Regexp::EXTENDED if /x/ =~ o k = o.delete("^imx") end Regexp.new(s || all, f, k) end # # Exceptions # # # Base class of exceptions from OptionParser. # class ParseError < RuntimeError # Reason which caused the error. Reason = 'parse error'.freeze def initialize(*args) @args = args @reason = nil end attr_reader :args attr_writer :reason # # Pushes back erred argument(s) to +argv+. # def recover(argv) argv[0, 0] = @args argv end def set_option(opt, eq) if eq @args[0] = opt else @args.unshift(opt) end self end # # Returns error reason. Override this for I18N. # def reason @reason || self.class::Reason end def inspect "#<#{self.class.to_s}: #{args.join(' ')}>" end # # Default stringizing method to emit standard error message. # def message reason + ': ' + args.join(' ') end alias to_s message end # # Raises when ambiguously completable string is encountered. # class AmbiguousOption < ParseError const_set(:Reason, 'ambiguous option'.freeze) end # # Raises when there is an argument for a switch which takes no argument. # class NeedlessArgument < ParseError const_set(:Reason, 'needless argument'.freeze) end # # Raises when a switch with mandatory argument has no argument. # class MissingArgument < ParseError const_set(:Reason, 'missing argument'.freeze) end # # Raises when switch is undefined. # class InvalidOption < ParseError const_set(:Reason, 'invalid option'.freeze) end # # Raises when the given argument does not match required format. # class InvalidArgument < ParseError const_set(:Reason, 'invalid argument'.freeze) end # # Raises when the given argument word can't be completed uniquely. # class AmbiguousArgument < InvalidArgument const_set(:Reason, 'ambiguous argument'.freeze) end # # Miscellaneous # # # Extends command line arguments array (ARGV) to parse itself. # module Arguable # # Sets OptionParser object, when +opt+ is +false+ or +nil+, methods # OptionParser::Arguable#options and OptionParser::Arguable#options= are # undefined. Thus, there is no ways to access the OptionParser object # via the receiver object. # def options=(opt) unless @optparse = opt class << self undef_method(:options) undef_method(:options=) end end end # # Actual OptionParser object, automatically created if nonexistent. # # If called with a block, yields the OptionParser object and returns the # result of the block. If an OptionParser::ParseError exception occurs # in the block, it is rescued, a error message printed to STDERR and # +nil+ returned. # def options @optparse ||= OptionParser.new @optparse.default_argv = self block_given? or return @optparse begin yield @optparse rescue ParseError @optparse.warn $! nil end end # # Parses +self+ destructively in order and returns +self+ containing the # rest arguments left unparsed. # def order!(&blk) options.order!(self, &blk) end # # Parses +self+ destructively in permutation mode and returns +self+ # containing the rest arguments left unparsed. # def permute!() options.permute!(self) end # # Parses +self+ destructively and returns +self+ containing the # rest arguments left unparsed. # def parse!() options.parse!(self) end # # Substitution of getopts is possible as follows. Also see # OptionParser#getopts. # # def getopts(*args) # ($OPT = ARGV.getopts(*args)).each do |opt, val| # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val" # end # rescue OptionParser::ParseError # end # def getopts(*args) options.getopts(self, *args) end # # Initializes instance variable. # def self.extend_object(obj) super obj.instance_eval {@optparse = nil} end def initialize(*args) super @optparse = nil end end # # Acceptable argument classes. Now contains DecimalInteger, OctalInteger # and DecimalNumeric. See Acceptable argument classes (in source code). # module Acceptables const_set(:DecimalInteger, OptionParser::DecimalInteger) const_set(:OctalInteger, OptionParser::OctalInteger) const_set(:DecimalNumeric, OptionParser::DecimalNumeric) end end # ARGV is arguable by OptionParser ARGV.extend(OptionParser::Arguable) if $0 == __FILE__ Version = OptionParser::Version ARGV.options {|q| q.parse!.empty? or puts "what's #{ARGV.join(' ')}?" } or abort(ARGV.options.to_s) end PK|]KC̼ weakref.rbnu[require "delegate" # WeakRef is a class to represent a reference to an object that is not seen by # the tracing phase of the garbage collector. This allows the referenced # object to be garbage collected as if nothing is referring to it. Because # WeakRef delegates method calls to the referenced object, it may be used in # place of that object, i.e. it is of the same duck type. # # Usage: # # foo = Object.new # foo = Object.new # p foo.to_s # original's class # foo = WeakRef.new(foo) # p foo.to_s # should be same class # ObjectSpace.garbage_collect # p foo.to_s # should raise exception (recycled) class WeakRef [ref,...] @@id_rev_map = {} # ref -> obj @@final = lambda{|id| __old_status = Thread.critical Thread.critical = true begin rids = @@id_map[id] if rids for rid in rids @@id_rev_map.delete(rid) end @@id_map.delete(id) end rid = @@id_rev_map[id] if rid @@id_rev_map.delete(id) @@id_map[rid].delete(id) @@id_map.delete(rid) if @@id_map[rid].empty? end ensure Thread.critical = __old_status end } # Create a new WeakRef from +orig+. def initialize(orig) super __setobj__(orig) end # Return the object this WeakRef references. Raises RefError if the object # has been garbage collected. The object returned is the object to which # method calls are delegated (see Delegator). def __getobj__ unless @@id_rev_map[self.__id__] == @__id raise RefError, "Illegal Reference - probably recycled", caller(2) end begin ObjectSpace._id2ref(@__id) rescue RangeError raise RefError, "Illegal Reference - probably recycled", caller(2) end end def __setobj__(obj) @__id = obj.__id__ __old_status = Thread.critical begin Thread.critical = true unless @@id_rev_map.key?(self) ObjectSpace.define_finalizer obj, @@final ObjectSpace.define_finalizer self, @@final end @@id_map[@__id] = [] unless @@id_map[@__id] ensure Thread.critical = __old_status end @@id_map[@__id].push self.__id__ @@id_rev_map[self.__id__] = @__id end # Returns true if the referenced object still exists, and false if it has # been garbage collected. def weakref_alive? @@id_rev_map[self.__id__] == @__id end end if __FILE__ == $0 require 'thread' foo = Object.new p foo.to_s # original's class foo = WeakRef.new(foo) p foo.to_s # should be same class ObjectSpace.garbage_collect p foo.to_s # should raise exception (recycled) end PK|]tsort.rbnu[#!/usr/bin/env ruby #-- # tsort.rb - provides a module for topological sorting and strongly connected components. #++ # # # TSort implements topological sorting using Tarjan's algorithm for # strongly connected components. # # TSort is designed to be able to be used with any object which can be # interpreted as a directed graph. # # TSort requires two methods to interpret an object as a graph, # tsort_each_node and tsort_each_child. # # * tsort_each_node is used to iterate for all nodes over a graph. # * tsort_each_child is used to iterate for child nodes of a given node. # # The equality of nodes are defined by eql? and hash since # TSort uses Hash internally. # # == A Simple Example # # The following example demonstrates how to mix the TSort module into an # existing class (in this case, Hash). Here, we're treating each key in # the hash as a node in the graph, and so we simply alias the required # #tsort_each_node method to Hash's #each_key method. For each key in the # hash, the associated value is an array of the node's child nodes. This # choice in turn leads to our implementation of the required #tsort_each_child # method, which fetches the array of child nodes and then iterates over that # array using the user-supplied block. # # require 'tsort' # # class Hash # include TSort # alias tsort_each_node each_key # def tsort_each_child(node, &block) # fetch(node).each(&block) # end # end # # {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort # #=> [3, 2, 1, 4] # # {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components # #=> [[4], [2, 3], [1]] # # == A More Realistic Example # # A very simple `make' like tool can be implemented as follows: # # require 'tsort' # # class Make # def initialize # @dep = {} # @dep.default = [] # end # # def rule(outputs, inputs=[], &block) # triple = [outputs, inputs, block] # outputs.each {|f| @dep[f] = [triple]} # @dep[triple] = inputs # end # # def build(target) # each_strongly_connected_component_from(target) {|ns| # if ns.length != 1 # fs = ns.delete_if {|n| Array === n} # raise TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}") # end # n = ns.first # if Array === n # outputs, inputs, block = n # inputs_time = inputs.map {|f| File.mtime f}.max # begin # outputs_time = outputs.map {|f| File.mtime f}.min # rescue Errno::ENOENT # outputs_time = nil # end # if outputs_time == nil || # inputs_time != nil && outputs_time <= inputs_time # sleep 1 if inputs_time != nil && inputs_time.to_i == Time.now.to_i # block.call # end # end # } # end # # def tsort_each_child(node, &block) # @dep[node].each(&block) # end # include TSort # end # # def command(arg) # print arg, "\n" # system arg # end # # m = Make.new # m.rule(%w[t1]) { command 'date > t1' } # m.rule(%w[t2]) { command 'date > t2' } # m.rule(%w[t3]) { command 'date > t3' } # m.rule(%w[t4], %w[t1 t3]) { command 'cat t1 t3 > t4' } # m.rule(%w[t5], %w[t4 t2]) { command 'cat t4 t2 > t5' } # m.build('t5') # # == Bugs # # * 'tsort.rb' is wrong name because this library uses # Tarjan's algorithm for strongly connected components. # Although 'strongly_connected_components.rb' is correct but too long. # # == References # # R. E. Tarjan, "Depth First Search and Linear Graph Algorithms", # SIAM Journal on Computing, Vol. 1, No. 2, pp. 146-160, June 1972. # module TSort class Cyclic < StandardError end # # Returns a topologically sorted array of nodes. # The array is sorted from children to parents, i.e. # the first element has no child and the last node has no parent. # # If there is a cycle, TSort::Cyclic is raised. # def tsort result = [] tsort_each {|element| result << element} result end # # The iterator version of the #tsort method. # obj.tsort_each is similar to obj.tsort.each, but # modification of _obj_ during the iteration may lead to unexpected results. # # #tsort_each returns +nil+. # If there is a cycle, TSort::Cyclic is raised. # def tsort_each # :yields: node each_strongly_connected_component {|component| if component.size == 1 yield component.first else raise Cyclic.new("topological sort failed: #{component.inspect}") end } end # # Returns strongly connected components as an array of arrays of nodes. # The array is sorted from children to parents. # Each elements of the array represents a strongly connected component. # def strongly_connected_components result = [] each_strongly_connected_component {|component| result << component} result end # # The iterator version of the #strongly_connected_components method. # obj.each_strongly_connected_component is similar to # obj.strongly_connected_components.each, but # modification of _obj_ during the iteration may lead to unexpected results. # # # #each_strongly_connected_component returns +nil+. # def each_strongly_connected_component # :yields: nodes id_map = {} stack = [] tsort_each_node {|node| unless id_map.include? node each_strongly_connected_component_from(node, id_map, stack) {|c| yield c } end } nil end # # Iterates over strongly connected component in the subgraph reachable from # _node_. # # Return value is unspecified. # # #each_strongly_connected_component_from doesn't call #tsort_each_node. # def each_strongly_connected_component_from(node, id_map={}, stack=[]) # :yields: nodes minimum_id = node_id = id_map[node] = id_map.size stack_length = stack.length stack << node tsort_each_child(node) {|child| if id_map.include? child child_id = id_map[child] minimum_id = child_id if child_id && child_id < minimum_id else sub_minimum_id = each_strongly_connected_component_from(child, id_map, stack) {|c| yield c } minimum_id = sub_minimum_id if sub_minimum_id < minimum_id end } if node_id == minimum_id component = stack.slice!(stack_length .. -1) component.each {|n| id_map[n] = nil} yield component end minimum_id end # # Should be implemented by a extended class. # # #tsort_each_node is used to iterate for all nodes over a graph. # def tsort_each_node # :yields: node raise NotImplementedError.new end # # Should be implemented by a extended class. # # #tsort_each_child is used to iterate for child nodes of _node_. # def tsort_each_child(node) # :yields: child raise NotImplementedError.new end end if __FILE__ == $0 require 'test/unit' class TSortHash < Hash # :nodoc: include TSort alias tsort_each_node each_key def tsort_each_child(node, &block) fetch(node).each(&block) end end class TSortArray < Array # :nodoc: include TSort alias tsort_each_node each_index def tsort_each_child(node, &block) fetch(node).each(&block) end end class TSortTest < Test::Unit::TestCase # :nodoc: def test_dag h = TSortHash[{1=>[2, 3], 2=>[3], 3=>[]}] assert_equal([3, 2, 1], h.tsort) assert_equal([[3], [2], [1]], h.strongly_connected_components) end def test_cycle h = TSortHash[{1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}] assert_equal([[4], [2, 3], [1]], h.strongly_connected_components.map {|nodes| nodes.sort}) assert_raise(TSort::Cyclic) { h.tsort } end def test_array a = TSortArray[[1], [0], [0], [2]] assert_equal([[0, 1], [2], [3]], a.strongly_connected_components.map {|nodes| nodes.sort}) a = TSortArray[[], [0]] assert_equal([[0], [1]], a.strongly_connected_components.map {|nodes| nodes.sort}) end end end PK|]N>el1l1yaml.rbnu[# -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4 # $Id: yaml.rb 16084 2008-04-19 11:45:39Z knu $ # # = yaml.rb: top-level module with methods for loading and parsing YAML documents # # Author:: why the lucky stiff # require 'stringio' require 'yaml/error' require 'yaml/syck' require 'yaml/tag' require 'yaml/stream' require 'yaml/constants' # == YAML # # YAML(tm) (rhymes with 'camel') is a # straightforward machine parsable data serialization format designed for # human readability and interaction with scripting languages such as Perl # and Python. YAML is optimized for data serialization, formatted # dumping, configuration files, log files, Internet messaging and # filtering. This specification describes the YAML information model and # serialization format. Together with the Unicode standard for characters, it # provides all the information necessary to understand YAML Version 1.0 # and construct computer programs to process it. # # See http://yaml.org/ for more information. For a quick tutorial, please # visit YAML In Five Minutes (http://yaml.kwiki.org/?YamlInFiveMinutes). # # == About This Library # # The YAML 1.0 specification outlines four stages of YAML loading and dumping. # This library honors all four of those stages, although data is really only # available to you in three stages. # # The four stages are: native, representation, serialization, and presentation. # # The native stage refers to data which has been loaded completely into Ruby's # own types. (See +YAML::load+.) # # The representation stage means data which has been composed into # +YAML::BaseNode+ objects. In this stage, the document is available as a # tree of node objects. You can perform YPath queries and transformations # at this level. (See +YAML::parse+.) # # The serialization stage happens inside the parser. The YAML parser used in # Ruby is called Syck. Serialized nodes are available in the extension as # SyckNode structs. # # The presentation stage is the YAML document itself. This is accessible # to you as a string. (See +YAML::dump+.) # # For more information about the various information models, see Chapter # 3 of the YAML 1.0 Specification (http://yaml.org/spec/#id2491269). # # The YAML module provides quick access to the most common loading (YAML::load) # and dumping (YAML::dump) tasks. This module also provides an API for registering # global types (YAML::add_domain_type). # # == Example # # A simple round-trip (load and dump) of an object. # # require "yaml" # # test_obj = ["dogs", "cats", "badgers"] # # yaml_obj = YAML::dump( test_obj ) # # -> --- # - dogs # - cats # - badgers # ruby_obj = YAML::load( yaml_obj ) # # => ["dogs", "cats", "badgers"] # ruby_obj == test_obj # # => true # # To register your custom types with the global resolver, use +add_domain_type+. # # YAML::add_domain_type( "your-site.com,2004", "widget" ) do |type, val| # Widget.new( val ) # end # module YAML Resolver = YAML::Syck::Resolver DefaultResolver = YAML::Syck::DefaultResolver DefaultResolver.use_types_at( @@tagged_classes ) GenericResolver = YAML::Syck::GenericResolver Parser = YAML::Syck::Parser Emitter = YAML::Syck::Emitter # Returns a new default parser def YAML.parser; Parser.new.set_resolver( YAML.resolver ); end # Returns a new generic parser def YAML.generic_parser; Parser.new.set_resolver( GenericResolver ); end # Returns the default resolver def YAML.resolver; DefaultResolver; end # Returns a new default emitter def YAML.emitter; Emitter.new.set_resolver( YAML.resolver ); end # # Converts _obj_ to YAML and writes the YAML result to _io_. # # File.open( 'animals.yaml', 'w' ) do |out| # YAML.dump( ['badger', 'elephant', 'tiger'], out ) # end # # If no _io_ is provided, a string containing the dumped YAML # is returned. # # YAML.dump( :locked ) # #=> "--- :locked" # def YAML.dump( obj, io = nil ) obj.to_yaml( io || io2 = StringIO.new ) io || ( io2.rewind; io2.read ) end # # Load a document from the current _io_ stream. # # File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) } # #=> ['badger', 'elephant', 'tiger'] # # Can also load from a string. # # YAML.load( "--- :locked" ) # #=> :locked # def YAML.load( io ) yp = parser.load( io ) end # # Load a document from the file located at _filepath_. # # YAML.load_file( 'animals.yaml' ) # #=> ['badger', 'elephant', 'tiger'] # def YAML.load_file( filepath ) File.open( filepath ) do |f| load( f ) end end # # Parse the first document from the current _io_ stream # # File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) } # #=> #, # #, # #]> # # Can also load from a string. # # YAML.parse( "--- :locked" ) # #=> # # def YAML.parse( io ) yp = generic_parser.load( io ) end # # Parse a document from the file located at _filepath_. # # YAML.parse_file( 'animals.yaml' ) # #=> #, # #, # #]> # def YAML.parse_file( filepath ) File.open( filepath ) do |f| parse( f ) end end # # Calls _block_ with each consecutive document in the YAML # stream contained in _io_. # # File.open( 'many-docs.yaml' ) do |yf| # YAML.each_document( yf ) do |ydoc| # ## ydoc contains the single object # ## from the YAML document # end # end # def YAML.each_document( io, &block ) yp = parser.load_documents( io, &block ) end # # Calls _block_ with each consecutive document in the YAML # stream contained in _io_. # # File.open( 'many-docs.yaml' ) do |yf| # YAML.load_documents( yf ) do |ydoc| # ## ydoc contains the single object # ## from the YAML document # end # end # def YAML.load_documents( io, &doc_proc ) YAML.each_document( io, &doc_proc ) end # # Calls _block_ with a tree of +YAML::BaseNodes+, one tree for # each consecutive document in the YAML stream contained in _io_. # # File.open( 'many-docs.yaml' ) do |yf| # YAML.each_node( yf ) do |ydoc| # ## ydoc contains a tree of nodes # ## from the YAML document # end # end # def YAML.each_node( io, &doc_proc ) yp = generic_parser.load_documents( io, &doc_proc ) end # # Calls _block_ with a tree of +YAML::BaseNodes+, one tree for # each consecutive document in the YAML stream contained in _io_. # # File.open( 'many-docs.yaml' ) do |yf| # YAML.parse_documents( yf ) do |ydoc| # ## ydoc contains a tree of nodes # ## from the YAML document # end # end # def YAML.parse_documents( io, &doc_proc ) YAML.each_node( io, &doc_proc ) end # # Loads all documents from the current _io_ stream, # returning a +YAML::Stream+ object containing all # loaded documents. # def YAML.load_stream( io ) d = nil parser.load_documents( io ) do |doc| d = YAML::Stream.new if not d d.add( doc ) end return d end # # Returns a YAML stream containing each of the items in +objs+, # each having their own document. # # YAML.dump_stream( 0, [], {} ) # #=> --- 0 # --- [] # --- {} # def YAML.dump_stream( *objs ) d = YAML::Stream.new objs.each do |doc| d.add( doc ) end d.emit end # # Add a global handler for a YAML domain type. # def YAML.add_domain_type( domain, type_tag, &transfer_proc ) resolver.add_type( "tag:#{ domain }:#{ type_tag }", transfer_proc ) end # # Add a transfer method for a builtin type # def YAML.add_builtin_type( type_tag, &transfer_proc ) resolver.add_type( "tag:yaml.org,2002:#{ type_tag }", transfer_proc ) end # # Add a transfer method for a builtin type # def YAML.add_ruby_type( type_tag, &transfer_proc ) resolver.add_type( "tag:ruby.yaml.org,2002:#{ type_tag }", transfer_proc ) end # # Add a private document type # def YAML.add_private_type( type_re, &transfer_proc ) resolver.add_type( "x-private:" + type_re, transfer_proc ) end # # Detect typing of a string # def YAML.detect_implicit( val ) resolver.detect_implicit( val ) end # # Convert a type_id to a taguri # def YAML.tagurize( val ) resolver.tagurize( val ) end # # Apply a transfer method to a Ruby object # def YAML.transfer( type_id, obj ) resolver.transfer( YAML.tagurize( type_id ), obj ) end # # Apply any implicit a node may qualify for # def YAML.try_implicit( obj ) YAML.transfer( YAML.detect_implicit( obj ), obj ) end # # Method to extract colon-seperated type and class, returning # the type and the constant of the class # def YAML.read_type_class( type, obj_class ) scheme, domain, type, tclass = type.split( ':', 4 ) tclass.split( "::" ).each { |c| obj_class = obj_class.const_get( c ) } if tclass return [ type, obj_class ] end # # Allocate blank object # def YAML.object_maker( obj_class, val ) if Hash === val o = obj_class.allocate val.each_pair { |k,v| o.instance_variable_set("@#{k}", v) } o else raise YAML::Error, "Invalid object explicitly tagged !ruby/Object: " + val.inspect end end # # Allocate an Emitter if needed # def YAML.quick_emit( oid, opts = {}, &e ) out = if opts.is_a? YAML::Emitter opts else emitter.reset( opts ) end oid = case oid when Fixnum, NilClass; oid else oid = "#{oid.object_id}-#{oid.hash}" end out.emit( oid, &e ) end end require 'yaml/rubytypes' require 'yaml/types' module Kernel # # ryan:: You know how Kernel.p is a really convenient way to dump ruby # structures? The only downside is that it's not as legible as # YAML. # # _why:: (listening) # # ryan:: I know you don't want to urinate all over your users' namespaces. # But, on the other hand, convenience of dumping for debugging is, # IMO, a big YAML use case. # # _why:: Go nuts! Have a pony parade! # # ryan:: Either way, I certainly will have a pony parade. # # Prints any supplied _objects_ out in YAML. Intended as # a variation on +Kernel::p+. # # S = Struct.new(:name, :state) # s = S['dave', 'TX'] # y s # # _produces:_ # # --- !ruby/struct:S # name: dave # state: TX # def y( object, *objects ) objects.unshift object puts( if objects.length == 1 YAML::dump( *objects ) else YAML::dump_stream( *objects ) end ) end private :y end PK|]P-wuu pathname.rbnu[# # = pathname.rb # # Object-Oriented Pathname Class # # Author:: Tanaka Akira # Documentation:: Author and Gavin Sinclair # # For documentation, see class Pathname. # # pathname.rb is distributed with Ruby since 1.8.0. # # # == Pathname # # Pathname represents a pathname which locates a file in a filesystem. # The pathname depends on OS: Unix, Windows, etc. # Pathname library works with pathnames of local OS. # However non-Unix pathnames are supported experimentally. # # It does not represent the file itself. # A Pathname can be relative or absolute. It's not until you try to # reference the file that it even matters whether the file exists or not. # # Pathname is immutable. It has no method for destructive update. # # The value of this class is to manipulate file path information in a neater # way than standard Ruby provides. The examples below demonstrate the # difference. *All* functionality from File, FileTest, and some from Dir and # FileUtils is included, in an unsurprising way. It is essentially a facade for # all of these, and more. # # == Examples # # === Example 1: Using Pathname # # require 'pathname' # p = Pathname.new("/usr/bin/ruby") # size = p.size # 27662 # isdir = p.directory? # false # dir = p.dirname # Pathname:/usr/bin # base = p.basename # Pathname:ruby # dir, base = p.split # [Pathname:/usr/bin, Pathname:ruby] # data = p.read # p.open { |f| _ } # p.each_line { |line| _ } # # === Example 2: Using standard Ruby # # p = "/usr/bin/ruby" # size = File.size(p) # 27662 # isdir = File.directory?(p) # false # dir = File.dirname(p) # "/usr/bin" # base = File.basename(p) # "ruby" # dir, base = File.split(p) # ["/usr/bin", "ruby"] # data = File.read(p) # File.open(p) { |f| _ } # File.foreach(p) { |line| _ } # # === Example 3: Special features # # p1 = Pathname.new("/usr/lib") # Pathname:/usr/lib # p2 = p1 + "ruby/1.8" # Pathname:/usr/lib/ruby/1.8 # p3 = p1.parent # Pathname:/usr # p4 = p2.relative_path_from(p3) # Pathname:lib/ruby/1.8 # pwd = Pathname.pwd # Pathname:/home/gavin # pwd.absolute? # true # p5 = Pathname.new "." # Pathname:. # p5 = p5 + "music/../articles" # Pathname:music/../articles # p5.cleanpath # Pathname:articles # p5.realpath # Pathname:/home/gavin/articles # p5.children # [Pathname:/home/gavin/articles/linux, ...] # # == Breakdown of functionality # # === Core methods # # These methods are effectively manipulating a String, because that's all a path # is. Except for #mountpoint?, #children, and #realpath, they don't access the # filesystem. # # - + # - #join # - #parent # - #root? # - #absolute? # - #relative? # - #relative_path_from # - #each_filename # - #cleanpath # - #realpath # - #children # - #mountpoint? # # === File status predicate methods # # These methods are a facade for FileTest: # - #blockdev? # - #chardev? # - #directory? # - #executable? # - #executable_real? # - #exist? # - #file? # - #grpowned? # - #owned? # - #pipe? # - #readable? # - #world_readable? # - #readable_real? # - #setgid? # - #setuid? # - #size # - #size? # - #socket? # - #sticky? # - #symlink? # - #writable? # - #world_writable? # - #writable_real? # - #zero? # # === File property and manipulation methods # # These methods are a facade for File: # - #atime # - #ctime # - #mtime # - #chmod(mode) # - #lchmod(mode) # - #chown(owner, group) # - #lchown(owner, group) # - #fnmatch(pattern, *args) # - #fnmatch?(pattern, *args) # - #ftype # - #make_link(old) # - #open(*args, &block) # - #readlink # - #rename(to) # - #stat # - #lstat # - #make_symlink(old) # - #truncate(length) # - #utime(atime, mtime) # - #basename(*args) # - #dirname # - #extname # - #expand_path(*args) # - #split # # === Directory methods # # These methods are a facade for Dir: # - Pathname.glob(*args) # - Pathname.getwd / Pathname.pwd # - #rmdir # - #entries # - #each_entry(&block) # - #mkdir(*args) # - #opendir(*args) # # === IO # # These methods are a facade for IO: # - #each_line(*args, &block) # - #read(*args) # - #readlines(*args) # - #sysopen(*args) # # === Utilities # # These methods are a mixture of Find, FileUtils, and others: # - #find(&block) # - #mkpath # - #rmtree # - #unlink / #delete # # # == Method documentation # # As the above section shows, most of the methods in Pathname are facades. The # documentation for these methods generally just says, for instance, "See # FileTest.writable?", as you should be familiar with the original method # anyway, and its documentation (e.g. through +ri+) will contain more # information. In some cases, a brief description will follow. # class Pathname # :stopdoc: if RUBY_VERSION < "1.9" TO_PATH = :to_str else # to_path is implemented so Pathname objects are usable with File.open, etc. TO_PATH = :to_path end SAME_PATHS = if File::FNM_SYSCASE.nonzero? proc {|a, b| a.casecmp(b).zero?} else proc {|a, b| a == b} end # :startdoc: # # Create a Pathname object from the given String (or String-like object). # If +path+ contains a NUL character (\0), an ArgumentError is raised. # def initialize(path) path = path.__send__(TO_PATH) if path.respond_to? TO_PATH @path = path.dup if /\0/ =~ @path raise ArgumentError, "pathname contains \\0: #{@path.inspect}" end self.taint if @path.tainted? end def freeze() super; @path.freeze; self end def taint() super; @path.taint; self end def untaint() super; @path.untaint; self end # # Compare this pathname with +other+. The comparison is string-based. # Be aware that two different paths (foo.txt and ./foo.txt) # can refer to the same file. # def ==(other) return false unless Pathname === other other.to_s == @path end alias === == alias eql? == # Provides for comparing pathnames, case-sensitively. def <=>(other) return nil unless Pathname === other @path.tr('/', "\0") <=> other.to_s.tr('/', "\0") end def hash # :nodoc: @path.hash end # Return the path as a String. def to_s @path.dup end # to_path is implemented so Pathname objects are usable with File.open, etc. alias_method TO_PATH, :to_s def inspect # :nodoc: "#<#{self.class}:#{@path}>" end # Return a pathname which is substituted by String#sub. def sub(pattern, *rest, &block) if block path = @path.sub(pattern, *rest) {|*args| begin old = Thread.current[:pathname_sub_matchdata] Thread.current[:pathname_sub_matchdata] = $~ eval("$~ = Thread.current[:pathname_sub_matchdata]", block.binding) ensure Thread.current[:pathname_sub_matchdata] = old end yield(*args) } else path = @path.sub(pattern, *rest) end self.class.new(path) end if File::ALT_SEPARATOR SEPARATOR_PAT = /[#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}]/ else SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/ end # chop_basename(path) -> [pre-basename, basename] or nil def chop_basename(path) base = File.basename(path) if /\A#{SEPARATOR_PAT}?\z/ =~ base return nil else return path[0, path.rindex(base)], base end end private :chop_basename # split_names(path) -> prefix, [name, ...] def split_names(path) names = [] while r = chop_basename(path) path, basename = r names.unshift basename end return path, names end private :split_names def prepend_prefix(prefix, relpath) if relpath.empty? File.dirname(prefix) elsif /#{SEPARATOR_PAT}/ =~ prefix prefix = File.dirname(prefix) prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a' prefix + relpath else prefix + relpath end end private :prepend_prefix # Returns clean pathname of +self+ with consecutive slashes and useless dots # removed. The filesystem is not accessed. # # If +consider_symlink+ is +true+, then a more conservative algorithm is used # to avoid breaking symbolic linkages. This may retain more .. # entries than absolutely necessary, but without accessing the filesystem, # this can't be avoided. See #realpath. # def cleanpath(consider_symlink=false) if consider_symlink cleanpath_conservative else cleanpath_aggressive end end # # Clean the path simply by resolving and removing excess "." and ".." entries. # Nothing more, nothing less. # def cleanpath_aggressive path = @path names = [] pre = path while r = chop_basename(pre) pre, base = r case base when '.' when '..' names.unshift base else if names[0] == '..' names.shift else names.unshift base end end end if /#{SEPARATOR_PAT}/o =~ File.basename(pre) names.shift while names[0] == '..' end self.class.new(prepend_prefix(pre, File.join(*names))) end private :cleanpath_aggressive # has_trailing_separator?(path) -> bool def has_trailing_separator?(path) if r = chop_basename(path) pre, basename = r pre.length + basename.length < path.length else false end end private :has_trailing_separator? # add_trailing_separator(path) -> path def add_trailing_separator(path) if File.basename(path + 'a') == 'a' path else File.join(path, "") # xxx: Is File.join is appropriate to add separator? end end private :add_trailing_separator def del_trailing_separator(path) if r = chop_basename(path) pre, basename = r pre + basename elsif /#{SEPARATOR_PAT}+\z/o =~ path $` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o] else path end end private :del_trailing_separator def cleanpath_conservative path = @path names = [] pre = path while r = chop_basename(pre) pre, base = r names.unshift base if base != '.' end if /#{SEPARATOR_PAT}/o =~ File.basename(pre) names.shift while names[0] == '..' end if names.empty? self.class.new(File.dirname(pre)) else if names.last != '..' && File.basename(path) == '.' names << '.' end result = prepend_prefix(pre, File.join(*names)) if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path) self.class.new(add_trailing_separator(result)) else self.class.new(result) end end end private :cleanpath_conservative def realpath_rec(prefix, unresolved, h) resolved = [] until unresolved.empty? n = unresolved.shift if n == '.' next elsif n == '..' resolved.pop else path = prepend_prefix(prefix, File.join(*(resolved + [n]))) if h.include? path if h[path] == :resolving raise Errno::ELOOP.new(path) else prefix, *resolved = h[path] end else s = File.lstat(path) if s.symlink? h[path] = :resolving link_prefix, link_names = split_names(File.readlink(path)) if link_prefix == '' prefix, *resolved = h[path] = realpath_rec(prefix, resolved + link_names, h) else prefix, *resolved = h[path] = realpath_rec(link_prefix, link_names, h) end else resolved << n h[path] = [prefix, *resolved] end end end end return prefix, *resolved end private :realpath_rec # # Returns a real (absolute) pathname of +self+ in the actual filesystem. # The real pathname doesn't contain symlinks or useless dots. # # No arguments should be given; the old behaviour is *obsoleted*. # def realpath path = @path prefix, names = split_names(path) if prefix == '' prefix, names2 = split_names(Dir.pwd) names = names2 + names end prefix, *names = realpath_rec(prefix, names, {}) self.class.new(prepend_prefix(prefix, File.join(*names))) end # #parent returns the parent directory. # # This is same as self + '..'. def parent self + '..' end # #mountpoint? returns +true+ if self points to a mountpoint. def mountpoint? begin stat1 = self.lstat stat2 = self.parent.lstat stat1.dev == stat2.dev && stat1.ino == stat2.ino || stat1.dev != stat2.dev rescue Errno::ENOENT false end end # # #root? is a predicate for root directories. I.e. it returns +true+ if the # pathname consists of consecutive slashes. # # It doesn't access actual filesystem. So it may return +false+ for some # pathnames which points to roots such as /usr/... # def root? !!(chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o =~ @path) end # Predicate method for testing whether a path is absolute. # It returns +true+ if the pathname begins with a slash. def absolute? !relative? end # The opposite of #absolute? def relative? path = @path while r = chop_basename(path) path, basename = r end path == '' end # # Iterates over each component of the path. # # Pathname.new("/usr/bin/ruby").each_filename {|filename| ... } # # yields "usr", "bin", and "ruby". # def each_filename # :yield: filename prefix, names = split_names(@path) names.each {|filename| yield filename } nil end # Iterates over and yields a new Pathname object # for each element in the given path in descending order. # # Pathname.new('/path/to/some/file.rb').descend {|v| p v} # # # # # # # # # # # # Pathname.new('path/to/some/file.rb').descend {|v| p v} # # # # # # # # # # It doesn't access actual filesystem. # # This method is available since 1.8.5. # def descend vs = [] ascend {|v| vs << v } vs.reverse_each {|v| yield v } nil end # Iterates over and yields a new Pathname object # for each element in the given path in ascending order. # # Pathname.new('/path/to/some/file.rb').ascend {|v| p v} # # # # # # # # # # # # Pathname.new('path/to/some/file.rb').ascend {|v| p v} # # # # # # # # # # It doesn't access actual filesystem. # # This method is available since 1.8.5. # def ascend path = @path yield self while r = chop_basename(path) path, name = r break if path.empty? yield self.class.new(del_trailing_separator(path)) end end # # Pathname#+ appends a pathname fragment to this one to produce a new Pathname # object. # # p1 = Pathname.new("/usr") # Pathname:/usr # p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby # p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd # # This method doesn't access the file system; it is pure string manipulation. # def +(other) other = Pathname.new(other) unless Pathname === other Pathname.new(plus(@path, other.to_s)) end def plus(path1, path2) # -> path prefix2 = path2 index_list2 = [] basename_list2 = [] while r2 = chop_basename(prefix2) prefix2, basename2 = r2 index_list2.unshift prefix2.length basename_list2.unshift basename2 end return path2 if prefix2 != '' prefix1 = path1 while true while !basename_list2.empty? && basename_list2.first == '.' index_list2.shift basename_list2.shift end break unless r1 = chop_basename(prefix1) prefix1, basename1 = r1 next if basename1 == '.' if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..' prefix1 = prefix1 + basename1 break end index_list2.shift basename_list2.shift end r1 = chop_basename(prefix1) if !r1 && /#{SEPARATOR_PAT}/o =~ File.basename(prefix1) while !basename_list2.empty? && basename_list2.first == '..' index_list2.shift basename_list2.shift end end if !basename_list2.empty? suffix2 = path2[index_list2.first..-1] r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2 else r1 ? prefix1 : File.dirname(prefix1) end end private :plus # # Pathname#join joins pathnames. # # path0.join(path1, ..., pathN) is the same as # path0 + path1 + ... + pathN. # def join(*args) args.unshift self result = args.pop result = Pathname.new(result) unless Pathname === result return result if result.absolute? args.reverse_each {|arg| arg = Pathname.new(arg) unless Pathname === arg result = arg + result return result if result.absolute? } result end # # Returns the children of the directory (files and subdirectories, not # recursive) as an array of Pathname objects. By default, the returned # pathnames will have enough information to access the files. If you set # +with_directory+ to +false+, then the returned pathnames will contain the # filename only. # # For example: # p = Pathname("/usr/lib/ruby/1.8") # p.children # # -> [ Pathname:/usr/lib/ruby/1.8/English.rb, # Pathname:/usr/lib/ruby/1.8/Env.rb, # Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ] # p.children(false) # # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ] # # Note that the result never contain the entries . and .. in # the directory because they are not children. # # This method has existed since 1.8.1. # def children(with_directory=true) with_directory = false if @path == '.' result = [] Dir.foreach(@path) {|e| next if e == '.' || e == '..' if with_directory result << self.class.new(File.join(@path, e)) else result << self.class.new(e) end } result end # # #relative_path_from returns a relative path from the argument to the # receiver. If +self+ is absolute, the argument must be absolute too. If # +self+ is relative, the argument must be relative too. # # #relative_path_from doesn't access the filesystem. It assumes no symlinks. # # ArgumentError is raised when it cannot find a relative path. # # This method has existed since 1.8.1. # def relative_path_from(base_directory) dest_directory = self.cleanpath.to_s base_directory = base_directory.cleanpath.to_s dest_prefix = dest_directory dest_names = [] while r = chop_basename(dest_prefix) dest_prefix, basename = r dest_names.unshift basename if basename != '.' end base_prefix = base_directory base_names = [] while r = chop_basename(base_prefix) base_prefix, basename = r base_names.unshift basename if basename != '.' end unless SAME_PATHS[dest_prefix, base_prefix] raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}" end while !dest_names.empty? && !base_names.empty? && SAME_PATHS[dest_names.first, base_names.first] dest_names.shift base_names.shift end if base_names.include? '..' raise ArgumentError, "base_directory has ..: #{base_directory.inspect}" end base_names.fill('..') relpath_names = base_names + dest_names if relpath_names.empty? Pathname.new('.') else Pathname.new(File.join(*relpath_names)) end end end class Pathname # * IO * # # #each_line iterates over the line in the file. It yields a String object # for each line. # # This method has existed since 1.8.1. # def each_line(*args, &block) # :yield: line IO.foreach(@path, *args, &block) end # Pathname#foreachline is *obsoleted* at 1.8.1. Use #each_line. def foreachline(*args, &block) warn "Pathname#foreachline is obsoleted. Use Pathname#each_line." each_line(*args, &block) end # See IO.read. Returns all the bytes from the file, or the first +N+ # if specified. def read(*args) IO.read(@path, *args) end # See IO.readlines. Returns all the lines from the file. def readlines(*args) IO.readlines(@path, *args) end # See IO.sysopen. def sysopen(*args) IO.sysopen(@path, *args) end end class Pathname # * File * # See File.atime. Returns last access time. def atime() File.atime(@path) end # See File.ctime. Returns last (directory entry, not file) change time. def ctime() File.ctime(@path) end # See File.mtime. Returns last modification time. def mtime() File.mtime(@path) end # See File.chmod. Changes permissions. def chmod(mode) File.chmod(mode, @path) end # See File.lchmod. def lchmod(mode) File.lchmod(mode, @path) end # See File.chown. Change owner and group of file. def chown(owner, group) File.chown(owner, group, @path) end # See File.lchown. def lchown(owner, group) File.lchown(owner, group, @path) end # See File.fnmatch. Return +true+ if the receiver matches the given # pattern. def fnmatch(pattern, *args) File.fnmatch(pattern, @path, *args) end # See File.fnmatch? (same as #fnmatch). def fnmatch?(pattern, *args) File.fnmatch?(pattern, @path, *args) end # See File.ftype. Returns "type" of file ("file", "directory", # etc). def ftype() File.ftype(@path) end # See File.link. Creates a hard link. def make_link(old) File.link(old, @path) end # See File.open. Opens the file for reading or writing. def open(*args, &block) # :yield: file File.open(@path, *args, &block) end # See File.readlink. Read symbolic link. def readlink() self.class.new(File.readlink(@path)) end # See File.rename. Rename the file. def rename(to) File.rename(@path, to) end # See File.stat. Returns a File::Stat object. def stat() File.stat(@path) end # See File.lstat. def lstat() File.lstat(@path) end # See File.symlink. Creates a symbolic link. def make_symlink(old) File.symlink(old, @path) end # See File.truncate. Truncate the file to +length+ bytes. def truncate(length) File.truncate(@path, length) end # See File.utime. Update the access and modification times. def utime(atime, mtime) File.utime(atime, mtime, @path) end # See File.basename. Returns the last component of the path. def basename(*args) self.class.new(File.basename(@path, *args)) end # See File.dirname. Returns all but the last component of the path. def dirname() self.class.new(File.dirname(@path)) end # See File.extname. Returns the file's extension. def extname() File.extname(@path) end # See File.expand_path. def expand_path(*args) self.class.new(File.expand_path(@path, *args)) end # See File.split. Returns the #dirname and the #basename in an # Array. def split() File.split(@path).map {|f| self.class.new(f) } end # Pathname#link is confusing and *obsoleted* because the receiver/argument # order is inverted to corresponding system call. def link(old) warn 'Pathname#link is obsoleted. Use Pathname#make_link.' File.link(old, @path) end # Pathname#symlink is confusing and *obsoleted* because the receiver/argument # order is inverted to corresponding system call. def symlink(old) warn 'Pathname#symlink is obsoleted. Use Pathname#make_symlink.' File.symlink(old, @path) end end class Pathname # * FileTest * # See FileTest.blockdev?. def blockdev?() FileTest.blockdev?(@path) end # See FileTest.chardev?. def chardev?() FileTest.chardev?(@path) end # See FileTest.executable?. def executable?() FileTest.executable?(@path) end # See FileTest.executable_real?. def executable_real?() FileTest.executable_real?(@path) end # See FileTest.exist?. def exist?() FileTest.exist?(@path) end # See FileTest.grpowned?. def grpowned?() FileTest.grpowned?(@path) end # See FileTest.directory?. def directory?() FileTest.directory?(@path) end # See FileTest.file?. def file?() FileTest.file?(@path) end # See FileTest.pipe?. def pipe?() FileTest.pipe?(@path) end # See FileTest.socket?. def socket?() FileTest.socket?(@path) end # See FileTest.owned?. def owned?() FileTest.owned?(@path) end # See FileTest.readable?. def readable?() FileTest.readable?(@path) end # See FileTest.world_readable?. def world_readable?() FileTest.world_readable?(@path) end # See FileTest.readable_real?. def readable_real?() FileTest.readable_real?(@path) end # See FileTest.setuid?. def setuid?() FileTest.setuid?(@path) end # See FileTest.setgid?. def setgid?() FileTest.setgid?(@path) end # See FileTest.size. def size() FileTest.size(@path) end # See FileTest.size?. def size?() FileTest.size?(@path) end # See FileTest.sticky?. def sticky?() FileTest.sticky?(@path) end # See FileTest.symlink?. def symlink?() FileTest.symlink?(@path) end # See FileTest.writable?. def writable?() FileTest.writable?(@path) end # See FileTest.world_writable?. def world_writable?() FileTest.world_writable?(@path) end # See FileTest.writable_real?. def writable_real?() FileTest.writable_real?(@path) end # See FileTest.zero?. def zero?() FileTest.zero?(@path) end end class Pathname # * Dir * # See Dir.glob. Returns or yields Pathname objects. def Pathname.glob(*args) # :yield: p if block_given? Dir.glob(*args) {|f| yield self.new(f) } else Dir.glob(*args).map {|f| self.new(f) } end end # See Dir.getwd. Returns the current working directory as a Pathname. def Pathname.getwd() self.new(Dir.getwd) end class << self; alias pwd getwd end # Pathname#chdir is *obsoleted* at 1.8.1. def chdir(&block) warn "Pathname#chdir is obsoleted. Use Dir.chdir." Dir.chdir(@path, &block) end # Pathname#chroot is *obsoleted* at 1.8.1. def chroot warn "Pathname#chroot is obsoleted. Use Dir.chroot." Dir.chroot(@path) end # Return the entries (files and subdirectories) in the directory, each as a # Pathname object. def entries() Dir.entries(@path).map {|f| self.class.new(f) } end # Iterates over the entries (files and subdirectories) in the directory. It # yields a Pathname object for each entry. # # This method has existed since 1.8.1. def each_entry(&block) # :yield: p Dir.foreach(@path) {|f| yield self.class.new(f) } end # Pathname#dir_foreach is *obsoleted* at 1.8.1. def dir_foreach(*args, &block) warn "Pathname#dir_foreach is obsoleted. Use Pathname#each_entry." each_entry(*args, &block) end # See Dir.mkdir. Create the referenced directory. def mkdir(*args) Dir.mkdir(@path, *args) end # See Dir.rmdir. Remove the referenced directory. def rmdir() Dir.rmdir(@path) end # See Dir.open. def opendir(&block) # :yield: dir Dir.open(@path, &block) end end class Pathname # * Find * # # Pathname#find is an iterator to traverse a directory tree in a depth first # manner. It yields a Pathname for each file under "this" directory. # # Since it is implemented by find.rb, Find.prune can be used # to control the traverse. # # If +self+ is ., yielded pathnames begin with a filename in the # current directory, not ./. # def find(&block) # :yield: p require 'find' if @path == '.' Find.find(@path) {|f| yield self.class.new(f.sub(%r{\A\./}, '')) } else Find.find(@path) {|f| yield self.class.new(f) } end end end class Pathname # * FileUtils * # See FileUtils.mkpath. Creates a full path, including any # intermediate directories that don't yet exist. def mkpath require 'fileutils' FileUtils.mkpath(@path) nil end # See FileUtils.rm_r. Deletes a directory and all beneath it. def rmtree # The name "rmtree" is borrowed from File::Path of Perl. # File::Path provides "mkpath" and "rmtree". require 'fileutils' FileUtils.rm_r(@path) nil end end class Pathname # * mixed * # Removes a file or directory, using File.unlink or # Dir.unlink as necessary. def unlink() begin Dir.unlink @path rescue Errno::ENOTDIR File.unlink @path end end alias delete unlink # This method is *obsoleted* at 1.8.1. Use #each_line or #each_entry. def foreach(*args, &block) warn "Pathname#foreach is obsoleted. Use each_line or each_entry." if FileTest.directory? @path # For polymorphism between Dir.foreach and IO.foreach, # Pathname#foreach doesn't yield Pathname object. Dir.foreach(@path, *args, &block) else IO.foreach(@path, *args, &block) end end end module Kernel # create a pathname object. # # This method is available since 1.8.5. def Pathname(path) # :doc: Pathname.new(path) end private :Pathname end PK|]rOwebrick/server.rbnu[# # server.rb -- GenericServer Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $ require 'thread' require 'socket' require 'timeout' require 'webrick/config' require 'webrick/log' module WEBrick class ServerError < StandardError; end class SimpleServer def SimpleServer.start yield end end class Daemon def Daemon.start exit!(0) if fork Process::setsid exit!(0) if fork Dir::chdir("/") File::umask(0) STDIN.reopen("/dev/null") STDOUT.reopen("/dev/null", "w") STDERR.reopen("/dev/null", "w") yield if block_given? end end class GenericServer attr_reader :status, :config, :logger, :tokens, :listeners def initialize(config={}, default=Config::General) @config = default.dup.update(config) @status = :Stop @config[:Logger] ||= Log::new @logger = @config[:Logger] @tokens = SizedQueue.new(@config[:MaxClients]) @config[:MaxClients].times{ @tokens.push(nil) } webrickv = WEBrick::VERSION rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]" @logger.info("WEBrick #{webrickv}") @logger.info("ruby #{rubyv}") @listeners = [] unless @config[:DoNotListen] if @config[:Listen] warn(":Listen option is deprecated; use GenericServer#listen") end listen(@config[:BindAddress], @config[:Port]) if @config[:Port] == 0 @config[:Port] = @listeners[0].addr[1] end end end def [](key) @config[key] end def listen(address, port) @listeners += Utils::create_listeners(address, port, @logger) end def start(&block) raise ServerError, "already started." if @status != :Stop server_type = @config[:ServerType] || SimpleServer server_type.start{ @logger.info \ "#{self.class}#start: pid=#{$$} port=#{@config[:Port]}" call_callback(:StartCallback) thgroup = ThreadGroup.new @status = :Running while @status == :Running begin if svrs = IO.select(@listeners, nil, nil, 2.0) svrs[0].each{|svr| @tokens.pop # blocks while no token is there. if sock = accept_client(svr) th = start_thread(sock, &block) th[:WEBrickThread] = true thgroup.add(th) else @tokens.push(nil) end } end rescue Errno::EBADF, IOError => ex # if the listening socket was closed in GenericServer#shutdown, # IO::select raise it. rescue Exception => ex msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}" @logger.error msg end end @logger.info "going to shutdown ..." thgroup.list.each{|th| th.join if th[:WEBrickThread] } call_callback(:StopCallback) @logger.info "#{self.class}#start done." @status = :Stop } end def stop if @status == :Running @status = :Shutdown end end def shutdown stop @listeners.each{|s| if @logger.debug? addr = s.addr @logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})") end s.close } @listeners.clear end def run(sock) @logger.fatal "run() must be provided by user." end private def accept_client(svr) sock = nil begin sock = svr.accept sock.sync = true Utils::set_non_blocking(sock) Utils::set_close_on_exec(sock) rescue Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPROTO => ex # TCP connection was established but RST segment was sent # from peer before calling TCPServer#accept. rescue Exception => ex msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}" @logger.error msg end return sock end def start_thread(sock, &block) Thread.start{ begin Thread.current[:WEBrickSocket] = sock begin addr = sock.peeraddr @logger.debug "accept: #{addr[3]}:#{addr[1]}" rescue SocketError @logger.debug "accept:
    " raise end call_callback(:AcceptCallback, sock) block ? block.call(sock) : run(sock) rescue Errno::ENOTCONN @logger.debug "Errno::ENOTCONN raised" rescue ServerError => ex msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}" @logger.error msg rescue Exception => ex @logger.error ex ensure @tokens.push(nil) Thread.current[:WEBrickSocket] = nil if addr @logger.debug "close: #{addr[3]}:#{addr[1]}" else @logger.debug "close:
    " end sock.close end } end def call_callback(callback_name, *args) if cb = @config[callback_name] cb.call(*args) end end end # end of GenericServer end PK|]~webrick/httpproxy.rbnu[# # httpproxy.rb -- HTTPProxy Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2002 GOTO Kentaro # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpproxy.rb,v 1.18 2003/03/08 18:58:10 gotoyuzo Exp $ # $kNotwork: straw.rb,v 1.3 2002/02/12 15:13:07 gotoken Exp $ require "webrick/httpserver" require "net/http" Net::HTTP::version_1_2 if RUBY_VERSION < "1.7" module WEBrick NullReader = Object.new class << NullReader def read(*args) nil end alias gets read end class HTTPProxyServer < HTTPServer def initialize(config) super c = @config @via = "#{c[:HTTPVersion]} #{c[:ServerName]}:#{c[:Port]}" end def service(req, res) if req.request_method == "CONNECT" proxy_connect(req, res) elsif req.unparsed_uri =~ %r!^http://! proxy_service(req, res) else super(req, res) end end def proxy_auth(req, res) if proc = @config[:ProxyAuthProc] proc.call(req, res) end req.header.delete("proxy-authorization") end # Some header fields should not be transferred. HopByHop = %w( connection keep-alive proxy-authenticate upgrade proxy-authorization te trailers transfer-encoding ) ShouldNotTransfer = %w( set-cookie proxy-connection ) def split_field(f) f ? f.split(/,\s+/).collect{|i| i.downcase } : [] end def choose_header(src, dst) connections = split_field(src['connection']) src.each{|key, value| key = key.downcase if HopByHop.member?(key) || # RFC2616: 13.5.1 connections.member?(key) || # RFC2616: 14.10 ShouldNotTransfer.member?(key) # pragmatics @logger.debug("choose_header: `#{key}: #{value}'") next end dst[key] = value } end # Net::HTTP is stupid about the multiple header fields. # Here is workaround: def set_cookie(src, dst) if str = src['set-cookie'] cookies = [] str.split(/,\s*/).each{|token| if /^[^=]+;/o =~ token cookies[-1] << ", " << token elsif /=/o =~ token cookies << token else cookies[-1] << ", " << token end } dst.cookies.replace(cookies) end end def set_via(h) if @config[:ProxyVia] if h['via'] h['via'] << ", " << @via else h['via'] = @via end end end def proxy_uri(req, res) @config[:ProxyURI] end def proxy_service(req, res) # Proxy Authentication proxy_auth(req, res) # Create Request-URI to send to the origin server uri = req.request_uri path = uri.path.dup path << "?" << uri.query if uri.query # Choose header fields to transfer header = Hash.new choose_header(req, header) set_via(header) # select upstream proxy server if proxy = proxy_uri(req, res) proxy_host = proxy.host proxy_port = proxy.port if proxy.userinfo credentials = "Basic " + [proxy.userinfo].pack("m*") credentials.chomp! header['proxy-authorization'] = credentials end end response = nil begin http = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port) http.start{ if @config[:ProxyTimeout] ################################## these issues are http.open_timeout = 30 # secs # necessary (maybe bacause http.read_timeout = 60 # secs # Ruby's bug, but why?) ################################## end case req.request_method when "GET" then response = http.get(path, header) when "POST" then response = http.post(path, req.body || "", header) when "HEAD" then response = http.head(path, header) else raise HTTPStatus::MethodNotAllowed, "unsupported method `#{req.request_method}'." end } rescue => err logger.debug("#{err.class}: #{err.message}") raise HTTPStatus::ServiceUnavailable, err.message end # Persistent connction requirements are mysterious for me. # So I will close the connection in every response. res['proxy-connection'] = "close" res['connection'] = "close" # Convert Net::HTTP::HTTPResponse to WEBrick::HTTPProxy res.status = response.code.to_i choose_header(response, res) set_cookie(response, res) set_via(res) res.body = response.body # Process contents if handler = @config[:ProxyContentHandler] handler.call(req, res) end end def proxy_connect(req, res) # Proxy Authentication proxy_auth(req, res) ua = Thread.current[:WEBrickSocket] # User-Agent raise HTTPStatus::InternalServerError, "[BUG] cannot get socket" unless ua host, port = req.unparsed_uri.split(":", 2) # Proxy authentication for upstream proxy server if proxy = proxy_uri(req, res) proxy_request_line = "CONNECT #{host}:#{port} HTTP/1.0" if proxy.userinfo credentials = "Basic " + [proxy.userinfo].pack("m*") credentials.chomp! end host, port = proxy.host, proxy.port end begin @logger.debug("CONNECT: upstream proxy is `#{host}:#{port}'.") os = TCPSocket.new(host, port) # origin server if proxy @logger.debug("CONNECT: sending a Request-Line") os << proxy_request_line << CRLF @logger.debug("CONNECT: > #{proxy_request_line}") if credentials @logger.debug("CONNECT: sending a credentials") os << "Proxy-Authorization: " << credentials << CRLF end os << CRLF proxy_status_line = os.gets(LF) @logger.debug("CONNECT: read a Status-Line form the upstream server") @logger.debug("CONNECT: < #{proxy_status_line}") if %r{^HTTP/\d+\.\d+\s+200\s*} =~ proxy_status_line while line = os.gets(LF) break if /\A(#{CRLF}|#{LF})\z/om =~ line end else raise HTTPStatus::BadGateway end end @logger.debug("CONNECT #{host}:#{port}: succeeded") res.status = HTTPStatus::RC_OK rescue => ex @logger.debug("CONNECT #{host}:#{port}: failed `#{ex.message}'") res.set_error(ex) raise HTTPStatus::EOFError ensure if handler = @config[:ProxyContentHandler] handler.call(req, res) end res.send_response(ua) access_log(@config, req, res) # Should clear request-line not to send the sesponse twice. # see: HTTPServer#run req.parse(NullReader) rescue nil end begin while fds = IO::select([ua, os]) if fds[0].member?(ua) buf = ua.sysread(1024); @logger.debug("CONNECT: #{buf.size} byte from User-Agent") os.syswrite(buf) elsif fds[0].member?(os) buf = os.sysread(1024); @logger.debug("CONNECT: #{buf.size} byte from #{host}:#{port}") ua.syswrite(buf) end end rescue => ex os.close @logger.debug("CONNECT #{host}:#{port}: closed") end raise HTTPStatus::EOFError end def do_OPTIONS(req, res) res['allow'] = "GET,HEAD,POST,OPTIONS,CONNECT" end end end PK|]DgQ, , webrick/utils.rbnu[# # utils.rb -- Miscellaneous utilities # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: utils.rb,v 1.10 2003/02/16 22:22:54 gotoyuzo Exp $ require 'socket' require 'fcntl' begin require 'etc' rescue LoadError nil end module WEBrick module Utils def set_non_blocking(io) flag = File::NONBLOCK if defined?(Fcntl::F_GETFL) flag |= io.fcntl(Fcntl::F_GETFL) end io.fcntl(Fcntl::F_SETFL, flag) end module_function :set_non_blocking def set_close_on_exec(io) if defined?(Fcntl::FD_CLOEXEC) io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) end end module_function :set_close_on_exec def su(user) if defined?(Etc) pw = Etc.getpwnam(user) Process::initgroups(user, pw.gid) Process::Sys::setgid(pw.gid) Process::Sys::setuid(pw.uid) else warn("WEBrick::Utils::su doesn't work on this platform") end end module_function :su def getservername host = Socket::gethostname begin Socket::gethostbyname(host)[0] rescue host end end module_function :getservername def create_listeners(address, port, logger=nil) unless port raise ArgumentError, "must specify port" end res = Socket::getaddrinfo(address, port, Socket::AF_UNSPEC, # address family Socket::SOCK_STREAM, # socket type 0, # protocol Socket::AI_PASSIVE) # flag last_error = nil sockets = [] res.each{|ai| begin logger.debug("TCPServer.new(#{ai[3]}, #{port})") if logger sock = TCPServer.new(ai[3], port) port = sock.addr[1] if port == 0 Utils::set_close_on_exec(sock) sockets << sock rescue => ex logger.warn("TCPServer Error: #{ex}") if logger last_error = ex end } raise last_error if sockets.empty? return sockets end module_function :create_listeners RAND_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "abcdefghijklmnopqrstuvwxyz" def random_string(len) rand_max = RAND_CHARS.size ret = "" len.times{ ret << RAND_CHARS[rand(rand_max)] } ret end module_function :random_string end end PK|]!Gwebrick/httpserver.rbnu[# # httpserver.rb -- HTTPServer Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpserver.rb,v 1.63 2002/10/01 17:16:32 gotoyuzo Exp $ require 'webrick/server' require 'webrick/httputils' require 'webrick/httpstatus' require 'webrick/httprequest' require 'webrick/httpresponse' require 'webrick/httpservlet' require 'webrick/accesslog' module WEBrick class HTTPServerError < ServerError; end class HTTPServer < ::WEBrick::GenericServer def initialize(config={}, default=Config::HTTP) super @http_version = HTTPVersion::convert(@config[:HTTPVersion]) @mount_tab = MountTable.new if @config[:DocumentRoot] mount("/", HTTPServlet::FileHandler, @config[:DocumentRoot], @config[:DocumentRootOptions]) end unless @config[:AccessLog] @config[:AccessLog] = [ [ $stderr, AccessLog::COMMON_LOG_FORMAT ], [ $stderr, AccessLog::REFERER_LOG_FORMAT ] ] end @virtual_hosts = Array.new end def run(sock) while true res = HTTPResponse.new(@config) req = HTTPRequest.new(@config) server = self begin timeout = @config[:RequestTimeout] while timeout > 0 break if IO.select([sock], nil, nil, 0.5) timeout = 0 if @status != :Running timeout -= 0.5 end raise HTTPStatus::EOFError if timeout <= 0 || sock.eof? req.parse(sock) res.request_method = req.request_method res.request_uri = req.request_uri res.request_http_version = req.http_version res.keep_alive = req.keep_alive? server = lookup_server(req) || self if callback = server[:RequestCallback] || server[:RequestHandler] callback.call(req, res) end server.service(req, res) rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex res.set_error(ex) rescue HTTPStatus::Error => ex @logger.error(ex.message) res.set_error(ex) rescue HTTPStatus::Status => ex res.status = ex.code rescue StandardError => ex @logger.error(ex) res.set_error(ex, true) ensure if req.request_line req.fixup() res.send_response(sock) server.access_log(@config, req, res) end end break if @http_version < "1.1" break unless req.keep_alive? break unless res.keep_alive? end end def service(req, res) if req.unparsed_uri == "*" if req.request_method == "OPTIONS" do_OPTIONS(req, res) raise HTTPStatus::OK end raise HTTPStatus::NotFound, "`#{req.unparsed_uri}' not found." end servlet, options, script_name, path_info = search_servlet(req.path) raise HTTPStatus::NotFound, "`#{req.path}' not found." unless servlet req.script_name = script_name req.path_info = path_info si = servlet.get_instance(self, *options) @logger.debug(format("%s is invoked.", si.class.name)) si.service(req, res) end def do_OPTIONS(req, res) res["allow"] = "GET,HEAD,POST,OPTIONS" end def mount(dir, servlet, *options) @logger.debug(sprintf("%s is mounted on %s.", servlet.inspect, dir)) @mount_tab[dir] = [ servlet, options ] end def mount_proc(dir, proc=nil, &block) proc ||= block raise HTTPServerError, "must pass a proc or block" unless proc mount(dir, HTTPServlet::ProcHandler.new(proc)) end def unmount(dir) @logger.debug(sprintf("unmount %s.", dir)) @mount_tab.delete(dir) end alias umount unmount def search_servlet(path) script_name, path_info = @mount_tab.scan(path) servlet, options = @mount_tab[script_name] if servlet [ servlet, options, script_name, path_info ] end end def virtual_host(server) @virtual_hosts << server @virtual_hosts = @virtual_hosts.sort_by{|s| num = 0 num -= 4 if s[:BindAddress] num -= 2 if s[:Port] num -= 1 if s[:ServerName] num } end def lookup_server(req) @virtual_hosts.find{|s| (s[:BindAddress].nil? || req.addr[3] == s[:BindAddress]) && (s[:Port].nil? || req.port == s[:Port]) && ((s[:ServerName].nil? || req.host == s[:ServerName]) || (!s[:ServerAlias].nil? && s[:ServerAlias].find{|h| h === req.host})) } end def access_log(config, req, res) param = AccessLog::setup_params(config, req, res) @config[:AccessLog].each{|logger, fmt| logger << AccessLog::format(fmt+"\n", param) } end class MountTable def initialize @tab = Hash.new compile end def [](dir) dir = normalize(dir) @tab[dir] end def []=(dir, val) dir = normalize(dir) @tab[dir] = val compile val end def delete(dir) dir = normalize(dir) res = @tab.delete(dir) compile res end def scan(path) @scanner =~ path [ $&, $' ] end private def compile k = @tab.keys k.sort! k.reverse! k.collect!{|path| Regexp.escape(path) } @scanner = Regexp.new("^(" + k.join("|") +")(?=/|$)") end def normalize(dir) ret = dir ? dir.dup : "" ret.sub!(%r|/+$|, "") ret end end end end PK|]W''webrick/httputils.rbnu[# # httputils.rb -- HTTPUtils Module # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httputils.rb,v 1.34 2003/06/05 21:34:08 gotoyuzo Exp $ require 'socket' require 'tempfile' module WEBrick CR = "\x0d" LF = "\x0a" CRLF = "\x0d\x0a" module HTTPUtils def normalize_path(path) raise "abnormal path `#{path}'" if path[0] != ?/ ret = path.dup ret.gsub!(%r{/+}o, '/') # // => / while ret.sub!(%r'/\.(?:/|\Z)', '/'); end # /. => / while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo raise "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret ret end module_function :normalize_path ##### DefaultMimeTypes = { "ai" => "application/postscript", "asc" => "text/plain", "avi" => "video/x-msvideo", "bin" => "application/octet-stream", "bmp" => "image/bmp", "class" => "application/octet-stream", "cer" => "application/pkix-cert", "crl" => "application/pkix-crl", "crt" => "application/x-x509-ca-cert", #"crl" => "application/x-pkcs7-crl", "css" => "text/css", "dms" => "application/octet-stream", "doc" => "application/msword", "dvi" => "application/x-dvi", "eps" => "application/postscript", "etx" => "text/x-setext", "exe" => "application/octet-stream", "gif" => "image/gif", "htm" => "text/html", "html" => "text/html", "jpe" => "image/jpeg", "jpeg" => "image/jpeg", "jpg" => "image/jpeg", "lha" => "application/octet-stream", "lzh" => "application/octet-stream", "mov" => "video/quicktime", "mpe" => "video/mpeg", "mpeg" => "video/mpeg", "mpg" => "video/mpeg", "pbm" => "image/x-portable-bitmap", "pdf" => "application/pdf", "pgm" => "image/x-portable-graymap", "png" => "image/png", "pnm" => "image/x-portable-anymap", "ppm" => "image/x-portable-pixmap", "ppt" => "application/vnd.ms-powerpoint", "ps" => "application/postscript", "qt" => "video/quicktime", "ras" => "image/x-cmu-raster", "rb" => "text/plain", "rd" => "text/plain", "rtf" => "application/rtf", "sgm" => "text/sgml", "sgml" => "text/sgml", "tif" => "image/tiff", "tiff" => "image/tiff", "txt" => "text/plain", "xbm" => "image/x-xbitmap", "xls" => "application/vnd.ms-excel", "xml" => "text/xml", "xpm" => "image/x-xpixmap", "xwd" => "image/x-xwindowdump", "zip" => "application/zip", } # Load Apache compatible mime.types file. def load_mime_types(file) open(file){ |io| hash = Hash.new io.each{ |line| next if /^#/ =~ line line.chomp! mimetype, ext0 = line.split(/\s+/, 2) next unless ext0 next if ext0.empty? ext0.split(/\s+/).each{ |ext| hash[ext] = mimetype } } hash } end module_function :load_mime_types def mime_type(filename, mime_tab) suffix1 = (/\.(\w+)$/ =~ filename && $1.downcase) suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ filename && $1.downcase) mime_tab[suffix1] || mime_tab[suffix2] || "application/octet-stream" end module_function :mime_type ##### def parse_header(raw) header = Hash.new([].freeze) field = nil raw.each{|line| case line when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):\s*(.*?)\s*\z/om field, value = $1, $2 field.downcase! header[field] = [] unless header.has_key?(field) header[field] << value when /^\s+(.*?)\s*\z/om value = $1 unless field raise HTTPStatus::BadRequest, "bad header '#{line}'." end header[field][-1] << " " << value else raise HTTPStatus::BadRequest, "bad header '#{line}'." end } header.each{|key, values| values.each{|value| value.strip! value.gsub!(/\s+/, " ") } } header end module_function :parse_header def split_header_value(str) str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+) (?:,\s*|\Z)'xn).flatten end module_function :split_header_value def parse_range_header(ranges_specifier) if /^bytes=(.*)/ =~ ranges_specifier byte_range_set = split_header_value($1) byte_range_set.collect{|range_spec| case range_spec when /^(\d+)-(\d+)/ then $1.to_i .. $2.to_i when /^(\d+)-/ then $1.to_i .. -1 when /^-(\d+)/ then -($1.to_i) .. -1 else return nil end } end end module_function :parse_range_header def parse_qvalues(value) tmp = [] if value parts = value.split(/,\s*/) parts.each {|part| if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) val = m[1] q = (m[2] or 1).to_f tmp.push([val, q]) end } tmp = tmp.sort_by{|val, q| -q} tmp.collect!{|val, q| val} end return tmp end module_function :parse_qvalues ##### def dequote(str) ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup ret.gsub!(/\\(.)/, "\\1") ret end module_function :dequote def quote(str) '"' << str.gsub(/[\\\"]/o, "\\\1") << '"' end module_function :quote ##### class FormData < String EmptyRawHeader = [].freeze EmptyHeader = {}.freeze attr_accessor :name, :filename, :next_data protected :next_data def initialize(*args) @name = @filename = @next_data = nil if args.empty? @raw_header = [] @header = nil super("") else @raw_header = EmptyRawHeader @header = EmptyHeader super(args.shift) unless args.empty? @next_data = self.class.new(*args) end end end def [](*key) begin @header[key[0].downcase].join(", ") rescue StandardError, NameError super end end def <<(str) if @header super elsif str == CRLF @header = HTTPUtils::parse_header(@raw_header) if cd = self['content-disposition'] if /\s+name="(.*?)"/ =~ cd then @name = $1 end if /\s+filename="(.*?)"/ =~ cd then @filename = $1 end end else @raw_header << str end self end def append_data(data) tmp = self while tmp unless tmp.next_data tmp.next_data = data break end tmp = tmp.next_data end self end def each_data tmp = self while tmp next_data = tmp.next_data yield(tmp) tmp = next_data end end def list ret = [] each_data{|data| ret << data.to_s } ret end alias :to_ary :list def to_s String.new(self) end end def parse_query(str) query = Hash.new if str str.split(/[&;]/).each{|x| next if x.empty? key, val = x.split(/=/,2) key = unescape_form(key) val = unescape_form(val.to_s) val = FormData.new(val) val.name = key if query.has_key?(key) query[key].append_data(val) next end query[key] = val } end query end module_function :parse_query def parse_form_data(io, boundary) boundary_regexp = /\A--#{boundary}(--)?#{CRLF}\z/ form_data = Hash.new return form_data unless io data = nil io.each{|line| if boundary_regexp =~ line if data data.chop! key = data.name if form_data.has_key?(key) form_data[key].append_data(data) else form_data[key] = data end end data = FormData.new next else if data data << line end end } return form_data end module_function :parse_form_data ##### reserved = ';/?:@&=+$,' num = '0123456789' lowalpha = 'abcdefghijklmnopqrstuvwxyz' upalpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' mark = '-_.!~*\'()' unreserved = num + lowalpha + upalpha + mark control = (0x0..0x1f).collect{|c| c.chr }.join + "\x7f" space = " " delims = '<>#%"' unwise = '{}|\\^[]`' nonascii = (0x80..0xff).collect{|c| c.chr }.join module_function def _make_regex(str) /([#{Regexp.escape(str)}])/n end def _make_regex!(str) /([^#{Regexp.escape(str)}])/n end def _escape(str, regex) str.gsub(regex){ "%%%02X" % $1[0] } end def _unescape(str, regex) str.gsub(regex){ $1.hex.chr } end UNESCAPED = _make_regex(control+space+delims+unwise+nonascii) UNESCAPED_FORM = _make_regex(reserved+control+delims+unwise+nonascii) NONASCII = _make_regex(nonascii) ESCAPED = /%([0-9a-fA-F]{2})/ UNESCAPED_PCHAR = _make_regex!(unreserved+":@&=+$,") def escape(str) _escape(str, UNESCAPED) end def unescape(str) _unescape(str, ESCAPED) end def escape_form(str) ret = _escape(str, UNESCAPED_FORM) ret.gsub!(/ /, "+") ret end def unescape_form(str) _unescape(str.gsub(/\+/, " "), ESCAPED) end def escape_path(str) result = "" str.scan(%r{/([^/]*)}).each{|i| result << "/" << _escape(i[0], UNESCAPED_PCHAR) } return result end def escape8bit(str) _escape(str, NONASCII) end end end PK|] t8webrick/ssl.rbnu[# # ssl.rb -- SSL/TLS enhancement for GenericServer # # Copyright (c) 2003 GOTOU Yuuzou All rights reserved. # # $Id: ssl.rb 29858 2010-11-22 07:21:52Z shyouhei $ require 'webrick' require 'openssl' module WEBrick module Config svrsoft = General[:ServerSoftware] osslv = ::OpenSSL::OPENSSL_VERSION.split[1] SSL = { :ServerSoftware => "#{svrsoft} OpenSSL/#{osslv}", :SSLEnable => false, :SSLCertificate => nil, :SSLPrivateKey => nil, :SSLClientCA => nil, :SSLExtraChainCert => nil, :SSLCACertificateFile => nil, :SSLCACertificatePath => nil, :SSLCertificateStore => nil, :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE, :SSLVerifyDepth => nil, :SSLVerifyCallback => nil, # custom verification :SSLTimeout => nil, :SSLOptions => nil, :SSLStartImmediately => true, # Must specify if you use auto generated certificate. :SSLCertName => nil, :SSLCertComment => "Generated by Ruby/OpenSSL" } General.update(SSL) end module Utils def create_self_signed_cert(bits, cn, comment) rsa = OpenSSL::PKey::RSA.new(bits){|p, n| case p when 0; $stderr.putc "." # BN_generate_prime when 1; $stderr.putc "+" # BN_generate_prime when 2; $stderr.putc "*" # searching good prime, # n = #of try, # but also data from BN_generate_prime when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q, # but also data from BN_generate_prime else; $stderr.putc "*" # BN_generate_prime end } cert = OpenSSL::X509::Certificate.new cert.version = 2 cert.serial = 1 name = OpenSSL::X509::Name.new(cn) cert.subject = name cert.issuer = name cert.not_before = Time.now cert.not_after = Time.now + (365*24*60*60) cert.public_key = rsa.public_key ef = OpenSSL::X509::ExtensionFactory.new(nil,cert) ef.issuer_certificate = cert cert.extensions = [ ef.create_extension("basicConstraints","CA:FALSE"), ef.create_extension("keyUsage", "keyEncipherment"), ef.create_extension("subjectKeyIdentifier", "hash"), ef.create_extension("extendedKeyUsage", "serverAuth"), ef.create_extension("nsComment", comment), ] aki = ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") cert.add_extension(aki) cert.sign(rsa, OpenSSL::Digest::SHA1.new) return [ cert, rsa ] end module_function :create_self_signed_cert end class GenericServer def ssl_context @ssl_context ||= nil end def listen(address, port) listeners = Utils::create_listeners(address, port, @logger) if @config[:SSLEnable] unless ssl_context @ssl_context = setup_ssl_context(@config) @logger.info("\n" + @config[:SSLCertificate].to_text) end listeners.collect!{|svr| ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context) ssvr.start_immediately = @config[:SSLStartImmediately] ssvr } end @listeners += listeners end def setup_ssl_context(config) unless config[:SSLCertificate] cn = config[:SSLCertName] comment = config[:SSLCertComment] cert, key = Utils::create_self_signed_cert(1024, cn, comment) config[:SSLCertificate] = cert config[:SSLPrivateKey] = key end ctx = OpenSSL::SSL::SSLContext.new ctx.key = config[:SSLPrivateKey] ctx.cert = config[:SSLCertificate] ctx.client_ca = config[:SSLClientCA] ctx.extra_chain_cert = config[:SSLExtraChainCert] ctx.ca_file = config[:SSLCACertificateFile] ctx.ca_path = config[:SSLCACertificatePath] ctx.cert_store = config[:SSLCertificateStore] ctx.verify_mode = config[:SSLVerifyClient] ctx.verify_depth = config[:SSLVerifyDepth] ctx.verify_callback = config[:SSLVerifyCallback] ctx.timeout = config[:SSLTimeout] ctx.options = config[:SSLOptions] ctx end end end PK|]O-webrick/accesslog.rbnu[# # accesslog.rb -- Access log handling utilities # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2002 keita yamaguchi # Copyright (c) 2002 Internet Programming with Ruby writers # # $IPR: accesslog.rb,v 1.1 2002/10/01 17:16:32 gotoyuzo Exp $ module WEBrick module AccessLog class AccessLogError < StandardError; end CLF_TIME_FORMAT = "[%d/%b/%Y:%H:%M:%S %Z]" COMMON_LOG_FORMAT = "%h %l %u %t \"%r\" %s %b" CLF = COMMON_LOG_FORMAT REFERER_LOG_FORMAT = "%{Referer}i -> %U" AGENT_LOG_FORMAT = "%{User-Agent}i" COMBINED_LOG_FORMAT = "#{CLF} \"%{Referer}i\" \"%{User-agent}i\"" module_function # This format specification is a subset of mod_log_config of Apache. # http://httpd.apache.org/docs/mod/mod_log_config.html#formats def setup_params(config, req, res) params = Hash.new("") params["a"] = req.peeraddr[3] params["b"] = res.sent_size params["e"] = ENV params["f"] = res.filename || "" params["h"] = req.peeraddr[2] params["i"] = req params["l"] = "-" params["m"] = req.request_method params["n"] = req.attributes params["o"] = res params["p"] = req.port params["q"] = req.query_string params["r"] = req.request_line.sub(/\x0d?\x0a\z/o, '') params["s"] = res.status # won't support "%>s" params["t"] = req.request_time params["T"] = Time.now - req.request_time params["u"] = req.user || "-" params["U"] = req.unparsed_uri params["v"] = config[:ServerName] params end def format(format_string, params) format_string.gsub(/\%(?:\{(.*?)\})?>?([a-zA-Z%])/){ param, spec = $1, $2 case spec[0] when ?e, ?i, ?n, ?o raise AccessLogError, "parameter is required for \"#{spec}\"" unless param (param = params[spec][param]) ? escape(param) : "-" when ?t params[spec].strftime(param || CLF_TIME_FORMAT) when ?% "%" else escape(params[spec].to_s) end } end def escape(data) if data.tainted? data.gsub(/[[:cntrl:]\\]+/) {$&.dump[1...-1]}.untaint else data end end end end PK|]VLwebrick/httpauth/userdb.rbnu[# # httpauth/userdb.rb -- UserDB mix-in module. # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: userdb.rb,v 1.2 2003/02/20 07:15:48 gotoyuzo Exp $ module WEBrick module HTTPAuth module UserDB attr_accessor :auth_type # BasicAuth or DigestAuth def make_passwd(realm, user, pass) @auth_type::make_passwd(realm, user, pass) end def set_passwd(realm, user, pass) self[user] = pass end def get_passwd(realm, user, reload_db=false) # reload_db is dummy make_passwd(realm, user, self[user]) end end end end PK|]wwwebrick/httpauth/htdigest.rbnu[# # httpauth/htdigest.rb -- Apache compatible htdigest file # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: htdigest.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $ require 'webrick/httpauth/userdb' require 'webrick/httpauth/digestauth' require 'tempfile' module WEBrick module HTTPAuth class Htdigest include UserDB def initialize(path) @path = path @mtime = Time.at(0) @digest = Hash.new @mutex = Mutex::new @auth_type = DigestAuth open(@path,"a").close unless File::exist?(@path) reload end def reload mtime = File::mtime(@path) if mtime > @mtime @digest.clear open(@path){|io| while line = io.gets line.chomp! user, realm, pass = line.split(/:/, 3) unless @digest[realm] @digest[realm] = Hash.new end @digest[realm][user] = pass end } @mtime = mtime end end def flush(output=nil) output ||= @path tmp = Tempfile.new("htpasswd", File::dirname(output)) begin each{|item| tmp.puts(item.join(":")) } tmp.close File::rename(tmp.path, output) rescue tmp.close(true) end end def get_passwd(realm, user, reload_db) reload() if reload_db if hash = @digest[realm] hash[user] end end def set_passwd(realm, user, pass) @mutex.synchronize{ unless @digest[realm] @digest[realm] = Hash.new end @digest[realm][user] = make_passwd(realm, user, pass) } end def delete_passwd(realm, user) if hash = @digest[realm] hash.delete(user) end end def each @digest.keys.sort.each{|realm| hash = @digest[realm] hash.keys.sort.each{|user| yield([user, realm, hash[user]]) } } end end end end PK|]U؝mwebrick/httpauth/htpasswd.rbnu[# # httpauth/htpasswd -- Apache compatible htpasswd file # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: htpasswd.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $ require 'webrick/httpauth/userdb' require 'webrick/httpauth/basicauth' require 'tempfile' module WEBrick module HTTPAuth class Htpasswd include UserDB def initialize(path) @path = path @mtime = Time.at(0) @passwd = Hash.new @auth_type = BasicAuth open(@path,"a").close unless File::exist?(@path) reload end def reload mtime = File::mtime(@path) if mtime > @mtime @passwd.clear open(@path){|io| while line = io.gets line.chomp! case line when %r!\A[^:]+:[a-zA-Z0-9./]{13}\z! user, pass = line.split(":") when /:\$/, /:\{SHA\}/ raise NotImplementedError, 'MD5, SHA1 .htpasswd file not supported' else raise StandardError, 'bad .htpasswd file' end @passwd[user] = pass end } @mtime = mtime end end def flush(output=nil) output ||= @path tmp = Tempfile.new("htpasswd", File::dirname(output)) begin each{|item| tmp.puts(item.join(":")) } tmp.close File::rename(tmp.path, output) rescue tmp.close(true) end end def get_passwd(realm, user, reload_db) reload() if reload_db @passwd[user] end def set_passwd(realm, user, pass) @passwd[user] = make_passwd(realm, user, pass) end def delete_passwd(realm, user) @passwd.delete(user) end def each @passwd.keys.sort.each{|user| yield([user, @passwd[user]]) } end end end end PK|]x{,,webrick/httpauth/digestauth.rbnu[# # httpauth/digestauth.rb -- HTTP digest access authentication # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. # Copyright (c) 2003 H.M. # # The original implementation is provided by H.M. # URL: http://rwiki.jin.gr.jp/cgi-bin/rw-cgi.rb?cmd=view;name= # %C7%A7%BE%DA%B5%A1%C7%BD%A4%F2%B2%FE%C2%A4%A4%B7%A4%C6%A4%DF%A4%EB # # $IPR: digestauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $ require 'webrick/config' require 'webrick/httpstatus' require 'webrick/httpauth/authenticator' require 'digest/md5' require 'digest/sha1' module WEBrick module HTTPAuth class DigestAuth include Authenticator AuthScheme = "Digest" OpaqueInfo = Struct.new(:time, :nonce, :nc) attr_reader :algorithm, :qop def self.make_passwd(realm, user, pass) pass ||= "" Digest::MD5::hexdigest([user, realm, pass].join(":")) end def initialize(config, default=Config::DigestAuth) check_init(config) @config = default.dup.update(config) @algorithm = @config[:Algorithm] @domain = @config[:Domain] @qop = @config[:Qop] @use_opaque = @config[:UseOpaque] @use_next_nonce = @config[:UseNextNonce] @check_nc = @config[:CheckNc] @use_auth_info_header = @config[:UseAuthenticationInfoHeader] @nonce_expire_period = @config[:NonceExpirePeriod] @nonce_expire_delta = @config[:NonceExpireDelta] @internet_explorer_hack = @config[:InternetExplorerHack] @opera_hack = @config[:OperaHack] case @algorithm when 'MD5','MD5-sess' @h = Digest::MD5 when 'SHA1','SHA1-sess' # it is a bonus feature :-) @h = Digest::SHA1 else msg = format('Alogrithm "%s" is not supported.', @algorithm) raise ArgumentError.new(msg) end @instance_key = hexdigest(self.__id__, Time.now.to_i, Process.pid) @opaques = {} @last_nonce_expire = Time.now @mutex = Mutex.new end def authenticate(req, res) unless result = @mutex.synchronize{ _authenticate(req, res) } challenge(req, res) end if result == :nonce_is_stale challenge(req, res, true) end return true end def challenge(req, res, stale=false) nonce = generate_next_nonce(req) if @use_opaque opaque = generate_opaque(req) @opaques[opaque].nonce = nonce end param = Hash.new param["realm"] = HTTPUtils::quote(@realm) param["domain"] = HTTPUtils::quote(@domain.to_a.join(" ")) if @domain param["nonce"] = HTTPUtils::quote(nonce) param["opaque"] = HTTPUtils::quote(opaque) if opaque param["stale"] = stale.to_s param["algorithm"] = @algorithm param["qop"] = HTTPUtils::quote(@qop.to_a.join(",")) if @qop res[@response_field] = "#{@auth_scheme} " + param.map{|k,v| "#{k}=#{v}" }.join(", ") info("%s: %s", @response_field, res[@response_field]) if $DEBUG raise @auth_exception end private MustParams = ['username','realm','nonce','uri','response'] MustParamsAuth = ['cnonce','nc'] def _authenticate(req, res) unless digest_credentials = check_scheme(req) return false end auth_req = split_param_value(digest_credentials) if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int" req_params = MustParams + MustParamsAuth else req_params = MustParams end req_params.each{|key| unless auth_req.has_key?(key) error('%s: parameter missing. "%s"', auth_req['username'], key) raise HTTPStatus::BadRequest end } if !check_uri(req, auth_req) raise HTTPStatus::BadRequest end if auth_req['realm'] != @realm error('%s: realm unmatch. "%s" for "%s"', auth_req['username'], auth_req['realm'], @realm) return false end auth_req['algorithm'] ||= 'MD5' if auth_req['algorithm'] != @algorithm && (@opera_hack && auth_req['algorithm'] != @algorithm.upcase) error('%s: algorithm unmatch. "%s" for "%s"', auth_req['username'], auth_req['algorithm'], @algorithm) return false end if (@qop.nil? && auth_req.has_key?('qop')) || (@qop && (! @qop.member?(auth_req['qop']))) error('%s: the qop is not allowed. "%s"', auth_req['username'], auth_req['qop']) return false end password = @userdb.get_passwd(@realm, auth_req['username'], @reload_db) unless password error('%s: the user is not allowd.', auth_req['username']) return false end nonce_is_invalid = false if @use_opaque info("@opaque = %s", @opaque.inspect) if $DEBUG if !(opaque = auth_req['opaque']) error('%s: opaque is not given.', auth_req['username']) nonce_is_invalid = true elsif !(opaque_struct = @opaques[opaque]) error('%s: invalid opaque is given.', auth_req['username']) nonce_is_invalid = true elsif !check_opaque(opaque_struct, req, auth_req) @opaques.delete(auth_req['opaque']) nonce_is_invalid = true end elsif !check_nonce(req, auth_req) nonce_is_invalid = true end if /-sess$/ =~ auth_req['algorithm'] || (@opera_hack && /-SESS$/ =~ auth_req['algorithm']) ha1 = hexdigest(password, auth_req['nonce'], auth_req['cnonce']) else ha1 = password end if auth_req['qop'] == "auth" || auth_req['qop'] == nil ha2 = hexdigest(req.request_method, auth_req['uri']) ha2_res = hexdigest("", auth_req['uri']) elsif auth_req['qop'] == "auth-int" ha2 = hexdigest(req.request_method, auth_req['uri'], hexdigest(req.body)) ha2_res = hexdigest("", auth_req['uri'], hexdigest(res.body)) end if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int" param2 = ['nonce', 'nc', 'cnonce', 'qop'].map{|key| auth_req[key] }.join(':') digest = hexdigest(ha1, param2, ha2) digest_res = hexdigest(ha1, param2, ha2_res) else digest = hexdigest(ha1, auth_req['nonce'], ha2) digest_res = hexdigest(ha1, auth_req['nonce'], ha2_res) end if digest != auth_req['response'] error("%s: digest unmatch.", auth_req['username']) return false elsif nonce_is_invalid error('%s: digest is valid, but nonce is not valid.', auth_req['username']) return :nonce_is_stale elsif @use_auth_info_header auth_info = { 'nextnonce' => generate_next_nonce(req), 'rspauth' => digest_res } if @use_opaque opaque_struct.time = req.request_time opaque_struct.nonce = auth_info['nextnonce'] opaque_struct.nc = "%08x" % (auth_req['nc'].hex + 1) end if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int" ['qop','cnonce','nc'].each{|key| auth_info[key] = auth_req[key] } end res[@resp_info_field] = auth_info.keys.map{|key| if key == 'nc' key + '=' + auth_info[key] else key + "=" + HTTPUtils::quote(auth_info[key]) end }.join(', ') end info('%s: authentication scceeded.', auth_req['username']) req.user = auth_req['username'] return true end def split_param_value(string) ret = {} while string.size != 0 case string when /^\s*([\w\-\.\*\%\!]+)=\s*\"((\\.|[^\"])*)\"\s*,?/ key = $1 matched = $2 string = $' ret[key] = matched.gsub(/\\(.)/, "\\1") when /^\s*([\w\-\.\*\%\!]+)=\s*([^,\"]*),?/ key = $1 matched = $2 string = $' ret[key] = matched.clone when /^s*^,/ string = $' else break end end ret end def generate_next_nonce(req) now = "%012d" % req.request_time.to_i pk = hexdigest(now, @instance_key)[0,32] nonce = [now + ":" + pk].pack("m*").chop # it has 60 length of chars. nonce end def check_nonce(req, auth_req) username = auth_req['username'] nonce = auth_req['nonce'] pub_time, pk = nonce.unpack("m*")[0].split(":", 2) if (!pub_time || !pk) error("%s: empty nonce is given", username) return false elsif (hexdigest(pub_time, @instance_key)[0,32] != pk) error("%s: invalid private-key: %s for %s", username, hexdigest(pub_time, @instance_key)[0,32], pk) return false end diff_time = req.request_time.to_i - pub_time.to_i if (diff_time < 0) error("%s: difference of time-stamp is negative.", username) return false elsif diff_time > @nonce_expire_period error("%s: nonce is expired.", username) return false end return true end def generate_opaque(req) @mutex.synchronize{ now = req.request_time if now - @last_nonce_expire > @nonce_expire_delta @opaques.delete_if{|key,val| (now - val.time) > @nonce_expire_period } @last_nonce_expire = now end begin opaque = Utils::random_string(16) end while @opaques[opaque] @opaques[opaque] = OpaqueInfo.new(now, nil, '00000001') opaque } end def check_opaque(opaque_struct, req, auth_req) if (@use_next_nonce && auth_req['nonce'] != opaque_struct.nonce) error('%s: nonce unmatched. "%s" for "%s"', auth_req['username'], auth_req['nonce'], opaque_struct.nonce) return false elsif !check_nonce(req, auth_req) return false end if (@check_nc && auth_req['nc'] != opaque_struct.nc) error('%s: nc unmatched."%s" for "%s"', auth_req['username'], auth_req['nc'], opaque_struct.nc) return false end true end def check_uri(req, auth_req) uri = auth_req['uri'] if uri != req.request_uri.to_s && uri != req.unparsed_uri && (@internet_explorer_hack && uri != req.path) error('%s: uri unmatch. "%s" for "%s"', auth_req['username'], auth_req['uri'], req.request_uri.to_s) return false end true end def hexdigest(*args) @h.hexdigest(args.join(":")) end end class ProxyDigestAuth < DigestAuth include ProxyAuthenticator def check_uri(req, auth_req) return true end end end end PK|]9 E E !webrick/httpauth/authenticator.rbnu[# # httpauth/authenticator.rb -- Authenticator mix-in module. # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: authenticator.rb,v 1.3 2003/02/20 07:15:47 gotoyuzo Exp $ module WEBrick module HTTPAuth module Authenticator RequestField = "Authorization" ResponseField = "WWW-Authenticate" ResponseInfoField = "Authentication-Info" AuthException = HTTPStatus::Unauthorized AuthScheme = nil # must override by the derived class attr_reader :realm, :userdb, :logger private def check_init(config) [:UserDB, :Realm].each{|sym| unless config[sym] raise ArgumentError, "Argument #{sym.inspect} missing." end } @realm = config[:Realm] @userdb = config[:UserDB] @logger = config[:Logger] || Log::new($stderr) @reload_db = config[:AutoReloadUserDB] @request_field = self::class::RequestField @response_field = self::class::ResponseField @resp_info_field = self::class::ResponseInfoField @auth_exception = self::class::AuthException @auth_scheme = self::class::AuthScheme end def check_scheme(req) unless credentials = req[@request_field] error("no credentials in the request.") return nil end unless match = /^#{@auth_scheme}\s+/.match(credentials) error("invalid scheme in %s.", credentials) info("%s: %s", @request_field, credentials) if $DEBUG return nil end return match.post_match end def log(meth, fmt, *args) msg = format("%s %s: ", @auth_scheme, @realm) msg << fmt % args @logger.send(meth, msg) end def error(fmt, *args) if @logger.error? log(:error, fmt, *args) end end def info(fmt, *args) if @logger.info? log(:info, fmt, *args) end end end module ProxyAuthenticator RequestField = "Proxy-Authorization" ResponseField = "Proxy-Authenticate" InfoField = "Proxy-Authentication-Info" AuthException = HTTPStatus::ProxyAuthenticationRequired end end end PK|]^webrick/httpauth/basicauth.rbnu[# # httpauth/basicauth.rb -- HTTP basic access authentication # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: basicauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $ require 'webrick/config' require 'webrick/httpstatus' require 'webrick/httpauth/authenticator' module WEBrick module HTTPAuth class BasicAuth include Authenticator AuthScheme = "Basic" def self.make_passwd(realm, user, pass) pass ||= "" pass.crypt(Utils::random_string(2)) end attr_reader :realm, :userdb, :logger def initialize(config, default=Config::BasicAuth) check_init(config) @config = default.dup.update(config) end def authenticate(req, res) unless basic_credentials = check_scheme(req) challenge(req, res) end userid, password = basic_credentials.unpack("m*")[0].split(":", 2) password ||= "" if userid.empty? error("user id was not given.") challenge(req, res) end unless encpass = @userdb.get_passwd(@realm, userid, @reload_db) error("%s: the user is not allowed.", userid) challenge(req, res) end if password.crypt(encpass) != encpass error("%s: password unmatch.", userid) challenge(req, res) end info("%s: authentication succeeded.", userid) req.user = userid end def challenge(req, res) res[@response_field] = "#{@auth_scheme} realm=\"#{@realm}\"" raise @auth_exception end end class ProxyBasicAuth < BasicAuth include ProxyAuthenticator end end end PK|][webrick/httpauth/htgroup.rbnu[# # httpauth/htgroup.rb -- Apache compatible htgroup file # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: htgroup.rb,v 1.1 2003/02/16 22:22:56 gotoyuzo Exp $ require 'tempfile' module WEBrick module HTTPAuth class Htgroup def initialize(path) @path = path @mtime = Time.at(0) @group = Hash.new open(@path,"a").close unless File::exist?(@path) reload end def reload if (mtime = File::mtime(@path)) > @mtime @group.clear open(@path){|io| while line = io.gets line.chomp! group, members = line.split(/:\s*/) @group[group] = members.split(/\s+/) end } @mtime = mtime end end def flush(output=nil) output ||= @path tmp = Tempfile.new("htgroup", File::dirname(output)) begin @group.keys.sort.each{|group| tmp.puts(format("%s: %s", group, self.members(group).join(" "))) } tmp.close File::rename(tmp.path, output) rescue tmp.close(true) end end def members(group) reload @group[group] || [] end def add(group, members) @group[group] = members(group) | members end end end end PK|]-G__webrick/version.rbnu[# # version.rb -- version and release date # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: version.rb,v 1.74 2003/07/22 19:20:43 gotoyuzo Exp $ module WEBrick VERSION = "1.3.1" end PK|]F! ! webrick/cookie.rbnu[# # cookie.rb -- Cookie class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: cookie.rb,v 1.16 2002/09/21 12:23:35 gotoyuzo Exp $ require 'time' require 'webrick/httputils' module WEBrick class Cookie attr_reader :name attr_accessor :value, :version attr_accessor :domain, :path, :secure attr_accessor :comment, :max_age #attr_accessor :comment_url, :discard, :port def initialize(name, value) @name = name @value = value @version = 0 # Netscape Cookie @domain = @path = @secure = @comment = @max_age = @expires = @comment_url = @discard = @port = nil end def expires=(t) @expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s) end def expires @expires && Time.parse(@expires) end def to_s ret = "" ret << @name << "=" << @value ret << "; " << "Version=" << @version.to_s if @version > 0 ret << "; " << "Domain=" << @domain if @domain ret << "; " << "Expires=" << @expires if @expires ret << "; " << "Max-Age=" << @max_age.to_s if @max_age ret << "; " << "Comment=" << @comment if @comment ret << "; " << "Path=" << @path if @path ret << "; " << "Secure" if @secure ret end # Cookie::parse() # It parses Cookie field sent from the user agent. def self.parse(str) if str ret = [] cookie = nil ver = 0 str.split(/[;,]\s+/).each{|x| key, val = x.split(/=/,2) val = val ? HTTPUtils::dequote(val) : "" case key when "$Version"; ver = val.to_i when "$Path"; cookie.path = val when "$Domain"; cookie.domain = val when "$Port"; cookie.port = val else ret << cookie if cookie cookie = self.new(key, val) cookie.version = ver end } ret << cookie if cookie ret end end def self.parse_set_cookie(str) cookie_elem = str.split(/;/) first_elem = cookie_elem.shift first_elem.strip! key, value = first_elem.split(/=/, 2) cookie = new(key, HTTPUtils.dequote(value)) cookie_elem.each{|pair| pair.strip! key, value = pair.split(/=/, 2) if value value = HTTPUtils.dequote(value.strip) end case key.downcase when "domain" then cookie.domain = value when "path" then cookie.path = value when "expires" then cookie.expires = value when "max-age" then cookie.max_age = Integer(value) when "comment" then cookie.comment = value when "version" then cookie.version = Integer(value) when "secure" then cookie.secure = true end } return cookie end def self.parse_set_cookies(str) return str.split(/,(?=[^;,]*=)|,$/).collect{|c| parse_set_cookie(c) } end end end PK|]بj##webrick/log.rbnu[# # log.rb -- Log Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: log.rb,v 1.26 2002/10/06 17:06:10 gotoyuzo Exp $ module WEBrick class BasicLog # log-level constant FATAL, ERROR, WARN, INFO, DEBUG = 1, 2, 3, 4, 5 attr_accessor :level def initialize(log_file=nil, level=nil) @level = level || INFO case log_file when String @log = open(log_file, "a+") @log.sync = true @opened = true when NilClass @log = $stderr else @log = log_file # requires "<<". (see BasicLog#log) end end def close @log.close if @opened @log = nil end def log(level, data) if @log && level <= @level data += "\n" if /\n\Z/ !~ data @log << data end end def <<(obj) log(INFO, obj.to_s) end def fatal(msg) log(FATAL, "FATAL " << format(msg)); end def error(msg) log(ERROR, "ERROR " << format(msg)); end def warn(msg) log(WARN, "WARN " << format(msg)); end def info(msg) log(INFO, "INFO " << format(msg)); end def debug(msg) log(DEBUG, "DEBUG " << format(msg)); end def fatal?; @level >= FATAL; end def error?; @level >= ERROR; end def warn?; @level >= WARN; end def info?; @level >= INFO; end def debug?; @level >= DEBUG; end private def format(arg) str = if arg.is_a?(Exception) "#{arg.class}: #{arg.message}\n\t" << arg.backtrace.join("\n\t") << "\n" elsif arg.respond_to?(:to_str) arg.to_str else arg.inspect end end end class Log < BasicLog attr_accessor :time_format def initialize(log_file=nil, level=nil) super(log_file, level) @time_format = "[%Y-%m-%d %H:%M:%S]" end def log(level, data) tmp = Time.now.strftime(@time_format) tmp << " " << data super(level, tmp) end end end PK|]2webrick/httpresponse.rbnu[# # httpresponse.rb -- HTTPResponse Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $ require 'time' require 'webrick/httpversion' require 'webrick/htmlutils' require 'webrick/httputils' require 'webrick/httpstatus' module WEBrick class HTTPResponse BUFSIZE = 1024*4 attr_reader :http_version, :status, :header attr_reader :cookies attr_accessor :reason_phrase attr_accessor :body attr_accessor :request_method, :request_uri, :request_http_version attr_accessor :filename attr_accessor :keep_alive attr_reader :config, :sent_size def initialize(config) @config = config @logger = config[:Logger] @header = Hash.new @status = HTTPStatus::RC_OK @reason_phrase = nil @http_version = HTTPVersion::convert(@config[:HTTPVersion]) @body = '' @keep_alive = true @cookies = [] @request_method = nil @request_uri = nil @request_http_version = @http_version # temporary @chunked = false @filename = nil @sent_size = 0 end def status_line "HTTP/#@http_version #@status #@reason_phrase #{CRLF}" end def status=(status) @status = status @reason_phrase = HTTPStatus::reason_phrase(status) end def [](field) @header[field.downcase] end def []=(field, value) @header[field.downcase] = value.to_s end def content_length if len = self['content-length'] return Integer(len) end end def content_length=(len) self['content-length'] = len.to_s end def content_type self['content-type'] end def content_type=(type) self['content-type'] = type end def each @header.each{|k, v| yield(k, v) } end def chunked? @chunked end def chunked=(val) @chunked = val ? true : false end def keep_alive? @keep_alive end def send_response(socket) begin setup_header() send_header(socket) send_body(socket) rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN => ex @logger.debug(ex) @keep_alive = false rescue Exception => ex @logger.error(ex) @keep_alive = false end end def setup_header() @reason_phrase ||= HTTPStatus::reason_phrase(@status) @header['server'] ||= @config[:ServerSoftware] @header['date'] ||= Time.now.httpdate # HTTP/0.9 features if @request_http_version < "1.0" @http_version = HTTPVersion.new("0.9") @keep_alive = false end # HTTP/1.0 features if @request_http_version < "1.1" if chunked? @chunked = false ver = @request_http_version.to_s msg = "chunked is set for an HTTP/#{ver} request. (ignored)" @logger.warn(msg) end end # Determine the message length (RFC2616 -- 4.4 Message Length) if @status == 304 || @status == 204 || HTTPStatus::info?(@status) @header.delete('content-length') @body = "" elsif chunked? @header["transfer-encoding"] = "chunked" @header.delete('content-length') elsif %r{^multipart/byteranges} =~ @header['content-type'] @header.delete('content-length') elsif @header['content-length'].nil? unless @body.is_a?(IO) @header['content-length'] = @body ? @body.size : 0 end end # Keep-Alive connection. if @header['connection'] == "close" @keep_alive = false elsif keep_alive? if chunked? || @header['content-length'] @header['connection'] = "Keep-Alive" end else @header['connection'] = "close" end # Location is a single absoluteURI. if location = @header['location'] if @request_uri @header['location'] = @request_uri.merge(location) end end end def send_header(socket) if @http_version.major > 0 data = status_line() @header.each{|key, value| tmp = key.gsub(/\bwww|^te$|\b\w/){|s| s.upcase } data << "#{tmp}: #{value}" << CRLF } @cookies.each{|cookie| data << "Set-Cookie: " << cookie.to_s << CRLF } data << CRLF _write_data(socket, data) end end def send_body(socket) case @body when IO then send_body_io(socket) else send_body_string(socket) end end def to_s ret = "" send_response(ret) ret end def set_redirect(status, url) @body = "#{url.to_s}.\n" @header['location'] = url.to_s raise status end def set_error(ex, backtrace=false) case ex when HTTPStatus::Status @keep_alive = false if HTTPStatus::error?(ex.code) self.status = ex.code else @keep_alive = false self.status = HTTPStatus::RC_INTERNAL_SERVER_ERROR end @header['content-type'] = "text/html; charset=ISO-8859-1" if respond_to?(:create_error_page) create_error_page() return end if @request_uri host, port = @request_uri.host, @request_uri.port else host, port = @config[:ServerName], @config[:Port] end @body = '' @body << <<-_end_of_html_ #{HTMLUtils::escape(@reason_phrase)}

    #{HTMLUtils::escape(@reason_phrase)}

    #{HTMLUtils::escape(ex.message)}
    _end_of_html_ if backtrace && $DEBUG @body << "backtrace of `#{HTMLUtils::escape(ex.class.to_s)}' " @body << "#{HTMLUtils::escape(ex.message)}" @body << "
    "
            ex.backtrace.each{|line| @body << "\t#{line}\n"}
            @body << "

    " end @body << <<-_end_of_html_
    #{HTMLUtils::escape(@config[:ServerSoftware])} at #{host}:#{port}
    _end_of_html_ end private def send_body_io(socket) begin if @request_method == "HEAD" # do nothing elsif chunked? while buf = @body.read(BUFSIZE) next if buf.empty? data = "" data << format("%x", buf.size) << CRLF data << buf << CRLF _write_data(socket, data) @sent_size += buf.size end _write_data(socket, "0#{CRLF}#{CRLF}") else size = @header['content-length'].to_i _send_file(socket, @body, 0, size) @sent_size = size end ensure @body.close end end def send_body_string(socket) if @request_method == "HEAD" # do nothing elsif chunked? remain = body ? @body.size : 0 while buf = @body[@sent_size, BUFSIZE] break if buf.empty? data = "" data << format("%x", buf.size) << CRLF data << buf << CRLF _write_data(socket, data) @sent_size += buf.size end _write_data(socket, "0#{CRLF}#{CRLF}") else if @body && @body.size > 0 _write_data(socket, @body) @sent_size = @body.size end end end def _send_file(output, input, offset, size) while offset > 0 sz = BUFSIZE < offset ? BUFSIZE : offset buf = input.read(sz) offset -= buf.size end if size == 0 while buf = input.read(BUFSIZE) _write_data(output, buf) end else while size > 0 sz = BUFSIZE < size ? BUFSIZE : size buf = input.read(sz) _write_data(output, buf) size -= buf.size end end end def _write_data(socket, data) socket << data end end end PK|]buM''webrick/httprequest.rbnu[# # httprequest.rb -- HTTPRequest Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httprequest.rb,v 1.64 2003/07/13 17:18:22 gotoyuzo Exp $ require 'timeout' require 'uri' require 'webrick/httpversion' require 'webrick/httpstatus' require 'webrick/httputils' require 'webrick/cookie' module WEBrick class HTTPRequest BODY_CONTAINABLE_METHODS = [ "POST", "PUT" ] BUFSIZE = 1024*4 # Request line attr_reader :request_line attr_reader :request_method, :unparsed_uri, :http_version # Request-URI attr_reader :request_uri, :host, :port, :path attr_accessor :script_name, :path_info, :query_string # Header and entity body attr_reader :raw_header, :header, :cookies attr_reader :accept, :accept_charset attr_reader :accept_encoding, :accept_language # Misc attr_accessor :user attr_reader :addr, :peeraddr attr_reader :attributes attr_reader :keep_alive attr_reader :request_time def initialize(config) @config = config @logger = config[:Logger] @request_line = @request_method = @unparsed_uri = @http_version = nil @request_uri = @host = @port = @path = nil @script_name = @path_info = nil @query_string = nil @query = nil @form_data = nil @raw_header = Array.new @header = nil @cookies = [] @accept = [] @accept_charset = [] @accept_encoding = [] @accept_language = [] @body = "" @addr = @peeraddr = nil @attributes = {} @user = nil @keep_alive = false @request_time = nil @remaining_size = nil @socket = nil end def parse(socket=nil) @socket = socket begin @peeraddr = socket.respond_to?(:peeraddr) ? socket.peeraddr : [] @addr = socket.respond_to?(:addr) ? socket.addr : [] rescue Errno::ENOTCONN raise HTTPStatus::EOFError end read_request_line(socket) if @http_version.major > 0 read_header(socket) @header['cookie'].each{|cookie| @cookies += Cookie::parse(cookie) } @accept = HTTPUtils.parse_qvalues(self['accept']) @accept_charset = HTTPUtils.parse_qvalues(self['accept-charset']) @accept_encoding = HTTPUtils.parse_qvalues(self['accept-encoding']) @accept_language = HTTPUtils.parse_qvalues(self['accept-language']) end return if @request_method == "CONNECT" return if @unparsed_uri == "*" begin @request_uri = parse_uri(@unparsed_uri) @path = HTTPUtils::unescape(@request_uri.path) @path = HTTPUtils::normalize_path(@path) @host = @request_uri.host @port = @request_uri.port @query_string = @request_uri.query @script_name = "" @path_info = @path.dup rescue raise HTTPStatus::BadRequest, "bad URI `#{@unparsed_uri}'." end if /close/io =~ self["connection"] @keep_alive = false elsif /keep-alive/io =~ self["connection"] @keep_alive = true elsif @http_version < "1.1" @keep_alive = false else @keep_alive = true end end def body(&block) block ||= Proc.new{|chunk| @body << chunk } read_body(@socket, block) @body.empty? ? nil : @body end def query unless @query parse_query() end @query end def content_length return Integer(self['content-length']) end def content_type return self['content-type'] end def [](header_name) if @header value = @header[header_name.downcase] value.empty? ? nil : value.join(", ") end end def each @header.each{|k, v| value = @header[k] yield(k, value.empty? ? nil : value.join(", ")) } end def keep_alive? @keep_alive end def to_s ret = @request_line.dup @raw_header.each{|line| ret << line } ret << CRLF ret << body if body ret end def fixup() begin body{|chunk| } # read remaining body rescue HTTPStatus::Error => ex @logger.error("HTTPRequest#fixup: #{ex.class} occured.") @keep_alive = false rescue => ex @logger.error(ex) @keep_alive = false end end def meta_vars # This method provides the metavariables defined by the revision 3 # of ``The WWW Common Gateway Interface Version 1.1''. # (http://Web.Golux.Com/coar/cgi/) meta = Hash.new cl = self["Content-Length"] ct = self["Content-Type"] meta["CONTENT_LENGTH"] = cl if cl.to_i > 0 meta["CONTENT_TYPE"] = ct.dup if ct meta["GATEWAY_INTERFACE"] = "CGI/1.1" meta["PATH_INFO"] = @path_info ? @path_info.dup : "" #meta["PATH_TRANSLATED"] = nil # no plan to be provided meta["QUERY_STRING"] = @query_string ? @query_string.dup : "" meta["REMOTE_ADDR"] = @peeraddr[3] meta["REMOTE_HOST"] = @peeraddr[2] #meta["REMOTE_IDENT"] = nil # no plan to be provided meta["REMOTE_USER"] = @user meta["REQUEST_METHOD"] = @request_method.dup meta["REQUEST_URI"] = @request_uri.to_s meta["SCRIPT_NAME"] = @script_name.dup meta["SERVER_NAME"] = @host meta["SERVER_PORT"] = @port.to_s meta["SERVER_PROTOCOL"] = "HTTP/" + @config[:HTTPVersion].to_s meta["SERVER_SOFTWARE"] = @config[:ServerSoftware].dup self.each{|key, val| next if /^content-type$/i =~ key next if /^content-length$/i =~ key name = "HTTP_" + key name.gsub!(/-/o, "_") name.upcase! meta[name] = val } meta end private def read_request_line(socket) @request_line = read_line(socket) if socket @request_time = Time.now raise HTTPStatus::EOFError unless @request_line if /^(\S+)\s+(\S+?)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line @request_method = $1 @unparsed_uri = $2 @http_version = HTTPVersion.new($3 ? $3 : "0.9") else rl = @request_line.sub(/\x0d?\x0a\z/o, '') raise HTTPStatus::BadRequest, "bad Request-Line `#{rl}'." end end def read_header(socket) if socket while line = read_line(socket) break if /\A(#{CRLF}|#{LF})\z/om =~ line @raw_header << line end end @header = HTTPUtils::parse_header(@raw_header.join) end def parse_uri(str, scheme="http") if @config[:Escape8bitURI] str = HTTPUtils::escape8bit(str) end str.sub!(%r{\A/+}o, '/') uri = URI::parse(str) return uri if uri.absolute? if self["host"] pattern = /\A(#{URI::REGEXP::PATTERN::HOST})(?::(\d+))?\z/n host, port = *self['host'].scan(pattern)[0] elsif @addr.size > 0 host, port = @addr[2], @addr[1] else host, port = @config[:ServerName], @config[:Port] end uri.scheme = scheme uri.host = host uri.port = port ? port.to_i : nil return URI::parse(uri.to_s) end def read_body(socket, block) return unless socket if tc = self['transfer-encoding'] case tc when /chunked/io then read_chunked(socket, block) else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}." end elsif self['content-length'] || @remaining_size @remaining_size ||= self['content-length'].to_i while @remaining_size > 0 sz = BUFSIZE < @remaining_size ? BUFSIZE : @remaining_size break unless buf = read_data(socket, sz) @remaining_size -= buf.size block.call(buf) end if @remaining_size > 0 && @socket.eof? raise HTTPStatus::BadRequest, "invalid body size." end elsif BODY_CONTAINABLE_METHODS.member?(@request_method) raise HTTPStatus::LengthRequired end return @body end def read_chunk_size(socket) line = read_line(socket) if /^([0-9a-fA-F]+)(?:;(\S+))?/ =~ line chunk_size = $1.hex chunk_ext = $2 [ chunk_size, chunk_ext ] else raise HTTPStatus::BadRequest, "bad chunk `#{line}'." end end def read_chunked(socket, block) chunk_size, = read_chunk_size(socket) while chunk_size > 0 data = "" while data.size < chunk_size tmp = read_data(socket, chunk_size-data.size) # read chunk-data break unless tmp data << tmp end if data.nil? || data.size != chunk_size raise BadRequest, "bad chunk data size." end read_line(socket) # skip CRLF block.call(data) chunk_size, = read_chunk_size(socket) end read_header(socket) # trailer + CRLF @header.delete("transfer-encoding") @remaining_size = 0 end def _read_data(io, method, arg) begin timeout(@config[:RequestTimeout]){ return io.__send__(method, arg) } rescue Errno::ECONNRESET return nil rescue TimeoutError raise HTTPStatus::RequestTimeout end end def read_line(io) _read_data(io, :gets, LF) end def read_data(io, size) _read_data(io, :read, size) end def parse_query() begin if @request_method == "GET" || @request_method == "HEAD" @query = HTTPUtils::parse_query(@query_string) elsif self['content-type'] =~ /^application\/x-www-form-urlencoded/ @query = HTTPUtils::parse_query(body) elsif self['content-type'] =~ /^multipart\/form-data; boundary=(.+)/ boundary = HTTPUtils::dequote($1) @query = HTTPUtils::parse_form_data(body, boundary) else @query = Hash.new end rescue => ex raise HTTPStatus::BadRequest, ex.message end end end end PK|]ɒQ==webrick/httpauth.rbnu[# # httpauth.rb -- HTTP access authentication # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpauth.rb,v 1.14 2003/07/22 19:20:42 gotoyuzo Exp $ require 'webrick/httpauth/basicauth' require 'webrick/httpauth/digestauth' require 'webrick/httpauth/htpasswd' require 'webrick/httpauth/htdigest' require 'webrick/httpauth/htgroup' module WEBrick module HTTPAuth module_function def _basic_auth(req, res, realm, req_field, res_field, err_type, block) user = pass = nil if /^Basic\s+(.*)/o =~ req[req_field] userpass = $1 user, pass = userpass.unpack("m*")[0].split(":", 2) end if block.call(user, pass) req.user = user return end res[res_field] = "Basic realm=\"#{realm}\"" raise err_type end def basic_auth(req, res, realm, &block) _basic_auth(req, res, realm, "Authorization", "WWW-Authenticate", HTTPStatus::Unauthorized, block) end def proxy_basic_auth(req, res, realm, &block) _basic_auth(req, res, realm, "Proxy-Authorization", "Proxy-Authenticate", HTTPStatus::ProxyAuthenticationRequired, block) end end end PK|]ͩwebrick/cgi.rbnu[# # cgi.rb -- Yet another CGI library # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $Id: cgi.rb 11708 2007-02-12 23:01:19Z shyouhei $ require "webrick/httprequest" require "webrick/httpresponse" require "webrick/config" require "stringio" module WEBrick class CGI CGIError = Class.new(StandardError) attr_reader :config, :logger def initialize(*args) if defined?(MOD_RUBY) unless ENV.has_key?("GATEWAY_INTERFACE") Apache.request.setup_cgi_env end end if %r{HTTP/(\d+\.\d+)} =~ ENV["SERVER_PROTOCOL"] httpv = $1 end @config = WEBrick::Config::HTTP.dup.update( :ServerSoftware => ENV["SERVER_SOFTWARE"] || "null", :HTTPVersion => HTTPVersion.new(httpv || "1.0"), :RunOnCGI => true, # to detect if it runs on CGI. :NPH => false # set true to run as NPH script. ) if config = args.shift @config.update(config) end @config[:Logger] ||= WEBrick::BasicLog.new($stderr) @logger = @config[:Logger] @options = args end def [](key) @config[key] end def start(env=ENV, stdin=$stdin, stdout=$stdout) sock = WEBrick::CGI::Socket.new(@config, env, stdin, stdout) req = HTTPRequest.new(@config) res = HTTPResponse.new(@config) unless @config[:NPH] or defined?(MOD_RUBY) def res.setup_header unless @header["status"] phrase = HTTPStatus::reason_phrase(@status) @header["status"] = "#{@status} #{phrase}" end super end def res.status_line "" end end begin req.parse(sock) req.script_name = (env["SCRIPT_NAME"] || File.expand_path($0)).dup req.path_info = (env["PATH_INFO"] || "").dup req.query_string = env["QUERY_STRING"] req.user = env["REMOTE_USER"] res.request_method = req.request_method res.request_uri = req.request_uri res.request_http_version = req.http_version res.keep_alive = req.keep_alive? self.service(req, res) rescue HTTPStatus::Error => ex res.set_error(ex) rescue HTTPStatus::Status => ex res.status = ex.code rescue Exception => ex @logger.error(ex) res.set_error(ex, true) ensure req.fixup if defined?(MOD_RUBY) res.setup_header Apache.request.status_line = "#{res.status} #{res.reason_phrase}" Apache.request.status = res.status table = Apache.request.headers_out res.header.each{|key, val| case key when /^content-encoding$/i Apache::request.content_encoding = val when /^content-type$/i Apache::request.content_type = val else table[key] = val.to_s end } res.cookies.each{|cookie| table.add("Set-Cookie", cookie.to_s) } Apache.request.send_http_header res.send_body(sock) else res.send_response(sock) end end end def service(req, res) method_name = "do_" + req.request_method.gsub(/-/, "_") if respond_to?(method_name) __send__(method_name, req, res) else raise HTTPStatus::MethodNotAllowed, "unsupported method `#{req.request_method}'." end end class Socket include Enumerable private def initialize(config, env, stdin, stdout) @config = config @env = env @header_part = StringIO.new @body_part = stdin @out_port = stdout @out_port.binmode @server_addr = @env["SERVER_ADDR"] || "0.0.0.0" @server_name = @env["SERVER_NAME"] @server_port = @env["SERVER_PORT"] @remote_addr = @env["REMOTE_ADDR"] @remote_host = @env["REMOTE_HOST"] || @remote_addr @remote_port = @env["REMOTE_PORT"] || 0 begin @header_part << request_line << CRLF setup_header @header_part << CRLF @header_part.rewind rescue Exception => ex raise CGIError, "invalid CGI environment" end end def request_line meth = @env["REQUEST_METHOD"] || "GET" unless url = @env["REQUEST_URI"] url = (@env["SCRIPT_NAME"] || File.expand_path($0)).dup url << @env["PATH_INFO"].to_s url = WEBrick::HTTPUtils.escape_path(url) if query_string = @env["QUERY_STRING"] unless query_string.empty? url << "?" << query_string end end end # we cannot get real HTTP version of client ;) httpv = @config[:HTTPVersion] return "#{meth} #{url} HTTP/#{httpv}" end def setup_header add_header("CONTENT_TYPE", "Content-Type") add_header("CONTENT_LENGTH", "Content-length") @env.each_key{|name| if /^HTTP_(.*)/ =~ name add_header(name, $1.gsub(/_/, "-")) end } end def add_header(envname, hdrname) if value = @env[envname] unless value.empty? @header_part << hdrname << ": " << value << CRLF end end end def input @header_part.eof? ? @body_part : @header_part end public def peeraddr [nil, @remote_port, @remote_host, @remote_addr] end def addr [nil, @server_port, @server_name, @server_addr] end def gets(eol=LF) input.gets(eol) end def read(size=nil) input.read(size) end def each input.each{|line| yield(line) } end def <<(data) @out_port << data end def cert return nil unless defined?(OpenSSL) if pem = @env["SSL_SERVER_CERT"] OpenSSL::X509::Certificate.new(pem) unless pem.empty? end end def peer_cert return nil unless defined?(OpenSSL) if pem = @env["SSL_CLIENT_CERT"] OpenSSL::X509::Certificate.new(pem) unless pem.empty? end end def peer_cert_chain return nil unless defined?(OpenSSL) if @env["SSL_CLIENT_CERT_CHAIN_0"] keys = @env.keys certs = keys.sort.collect{|k| if /^SSL_CLIENT_CERT_CHAIN_\d+$/ =~ k if pem = @env[k] OpenSSL::X509::Certificate.new(pem) unless pem.empty? end end } certs.compact end end def cipher return nil unless defined?(OpenSSL) if cipher = @env["SSL_CIPHER"] ret = [ cipher ] ret << @env["SSL_PROTOCOL"] ret << @env["SSL_CIPHER_USEKEYSIZE"] ret << @env["SSL_CIPHER_ALGKEYSIZE"] ret end end end end end PK|]{L  webrick/httpstatus.rbnu[# # httpstatus.rb -- HTTPStatus Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpstatus.rb,v 1.11 2003/03/24 20:18:55 gotoyuzo Exp $ module WEBrick module HTTPStatus class Status < StandardError def initialize(*args) args[0] = AccessLog.escape(args[0]) unless args.empty? super(*args) end class << self attr_reader :code, :reason_phrase end def code() self::class::code end def reason_phrase() self::class::reason_phrase end alias to_i code end class Info < Status; end class Success < Status; end class Redirect < Status; end class Error < Status; end class ClientError < Error; end class ServerError < Error; end class EOFError < StandardError; end StatusMessage = { 100, 'Continue', 101, 'Switching Protocols', 200, 'OK', 201, 'Created', 202, 'Accepted', 203, 'Non-Authoritative Information', 204, 'No Content', 205, 'Reset Content', 206, 'Partial Content', 300, 'Multiple Choices', 301, 'Moved Permanently', 302, 'Found', 303, 'See Other', 304, 'Not Modified', 305, 'Use Proxy', 307, 'Temporary Redirect', 400, 'Bad Request', 401, 'Unauthorized', 402, 'Payment Required', 403, 'Forbidden', 404, 'Not Found', 405, 'Method Not Allowed', 406, 'Not Acceptable', 407, 'Proxy Authentication Required', 408, 'Request Timeout', 409, 'Conflict', 410, 'Gone', 411, 'Length Required', 412, 'Precondition Failed', 413, 'Request Entity Too Large', 414, 'Request-URI Too Large', 415, 'Unsupported Media Type', 416, 'Request Range Not Satisfiable', 417, 'Expectation Failed', 500, 'Internal Server Error', 501, 'Not Implemented', 502, 'Bad Gateway', 503, 'Service Unavailable', 504, 'Gateway Timeout', 505, 'HTTP Version Not Supported' } CodeToError = {} StatusMessage.each{|code, message| message.freeze var_name = message.gsub(/[ \-]/,'_').upcase err_name = message.gsub(/[ \-]/,'') case code when 100...200; parent = Info when 200...300; parent = Success when 300...400; parent = Redirect when 400...500; parent = ClientError when 500...600; parent = ServerError end const_set("RC_#{var_name}", code) err_class = Class.new(parent) err_class.instance_variable_set(:@code, code) err_class.instance_variable_set(:@reason_phrase, message) const_set(err_name, err_class) CodeToError[code] = err_class } def reason_phrase(code) StatusMessage[code.to_i] end def info?(code) code.to_i >= 100 and code.to_i < 200 end def success?(code) code.to_i >= 200 and code.to_i < 300 end def redirect?(code) code.to_i >= 300 and code.to_i < 400 end def error?(code) code.to_i >= 400 and code.to_i < 600 end def client_error?(code) code.to_i >= 400 and code.to_i < 500 end def server_error?(code) code.to_i >= 500 and code.to_i < 600 end def self.[](code) CodeToError[code] end module_function :reason_phrase module_function :info?, :success?, :redirect?, :error? module_function :client_error?, :server_error? end end PK|]6f|uwebrick/compat.rbnu[# # compat.rb -- cross platform compatibility # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2002 GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: compat.rb,v 1.6 2002/10/01 17:16:32 gotoyuzo Exp $ module Errno class EPROTO < SystemCallError; end class ECONNRESET < SystemCallError; end class ECONNABORTED < SystemCallError; end end PK|]/ݔvvwebrick/httpversion.rbnu[# # HTTPVersion.rb -- presentation of HTTP version # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpversion.rb,v 1.5 2002/09/21 12:23:37 gotoyuzo Exp $ module WEBrick class HTTPVersion include Comparable attr_accessor :major, :minor def self.convert(version) version.is_a?(self) ? version : new(version) end def initialize(version) case version when HTTPVersion @major, @minor = version.major, version.minor when String if /^(\d+)\.(\d+)$/ =~ version @major, @minor = $1.to_i, $2.to_i end end if @major.nil? || @minor.nil? raise ArgumentError, format("cannot convert %s into %s", version.class, self.class) end end def <=>(other) unless other.is_a?(self.class) other = self.class.new(other) end if (ret = @major <=> other.major) == 0 return @minor <=> other.minor end return ret end def to_s format("%d.%d", @major, @minor) end end end PK|] _webrick/https.rbnu[# # https.rb -- SSL/TLS enhancement for HTTPServer # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $ require 'webrick/ssl' module WEBrick module Config HTTP.update(SSL) end class HTTPRequest attr_reader :cipher, :server_cert, :client_cert alias orig_parse parse def parse(socket=nil) @cipher = @server_cert = @client_cert = nil if socket.respond_to?(:cert) @server_cert = socket.cert || @config[:SSLCertificate] @client_cert = socket.peer_cert @client_cert_chain = socket.peer_cert_chain @cipher = socket.cipher end orig_parse(socket) end alias orig_parse_uri parse_uri def parse_uri(str, scheme="https") if @server_cert return orig_parse_uri(str, scheme) end return orig_parse_uri(str) end alias orig_meta_vars meta_vars def meta_vars meta = orig_meta_vars if @server_cert meta["HTTPS"] = "on" meta["SSL_SERVER_CERT"] = @server_cert.to_pem meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : "" if @client_cert_chain @client_cert_chain.each_with_index{|cert, i| meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem } end meta["SSL_CIPHER"] = @cipher[0] meta["SSL_PROTOCOL"] = @cipher[1] meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s meta["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s end meta end end end PK|] n>webrick/httpservlet.rbnu[# # httpservlet.rb -- HTTPServlet Utility File # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: httpservlet.rb,v 1.21 2003/02/23 12:24:46 gotoyuzo Exp $ require 'webrick/httpservlet/abstract' require 'webrick/httpservlet/filehandler' require 'webrick/httpservlet/cgihandler' require 'webrick/httpservlet/erbhandler' require 'webrick/httpservlet/prochandler' module WEBrick module HTTPServlet FileHandler.add_handler("cgi", CGIHandler) FileHandler.add_handler("rhtml", ERBHandler) end end PK|]8iɚ!webrick/httpservlet/erbhandler.rbnu[# # erbhandler.rb -- ERBHandler Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: erbhandler.rb,v 1.25 2003/02/24 19:25:31 gotoyuzo Exp $ require 'webrick/httpservlet/abstract.rb' require 'erb' module WEBrick module HTTPServlet class ERBHandler < AbstractServlet def initialize(server, name) super @script_filename = name end def do_GET(req, res) unless defined?(ERB) @logger.warn "#{self.class}: ERB not defined." raise HTTPStatus::Forbidden, "ERBHandler cannot work." end begin data = open(@script_filename){|io| io.read } res.body = evaluate(ERB.new(data), req, res) res['content-type'] = HTTPUtils::mime_type(@script_filename, @config[:MimeTypes]) rescue StandardError => ex raise rescue Exception => ex @logger.error(ex) raise HTTPStatus::InternalServerError, ex.message end end alias do_POST do_GET private def evaluate(erb, servlet_request, servlet_response) Module.new.module_eval{ meta_vars = servlet_request.meta_vars query = servlet_request.query erb.result(binding) } end end end end PK|]-!!webrick/httpservlet/cgi_runner.rbnu[# # cgi_runner.rb -- CGI launcher. # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: cgi_runner.rb,v 1.9 2002/09/25 11:33:15 gotoyuzo Exp $ def sysread(io, size) buf = "" while size > 0 tmp = io.sysread(size) buf << tmp size -= tmp.size end return buf end STDIN.binmode buf = "" len = sysread(STDIN, 8).to_i out = sysread(STDIN, len) STDOUT.reopen(open(out, "w")) len = sysread(STDIN, 8).to_i err = sysread(STDIN, len) STDERR.reopen(open(err, "w")) len = sysread(STDIN, 8).to_i dump = sysread(STDIN, len) hash = Marshal.restore(dump) ENV.keys.each{|name| ENV.delete(name) } hash.each{|k, v| ENV[k] = v if v } dir = File::dirname(ENV["SCRIPT_FILENAME"]) Dir::chdir dir if interpreter = ARGV[0] argv = ARGV.dup argv << ENV["SCRIPT_FILENAME"] exec(*argv) # NOTREACHED end exec ENV["SCRIPT_FILENAME"] PK|]XgV  !webrick/httpservlet/cgihandler.rbnu[# # cgihandler.rb -- CGIHandler Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: cgihandler.rb,v 1.27 2003/03/21 19:56:01 gotoyuzo Exp $ require 'rbconfig' require 'tempfile' require 'webrick/config' require 'webrick/httpservlet/abstract' module WEBrick module HTTPServlet class CGIHandler < AbstractServlet Ruby = File::join(::Config::CONFIG['bindir'], ::Config::CONFIG['ruby_install_name']) Ruby << ::Config::CONFIG['EXEEXT'] CGIRunner = "\"#{Ruby}\" \"#{Config::LIBDIR}/httpservlet/cgi_runner.rb\"" def initialize(server, name) super @script_filename = name @tempdir = server[:TempDir] @cgicmd = "#{CGIRunner} #{server[:CGIInterpreter]}" end def do_GET(req, res) data = nil status = -1 cgi_in = IO::popen(@cgicmd, "wb") cgi_out = Tempfile.new("webrick.cgiout.", @tempdir) cgi_err = Tempfile.new("webrick.cgierr.", @tempdir) begin cgi_in.sync = true meta = req.meta_vars meta["SCRIPT_FILENAME"] = @script_filename meta["PATH"] = @config[:CGIPathEnv] if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM meta["SystemRoot"] = ENV["SystemRoot"] end dump = Marshal.dump(meta) cgi_in.write("%8d" % cgi_out.path.size) cgi_in.write(cgi_out.path) cgi_in.write("%8d" % cgi_err.path.size) cgi_in.write(cgi_err.path) cgi_in.write("%8d" % dump.size) cgi_in.write(dump) if req.body and req.body.size > 0 cgi_in.write(req.body) end ensure cgi_in.close status = $?.exitstatus sleep 0.1 if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM data = cgi_out.read cgi_out.close(true) if errmsg = cgi_err.read if errmsg.size > 0 @logger.error("CGIHandler: #{@script_filename}:\n" + errmsg) end end cgi_err.close(true) end if status != 0 @logger.error("CGIHandler: #{@script_filename} exit with #{status}") end data = "" unless data raw_header, body = data.split(/^[\xd\xa]+/on, 2) raise HTTPStatus::InternalServerError, "Premature end of script headers: #{@script_filename}" if body.nil? begin header = HTTPUtils::parse_header(raw_header) if /^(\d+)/ =~ header['status'][0] res.status = $1.to_i header.delete('status') end if header.has_key?('location') # RFC 3875 6.2.3, 6.2.4 res.status = 302 unless (300...400) === res.status end if header.has_key?('set-cookie') header['set-cookie'].each{|k| res.cookies << Cookie.parse_set_cookie(k) } header.delete('set-cookie') end header.each{|key, val| res[key] = val.join(", ") } rescue => ex raise HTTPStatus::InternalServerError, ex.message end res.body = body end alias do_POST do_GET end end end PK|]'66"webrick/httpservlet/filehandler.rbnu[# # filehandler.rb -- FileHandler Module # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: filehandler.rb,v 1.44 2003/06/07 01:34:51 gotoyuzo Exp $ require 'thread' require 'time' require 'webrick/htmlutils' require 'webrick/httputils' require 'webrick/httpstatus' module WEBrick module HTTPServlet class DefaultFileHandler < AbstractServlet def initialize(server, local_path) super @local_path = local_path end def do_GET(req, res) st = File::stat(@local_path) mtime = st.mtime res['etag'] = sprintf("%x-%x-%x", st.ino, st.size, st.mtime.to_i) if not_modified?(req, res, mtime, res['etag']) res.body = '' raise HTTPStatus::NotModified elsif req['range'] make_partial_content(req, res, @local_path, st.size) raise HTTPStatus::PartialContent else mtype = HTTPUtils::mime_type(@local_path, @config[:MimeTypes]) res['content-type'] = mtype res['content-length'] = st.size res['last-modified'] = mtime.httpdate res.body = open(@local_path, "rb") end end def not_modified?(req, res, mtime, etag) if ir = req['if-range'] begin if Time.httpdate(ir) >= mtime return true end rescue if HTTPUtils::split_header_value(ir).member?(res['etag']) return true end end end if (ims = req['if-modified-since']) && Time.parse(ims) >= mtime return true end if (inm = req['if-none-match']) && HTTPUtils::split_header_value(inm).member?(res['etag']) return true end return false end def make_partial_content(req, res, filename, filesize) mtype = HTTPUtils::mime_type(filename, @config[:MimeTypes]) unless ranges = HTTPUtils::parse_range_header(req['range']) raise HTTPStatus::BadRequest, "Unrecognized range-spec: \"#{req['range']}\"" end open(filename, "rb"){|io| if ranges.size > 1 time = Time.now boundary = "#{time.sec}_#{time.usec}_#{Process::pid}" body = '' ranges.each{|range| first, last = prepare_range(range, filesize) next if first < 0 io.pos = first content = io.read(last-first+1) body << "--" << boundary << CRLF body << "Content-Type: #{mtype}" << CRLF body << "Content-Range: bytes #{first}-#{last}/#{filesize}" << CRLF body << CRLF body << content body << CRLF } raise HTTPStatus::RequestRangeNotSatisfiable if body.empty? body << "--" << boundary << "--" << CRLF res["content-type"] = "multipart/byteranges; boundary=#{boundary}" res.body = body elsif range = ranges[0] first, last = prepare_range(range, filesize) raise HTTPStatus::RequestRangeNotSatisfiable if first < 0 if last == filesize - 1 content = io.dup content.pos = first else io.pos = first content = io.read(last-first+1) end res['content-type'] = mtype res['content-range'] = "bytes #{first}-#{last}/#{filesize}" res['content-length'] = last - first + 1 res.body = content else raise HTTPStatus::BadRequest end } end def prepare_range(range, filesize) first = range.first < 0 ? filesize + range.first : range.first return -1, -1 if first < 0 || first >= filesize last = range.last < 0 ? filesize + range.last : range.last last = filesize - 1 if last >= filesize return first, last end end class FileHandler < AbstractServlet HandlerTable = Hash.new def self.add_handler(suffix, handler) HandlerTable[suffix] = handler end def self.remove_handler(suffix) HandlerTable.delete(suffix) end def initialize(server, root, options={}, default=Config::FileHandler) @config = server.config @logger = @config[:Logger] @root = File.expand_path(root) if options == true || options == false options = { :FancyIndexing => options } end @options = default.dup.update(options) end def service(req, res) # if this class is mounted on "/" and /~username is requested. # we're going to override path informations before invoking service. if defined?(Etc) && @options[:UserDir] && req.script_name.empty? if %r|^(/~([^/]+))| =~ req.path_info script_name, user = $1, $2 path_info = $' begin passwd = Etc::getpwnam(user) @root = File::join(passwd.dir, @options[:UserDir]) req.script_name = script_name req.path_info = path_info rescue @logger.debug "#{self.class}#do_GET: getpwnam(#{user}) failed" end end end prevent_directory_traversal(req, res) super(req, res) end def do_GET(req, res) unless exec_handler(req, res) set_dir_list(req, res) end end def do_POST(req, res) unless exec_handler(req, res) raise HTTPStatus::NotFound, "`#{req.path}' not found." end end def do_OPTIONS(req, res) unless exec_handler(req, res) super(req, res) end end # ToDo # RFC2518: HTTP Extensions for Distributed Authoring -- WEBDAV # # PROPFIND PROPPATCH MKCOL DELETE PUT COPY MOVE # LOCK UNLOCK # RFC3253: Versioning Extensions to WebDAV # (Web Distributed Authoring and Versioning) # # VERSION-CONTROL REPORT CHECKOUT CHECK_IN UNCHECKOUT # MKWORKSPACE UPDATE LABEL MERGE ACTIVITY private def trailing_pathsep?(path) # check for trailing path separator: # File.dirname("/aaaa/bbbb/") #=> "/aaaa") # File.dirname("/aaaa/bbbb/x") #=> "/aaaa/bbbb") # File.dirname("/aaaa/bbbb") #=> "/aaaa") # File.dirname("/aaaa/bbbbx") #=> "/aaaa") return File.dirname(path) != File.dirname(path+"x") end def prevent_directory_traversal(req, res) # Preventing directory traversal on Windows platforms; # Backslashes (0x5c) in path_info are not interpreted as special # character in URI notation. So the value of path_info should be # normalize before accessing to the filesystem. if trailing_pathsep?(req.path_info) # File.expand_path removes the trailing path separator. # Adding a character is a workaround to save it. # File.expand_path("/aaa/") #=> "/aaa" # File.expand_path("/aaa/" + "x") #=> "/aaa/x" expanded = File.expand_path(req.path_info + "x") expanded.chop! # remove trailing "x" else expanded = File.expand_path(req.path_info) end req.path_info = expanded end def exec_handler(req, res) raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root if set_filename(req, res) handler = get_handler(req, res) call_callback(:HandlerCallback, req, res) h = handler.get_instance(@config, res.filename) h.service(req, res) return true end call_callback(:HandlerCallback, req, res) return false end def get_handler(req, res) suffix1 = (/\.(\w+)\z/ =~ res.filename) && $1.downcase if /\.(\w+)\.([\w\-]+)\z/ =~ res.filename if @options[:AcceptableLanguages].include?($2.downcase) suffix2 = $1.downcase end end handler_table = @options[:HandlerTable] return handler_table[suffix1] || handler_table[suffix2] || HandlerTable[suffix1] || HandlerTable[suffix2] || DefaultFileHandler end def set_filename(req, res) res.filename = @root.dup path_info = req.path_info.scan(%r|/[^/]*|) path_info.unshift("") # dummy for checking @root dir while base = path_info.first break if base == "/" break unless File.directory?(File.expand_path(res.filename + base)) shift_path_info(req, res, path_info) call_callback(:DirectoryCallback, req, res) end if base = path_info.first if base == "/" if file = search_index_file(req, res) shift_path_info(req, res, path_info, file) call_callback(:FileCallback, req, res) return true end shift_path_info(req, res, path_info) elsif file = search_file(req, res, base) shift_path_info(req, res, path_info, file) call_callback(:FileCallback, req, res) return true else raise HTTPStatus::NotFound, "`#{req.path}' not found." end end return false end def check_filename(req, res, name) if nondisclosure_name?(name) || windows_ambiguous_name?(name) @logger.warn("the request refers nondisclosure name `#{name}'.") raise HTTPStatus::NotFound, "`#{req.path}' not found." end end def shift_path_info(req, res, path_info, base=nil) tmp = path_info.shift base = base || tmp req.path_info = path_info.join req.script_name << base res.filename = File.expand_path(res.filename + base) check_filename(req, res, File.basename(res.filename)) end def search_index_file(req, res) @config[:DirectoryIndex].each{|index| if file = search_file(req, res, "/"+index) return file end } return nil end def search_file(req, res, basename) langs = @options[:AcceptableLanguages] path = res.filename + basename if File.file?(path) return basename elsif langs.size > 0 req.accept_language.each{|lang| path_with_lang = path + ".#{lang}" if langs.member?(lang) && File.file?(path_with_lang) return basename + ".#{lang}" end } (langs - req.accept_language).each{|lang| path_with_lang = path + ".#{lang}" if File.file?(path_with_lang) return basename + ".#{lang}" end } end return nil end def call_callback(callback_name, req, res) if cb = @options[callback_name] cb.call(req, res) end end def windows_ambiguous_name?(name) return true if /[. ]+\z/ =~ name return true if /::\$DATA\z/ =~ name return false end def nondisclosure_name?(name) @options[:NondisclosureName].each{|pattern| if File.fnmatch(pattern, name, File::FNM_CASEFOLD) return true end } return false end def set_dir_list(req, res) redirect_to_directory_uri(req, res) unless @options[:FancyIndexing] raise HTTPStatus::Forbidden, "no access permission to `#{req.path}'" end local_path = res.filename list = Dir::entries(local_path).collect{|name| next if name == "." || name == ".." next if nondisclosure_name?(name) next if windows_ambiguous_name?(name) st = (File::stat(File.join(local_path, name)) rescue nil) if st.nil? [ name, nil, -1 ] elsif st.directory? [ name + "/", st.mtime, -1 ] else [ name, st.mtime, st.size ] end } list.compact! if d0 = req.query["N"]; idx = 0 elsif d0 = req.query["M"]; idx = 1 elsif d0 = req.query["S"]; idx = 2 else d0 = "A" ; idx = 0 end d1 = (d0 == "A") ? "D" : "A" if d0 == "A" list.sort!{|a,b| a[idx] <=> b[idx] } else list.sort!{|a,b| b[idx] <=> a[idx] } end res['content-type'] = "text/html" res.body = <<-_end_of_html_ Index of #{HTMLUtils::escape(req.path)}

    Index of #{HTMLUtils::escape(req.path)}

    _end_of_html_ res.body << "
    \n"
            res.body << " Name                          "
            res.body << "Last modified         "
            res.body << "Size\n"
            res.body << "
    \n" list.unshift [ "..", File::mtime(local_path+"/.."), -1 ] list.each{ |name, time, size| if name == ".." dname = "Parent Directory" elsif name.size > 25 dname = name.sub(/^(.{23})(.*)/){ $1 + ".." } else dname = name end s = " #{dname}" s << " " * (30 - dname.size) s << (time ? time.strftime("%Y/%m/%d %H:%M ") : " " * 22) s << (size >= 0 ? size.to_s : "-") << "\n" res.body << s } res.body << "

    " res.body << <<-_end_of_html_
    #{HTMLUtils::escape(@config[:ServerSoftware])}
    at #{req.host}:#{req.port}
    _end_of_html_ end end end end PK|]`webrick/httpservlet/abstract.rbnu[# # httpservlet.rb -- HTTPServlet Module # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: abstract.rb,v 1.24 2003/07/11 11:16:46 gotoyuzo Exp $ require 'thread' require 'webrick/htmlutils' require 'webrick/httputils' require 'webrick/httpstatus' module WEBrick module HTTPServlet class HTTPServletError < StandardError; end class AbstractServlet def self.get_instance(config, *options) self.new(config, *options) end def initialize(server, *options) @server = @config = server @logger = @server[:Logger] @options = options end def service(req, res) method_name = "do_" + req.request_method.gsub(/-/, "_") if respond_to?(method_name) __send__(method_name, req, res) else raise HTTPStatus::MethodNotAllowed, "unsupported method `#{req.request_method}'." end end def do_GET(req, res) raise HTTPStatus::NotFound, "not found." end def do_HEAD(req, res) do_GET(req, res) end def do_OPTIONS(req, res) m = self.methods.grep(/^do_[A-Z]+$/) m.collect!{|i| i.sub(/do_/, "") } m.sort! res["allow"] = m.join(",") end private def redirect_to_directory_uri(req, res) if req.path[-1] != ?/ location = WEBrick::HTTPUtils.escape_path(req.path + "/") if req.query_string && req.query_string.size > 0 location << "?" << req.query_string end res.set_redirect(HTTPStatus::MovedPermanently, location) end end end end end PK|]Bh"webrick/httpservlet/prochandler.rbnu[# # prochandler.rb -- ProcHandler Class # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: prochandler.rb,v 1.7 2002/09/21 12:23:42 gotoyuzo Exp $ require 'webrick/httpservlet/abstract.rb' module WEBrick module HTTPServlet class ProcHandler < AbstractServlet def get_instance(server, *options) self end def initialize(proc) @proc = proc end def do_GET(request, response) @proc.call(request, response) end alias do_POST do_GET end end end PK|]`>HHwebrick/htmlutils.rbnu[# # htmlutils.rb -- HTMLUtils Module # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou # Copyright (c) 2002 Internet Programming with Ruby writers. All rights # reserved. # # $IPR: htmlutils.rb,v 1.7 2002/09/21 12:23:35 gotoyuzo Exp $ module WEBrick module HTMLUtils def escape(string) str = string ? string.dup : "" str.gsub!(/&/n, '&') str.gsub!(/\"/n, '"') str.gsub!(/>/n, '>') str.gsub!(/ Utils::getservername, :BindAddress => nil, # "0.0.0.0" or "::" or nil :Port => nil, # users MUST specifiy this!! :MaxClients => 100, # maximum number of the concurrent connections :ServerType => nil, # default: WEBrick::SimpleServer :Logger => nil, # default: WEBrick::Log.new :ServerSoftware => "WEBrick/#{WEBrick::VERSION} " + "(Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})", :TempDir => ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'/tmp', :DoNotListen => false, :StartCallback => nil, :StopCallback => nil, :AcceptCallback => nil, } # for HTTPServer, HTTPRequest, HTTPResponse ... HTTP = General.dup.update( :Port => 80, :RequestTimeout => 30, :HTTPVersion => HTTPVersion.new("1.1"), :AccessLog => nil, :MimeTypes => HTTPUtils::DefaultMimeTypes, :DirectoryIndex => ["index.html","index.htm","index.cgi","index.rhtml"], :DocumentRoot => nil, :DocumentRootOptions => { :FancyIndexing => true }, :RequestHandler => nil, :RequestCallback => nil, # alias of :RequestHandler :ServerAlias => nil, # for HTTPProxyServer :ProxyAuthProc => nil, :ProxyContentHandler => nil, :ProxyVia => true, :ProxyTimeout => true, :ProxyURI => nil, :CGIInterpreter => nil, :CGIPathEnv => nil, # workaround: if Request-URIs contain 8bit chars, # they should be escaped before calling of URI::parse(). :Escape8bitURI => false ) FileHandler = { :NondisclosureName => [".ht*", "*~"], :FancyIndexing => false, :HandlerTable => {}, :HandlerCallback => nil, :DirectoryCallback => nil, :FileCallback => nil, :UserDir => nil, # e.g. "public_html" :AcceptableLanguages => [] # ["en", "ja", ... ] } BasicAuth = { :AutoReloadUserDB => true, } DigestAuth = { :Algorithm => 'MD5-sess', # or 'MD5' :Domain => nil, # an array includes domain names. :Qop => [ 'auth' ], # 'auth' or 'auth-int' or both. :UseOpaque => true, :UseNextNonce => false, :CheckNc => false, :UseAuthenticationInfoHeader => true, :AutoReloadUserDB => true, :NonceExpirePeriod => 30*60, :NonceExpireDelta => 60, :InternetExplorerHack => true, :OperaHack => true, } end end PK|]UWIWIprettyprint.rbnu[# $Id$ # This class implements a pretty printing algorithm. It finds line breaks and # nice indentations for grouped structure. # # By default, the class assumes that primitive elements are strings and each # byte in the strings have single column in width. But it can be used for # other situations by giving suitable arguments for some methods: # * newline object and space generation block for PrettyPrint.new # * optional width argument for PrettyPrint#text # * PrettyPrint#breakable # # There are several candidate uses: # * text formatting using proportional fonts # * multibyte characters which has columns different to number of bytes # * non-string formatting # # == Bugs # * Box based formatting? # * Other (better) model/algorithm? # # == References # Christian Lindig, Strictly Pretty, March 2000, # http://www.st.cs.uni-sb.de/~lindig/papers/#pretty # # Philip Wadler, A prettier printer, March 1998, # http://homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier # # == Author # Tanaka Akira # class PrettyPrint # This is a convenience method which is same as follows: # # begin # q = PrettyPrint.new(output, maxwidth, newline, &genspace) # ... # q.flush # output # end # def PrettyPrint.format(output='', maxwidth=79, newline="\n", genspace=lambda {|n| ' ' * n}) q = PrettyPrint.new(output, maxwidth, newline, &genspace) yield q q.flush output end # This is similar to PrettyPrint::format but the result has no breaks. # # +maxwidth+, +newline+ and +genspace+ are ignored. # # The invocation of +breakable+ in the block doesn't break a line and is # treated as just an invocation of +text+. # def PrettyPrint.singleline_format(output='', maxwidth=nil, newline=nil, genspace=nil) q = SingleLine.new(output) yield q output end # Creates a buffer for pretty printing. # # +output+ is an output target. If it is not specified, '' is assumed. It # should have a << method which accepts the first argument +obj+ of # PrettyPrint#text, the first argument +sep+ of PrettyPrint#breakable, the # first argument +newline+ of PrettyPrint.new, and the result of a given # block for PrettyPrint.new. # # +maxwidth+ specifies maximum line length. If it is not specified, 79 is # assumed. However actual outputs may overflow +maxwidth+ if long # non-breakable texts are provided. # # +newline+ is used for line breaks. "\n" is used if it is not specified. # # The block is used to generate spaces. {|width| ' ' * width} is used if it # is not given. # def initialize(output='', maxwidth=79, newline="\n", &genspace) @output = output @maxwidth = maxwidth @newline = newline @genspace = genspace || lambda {|n| ' ' * n} @output_width = 0 @buffer_width = 0 @buffer = [] root_group = Group.new(0) @group_stack = [root_group] @group_queue = GroupQueue.new(root_group) @indent = 0 end attr_reader :output, :maxwidth, :newline, :genspace attr_reader :indent, :group_queue def current_group @group_stack.last end # first? is a predicate to test the call is a first call to first? with # current group. # # It is useful to format comma separated values as: # # q.group(1, '[', ']') { # xxx.each {|yyy| # unless q.first? # q.text ',' # q.breakable # end # ... pretty printing yyy ... # } # } # # first? is obsoleted in 1.8.2. # def first? warn "PrettyPrint#first? is obsoleted at 1.8.2." current_group.first? end def break_outmost_groups while @maxwidth < @output_width + @buffer_width return unless group = @group_queue.deq until group.breakables.empty? data = @buffer.shift @output_width = data.output(@output, @output_width) @buffer_width -= data.width end while !@buffer.empty? && Text === @buffer.first text = @buffer.shift @output_width = text.output(@output, @output_width) @buffer_width -= text.width end end end # This adds +obj+ as a text of +width+ columns in width. # # If +width+ is not specified, obj.length is used. # def text(obj, width=obj.length) if @buffer.empty? @output << obj @output_width += width else text = @buffer.last unless Text === text text = Text.new @buffer << text end text.add(obj, width) @buffer_width += width break_outmost_groups end end def fill_breakable(sep=' ', width=sep.length) group { breakable sep, width } end # This tells "you can break a line here if necessary", and a +width+\-column # text +sep+ is inserted if a line is not broken at the point. # # If +sep+ is not specified, " " is used. # # If +width+ is not specified, +sep.length+ is used. You will have to # specify this when +sep+ is a multibyte character, for example. # def breakable(sep=' ', width=sep.length) group = @group_stack.last if group.break? flush @output << @newline @output << @genspace.call(@indent) @output_width = @indent @buffer_width = 0 else @buffer << Breakable.new(sep, width, self) @buffer_width += width break_outmost_groups end end # Groups line break hints added in the block. The line break hints are all # to be used or not. # # If +indent+ is specified, the method call is regarded as nested by # nest(indent) { ... }. # # If +open_obj+ is specified, text open_obj, open_width is called # before grouping. If +close_obj+ is specified, text close_obj, # close_width is called after grouping. # def group(indent=0, open_obj='', close_obj='', open_width=open_obj.length, close_width=close_obj.length) text open_obj, open_width group_sub { nest(indent) { yield } } text close_obj, close_width end def group_sub group = Group.new(@group_stack.last.depth + 1) @group_stack.push group @group_queue.enq group begin yield ensure @group_stack.pop if group.breakables.empty? @group_queue.delete group end end end # Increases left margin after newline with +indent+ for line breaks added in # the block. # def nest(indent) @indent += indent begin yield ensure @indent -= indent end end # outputs buffered data. # def flush @buffer.each {|data| @output_width = data.output(@output, @output_width) } @buffer.clear @buffer_width = 0 end class Text def initialize @objs = [] @width = 0 end attr_reader :width def output(out, output_width) @objs.each {|obj| out << obj} output_width + @width end def add(obj, width) @objs << obj @width += width end end class Breakable def initialize(sep, width, q) @obj = sep @width = width @pp = q @indent = q.indent @group = q.current_group @group.breakables.push self end attr_reader :obj, :width, :indent def output(out, output_width) @group.breakables.shift if @group.break? out << @pp.newline out << @pp.genspace.call(@indent) @indent else @pp.group_queue.delete @group if @group.breakables.empty? out << @obj output_width + @width end end end class Group def initialize(depth) @depth = depth @breakables = [] @break = false end attr_reader :depth, :breakables def break @break = true end def break? @break end def first? if defined? @first false else @first = false true end end end class GroupQueue def initialize(*groups) @queue = [] groups.each {|g| enq g} end def enq(group) depth = group.depth @queue << [] until depth < @queue.length @queue[depth] << group end def deq @queue.each {|gs| (gs.length-1).downto(0) {|i| unless gs[i].breakables.empty? group = gs.slice!(i, 1).first group.break return group end } gs.each {|group| group.break} gs.clear } return nil end def delete(group) @queue[group.depth].delete(group) end end class SingleLine def initialize(output, maxwidth=nil, newline=nil) @output = output @first = [true] end def text(obj, width=nil) @output << obj end def breakable(sep=' ', width=nil) @output << sep end def nest(indent) yield end def group(indent=nil, open_obj='', close_obj='', open_width=nil, close_width=nil) @first.push true @output << open_obj yield @output << close_obj @first.pop end def flush end def first? result = @first[-1] @first[-1] = false result end end end if __FILE__ == $0 require 'test/unit' class WadlerExample < Test::Unit::TestCase # :nodoc: def setup @tree = Tree.new("aaaa", Tree.new("bbbbb", Tree.new("ccc"), Tree.new("dd")), Tree.new("eee"), Tree.new("ffff", Tree.new("gg"), Tree.new("hhh"), Tree.new("ii"))) end def hello(width) PrettyPrint.format('', width) {|hello| hello.group { hello.group { hello.group { hello.group { hello.text 'hello' hello.breakable; hello.text 'a' } hello.breakable; hello.text 'b' } hello.breakable; hello.text 'c' } hello.breakable; hello.text 'd' } } end def test_hello_00_06 expected = <<'End'.chomp hello a b c d End assert_equal(expected, hello(0)) assert_equal(expected, hello(6)) end def test_hello_07_08 expected = <<'End'.chomp hello a b c d End assert_equal(expected, hello(7)) assert_equal(expected, hello(8)) end def test_hello_09_10 expected = <<'End'.chomp hello a b c d End out = hello(9); assert_equal(expected, out) out = hello(10); assert_equal(expected, out) end def test_hello_11_12 expected = <<'End'.chomp hello a b c d End assert_equal(expected, hello(11)) assert_equal(expected, hello(12)) end def test_hello_13 expected = <<'End'.chomp hello a b c d End assert_equal(expected, hello(13)) end def tree(width) PrettyPrint.format('', width) {|q| @tree.show(q)} end def test_tree_00_19 expected = <<'End'.chomp aaaa[bbbbb[ccc, dd], eee, ffff[gg, hhh, ii]] End assert_equal(expected, tree(0)) assert_equal(expected, tree(19)) end def test_tree_20_22 expected = <<'End'.chomp aaaa[bbbbb[ccc, dd], eee, ffff[gg, hhh, ii]] End assert_equal(expected, tree(20)) assert_equal(expected, tree(22)) end def test_tree_23_43 expected = <<'End'.chomp aaaa[bbbbb[ccc, dd], eee, ffff[gg, hhh, ii]] End assert_equal(expected, tree(23)) assert_equal(expected, tree(43)) end def test_tree_44 assert_equal(<<'End'.chomp, tree(44)) aaaa[bbbbb[ccc, dd], eee, ffff[gg, hhh, ii]] End end def tree_alt(width) PrettyPrint.format('', width) {|q| @tree.altshow(q)} end def test_tree_alt_00_18 expected = <<'End'.chomp aaaa[ bbbbb[ ccc, dd ], eee, ffff[ gg, hhh, ii ] ] End assert_equal(expected, tree_alt(0)) assert_equal(expected, tree_alt(18)) end def test_tree_alt_19_20 expected = <<'End'.chomp aaaa[ bbbbb[ ccc, dd ], eee, ffff[ gg, hhh, ii ] ] End assert_equal(expected, tree_alt(19)) assert_equal(expected, tree_alt(20)) end def test_tree_alt_20_49 expected = <<'End'.chomp aaaa[ bbbbb[ ccc, dd ], eee, ffff[ gg, hhh, ii ] ] End assert_equal(expected, tree_alt(21)) assert_equal(expected, tree_alt(49)) end def test_tree_alt_50 expected = <<'End'.chomp aaaa[ bbbbb[ ccc, dd ], eee, ffff[ gg, hhh, ii ] ] End assert_equal(expected, tree_alt(50)) end class Tree # :nodoc: def initialize(string, *children) @string = string @children = children end def show(q) q.group { q.text @string q.nest(@string.length) { unless @children.empty? q.text '[' q.nest(1) { first = true @children.each {|t| if first first = false else q.text ',' q.breakable end t.show(q) } } q.text ']' end } } end def altshow(q) q.group { q.text @string unless @children.empty? q.text '[' q.nest(2) { q.breakable first = true @children.each {|t| if first first = false else q.text ',' q.breakable end t.altshow(q) } } q.breakable q.text ']' end } end end end class StrictPrettyExample < Test::Unit::TestCase # :nodoc: def prog(width) PrettyPrint.format('', width) {|q| q.group { q.group {q.nest(2) { q.text "if"; q.breakable; q.group { q.nest(2) { q.group {q.text "a"; q.breakable; q.text "=="} q.breakable; q.text "b"}}}} q.breakable q.group {q.nest(2) { q.text "then"; q.breakable; q.group { q.nest(2) { q.group {q.text "a"; q.breakable; q.text "<<"} q.breakable; q.text "2"}}}} q.breakable q.group {q.nest(2) { q.text "else"; q.breakable; q.group { q.nest(2) { q.group {q.text "a"; q.breakable; q.text "+"} q.breakable; q.text "b"}}}}} } end def test_00_04 expected = <<'End'.chomp if a == b then a << 2 else a + b End assert_equal(expected, prog(0)) assert_equal(expected, prog(4)) end def test_05 expected = <<'End'.chomp if a == b then a << 2 else a + b End assert_equal(expected, prog(5)) end def test_06 expected = <<'End'.chomp if a == b then a << 2 else a + b End assert_equal(expected, prog(6)) end def test_07 expected = <<'End'.chomp if a == b then a << 2 else a + b End assert_equal(expected, prog(7)) end def test_08 expected = <<'End'.chomp if a == b then a << 2 else a + b End assert_equal(expected, prog(8)) end def test_09 expected = <<'End'.chomp if a == b then a << 2 else a + b End assert_equal(expected, prog(9)) end def test_10 expected = <<'End'.chomp if a == b then a << 2 else a + b End assert_equal(expected, prog(10)) end def test_11_31 expected = <<'End'.chomp if a == b then a << 2 else a + b End assert_equal(expected, prog(11)) assert_equal(expected, prog(15)) assert_equal(expected, prog(31)) end def test_32 expected = <<'End'.chomp if a == b then a << 2 else a + b End assert_equal(expected, prog(32)) end end class TailGroup < Test::Unit::TestCase # :nodoc: def test_1 out = PrettyPrint.format('', 10) {|q| q.group { q.group { q.text "abc" q.breakable q.text "def" } q.group { q.text "ghi" q.breakable q.text "jkl" } } } assert_equal("abc defghi\njkl", out) end end class NonString < Test::Unit::TestCase # :nodoc: def format(width) PrettyPrint.format([], width, 'newline', lambda {|n| "#{n} spaces"}) {|q| q.text(3, 3) q.breakable(1, 1) q.text(3, 3) } end def test_6 assert_equal([3, "newline", "0 spaces", 3], format(6)) end def test_7 assert_equal([3, 1, 3], format(7)) end end class Fill < Test::Unit::TestCase # :nodoc: def format(width) PrettyPrint.format('', width) {|q| q.group { q.text 'abc' q.fill_breakable q.text 'def' q.fill_breakable q.text 'ghi' q.fill_breakable q.text 'jkl' q.fill_breakable q.text 'mno' q.fill_breakable q.text 'pqr' q.fill_breakable q.text 'stu' } } end def test_00_06 expected = <<'End'.chomp abc def ghi jkl mno pqr stu End assert_equal(expected, format(0)) assert_equal(expected, format(6)) end def test_07_10 expected = <<'End'.chomp abc def ghi jkl mno pqr stu End assert_equal(expected, format(7)) assert_equal(expected, format(10)) end def test_11_14 expected = <<'End'.chomp abc def ghi jkl mno pqr stu End assert_equal(expected, format(11)) assert_equal(expected, format(14)) end def test_15_18 expected = <<'End'.chomp abc def ghi jkl mno pqr stu End assert_equal(expected, format(15)) assert_equal(expected, format(18)) end def test_19_22 expected = <<'End'.chomp abc def ghi jkl mno pqr stu End assert_equal(expected, format(19)) assert_equal(expected, format(22)) end def test_23_26 expected = <<'End'.chomp abc def ghi jkl mno pqr stu End assert_equal(expected, format(23)) assert_equal(expected, format(26)) end def test_27 expected = <<'End'.chomp abc def ghi jkl mno pqr stu End assert_equal(expected, format(27)) end end end PK|]Fbshell.rbnu[# # shell.rb - # $Release Version: 0.6.0 $ # $Revision: 1.8 $ # $Date: 2001/03/19 09:01:11 $ # by Keiju ISHITSUKA(Nippon Rational Inc.) # # -- # # # require "e2mmap" require "thread" require "shell/error" require "shell/command-processor" require "shell/process-controller" class Shell @RCS_ID='-$Id: shell.rb,v 1.8 2001/03/19 09:01:11 keiju Exp keiju $-' include Error extend Exception2MessageMapper # @cascade = true # debug: true -> normal debug # debug: 1 -> eval definition debug # debug: 2 -> detail inspect debug @debug = false @verbose = true class << Shell attr :cascade, true attr :debug, true attr :verbose, true # alias cascade? cascade alias debug? debug alias verbose? verbose @verbose = true def debug=(val) @debug = val @verbose = val if val end def cd(path) sh = new sh.cd path sh end def default_system_path if @default_system_path @default_system_path else ENV["PATH"].split(":") end end def default_system_path=(path) @default_system_path = path end def default_record_separator if @default_record_separator @default_record_separator else $/ end end def default_record_separator=(rs) @default_record_separator = rs end end def initialize @cwd = Dir.pwd @dir_stack = [] @umask = nil @system_path = Shell.default_system_path @record_separator = Shell.default_record_separator @command_processor = CommandProcessor.new(self) @process_controller = ProcessController.new(self) @verbose = Shell.verbose @debug = Shell.debug end attr_reader :system_path def system_path=(path) @system_path = path rehash end attr :umask, true attr :record_separator, true attr :verbose, true attr :debug, true def debug=(val) @debug = val @verbose = val if val end alias verbose? verbose alias debug? debug attr_reader :command_processor attr_reader :process_controller def expand_path(path) File.expand_path(path, @cwd) end # Most Shell commands are defined via CommandProcessor # # Dir related methods # # Shell#cwd/dir/getwd/pwd # Shell#chdir/cd # Shell#pushdir/pushd # Shell#popdir/popd # Shell#mkdir # Shell#rmdir attr :cwd alias dir cwd alias getwd cwd alias pwd cwd attr :dir_stack alias dirs dir_stack # If called as iterator, it restores the current directory when the # block ends. def chdir(path = nil) if iterator? cwd_old = @cwd begin chdir(path) yield ensure chdir(cwd_old) end else path = "~" unless path @cwd = expand_path(path) notify "current dir: #{@cwd}" rehash self end end alias cd chdir def pushdir(path = nil) if iterator? pushdir(path) begin yield ensure popdir end elsif path @dir_stack.push @cwd chdir path notify "dir stack: [#{@dir_stack.join ', '}]" self else if pop = @dir_stack.pop @dir_stack.push @cwd chdir pop notify "dir stack: [#{@dir_stack.join ', '}]" self else Shell.Fail DirStackEmpty end end end alias pushd pushdir def popdir if pop = @dir_stack.pop chdir pop notify "dir stack: [#{@dir_stack.join ', '}]" self else Shell.Fail DirStackEmpty end end alias popd popdir # # process management # def jobs @process_controller.jobs end def kill(sig, command) @process_controller.kill_job(sig, command) end # # command definitions # def Shell.def_system_command(command, path = command) CommandProcessor.def_system_command(command, path) end def Shell.undef_system_command(command) CommandProcessor.undef_system_command(command) end def Shell.alias_command(ali, command, *opts, &block) CommandProcessor.alias_command(ali, command, *opts, &block) end def Shell.unalias_command(ali) CommandProcessor.unalias_command(ali) end def Shell.install_system_commands(pre = "sys_") CommandProcessor.install_system_commands(pre) end # def inspect if debug.kind_of?(Integer) && debug > 2 super else to_s end end def self.notify(*opts, &block) Thread.exclusive do if opts[-1].kind_of?(String) yorn = verbose? else yorn = opts.pop end return unless yorn _head = true print opts.collect{|mes| mes = mes.dup yield mes if iterator? if _head _head = false "shell: " + mes else " " + mes end }.join("\n")+"\n" end end CommandProcessor.initialize CommandProcessor.run_config end PK|]Virb/context.rbnu[# # irb/context.rb - irb context # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "irb/workspace" module IRB class Context # # Arguments: # input_method: nil -- stdin or readline # String -- File # other -- using this as InputMethod # def initialize(irb, workspace = nil, input_method = nil, output_method = nil) @irb = irb if workspace @workspace = workspace else @workspace = WorkSpace.new end @thread = Thread.current if defined? Thread # @irb_level = 0 # copy of default configuration @ap_name = IRB.conf[:AP_NAME] @rc = IRB.conf[:RC] @load_modules = IRB.conf[:LOAD_MODULES] @use_readline = IRB.conf[:USE_READLINE] @inspect_mode = IRB.conf[:INSPECT_MODE] self.math_mode = IRB.conf[:MATH_MODE] if IRB.conf[:MATH_MODE] self.use_tracer = IRB.conf[:USE_TRACER] if IRB.conf[:USE_TRACER] self.use_loader = IRB.conf[:USE_LOADER] if IRB.conf[:USE_LOADER] self.eval_history = IRB.conf[:EVAL_HISTORY] if IRB.conf[:EVAL_HISTORY] @ignore_sigint = IRB.conf[:IGNORE_SIGINT] @ignore_eof = IRB.conf[:IGNORE_EOF] @back_trace_limit = IRB.conf[:BACK_TRACE_LIMIT] self.prompt_mode = IRB.conf[:PROMPT_MODE] if IRB.conf[:SINGLE_IRB] or !defined?(JobManager) @irb_name = IRB.conf[:IRB_NAME] else @irb_name = "irb#"+IRB.JobManager.n_jobs.to_s end @irb_path = "(" + @irb_name + ")" case input_method when nil case use_readline? when nil if (defined?(ReadlineInputMethod) && STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY) @io = ReadlineInputMethod.new else @io = StdioInputMethod.new end when false @io = StdioInputMethod.new when true if defined?(ReadlineInputMethod) @io = ReadlineInputMethod.new else @io = StdioInputMethod.new end end when String @io = FileInputMethod.new(input_method) @irb_name = File.basename(input_method) @irb_path = input_method else @io = input_method end self.save_history = IRB.conf[:SAVE_HISTORY] if IRB.conf[:SAVE_HISTORY] if output_method @output_method = output_method else @output_method = StdioOutputMethod.new end @verbose = IRB.conf[:VERBOSE] @echo = IRB.conf[:ECHO] if @echo.nil? @echo = true end @debug_level = IRB.conf[:DEBUG_LEVEL] end def main @workspace.main end attr_reader :workspace_home attr_accessor :workspace attr_reader :thread attr_accessor :io attr_accessor :irb attr_accessor :ap_name attr_accessor :rc attr_accessor :load_modules attr_accessor :irb_name attr_accessor :irb_path attr_reader :use_readline attr_reader :inspect_mode attr_reader :prompt_mode attr_accessor :prompt_i attr_accessor :prompt_s attr_accessor :prompt_c attr_accessor :prompt_n attr_accessor :auto_indent_mode attr_accessor :return_format attr_accessor :ignore_sigint attr_accessor :ignore_eof attr_accessor :echo attr_accessor :verbose attr_reader :debug_level attr_accessor :back_trace_limit alias use_readline? use_readline alias rc? rc alias ignore_sigint? ignore_sigint alias ignore_eof? ignore_eof alias echo? echo def verbose? if @verbose.nil? if defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod) false elsif !STDIN.tty? or @io.kind_of?(FileInputMethod) true else false end end end def prompting? verbose? || (STDIN.tty? && @io.kind_of?(StdioInputMethod) || (defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod))) end attr_reader :last_value def set_last_value(value) @last_value = value @workspace.evaluate self, "_ = IRB.CurrentContext.last_value" end attr_reader :irb_name def prompt_mode=(mode) @prompt_mode = mode pconf = IRB.conf[:PROMPT][mode] @prompt_i = pconf[:PROMPT_I] @prompt_s = pconf[:PROMPT_S] @prompt_c = pconf[:PROMPT_C] @prompt_n = pconf[:PROMPT_N] @return_format = pconf[:RETURN] if ai = pconf.include?(:AUTO_INDENT) @auto_indent_mode = ai else @auto_indent_mode = IRB.conf[:AUTO_INDENT] end end def inspect? @inspect_mode.nil? or @inspect_mode end def file_input? @io.class == FileInputMethod end def inspect_mode=(opt) if opt @inspect_mode = opt else @inspect_mode = !@inspect_mode end print "Switch to#{unless @inspect_mode; ' non';end} inspect mode.\n" if verbose? @inspect_mode end def use_readline=(opt) @use_readline = opt print "use readline module\n" if @use_readline end def debug_level=(value) @debug_level = value RubyLex.debug_level = value SLex.debug_level = value end def debug? @debug_level > 0 end def evaluate(line, line_no) @line_no = line_no set_last_value(@workspace.evaluate(self, line, irb_path, line_no)) # @workspace.evaluate("_ = IRB.conf[:MAIN_CONTEXT]._") # @_ = @workspace.evaluate(line, irb_path, line_no) end alias __exit__ exit def exit(ret = 0) IRB.irb_exit(@irb, ret) end NOPRINTING_IVARS = ["@last_value"] NO_INSPECTING_IVARS = ["@irb", "@io"] IDNAME_IVARS = ["@prompt_mode"] alias __inspect__ inspect def inspect array = [] for ivar in instance_variables.sort{|e1, e2| e1 <=> e2} name = ivar.sub(/^@(.*)$/){$1} val = instance_eval(ivar) case ivar when *NOPRINTING_IVARS array.push format("conf.%s=%s", name, "...") when *NO_INSPECTING_IVARS array.push format("conf.%s=%s", name, val.to_s) when *IDNAME_IVARS array.push format("conf.%s=:%s", name, val.id2name) else array.push format("conf.%s=%s", name, val.inspect) end end array.join("\n") end alias __to_s__ to_s alias to_s inspect end end PK|]&FF irb/help.rbnu[# # irb/help.rb - print usage module # $Release Version: 0.9.5$ # $Revision: 16857 $ # $Date: 2008-06-06 17:05:24 +0900 (Fri, 06 Jun 2008) $ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # # # module IRB def IRB.print_usage lc = IRB.conf[:LC_MESSAGES] path = lc.find("irb/help-message") space_line = false File.foreach(path) do |l| if /^\s*$/ =~ l lc.puts l unless space_line space_line = true next end space_line = false l.sub!(/#.*$/, "") next if /^\s*$/ =~ l lc.puts l end end end PK|]nXirb/lc/error.rbnu[# # irb/lc/error.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "e2mmap" module IRB # exceptions extend Exception2MessageMapper def_exception :UnrecognizedSwitch, "Unrecognized switch: %s" def_exception :NotImplementedError, "Need to define `%s'" def_exception :CantReturnToNormalMode, "Can't return to normal mode." def_exception :IllegalParameter, "Illegal parameter(%s)." def_exception :IrbAlreadyDead, "Irb is already dead." def_exception :IrbSwitchedToCurrentThread, "Switched to current thread." def_exception :NoSuchJob, "No such job(%s)." def_exception :CantShiftToMultiIrbMode, "Can't shift to multi irb mode." def_exception :CantChangeBinding, "Can't change binding to (%s)." def_exception :UndefinedPromptMode, "Undefined prompt mode(%s)." end PK|]*O..irb/lc/ja/error.rbnu[# # irb/lc/ja/error.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "e2mmap" module IRB # exceptions extend Exception2MessageMapper def_exception :UnrecognizedSwitch, '$B%9%$%C%A(B(%s)$B$,J,$j$^$;$s(B' def_exception :NotImplementedError, '`%s\'$B$NDj5A$,I,MW$G$9(B' def_exception :CantReturnToNormalMode, 'Normal$B%b!<%I$KLa$l$^$;$s(B.' def_exception :IllegalParameter, '$B%Q%i%a!<%?(B(%s)$B$,4V0c$C$F$$$^$9(B.' def_exception :IrbAlreadyDead, 'Irb$B$O4{$K;`$s$G$$$^$9(B.' def_exception :IrbSwitchedToCurrentThread, '$B%+%l%s%H%9%l%C%I$K@Z$jBX$o$j$^$7$?(B.' def_exception :NoSuchJob, '$B$=$N$h$&$J%8%g%V(B(%s)$B$O$"$j$^$;$s(B.' def_exception :CantShiftToMultiIrbMode, 'multi-irb mode$B$K0\$l$^$;$s(B.' def_exception :CantChangeBinding, '$B%P%$%s%G%#%s%0(B(%s)$B$KJQ99$G$-$^$;$s(B.' def_exception :UndefinedPromptMode, '$B%W%m%s%W%H%b!<%I(B(%s)$B$ODj5A$5$l$F$$$^$;$s(B.' end PK|]irb/lc/ja/help-messagenu[# # irb/lc/ja/help-message.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # Usage: irb.rb [options] [programfile] [arguments] -f ~/.irbrc $B$rFI$_9~$^$J$$(B. -m bc$B%b!<%I(B($BJ,?t(B, $B9TNs$N7W;;$,$G$-$k(B) -d $DEBUG $B$r(Btrue$B$K$9$k(B(ruby -d $B$HF1$8(B) -r load-module ruby -r $B$HF1$8(B. -I path $LOAD_PATH $B$K(B path $B$rDI2C$9$k(B. --inspect $B7k2L=PNO$K(Binspect$B$rMQ$$$k(B(bc$B%b!<%I0J30$O%G%U%)%k%H(B). --noinspect $B7k2L=PNO$K(Binspect$B$rMQ$$$J$$(B. --readline readline$B%i%$%V%i%j$rMxMQ$9$k(B. --noreadline readline$B%i%$%V%i%j$rMxMQ$7$J$$(B. --prompt prompt-mode/--prompt-mode prompt-mode $B%W%m%s%W%H%b!<%I$r@ZBX$($^$9(B. $B8=:_Dj5A$5$l$F$$$k%W(B $B%m%s%W%H%b!<%I$O(B, default, simple, xmp, inf-ruby$B$,(B $BMQ0U$5$l$F$$$^$9(B. --inf-ruby-mode emacs$B$N(Binf-ruby-mode$BMQ$N%W%m%s%W%HI=<($r9T$J$&(B. $BFC(B $B$K;XDj$,$J$$8B$j(B, readline$B%i%$%V%i%j$O;H$o$J$/$J$k(B. --simple-prompt $BHs>o$K%7%s%W%k$J%W%m%s%W%H$rMQ$$$k%b!<%I$G$9(B. --noprompt $B%W%m%s%W%HI=<($r9T$J$o$J$$(B. --tracer $B%3%^%s%I irb/ext/tracer.rbnu[# # irb/lib/tracer.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "tracer" module IRB # initialize tracing function def IRB.initialize_tracer Tracer.verbose = false Tracer.add_filter { |event, file, line, id, binding, *rests| /^#{Regexp.quote(@CONF[:IRB_LIB_PATH])}/ !~ file and File::basename(file) != "irb.rb" } end class Context attr_reader :use_tracer alias use_tracer? use_tracer def use_tracer=(opt) if opt Tracer.set_get_line_procs(@irb_path) { |line_no, *rests| @io.line(line_no) } elsif !opt && @use_tracer Tracer.off end @use_tracer=opt end end class WorkSpace alias __evaluate__ evaluate def evaluate(context, statements, file = nil, line = nil) if context.use_tracer? && file != nil && line != nil Tracer.on begin __evaluate__(context, statements, file, line) ensure Tracer.off end else __evaluate__(context, statements, file || __FILE__, line || __LINE__) end end end IRB.initialize_tracer end PK|]  irb/ext/loader.rbnu[# # loader.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB class LoadAbort < Exception;end module IrbLoader @RCS_ID='-$Id: loader.rb 11708 2007-02-12 23:01:19Z shyouhei $-' alias ruby_load load alias ruby_require require def irb_load(fn, priv = nil) path = search_file_from_ruby_path(fn) raise LoadError, "No such file to load -- #{fn}" unless path load_file(path, priv) end def search_file_from_ruby_path(fn) if /^#{Regexp.quote(File::Separator)}/ =~ fn return fn if File.exist?(fn) return nil end for path in $: if File.exist?(f = File.join(path, fn)) return f end end return nil end def source_file(path) irb.suspend_name(path, File.basename(path)) do irb.suspend_input_method(FileInputMethod.new(path)) do |back_io| irb.signal_status(:IN_LOAD) do if back_io.kind_of?(FileInputMethod) irb.eval_input else begin irb.eval_input rescue LoadAbort print "load abort!!\n" end end end end end end def load_file(path, priv = nil) irb.suspend_name(path, File.basename(path)) do if priv ws = WorkSpace.new(Module.new) else ws = WorkSpace.new end irb.suspend_workspace(ws) do irb.suspend_input_method(FileInputMethod.new(path)) do |back_io| irb.signal_status(:IN_LOAD) do # p irb.conf if back_io.kind_of?(FileInputMethod) irb.eval_input else begin irb.eval_input rescue LoadAbort print "load abort!!\n" end end end end end end end def old back_io = @io back_path = @irb_path back_name = @irb_name back_scanner = @irb.scanner begin @io = FileInputMethod.new(path) @irb_name = File.basename(path) @irb_path = path @irb.signal_status(:IN_LOAD) do if back_io.kind_of?(FileInputMethod) @irb.eval_input else begin @irb.eval_input rescue LoadAbort print "load abort!!\n" end end end ensure @io = back_io @irb_name = back_name @irb_path = back_path @irb.scanner = back_scanner end end end end PK|]Girb/ext/change-ws.rbnu[# # irb/ext/cb.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB class Context def home_workspace if defined? @home_workspace @home_workspace else @home_workspace = @workspace end end def change_workspace(*_main) if _main.empty? @workspace = home_workspace return main end @workspace = WorkSpace.new(_main[0]) if !(class< 0 # if hf = IRB.conf[:HISTORY_FILE] # file = File.expand_path(hf) # end # file = IRB.rc_file("_history") unless file # open(file, 'w' ) do |f| # hist = HISTORY.to_a # f.puts(hist[-num..-1] || hist) # end # end # end # end def HistorySavingAbility.extended(obj) # ObjectSpace.define_finalizer(obj, HistorySavingAbility.create_finalizer) IRB.conf[:AT_EXIT].push proc{obj.save_history} obj.load_history obj end def load_history hist = IRB.conf[:HISTORY_FILE] hist = IRB.rc_file("_history") unless hist if File.exist?(hist) open(hist) do |f| f.each {|l| HISTORY << l.chomp} end end end def save_history if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) > 0 if history_file = IRB.conf[:HISTORY_FILE] history_file = File.expand_path(history_file) end history_file = IRB.rc_file("_history") unless history_file open(history_file, 'w' ) do |f| hist = HISTORY.to_a f.puts(hist[-num..-1] || hist) end end end end end PK|]+irb/ext/multi-irb.rbnu[# # irb/multi-irb.rb - multiple irb module # $Release Version: 0.9.5$ # $Revision: 25814 $ # $Date: 2009-11-17 15:51:29 +0900 (Tue, 17 Nov 2009) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # IRB.fail CantShiftToMultiIrbMode unless defined?(Thread) require "thread" module IRB # job management class class JobManager @RCS_ID='-$Id: multi-irb.rb 25814 2009-11-17 06:51:29Z shyouhei $-' def initialize # @jobs = [[thread, irb],...] @jobs = [] @current_job = nil end attr_accessor :current_job def n_jobs @jobs.size end def thread(key) th, irb = search(key) th end def irb(key) th, irb = search(key) irb end def main_thread @jobs[0][0] end def main_irb @jobs[0][1] end def insert(irb) @jobs.push [Thread.current, irb] end def switch(key) th, irb = search(key) IRB.fail IrbAlreadyDead unless th.alive? IRB.fail IrbSwitchedToCurrentThread if th == Thread.current @current_job = irb th.run Thread.stop @current_job = irb(Thread.current) end def kill(*keys) for key in keys th, irb = search(key) IRB.fail IrbAlreadyDead unless th.alive? th.exit end end def search(key) job = case key when Integer @jobs[key] when Irb @jobs.find{|k, v| v.equal?(key)} when Thread @jobs.assoc(key) else @jobs.find{|k, v| v.context.main.equal?(key)} end IRB.fail NoSuchJob, key if job.nil? job end def delete(key) case key when Integer IRB.fail NoSuchJob, key unless @jobs[key] @jobs[key] = nil else catch(:EXISTS) do @jobs.each_index do |i| if @jobs[i] and (@jobs[i][0] == key || @jobs[i][1] == key || @jobs[i][1].context.main.equal?(key)) @jobs[i] = nil throw :EXISTS end end IRB.fail NoSuchJob, key end end until assoc = @jobs.pop; end unless @jobs.empty? @jobs.push assoc end def inspect ary = [] @jobs.each_index do |i| th, irb = @jobs[i] next if th.nil? if th.alive? if th.stop? t_status = "stop" else t_status = "running" end else t_status = "exited" end ary.push format("#%d->%s on %s (%s: %s)", i, irb.context.irb_name, irb.context.main, th, t_status) end ary.join("\n") end end @JobManager = JobManager.new def IRB.JobManager @JobManager end def IRB.CurrentContext IRB.JobManager.irb(Thread.current).context end # invoke multi-irb def IRB.irb(file = nil, *main) workspace = WorkSpace.new(*main) parent_thread = Thread.current Thread.start do begin irb = Irb.new(workspace, file) rescue print "Subirb can't start with context(self): ", workspace.main.inspect, "\n" print "return to main irb\n" Thread.pass Thread.main.wakeup Thread.exit end @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] @JobManager.insert(irb) @JobManager.current_job = irb begin system_exit = false catch(:IRB_EXIT) do irb.eval_input end rescue SystemExit system_exit = true raise #fail ensure unless system_exit @JobManager.delete(irb) if parent_thread.alive? @JobManager.current_job = @JobManager.irb(parent_thread) parent_thread.run else @JobManager.current_job = @JobManager.main_irb @JobManager.main_thread.run end end end end Thread.stop @JobManager.current_job = @JobManager.irb(Thread.current) end # class Context # def set_last_value(value) # @last_value = value # @workspace.evaluate "_ = IRB.JobManager.irb(Thread.current).context.last_value" # if @eval_history #and !@__.equal?(@last_value) # @eval_history_values.push @line_no, @last_value # @workspace.evaluate "__ = IRB.JobManager.irb(Thread.current).context.instance_eval{@eval_history_values}" # end # @last_value # end # end # module ExtendCommand # def irb_context # IRB.JobManager.irb(Thread.current).context # end # # alias conf irb_context # end @CONF[:SINGLE_IRB_MODE] = false @JobManager.insert(@CONF[:MAIN_CONTEXT].irb) @JobManager.current_job = @CONF[:MAIN_CONTEXT].irb class Irb def signal_handle unless @context.ignore_sigint? print "\nabort!!\n" if @context.verbose? exit end case @signal_status when :IN_INPUT print "^C\n" IRB.JobManager.thread(self).raise RubyLex::TerminateLineInput when :IN_EVAL IRB.irb_abort(self) when :IN_LOAD IRB.irb_abort(self, LoadAbort) when :IN_IRB # ignore else # ignore other cases as well end end end trap("SIGINT") do @JobManager.current_job.signal_handle Thread.stop end end PK|]I|SSirb/ext/use-loader.rbnu[# # use-loader.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "irb/cmd/load" require "irb/ext/loader" class Object alias __original__load__IRB_use_loader__ load alias __original__require__IRB_use_loader__ require end module IRB module ExtendCommandBundle def irb_load(*opts, &b) ExtendCommand::Load.execute(irb_context, *opts, &b) end def irb_require(*opts, &b) ExtendCommand::Require.execute(irb_context, *opts, &b) end end class Context IRB.conf[:USE_LOADER] = false def use_loader IRB.conf[:USE_LOADER] end alias use_loader? use_loader def use_loader=(opt) if IRB.conf[:USE_LOADER] != opt IRB.conf[:USE_LOADER] = opt if opt if !$".include?("irb/cmd/load") end (class<<@workspace.main;self;end).instance_eval { alias_method :load, :irb_load alias_method :require, :irb_require } else (class<<@workspace.main;self;end).instance_eval { alias_method :load, :__original__load__IRB_use_loader__ alias_method :require, :__original__require__IRB_use_loader__ } end end print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose? opt end end end PK|]irb/ext/workspaces.rbnu[# # push-ws.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB class Context def irb_level workspace_stack.size end def workspaces if defined? @workspaces @workspaces else @workspaces = [] end end def push_workspace(*_main) if _main.empty? if workspaces.empty? print "No other workspace\n" return nil end ws = workspaces.pop workspaces.push @workspace @workspace = ws return workspaces end workspaces.push @workspace @workspace = WorkSpace.new(@workspace.binding, _main[0]) if !(class<= 0 @contents.find{|no, val| no == idx}[1] else @contents[idx][1] end rescue NameError nil end end def push(no, val) @contents.push [no, val] @contents.shift if @size != 0 && @contents.size > @size end alias real_inspect inspect def inspect if @contents.empty? return real_inspect end unless (last = @contents.pop)[1].equal?(self) @contents.push last last = nil end str = @contents.collect{|no, val| if val.equal?(self) "#{no} ...self-history..." else "#{no} #{val.inspect}" end }.join("\n") if str == "" str = "Empty." end @contents.push last if last str end end end PK|]DmUUirb/ruby-lex.rbnu[# # irb/ruby-lex.rb - ruby lexcal analyzer # $Release Version: 0.9.5$ # $Revision: 16857 $ # $Date: 2008-06-06 17:05:24 +0900 (Fri, 06 Jun 2008) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "e2mmap" require "irb/slex" require "irb/ruby-token" class RubyLex @RCS_ID='-$Id: ruby-lex.rb 16857 2008-06-06 08:05:24Z knu $-' extend Exception2MessageMapper def_exception(:AlreadyDefinedToken, "Already defined token(%s)") def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')") def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')") def_exception(:TkReading2TokenDuplicateError, "key duplicate(token_n='%s', key='%s')") def_exception(:SyntaxError, "%s") def_exception(:TerminateLineInput, "Terminate Line Input") include RubyToken class << self attr_accessor :debug_level def debug? @debug_level > 0 end end @debug_level = 0 def initialize lex_init set_input(STDIN) @seek = 0 @exp_line_no = @line_no = 1 @base_char_no = 0 @char_no = 0 @rests = [] @readed = [] @here_readed = [] @indent = 0 @indent_stack = [] @lex_state = EXPR_BEG @space_seen = false @here_header = false @continue = false @line = "" @skip_space = false @readed_auto_clean_up = false @exception_on_syntax_error = true @prompt = nil end attr_accessor :skip_space attr_accessor :readed_auto_clean_up attr_accessor :exception_on_syntax_error attr_reader :seek attr_reader :char_no attr_reader :line_no attr_reader :indent # io functions def set_input(io, p = nil, &block) @io = io if p.respond_to?(:call) @input = p elsif block_given? @input = block else @input = Proc.new{@io.gets} end end def get_readed if idx = @readed.reverse.index("\n") @base_char_no = idx else @base_char_no += @readed.size end readed = @readed.join("") @readed = [] readed end def getc while @rests.empty? # return nil unless buf_input @rests.push nil unless buf_input end c = @rests.shift if @here_header @here_readed.push c else @readed.push c end @seek += 1 if c == "\n" @line_no += 1 @char_no = 0 else @char_no += 1 end c end def gets l = "" while c = getc l.concat(c) break if c == "\n" end return nil if l == "" and c.nil? l end def eof? @io.eof? end def getc_of_rests if @rests.empty? nil else getc end end def ungetc(c = nil) if @here_readed.empty? c2 = @readed.pop else c2 = @here_readed.pop end c = c2 unless c @rests.unshift c #c = @seek -= 1 if c == "\n" @line_no -= 1 if idx = @readed.reverse.index("\n") @char_no = @readed.size - idx else @char_no = @base_char_no + @readed.size end else @char_no -= 1 end end def peek_equal?(str) chrs = str.split(//) until @rests.size >= chrs.size return false unless buf_input end @rests[0, chrs.size] == chrs end def peek_match?(regexp) while @rests.empty? return false unless buf_input end regexp =~ @rests.join("") end def peek(i = 0) while @rests.size <= i return nil unless buf_input end @rests[i] end def buf_input prompt line = @input.call return nil unless line @rests.concat line.split(//) true end private :buf_input def set_prompt(p = nil, &block) p = block if block_given? if p.respond_to?(:call) @prompt = p else @prompt = Proc.new{print p} end end def prompt if @prompt @prompt.call(@ltype, @indent, @continue, @line_no) end end def initialize_input @ltype = nil @quoted = nil @indent = 0 @indent_stack = [] @lex_state = EXPR_BEG @space_seen = false @here_header = false @continue = false prompt @line = "" @exp_line_no = @line_no end def each_top_level_statement initialize_input catch(:TERM_INPUT) do loop do begin @continue = false prompt unless l = lex throw :TERM_INPUT if @line == '' else #p l @line.concat l if @ltype or @continue or @indent > 0 next end end if @line != "\n" yield @line, @exp_line_no end break unless l @line = '' @exp_line_no = @line_no @indent = 0 @indent_stack = [] prompt rescue TerminateLineInput initialize_input prompt get_readed end end end end def lex until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) && !@continue or tk.nil?) #p tk #p @lex_state #p self end line = get_readed # print self.inspect if line == "" and tk.kind_of?(TkEND_OF_SCRIPT) || tk.nil? nil else line end end def token # require "tracer" # Tracer.on @prev_seek = @seek @prev_line_no = @line_no @prev_char_no = @char_no begin begin tk = @OP.match(self) @space_seen = tk.kind_of?(TkSPACE) rescue SyntaxError raise if @exception_on_syntax_error tk = TkError.new(@seek, @line_no, @char_no) end end while @skip_space and tk.kind_of?(TkSPACE) if @readed_auto_clean_up get_readed end # Tracer.off tk end ENINDENT_CLAUSE = [ "case", "class", "def", "do", "for", "if", "module", "unless", "until", "while", "begin" #, "when" ] DEINDENT_CLAUSE = ["end" #, "when" ] PERCENT_LTYPE = { "q" => "\'", "Q" => "\"", "x" => "\`", "r" => "/", "w" => "]", "W" => "]", "s" => ":" } PERCENT_PAREN = { "{" => "}", "[" => "]", "<" => ">", "(" => ")" } Ltype2Token = { "\'" => TkSTRING, "\"" => TkSTRING, "\`" => TkXSTRING, "/" => TkREGEXP, "]" => TkDSTRING, ":" => TkSYMBOL } DLtype2Token = { "\"" => TkDSTRING, "\`" => TkDXSTRING, "/" => TkDREGEXP, } def lex_init() @OP = IRB::SLex.new @OP.def_rules("\0", "\004", "\032") do |op, io| Token(TkEND_OF_SCRIPT) end @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |op, io| @space_seen = true while getc =~ /[ \t\f\r\13]/; end ungetc Token(TkSPACE) end @OP.def_rule("#") do |op, io| identify_comment end @OP.def_rule("=begin", proc{|op, io| @prev_char_no == 0 && peek(0) =~ /\s/}) do |op, io| @ltype = "=" until getc == "\n"; end until peek_equal?("=end") && peek(4) =~ /\s/ until getc == "\n"; end end gets @ltype = nil Token(TkRD_COMMENT) end @OP.def_rule("\n") do |op, io| print "\\n\n" if RubyLex.debug? case @lex_state when EXPR_BEG, EXPR_FNAME, EXPR_DOT @continue = true else @continue = false @lex_state = EXPR_BEG until (@indent_stack.empty? || [TkLPAREN, TkLBRACK, TkLBRACE, TkfLPAREN, TkfLBRACK, TkfLBRACE].include?(@indent_stack.last)) @indent_stack.pop end end @here_header = false @here_readed = [] Token(TkNL) end @OP.def_rules("*", "**", "=", "==", "===", "=~", "<=>", "<", "<=", ">", ">=", ">>") do |op, io| case @lex_state when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end Token(op) end @OP.def_rules("!", "!=", "!~") do |op, io| @lex_state = EXPR_BEG Token(op) end @OP.def_rules("<<") do |op, io| tk = nil if @lex_state != EXPR_END && @lex_state != EXPR_CLASS && (@lex_state != EXPR_ARG || @space_seen) c = peek(0) if /\S/ =~ c && (/["'`]/ =~ c || /[\w_]/ =~ c || c == "-") tk = identify_here_document end end unless tk tk = Token(op) case @lex_state when EXPR_FNAME, EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_BEG end end tk end @OP.def_rules("'", '"') do |op, io| identify_string(op) end @OP.def_rules("`") do |op, io| if @lex_state == EXPR_FNAME @lex_state = EXPR_END Token(op) else identify_string(op) end end @OP.def_rules('?') do |op, io| if @lex_state == EXPR_END @lex_state = EXPR_BEG Token(TkQUESTION) else ch = getc if @lex_state == EXPR_ARG && ch =~ /\s/ ungetc @lex_state = EXPR_BEG; Token(TkQUESTION) else if (ch == '\\') read_escape end @lex_state = EXPR_END Token(TkINTEGER) end end end @OP.def_rules("&", "&&", "|", "||") do |op, io| @lex_state = EXPR_BEG Token(op) end @OP.def_rules("+=", "-=", "*=", "**=", "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do |op, io| @lex_state = EXPR_BEG op =~ /^(.*)=$/ Token(TkOPASGN, $1) end @OP.def_rule("+@", proc{|op, io| @lex_state == EXPR_FNAME}) do |op, io| @lex_state = EXPR_ARG Token(op) end @OP.def_rule("-@", proc{|op, io| @lex_state == EXPR_FNAME}) do |op, io| @lex_state = EXPR_ARG Token(op) end @OP.def_rules("+", "-") do |op, io| catch(:RET) do if @lex_state == EXPR_ARG if @space_seen and peek(0) =~ /[0-9]/ throw :RET, identify_number else @lex_state = EXPR_BEG end elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/ throw :RET, identify_number else @lex_state = EXPR_BEG end Token(op) end end @OP.def_rule(".") do |op, io| @lex_state = EXPR_BEG if peek(0) =~ /[0-9]/ ungetc identify_number else # for "obj.if" etc. @lex_state = EXPR_DOT Token(TkDOT) end end @OP.def_rules("..", "...") do |op, io| @lex_state = EXPR_BEG Token(op) end lex_int2 end def lex_int2 @OP.def_rules("]", "}", ")") do |op, io| @lex_state = EXPR_END @indent -= 1 @indent_stack.pop Token(op) end @OP.def_rule(":") do |op, io| if @lex_state == EXPR_END || peek(0) =~ /\s/ @lex_state = EXPR_BEG Token(TkCOLON) else @lex_state = EXPR_FNAME; Token(TkSYMBEG) end end @OP.def_rule("::") do |op, io| # p @lex_state.id2name, @space_seen if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen @lex_state = EXPR_BEG Token(TkCOLON3) else @lex_state = EXPR_DOT Token(TkCOLON2) end end @OP.def_rule("/") do |op, io| if @lex_state == EXPR_BEG || @lex_state == EXPR_MID identify_string(op) elsif peek(0) == '=' getc @lex_state = EXPR_BEG Token(TkOPASGN, "/") #/) elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ identify_string(op) else @lex_state = EXPR_BEG Token("/") #/) end end @OP.def_rules("^") do |op, io| @lex_state = EXPR_BEG Token("^") end # @OP.def_rules("^=") do # @lex_state = EXPR_BEG # Token(OP_ASGN, :^) # end @OP.def_rules(",") do |op, io| @lex_state = EXPR_BEG Token(op) end @OP.def_rules(";") do |op, io| @lex_state = EXPR_BEG until (@indent_stack.empty? || [TkLPAREN, TkLBRACK, TkLBRACE, TkfLPAREN, TkfLBRACK, TkfLBRACE].include?(@indent_stack.last)) @indent_stack.pop end Token(op) end @OP.def_rule("~") do |op, io| @lex_state = EXPR_BEG Token("~") end @OP.def_rule("~@", proc{|op, io| @lex_state == EXPR_FNAME}) do |op, io| @lex_state = EXPR_BEG Token("~") end @OP.def_rule("(") do |op, io| @indent += 1 if @lex_state == EXPR_BEG || @lex_state == EXPR_MID @lex_state = EXPR_BEG tk_c = TkfLPAREN else @lex_state = EXPR_BEG tk_c = TkLPAREN end @indent_stack.push tk_c tk = Token(tk_c) end @OP.def_rule("[]", proc{|op, io| @lex_state == EXPR_FNAME}) do |op, io| @lex_state = EXPR_ARG Token("[]") end @OP.def_rule("[]=", proc{|op, io| @lex_state == EXPR_FNAME}) do |op, io| @lex_state = EXPR_ARG Token("[]=") end @OP.def_rule("[") do |op, io| @indent += 1 if @lex_state == EXPR_FNAME tk_c = TkfLBRACK else if @lex_state == EXPR_BEG || @lex_state == EXPR_MID tk_c = TkLBRACK elsif @lex_state == EXPR_ARG && @space_seen tk_c = TkLBRACK else tk_c = TkfLBRACK end @lex_state = EXPR_BEG end @indent_stack.push tk_c Token(tk_c) end @OP.def_rule("{") do |op, io| @indent += 1 if @lex_state != EXPR_END && @lex_state != EXPR_ARG tk_c = TkLBRACE else tk_c = TkfLBRACE end @lex_state = EXPR_BEG @indent_stack.push tk_c Token(tk_c) end @OP.def_rule('\\') do |op, io| if getc == "\n" @space_seen = true @continue = true Token(TkSPACE) else ungetc Token("\\") end end @OP.def_rule('%') do |op, io| if @lex_state == EXPR_BEG || @lex_state == EXPR_MID identify_quotation elsif peek(0) == '=' getc Token(TkOPASGN, :%) elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ identify_quotation else @lex_state = EXPR_BEG Token("%") #)) end end @OP.def_rule('$') do |op, io| identify_gvar end @OP.def_rule('@') do |op, io| if peek(0) =~ /[\w_@]/ ungetc identify_identifier else Token("@") end end # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do # |op, io| # @indent += 1 # @lex_state = EXPR_FNAME # # @lex_state = EXPR_END # # until @rests[0] == "\n" or @rests[0] == ";" # # rests.shift # # end # end @OP.def_rule("") do |op, io| printf "MATCH: start %s: %s\n", op, io.inspect if RubyLex.debug? if peek(0) =~ /[0-9]/ t = identify_number elsif peek(0) =~ /[\w_]/ t = identify_identifier end printf "MATCH: end %s: %s\n", op, io.inspect if RubyLex.debug? t end p @OP if RubyLex.debug? end def identify_gvar @lex_state = EXPR_END case ch = getc when /[~_*$?!@\/\\;,=:<>".]/ #" Token(TkGVAR, "$" + ch) when "-" Token(TkGVAR, "$-" + getc) when "&", "`", "'", "+" Token(TkBACK_REF, "$"+ch) when /[1-9]/ while getc =~ /[0-9]/; end ungetc Token(TkNTH_REF) when /\w/ ungetc ungetc identify_identifier else ungetc Token("$") end end def identify_identifier token = "" if peek(0) =~ /[$@]/ token.concat(c = getc) if c == "@" and peek(0) == "@" token.concat getc end end while (ch = getc) =~ /\w|_/ print ":", ch, ":" if RubyLex.debug? token.concat ch end ungetc if (ch == "!" || ch == "?") && token[0,1] =~ /\w/ && peek(0) != "=" token.concat getc end # almost fix token case token when /^\$/ return Token(TkGVAR, token) when /^\@\@/ @lex_state = EXPR_END # p Token(TkCVAR, token) return Token(TkCVAR, token) when /^\@/ @lex_state = EXPR_END return Token(TkIVAR, token) end if @lex_state != EXPR_DOT print token, "\n" if RubyLex.debug? token_c, *trans = TkReading2Token[token] if token_c # reserved word? if (@lex_state != EXPR_BEG && @lex_state != EXPR_FNAME && trans[1]) # modifiers token_c = TkSymbol2Token[trans[1]] @lex_state = trans[0] else if @lex_state != EXPR_FNAME if ENINDENT_CLAUSE.include?(token) # check for ``class = val'' etc. valid = true case token when "class" valid = false unless peek_match?(/^\s*(<<|\w|::)/) when "def" valid = false if peek_match?(/^\s*(([+-\/*&\|^]|<<|>>|\|\||\&\&)=|\&\&|\|\|)/) when "do" valid = false if peek_match?(/^\s*([+-\/*]?=|\*|<|>|\&)/) when *ENINDENT_CLAUSE valid = false if peek_match?(/^\s*([+-\/*]?=|\*|<|>|\&|\|)/) else # no nothing end if valid if token == "do" if ![TkFOR, TkWHILE, TkUNTIL].include?(@indent_stack.last) @indent += 1 @indent_stack.push token_c end else @indent += 1 @indent_stack.push token_c end # p @indent_stack end elsif DEINDENT_CLAUSE.include?(token) @indent -= 1 @indent_stack.pop end @lex_state = trans[0] else @lex_state = EXPR_END end end return Token(token_c, token) end end if @lex_state == EXPR_FNAME @lex_state = EXPR_END if peek(0) == '=' token.concat getc end elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_END end if token[0, 1] =~ /[A-Z]/ return Token(TkCONSTANT, token) elsif token[token.size - 1, 1] =~ /[!?]/ return Token(TkFID, token) else return Token(TkIDENTIFIER, token) end end def identify_here_document ch = getc # if lt = PERCENT_LTYPE[ch] if ch == "-" ch = getc indent = true end if /['"`]/ =~ ch lt = ch quoted = "" while (c = getc) && c != lt quoted.concat c end else lt = '"' quoted = ch.dup while (c = getc) && c =~ /\w/ quoted.concat c end ungetc end ltback, @ltype = @ltype, lt reserve = [] while ch = getc reserve.push ch if ch == "\\" reserve.push ch = getc elsif ch == "\n" break end end @here_header = false while l = gets l = l.sub(/(:?\r)?\n\z/, '') if (indent ? l.strip : l) == quoted break end end @here_header = true @here_readed.concat reserve while ch = reserve.pop ungetc ch end @ltype = ltback @lex_state = EXPR_END Token(Ltype2Token[lt]) end def identify_quotation ch = getc if lt = PERCENT_LTYPE[ch] ch = getc elsif ch =~ /\W/ lt = "\"" else RubyLex.fail SyntaxError, "unknown type of %string" end # if ch !~ /\W/ # ungetc # next # end #@ltype = lt @quoted = ch unless @quoted = PERCENT_PAREN[ch] identify_string(lt, @quoted) end def identify_number @lex_state = EXPR_END if peek(0) == "0" && peek(1) !~ /[.eE]/ getc case peek(0) when /[xX]/ ch = getc match = /[0-9a-fA-F_]/ when /[bB]/ ch = getc match = /[01_]/ when /[oO]/ ch = getc match = /[0-7_]/ when /[dD]/ ch = getc match = /[0-9_]/ when /[0-7]/ match = /[0-7_]/ when /[89]/ RubyLex.fail SyntaxError, "Illegal octal digit" else return Token(TkINTEGER) end len0 = true non_digit = false while ch = getc if match =~ ch if ch == "_" if non_digit RubyLex.fail SyntaxError, "trailing `#{ch}' in number" else non_digit = ch end else non_digit = false len0 = false end else ungetc if len0 RubyLex.fail SyntaxError, "numeric literal without digits" end if non_digit RubyLex.fail SyntaxError, "trailing `#{non_digit}' in number" end break end end return Token(TkINTEGER) end type = TkINTEGER allow_point = true allow_e = true non_digit = false while ch = getc case ch when /[0-9]/ non_digit = false when "_" non_digit = ch when allow_point && "." if non_digit RubyLex.fail SyntaxError, "trailing `#{non_digit}' in number" end type = TkFLOAT if peek(0) !~ /[0-9]/ type = TkINTEGER ungetc break end allow_point = false when allow_e && "e", allow_e && "E" if non_digit RubyLex.fail SyntaxError, "trailing `#{non_digit}' in number" end type = TkFLOAT if peek(0) =~ /[+-]/ getc end allow_e = false allow_point = false non_digit = ch else if non_digit RubyLex.fail SyntaxError, "trailing `#{non_digit}' in number" end ungetc break end end Token(type) end def identify_string(ltype, quoted = ltype) @ltype = ltype @quoted = quoted subtype = nil begin nest = 0 while ch = getc if @quoted == ch and nest == 0 break elsif @ltype != "'" && @ltype != "]" && @ltype != ":" and ch == "#" subtype = true elsif ch == '\\' #' read_escape end if PERCENT_PAREN.values.include?(@quoted) if PERCENT_PAREN[ch] == @quoted nest += 1 elsif ch == @quoted nest -= 1 end end end if @ltype == "/" if peek(0) =~ /i|m|x|o|e|s|u|n/ getc end end if subtype Token(DLtype2Token[ltype]) else Token(Ltype2Token[ltype]) end ensure @ltype = nil @quoted = nil @lex_state = EXPR_END end end def identify_comment @ltype = "#" while ch = getc # if ch == "\\" #" # read_escape # end if ch == "\n" @ltype = nil ungetc break end end return Token(TkCOMMENT) end def read_escape case ch = getc when "\n", "\r", "\f" when "\\", "n", "t", "r", "f", "v", "a", "e", "b", "s" #" when /[0-7]/ ungetc ch 3.times do case ch = getc when /[0-7]/ when nil break else ungetc break end end when "x" 2.times do case ch = getc when /[0-9a-fA-F]/ when nil break else ungetc break end end when "M" if (ch = getc) != '-' ungetc else if (ch = getc) == "\\" #" read_escape end end when "C", "c" #, "^" if ch == "C" and (ch = getc) != "-" ungetc elsif (ch = getc) == "\\" #" read_escape end else # other characters end end end PK|]6| | irb/locale.rbnu[# # irb/locale.rb - internationalization module # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # autoload :Kconv, "kconv" module IRB class Locale @RCS_ID='-$Id: locale.rb 11708 2007-02-12 23:01:19Z shyouhei $-' JPDefaultLocale = "ja" LOCALE_DIR = "/lc/" def initialize(locale = nil) @lang = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] || "C" end attr_reader :lang def lc2kconv(lang) case lang when "ja_JP.ujis", "ja_JP.euc", "ja_JP.eucJP" Kconv::EUC when "ja_JP.sjis", "ja_JP.SJIS" Kconv::SJIS when /ja_JP.utf-?8/i Kconv::UTF8 end end private :lc2kconv def String(mes) mes = super(mes) case @lang when /^ja/ mes = Kconv::kconv(mes, lc2kconv(@lang)) else mes end mes end def format(*opts) String(super(*opts)) end def gets(*rs) String(super(*rs)) end def readline(*rs) String(super(*rs)) end def print(*opts) ary = opts.collect{|opt| String(opt)} super(*ary) end def printf(*opts) s = format(*opts) print s end def puts(*opts) ary = opts.collect{|opt| String(opt)} super(*ary) end def require(file, priv = nil) rex = Regexp.new("lc/#{Regexp.quote(file)}\.(so|o|sl|rb)?") return false if $".find{|f| f =~ rex} case file when /\.rb$/ begin load(file, priv) $".push file return true rescue LoadError end when /\.(so|o|sl)$/ return super end begin load(f = file + ".rb") $".push f #" return true rescue LoadError return ruby_require(file) end end alias toplevel_load load def load(file, priv=nil) dir = File.dirname(file) dir = "" if dir == "." base = File.basename(file) if /^ja(_JP)?$/ =~ @lang back, @lang = @lang, "C" end begin if dir[0] == ?/ #/ lc_path = search_file(dir, base) return real_load(lc_path, priv) if lc_path end for path in $: lc_path = search_file(path + "/" + dir, base) return real_load(lc_path, priv) if lc_path end ensure @lang = back if back end raise LoadError, "No such file to load -- #{file}" end def real_load(path, priv) src = self.String(File.read(path)) if priv eval("self", TOPLEVEL_BINDING).extend(Module.new {eval(src, nil, path)}) else eval(src, TOPLEVEL_BINDING, path) end end private :real_load def find(file , paths = $:) dir = File.dirname(file) dir = "" if dir == "." base = File.basename(file) if dir[0] == ?/ #/ return lc_path = search_file(dir, base) else for path in $: if lc_path = search_file(path + "/" + dir, base) return lc_path end end end nil end def search_file(path, file) if File.exist?(p1 = path + lc_path(file, "C")) if File.exist?(p2 = path + lc_path(file)) return p2 else end return p1 else end nil end private :search_file def lc_path(file = "", lc = @lang) case lc when "C" LOCALE_DIR + file when /^ja/ LOCALE_DIR + "ja/" + file else LOCALE_DIR + @lang + "/" + file end end private :lc_path end end PK|]SWW irb/init.rbnu[# # irb/init.rb - irb initialize module # $Release Version: 0.9.5$ # $Revision: 24483 $ # $Date: 2009-08-09 17:44:15 +0900 (Sun, 09 Aug 2009) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB # initialize config def IRB.setup(ap_path) IRB.init_config(ap_path) IRB.init_error IRB.parse_opts IRB.run_config IRB.load_modules unless @CONF[:PROMPT][@CONF[:PROMPT_MODE]] IRB.fail(UndefinedPromptMode, @CONF[:PROMPT_MODE]) end end # @CONF default setting def IRB.init_config(ap_path) # class instance variables @TRACER_INITIALIZED = false # default configurations unless ap_path and @CONF[:AP_NAME] ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb") end @CONF[:AP_NAME] = File::basename(ap_path, ".rb") @CONF[:IRB_NAME] = "irb" @CONF[:IRB_LIB_PATH] = File.dirname(__FILE__) @CONF[:RC] = true @CONF[:LOAD_MODULES] = [] @CONF[:IRB_RC] = nil @CONF[:MATH_MODE] = false @CONF[:USE_READLINE] = false unless defined?(ReadlineInputMethod) @CONF[:INSPECT_MODE] = nil @CONF[:USE_TRACER] = false @CONF[:USE_LOADER] = false @CONF[:IGNORE_SIGINT] = true @CONF[:IGNORE_EOF] = false @CONF[:ECHO] = nil @CONF[:VERBOSE] = nil @CONF[:EVAL_HISTORY] = nil @CONF[:SAVE_HISTORY] = nil @CONF[:BACK_TRACE_LIMIT] = 16 @CONF[:PROMPT] = { :NULL => { :PROMPT_I => nil, :PROMPT_N => nil, :PROMPT_S => nil, :PROMPT_C => nil, :RETURN => "%s\n" }, :DEFAULT => { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_N => "%N(%m):%03n:%i> ", :PROMPT_S => "%N(%m):%03n:%i%l ", :PROMPT_C => "%N(%m):%03n:%i* ", :RETURN => "=> %s\n" }, :CLASSIC => { :PROMPT_I => "%N(%m):%03n:%i> ", :PROMPT_N => "%N(%m):%03n:%i> ", :PROMPT_S => "%N(%m):%03n:%i%l ", :PROMPT_C => "%N(%m):%03n:%i* ", :RETURN => "%s\n" }, :SIMPLE => { :PROMPT_I => ">> ", :PROMPT_N => ">> ", :PROMPT_S => nil, :PROMPT_C => "?> ", :RETURN => "=> %s\n" }, :INF_RUBY => { :PROMPT_I => "%N(%m):%03n:%i> ", # :PROMPT_N => "%N(%m):%03n:%i> ", :PROMPT_N => nil, :PROMPT_S => nil, :PROMPT_C => nil, :RETURN => "%s\n", :AUTO_INDENT => true }, :XMP => { :PROMPT_I => nil, :PROMPT_N => nil, :PROMPT_S => nil, :PROMPT_C => nil, :RETURN => " ==>%s\n" } } @CONF[:PROMPT_MODE] = (STDIN.tty? ? :DEFAULT : :NULL) @CONF[:AUTO_INDENT] = false @CONF[:CONTEXT_MODE] = 3 # use binding in function on TOPLEVEL_BINDING @CONF[:SINGLE_IRB] = false # @CONF[:LC_MESSAGES] = "en" @CONF[:LC_MESSAGES] = Locale.new @CONF[:AT_EXIT] = [] @CONF[:DEBUG_LEVEL] = 1 end def IRB.init_error @CONF[:LC_MESSAGES].load("irb/error.rb") end FEATURE_IOPT_CHANGE_VERSION = "1.9.0" # option analyzing def IRB.parse_opts load_path = [] while opt = ARGV.shift case opt when "-f" @CONF[:RC] = false when "-m" @CONF[:MATH_MODE] = true when "-d" $DEBUG = true when /^-r(.+)?/ opt = $1 || ARGV.shift @CONF[:LOAD_MODULES].push opt if opt when /^-I(.+)?/ opt = $1 || ARGV.shift load_path.concat(opt.split(File::PATH_SEPARATOR)) if opt when /^-K(.)/ $KCODE = $1 when "--inspect" @CONF[:INSPECT_MODE] = true when "--noinspect" @CONF[:INSPECT_MODE] = false when "--readline" @CONF[:USE_READLINE] = true when "--noreadline" @CONF[:USE_READLINE] = false when "--echo" @CONF[:ECHO] = true when "--noecho" @CONF[:ECHO] = false when "--verbose" @CONF[:VERBOSE] = true when "--noverbose" @CONF[:VERBOSE] = false when "--prompt-mode", "--prompt" prompt_mode = ARGV.shift.upcase.tr("-", "_").intern @CONF[:PROMPT_MODE] = prompt_mode when "--noprompt" @CONF[:PROMPT_MODE] = :NULL when "--inf-ruby-mode" @CONF[:PROMPT_MODE] = :INF_RUBY when "--sample-book-mode", "--simple-prompt" @CONF[:PROMPT_MODE] = :SIMPLE when "--tracer" @CONF[:USE_TRACER] = true when "--back-trace-limit" @CONF[:BACK_TRACE_LIMIT] = ARGV.shift.to_i when "--context-mode" @CONF[:CONTEXT_MODE] = ARGV.shift.to_i when "--single-irb" @CONF[:SINGLE_IRB] = true when "--irb_debug" @CONF[:DEBUG_LEVEL] = ARGV.shift.to_i when "-v", "--version" print IRB.version, "\n" exit 0 when "-h", "--help" require "irb/help" IRB.print_usage exit 0 when /^-/ IRB.fail UnrecognizedSwitch, opt else @CONF[:SCRIPT] = opt $0 = opt break end end if RUBY_VERSION >= FEATURE_IOPT_CHANGE_VERSION load_path.collect! do |path| /\A\.\// =~ path ? path : File.expand_path(path) end end $LOAD_PATH.unshift(*load_path) end # running config def IRB.run_config if @CONF[:RC] begin load rc_file rescue LoadError, Errno::ENOENT rescue print "load error: #{rc_file}\n" print $!.class, ": ", $!, "\n" for err in $@[0, $@.size - 2] print "\t", err, "\n" end end end end IRBRC_EXT = "rc" def IRB.rc_file(ext = IRBRC_EXT) if !@CONF[:RC_NAME_GENERATOR] rc_file_generators do |rcgen| @CONF[:RC_NAME_GENERATOR] ||= rcgen if File.exist?(rcgen.call(IRBRC_EXT)) @CONF[:RC_NAME_GENERATOR] = rcgen break end end end @CONF[:RC_NAME_GENERATOR].call ext end # enumerate possible rc-file base name generators def IRB.rc_file_generators if irbrc = ENV["IRBRC"] yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc} end if home = ENV["HOME"] yield proc{|rc| home+"/.irb#{rc}"} end home = Dir.pwd yield proc{|rc| home+"/.irb#{rc}"} yield proc{|rc| home+"/irb#{rc.sub(/\A_?/, '.')}"} yield proc{|rc| home+"/_irb#{rc}"} yield proc{|rc| home+"/$irb#{rc}"} end # loading modules def IRB.load_modules for m in @CONF[:LOAD_MODULES] begin require m rescue print $@[0], ":", $!.class, ": ", $!, "\n" end end end end PK|]L MMirb/cmd/help.rbnu[# # help.rb - helper using ri # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # # -- # # # require 'rdoc/ri/ri_driver' module IRB module ExtendCommand module Help begin @ri = RiDriver.new rescue SystemExit else def self.execute(context, *names) names.each do |name| begin @ri.get_info_for(name.to_s) rescue RiError puts $!.message end end nil end end end end end PK|]ิirb/cmd/load.rbnu[# # load.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "irb/cmd/nop.rb" require "irb/ext/loader" module IRB module ExtendCommand class Load"], [:TkEQ, TkOp, "=="], [:TkEQQ, TkOp, "==="], [:TkNEQ, TkOp, "!="], [:TkGEQ, TkOp, ">="], [:TkLEQ, TkOp, "<="], [:TkANDOP, TkOp, "&&"], [:TkOROP, TkOp, "||"], [:TkMATCH, TkOp, "=~"], [:TkNMATCH, TkOp, "!~"], [:TkDOT2, TkOp, ".."], [:TkDOT3, TkOp, "..."], [:TkAREF, TkOp, "[]"], [:TkASET, TkOp, "[]="], [:TkLSHFT, TkOp, "<<"], [:TkRSHFT, TkOp, ">>"], [:TkCOLON2, TkOp], [:TkCOLON3, TkOp], # [:OPASGN, TkOp], # +=, -= etc. # [:TkASSOC, TkOp, "=>"], [:TkQUESTION, TkOp, "?"], #? [:TkCOLON, TkOp, ":"], #: [:TkfLPAREN], # func( # [:TkfLBRACK], # func[ # [:TkfLBRACE], # func{ # [:TkSTAR], # *arg [:TkAMPER], # &arg # [:TkSYMBEG], # :SYMBOL [:TkGT, TkOp, ">"], [:TkLT, TkOp, "<"], [:TkPLUS, TkOp, "+"], [:TkMINUS, TkOp, "-"], [:TkMULT, TkOp, "*"], [:TkDIV, TkOp, "/"], [:TkMOD, TkOp, "%"], [:TkBITOR, TkOp, "|"], [:TkBITXOR, TkOp, "^"], [:TkBITAND, TkOp, "&"], [:TkBITNOT, TkOp, "~"], [:TkNOTOP, TkOp, "!"], [:TkBACKQUOTE, TkOp, "`"], [:TkASSIGN, Token, "="], [:TkDOT, Token, "."], [:TkLPAREN, Token, "("], #(exp) [:TkLBRACK, Token, "["], #[arry] [:TkLBRACE, Token, "{"], #{hash} [:TkRPAREN, Token, ")"], [:TkRBRACK, Token, "]"], [:TkRBRACE, Token, "}"], [:TkCOMMA, Token, ","], [:TkSEMICOLON, Token, ";"], [:TkCOMMENT], [:TkRD_COMMENT], [:TkSPACE], [:TkNL], [:TkEND_OF_SCRIPT], [:TkBACKSLASH, TkUnknownChar, "\\"], [:TkAT, TkUnknownChar, "@"], [:TkDOLLAR, TkUnknownChar, "$"], ] # {reading => token_class} # {reading => [token_class, *opt]} TkReading2Token = {} TkSymbol2Token = {} def RubyToken.def_token(token_n, super_token = Token, reading = nil, *opts) token_n = token_n.id2name if token_n.kind_of?(Symbol) if RubyToken.const_defined?(token_n) IRB.fail AlreadyDefinedToken, token_n end token_c = eval("class #{token_n} < #{super_token}; end; #{token_n}") if reading if TkReading2Token[reading] IRB.fail TkReading2TokenDuplicateError, token_n, reading end if opts.empty? TkReading2Token[reading] = [token_c] else TkReading2Token[reading] = [token_c].concat(opts) end end TkSymbol2Token[token_n.intern] = token_c end for defs in TokenDefinitions def_token(*defs) end end PK|]z//irb/version.rbnu[# # irb/version.rb - irb version definition file # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # # # module IRB @RELEASE_VERSION = "0.9.5" @LAST_UPDATE_DATE = "05/04/13" end PK|]shhirb/completion.rbnu[# # irb/completor.rb - # $Release Version: 0.9$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # From Original Idea of shugo@ruby-lang.org # require "readline" module IRB module InputCompletor @RCS_ID='-$Id: completion.rb 11708 2007-02-12 23:01:19Z shyouhei $-' ReservedWords = [ "BEGIN", "END", "alias", "and", "begin", "break", "case", "class", "def", "defined", "do", "else", "elsif", "end", "ensure", "false", "for", "if", "in", "module", "next", "nil", "not", "or", "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", "until", "when", "while", "yield", ] CompletionProc = proc { |input| bind = IRB.conf[:MAIN_CONTEXT].workspace.binding # puts "input: #{input}" case input when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp receiver = $1 message = Regexp.quote($2) candidates = Regexp.instance_methods(true) select_message(receiver, message, candidates) when /^([^\]]*\])\.([^.]*)$/ # Array receiver = $1 message = Regexp.quote($2) candidates = Array.instance_methods(true) select_message(receiver, message, candidates) when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash receiver = $1 message = Regexp.quote($2) candidates = Proc.instance_methods(true) | Hash.instance_methods(true) select_message(receiver, message, candidates) when /^(:[^:.]*)$/ # Symbol if Symbol.respond_to?(:all_symbols) sym = $1 candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name} candidates.grep(/^#{sym}/) else [] end when /^::([A-Z][^:\.\(]*)$/ # Absolute Constant or class methods receiver = $1 candidates = Object.constants candidates.grep(/^#{receiver}/).collect{|e| "::" + e} when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/ # Constant or class methods receiver = $1 message = Regexp.quote($4) begin candidates = eval("#{receiver}.constants | #{receiver}.methods", bind) rescue Exception candidates = [] end candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e} when /^(:[^:.]+)\.([^.]*)$/ # Symbol receiver = $1 message = Regexp.quote($2) candidates = Symbol.instance_methods(true) select_message(receiver, message, candidates) when /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/ # Numeric receiver = $1 message = Regexp.quote($5) begin candidates = eval(receiver, bind).methods rescue Exception candidates = [] end select_message(receiver, message, candidates) when /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/ # Numeric(0xFFFF) receiver = $1 message = Regexp.quote($2) begin candidates = eval(receiver, bind).methods rescue Exception candidates = [] end select_message(receiver, message, candidates) when /^(\$[^.]*)$/ candidates = global_variables.grep(Regexp.new(Regexp.quote($1))) # when /^(\$?(\.?[^.]+)+)\.([^.]*)$/ when /^((\.?[^.]+)+)\.([^.]*)$/ # variable receiver = $1 message = Regexp.quote($3) gv = eval("global_variables", bind) lv = eval("local_variables", bind) cv = eval("self.class.constants", bind) if (gv | lv | cv).include?(receiver) # foo.func and foo is local var. candidates = eval("#{receiver}.methods", bind) elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver # Foo::Bar.func begin candidates = eval("#{receiver}.methods", bind) rescue Exception candidates = [] end else # func1.func2 candidates = [] ObjectSpace.each_object(Module){|m| begin name = m.name rescue Exception name = "" end next if name != "IRB::Context" and /^(IRB|SLex|RubyLex|RubyToken)/ =~ name candidates.concat m.instance_methods(false) } candidates.sort! candidates.uniq! end select_message(receiver, message, candidates) when /^\.([^.]*)$/ # unknown(maybe String) receiver = "" message = Regexp.quote($1) candidates = String.instance_methods(true) select_message(receiver, message, candidates) else candidates = eval("methods | private_methods | local_variables | self.class.constants", bind) (candidates|ReservedWords).grep(/^#{Regexp.quote(input)}/) end } Operators = ["%", "&", "*", "**", "+", "-", "/", "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>", "[]", "[]=", "^",] def self.select_message(receiver, message, candidates) candidates.grep(/^#{message}/).collect do |e| case e when /^[a-zA-Z_]/ receiver + "." + e when /^[0-9]/ when *Operators #receiver + " " + e end end end end end if Readline.respond_to?("basic_word_break_characters=") Readline.basic_word_break_characters= " \t\n\"\\'`><=;|&{(" end Readline.completion_append_character = nil Readline.completion_proc = IRB::InputCompletor::CompletionProc PK|]L(EE irb/slex.rbnu[# # irb/slex.rb - simple lex analyzer # $Release Version: 0.9.5$ # $Revision: 16857 $ # $Date: 2008-06-06 17:05:24 +0900 (Fri, 06 Jun 2008) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "e2mmap" require "irb/notifier" module IRB class SLex @RCS_ID='-$Id: slex.rb 16857 2008-06-06 08:05:24Z knu $-' extend Exception2MessageMapper def_exception :ErrNodeNothing, "node nothing" def_exception :ErrNodeAlreadyExists, "node already exists" DOUT = Notifier::def_notifier("SLex::") D_WARN = DOUT::def_notifier(1, "Warn: ") D_DEBUG = DOUT::def_notifier(2, "Debug: ") D_DETAIL = DOUT::def_notifier(4, "Detail: ") DOUT.level = Notifier::D_NOMSG def initialize @head = Node.new("") end def def_rule(token, preproc = nil, postproc = nil, &block) D_DETAIL.pp token postproc = block if block_given? node = create(token, preproc, postproc) end def def_rules(*tokens, &block) if block_given? p = block end for token in tokens def_rule(token, nil, p) end end def preproc(token, proc) node = search(token) node.preproc=proc end #$BMW%A%'%C%/(B? def postproc(token) node = search(token, proc) node.postproc=proc end def search(token) @head.search(token.split(//)) end def create(token, preproc = nil, postproc = nil) @head.create_subnode(token.split(//), preproc, postproc) end def match(token) case token when Array when String return match(token.split(//)) else return @head.match_io(token) end ret = @head.match(token) D_DETAIL.exec_if{D_DEATIL.printf "match end: %s:%s\n", ret, token.inspect} ret end def inspect format("", @head.inspect) end #---------------------------------------------------------------------- # # class Node - # #---------------------------------------------------------------------- class Node # if postproc is nil, this node is an abstract node. # if postproc is non-nil, this node is a real node. def initialize(preproc = nil, postproc = nil) @Tree = {} @preproc = preproc @postproc = postproc end attr_accessor :preproc attr_accessor :postproc def search(chrs, opt = nil) return self if chrs.empty? ch = chrs.shift if node = @Tree[ch] node.search(chrs, opt) else if opt chrs.unshift ch self.create_subnode(chrs) else SLex.fail ErrNodeNothing end end end def create_subnode(chrs, preproc = nil, postproc = nil) if chrs.empty? if @postproc D_DETAIL.pp node SLex.fail ErrNodeAlreadyExists else D_DEBUG.puts "change abstract node to real node." @preproc = preproc @postproc = postproc end return self end ch = chrs.shift if node = @Tree[ch] if chrs.empty? if node.postproc DebugLogger.pp node DebugLogger.pp self DebugLogger.pp ch DebugLogger.pp chrs SLex.fail ErrNodeAlreadyExists else D_WARN.puts "change abstract node to real node" node.preproc = preproc node.postproc = postproc end else node.create_subnode(chrs, preproc, postproc) end else if chrs.empty? node = Node.new(preproc, postproc) else node = Node.new node.create_subnode(chrs, preproc, postproc) end @Tree[ch] = node end node end # # chrs: String # character array # io must have getc()/ungetc(); and ungetc() must be # able to be called arbitrary number of times. # def match(chrs, op = "") D_DETAIL.print "match>: ", chrs, "op:", op, "\n" if chrs.empty? if @preproc.nil? || @preproc.call(op, chrs) DOUT.printf(D_DETAIL, "op1: %s\n", op) @postproc.call(op, chrs) else nil end else ch = chrs.shift if node = @Tree[ch] if ret = node.match(chrs, op+ch) return ret else chrs.unshift ch if @postproc and @preproc.nil? || @preproc.call(op, chrs) DOUT.printf(D_DETAIL, "op2: %s\n", op.inspect) ret = @postproc.call(op, chrs) return ret else return nil end end else chrs.unshift ch if @postproc and @preproc.nil? || @preproc.call(op, chrs) DOUT.printf(D_DETAIL, "op3: %s\n", op) @postproc.call(op, chrs) return "" else return nil end end end end def match_io(io, op = "") if op == "" ch = io.getc if ch == nil return nil end else ch = io.getc_of_rests end if ch.nil? if @preproc.nil? || @preproc.call(op, io) D_DETAIL.printf("op1: %s\n", op) @postproc.call(op, io) else nil end else if node = @Tree[ch] if ret = node.match_io(io, op+ch) ret else io.ungetc ch if @postproc and @preproc.nil? || @preproc.call(op, io) DOUT.exec_if{D_DETAIL.printf "op2: %s\n", op.inspect} @postproc.call(op, io) else nil end end else io.ungetc ch if @postproc and @preproc.nil? || @preproc.call(op, io) D_DETAIL.printf("op3: %s\n", op) @postproc.call(op, io) else nil end end end end end end end SLex=IRB::SLex if $0 == __FILE__ # Tracer.on case $1 when "1" tr = SLex.new print "0: ", tr.inspect, "\n" tr.def_rule("=") {print "=\n"} print "1: ", tr.inspect, "\n" tr.def_rule("==") {print "==\n"} print "2: ", tr.inspect, "\n" print "case 1:\n" print tr.match("="), "\n" print "case 2:\n" print tr.match("=="), "\n" print "case 3:\n" print tr.match("=>"), "\n" when "2" tr = SLex.new print "0: ", tr.inspect, "\n" tr.def_rule("=") {print "=\n"} print "1: ", tr.inspect, "\n" tr.def_rule("==", proc{false}) {print "==\n"} print "2: ", tr.inspect, "\n" print "case 1:\n" print tr.match("="), "\n" print "case 2:\n" print tr.match("=="), "\n" print "case 3:\n" print tr.match("=>"), "\n" end exit end PK|]S0 0 irb/workspace.rbnu[# # irb/workspace-binding.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # module IRB class WorkSpace # create new workspace. set self to main if specified, otherwise # inherit main from TOPLEVEL_BINDING. def initialize(*main) if main[0].kind_of?(Binding) @binding = main.shift elsif IRB.conf[:SINGLE_IRB] @binding = TOPLEVEL_BINDING else case IRB.conf[:CONTEXT_MODE] when 0 # binding in proc on TOPLEVEL_BINDING @binding = eval("proc{binding}.call", TOPLEVEL_BINDING, __FILE__, __LINE__) when 1 # binding in loaded file require "tempfile" f = Tempfile.open("irb-binding") f.print < def new_alias_name(name, prefix = "__alias_of__", postfix = "__") base_name = "#{prefix}#{name}#{postfix}" all_methods = instance_methods(true) + private_instance_methods(true) same_methods = all_methods.grep(/^#{Regexp.quote(base_name)}[0-9]*$/) return base_name if same_methods.empty? no = same_methods.size while !same_methods.include?(alias_name = base_name + no) no += 1 end alias_name end end end PK|]1Iirb/ws-for-case-2.rbnu[# # irb/ws-for-case-2.rb - # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # while true IRB::BINDING_QUEUE.push b = binding end PK|]--irb/output-method.rbnu[# # output-method.rb - optput methods used by irb # $Release Version: 0.9.5$ # $Revision: 11708 $ # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ # by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # # # require "e2mmap" module IRB # OutputMethod # StdioOutputMethod class OutputMethod @RCS_ID='-$Id: output-method.rb 11708 2007-02-12 23:01:19Z shyouhei $-' def print(*opts) IRB.fail NotImplementError, "print" end def printn(*opts) print opts.join(" "), "\n" end # extend printf def printf(format, *opts) if /(%*)%I/ =~ format format, opts = parse_printf_format(format, opts) end print sprintf(format, *opts) end # % # <ե饰> [#0- +] # <Ǿե> (\*|\*[1-9][0-9]*\$|[1-9][0-9]*) # <>.(\*|\*[1-9][0-9]*\$|[1-9][0-9]*|)? # #<Ĺʸ>(hh|h|l|ll|L|q|j|z|t) # <Ѵʸ>[diouxXeEfgGcsb%] def parse_printf_format(format, opts) return format, opts if $1.size % 2 == 1 end def foo(format) pos = 0 inspects = [] format.scan(/%[#0\-+ ]?(\*(?=[^0-9])|\*[1-9][0-9]*\$|[1-9][0-9]*(?=[^0-9]))?(\.(\*(?=[^0-9])|\*[1-9][0-9]*\$|[1-9][0-9]*(?=[^0-9])))?(([1-9][0-9]*\$)*)([diouxXeEfgGcsb%])/) {|f, p, pp, pos, new_pos, c| puts [f, p, pp, pos, new_pos, c].join("!") pos = new_pos if new_pos if c == "I" inspects.push pos.to_i (f||"")+(p||"")+(pp||"")+(pos||"")+"s" else $& end } end def puts(*objs) for obj in objs print(*obj) print "\n" end end def pp(*objs) puts(*objs.collect{|obj| obj.inspect}) end def ppx(prefix, *objs) puts(*objs.collect{|obj| prefix+obj.inspect}) end end class StdioOutputMethod(other) @level <=> other.level end def notify? @base_notifier.level >= self end end class NoMsgNotifier # # Contact: # - Akinori MUSHA (current maintainer) # module Shellwords # # Splits a string into an array of tokens in the same way the UNIX # Bourne shell does. # # argv = Shellwords.split('here are "two words"') # argv #=> ["here", "are", "two words"] # # +String#shellsplit+ is a shorthand for this function. # # argv = 'here are "two words"'.shellsplit # argv #=> ["here", "are", "two words"] # def shellsplit(line) line = String.new(line) rescue raise(ArgumentError, "Argument must be a string") line.lstrip! words = [] until line.empty? field = '' loop do if line.sub!(/\A"(([^"\\]|\\.)*)"/, '') then snippet = $1.gsub(/\\(.)/, '\1') elsif line =~ /\A"/ then raise ArgumentError, "Unmatched double quote: #{line}" elsif line.sub!(/\A'([^']*)'/, '') then snippet = $1 elsif line =~ /\A'/ then raise ArgumentError, "Unmatched single quote: #{line}" elsif line.sub!(/\A\\(.)?/, '') then snippet = $1 || '\\' elsif line.sub!(/\A([^\s\\'"]+)/, '') then snippet = $1 else line.lstrip! break end field.concat(snippet) end words.push(field) end words end alias shellwords shellsplit module_function :shellsplit, :shellwords class << self alias split shellsplit end # # Escapes a string so that it can be safely used in a Bourne shell # command line. # # Note that a resulted string should be used unquoted and is not # intended for use in double quotes nor in single quotes. # # open("| grep #{Shellwords.escape(pattern)} file") { |pipe| # # ... # } # # +String#shellescape+ is a shorthand for this function. # # open("| grep #{pattern.shellescape} file") { |pipe| # # ... # } # def shellescape(str) # An empty argument will be skipped, so return empty quotes. return "''" if str.empty? str = str.dup # Process as a single byte sequence because not all shell # implementations are multibyte aware. str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1") # A LF cannot be escaped with a backslash because a backslash + LF # combo is regarded as line continuation and simply ignored. str.gsub!(/\n/, "'\n'") return str end module_function :shellescape class << self alias escape shellescape end # # Builds a command line string from an argument list +array+ joining # all elements escaped for Bourne shell and separated by a space. # # open('|' + Shellwords.join(['grep', pattern, *files])) { |pipe| # # ... # } # # +Array#shelljoin+ is a shorthand for this function. # # open('|' + ['grep', pattern, *files].shelljoin) { |pipe| # # ... # } # def shelljoin(array) array.map { |arg| shellescape(arg) }.join(' ') end module_function :shelljoin class << self alias join shelljoin end end class String # # call-seq: # str.shellsplit => array # # Splits +str+ into an array of tokens in the same way the UNIX # Bourne shell does. See +Shellwords::shellsplit+ for details. # def shellsplit Shellwords.split(self) end # # call-seq: # str.shellescape => string # # Escapes +str+ so that it can be safely used in a Bourne shell # command line. See +Shellwords::shellescape+ for details. # def shellescape Shellwords.escape(self) end end class Array # # call-seq: # array.shelljoin => string # # Builds a command line string from an argument list +array+ joining # all elements escaped for Bourne shell and separated by a space. # See +Shellwords::shelljoin+ for details. # def shelljoin Shellwords.join(self) end end PK|]_ttxmlrpc/datetime.rbnu[=begin = xmlrpc/datetime.rb Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) Released under the same term of license as Ruby. = Classes * (()) = XMLRPC::DateTime == Description This class is important to handle XMLRPC (('dateTime.iso8601')) values, correcly, because normal UNIX-dates (class (({Date}))) only handle dates from year 1970 on, and class (({Time})) handles dates without the time component. (({XMLRPC::DateTime})) is able to store a XMLRPC (('dateTime.iso8601')) value correctly. == Class Methods --- XMLRPC::DateTime.new( year, month, day, hour, min, sec ) Creates a new (({XMLRPC::DateTime})) instance with the parameters ((|year|)), ((|month|)), ((|day|)) as date and ((|hour|)), ((|min|)), ((|sec|)) as time. Raises (({ArgumentError})) if a parameter is out of range, or ((|year|)) is not of type (({Integer})). == Instance Methods --- XMLRPC::DateTime#year --- XMLRPC::DateTime#month --- XMLRPC::DateTime#day --- XMLRPC::DateTime#hour --- XMLRPC::DateTime#min --- XMLRPC::DateTime#sec Return the value of the specified date/time component. --- XMLRPC::DateTime#mon Alias for (()). --- XMLRPC::DateTime#year=( value ) --- XMLRPC::DateTime#month=( value ) --- XMLRPC::DateTime#day=( value ) --- XMLRPC::DateTime#hour=( value ) --- XMLRPC::DateTime#min=( value ) --- XMLRPC::DateTime#sec=( value ) Set ((|value|)) as the new date/time component. Raises (({ArgumentError})) if ((|value|)) is out of range, or in the case of (({XMLRPC::DateTime#year=})) if ((|value|)) is not of type (({Integer})). --- XMLRPC::DateTime#mon=( value ) Alias for (()). --- XMLRPC::DateTime#to_time Return a (({Time})) object of the date/time which (({self})) represents. If the (('year')) is below 1970, this method returns (({nil})), because (({Time})) cannot handle years below 1970. The used timezone is GMT. --- XMLRPC::DateTime#to_date Return a (({Date})) object of the date which (({self})) represents. The (({Date})) object do ((*not*)) contain the time component (only date). --- XMLRPC::DateTime#to_a Returns all date/time components in an array. Returns (({[year, month, day, hour, min, sec]})). =end require "date" module XMLRPC class DateTime attr_reader :year, :month, :day, :hour, :min, :sec def year= (value) raise ArgumentError, "date/time out of range" unless value.is_a? Integer @year = value end def month= (value) raise ArgumentError, "date/time out of range" unless (1..12).include? value @month = value end def day= (value) raise ArgumentError, "date/time out of range" unless (1..31).include? value @day = value end def hour= (value) raise ArgumentError, "date/time out of range" unless (0..24).include? value @hour = value end def min= (value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @min = value end def sec= (value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @sec = value end alias mon month alias mon= month= def initialize(year, month, day, hour, min, sec) self.year, self.month, self.day = year, month, day self.hour, self.min, self.sec = hour, min, sec end def to_time if @year >= 1970 Time.gm(*to_a) else nil end end def to_date Date.new(*to_a[0,3]) end def to_a [@year, @month, @day, @hour, @min, @sec] end def ==(o) Array(self) == Array(o) end end end # module XMLRPC =begin = History $Id: datetime.rb 11708 2007-02-12 23:01:19Z shyouhei $ =end PK|]JJxmlrpc/client.rbnu[=begin = xmlrpc/client.rb Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) Released under the same term of license as Ruby. = Classes * (()) * (()) = XMLRPC::Client == Synopsis require "xmlrpc/client" server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) begin param = server.call("michael.add", 4, 5) puts "4 + 5 = #{param}" rescue XMLRPC::FaultException => e puts "Error:" puts e.faultCode puts e.faultString end or require "xmlrpc/client" server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) ok, param = server.call2("michael.add", 4, 5) if ok then puts "4 + 5 = #{param}" else puts "Error:" puts param.faultCode puts param.faultString end == Description Class (({XMLRPC::Client})) provides remote procedure calls to a XML-RPC server. After setting the connection-parameters with (()) which creates a new (({XMLRPC::Client})) instance, you can execute a remote procedure by sending the (()) or (()) message to this new instance. The given parameters indicate which method to call on the remote-side and of course the parameters for the remote procedure. == Class Methods --- XMLRPC::Client.new( host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=false, timeout =nil) Creates an object which represents the remote XML-RPC server on the given host ((|host|)). If the server is CGI-based, ((|path|)) is the path to the CGI-script, which will be called, otherwise (in the case of a standalone server) ((|path|)) should be (({"/RPC2"})). ((|port|)) is the port on which the XML-RPC server listens. If ((|proxy_host|)) is given, then a proxy server listening at ((|proxy_host|)) is used. ((|proxy_port|)) is the port of the proxy server. Default values for ((|host|)), ((|path|)) and ((|port|)) are 'localhost', '/RPC2' and '80' respectively using SSL '443'. If ((|user|)) and ((|password|)) are given, each time a request is send, a Authorization header is send. Currently only Basic Authentification is implemented no Digest. If ((|use_ssl|)) is set to (({true})), comunication over SSL is enabled. Note, that you need the SSL package from RAA installed. Parameter ((|timeout|)) is the time to wait for a XML-RPC response, defaults to 30. --- XMLRPC::Client.new2( uri, proxy=nil, timeout=nil) --- XMLRPC::Client.new_from_uri( uri, proxy=nil, timeout=nil) : uri URI specifying protocol (http or https), host, port, path, user and password. Example: https://user:password@host:port/path : proxy Is of the form "host:port". : timeout Defaults to 30. --- XMLRPC::Client.new3( hash={} ) --- XMLRPC::Client.new_from_hash( hash={} ) Parameter ((|hash|)) has following case-insensitive keys: * host * path * port * proxy_host * proxy_port * user * password * use_ssl * timeout Calls (()) with the corresponding values. == Instance Methods --- XMLRPC::Client#call( method, *args ) Invokes the method named ((|method|)) with the parameters given by ((|args|)) on the XML-RPC server. The parameter ((|method|)) is converted into a (({String})) and should be a valid XML-RPC method-name. Each parameter of ((|args|)) must be of one of the following types, where (({Hash})), (({Struct})) and (({Array})) can contain any of these listed ((:types:)): * (({Fixnum})), (({Bignum})) * (({TrueClass})), (({FalseClass})) ((({true})), (({false}))) * (({String})), (({Symbol})) * (({Float})) * (({Hash})), (({Struct})) * (({Array})) * (({Date})), (({Time})), (({XMLRPC::DateTime})) * (({XMLRPC::Base64})) * A Ruby object which class includes XMLRPC::Marshallable (only if Config::ENABLE_MARSHALLABLE is (({true}))). That object is converted into a hash, with one additional key/value pair "___class___" which contains the class name for restoring later that object. The method returns the return-value from the RPC ((-stands for Remote Procedure Call-)). The type of the return-value is one of the above shown, only that a (({Bignum})) is only allowed when it fits in 32-bit and that a XML-RPC (('dateTime.iso8601')) type is always returned as a ((<(({XMLRPC::DateTime}))|URL:datetime.html>)) object and a (({Struct})) is never returned, only a (({Hash})), the same for a (({Symbol})), where always a (({String})) is returned. A (({XMLRPC::Base64})) is returned as a (({String})) from xmlrpc4r version 1.6.1 on. If the remote procedure returned a fault-structure, then a (({XMLRPC::FaultException})) exception is raised, which has two accessor-methods (({faultCode})) and (({faultString})) of type (({Integer})) and (({String})). --- XMLRPC::Client#call2( method, *args ) The difference between this method and (()) is, that this method do ((*not*)) raise a (({XMLRPC::FaultException})) exception. The method returns an array of two values. The first value indicates if the second value is a return-value ((({true}))) or an object of type (({XMLRPC::FaultException})). Both are explained in (()). Simple to remember: The "2" in "call2" denotes the number of values it returns. --- XMLRPC::Client#multicall( *methods ) You can use this method to execute several methods on a XMLRPC server which supports the multi-call extension. Example: s.multicall( ['michael.add', 3, 4], ['michael.sub', 4, 5] ) # => [7, -1] --- XMLRPC::Client#multicall2( *methods ) Same as (()), but returns like (()) two parameters instead of raising an (({XMLRPC::FaultException})). --- XMLRPC::Client#proxy( prefix, *args ) Returns an object of class (({XMLRPC::Client::Proxy})), initialized with ((|prefix|)) and ((|args|)). A proxy object returned by this method behaves like (()), i.e. a call on that object will raise a (({XMLRPC::FaultException})) when a fault-structure is returned by that call. --- XMLRPC::Client#proxy2( prefix, *args ) Almost the same like (()) only that a call on the returned (({XMLRPC::Client::Proxy})) object behaves like (()), i.e. a call on that object will return two parameters. --- XMLRPC::Client#call_async(...) --- XMLRPC::Client#call2_async(...) --- XMLRPC::Client#multicall_async(...) --- XMLRPC::Client#multicall2_async(...) --- XMLRPC::Client#proxy_async(...) --- XMLRPC::Client#proxy2_async(...) In contrast to corresponding methods without "_async", these can be called concurrently and use for each request a new connection, where the non-asynchronous counterparts use connection-alive (one connection for all requests) if possible. Note, that you have to use Threads to call these methods concurrently. The following example calls two methods concurrently: Thread.new { p client.call_async("michael.add", 4, 5) } Thread.new { p client.call_async("michael.div", 7, 9) } --- XMLRPC::Client#timeout --- XMLRPC::Client#user --- XMLRPC::Client#password Return the corresponding attributes. --- XMLRPC::Client#timeout= (new_timeout) --- XMLRPC::Client#user= (new_user) --- XMLRPC::Client#password= (new_password) Set the corresponding attributes. --- XMLRPC::Client#set_writer( writer ) Sets the XML writer to use for generating XML output. Should be an instance of a class from module (({XMLRPC::XMLWriter})). If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used. --- XMLRPC::Client#set_parser( parser ) Sets the XML parser to use for parsing XML documents. Should be an instance of a class from module (({XMLRPC::XMLParser})). If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used. --- XMLRPC::Client#cookie --- XMLRPC::Client#cookie= (cookieString) Get and set the HTTP Cookie header. --- XMLRPC::Client#http_header_extra= (additionalHeaders) Set extra HTTP headers that are included in the request. --- XMLRPC::Client#http_header_extra Access the via (()) assigned header. --- XMLRPC::Client#http_last_response Returns the (({Net::HTTPResponse})) object of the last RPC. = XMLRPC::Client::Proxy == Synopsis require "xmlrpc/client" server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) michael = server.proxy("michael") michael2 = server.proxy("michael", 4) # both calls should return the same value '9'. p michael.add(4,5) p michael2.add(5) == Description Class (({XMLRPC::Client::Proxy})) makes XML-RPC calls look nicer! You can call any method onto objects of that class - the object handles (({method_missing})) and will forward the method call to a XML-RPC server. Don't use this class directly, but use instead method (()) or (()). == Class Methods --- XMLRPC::Client::Proxy.new( server, prefix, args=[], meth=:call, delim="." ) Creates an object which provides (({method_missing})). ((|server|)) must be of type (({XMLRPC::Client})), which is the XML-RPC server to be used for a XML-RPC call. ((|prefix|)) and ((|delim|)) will be prepended to the methodname called onto this object. Parameter ((|meth|)) is the method (call, call2, call_async, call2_async) to use for a RPC. ((|args|)) are arguments which are automatically given to every XML-RPC call before the arguments provides through (({method_missing})). == Instance Methods Every method call is forwarded to the XML-RPC server defined in (()). Note: Inherited methods from class (({Object})) cannot be used as XML-RPC names, because they get around (({method_missing})). = History $Id: client.rb 18091 2008-07-16 17:07:44Z shyouhei $ =end require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" # ParserWriterChooseMixin require "net/http" module XMLRPC class Client USER_AGENT = "XMLRPC::Client (Ruby #{RUBY_VERSION})" include ParserWriterChooseMixin include ParseContentType # Constructors ------------------------------------------------------------------- def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=nil, timeout=nil) @http_header_extra = nil @http_last_response = nil @cookie = nil @host = host || "localhost" @path = path || "/RPC2" @proxy_host = proxy_host @proxy_port = proxy_port @proxy_host ||= 'localhost' if @proxy_port != nil @proxy_port ||= 8080 if @proxy_host != nil @use_ssl = use_ssl || false @timeout = timeout || 30 if use_ssl require "net/https" @port = port || 443 else @port = port || 80 end @user, @password = user, password set_auth # convert ports to integers @port = @port.to_i if @port != nil @proxy_port = @proxy_port.to_i if @proxy_port != nil # HTTP object for synchronous calls Net::HTTP.version_1_2 @http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port) @http.use_ssl = @use_ssl if @use_ssl @http.read_timeout = @timeout @http.open_timeout = @timeout @parser = nil @create = nil end class << self def new2(uri, proxy=nil, timeout=nil) if match = /^([^:]+):\/\/(([^@]+)@)?([^\/]+)(\/.*)?$/.match(uri) proto = match[1] user, passwd = (match[3] || "").split(":") host, port = match[4].split(":") path = match[5] if proto != "http" and proto != "https" raise "Wrong protocol specified. Only http or https allowed!" end else raise "Wrong URI as parameter!" end proxy_host, proxy_port = (proxy || "").split(":") self.new(host, path, port, proxy_host, proxy_port, user, passwd, (proto == "https"), timeout) end alias new_from_uri new2 def new3(hash={}) # convert all keys into lowercase strings h = {} hash.each { |k,v| h[k.to_s.downcase] = v } self.new(h['host'], h['path'], h['port'], h['proxy_host'], h['proxy_port'], h['user'], h['password'], h['use_ssl'], h['timeout']) end alias new_from_hash new3 end # Attribute Accessors ------------------------------------------------------------------- # add additional HTTP headers to the request attr_accessor :http_header_extra # makes last HTTP response accessible attr_reader :http_last_response # Cookie support attr_accessor :cookie attr_reader :timeout, :user, :password def timeout=(new_timeout) @timeout = new_timeout @http.read_timeout = @timeout @http.open_timeout = @timeout end def user=(new_user) @user = new_user set_auth end def password=(new_password) @password = new_password set_auth end # Call methods -------------------------------------------------------------- def call(method, *args) ok, param = call2(method, *args) if ok param else raise param end end def call2(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, false) parser().parseMethodResponse(data) end def call_async(method, *args) ok, param = call2_async(method, *args) if ok param else raise param end end def call2_async(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, true) parser().parseMethodResponse(data) end # Multicall methods -------------------------------------------------------------- def multicall(*methods) ok, params = multicall2(*methods) if ok params else raise params end end def multicall2(*methods) gen_multicall(methods, false) end def multicall_async(*methods) ok, params = multicall2_async(*methods) if ok params else raise params end end def multicall2_async(*methods) gen_multicall(methods, true) end # Proxy generating methods ------------------------------------------ def proxy(prefix=nil, *args) Proxy.new(self, prefix, args, :call) end def proxy2(prefix=nil, *args) Proxy.new(self, prefix, args, :call2) end def proxy_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call_async) end def proxy2_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call2_async) end private # ---------------------------------------------------------- def set_auth if @user.nil? @auth = nil else a = "#@user" a << ":#@password" if @password != nil @auth = ("Basic " + [a].pack("m")).chomp end end def do_rpc(request, async=false) header = { "User-Agent" => USER_AGENT, "Content-Type" => "text/xml; charset=utf-8", "Content-Length" => request.size.to_s, "Connection" => (async ? "close" : "keep-alive") } header["Cookie"] = @cookie if @cookie header.update(@http_header_extra) if @http_header_extra if @auth != nil # add authorization header header["Authorization"] = @auth end resp = nil @http_last_response = nil if async # use a new HTTP object for each call Net::HTTP.version_1_2 http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port) http.use_ssl = @use_ssl if @use_ssl http.read_timeout = @timeout http.open_timeout = @timeout # post request http.start { resp = http.post2(@path, request, header) } else # reuse the HTTP object for each call => connection alive is possible # we must start connection explicitely first time so that http.request # does not assume that we don't want keepalive @http.start if not @http.started? # post request resp = @http.post2(@path, request, header) end @http_last_response = resp data = resp.body if resp.code == "401" # Authorization Required raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}" elsif resp.code[0,1] != "2" raise "HTTP-Error: #{resp.code} #{resp.message}" end ct = parse_content_type(resp["Content-Type"]).first if ct != "text/xml" if ct == "text/html" raise "Wrong content-type (received '#{ct}' but expected 'text/xml'): \n#{data}" else raise "Wrong content-type (received '#{ct}' but expected 'text/xml')" end end expected = resp["Content-Length"] || "" if data.nil? or data.size == 0 raise "Wrong size. Was #{data.size}, should be #{expected}" elsif expected != "" and expected.to_i != data.size and resp["Transfer-Encoding"].nil? raise "Wrong size. Was #{data.size}, should be #{expected}" end set_cookies = resp.get_fields("Set-Cookie") if set_cookies and !set_cookies.empty? require 'webrick/cookie' @cookie = set_cookies.collect do |set_cookie| cookie = WEBrick::Cookie.parse_set_cookie(set_cookie) WEBrick::Cookie.new(cookie.name, cookie.value).to_s end.join("; ") end return data end def gen_multicall(methods=[], async=false) meth = :call2 meth = :call2_async if async ok, params = self.send(meth, "system.multicall", methods.collect {|m| {'methodName' => m[0], 'params' => m[1..-1]} } ) if ok params = params.collect do |param| if param.is_a? Array param[0] elsif param.is_a? Hash XMLRPC::FaultException.new(param["faultCode"], param["faultString"]) else raise "Wrong multicall return value" end end end return ok, params end class Proxy def initialize(server, prefix, args=[], meth=:call, delim=".") @server = server @prefix = prefix ? prefix + delim : "" @args = args @meth = meth end def method_missing(mid, *args) pre = @prefix + mid.to_s arg = @args + args @server.send(@meth, pre, *arg) end end # class Proxy end # class Client end # module XMLRPC PK|]K;%HWHWxmlrpc/server.rbnu[=begin = xmlrpc/server.rb Copyright (C) 2001, 2002, 2003, 2005 by Michael Neumann (mneumann@ntecs.de) Released under the same term of license as Ruby. = Classes * (()) * (()) * (()) * (()) * (()) = XMLRPC::BasicServer == Description Is the base class for all XML-RPC server-types (CGI, standalone). You can add handler and set a default handler. Do not use this server, as this is/should be an abstract class. === How the method to call is found The arity (number of accepted arguments) of a handler (method or (({Proc})) object) is compared to the given arguments submitted by the client for a RPC ((-Remote Procedure Call-)). A handler is only called if it accepts the number of arguments, otherwise the search for another handler will go on. When at the end no handler was found, the (()) will be called. With this technique it is possible to do overloading by number of parameters, but only for (({Proc})) handler, because you cannot define two methods of the same name in the same class. == Class Methods --- XMLRPC::BasicServer.new( class_delim="." ) Creates a new (({XMLRPC::BasicServer})) instance, which should not be done, because (({XMLRPC::BasicServer})) is an abstract class. This method should be called from a subclass indirectly by a (({super})) call in the method (({initialize})). The paramter ((|class_delim|)) is used in (()) when an object is added as handler, to delimit the object-prefix and the method-name. == Instance Methods --- XMLRPC::BasicServer#add_handler( name, signature=nil, help=nil ) { aBlock } Adds ((|aBlock|)) to the list of handlers, with ((|name|)) as the name of the method. Parameters ((|signature|)) and ((|help|)) are used by the Introspection method if specified, where ((|signature|)) is either an Array containing strings each representing a type of it's signature (the first is the return value) or an Array of Arrays if the method has multiple signatures. Value type-names are "int, boolean, double, string, dateTime.iso8601, base64, array, struct". Parameter ((|help|)) is a String with informations about how to call this method etc. A handler method or code-block can return the types listed at (()). When a method fails, it can tell it the client by throwing an (({XMLRPC::FaultException})) like in this example: s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end The client gets in the case of (({b==0})) an object back of type (({XMLRPC::FaultException})) that has a ((|faultCode|)) and ((|faultString|)) field. --- XMLRPC::BasicServer#add_handler( prefix, obj ) This is the second form of (()). To add an object write: server.add_handler("michael", MyHandlerClass.new) All public methods of (({MyHandlerClass})) are accessible to the XML-RPC clients by (('michael."name of method"')). This is where the ((|class_delim|)) in (()) has it's role, a XML-RPC method-name is defined by ((|prefix|)) + ((|class_delim|)) + (('"name of method"')). --- XMLRPC::BasicServer#add_handler( interface, obj ) This is the third form of (()). Use (({XMLRPC::interface})) to generate an ServiceInterface object, which represents an interface (with signature and help text) for a handler class. Parameter ((|interface|)) must be of type (({XMLRPC::ServiceInterface})). Adds all methods of ((|obj|)) which are defined in ((|interface|)) to the server. This is the recommended way of adding services to a server! --- XMLRPC::BasicServer#get_default_handler Returns the default-handler, which is called when no handler for a method-name is found. It is a (({Proc})) object or (({nil})). --- XMLRPC::BasicServer#set_default_handler ( &handler ) Sets ((|handler|)) as the default-handler, which is called when no handler for a method-name is found. ((|handler|)) is a code-block. The default-handler is called with the (XML-RPC) method-name as first argument, and the other arguments are the parameters given by the client-call. If no block is specified the default of (({XMLRPC::BasicServer})) is used, which raises a XMLRPC::FaultException saying "method missing". --- XMLRPC::BasicServer#set_writer( writer ) Sets the XML writer to use for generating XML output. Should be an instance of a class from module (({XMLRPC::XMLWriter})). If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used. --- XMLRPC::BasicServer#set_parser( parser ) Sets the XML parser to use for parsing XML documents. Should be an instance of a class from module (({XMLRPC::XMLParser})). If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used. --- XMLRPC::BasicServer#add_introspection Adds the introspection handlers "system.listMethods", "system.methodSignature" and "system.methodHelp", where only the first one works. --- XMLRPC::BasicServer#add_multicall Adds the multi-call handler "system.multicall". --- XMLRPC::BasicServer#get_service_hook Returns the service-hook, which is called on each service request (RPC) unless it's (({nil})). --- XMLRPC::BasicServer#set_service_hook ( &handler ) A service-hook is called for each service request (RPC). You can use a service-hook for example to wrap existing methods and catch exceptions of them or convert values to values recognized by XMLRPC. You can disable it by passing (({nil})) as parameter ((|handler|)) . The service-hook is called with a (({Proc})) object and with the parameters for this (({Proc})). An example: server.set_service_hook {|obj, *args| begin ret = obj.call(*args) # call the original service-method # could convert the return value resuce # rescue exceptions end } =end require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" # ParserWriterChooseMixin module XMLRPC class BasicServer include ParserWriterChooseMixin include ParseContentType ERR_METHOD_MISSING = 1 ERR_UNCAUGHT_EXCEPTION = 2 ERR_MC_WRONG_PARAM = 3 ERR_MC_MISSING_PARAMS = 4 ERR_MC_MISSING_METHNAME = 5 ERR_MC_RECURSIVE_CALL = 6 ERR_MC_WRONG_PARAM_PARAMS = 7 ERR_MC_EXPECTED_STRUCT = 8 def initialize(class_delim=".") @handler = [] @default_handler = nil @service_hook = nil @class_delim = class_delim @create = nil @parser = nil add_multicall if Config::ENABLE_MULTICALL add_introspection if Config::ENABLE_INTROSPECTION end def add_handler(prefix, obj_or_signature=nil, help=nil, &block) if block_given? # proc-handler @handler << [prefix, block, obj_or_signature, help] else if prefix.kind_of? String # class-handler raise ArgumentError, "Expected non-nil value" if obj_or_signature.nil? @handler << [prefix + @class_delim, obj_or_signature] elsif prefix.kind_of? XMLRPC::Service::BasicInterface # class-handler with interface # add all methods @handler += prefix.get_methods(obj_or_signature, @class_delim) else raise ArgumentError, "Wrong type for parameter 'prefix'" end end self end def get_service_hook @service_hook end def set_service_hook(&handler) @service_hook = handler self end def get_default_handler @default_handler end def set_default_handler (&handler) @default_handler = handler self end def add_multicall add_handler("system.multicall", %w(array array), "Multicall Extension") do |arrStructs| unless arrStructs.is_a? Array raise XMLRPC::FaultException.new(ERR_MC_WRONG_PARAM, "system.multicall expects an array") end arrStructs.collect {|call| if call.is_a? Hash methodName = call["methodName"] params = call["params"] if params.nil? multicall_fault(ERR_MC_MISSING_PARAMS, "Missing params") elsif methodName.nil? multicall_fault(ERR_MC_MISSING_METHNAME, "Missing methodName") else if methodName == "system.multicall" multicall_fault(ERR_MC_RECURSIVE_CALL, "Recursive system.multicall forbidden") else unless params.is_a? Array multicall_fault(ERR_MC_WRONG_PARAM_PARAMS, "Parameter params have to be an Array") else ok, val = call_method(methodName, *params) if ok # correct return value [val] else # exception multicall_fault(val.faultCode, val.faultString) end end end end else multicall_fault(ERR_MC_EXPECTED_STRUCT, "system.multicall expected struct") end } end # end add_handler self end def add_introspection add_handler("system.listMethods",%w(array), "List methods available on this XML-RPC server") do methods = [] @handler.each do |name, obj| if obj.kind_of? Proc methods << name else obj.class.public_instance_methods(false).each do |meth| methods << "#{name}#{meth}" end end end methods end add_handler("system.methodSignature", %w(array string), "Returns method signature") do |meth| sigs = [] @handler.each do |name, obj, sig| if obj.kind_of? Proc and sig != nil and name == meth if sig[0].kind_of? Array # sig contains multiple signatures, e.g. [["array"], ["array", "string"]] sig.each {|s| sigs << s} else # sig is a single signature, e.g. ["array"] sigs << sig end end end sigs.uniq! || sigs # remove eventually duplicated signatures end add_handler("system.methodHelp", %w(string string), "Returns help on using this method") do |meth| help = nil @handler.each do |name, obj, sig, hlp| if obj.kind_of? Proc and name == meth help = hlp break end end help || "" end self end def process(data) method, params = parser().parseMethodCall(data) handle(method, *params) end private # -------------------------------------------------------------- def multicall_fault(nr, str) {"faultCode" => nr, "faultString" => str} end # # method dispatch # def dispatch(methodname, *args) for name, obj in @handler if obj.kind_of? Proc next unless methodname == name else next unless methodname =~ /^#{name}(.+)$/ next unless obj.respond_to? $1 obj = obj.method($1) end if check_arity(obj, args.size) if @service_hook.nil? return obj.call(*args) else return @service_hook.call(obj, *args) end end end if @default_handler.nil? raise XMLRPC::FaultException.new(ERR_METHOD_MISSING, "Method #{methodname} missing or wrong number of parameters!") else @default_handler.call(methodname, *args) end end # # returns true, if the arity of "obj" matches # def check_arity(obj, n_args) ary = obj.arity if ary >= 0 n_args == ary else n_args >= (ary+1).abs end end def call_method(methodname, *args) begin [true, dispatch(methodname, *args)] rescue XMLRPC::FaultException => e [false, e] rescue Exception => e [false, XMLRPC::FaultException.new(ERR_UNCAUGHT_EXCEPTION, "Uncaught exception #{e.message} in method #{methodname}")] end end # # # def handle(methodname, *args) create().methodResponse(*call_method(methodname, *args)) end end =begin = XMLRPC::CGIServer == Synopsis require "xmlrpc/server" s = XMLRPC::CGIServer.new s.add_handler("michael.add") do |a,b| a + b end s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end s.serve == Description Implements a CGI-based XML-RPC server. == Superclass (()) == Class Methods --- XMLRPC::CGIServer.new( *a ) Creates a new (({XMLRPC::CGIServer})) instance. All parameters given are by-passed to (()). You can only create ((*one*)) (({XMLRPC::CGIServer})) instance, because more than one makes no sense. == Instance Methods --- XMLRPC::CGIServer#serve Call this after you have added all you handlers to the server. This method processes a XML-RPC methodCall and sends the answer back to the client. Make sure that you don't write to standard-output in a handler, or in any other part of your program, this would case a CGI-based server to fail! =end class CGIServer < BasicServer @@obj = nil def CGIServer.new(*a) @@obj = super(*a) if @@obj.nil? @@obj end def initialize(*a) super(*a) end def serve catch(:exit_serve) { length = ENV['CONTENT_LENGTH'].to_i http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST" http_error(400, "Bad Request") unless parse_content_type(ENV['CONTENT_TYPE']).first == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? $stdin.binmode if $stdin.respond_to? :binmode data = $stdin.read(length) http_error(400, "Bad Request") if data.nil? or data.size != length http_write(process(data), "Content-type" => "text/xml; charset=utf-8") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

    #{err}

    Unexpected error occured while processing XML-RPC request!

    MSGEND http_write(msg, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.size.to_s str = "" h.each {|key, value| str << "#{key}: #{value}\r\n"} str << "\r\n#{body}" print str end end =begin = XMLRPC::ModRubyServer == Description Implements a XML-RPC server, which works with Apache mod_ruby. Use it in the same way as CGIServer! == Superclass (()) =end class ModRubyServer < BasicServer def initialize(*a) @ap = Apache::request super(*a) end def serve catch(:exit_serve) { header = {} @ap.headers_in.each {|key, value| header[key.capitalize] = value} length = header['Content-length'].to_i http_error(405, "Method Not Allowed") unless @ap.request_method == "POST" http_error(400, "Bad Request") unless parse_content_type(header['Content-type']).first == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? @ap.binmode data = @ap.read(length) http_error(400, "Bad Request") if data.nil? or data.size != length http_write(process(data), 200, "Content-type" => "text/xml; charset=utf-8") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

    #{err}

    Unexpected error occured while processing XML-RPC request!

    MSGEND http_write(msg, status, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, status, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.size.to_s h.each {|key, value| @ap.headers_out[key] = value } @ap.content_type = h["Content-type"] @ap.status = status.to_i @ap.send_http_header @ap.print body end end =begin = XMLRPC::Server == Synopsis require "xmlrpc/server" s = XMLRPC::Server.new(8080) s.add_handler("michael.add") do |a,b| a + b end s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end s.serve == Description Implements a standalone XML-RPC server. The method (({serve}))) is left if a SIGHUP is sent to the program. == Superclass (()) == Class Methods --- XMLRPC::Server.new( port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a ) Creates a new (({XMLRPC::Server})) instance, which is a XML-RPC server listening on port ((|port|)) and accepts requests for the host ((|host|)), which is by default only the localhost. The server is not started, to start it you have to call (()). Parameters ((|audit|)) and ((|debug|)) are obsolete! All additionally given parameters in ((|*a|)) are by-passed to (()). == Instance Methods --- XMLRPC::Server#serve Call this after you have added all you handlers to the server. This method starts the server to listen for XML-RPC requests and answer them. --- XMLRPC::Server#shutdown Stops and shuts the server down. =end class WEBrickServlet < BasicServer; end # forward declaration class Server < WEBrickServlet def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a) super(*a) require 'webrick' @server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections, :Logger => WEBrick::Log.new(stdlog)) @server.mount("/", self) end def serve if RUBY_PLATFORM =~ /mingw|mswin32/ signals = [1] else signals = %w[INT TERM HUP] end signals.each { |signal| trap(signal) { @server.shutdown } } @server.start end def shutdown @server.shutdown end end =begin = XMLRPC::WEBrickServlet == Synopsis require "webrick" require "xmlrpc/server" s = XMLRPC::WEBrickServlet.new s.add_handler("michael.add") do |a,b| a + b end s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end httpserver = WEBrick::HTTPServer.new(:Port => 8080) httpserver.mount("/RPC2", s) trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows httpserver.start == Instance Methods --- XMLRPC::WEBrickServlet#set_valid_ip( *ip_addr ) Specifies the valid IP addresses that are allowed to connect to the server. Each IP is either a (({String})) or a (({Regexp})). --- XMLRPC::WEBrickServlet#get_valid_ip Return the via method (()) specified valid IP addresses. == Description Implements a servlet for use with WEBrick, a pure Ruby (HTTP-) server framework. == Superclass (()) =end class WEBrickServlet < BasicServer def initialize(*a) super require "webrick/httpstatus" @valid_ip = nil end # deprecated from WEBrick/1.2.2. # but does not break anything. def require_path_info? false end def get_instance(config, *options) # TODO: set config & options self end def set_valid_ip(*ip_addr) if ip_addr.size == 1 and ip_addr[0].nil? @valid_ip = nil else @valid_ip = ip_addr end end def get_valid_ip @valid_ip end def service(request, response) if @valid_ip raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip } end if request.request_method != "POST" raise WEBrick::HTTPStatus::MethodNotAllowed, "unsupported method `#{request.request_method}'." end if parse_content_type(request['Content-type']).first != "text/xml" raise WEBrick::HTTPStatus::BadRequest end length = (request['Content-length'] || 0).to_i raise WEBrick::HTTPStatus::LengthRequired unless length > 0 data = request.body if data.nil? or data.size != length raise WEBrick::HTTPStatus::BadRequest end resp = process(data) if resp.nil? or resp.size <= 0 raise WEBrick::HTTPStatus::InternalServerError end response.status = 200 response['Content-Length'] = resp.size response['Content-Type'] = "text/xml; charset=utf-8" response.body = resp end end end # module XMLRPC =begin = History $Id: server.rb 22461 2009-02-20 09:06:53Z shyouhei $ =end PK|]XWHHxmlrpc/parser.rbnu[# # Parser for XML-RPC call and response # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id: parser.rb 13771 2007-10-24 23:04:42Z jeg2 $ # require "date" require "xmlrpc/base64" require "xmlrpc/datetime" # add some methods to NQXML::Node module NQXML class Node def removeChild(node) @children.delete(node) end def childNodes @children end def hasChildNodes not @children.empty? end def [] (index) @children[index] end def nodeType if @entity.instance_of? NQXML::Text then :TEXT elsif @entity.instance_of? NQXML::Comment then :COMMENT #elsif @entity.instance_of? NQXML::Element then :ELEMENT elsif @entity.instance_of? NQXML::Tag then :ELEMENT else :ELSE end end def nodeValue #TODO: error when wrong Entity-type @entity.text end def nodeName #TODO: error when wrong Entity-type @entity.name end end # class Node end # module NQXML module XMLRPC class FaultException < StandardError attr_reader :faultCode, :faultString alias message faultString def initialize(faultCode, faultString) @faultCode = faultCode @faultString = faultString end # returns a hash def to_h {"faultCode" => @faultCode, "faultString" => @faultString} end end module Convert def self.int(str) str.to_i end def self.boolean(str) case str when "0" then false when "1" then true else raise "RPC-value of type boolean is wrong" end end def self.double(str) str.to_f end def self.dateTime(str) case str when /^(-?\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(?:Z|([+-])(\d\d):?(\d\d))?$/ a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} if $7 ofs = $8.to_i*3600 + $9.to_i*60 ofs = -ofs if $7=='+' utc = Time.utc(*a) + ofs a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ] end XMLRPC::DateTime.new(*a) when /^(-?\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(Z|([+-]\d\d):(\d\d))?$/ a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} if a[0] < 70 a[0] += 2000 else a[0] += 1900 end if $7 ofs = $8.to_i*3600 + $9.to_i*60 ofs = -ofs if $7=='+' utc = Time.utc(*a) + ofs a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ] end XMLRPC::DateTime.new(*a) else raise "wrong dateTime.iso8601 format " + str end end def self.base64(str) XMLRPC::Base64.decode(str) end def self.struct(hash) # convert to marhalled object klass = hash["___class___"] if klass.nil? or Config::ENABLE_MARSHALLING == false hash else begin mod = Module klass.split("::").each {|const| mod = mod.const_get(const.strip)} obj = mod.allocate hash.delete "___class___" hash.each {|key, value| obj.instance_variable_set("@#{ key }", value) if key =~ /^([\w_][\w_0-9]*)$/ } obj rescue hash end end end def self.fault(hash) if hash.kind_of? Hash and hash.size == 2 and hash.has_key? "faultCode" and hash.has_key? "faultString" and hash["faultCode"].kind_of? Integer and hash["faultString"].kind_of? String XMLRPC::FaultException.new(hash["faultCode"], hash["faultString"]) else raise "wrong fault-structure: #{hash.inspect}" end end end # module Convert module XMLParser class AbstractTreeParser def parseMethodResponse(str) methodResponse_document(createCleanedTree(str)) end def parseMethodCall(str) methodCall_document(createCleanedTree(str)) end private # # remove all whitespaces but in the tags i4, int, boolean.... # and all comments # def removeWhitespacesAndComments(node) remove = [] childs = node.childNodes.to_a childs.each do |nd| case _nodeType(nd) when :TEXT # TODO: add nil? unless %w(i4 int boolean string double dateTime.iso8601 base64).include? node.nodeName if node.nodeName == "value" if not node.childNodes.to_a.detect {|n| _nodeType(n) == :ELEMENT}.nil? remove << nd if nd.nodeValue.strip == "" end else remove << nd if nd.nodeValue.strip == "" end end when :COMMENT remove << nd else removeWhitespacesAndComments(nd) end end remove.each { |i| node.removeChild(i) } end def nodeMustBe(node, name) cmp = case name when Array name.include?(node.nodeName) when String name == node.nodeName else raise "error" end if not cmp then raise "wrong xml-rpc (name)" end node end # # returns, when successfully the only child-node # def hasOnlyOneChild(node, name=nil) if node.childNodes.to_a.size != 1 raise "wrong xml-rpc (size)" end if name != nil then nodeMustBe(node.firstChild, name) end end def assert(b) if not b then raise "assert-fail" end end # the node `node` has empty string or string def text_zero_one(node) nodes = node.childNodes.to_a.size if nodes == 1 text(node.firstChild) elsif nodes == 0 "" else raise "wrong xml-rpc (size)" end end def integer(node) #TODO: check string for float because to_i returnsa # 0 when wrong string nodeMustBe(node, %w(i4 int)) hasOnlyOneChild(node) Convert.int(text(node.firstChild)) end def boolean(node) nodeMustBe(node, "boolean") hasOnlyOneChild(node) Convert.boolean(text(node.firstChild)) end def v_nil(node) nodeMustBe(node, "nil") assert( node.childNodes.to_a.size == 0 ) nil end def string(node) nodeMustBe(node, "string") text_zero_one(node) end def double(node) #TODO: check string for float because to_f returnsa # 0.0 when wrong string nodeMustBe(node, "double") hasOnlyOneChild(node) Convert.double(text(node.firstChild)) end def dateTime(node) nodeMustBe(node, "dateTime.iso8601") hasOnlyOneChild(node) Convert.dateTime( text(node.firstChild) ) end def base64(node) nodeMustBe(node, "base64") #hasOnlyOneChild(node) Convert.base64(text_zero_one(node)) end def member(node) nodeMustBe(node, "member") assert( node.childNodes.to_a.size == 2 ) [ name(node[0]), value(node[1]) ] end def name(node) nodeMustBe(node, "name") #hasOnlyOneChild(node) text_zero_one(node) end def array(node) nodeMustBe(node, "array") hasOnlyOneChild(node, "data") data(node.firstChild) end def data(node) nodeMustBe(node, "data") node.childNodes.to_a.collect do |val| value(val) end end def param(node) nodeMustBe(node, "param") hasOnlyOneChild(node, "value") value(node.firstChild) end def methodResponse(node) nodeMustBe(node, "methodResponse") hasOnlyOneChild(node, %w(params fault)) child = node.firstChild case child.nodeName when "params" [ true, params(child,false) ] when "fault" [ false, fault(child) ] else raise "unexpected error" end end def methodName(node) nodeMustBe(node, "methodName") hasOnlyOneChild(node) text(node.firstChild) end def params(node, call=true) nodeMustBe(node, "params") if call node.childNodes.to_a.collect do |n| param(n) end else # response (only one param) hasOnlyOneChild(node) param(node.firstChild) end end def fault(node) nodeMustBe(node, "fault") hasOnlyOneChild(node, "value") f = value(node.firstChild) Convert.fault(f) end # _nodeType is defined in the subclass def text(node) assert( _nodeType(node) == :TEXT ) assert( node.hasChildNodes == false ) assert( node.nodeValue != nil ) node.nodeValue.to_s end def struct(node) nodeMustBe(node, "struct") hash = {} node.childNodes.to_a.each do |me| n, v = member(me) hash[n] = v end Convert.struct(hash) end def value(node) nodeMustBe(node, "value") nodes = node.childNodes.to_a.size if nodes == 0 return "" elsif nodes > 1 raise "wrong xml-rpc (size)" end child = node.firstChild case _nodeType(child) when :TEXT text_zero_one(node) when :ELEMENT case child.nodeName when "i4", "int" then integer(child) when "boolean" then boolean(child) when "string" then string(child) when "double" then double(child) when "dateTime.iso8601" then dateTime(child) when "base64" then base64(child) when "struct" then struct(child) when "array" then array(child) when "nil" if Config::ENABLE_NIL_PARSER v_nil(child) else raise "wrong/unknown XML-RPC type 'nil'" end else raise "wrong/unknown XML-RPC type" end else raise "wrong type of node" end end def methodCall(node) nodeMustBe(node, "methodCall") assert( (1..2).include?( node.childNodes.to_a.size ) ) name = methodName(node[0]) if node.childNodes.to_a.size == 2 then pa = params(node[1]) else # no parameters given pa = [] end [name, pa] end end # module TreeParserMixin class AbstractStreamParser def parseMethodResponse(str) parser = @parser_class.new parser.parse(str) raise "No valid method response!" if parser.method_name != nil if parser.fault != nil # is a fault structure [false, parser.fault] else # is a normal return value raise "Missing return value!" if parser.params.size == 0 raise "Too many return values. Only one allowed!" if parser.params.size > 1 [true, parser.params[0]] end end def parseMethodCall(str) parser = @parser_class.new parser.parse(str) raise "No valid method call - missing method name!" if parser.method_name.nil? [parser.method_name, parser.params] end end module StreamParserMixin attr_reader :params attr_reader :method_name attr_reader :fault def initialize(*a) super(*a) @params = [] @values = [] @val_stack = [] @names = [] @name = [] @structs = [] @struct = {} @method_name = nil @fault = nil @data = nil end def startElement(name, attrs=[]) @data = nil case name when "value" @value = nil when "nil" raise "wrong/unknown XML-RPC type 'nil'" unless Config::ENABLE_NIL_PARSER @value = :nil when "array" @val_stack << @values @values = [] when "struct" @names << @name @name = [] @structs << @struct @struct = {} end end def endElement(name) @data ||= "" case name when "string" @value = @data when "i4", "int" @value = Convert.int(@data) when "boolean" @value = Convert.boolean(@data) when "double" @value = Convert.double(@data) when "dateTime.iso8601" @value = Convert.dateTime(@data) when "base64" @value = Convert.base64(@data) when "value" @value = @data if @value.nil? @values << (@value == :nil ? nil : @value) when "array" @value = @values @values = @val_stack.pop when "struct" @value = Convert.struct(@struct) @name = @names.pop @struct = @structs.pop when "name" @name[0] = @data when "member" @struct[@name[0]] = @values.pop when "param" @params << @values[0] @values = [] when "fault" @fault = Convert.fault(@values[0]) when "methodName" @method_name = @data end @data = nil end def character(data) if @data @data << data else @data = data end end end # module StreamParserMixin # --------------------------------------------------------------------------- class XMLStreamParser < AbstractStreamParser def initialize require "xmlparser" @parser_class = Class.new(::XMLParser) { include StreamParserMixin } end end # class XMLStreamParser # --------------------------------------------------------------------------- class NQXMLStreamParser < AbstractStreamParser def initialize require "nqxml/streamingparser" @parser_class = XMLRPCParser end class XMLRPCParser include StreamParserMixin def parse(str) parser = NQXML::StreamingParser.new(str) parser.each do |ele| case ele when NQXML::Text @data = ele.text #character(ele.text) when NQXML::Tag if ele.isTagEnd endElement(ele.name) else startElement(ele.name, ele.attrs) end end end # do end # method parse end # class XMLRPCParser end # class NQXMLStreamParser # --------------------------------------------------------------------------- class XMLTreeParser < AbstractTreeParser def initialize require "xmltreebuilder" # The new XMLParser library (0.6.2+) uses a slightly different DOM implementation. # The following code removes the differences between both versions. if defined? XML::DOM::Builder return if defined? XML::DOM::Node::DOCUMENT # code below has been already executed klass = XML::DOM::Node klass.const_set("DOCUMENT", klass::DOCUMENT_NODE) klass.const_set("TEXT", klass::TEXT_NODE) klass.const_set("COMMENT", klass::COMMENT_NODE) klass.const_set("ELEMENT", klass::ELEMENT_NODE) end end private def _nodeType(node) tp = node.nodeType if tp == XML::SimpleTree::Node::TEXT then :TEXT elsif tp == XML::SimpleTree::Node::COMMENT then :COMMENT elsif tp == XML::SimpleTree::Node::ELEMENT then :ELEMENT else :ELSE end end def methodResponse_document(node) assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT ) hasOnlyOneChild(node, "methodResponse") methodResponse(node.firstChild) end def methodCall_document(node) assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT ) hasOnlyOneChild(node, "methodCall") methodCall(node.firstChild) end def createCleanedTree(str) doc = XML::SimpleTreeBuilder.new.parse(str) doc.documentElement.normalize removeWhitespacesAndComments(doc) doc end end # class XMLParser # --------------------------------------------------------------------------- class NQXMLTreeParser < AbstractTreeParser def initialize require "nqxml/treeparser" end private def _nodeType(node) node.nodeType end def methodResponse_document(node) methodResponse(node) end def methodCall_document(node) methodCall(node) end def createCleanedTree(str) doc = ::NQXML::TreeParser.new(str).document.rootNode removeWhitespacesAndComments(doc) doc end end # class NQXMLTreeParser # --------------------------------------------------------------------------- class REXMLStreamParser < AbstractStreamParser def initialize require "rexml/document" @parser_class = StreamListener end class StreamListener include StreamParserMixin alias :tag_start :startElement alias :tag_end :endElement alias :text :character alias :cdata :character def method_missing(*a) # ignore end def parse(str) parser = REXML::Document.parse_stream(str, self) end end end # --------------------------------------------------------------------------- class XMLScanStreamParser < AbstractStreamParser def initialize require "xmlscan/parser" @parser_class = XMLScanParser end class XMLScanParser include StreamParserMixin Entities = { "lt" => "<", "gt" => ">", "amp" => "&", "quot" => '"', "apos" => "'" } def parse(str) parser = XMLScan::XMLParser.new(self) parser.parse(str) end alias :on_stag :startElement alias :on_etag :endElement def on_stag_end(name); end def on_stag_end_empty(name) startElement(name) endElement(name) end def on_chardata(str) character(str) end def on_cdata(str) character(str) end def on_entityref(ent) str = Entities[ent] if str character(str) else raise "unknown entity" end end def on_charref(code) character(code.chr) end def on_charref_hex(code) character(code.chr) end def method_missing(*a) end # TODO: call/implement? # valid_name? # valid_chardata? # valid_char? # parse_error end end # --------------------------------------------------------------------------- XMLParser = XMLTreeParser NQXMLParser = NQXMLTreeParser Classes = [XMLStreamParser, XMLTreeParser, NQXMLStreamParser, NQXMLTreeParser, REXMLStreamParser, XMLScanStreamParser] # yields an instance of each installed parser def self.each_installed_parser XMLRPC::XMLParser::Classes.each do |klass| begin yield klass.new rescue LoadError end end end end # module XMLParser end # module XMLRPC PK|]`% xmlrpc/utils.rbnu[# # Defines ParserWriterChooseMixin, which makes it possible to choose a # different XML writer and/or XML parser then the default one. # The Mixin is used in client.rb (class Client) and server.rb (class # BasicServer) # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id: utils.rb 13771 2007-10-24 23:04:42Z jeg2 $ # module XMLRPC # # This module enables a user-class to be marshalled # by XML-RPC for Ruby into a Hash, with one additional # key/value pair "___class___" => ClassName # module Marshallable end module ParserWriterChooseMixin def set_writer(writer) @create = Create.new(writer) self end def set_parser(parser) @parser = parser self end private def create # if set_writer was not already called then call it now if @create.nil? then set_writer(Config::DEFAULT_WRITER.new) end @create end def parser # if set_parser was not already called then call it now if @parser.nil? then set_parser(Config::DEFAULT_PARSER.new) end @parser end end # module ParserWriterChooseMixin module Service # # base class for Service Interface definitions, used # by BasicServer#add_handler # class BasicInterface attr_reader :prefix, :methods def initialize(prefix) @prefix = prefix @methods = [] end def add_method(sig, help=nil, meth_name=nil) mname = nil sig = [sig] if sig.kind_of? String sig = sig.collect do |s| name, si = parse_sig(s) raise "Wrong signatures!" if mname != nil and name != mname mname = name si end @methods << [mname, meth_name || mname, sig, help] end private # --------------------------------- def parse_sig(sig) # sig is a String if sig =~ /^\s*(\w+)\s+([^(]+)(\(([^)]*)\))?\s*$/ params = [$1] name = $2.strip $4.split(",").each {|i| params << i.strip} if $4 != nil return name, params else raise "Syntax error in signature" end end end # class BasicInterface # # class which wraps a Service Interface definition, used # by BasicServer#add_handler # class Interface < BasicInterface def initialize(prefix, &p) raise "No interface specified" if p.nil? super(prefix) instance_eval(&p) end def get_methods(obj, delim=".") prefix = @prefix + delim @methods.collect { |name, meth, sig, help| [prefix + name, obj.method(meth).to_proc, sig, help] } end private # --------------------------------- def meth(*a) add_method(*a) end end # class Interface class PublicInstanceMethodsInterface < BasicInterface def initialize(prefix) super(prefix) end def get_methods(obj, delim=".") prefix = @prefix + delim obj.class.public_instance_methods(false).collect { |name| [prefix + name, obj.method(name).to_proc, nil, nil] } end end end # module Service # # short-form to create a Service::Interface # def self.interface(prefix, &p) Service::Interface.new(prefix, &p) end # short-cut for creating a PublicInstanceMethodsInterface def self.iPIMethods(prefix) Service::PublicInstanceMethodsInterface.new(prefix) end module ParseContentType def parse_content_type(str) a, *b = str.split(";") return a.strip.downcase, *b end end end # module XMLRPC PK|]sxmlrpc/httpserver.rbnu[# # Implements a simple HTTP-server by using John W. Small's (jsmall@laser.net) # ruby-generic-server. # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id: httpserver.rb 11708 2007-02-12 23:01:19Z shyouhei $ # require "gserver" class HttpServer < GServer ## # handle_obj specifies the object, that receives calls to request_handler # and ip_auth_handler def initialize(handle_obj, port = 8080, host = DEFAULT_HOST, maxConnections = 4, stdlog = $stdout, audit = true, debug = true) @handler = handle_obj super(port, host, maxConnections, stdlog, audit, debug) end private # Constants ----------------------------------------------- CRLF = "\r\n" HTTP_PROTO = "HTTP/1.0" SERVER_NAME = "HttpServer (Ruby #{RUBY_VERSION})" DEFAULT_HEADER = { "Server" => SERVER_NAME } ## # Mapping of status code and error message # StatusCodeMapping = { 200 => "OK", 400 => "Bad Request", 403 => "Forbidden", 405 => "Method Not Allowed", 411 => "Length Required", 500 => "Internal Server Error" } # Classes ------------------------------------------------- class Request attr_reader :data, :header, :method, :path, :proto def initialize(data, method=nil, path=nil, proto=nil) @header, @data = Table.new, data @method, @path, @proto = method, path, proto end def content_length len = @header['Content-Length'] return nil if len.nil? return len.to_i end end class Response attr_reader :header attr_accessor :body, :status, :status_message def initialize(status=200) @status = status @status_message = nil @header = Table.new end end ## # a case-insensitive Hash class for HTTP header # class Table include Enumerable def initialize(hash={}) @hash = hash update(hash) end def [](key) @hash[key.to_s.capitalize] end def []=(key, value) @hash[key.to_s.capitalize] = value end def update(hash) hash.each {|k,v| self[k] = v} self end def each @hash.each {|k,v| yield k.capitalize, v } end def writeTo(port) each { |k,v| port << "#{k}: #{v}" << CRLF } end end # class Table # Helper Methods ------------------------------------------ def http_header(header=nil) new_header = Table.new(DEFAULT_HEADER) new_header.update(header) unless header.nil? new_header["Connection"] = "close" new_header["Date"] = http_date(Time.now) new_header end def http_date( aTime ) aTime.gmtime.strftime( "%a, %d %b %Y %H:%M:%S GMT" ) end def http_resp(status_code, status_message=nil, header=nil, body=nil) status_message ||= StatusCodeMapping[status_code] str = "" str << "#{HTTP_PROTO} #{status_code} #{status_message}" << CRLF http_header(header).writeTo(str) str << CRLF str << body unless body.nil? str end # Main Serve Loop ----------------------------------------- def serve(io) # perform IP authentification unless @handler.ip_auth_handler(io) io << http_resp(403, "Forbidden") return end # parse first line if io.gets =~ /^(\S+)\s+(\S+)\s+(\S+)/ request = Request.new(io, $1, $2, $3) else io << http_resp(400, "Bad Request") return end # parse HTTP headers while (line=io.gets) !~ /^(\n|\r)/ if line =~ /^([\w-]+):\s*(.*)$/ request.header[$1] = $2.strip end end io.binmode response = Response.new # execute request handler @handler.request_handler(request, response) # write response back to the client io << http_resp(response.status, response.status_message, response.header, response.body) rescue Exception => e io << http_resp(500, "Internal Server Error") end end # class HttpServer PK|]` xmlrpc/create.rbnu[# # Creates XML-RPC call/response documents # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id: create.rb 11818 2007-02-23 03:45:55Z knu $ # require "date" require "xmlrpc/base64" module XMLRPC module XMLWriter class Abstract def ele(name, *children) element(name, nil, *children) end def tag(name, txt) element(name, nil, text(txt)) end end class Simple < Abstract def document_to_str(doc) doc end def document(*params) params.join("") end def pi(name, *params) "" end def element(name, attrs, *children) raise "attributes not yet implemented" unless attrs.nil? if children.empty? "<#{name}/>" else "<#{name}>" + children.join("") + "" end end def text(txt) cleaned = txt.dup cleaned.gsub!(/&/, '&') cleaned.gsub!(//, '>') cleaned end end # class Simple class XMLParser < Abstract def initialize require "xmltreebuilder" end def document_to_str(doc) doc.to_s end def document(*params) XML::SimpleTree::Document.new(*params) end def pi(name, *params) XML::SimpleTree::ProcessingInstruction.new(name, *params) end def element(name, attrs, *children) XML::SimpleTree::Element.new(name, attrs, *children) end def text(txt) XML::SimpleTree::Text.new(txt) end end # class XMLParser Classes = [Simple, XMLParser] # yields an instance of each installed XML writer def self.each_installed_writer XMLRPC::XMLWriter::Classes.each do |klass| begin yield klass.new rescue LoadError end end end end # module XMLWriter class Create def initialize(xml_writer = nil) @writer = xml_writer || Config::DEFAULT_WRITER.new end def methodCall(name, *params) name = name.to_s if name !~ /[a-zA-Z0-9_.:\/]+/ raise ArgumentError, "Wrong XML-RPC method-name" end parameter = params.collect do |param| @writer.ele("param", conv2value(param)) end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodCall", @writer.tag("methodName", name), @writer.ele("params", *parameter) ) ) @writer.document_to_str(tree) + "\n" end # # generates a XML-RPC methodResponse document # # if is_ret == false then the params array must # contain only one element, which is a structure # of a fault return-value. # # if is_ret == true then a normal # return-value of all the given params is created. # def methodResponse(is_ret, *params) if is_ret resp = params.collect do |param| @writer.ele("param", conv2value(param)) end resp = [@writer.ele("params", *resp)] else if params.size != 1 or params[0] === XMLRPC::FaultException raise ArgumentError, "no valid fault-structure given" end resp = @writer.ele("fault", conv2value(params[0].to_h)) end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodResponse", resp) ) @writer.document_to_str(tree) + "\n" end ##################################### private ##################################### # # converts a Ruby object into # a XML-RPC tag # def conv2value(param) val = case param when Fixnum @writer.tag("i4", param.to_s) when Bignum if Config::ENABLE_BIGINT @writer.tag("i4", param.to_s) else if param >= -(2**31) and param <= (2**31-1) @writer.tag("i4", param.to_s) else raise "Bignum is too big! Must be signed 32-bit integer!" end end when TrueClass, FalseClass @writer.tag("boolean", param ? "1" : "0") when String @writer.tag("string", param) when Symbol @writer.tag("string", param.to_s) when NilClass if Config::ENABLE_NIL_CREATE @writer.ele("nil") else raise "Wrong type NilClass. Not allowed!" end when Float @writer.tag("double", param.to_s) when Struct h = param.members.collect do |key| value = param[key] @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Hash # TODO: can a Hash be empty? h = param.collect do |key, value| @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Array # TODO: can an Array be empty? a = param.collect {|v| conv2value(v) } @writer.ele("array", @writer.ele("data", *a) ) when Time, Date, ::DateTime @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S")) when XMLRPC::DateTime @writer.tag("dateTime.iso8601", format("%.4d%02d%02dT%02d:%02d:%02d", *param.to_a)) when XMLRPC::Base64 @writer.tag("base64", param.encoded) else if Config::ENABLE_MARSHALLING and param.class.included_modules.include? XMLRPC::Marshallable # convert Ruby object into Hash ret = {"___class___" => param.class.name} param.instance_variables.each {|v| name = v[1..-1] val = param.instance_variable_get(v) if val.nil? ret[name] = val if Config::ENABLE_NIL_CREATE else ret[name] = val end } return conv2value(ret) else ok, pa = wrong_type(param) if ok return conv2value(pa) else raise "Wrong type!" end end end @writer.ele("value", val) end def wrong_type(value) false end end # class Create end # module XMLRPC PK|]j?;;xmlrpc/marshal.rbnu[# # Marshalling of XML-RPC methodCall and methodResponse # # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id: marshal.rb 11708 2007-02-12 23:01:19Z shyouhei $ # require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" module XMLRPC class Marshal include ParserWriterChooseMixin # class methods ------------------------------- class << self def dump_call( methodName, *params ) new.dump_call( methodName, *params ) end def dump_response( param ) new.dump_response( param ) end def load_call( stringOrReadable ) new.load_call( stringOrReadable ) end def load_response( stringOrReadable ) new.load_response( stringOrReadable ) end alias dump dump_response alias load load_response end # class self # instance methods ---------------------------- def initialize( parser = nil, writer = nil ) set_parser( parser ) set_writer( writer ) end def dump_call( methodName, *params ) create.methodCall( methodName, *params ) end def dump_response( param ) create.methodResponse( ! param.kind_of?( XMLRPC::FaultException ) , param ) end ## # returns [ methodname, params ] # def load_call( stringOrReadable ) parser.parseMethodCall( stringOrReadable ) end ## # returns paramOrFault # def load_response( stringOrReadable ) parser.parseMethodResponse( stringOrReadable )[1] end end # class Marshal end PK|] xmlrpc/base64.rbnu[=begin = xmlrpc/base64.rb Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) Released under the same term of license as Ruby. = Classes * (()) = XMLRPC::Base64 == Description This class is necessary for (('xmlrpc4r')) to determine that a string should be transmitted base64-encoded and not as a raw-string. You can use (({XMLRPC::Base64})) on the client and server-side as a parameter and/or return-value. == Class Methods --- XMLRPC::Base64.new( str, state = :dec ) Creates a new (({XMLRPC::Base64})) instance with string ((|str|)) as the internal string. When ((|state|)) is (({:dec})) it assumes that the string ((|str|)) is not in base64 format (perhaps already decoded), otherwise if ((|state|)) is (({:enc})) it decodes ((|str|)) and stores it as the internal string. --- XMLRPC::Base64.decode( str ) Decodes string ((|str|)) with base64 and returns that value. --- XMLRPC::Base64.encode( str ) Encodes string ((|str|)) with base64 and returns that value. == Instance Methods --- XMLRPC::Base64#decoded Returns the internal string decoded. --- XMLRPC::Base64#encoded Returns the internal string encoded with base64. =end module XMLRPC class Base64 def initialize(str, state = :dec) case state when :enc @str = Base64.decode(str) when :dec @str = str else raise ArgumentError, "wrong argument; either :enc or :dec" end end def decoded @str end def encoded Base64.encode(@str) end def Base64.decode(str) str.gsub(/\s+/, "").unpack("m")[0] end def Base64.encode(str) [str].pack("m") end end end # module XMLRPC =begin = History $Id: base64.rb 11708 2007-02-12 23:01:19Z shyouhei $ =end PK|]$xmlrpc/config.rbnu[# # $Id: config.rb 11708 2007-02-12 23:01:19Z shyouhei $ # Configuration file for XML-RPC for Ruby # module XMLRPC module Config DEFAULT_WRITER = XMLWriter::Simple # or XMLWriter::XMLParser # available parser: # * XMLParser::NQXMLTreeParser # * XMLParser::NQXMLStreamParser # * XMLParser::XMLTreeParser # * XMLParser::XMLStreamParser (fastest) # * XMLParser::REXMLStreamParser # * XMLParser::XMLScanStreamParser DEFAULT_PARSER = XMLParser::REXMLStreamParser # enable tag ENABLE_NIL_CREATE = false ENABLE_NIL_PARSER = false # allows integers greater than 32-bit if true ENABLE_BIGINT = false # enable marshalling ruby objects which include XMLRPC::Marshallable ENABLE_MARSHALLING = true # enable multiCall extension by default ENABLE_MULTICALL = false # enable Introspection extension by default ENABLE_INTROSPECTION = false end end PK|]ping.rbnu[# # = ping.rb: Check a host for upness # # Author:: Yukihiro Matsumoto # Documentation:: Konrad Meyer # # Performs the function of the basic network testing tool, ping. # See: Ping. # require 'timeout' require "socket" # # Ping contains routines to test for the reachability of remote hosts. # Currently the only routine implemented is pingecho(). # # Ping.pingecho uses a TCP echo (not an ICMP echo) to determine if the # remote host is reachable. This is usually adequate to tell that a remote # host is available to telnet, ftp, or ssh to. # # Warning: Ping.pingecho may block for a long time if DNS resolution is # slow. Requiring 'resolv-replace' allows non-blocking name resolution. # # Usage: # # require 'ping' # # puts "'jimmy' is alive and kicking" if Ping.pingecho('jimmy', 10) # module Ping # # Return true if we can open a connection to the hostname or IP address # +host+ on port +service+ (which defaults to the "echo" port) waiting up # to +timeout+ seconds. # # Example: # # require 'ping' # # Ping.pingecho "google.com", 10, 80 # def pingecho(host, timeout=5, service="echo") begin timeout(timeout) do s = TCPSocket.new(host, service) s.close end rescue Errno::ECONNREFUSED return true rescue Timeout::Error, StandardError return false end return true end module_function :pingecho end if $0 == __FILE__ host = ARGV[0] host ||= "localhost" printf("%s alive? - %s\n", host, Ping::pingecho(host, 5)) end PK|]5# uri/mailto.rbnu[# # = uri/mailto.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id: mailto.rb 11747 2007-02-15 02:41:45Z knu $ # require 'uri/generic' module URI # # RFC2368, The mailto URL scheme # class MailTo < Generic include REGEXP DEFAULT_PORT = nil COMPONENT = [ :scheme, :to, :headers ].freeze # :stopdoc: # "hname" and "hvalue" are encodings of an RFC 822 header name and # value, respectively. As with "to", all URL reserved characters must # be encoded. # # "#mailbox" is as specified in RFC 822 [RFC822]. This means that it # consists of zero or more comma-separated mail addresses, possibly # including "phrase" and "comment" components. Note that all URL # reserved characters in "to" must be encoded: in particular, # parentheses, commas, and the percent sign ("%"), which commonly occur # in the "mailbox" syntax. # # Within mailto URLs, the characters "?", "=", "&" are reserved. # hname = *urlc # hvalue = *urlc # header = hname "=" hvalue HEADER_PATTERN = "(?:[^?=&]*=[^?=&]*)".freeze HEADER_REGEXP = Regexp.new(HEADER_PATTERN, 'N').freeze # headers = "?" header *( "&" header ) # to = #mailbox # mailtoURL = "mailto:" [ to ] [ headers ] MAILBOX_PATTERN = "(?:#{PATTERN::ESCAPED}|[^(),%?=&])".freeze MAILTO_REGEXP = Regexp.new(" # :nodoc: \\A (#{MAILBOX_PATTERN}*?) (?# 1: to) (?: \\? (#{HEADER_PATTERN}(?:\\&#{HEADER_PATTERN})*) (?# 2: headers) )? (?: \\# (#{PATTERN::FRAGMENT}) (?# 3: fragment) )? \\z ", Regexp::EXTENDED, 'N').freeze # :startdoc: # # == Description # # Creates a new URI::MailTo object from components, with syntax checking. # # Components can be provided as an Array or Hash. If an Array is used, # the components must be supplied as [to, headers]. # # If a Hash is used, the keys are the component names preceded by colons. # # The headers can be supplied as a pre-encoded string, such as # "subject=subscribe&cc=address", or as an Array of Arrays like # [['subject', 'subscribe'], ['cc', 'address']] # # Examples: # # require 'uri' # # m1 = URI::MailTo.build(['joe@example.com', 'subject=Ruby']) # puts m1.to_s -> mailto:joe@example.com?subject=Ruby # # m2 = URI::MailTo.build(['john@example.com', [['Subject', 'Ruby'], ['Cc', 'jack@example.com']]]) # puts m2.to_s -> mailto:john@example.com?Subject=Ruby&Cc=jack@example.com # # m3 = URI::MailTo.build({:to => 'listman@example.com', :headers => [['subject', 'subscribe']]}) # puts m3.to_s -> mailto:listman@example.com?subject=subscribe # def self.build(args) tmp = Util::make_components_hash(self, args) if tmp[:to] tmp[:opaque] = tmp[:to] else tmp[:opaque] = '' end if tmp[:headers] tmp[:opaque] << '?' if tmp[:headers].kind_of?(Array) tmp[:opaque] << tmp[:headers].collect { |x| if x.kind_of?(Array) x[0] + '=' + x[1..-1].to_s else x.to_s end }.join('&') elsif tmp[:headers].kind_of?(Hash) tmp[:opaque] << tmp[:headers].collect { |h,v| h + '=' + v }.join('&') else tmp[:opaque] << tmp[:headers].to_s end end return super(tmp) end # # == Description # # Creates a new URI::MailTo object from generic URL components with # no syntax checking. # # This method is usually called from URI::parse, which checks # the validity of each component. # def initialize(*arg) super(*arg) @to = nil @headers = [] if MAILTO_REGEXP =~ @opaque if arg[-1] self.to = $1 self.headers = $2 else set_to($1) set_headers($2) end else raise InvalidComponentError, "unrecognised opaque part for mailtoURL: #{@opaque}" end end # The primary e-mail address of the URL, as a String attr_reader :to # E-mail headers set by the URL, as an Array of Arrays attr_reader :headers def check_to(v) return true unless v return true if v.size == 0 if OPAQUE !~ v || /\A#{MAILBOX_PATTERN}*\z/o !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end return true end private :check_to def set_to(v) @to = v end protected :set_to def to=(v) check_to(v) set_to(v) v end def check_headers(v) return true unless v return true if v.size == 0 if OPAQUE !~ v || /\A(#{HEADER_PATTERN}(?:\&#{HEADER_PATTERN})*)\z/o !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end return true end private :check_headers def set_headers(v) @headers = [] if v v.scan(HEADER_REGEXP) do |x| @headers << x.split(/=/o, 2) end end end protected :set_headers def headers=(v) check_headers(v) set_headers(v) v end def to_s @scheme + ':' + if @to @to else '' end + if @headers.size > 0 '?' + @headers.collect{|x| x.join('=')}.join('&') else '' end + if @fragment '#' + @fragment else '' end end # Returns the RFC822 e-mail text equivalent of the URL, as a String. # # Example: # # require 'uri' # # uri = URI.parse("mailto:ruby-list@ruby-lang.org?Subject=subscribe&cc=myaddr") # uri.to_mailtext # # => "To: ruby-list@ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n" # def to_mailtext to = URI::unescape(@to) head = '' body = '' @headers.each do |x| case x[0] when 'body' body = URI::unescape(x[1]) when 'to' to << ', ' + URI::unescape(x[1]) else head << URI::unescape(x[0]).capitalize + ': ' + URI::unescape(x[1]) + "\n" end end return "To: #{to} #{head} #{body} " end alias to_rfc822text to_mailtext end @@schemes['MAILTO'] = MailTo end PK|]͇MX^X^uri/generic.rbnu[# # = uri/generic.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id: generic.rb 31666 2011-05-20 22:29:17Z shyouhei $ # require 'uri/common' module URI # # Base class for all URI classes. # Implements generic URI syntax as per RFC 2396. # class Generic include URI include REGEXP DEFAULT_PORT = nil # # Returns default port # def self.default_port self::DEFAULT_PORT end def default_port self.class.default_port end COMPONENT = [ :scheme, :userinfo, :host, :port, :registry, :path, :opaque, :query, :fragment ].freeze # # Components of the URI in the order. # def self.component self::COMPONENT end USE_REGISTRY = false # # DOC: FIXME! # def self.use_registry self::USE_REGISTRY end # # == Synopsis # # See #new # # == Description # # At first, tries to create a new URI::Generic instance using # URI::Generic::build. But, if exception URI::InvalidComponentError is raised, # then it URI::Escape.escape all URI components and tries again. # # def self.build2(args) begin return self.build(args) rescue InvalidComponentError if args.kind_of?(Array) return self.build(args.collect{|x| if x URI.escape(x) else x end }) elsif args.kind_of?(Hash) tmp = {} args.each do |key, value| tmp[key] = if value URI.escape(value) else value end end return self.build(tmp) end end end # # == Synopsis # # See #new # # == Description # # Creates a new URI::Generic instance from components of URI::Generic # with check. Components are: scheme, userinfo, host, port, registry, path, # opaque, query and fragment. You can provide arguments either by an Array or a Hash. # See #new for hash keys to use or for order of array items. # def self.build(args) if args.kind_of?(Array) && args.size == ::URI::Generic::COMPONENT.size tmp = args elsif args.kind_of?(Hash) tmp = ::URI::Generic::COMPONENT.collect do |c| if args.include?(c) args[c] else nil end end else raise ArgumentError, "expected Array of or Hash of components of #{self.class} (#{self.class.component.join(', ')})" end tmp << true return self.new(*tmp) end # # == Args # # +scheme+:: # Protocol scheme, i.e. 'http','ftp','mailto' and so on. # +userinfo+:: # User name and password, i.e. 'sdmitry:bla' # +host+:: # Server host name # +port+:: # Server port # +registry+:: # DOC: FIXME! # +path+:: # Path on server # +opaque+:: # DOC: FIXME! # +query+:: # Query data # +fragment+:: # A part of URI after '#' sign # +arg_check+:: # Check arguments [false by default] # # == Description # # Creates a new URI::Generic instance from ``generic'' components without check. # def initialize(scheme, userinfo, host, port, registry, path, opaque, query, fragment, arg_check = false) @scheme = nil @user = nil @password = nil @host = nil @port = nil @path = nil @query = nil @opaque = nil @registry = nil @fragment = nil if arg_check self.scheme = scheme self.userinfo = userinfo self.host = host self.port = port self.path = path self.query = query self.opaque = opaque self.registry = registry self.fragment = fragment else self.set_scheme(scheme) self.set_userinfo(userinfo) self.set_host(host) self.set_port(port) self.set_path(path) self.set_query(query) self.set_opaque(opaque) self.set_registry(registry) self.set_fragment(fragment) end if @registry && !self.class.use_registry raise InvalidURIError, "the scheme #{@scheme} does not accept registry part: #{@registry} (or bad hostname?)" end @scheme.freeze if @scheme self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2) self.set_port(self.default_port) if self.default_port && !@port end attr_reader :scheme attr_reader :host attr_reader :port attr_reader :registry attr_reader :path attr_reader :query attr_reader :opaque attr_reader :fragment # replace self by other URI object def replace!(oth) if self.class != oth.class raise ArgumentError, "expected #{self.class} object" end component.each do |c| self.__send__("#{c}=", oth.__send__(c)) end end private :replace! def component self.class.component end def check_scheme(v) if v && SCHEME !~ v raise InvalidComponentError, "bad component(expected scheme component): #{v}" end return true end private :check_scheme def set_scheme(v) @scheme = v end protected :set_scheme def scheme=(v) check_scheme(v) set_scheme(v) v end def check_userinfo(user, password = nil) if !password user, password = split_userinfo(user) end check_user(user) check_password(password, user) return true end private :check_userinfo def check_user(v) if @registry || @opaque raise InvalidURIError, "can not set user with registry or opaque" end return v unless v if USERINFO !~ v raise InvalidComponentError, "bad component(expected userinfo component or user component): #{v}" end return true end private :check_user def check_password(v, user = @user) if @registry || @opaque raise InvalidURIError, "can not set password with registry or opaque" end return v unless v if !user raise InvalidURIError, "password component depends user component" end if USERINFO !~ v raise InvalidComponentError, "bad component(expected user component): #{v}" end return true end private :check_password # # Sets userinfo, argument is string like 'name:pass' # def userinfo=(userinfo) if userinfo.nil? return nil end check_userinfo(*userinfo) set_userinfo(*userinfo) # returns userinfo end def user=(user) check_user(user) set_user(user) # returns user end def password=(password) check_password(password) set_password(password) # returns password end def set_userinfo(user, password = nil) unless password user, password = split_userinfo(user) end @user = user @password = password if password [@user, @password] end protected :set_userinfo def set_user(v) set_userinfo(v, @password) v end protected :set_user def set_password(v) @password = v # returns v end protected :set_password def split_userinfo(ui) return nil, nil unless ui user, password = ui.split(/:/, 2) return user, password end private :split_userinfo def escape_userpass(v) v = URI.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/ end private :escape_userpass def userinfo if @user.nil? nil elsif @password.nil? @user else @user + ':' + @password end end def user @user end def password @password end def check_host(v) return v unless v if @registry || @opaque raise InvalidURIError, "can not set host with registry or opaque" elsif HOST !~ v raise InvalidComponentError, "bad component(expected host component): #{v}" end return true end private :check_host def set_host(v) @host = v end protected :set_host def host=(v) check_host(v) set_host(v) v end def check_port(v) return v unless v if @registry || @opaque raise InvalidURIError, "can not set port with registry or opaque" elsif !v.kind_of?(Fixnum) && PORT !~ v raise InvalidComponentError, "bad component(expected port component): #{v}" end return true end private :check_port def set_port(v) unless !v || v.kind_of?(Fixnum) if v.empty? v = nil else v = v.to_i end end @port = v end protected :set_port def port=(v) check_port(v) set_port(v) port end def check_registry(v) return v unless v # raise if both server and registry are not nil, because: # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] if @host || @port || @user # userinfo = @user + ':' + @password raise InvalidURIError, "can not set registry with host, port, or userinfo" elsif v && REGISTRY !~ v raise InvalidComponentError, "bad component(expected registry component): #{v}" end return true end private :check_registry def set_registry(v) @registry = v end protected :set_registry def registry=(v) check_registry(v) set_registry(v) v end def check_path(v) # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if v && @opaque raise InvalidURIError, "path conflicts with opaque" end if @scheme if v && v != '' && ABS_PATH !~ v raise InvalidComponentError, "bad component(expected absolute path component): #{v}" end else if v && v != '' && ABS_PATH !~ v && REL_PATH !~ v raise InvalidComponentError, "bad component(expected relative path component): #{v}" end end return true end private :check_path def set_path(v) @path = v end protected :set_path def path=(v) check_path(v) set_path(v) v end def check_query(v) return v unless v # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if @opaque raise InvalidURIError, "query conflicts with opaque" end if v && v != '' && QUERY !~ v raise InvalidComponentError, "bad component(expected query component): #{v}" end return true end private :check_query def set_query(v) @query = v end protected :set_query def query=(v) check_query(v) set_query(v) v end def check_opaque(v) return v unless v # raise if both hier and opaque are not nil, because: # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] if @host || @port || @user || @path # userinfo = @user + ':' + @password raise InvalidURIError, "can not set opaque with host, port, userinfo or path" elsif v && OPAQUE !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end return true end private :check_opaque def set_opaque(v) @opaque = v end protected :set_opaque def opaque=(v) check_opaque(v) set_opaque(v) v end def check_fragment(v) return v unless v if v && v != '' && FRAGMENT !~ v raise InvalidComponentError, "bad component(expected fragment component): #{v}" end return true end private :check_fragment def set_fragment(v) @fragment = v end protected :set_fragment def fragment=(v) check_fragment(v) set_fragment(v) v end # # Checks if URI has a path # def hierarchical? if @path true else false end end # # Checks if URI is an absolute one # def absolute? if @scheme true else false end end alias absolute absolute? # # Checks if URI is relative # def relative? !absolute? end def split_path(path) path.split(%r{/+}, -1) end private :split_path def merge_path(base, rel) # RFC2396, Section 5.2, 5) # RFC2396, Section 5.2, 6) base_path = split_path(base) rel_path = split_path(rel) # RFC2396, Section 5.2, 6), a) base_path << '' if base_path.last == '..' while i = base_path.index('..') base_path.slice!(i - 1, 2) end if (first = rel_path.first) and first.empty? base_path.clear rel_path.shift end # RFC2396, Section 5.2, 6), c) # RFC2396, Section 5.2, 6), d) rel_path.push('') if rel_path.last == '.' || rel_path.last == '..' rel_path.delete('.') # RFC2396, Section 5.2, 6), e) tmp = [] rel_path.each do |x| if x == '..' && !(tmp.empty? || tmp.last == '..') tmp.pop else tmp << x end end add_trailer_slash = !tmp.empty? if base_path.empty? base_path = [''] # keep '/' for root directory elsif add_trailer_slash base_path.pop end while x = tmp.shift if x == '..' # RFC2396, Section 4 # a .. or . in an absolute path has no special meaning base_path.pop if base_path.size > 1 else # if x == '..' # valid absolute (but abnormal) path "/../..." # else # valid absolute path # end base_path << x tmp.each {|t| base_path << t} add_trailer_slash = false break end end base_path.push('') if add_trailer_slash return base_path.join('/') end private :merge_path # # == Args # # +oth+:: # URI or String # # == Description # # Destructive form of #merge # # == Usage # # require 'uri' # # uri = URI.parse("http://my.example.com") # uri.merge!("/main.rbx?page=1") # p uri # # => # # def merge!(oth) t = merge(oth) if self == t nil else replace!(t) self end end # # == Args # # +oth+:: # URI or String # # == Description # # Merges two URI's. # # == Usage # # require 'uri' # # uri = URI.parse("http://my.example.com") # p uri.merge("/main.rbx?page=1") # # => # # def merge(oth) begin base, rel = merge0(oth) rescue raise $!.class, $!.message end if base == rel return base end authority = rel.userinfo || rel.host || rel.port # RFC2396, Section 5.2, 2) if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query base.set_fragment(rel.fragment) if rel.fragment return base end base.set_query(nil) base.set_fragment(nil) # RFC2396, Section 5.2, 4) if !authority base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path else # RFC2396, Section 5.2, 4) base.set_path(rel.path) if rel.path end # RFC2396, Section 5.2, 7) base.set_userinfo(rel.userinfo) if rel.userinfo base.set_host(rel.host) if rel.host base.set_port(rel.port) if rel.port base.set_query(rel.query) if rel.query base.set_fragment(rel.fragment) if rel.fragment return base end # merge alias + merge # return base and rel. # you can modify `base', but can not `rel'. def merge0(oth) case oth when Generic when String oth = URI.parse(oth) else raise ArgumentError, "bad argument(expected URI object or URI string)" end if self.relative? && oth.relative? raise BadURIError, "both URI are relative" end if self.absolute? && oth.absolute? #raise BadURIError, # "both URI are absolute" # hmm... should return oth for usability? return oth, oth end if self.absolute? return self.dup, oth else return oth, oth end end private :merge0 def route_from_path(src, dst) case dst when src # RFC2396, Section 4.2 return '' when %r{(?:\A|/)\.\.?(?:/|\z)} # dst has abnormal absolute path, # like "/./", "/../", "/x/../", ... return dst.dup end src_path = src.scan(%r{(?:\A|[^/]+)/}) dst_path = dst.scan(%r{(?:\A|[^/]+)/?}) # discard same parts while !dst_path.empty? && dst_path.first == src_path.first src_path.shift dst_path.shift end tmp = dst_path.join # calculate if src_path.empty? if tmp.empty? return './' elsif dst_path.first.include?(':') # (see RFC2396 Section 5) return './' + tmp else return tmp end end return '../' * src_path.size + tmp end private :route_from_path def route_from0(oth) case oth when Generic when String oth = URI.parse(oth) else raise ArgumentError, "bad argument(expected URI object or URI string)" end if self.relative? raise BadURIError, "relative URI: #{self}" end if oth.relative? raise BadURIError, "relative URI: #{oth}" end if self.scheme != oth.scheme return self, self.dup end rel = URI::Generic.new(nil, # it is relative URI self.userinfo, self.host, self.port, self.registry, self.path, self.opaque, self.query, self.fragment) if rel.userinfo != oth.userinfo || rel.host.to_s.downcase != oth.host.to_s.downcase || rel.port != oth.port if self.userinfo.nil? && self.host.nil? return self, self.dup end rel.set_port(nil) if rel.port == oth.default_port return rel, rel end rel.set_userinfo(nil) rel.set_host(nil) rel.set_port(nil) if rel.path && rel.path == oth.path rel.set_path('') rel.set_query(nil) if rel.query == oth.query return rel, rel elsif rel.opaque && rel.opaque == oth.opaque rel.set_opaque('') rel.set_query(nil) if rel.query == oth.query return rel, rel end # you can modify `rel', but can not `oth'. return oth, rel end private :route_from0 # # == Args # # +oth+:: # URI or String # # == Description # # Calculates relative path from oth to self # # == Usage # # require 'uri' # # uri = URI.parse('http://my.example.com/main.rbx?page=1') # p uri.route_from('http://my.example.com') # #=> # # def route_from(oth) # you can modify `rel', but can not `oth'. begin oth, rel = route_from0(oth) rescue raise $!.class, $!.message end if oth == rel return rel end rel.set_path(route_from_path(oth.path, self.path)) if rel.path == './' && self.query # "./?foo" -> "?foo" rel.set_path('') end return rel end alias - route_from # # == Args # # +oth+:: # URI or String # # == Description # # Calculates relative path to oth from self # # == Usage # # require 'uri' # # uri = URI.parse('http://my.example.com') # p uri.route_to('http://my.example.com/main.rbx?page=1') # #=> # # def route_to(oth) case oth when Generic when String oth = URI.parse(oth) else raise ArgumentError, "bad argument(expected URI object or URI string)" end oth.route_from(self) end # # Returns normalized URI # def normalize uri = dup uri.normalize! uri end # # Destructive version of #normalize # def normalize! if path && path == '' set_path('/') end if host && host != host.downcase set_host(self.host.downcase) end end def path_query str = @path if @query str += '?' + @query end str end private :path_query # # Constructs String from URI # def to_s str = '' if @scheme str << @scheme str << ':' end if @opaque str << @opaque else if @registry str << @registry else if @host str << '//' end if self.userinfo str << self.userinfo str << '@' end if @host str << @host end if @port && @port != self.default_port str << ':' str << @port.to_s end end str << path_query end if @fragment str << '#' str << @fragment end str end # # Compares to URI's # def ==(oth) if self.class == oth.class self.normalize.component_ary == oth.normalize.component_ary else false end end def hash self.component_ary.hash end def eql?(oth) self.class == oth.class && self.component_ary.eql?(oth.component_ary) end =begin --- URI::Generic#===(oth) =end # def ===(oth) # raise NotImplementedError # end =begin =end def component_ary component.collect do |x| self.send(x) end end protected :component_ary # == Args # # +components+:: # Multiple Symbol arguments defined in URI::HTTP # # == Description # # Selects specified components from URI # # == Usage # # require 'uri' # # uri = URI.parse('http://myuser:mypass@my.example.com/test.rbx') # p uri.select(:userinfo, :host, :path) # # => ["myuser:mypass", "my.example.com", "/test.rbx"] # def select(*components) components.collect do |c| if component.include?(c) self.send(c) else raise ArgumentError, "expected of components of #{self.class} (#{self.class.component.join(', ')})" end end end @@to_s = Kernel.instance_method(:to_s) def inspect @@to_s.bind(self).call.sub!(/>\z/) {" URL:#{self}>"} end def coerce(oth) case oth when String oth = URI.parse(oth) else super end return oth, self end end end PK|]OKi  uri/ldap.rbnu[# # = uri/ldap.rb # # Author:: # Takaaki Tateishi # Akira Yamada # License:: # URI::LDAP is copyrighted free software by Takaaki Tateishi and Akira Yamada. # You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id: ldap.rb 11708 2007-02-12 23:01:19Z shyouhei $ # require 'uri/generic' module URI # # LDAP URI SCHEMA (described in RFC2255) # ldap:///[?[?[?[?]]]] # class LDAP < Generic DEFAULT_PORT = 389 COMPONENT = [ :scheme, :host, :port, :dn, :attributes, :scope, :filter, :extensions, ].freeze SCOPE = [ SCOPE_ONE = 'one', SCOPE_SUB = 'sub', SCOPE_BASE = 'base', ].freeze def self.build(args) tmp = Util::make_components_hash(self, args) if tmp[:dn] tmp[:path] = tmp[:dn] end query = [] [:extensions, :filter, :scope, :attributes].collect do |x| next if !tmp[x] && query.size == 0 query.unshift(tmp[x]) end tmp[:query] = query.join('?') return super(tmp) end def initialize(*arg) super(*arg) if @fragment raise InvalidURIError, 'bad LDAP URL' end parse_dn parse_query end def parse_dn @dn = @path[1..-1] end private :parse_dn def parse_query @attributes = nil @scope = nil @filter = nil @extensions = nil if @query attrs, scope, filter, extensions = @query.split('?') @attributes = attrs if attrs && attrs.size > 0 @scope = scope if scope && scope.size > 0 @filter = filter if filter && filter.size > 0 @extensions = extensions if extensions && extensions.size > 0 end end private :parse_query def build_path_query @path = '/' + @dn query = [] [@extensions, @filter, @scope, @attributes].each do |x| next if !x && query.size == 0 query.unshift(x) end @query = query.join('?') end private :build_path_query def dn @dn end def set_dn(val) @dn = val build_path_query @dn end protected :set_dn def dn=(val) set_dn(val) val end def attributes @attributes end def set_attributes(val) @attributes = val build_path_query @attributes end protected :set_attributes def attributes=(val) set_attributes(val) val end def scope @scope end def set_scope(val) @scope = val build_path_query @scope end protected :set_scope def scope=(val) set_scope(val) val end def filter @filter end def set_filter(val) @filter = val build_path_query @filter end protected :set_filter def filter=(val) set_filter(val) val end def extensions @extensions end def set_extensions(val) @extensions = val build_path_query @extensions end protected :set_extensions def extensions=(val) set_extensions(val) val end def hierarchical? false end end @@schemes['LDAP'] = LDAP end PK|]? uri/ldaps.rbnu[require 'uri/ldap' module URI # The default port for LDAPS URIs is 636, and the scheme is 'ldaps:' rather # than 'ldap:'. Other than that, LDAPS URIs are identical to LDAP URIs; # see URI::LDAP. class LDAPS < LDAP DEFAULT_PORT = 636 end @@schemes['LDAPS'] = LDAPS end PK|]UT uri/ftp.rbnu[# # = uri/ftp.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id: ftp.rb 16085 2008-04-19 11:56:22Z knu $ # require 'uri/generic' module URI # # FTP URI syntax is defined by RFC1738 section 3.2. # class FTP < Generic DEFAULT_PORT = 21 COMPONENT = [ :scheme, :userinfo, :host, :port, :path, :typecode ].freeze # # Typecode is "a", "i" or "d". # # * "a" indicates a text file (the FTP command was ASCII) # * "i" indicates a binary file (FTP command IMAGE) # * "d" indicates the contents of a directory should be displayed # TYPECODE = ['a', 'i', 'd'].freeze TYPECODE_PREFIX = ';type='.freeze def self.new2(user, password, host, port, path, typecode = nil, arg_check = true) typecode = nil if typecode.size == 0 if typecode && !TYPECODE.include?(typecode) raise ArgumentError, "bad typecode is specified: #{typecode}" end # do escape self.new('ftp', [user, password], host, port, nil, typecode ? path + TYPECODE_PREFIX + typecode : path, nil, nil, nil, arg_check) end # # == Description # # Creates a new URI::FTP object from components, with syntax checking. # # The components accepted are +userinfo+, +host+, +port+, +path+ and # +typecode+. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the order # [userinfo, host, port, path, typecode] # # If the path supplied is absolute, it will be escaped in order to # make it absolute in the URI. Examples: # # require 'uri' # # uri = URI::FTP.build(['user:password', 'ftp.example.com', nil, # '/path/file.> zip', 'i']) # puts uri.to_s -> ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=a # # uri2 = URI::FTP.build({:host => 'ftp.example.com', # :path => 'ruby/src'}) # puts uri2.to_s -> ftp://ftp.example.com/ruby/src # def self.build(args) # Fix the incoming path to be generic URL syntax # FTP path -> URL path # foo/bar /foo/bar # /foo/bar /%2Ffoo/bar # if args.kind_of?(Array) args[3] = '/' + args[3].sub(/^\//, '%2F') else args[:path] = '/' + args[:path].sub(/^\//, '%2F') end tmp = Util::make_components_hash(self, args) if tmp[:typecode] if tmp[:typecode].size == 1 tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode] end tmp[:path] << tmp[:typecode] end return super(tmp) end # # == Description # # Creates a new URI::FTP object from generic URL components with no # syntax checking. # # Unlike build(), this method does not escape the path component as # required by RFC1738; instead it is treated as per RFC2396. # # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+, # +opaque+, +query+ and +fragment+, in that order. # def initialize(*arg) super(*arg) @typecode = nil tmp = @path.index(TYPECODE_PREFIX) if tmp typecode = @path[tmp + TYPECODE_PREFIX.size..-1] self.set_path(@path[0..tmp - 1]) if arg[-1] self.typecode = typecode else self.set_typecode(typecode) end end end attr_reader :typecode def check_typecode(v) if TYPECODE.include?(v) return true else raise InvalidComponentError, "bad typecode(expected #{TYPECODE.join(', ')}): #{v}" end end private :check_typecode def set_typecode(v) @typecode = v end protected :set_typecode def typecode=(typecode) check_typecode(typecode) set_typecode(typecode) typecode end def merge(oth) # :nodoc: tmp = super(oth) if self != tmp tmp.set_typecode(oth.typecode) end return tmp end # Returns the path from an FTP URI. # # RFC 1738 specifically states that the path for an FTP URI does not # include the / which separates the URI path from the URI host. Example: # # ftp://ftp.example.com/pub/ruby # # The above URI indicates that the client should connect to # ftp.example.com then cd pub/ruby from the initial login directory. # # If you want to cd to an absolute directory, you must include an # escaped / (%2F) in the path. Example: # # ftp://ftp.example.com/%2Fpub/ruby # # This method will then return "/pub/ruby" # def path return @path.sub(/^\//,'').sub(/^%2F/i,'/') end def to_s save_path = nil if @typecode save_path = @path @path = @path + TYPECODE_PREFIX + @typecode end str = super if @typecode @path = save_path end return str end end @@schemes['FTP'] = FTP end PK|]/[DD uri/common.rbnu[# = uri/common.rb # # Author:: Akira Yamada # Revision:: $Id: common.rb 14178 2007-12-10 09:31:55Z matz $ # License:: # You can redistribute it and/or modify it under the same term as Ruby. # module URI module REGEXP # # Patterns used to parse URI's # module PATTERN # :stopdoc: # RFC 2396 (URI Generic Syntax) # RFC 2732 (IPv6 Literal Addresses in URL's) # RFC 2373 (IPv6 Addressing Architecture) # alpha = lowalpha | upalpha ALPHA = "a-zA-Z" # alphanum = alpha | digit ALNUM = "#{ALPHA}\\d" # hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | # "a" | "b" | "c" | "d" | "e" | "f" HEX = "a-fA-F\\d" # escaped = "%" hex hex ESCAPED = "%[#{HEX}]{2}" # mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | # "(" | ")" # unreserved = alphanum | mark UNRESERVED = "-_.!~*'()#{ALNUM}" # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | # "$" | "," # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | # "$" | "," | "[" | "]" (RFC 2732) RESERVED = ";/?:@&=+$,\\[\\]" # uric = reserved | unreserved | escaped URIC = "(?:[#{UNRESERVED}#{RESERVED}]|#{ESCAPED})" # uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | # "&" | "=" | "+" | "$" | "," URIC_NO_SLASH = "(?:[#{UNRESERVED};?:@&=+$,]|#{ESCAPED})" # query = *uric QUERY = "#{URIC}*" # fragment = *uric FRAGMENT = "#{URIC}*" # domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)" # toplabel = alpha | alpha *( alphanum | "-" ) alphanum TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)" # hostname = *( domainlabel "." ) toplabel [ "." ] HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?" # RFC 2373, APPENDIX B: # IPv6address = hexpart [ ":" IPv4address ] # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT # hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ] # hexseq = hex4 *( ":" hex4) # hex4 = 1*4HEXDIG # # XXX: This definition has a flaw. "::" + IPv4address must be # allowed too. Here is a replacement. # # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT IPV4ADDR = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}" # hex4 = 1*4HEXDIG HEX4 = "[#{HEX}]{1,4}" # lastpart = hex4 | IPv4address LASTPART = "(?:#{HEX4}|#{IPV4ADDR})" # hexseq1 = *( hex4 ":" ) hex4 HEXSEQ1 = "(?:#{HEX4}:)*#{HEX4}" # hexseq2 = *( hex4 ":" ) lastpart HEXSEQ2 = "(?:#{HEX4}:)*#{LASTPART}" # IPv6address = hexseq2 | [ hexseq1 ] "::" [ hexseq2 ] IPV6ADDR = "(?:#{HEXSEQ2}|(?:#{HEXSEQ1})?::(?:#{HEXSEQ2})?)" # IPv6prefix = ( hexseq1 | [ hexseq1 ] "::" [ hexseq1 ] ) "/" 1*2DIGIT # unused # ipv6reference = "[" IPv6address "]" (RFC 2732) IPV6REF = "\\[#{IPV6ADDR}\\]" # host = hostname | IPv4address # host = hostname | IPv4address | IPv6reference (RFC 2732) HOST = "(?:#{HOSTNAME}|#{IPV4ADDR}|#{IPV6REF})" # port = *digit PORT = '\d*' # hostport = host [ ":" port ] HOSTPORT = "#{HOST}(?::#{PORT})?" # userinfo = *( unreserved | escaped | # ";" | ":" | "&" | "=" | "+" | "$" | "," ) USERINFO = "(?:[#{UNRESERVED};:&=+$,]|#{ESCAPED})*" # pchar = unreserved | escaped | # ":" | "@" | "&" | "=" | "+" | "$" | "," PCHAR = "(?:[#{UNRESERVED}:@&=+$,]|#{ESCAPED})" # param = *pchar PARAM = "#{PCHAR}*" # segment = *pchar *( ";" param ) SEGMENT = "#{PCHAR}*(?:;#{PARAM})*" # path_segments = segment *( "/" segment ) PATH_SEGMENTS = "#{SEGMENT}(?:/#{SEGMENT})*" # server = [ [ userinfo "@" ] hostport ] SERVER = "(?:#{USERINFO}@)?#{HOSTPORT}" # reg_name = 1*( unreserved | escaped | "$" | "," | # ";" | ":" | "@" | "&" | "=" | "+" ) REG_NAME = "(?:[#{UNRESERVED}$,;:@&=+]|#{ESCAPED})+" # authority = server | reg_name AUTHORITY = "(?:#{SERVER}|#{REG_NAME})" # rel_segment = 1*( unreserved | escaped | # ";" | "@" | "&" | "=" | "+" | "$" | "," ) REL_SEGMENT = "(?:[#{UNRESERVED};@&=+$,]|#{ESCAPED})+" # scheme = alpha *( alpha | digit | "+" | "-" | "." ) SCHEME = "[#{ALPHA}][-+.#{ALPHA}\\d]*" # abs_path = "/" path_segments ABS_PATH = "/#{PATH_SEGMENTS}" # rel_path = rel_segment [ abs_path ] REL_PATH = "#{REL_SEGMENT}(?:#{ABS_PATH})?" # net_path = "//" authority [ abs_path ] NET_PATH = "//#{AUTHORITY}(?:#{ABS_PATH})?" # hier_part = ( net_path | abs_path ) [ "?" query ] HIER_PART = "(?:#{NET_PATH}|#{ABS_PATH})(?:\\?(?:#{QUERY}))?" # opaque_part = uric_no_slash *uric OPAQUE_PART = "#{URIC_NO_SLASH}#{URIC}*" # absoluteURI = scheme ":" ( hier_part | opaque_part ) ABS_URI = "#{SCHEME}:(?:#{HIER_PART}|#{OPAQUE_PART})" # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] REL_URI = "(?:#{NET_PATH}|#{ABS_PATH}|#{REL_PATH})(?:\\?#{QUERY})?" # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] URI_REF = "(?:#{ABS_URI}|#{REL_URI})?(?:##{FRAGMENT})?" # XXX: X_ABS_URI = " (#{PATTERN::SCHEME}): (?# 1: scheme) (?: (#{PATTERN::OPAQUE_PART}) (?# 2: opaque) | (?:(?: //(?: (?:(?:(#{PATTERN::USERINFO})@)? (?# 3: userinfo) (?:(#{PATTERN::HOST})(?::(\\d*))?))?(?# 4: host, 5: port) | (#{PATTERN::REG_NAME}) (?# 6: registry) ) | (?!//)) (?# XXX: '//' is the mark for hostport) (#{PATTERN::ABS_PATH})? (?# 7: path) )(?:\\?(#{PATTERN::QUERY}))? (?# 8: query) ) (?:\\#(#{PATTERN::FRAGMENT}))? (?# 9: fragment) " X_REL_URI = " (?: (?: // (?: (?:(#{PATTERN::USERINFO})@)? (?# 1: userinfo) (#{PATTERN::HOST})?(?::(\\d*))? (?# 2: host, 3: port) | (#{PATTERN::REG_NAME}) (?# 4: registry) ) ) | (#{PATTERN::REL_SEGMENT}) (?# 5: rel_segment) )? (#{PATTERN::ABS_PATH})? (?# 6: abs_path) (?:\\?(#{PATTERN::QUERY}))? (?# 7: query) (?:\\#(#{PATTERN::FRAGMENT}))? (?# 8: fragment) " # :startdoc: end # PATTERN # :stopdoc: # for URI::split ABS_URI = Regexp.new('^' + PATTERN::X_ABS_URI + '$', #' Regexp::EXTENDED, 'N').freeze REL_URI = Regexp.new('^' + PATTERN::X_REL_URI + '$', #' Regexp::EXTENDED, 'N').freeze # for URI::extract URI_REF = Regexp.new(PATTERN::URI_REF, false, 'N').freeze ABS_URI_REF = Regexp.new(PATTERN::X_ABS_URI, Regexp::EXTENDED, 'N').freeze REL_URI_REF = Regexp.new(PATTERN::X_REL_URI, Regexp::EXTENDED, 'N').freeze # for URI::escape/unescape ESCAPED = Regexp.new(PATTERN::ESCAPED, false, 'N').freeze UNSAFE = Regexp.new("[^#{PATTERN::UNRESERVED}#{PATTERN::RESERVED}]", false, 'N').freeze # for Generic#initialize SCHEME = Regexp.new("^#{PATTERN::SCHEME}$", false, 'N').freeze #" USERINFO = Regexp.new("^#{PATTERN::USERINFO}$", false, 'N').freeze #" HOST = Regexp.new("^#{PATTERN::HOST}$", false, 'N').freeze #" PORT = Regexp.new("^#{PATTERN::PORT}$", false, 'N').freeze #" OPAQUE = Regexp.new("^#{PATTERN::OPAQUE_PART}$", false, 'N').freeze #" REGISTRY = Regexp.new("^#{PATTERN::REG_NAME}$", false, 'N').freeze #" ABS_PATH = Regexp.new("^#{PATTERN::ABS_PATH}$", false, 'N').freeze #" REL_PATH = Regexp.new("^#{PATTERN::REL_PATH}$", false, 'N').freeze #" QUERY = Regexp.new("^#{PATTERN::QUERY}$", false, 'N').freeze #" FRAGMENT = Regexp.new("^#{PATTERN::FRAGMENT}$", false, 'N').freeze #" # :startdoc: end # REGEXP module Util # :nodoc: def make_components_hash(klass, array_hash) tmp = {} if array_hash.kind_of?(Array) && array_hash.size == klass.component.size - 1 klass.component[1..-1].each_index do |i| begin tmp[klass.component[i + 1]] = array_hash[i].clone rescue TypeError tmp[klass.component[i + 1]] = array_hash[i] end end elsif array_hash.kind_of?(Hash) array_hash.each do |key, value| begin tmp[key] = value.clone rescue TypeError tmp[key] = value end end else raise ArgumentError, "expected Array of or Hash of components of #{klass.to_s} (#{klass.component[1..-1].join(', ')})" end tmp[:scheme] = klass.to_s.sub(/\A.*::/, '').downcase return tmp end module_function :make_components_hash end module Escape include REGEXP # # == Synopsis # # URI.escape(str [, unsafe]) # # == Args # # +str+:: # String to replaces in. # +unsafe+:: # Regexp that matches all symbols that must be replaced with codes. # By default uses REGEXP::UNSAFE. # When this argument is a String, it represents a character set. # # == Description # # Escapes the string, replacing all unsafe characters with codes. # # == Usage # # require 'uri' # # enc_uri = URI.escape("http://example.com/?a=\11\15") # p enc_uri # # => "http://example.com/?a=%09%0D" # # p URI.unescape(enc_uri) # # => "http://example.com/?a=\t\r" # # p URI.escape("@?@!", "!?") # # => "@%3F@%21" # def escape(str, unsafe = UNSAFE) unless unsafe.kind_of?(Regexp) # perhaps unsafe is String object unsafe = Regexp.new("[#{Regexp.quote(unsafe)}]", false, 'N') end str.gsub(unsafe) do |us| tmp = '' us.each_byte do |uc| tmp << sprintf('%%%02X', uc) end tmp end end alias encode escape # # == Synopsis # # URI.unescape(str) # # == Args # # +str+:: # Unescapes the string. # # == Usage # # require 'uri' # # enc_uri = URI.escape("http://example.com/?a=\11\15") # p enc_uri # # => "http://example.com/?a=%09%0D" # # p URI.unescape(enc_uri) # # => "http://example.com/?a=\t\r" # def unescape(str) str.gsub(ESCAPED) do $&[1,2].hex.chr end end alias decode unescape end include REGEXP extend Escape @@schemes = {} # # Base class for all URI exceptions. # class Error < StandardError; end # # Not a URI. # class InvalidURIError < Error; end # # Not a URI component. # class InvalidComponentError < Error; end # # URI is valid, bad usage is not. # class BadURIError < Error; end # # == Synopsis # # URI::split(uri) # # == Args # # +uri+:: # String with URI. # # == Description # # Splits the string on following parts and returns array with result: # # * Scheme # * Userinfo # * Host # * Port # * Registry # * Path # * Opaque # * Query # * Fragment # # == Usage # # require 'uri' # # p URI.split("http://www.ruby-lang.org/") # # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil] # def self.split(uri) case uri when '' # null uri when ABS_URI scheme, opaque, userinfo, host, port, registry, path, query, fragment = $~[1..-1] # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] # absoluteURI = scheme ":" ( hier_part | opaque_part ) # hier_part = ( net_path | abs_path ) [ "?" query ] # opaque_part = uric_no_slash *uric # abs_path = "/" path_segments # net_path = "//" authority [ abs_path ] # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] if !scheme raise InvalidURIError, "bad URI(absolute but no scheme): #{uri}" end if !opaque && (!path && (!host && !registry)) raise InvalidURIError, "bad URI(absolute but no path): #{uri}" end when REL_URI scheme = nil opaque = nil userinfo, host, port, registry, rel_segment, abs_path, query, fragment = $~[1..-1] if rel_segment && abs_path path = rel_segment + abs_path elsif rel_segment path = rel_segment elsif abs_path path = abs_path end # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] # net_path = "//" authority [ abs_path ] # abs_path = "/" path_segments # rel_path = rel_segment [ abs_path ] # authority = server | reg_name # server = [ [ userinfo "@" ] hostport ] else raise InvalidURIError, "bad URI(is not URI?): #{uri}" end path = '' if !path && !opaque # (see RFC2396 Section 5.2) ret = [ scheme, userinfo, host, port, # X registry, # X path, # Y opaque, # Y query, fragment ] return ret end # # == Synopsis # # URI::parse(uri_str) # # == Args # # +uri_str+:: # String with URI. # # == Description # # Creates one of the URI's subclasses instance from the string. # # == Raises # # URI::InvalidURIError # Raised if URI given is not a correct one. # # == Usage # # require 'uri' # # uri = URI.parse("http://www.ruby-lang.org/") # p uri # # => # # p uri.scheme # # => "http" # p uri.host # # => "www.ruby-lang.org" # def self.parse(uri) scheme, userinfo, host, port, registry, path, opaque, query, fragment = self.split(uri) if scheme && @@schemes.include?(scheme.upcase) @@schemes[scheme.upcase].new(scheme, userinfo, host, port, registry, path, opaque, query, fragment) else Generic.new(scheme, userinfo, host, port, registry, path, opaque, query, fragment) end end # # == Synopsis # # URI::join(str[, str, ...]) # # == Args # # +str+:: # String(s) to work with # # == Description # # Joins URIs. # # == Usage # # require 'uri' # # p URI.join("http://localhost/","main.rbx") # # => # # def self.join(*str) u = self.parse(str[0]) str[1 .. -1].each do |x| u = u.merge(x) end u end # # == Synopsis # # URI::extract(str[, schemes][,&blk]) # # == Args # # +str+:: # String to extract URIs from. # +schemes+:: # Limit URI matching to a specific schemes. # # == Description # # Extracts URIs from a string. If block given, iterates through all matched URIs. # Returns nil if block given or array with matches. # # == Usage # # require "uri" # # URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.") # # => ["http://foo.example.com/bla", "mailto:test@example.com"] # def self.extract(str, schemes = nil, &block) if block_given? str.scan(regexp(schemes)) { yield $& } nil else result = [] str.scan(regexp(schemes)) { result.push $& } result end end # # == Synopsis # # URI::regexp([match_schemes]) # # == Args # # +match_schemes+:: # Array of schemes. If given, resulting regexp matches to URIs # whose scheme is one of the match_schemes. # # == Description # Returns a Regexp object which matches to URI-like strings. # The Regexp object returned by this method includes arbitrary # number of capture group (parentheses). Never rely on it's number. # # == Usage # # require 'uri' # # # extract first URI from html_string # html_string.slice(URI.regexp) # # # remove ftp URIs # html_string.sub(URI.regexp(['ftp']) # # # You should not rely on the number of parentheses # html_string.scan(URI.regexp) do |*matches| # p $& # end # def self.regexp(schemes = nil) unless schemes ABS_URI_REF else /(?=#{Regexp.union(*schemes)}:)#{PATTERN::X_ABS_URI}/xn end end end module Kernel # alias for URI.parse. # # This method is introduced at 1.8.2. def URI(uri_str) # :doc: URI.parse(uri_str) end module_function :URI end PK|](p0Z Z uri/http.rbnu[# # = uri/http.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id: http.rb 11747 2007-02-15 02:41:45Z knu $ # require 'uri/generic' module URI # # The syntax of HTTP URIs is defined in RFC1738 section 3.3. # # Note that the Ruby URI library allows HTTP URLs containing usernames and # passwords. This is not legal as per the RFC, but used to be # supported in Internet Explorer 5 and 6, before the MS04-004 security # update. See . # class HTTP < Generic DEFAULT_PORT = 80 COMPONENT = [ :scheme, :userinfo, :host, :port, :path, :query, :fragment ].freeze # # == Description # # Create a new URI::HTTP object from components, with syntax checking. # # The components accepted are userinfo, host, port, path, query and # fragment. # # The components should be provided either as an Array, or as a Hash # with keys formed by preceding the component names with a colon. # # If an Array is used, the components must be passed in the order # [userinfo, host, port, path, query, fragment]. # # Example: # # newuri = URI::HTTP.build({:host => 'www.example.com', # :path> => '/foo/bar'}) # # newuri = URI::HTTP.build([nil, "www.example.com", nil, "/path", # "query", 'fragment']) # # Currently, if passed userinfo components this method generates # invalid HTTP URIs as per RFC 1738. # def self.build(args) tmp = Util::make_components_hash(self, args) return super(tmp) end # # == Description # # Create a new URI::HTTP object from generic URI components as per # RFC 2396. No HTTP-specific syntax checking (as per RFC 1738) is # performed. # # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+, # +opaque+, +query+ and +fragment+, in that order. # # Example: # # uri = URI::HTTP.new(['http', nil, "www.example.com", nil, "/path", # "query", 'fragment']) # def initialize(*arg) super(*arg) end # # == Description # # Returns the full path for an HTTP request, as required by Net::HTTP::Get. # # If the URI contains a query, the full path is URI#path + '?' + URI#query. # Otherwise, the path is simply URI#path. # def request_uri r = path_query if r[0] != ?/ r = '/' + r end r end end @@schemes['HTTP'] = HTTP end PK|]U uri/https.rbnu[# # = uri/https.rb # # Author:: Akira Yamada # License:: You can redistribute it and/or modify it under the same term as Ruby. # Revision:: $Id: https.rb 11747 2007-02-15 02:41:45Z knu $ # require 'uri/http' module URI # The default port for HTTPS URIs is 443, and the scheme is 'https:' rather # than 'http:'. Other than that, HTTPS URIs are identical to HTTP URIs; # see URI::HTTP. class HTTPS < HTTP DEFAULT_PORT = 443 end @@schemes['HTTPS'] = HTTPS end PK|]a WW ipaddr.rbnu[# # ipaddr.rb - A class to manipulate an IP address # # Copyright (c) 2002 Hajimu UMEMOTO . # Copyright (c) 2007 Akinori MUSHA . # All rights reserved. # # You can redistribute and/or modify it under the same terms as Ruby. # # $Id: ipaddr.rb 18049 2008-07-12 15:08:29Z shyouhei $ # # Contact: # - Akinori MUSHA (current maintainer) # # TODO: # - scope_id support # require 'socket' unless Socket.const_defined? "AF_INET6" class Socket AF_INET6 = Object.new end class << IPSocket def valid_v4?(addr) if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr return $~.captures.all? {|i| i.to_i < 256} end return false end def valid_v6?(addr) # IPv6 (normal) return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr # IPv6 (IPv4 compat) return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_v4?($') return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($') return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($') false end def valid?(addr) valid_v4?(addr) || valid_v6?(addr) end alias getaddress_orig getaddress def getaddress(s) if valid?(s) s elsif /\A[-A-Za-z\d.]+\Z/ =~ s getaddress_orig(s) else raise ArgumentError, "invalid address" end end end end # IPAddr provides a set of methods to manipulate an IP address. Both IPv4 and # IPv6 are supported. # # == Example # # require 'ipaddr' # # ipaddr1 = IPAddr.new "3ffe:505:2::1" # # p ipaddr1 #=> # # # p ipaddr1.to_s #=> "3ffe:505:2::1" # # ipaddr2 = ipaddr1.mask(48) #=> # # # p ipaddr2.to_s #=> "3ffe:505:2::" # # ipaddr3 = IPAddr.new "192.168.2.0/24" # # p ipaddr3 #=> # class IPAddr IN4MASK = 0xffffffff IN6MASK = 0xffffffffffffffffffffffffffffffff IN6FORMAT = (["%.4x"] * 8).join(':') # Returns the address family of this IP address. attr :family # Creates a new ipaddr containing the given network byte ordered # string form of an IP address. def IPAddr::new_ntoh(addr) return IPAddr.new(IPAddr::ntop(addr)) end # Convert a network byte ordered string form of an IP address into # human readable form. def IPAddr::ntop(addr) case addr.size when 4 s = addr.unpack('C4').join('.') when 16 s = IN6FORMAT % addr.unpack('n8') else raise ArgumentError, "unsupported address family" end return s end # Returns a new ipaddr built by bitwise AND. def &(other) return self.clone.set(@addr & coerce_other(other).to_i) end # Returns a new ipaddr built by bitwise OR. def |(other) return self.clone.set(@addr | coerce_other(other).to_i) end # Returns a new ipaddr built by bitwise right-shift. def >>(num) return self.clone.set(@addr >> num) end # Returns a new ipaddr built by bitwise left shift. def <<(num) return self.clone.set(addr_mask(@addr << num)) end # Returns a new ipaddr built by bitwise negation. def ~ return self.clone.set(addr_mask(~@addr)) end # Returns true if two ipaddrs are equal. def ==(other) other = coerce_other(other) return @family == other.family && @addr == other.to_i end # Returns a new ipaddr built by masking IP address with the given # prefixlen/netmask. (e.g. 8, 64, "255.255.255.0", etc.) def mask(prefixlen) return self.clone.mask!(prefixlen) end # Returns true if the given ipaddr is in the range. # # e.g.: # require 'ipaddr' # net1 = IPAddr.new("192.168.2.0/24") # net2 = IPAddr.new("192.168.2.100") # net3 = IPAddr.new("192.168.3.0") # p net1.include?(net2) #=> true # p net1.include?(net3) #=> false def include?(other) other = coerce_other(other) if ipv4_mapped? if (@mask_addr >> 32) != 0xffffffffffffffffffffffff return false end mask_addr = (@mask_addr & IN4MASK) addr = (@addr & IN4MASK) family = Socket::AF_INET else mask_addr = @mask_addr addr = @addr family = @family end if other.ipv4_mapped? other_addr = (other.to_i & IN4MASK) other_family = Socket::AF_INET else other_addr = other.to_i other_family = other.family end if family != other_family return false end return ((addr & mask_addr) == (other_addr & mask_addr)) end alias === include? # Returns the integer representation of the ipaddr. def to_i return @addr end # Returns a string containing the IP address representation. def to_s str = to_string return str if ipv4? str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1') loop do break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::') break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':') break if str.sub!(/\b0:0:0:0:0:0\b/, ':') break if str.sub!(/\b0:0:0:0:0\b/, ':') break if str.sub!(/\b0:0:0:0\b/, ':') break if str.sub!(/\b0:0:0\b/, ':') break if str.sub!(/\b0:0\b/, ':') break end str.sub!(/:{3,}/, '::') if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\Z/i =~ str str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256) end str end # Returns a string containing the IP address representation in # canonical form. def to_string return _to_string(@addr) end # Returns a network byte ordered string form of the IP address. def hton case @family when Socket::AF_INET return [@addr].pack('N') when Socket::AF_INET6 return (0..7).map { |i| (@addr >> (112 - 16 * i)) & 0xffff }.pack('n8') else raise "unsupported address family" end end # Returns true if the ipaddr is an IPv4 address. def ipv4? return @family == Socket::AF_INET end # Returns true if the ipaddr is an IPv6 address. def ipv6? return @family == Socket::AF_INET6 end # Returns true if the ipaddr is an IPv4-mapped IPv6 address. def ipv4_mapped? return ipv6? && (@addr >> 32) == 0xffff end # Returns true if the ipaddr is an IPv4-compatible IPv6 address. def ipv4_compat? if !ipv6? || (@addr >> 32) != 0 return false end a = (@addr & IN4MASK) return a != 0 && a != 1 end # Returns a new ipaddr built by converting the native IPv4 address # into an IPv4-mapped IPv6 address. def ipv4_mapped if !ipv4? raise ArgumentError, "not an IPv4 address" end return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6) end # Returns a new ipaddr built by converting the native IPv4 address # into an IPv4-compatible IPv6 address. def ipv4_compat if !ipv4? raise ArgumentError, "not an IPv4 address" end return self.clone.set(@addr, Socket::AF_INET6) end # Returns a new ipaddr built by converting the IPv6 address into a # native IPv4 address. If the IP address is not an IPv4-mapped or # IPv4-compatible IPv6 address, returns self. def native if !ipv4_mapped? && !ipv4_compat? return self end return self.clone.set(@addr & IN4MASK, Socket::AF_INET) end # Returns a string for DNS reverse lookup. It returns a string in # RFC3172 form for an IPv6 address. def reverse case @family when Socket::AF_INET return _reverse + ".in-addr.arpa" when Socket::AF_INET6 return ip6_arpa else raise "unsupported address family" end end # Returns a string for DNS reverse lookup compatible with RFC3172. def ip6_arpa if !ipv6? raise ArgumentError, "not an IPv6 address" end return _reverse + ".ip6.arpa" end # Returns a string for DNS reverse lookup compatible with RFC1886. def ip6_int if !ipv6? raise ArgumentError, "not an IPv6 address" end return _reverse + ".ip6.int" end # Returns the successor to the ipaddr. def succ return self.clone.set(@addr + 1, @family) end # Compares the ipaddr with another. def <=>(other) other = coerce_other(other) return nil if other.family != @family return @addr <=> other.to_i end include Comparable # Creates a Range object for the network address. def to_range begin_addr = (@addr & @mask_addr) case @family when Socket::AF_INET end_addr = (@addr | (IN4MASK ^ @mask_addr)) when Socket::AF_INET6 end_addr = (@addr | (IN6MASK ^ @mask_addr)) else raise "unsupported address family" end return clone.set(begin_addr, @family)..clone.set(end_addr, @family) end # Returns a string containing a human-readable representation of the # ipaddr. ("#") def inspect case @family when Socket::AF_INET af = "IPv4" when Socket::AF_INET6 af = "IPv6" else raise "unsupported address family" end return sprintf("#<%s: %s:%s/%s>", self.class.name, af, _to_string(@addr), _to_string(@mask_addr)) end protected def set(addr, *family) case family[0] ? family[0] : @family when Socket::AF_INET if addr < 0 || addr > IN4MASK raise ArgumentError, "invalid address" end when Socket::AF_INET6 if addr < 0 || addr > IN6MASK raise ArgumentError, "invalid address" end else raise ArgumentError, "unsupported address family" end @addr = addr if family[0] @family = family[0] end return self end def mask!(mask) if mask.kind_of?(String) if mask =~ /^\d+$/ prefixlen = mask.to_i else m = IPAddr.new(mask) if m.family != @family raise ArgumentError, "address family is not same" end @mask_addr = m.to_i @addr &= @mask_addr return self end else prefixlen = mask end case @family when Socket::AF_INET if prefixlen < 0 || prefixlen > 32 raise ArgumentError, "invalid length" end masklen = 32 - prefixlen @mask_addr = ((IN4MASK >> masklen) << masklen) when Socket::AF_INET6 if prefixlen < 0 || prefixlen > 128 raise ArgumentError, "invalid length" end masklen = 128 - prefixlen @mask_addr = ((IN6MASK >> masklen) << masklen) else raise "unsupported address family" end @addr = ((@addr >> masklen) << masklen) return self end private # Creates a new ipaddr object either from a human readable IP # address representation in string, or from a packed in_addr value # followed by an address family. # # In the former case, the following are the valid formats that will # be recognized: "address", "address/prefixlen" and "address/mask", # where IPv6 address may be enclosed in square brackets (`[' and # `]'). If a prefixlen or a mask is specified, it returns a masked # IP address. Although the address family is determined # automatically from a specified string, you can specify one # explicitly by the optional second argument. # # Otherwise an IP addess is generated from a packed in_addr value # and an address family. # # The IPAddr class defines many methods and operators, and some of # those, such as &, |, include? and ==, accept a string, or a packed # in_addr value instead of an IPAddr object. def initialize(addr = '::', family = Socket::AF_UNSPEC) if !addr.kind_of?(String) case family when Socket::AF_INET, Socket::AF_INET6 set(addr.to_i, family) @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK return when Socket::AF_UNSPEC raise ArgumentError, "address family must be specified" else raise ArgumentError, "unsupported address family: #{family}" end end prefix, prefixlen = addr.split('/') if prefix =~ /^\[(.*)\]$/i prefix = $1 family = Socket::AF_INET6 end # It seems AI_NUMERICHOST doesn't do the job. #Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil, # Socket::AI_NUMERICHOST) begin IPSocket.getaddress(prefix) # test if address is vaild rescue raise ArgumentError, "invalid address" end @addr = @family = nil if family == Socket::AF_UNSPEC || family == Socket::AF_INET @addr = in_addr(prefix) if @addr @family = Socket::AF_INET end end if !@addr && (family == Socket::AF_UNSPEC || family == Socket::AF_INET6) @addr = in6_addr(prefix) @family = Socket::AF_INET6 end if family != Socket::AF_UNSPEC && @family != family raise ArgumentError, "address family mismatch" end if prefixlen mask!(prefixlen) else @mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK end end def coerce_other(other) case other when IPAddr other when String self.class.new(other) else self.class.new(other, @family) end end def in_addr(addr) if addr =~ /^\d+\.\d+\.\d+\.\d+$/ return addr.split('.').inject(0) { |i, s| i << 8 | s.to_i } end return nil end def in6_addr(left) case left when /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i return in_addr($1) + 0xffff00000000 when /^::(\d+\.\d+\.\d+\.\d+)$/i return in_addr($1) when /[^0-9a-f:]/i raise ArgumentError, "invalid address" when /^(.*)::(.*)$/ left, right = $1, $2 else right = '' end l = left.split(':') r = right.split(':') rest = 8 - l.size - r.size if rest < 0 return nil end return (l + Array.new(rest, '0') + r).inject(0) { |i, s| i << 16 | s.hex } end def addr_mask(addr) case @family when Socket::AF_INET return addr & IN4MASK when Socket::AF_INET6 return addr & IN6MASK else raise "unsupported address family" end end def _reverse case @family when Socket::AF_INET return (0..3).map { |i| (@addr >> (8 * i)) & 0xff }.join('.') when Socket::AF_INET6 return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.') else raise "unsupported address family" end end def _to_string(addr) case @family when Socket::AF_INET return (0..3).map { |i| (addr >> (24 - 8 * i)) & 0xff }.join('.') when Socket::AF_INET6 return (("%.32x" % addr).gsub!(/.{4}(?!$)/, '\&:')) else raise "unsupported address family" end end end if $0 == __FILE__ eval DATA.read, nil, $0, __LINE__+4 end __END__ require 'test/unit' require 'test/unit/ui/console/testrunner' class TC_IPAddr < Test::Unit::TestCase def test_s_new assert_nothing_raised { IPAddr.new("3FFE:505:ffff::/48") IPAddr.new("0:0:0:1::") IPAddr.new("2001:200:300::/48") } a = IPAddr.new assert_equal("::", a.to_s) assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", a.to_string) assert_equal(Socket::AF_INET6, a.family) a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678") assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678", a.to_s) assert_equal("0123:4567:89ab:cdef:0abc:def0:1234:5678", a.to_string) assert_equal(Socket::AF_INET6, a.family) a = IPAddr.new("3ffe:505:2::/48") assert_equal("3ffe:505:2::", a.to_s) assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string) assert_equal(Socket::AF_INET6, a.family) assert_equal(false, a.ipv4?) assert_equal(true, a.ipv6?) assert_equal("#", a.inspect) a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::") assert_equal("3ffe:505:2::", a.to_s) assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string) assert_equal(Socket::AF_INET6, a.family) a = IPAddr.new("0.0.0.0") assert_equal("0.0.0.0", a.to_s) assert_equal("0.0.0.0", a.to_string) assert_equal(Socket::AF_INET, a.family) a = IPAddr.new("192.168.1.2") assert_equal("192.168.1.2", a.to_s) assert_equal("192.168.1.2", a.to_string) assert_equal(Socket::AF_INET, a.family) assert_equal(true, a.ipv4?) assert_equal(false, a.ipv6?) a = IPAddr.new("192.168.1.2/24") assert_equal("192.168.1.0", a.to_s) assert_equal("192.168.1.0", a.to_string) assert_equal(Socket::AF_INET, a.family) assert_equal("#", a.inspect) a = IPAddr.new("192.168.1.2/255.255.255.0") assert_equal("192.168.1.0", a.to_s) assert_equal("192.168.1.0", a.to_string) assert_equal(Socket::AF_INET, a.family) assert_equal("0:0:0:1::", IPAddr.new("0:0:0:1::").to_s) assert_equal("2001:200:300::", IPAddr.new("2001:200:300::/48").to_s) assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s) [ ["fe80::1%fxp0"], ["::1/255.255.255.0"], ["::1:192.168.1.2/120"], [IPAddr.new("::1").to_i], ["::ffff:192.168.1.2/120", Socket::AF_INET], ["[192.168.1.2]/120"], ].each { |args| assert_raises(ArgumentError) { IPAddr.new(*args) } } end def test_s_new_ntoh addr = '' IPAddr.new("1234:5678:9abc:def0:1234:5678:9abc:def0").hton.each_byte { |c| addr += sprintf("%02x", c) } assert_equal("123456789abcdef0123456789abcdef0", addr) addr = '' IPAddr.new("123.45.67.89").hton.each_byte { |c| addr += sprintf("%02x", c) } assert_equal(sprintf("%02x%02x%02x%02x", 123, 45, 67, 89), addr) a = IPAddr.new("3ffe:505:2::") assert_equal("3ffe:505:2::", IPAddr.new_ntoh(a.hton).to_s) a = IPAddr.new("192.168.2.1") assert_equal("192.168.2.1", IPAddr.new_ntoh(a.hton).to_s) end def test_ipv4_compat a = IPAddr.new("::192.168.1.2") assert_equal("::192.168.1.2", a.to_s) assert_equal("0000:0000:0000:0000:0000:0000:c0a8:0102", a.to_string) assert_equal(Socket::AF_INET6, a.family) assert_equal(true, a.ipv4_compat?) b = a.native assert_equal("192.168.1.2", b.to_s) assert_equal(Socket::AF_INET, b.family) assert_equal(false, b.ipv4_compat?) a = IPAddr.new("192.168.1.2") b = a.ipv4_compat assert_equal("::192.168.1.2", b.to_s) assert_equal(Socket::AF_INET6, b.family) end def test_ipv4_mapped a = IPAddr.new("::ffff:192.168.1.2") assert_equal("::ffff:192.168.1.2", a.to_s) assert_equal("0000:0000:0000:0000:0000:ffff:c0a8:0102", a.to_string) assert_equal(Socket::AF_INET6, a.family) assert_equal(true, a.ipv4_mapped?) b = a.native assert_equal("192.168.1.2", b.to_s) assert_equal(Socket::AF_INET, b.family) assert_equal(false, b.ipv4_mapped?) a = IPAddr.new("192.168.1.2") b = a.ipv4_mapped assert_equal("::ffff:192.168.1.2", b.to_s) assert_equal(Socket::AF_INET6, b.family) end def test_reverse assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").reverse) assert_equal("1.2.168.192.in-addr.arpa", IPAddr.new("192.168.2.1").reverse) end def test_ip6_arpa assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").ip6_arpa) assert_raises(ArgumentError) { IPAddr.new("192.168.2.1").ip6_arpa } end def test_ip6_int assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int", IPAddr.new("3ffe:505:2::f").ip6_int) assert_raises(ArgumentError) { IPAddr.new("192.168.2.1").ip6_int } end def test_to_s assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0001", IPAddr.new("3ffe:505:2::1").to_string) assert_equal("3ffe:505:2::1", IPAddr.new("3ffe:505:2::1").to_s) end end class TC_Operator < Test::Unit::TestCase IN6MASK32 = "ffff:ffff::" IN6MASK128 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" def setup @in6_addr_any = IPAddr.new() @a = IPAddr.new("3ffe:505:2::/48") @b = IPAddr.new("0:0:0:1::") @c = IPAddr.new(IN6MASK32) end alias set_up setup def test_or assert_equal("3ffe:505:2:1::", (@a | @b).to_s) a = @a a |= @b assert_equal("3ffe:505:2:1::", a.to_s) assert_equal("3ffe:505:2::", @a.to_s) assert_equal("3ffe:505:2:1::", (@a | 0x00000000000000010000000000000000).to_s) end def test_and assert_equal("3ffe:505::", (@a & @c).to_s) a = @a a &= @c assert_equal("3ffe:505::", a.to_s) assert_equal("3ffe:505:2::", @a.to_s) assert_equal("3ffe:505::", (@a & 0xffffffff000000000000000000000000).to_s) end def test_shift_right assert_equal("0:3ffe:505:2::", (@a >> 16).to_s) a = @a a >>= 16 assert_equal("0:3ffe:505:2::", a.to_s) assert_equal("3ffe:505:2::", @a.to_s) end def test_shift_left assert_equal("505:2::", (@a << 16).to_s) a = @a a <<= 16 assert_equal("505:2::", a.to_s) assert_equal("3ffe:505:2::", @a.to_s) end def test_carrot a = ~@in6_addr_any assert_equal(IN6MASK128, a.to_s) assert_equal("::", @in6_addr_any.to_s) end def test_equal assert_equal(true, @a == IPAddr.new("3ffe:505:2::")) assert_equal(false, @a == IPAddr.new("3ffe:505:3::")) assert_equal(true, @a != IPAddr.new("3ffe:505:3::")) assert_equal(false, @a != IPAddr.new("3ffe:505:2::")) end def test_mask a = @a.mask(32) assert_equal("3ffe:505::", a.to_s) assert_equal("3ffe:505:2::", @a.to_s) end def test_include? assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::"))) assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::1"))) assert_equal(false, @a.include?(IPAddr.new("3ffe:505:3::"))) net1 = IPAddr.new("192.168.2.0/24") assert_equal(true, net1.include?(IPAddr.new("192.168.2.0"))) assert_equal(true, net1.include?(IPAddr.new("192.168.2.255"))) assert_equal(false, net1.include?(IPAddr.new("192.168.3.0"))) # test with integer parameter int = (192 << 24) + (168 << 16) + (2 << 8) + 13 assert_equal(true, net1.include?(int)) assert_equal(false, net1.include?(int+255)) end end PK|]zUUerb.rbnu[# = ERB -- Ruby Templating # # Author:: Masatoshi SEKI # Documentation:: James Edward Gray II and Gavin Sinclair # # See ERB for primary documentation and ERB::Util for a couple of utility # routines. # # Copyright (c) 1999-2000,2002,2003 Masatoshi SEKI # # You can redistribute it and/or modify it under the same terms as Ruby. # # = ERB -- Ruby Templating # # == Introduction # # ERB provides an easy to use but powerful templating system for Ruby. Using # ERB, actual Ruby code can be added to any plain text document for the # purposes of generating document information details and/or flow control. # # A very simple example is this: # # require 'erb' # # x = 42 # template = ERB.new <<-EOF # The value of x is: <%= x %> # EOF # puts template.result(binding) # # Prints: The value of x is: 42 # # More complex examples are given below. # # # == Recognized Tags # # ERB recognizes certain tags in the provided template and converts them based # on the rules below: # # <% Ruby code -- inline with output %> # <%= Ruby expression -- replace with result %> # <%# comment -- ignored -- useful in testing %> # % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new) # %% replaced with % if first thing on a line and % processing is used # <%% or %%> -- replace with <% or %> respectively # # All other text is passed through ERB filtering unchanged. # # # == Options # # There are several settings you can change when you use ERB: # * the nature of the tags that are recognized; # * the value of $SAFE under which the template is run; # * the binding used to resolve local variables in the template. # # See the ERB.new and ERB#result methods for more detail. # # # == Examples # # === Plain Text # # ERB is useful for any generic templating situation. Note that in this example, we use the # convenient "% at start of line" tag, and we quote the template literally with # %q{...} to avoid trouble with the backslash. # # require "erb" # # # Create template. # template = %q{ # From: James Edward Gray II # To: <%= to %> # Subject: Addressing Needs # # <%= to[/\w+/] %>: # # Just wanted to send a quick note assuring that your needs are being # addressed. # # I want you to know that my team will keep working on the issues, # especially: # # <%# ignore numerous minor requests -- focus on priorities %> # % priorities.each do |priority| # * <%= priority %> # % end # # Thanks for your patience. # # James Edward Gray II # }.gsub(/^ /, '') # # message = ERB.new(template, 0, "%<>") # # # Set up template data. # to = "Community Spokesman " # priorities = [ "Run Ruby Quiz", # "Document Modules", # "Answer Questions on Ruby Talk" ] # # # Produce result. # email = message.result # puts email # # Generates: # # From: James Edward Gray II # To: Community Spokesman # Subject: Addressing Needs # # Community: # # Just wanted to send a quick note assuring that your needs are being addressed. # # I want you to know that my team will keep working on the issues, especially: # # * Run Ruby Quiz # * Document Modules # * Answer Questions on Ruby Talk # # Thanks for your patience. # # James Edward Gray II # # === Ruby in HTML # # ERB is often used in .rhtml files (HTML with embedded Ruby). Notice the need in # this example to provide a special binding when the template is run, so that the instance # variables in the Product object can be resolved. # # require "erb" # # # Build template data class. # class Product # def initialize( code, name, desc, cost ) # @code = code # @name = name # @desc = desc # @cost = cost # # @features = [ ] # end # # def add_feature( feature ) # @features << feature # end # # # Support templating of member data. # def get_binding # binding # end # # # ... # end # # # Create template. # template = %{ # # Ruby Toys -- <%= @name %> # # #

    <%= @name %> (<%= @code %>)

    #

    <%= @desc %>

    # #
      # <% @features.each do |f| %> #
    • <%= f %>
    • # <% end %> #
    # #

    # <% if @cost < 10 %> # Only <%= @cost %>!!! # <% else %> # Call for a price, today! # <% end %> #

    # # # # }.gsub(/^ /, '') # # rhtml = ERB.new(template) # # # Set up template data. # toy = Product.new( "TZ-1002", # "Rubysapien", # "Geek's Best Friend! Responds to Ruby commands...", # 999.95 ) # toy.add_feature("Listens for verbal commands in the Ruby language!") # toy.add_feature("Ignores Perl, Java, and all C variants.") # toy.add_feature("Karate-Chop Action!!!") # toy.add_feature("Matz signature on left leg.") # toy.add_feature("Gem studded eyes... Rubies, of course!") # # # Produce result. # rhtml.run(toy.get_binding) # # Generates (some blank lines removed): # # # Ruby Toys -- Rubysapien # # #

    Rubysapien (TZ-1002)

    #

    Geek's Best Friend! Responds to Ruby commands...

    # #
      #
    • Listens for verbal commands in the Ruby language!
    • #
    • Ignores Perl, Java, and all C variants.
    • #
    • Karate-Chop Action!!!
    • #
    • Matz signature on left leg.
    • #
    • Gem studded eyes... Rubies, of course!
    • #
    # #

    # Call for a price, today! #

    # # # # # # == Notes # # There are a variety of templating solutions available in various Ruby projects: # * ERB's big brother, eRuby, works the same but is written in C for speed; # * Amrita (smart at producing HTML/XML); # * cs/Template (written in C for speed); # * RDoc, distributed with Ruby, uses its own template engine, which can be reused elsewhere; # * and others; search the RAA. # # Rails, the web application framework, uses ERB to create views. # class ERB Revision = '$Date: 2009-02-24 02:44:50 +0900 (Tue, 24 Feb 2009) $' #' # Returns revision information for the erb.rb module. def self.version "erb.rb [2.1.0 #{ERB::Revision.split[1]}]" end end #-- # ERB::Compiler class ERB class Compiler # :nodoc: class PercentLine # :nodoc: def initialize(str) @value = str end attr_reader :value alias :to_s :value def empty? @value.empty? end end class Scanner # :nodoc: @scanner_map = {} def self.regist_scanner(klass, trim_mode, percent) @scanner_map[[trim_mode, percent]] = klass end def self.default_scanner=(klass) @default_scanner = klass end def self.make_scanner(src, trim_mode, percent) klass = @scanner_map.fetch([trim_mode, percent], @default_scanner) klass.new(src, trim_mode, percent) end def initialize(src, trim_mode, percent) @src = src @stag = nil end attr_accessor :stag def scan; end end class TrimScanner < Scanner # :nodoc: def initialize(src, trim_mode, percent) super @trim_mode = trim_mode @percent = percent if @trim_mode == '>' @scan_line = self.method(:trim_line1) elsif @trim_mode == '<>' @scan_line = self.method(:trim_line2) elsif @trim_mode == '-' @scan_line = self.method(:explicit_trim_line) else @scan_line = self.method(:scan_line) end end attr_accessor :stag def scan(&block) @stag = nil if @percent @src.each do |line| percent_line(line, &block) end else @scan_line.call(@src, &block) end nil end def percent_line(line, &block) if @stag || line[0] != ?% return @scan_line.call(line, &block) end line[0] = '' if line[0] == ?% @scan_line.call(line, &block) else yield(PercentLine.new(line.chomp)) end end def scan_line(line) line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens| tokens.each do |token| next if token.empty? yield(token) end end end def trim_line1(line) line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens| tokens.each do |token| next if token.empty? if token == "%>\n" yield('%>') yield(:cr) else yield(token) end end end end def trim_line2(line) head = nil line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens| tokens.each do |token| next if token.empty? head = token unless head if token == "%>\n" yield('%>') if is_erb_stag?(head) yield(:cr) else yield("\n") end head = nil else yield(token) head = nil if token == "\n" end end end end def explicit_trim_line(line) line.scan(/(.*?)(^[ \t]*<%\-|<%\-|<%%|%%>|<%=|<%#|<%|-%>\n|-%>|%>|\z)/m) do |tokens| tokens.each do |token| next if token.empty? if @stag.nil? && /[ \t]*<%-/ =~ token yield('<%') elsif @stag && token == "-%>\n" yield('%>') yield(:cr) elsif @stag && token == '-%>' yield('%>') else yield(token) end end end end ERB_STAG = %w(<%= <%# <%) def is_erb_stag?(s) ERB_STAG.member?(s) end end Scanner.default_scanner = TrimScanner class SimpleScanner < Scanner # :nodoc: def scan @src.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens| tokens.each do |token| next if token.empty? yield(token) end end end end Scanner.regist_scanner(SimpleScanner, nil, false) begin require 'strscan' class SimpleScanner2 < Scanner # :nodoc: def scan stag_reg = /(.*?)(<%%|<%=|<%#|<%|\z)/m etag_reg = /(.*?)(%%>|%>|\z)/m scanner = StringScanner.new(@src) while ! scanner.eos? scanner.scan(@stag ? etag_reg : stag_reg) yield(scanner[1]) yield(scanner[2]) end end end Scanner.regist_scanner(SimpleScanner2, nil, false) class ExplicitScanner < Scanner # :nodoc: def scan stag_reg = /(.*?)(^[ \t]*<%-|<%%|<%=|<%#|<%-|<%|\z)/m etag_reg = /(.*?)(%%>|-%>|%>|\z)/m scanner = StringScanner.new(@src) while ! scanner.eos? scanner.scan(@stag ? etag_reg : stag_reg) yield(scanner[1]) elem = scanner[2] if /[ \t]*<%-/ =~ elem yield('<%') elsif elem == '-%>' yield('%>') yield(:cr) if scanner.scan(/(\n|\z)/) else yield(elem) end end end end Scanner.regist_scanner(ExplicitScanner, '-', false) rescue LoadError end class Buffer # :nodoc: def initialize(compiler) @compiler = compiler @line = [] @script = "" @compiler.pre_cmd.each do |x| push(x) end end attr_reader :script def push(cmd) @line << cmd end def cr @script << (@line.join('; ')) @line = [] @script << "\n" end def close return unless @line @compiler.post_cmd.each do |x| push(x) end @script << (@line.join('; ')) @line = nil end end def content_dump(s) n = s.count("\n") if n > 0 s.dump + "\n" * n else s.dump end end def compile(s) out = Buffer.new(self) content = '' scanner = make_scanner(s) scanner.scan do |token| next if token.nil? next if token == '' if scanner.stag.nil? case token when PercentLine out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0 content = '' out.push(token.to_s) out.cr when :cr out.cr when '<%', '<%=', '<%#' scanner.stag = token out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0 content = '' when "\n" content << "\n" out.push("#{@put_cmd} #{content_dump(content)}") content = '' when '<%%' content << '<%' else content << token end else case token when '%>' case scanner.stag when '<%' if content[-1] == ?\n content.chop! out.push(content) out.cr else out.push(content) end when '<%=' out.push("#{@insert_cmd}((#{content}).to_s)") when '<%#' # out.push("# #{content_dump(content)}") end scanner.stag = nil content = '' when '%%>' content << '%>' else content << token end end end out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0 out.close out.script end def prepare_trim_mode(mode) case mode when 1 return [false, '>'] when 2 return [false, '<>'] when 0 return [false, nil] when String perc = mode.include?('%') if mode.include?('-') return [perc, '-'] elsif mode.include?('<>') return [perc, '<>'] elsif mode.include?('>') return [perc, '>'] else [perc, nil] end else return [false, nil] end end def make_scanner(src) Scanner.make_scanner(src, @trim_mode, @percent) end def initialize(trim_mode) @percent, @trim_mode = prepare_trim_mode(trim_mode) @put_cmd = 'print' @insert_cmd = @put_cmd @pre_cmd = [] @post_cmd = [] end attr_reader :percent, :trim_mode attr_accessor :put_cmd, :insert_cmd, :pre_cmd, :post_cmd end end #-- # ERB class ERB # # Constructs a new ERB object with the template specified in _str_. # # An ERB object works by building a chunk of Ruby code that will output # the completed template when run. If _safe_level_ is set to a non-nil value, # ERB code will be run in a separate thread with $SAFE set to the # provided level. # # If _trim_mode_ is passed a String containing one or more of the following # modifiers, ERB will adjust its code generation as listed: # # % enables Ruby code processing for lines beginning with % # <> omit newline for lines starting with <% and ending in %> # > omit newline for lines ending in %> # # _eoutvar_ can be used to set the name of the variable ERB will build up # its output in. This is useful when you need to run multiple ERB # templates through the same binding and/or when you want to control where # output ends up. Pass the name of the variable to be used inside a String. # # === Example # # require "erb" # # # build data class # class Listings # PRODUCT = { :name => "Chicken Fried Steak", # :desc => "A well messages pattie, breaded and fried.", # :cost => 9.95 } # # attr_reader :product, :price # # def initialize( product = "", price = "" ) # @product = product # @price = price # end # # def build # b = binding # # create and run templates, filling member data variables # ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), 0, "", "@product").result b # <%= PRODUCT[:name] %> # <%= PRODUCT[:desc] %> # END_PRODUCT # ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), 0, "", "@price").result b # <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %> # <%= PRODUCT[:desc] %> # END_PRICE # end # end # # # setup template data # listings = Listings.new # listings.build # # puts listings.product + "\n" + listings.price # # _Generates_ # # Chicken Fried Steak # A well messages pattie, breaded and fried. # # Chicken Fried Steak -- 9.95 # A well messages pattie, breaded and fried. # def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout') @safe_level = safe_level compiler = ERB::Compiler.new(trim_mode) set_eoutvar(compiler, eoutvar) @src = compiler.compile(str) @filename = nil end # The Ruby code generated by ERB attr_reader :src # The optional _filename_ argument passed to Kernel#eval when the ERB code # is run attr_accessor :filename # # Can be used to set _eoutvar_ as described in ERB#new. It's probably easier # to just use the constructor though, since calling this method requires the # setup of an ERB _compiler_ object. # def set_eoutvar(compiler, eoutvar = '_erbout') compiler.put_cmd = "#{eoutvar}.concat" compiler.insert_cmd = "#{eoutvar}.concat" cmd = [] cmd.push "#{eoutvar} = ''" compiler.pre_cmd = cmd cmd = [] cmd.push(eoutvar) compiler.post_cmd = cmd end # Generate results and print them. (see ERB#result) def run(b=TOPLEVEL_BINDING) print self.result(b) end # # Executes the generated ERB code to produce a completed template, returning # the results of that code. (See ERB#new for details on how this process can # be affected by _safe_level_.) # # _b_ accepts a Binding or Proc object which is used to set the context of # code evaluation. # def result(b=TOPLEVEL_BINDING) if @safe_level proc { $SAFE = @safe_level eval(@src, b, (@filename || '(erb)'), 1) }.call else eval(@src, b, (@filename || '(erb)'), 1) end end # Define _methodname_ as instance method of _mod_ from compiled ruby source. # # example: # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml # erb = ERB.new(File.read(filename)) # erb.def_method(MyClass, 'render(arg1, arg2)', filename) # print MyClass.new.render('foo', 123) def def_method(mod, methodname, fname='(ERB)') mod.module_eval("def #{methodname}\n" + self.src + "\nend\n", fname, 0) end # Create unnamed module, define _methodname_ as instance method of it, and return it. # # example: # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml # erb = ERB.new(File.read(filename)) # erb.filename = filename # MyModule = erb.def_module('render(arg1, arg2)') # class MyClass # include MyModule # end def def_module(methodname='erb') mod = Module.new def_method(mod, methodname, @filename || '(ERB)') mod end # Define unnamed class which has _methodname_ as instance method, and return it. # # example: # class MyClass_ # def initialize(arg1, arg2) # @arg1 = arg1; @arg2 = arg2 # end # end # filename = 'example.rhtml' # @arg1 and @arg2 are used in example.rhtml # erb = ERB.new(File.read(filename)) # erb.filename = filename # MyClass = erb.def_class(MyClass_, 'render()') # print MyClass.new('foo', 123).render() def def_class(superklass=Object, methodname='result') cls = Class.new(superklass) def_method(cls, methodname, @filename || '(ERB)') cls end end #-- # ERB::Util class ERB # A utility module for conversion routines, often handy in HTML generation. module Util public # # A utility method for escaping HTML tag characters in _s_. # # require "erb" # include ERB::Util # # puts html_escape("is a > 0 & a < 10?") # # _Generates_ # # is a > 0 & a < 10? # def html_escape(s) s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/ # <%= item %> # <% end %> # # example.rb: # require 'erb' # class MyClass # extend ERB::DefMethod # def_erb_method('render()', 'example.rhtml') # def initialize(items) # @items = items # end # end # print MyClass.new([10,20,30]).render() # # result: # # 10 # # 20 # # 30 # module DefMethod public # define _methodname_ as instance method of current module, using ERB object or eRuby file def def_erb_method(methodname, erb_or_fname) if erb_or_fname.kind_of? String fname = erb_or_fname erb = ERB.new(File.read(fname)) erb.def_method(self, methodname, fname) else erb = erb_or_fname erb.def_method(self, methodname, erb.filename || '(ERB)') end end module_function :def_erb_method end end PK|]0mrrdate/format.rbnu[# format.rb: Written by Tadayoshi Funaba 1999-2008 # $Id: format.rb,v 2.43 2008-01-17 20:16:31+09 tadf Exp $ require 'rational' class Date module Format # :nodoc: MONTHS = { 'january' => 1, 'february' => 2, 'march' => 3, 'april' => 4, 'may' => 5, 'june' => 6, 'july' => 7, 'august' => 8, 'september'=> 9, 'october' =>10, 'november' =>11, 'december' =>12 } DAYS = { 'sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday'=> 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6 } ABBR_MONTHS = { 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4, 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8, 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12 } ABBR_DAYS = { 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3, 'thu' => 4, 'fri' => 5, 'sat' => 6 } ZONES = { 'ut' => 0*3600, 'gmt' => 0*3600, 'est' => -5*3600, 'edt' => -4*3600, 'cst' => -6*3600, 'cdt' => -5*3600, 'mst' => -7*3600, 'mdt' => -6*3600, 'pst' => -8*3600, 'pdt' => -7*3600, 'a' => 1*3600, 'b' => 2*3600, 'c' => 3*3600, 'd' => 4*3600, 'e' => 5*3600, 'f' => 6*3600, 'g' => 7*3600, 'h' => 8*3600, 'i' => 9*3600, 'k' => 10*3600, 'l' => 11*3600, 'm' => 12*3600, 'n' => -1*3600, 'o' => -2*3600, 'p' => -3*3600, 'q' => -4*3600, 'r' => -5*3600, 's' => -6*3600, 't' => -7*3600, 'u' => -8*3600, 'v' => -9*3600, 'w' =>-10*3600, 'x' =>-11*3600, 'y' =>-12*3600, 'z' => 0*3600, 'utc' => 0*3600, 'wet' => 0*3600, 'at' => -2*3600, 'brst'=> -2*3600, 'ndt' => -(2*3600+1800), 'art' => -3*3600, 'adt' => -3*3600, 'brt' => -3*3600, 'clst'=> -3*3600, 'nst' => -(3*3600+1800), 'ast' => -4*3600, 'clt' => -4*3600, 'akdt'=> -8*3600, 'ydt' => -8*3600, 'akst'=> -9*3600, 'hadt'=> -9*3600, 'hdt' => -9*3600, 'yst' => -9*3600, 'ahst'=>-10*3600, 'cat' =>-10*3600, 'hast'=>-10*3600, 'hst' =>-10*3600, 'nt' =>-11*3600, 'idlw'=>-12*3600, 'bst' => 1*3600, 'cet' => 1*3600, 'fwt' => 1*3600, 'met' => 1*3600, 'mewt'=> 1*3600, 'mez' => 1*3600, 'swt' => 1*3600, 'wat' => 1*3600, 'west'=> 1*3600, 'cest'=> 2*3600, 'eet' => 2*3600, 'fst' => 2*3600, 'mest'=> 2*3600, 'mesz'=> 2*3600, 'sast'=> 2*3600, 'sst' => 2*3600, 'bt' => 3*3600, 'eat' => 3*3600, 'eest'=> 3*3600, 'msk' => 3*3600, 'msd' => 4*3600, 'zp4' => 4*3600, 'zp5' => 5*3600, 'ist' => (5*3600+1800), 'zp6' => 6*3600, 'wast'=> 7*3600, 'cct' => 8*3600, 'sgt' => 8*3600, 'wadt'=> 8*3600, 'jst' => 9*3600, 'kst' => 9*3600, 'east'=> 10*3600, 'gst' => 10*3600, 'eadt'=> 11*3600, 'idle'=> 12*3600, 'nzst'=> 12*3600, 'nzt' => 12*3600, 'nzdt'=> 13*3600, 'afghanistan' => 16200, 'alaskan' => -32400, 'arab' => 10800, 'arabian' => 14400, 'arabic' => 10800, 'atlantic' => -14400, 'aus central' => 34200, 'aus eastern' => 36000, 'azores' => -3600, 'canada central' => -21600, 'cape verde' => -3600, 'caucasus' => 14400, 'cen. australia' => 34200, 'central america' => -21600, 'central asia' => 21600, 'central europe' => 3600, 'central european' => 3600, 'central pacific' => 39600, 'central' => -21600, 'china' => 28800, 'dateline' => -43200, 'e. africa' => 10800, 'e. australia' => 36000, 'e. europe' => 7200, 'e. south america' => -10800, 'eastern' => -18000, 'egypt' => 7200, 'ekaterinburg' => 18000, 'fiji' => 43200, 'fle' => 7200, 'greenland' => -10800, 'greenwich' => 0, 'gtb' => 7200, 'hawaiian' => -36000, 'india' => 19800, 'iran' => 12600, 'jerusalem' => 7200, 'korea' => 32400, 'mexico' => -21600, 'mid-atlantic' => -7200, 'mountain' => -25200, 'myanmar' => 23400, 'n. central asia' => 21600, 'nepal' => 20700, 'new zealand' => 43200, 'newfoundland' => -12600, 'north asia east' => 28800, 'north asia' => 25200, 'pacific sa' => -14400, 'pacific' => -28800, 'romance' => 3600, 'russian' => 10800, 'sa eastern' => -10800, 'sa pacific' => -18000, 'sa western' => -14400, 'samoa' => -39600, 'se asia' => 25200, 'malay peninsula' => 28800, 'south africa' => 7200, 'sri lanka' => 21600, 'taipei' => 28800, 'tasmania' => 36000, 'tokyo' => 32400, 'tonga' => 46800, 'us eastern' => -18000, 'us mountain' => -25200, 'vladivostok' => 36000, 'w. australia' => 28800, 'w. central africa' => 3600, 'w. europe' => 3600, 'west asia' => 18000, 'west pacific' => 36000, 'yakutsk' => 32400 } [MONTHS, DAYS, ABBR_MONTHS, ABBR_DAYS, ZONES].each do |x| x.freeze end class Bag # :nodoc: def initialize @elem = {} end def method_missing(t, *args, &block) t = t.to_s set = t.chomp!('=') t = t.intern if set @elem[t] = args[0] else @elem[t] end end def to_hash @elem.reject{|k, v| /\A_/ =~ k.to_s || v.nil?} end end end def emit(e, f) # :nodoc: case e when Numeric sign = %w(+ + -)[e <=> 0] e = e.abs end s = e.to_s if f[:s] && f[:p] == '0' f[:w] -= 1 end if f[:s] && f[:p] == "\s" s[0,0] = sign end if f[:p] != '-' s = s.rjust(f[:w], f[:p]) end if f[:s] && f[:p] != "\s" s[0,0] = sign end s = s.upcase if f[:u] s = s.downcase if f[:d] s end def emit_w(e, w, f) # :nodoc: f[:w] = [f[:w], w].compact.max emit(e, f) end def emit_n(e, w, f) # :nodoc: f[:p] ||= '0' emit_w(e, w, f) end def emit_sn(e, w, f) # :nodoc: if e < 0 w += 1 f[:s] = true end emit_n(e, w, f) end def emit_z(e, w, f) # :nodoc: w += 1 f[:s] = true emit_n(e, w, f) end def emit_a(e, w, f) # :nodoc: f[:p] ||= "\s" emit_w(e, w, f) end def emit_ad(e, w, f) # :nodoc: if f[:x] f[:u] = true f[:d] = false end emit_a(e, w, f) end def emit_au(e, w, f) # :nodoc: if f[:x] f[:u] = false f[:d] = true end emit_a(e, w, f) end private :emit, :emit_w, :emit_n, :emit_sn, :emit_z, :emit_a, :emit_ad, :emit_au def strftime(fmt='%F') fmt.gsub(/%([-_0^#]+)?(\d+)?([EO]?(?::{1,3}z|.))/m) do |m| f = {} a = $& s, w, c = $1, $2, $3 if s s.scan(/./) do |k| case k when '-'; f[:p] = '-' when '_'; f[:p] = "\s" when '0'; f[:p] = '0' when '^'; f[:u] = true when '#'; f[:x] = true end end end if w f[:w] = w.to_i end case c when 'A'; emit_ad(DAYNAMES[wday], 0, f) when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f) when 'B'; emit_ad(MONTHNAMES[mon], 0, f) when 'b'; emit_ad(ABBR_MONTHNAMES[mon], 0, f) when 'C', 'EC'; emit_sn((year / 100).floor, 2, f) when 'c', 'Ec'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f) when 'D'; emit_a(strftime('%m/%d/%y'), 0, f) when 'd', 'Od'; emit_n(mday, 2, f) when 'e', 'Oe'; emit_a(mday, 2, f) when 'F' if m == '%F' format('%.4d-%02d-%02d', year, mon, mday) # 4p else emit_a(strftime('%Y-%m-%d'), 0, f) end when 'G'; emit_sn(cwyear, 4, f) when 'g'; emit_n(cwyear % 100, 2, f) when 'H', 'OH'; emit_n(hour, 2, f) when 'h'; emit_ad(strftime('%b'), 0, f) when 'I', 'OI'; emit_n((hour % 12).nonzero? || 12, 2, f) when 'j'; emit_n(yday, 3, f) when 'k'; emit_a(hour, 2, f) when 'L' emit_n((sec_fraction / MILLISECONDS_IN_DAY).floor, 3, f) when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f) when 'M', 'OM'; emit_n(min, 2, f) when 'm', 'Om'; emit_n(mon, 2, f) when 'N' emit_n((sec_fraction / NANOSECONDS_IN_DAY).floor, 9, f) when 'n'; "\n" when 'P'; emit_ad(strftime('%p').downcase, 0, f) when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f) when 'Q' s = ((ajd - UNIX_EPOCH_IN_AJD) / MILLISECONDS_IN_DAY).round emit_sn(s, 1, f) when 'R'; emit_a(strftime('%H:%M'), 0, f) when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f) when 'S', 'OS'; emit_n(sec, 2, f) when 's' s = ((ajd - UNIX_EPOCH_IN_AJD) / SECONDS_IN_DAY).round emit_sn(s, 1, f) when 'T' if m == '%T' format('%02d:%02d:%02d', hour, min, sec) # 4p else emit_a(strftime('%H:%M:%S'), 0, f) end when 't'; "\t" when 'U', 'W', 'OU', 'OW' emit_n(if c[-1,1] == 'U' then wnum0 else wnum1 end, 2, f) when 'u', 'Ou'; emit_n(cwday, 1, f) when 'V', 'OV'; emit_n(cweek, 2, f) when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f) when 'w', 'Ow'; emit_n(wday, 1, f) when 'X', 'EX'; emit_a(strftime('%H:%M:%S'), 0, f) when 'x', 'Ex'; emit_a(strftime('%m/%d/%y'), 0, f) when 'Y', 'EY'; emit_sn(year, 4, f) when 'y', 'Ey', 'Oy'; emit_n(year % 100, 2, f) when 'Z'; emit_au(strftime('%:z'), 0, f) when /\A(:{0,3})z/ t = $1.size sign = if offset < 0 then -1 else +1 end fr = offset.abs ss = fr.div(SECONDS_IN_DAY) # 4p hh, ss = ss.divmod(3600) mm, ss = ss.divmod(60) if t == 3 if ss.nonzero? then t = 2 elsif mm.nonzero? then t = 1 else t = -1 end end case t when -1 tail = [] sep = '' when 0 f[:w] -= 2 if f[:w] tail = ['%02d' % mm] sep = '' when 1 f[:w] -= 3 if f[:w] tail = ['%02d' % mm] sep = ':' when 2 f[:w] -= 6 if f[:w] tail = ['%02d' % mm, '%02d' % ss] sep = ':' end ([emit_z(sign * hh, 2, f)] + tail).join(sep) when '%'; emit_a('%', 0, f) when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f) when '1' if $VERBOSE warn("warning: strftime: %1 is deprecated; forget this") end emit_n(jd, 1, f) when '2' if $VERBOSE warn("warning: strftime: %2 is deprecated; use '%Y-%j'") end emit_a(strftime('%Y-%j'), 0, f) when '3' if $VERBOSE warn("warning: strftime: %3 is deprecated; use '%F'") end emit_a(strftime('%F'), 0, f) else a end end end # alias_method :format, :strftime def asctime() strftime('%c') end alias_method :ctime, :asctime =begin def iso8601() strftime('%F') end def rfc3339() iso8601 end def rfc2822() strftime('%a, %-d %b %Y %T %z') end alias_method :rfc822, :rfc2822 def jisx0301 if jd < 2405160 iso8601 else case jd when 2405160...2419614 g = 'M%02d' % (year - 1867) when 2419614...2424875 g = 'T%02d' % (year - 1911) when 2424875...2447535 g = 'S%02d' % (year - 1925) else g = 'H%02d' % (year - 1988) end g + strftime('.%m.%d') end end def beat(n=0) i, f = (new_offset(HOURS_IN_DAY).day_fraction * 1000).divmod(1) ('@%03d' % i) + if n < 1 '' else '.%0*d' % [n, (f / Rational(1, 10**n)).round] end end =end def self.num_pattern? (s) # :nodoc: /\A%[EO]?[CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy\d]/ =~ s || /\A\d/ =~ s end private_class_method :num_pattern? def self._strptime_i(str, fmt, e) # :nodoc: fmt.scan(/%([EO]?(?::{1,3}z|.))|(.)/m) do |s, c| a = $& if s case s when 'A', 'a' return unless str.sub!(/\A(#{Format::DAYS.keys.join('|')})/io, '') || str.sub!(/\A(#{Format::ABBR_DAYS.keys.join('|')})/io, '') val = Format::DAYS[$1.downcase] || Format::ABBR_DAYS[$1.downcase] return unless val e.wday = val when 'B', 'b', 'h' return unless str.sub!(/\A(#{Format::MONTHS.keys.join('|')})/io, '') || str.sub!(/\A(#{Format::ABBR_MONTHS.keys.join('|')})/io, '') val = Format::MONTHS[$1.downcase] || Format::ABBR_MONTHS[$1.downcase] return unless val e.mon = val when 'C', 'EC' return unless str.sub!(if num_pattern?($') then /\A([-+]?\d{1,2})/ else /\A([-+]?\d{1,})/ end, '') val = $1.to_i e._cent = val when 'c', 'Ec' return unless _strptime_i(str, '%a %b %e %H:%M:%S %Y', e) when 'D' return unless _strptime_i(str, '%m/%d/%y', e) when 'd', 'e', 'Od', 'Oe' return unless str.sub!(/\A( \d|\d{1,2})/, '') val = $1.to_i return unless (1..31) === val e.mday = val when 'F' return unless _strptime_i(str, '%Y-%m-%d', e) when 'G' return unless str.sub!(if num_pattern?($') then /\A([-+]?\d{1,4})/ else /\A([-+]?\d{1,})/ end, '') val = $1.to_i e.cwyear = val when 'g' return unless str.sub!(/\A(\d{1,2})/, '') val = $1.to_i return unless (0..99) === val e.cwyear = val e._cent ||= if val >= 69 then 19 else 20 end when 'H', 'k', 'OH' return unless str.sub!(/\A( \d|\d{1,2})/, '') val = $1.to_i return unless (0..24) === val e.hour = val when 'I', 'l', 'OI' return unless str.sub!(/\A( \d|\d{1,2})/, '') val = $1.to_i return unless (1..12) === val e.hour = val when 'j' return unless str.sub!(/\A(\d{1,3})/, '') val = $1.to_i return unless (1..366) === val e.yday = val when 'L' return unless str.sub!(if num_pattern?($') then /\A([-+]?\d{1,3})/ else /\A([-+]?\d{1,})/ end, '') # val = Rational($1.to_i, 10**3) val = Rational($1.to_i, 10**$1.size) e.sec_fraction = val when 'M', 'OM' return unless str.sub!(/\A(\d{1,2})/, '') val = $1.to_i return unless (0..59) === val e.min = val when 'm', 'Om' return unless str.sub!(/\A(\d{1,2})/, '') val = $1.to_i return unless (1..12) === val e.mon = val when 'N' return unless str.sub!(if num_pattern?($') then /\A([-+]?\d{1,9})/ else /\A([-+]?\d{1,})/ end, '') # val = Rational($1.to_i, 10**9) val = Rational($1.to_i, 10**$1.size) e.sec_fraction = val when 'n', 't' return unless _strptime_i(str, "\s", e) when 'P', 'p' return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/i, '') e._merid = if $1.downcase == 'a' then 0 else 12 end when 'Q' return unless str.sub!(/\A(-?\d{1,})/, '') val = Rational($1.to_i, 10**3) e.seconds = val when 'R' return unless _strptime_i(str, '%H:%M', e) when 'r' return unless _strptime_i(str, '%I:%M:%S %p', e) when 'S', 'OS' return unless str.sub!(/\A(\d{1,2})/, '') val = $1.to_i return unless (0..60) === val e.sec = val when 's' return unless str.sub!(/\A(-?\d{1,})/, '') val = $1.to_i e.seconds = val when 'T' return unless _strptime_i(str, '%H:%M:%S', e) when 'U', 'W', 'OU', 'OW' return unless str.sub!(/\A(\d{1,2})/, '') val = $1.to_i return unless (0..53) === val e.__send__(if s[-1,1] == 'U' then :wnum0= else :wnum1= end, val) when 'u', 'Ou' return unless str.sub!(/\A(\d{1})/, '') val = $1.to_i return unless (1..7) === val e.cwday = val when 'V', 'OV' return unless str.sub!(/\A(\d{1,2})/, '') val = $1.to_i return unless (1..53) === val e.cweek = val when 'v' return unless _strptime_i(str, '%e-%b-%Y', e) when 'w' return unless str.sub!(/\A(\d{1})/, '') val = $1.to_i return unless (0..6) === val e.wday = val when 'X', 'EX' return unless _strptime_i(str, '%H:%M:%S', e) when 'x', 'Ex' return unless _strptime_i(str, '%m/%d/%y', e) when 'Y', 'EY' return unless str.sub!(if num_pattern?($') then /\A([-+]?\d{1,4})/ else /\A([-+]?\d{1,})/ end, '') val = $1.to_i e.year = val when 'y', 'Ey', 'Oy' return unless str.sub!(/\A(\d{1,2})/, '') val = $1.to_i return unless (0..99) === val e.year = val e._cent ||= if val >= 69 then 19 else 20 end when 'Z', /\A:{0,3}z/ return unless str.sub!(/\A((?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)? |[[:alpha:].\s]+(?:standard|daylight)\s+time\b |[[:alpha:]]+(?:\s+dst)?\b )/ix, '') val = $1 e.zone = val offset = zone_to_diff(val) e.offset = offset when '%' return unless str.sub!(/\A%/, '') when '+' return unless _strptime_i(str, '%a %b %e %H:%M:%S %Z %Y', e) when '1' if $VERBOSE warn("warning: strptime: %1 is deprecated; forget this") end return unless str.sub!(/\A(\d+)/, '') val = $1.to_i e.jd = val when '2' if $VERBOSE warn("warning: strptime: %2 is deprecated; use '%Y-%j'") end return unless _strptime_i(str, '%Y-%j', e) when '3' if $VERBOSE warn("warning: strptime: %3 is deprecated; use '%F'") end return unless _strptime_i(str, '%F', e) else return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '') end else case c when /\A[\s\v]/ str.sub!(/\A[\s\v]+/, '') else return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '') end end end end private_class_method :_strptime_i def self._strptime(str, fmt='%F') str = str.dup e = Format::Bag.new return unless _strptime_i(str, fmt, e) if e._cent if e.cwyear e.cwyear += e._cent * 100 end if e.year e. year += e._cent * 100 end end if e._merid if e.hour e.hour %= 12 e.hour += e._merid end end unless str.empty? e.leftover = str end e.to_hash end def self.s3e(e, y, m, d, bc=false) unless String === m m = m.to_s end if y && m && !d y, m, d = d, y, m end if y == nil if d && d.size > 2 y = d d = nil end if d && d[0,1] == "'" y = d d = nil end end if y y.scan(/(\d+)(.+)?/) if $2 y, d = d, $1 end end if m if m[0,1] == "'" || m.size > 2 y, m, d = m, d, y # us -> be end end if d if d[0,1] == "'" || d.size > 2 y, d = d, y end end if y y =~ /([-+])?(\d+)/ if $1 || $2.size > 2 c = false end iy = $&.to_i if bc iy = -iy + 1 end e.year = iy end if m m =~ /\d+/ e.mon = $&.to_i end if d d =~ /\d+/ e.mday = $&.to_i end if c != nil e._comp = c end end private_class_method :s3e def self._parse_day(str, e) # :nodoc: if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/ino, ' ') e.wday = Format::ABBR_DAYS[$1.downcase] true =begin elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/in, ' ') e.wday = %w(su mo tu we th fr sa).index($1.downcase) true =end end end def self._parse_time(str, e) # :nodoc: if str.sub!( /( (?: \d+\s*:\s*\d+ (?: \s*:\s*\d+(?:[,.]\d*)? )? | \d+\s*h(?:\s*\d+m?(?:\s*\d+s?)?)? ) (?: \s* [ap](?:m\b|\.m\.) )? | \d+\s*[ap](?:m\b|\.m\.) ) (?: \s* ( (?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)? | [[:alpha:].\s]+(?:standard|daylight)\stime\b | [[:alpha:]]+(?:\sdst)?\b ) )? /inx, ' ') t = $1 e.zone = $2 if $2 t =~ /\A(\d+)h? (?:\s*:?\s*(\d+)m? (?: \s*:?\s*(\d+)(?:[,.](\d+))?s? )? )? (?:\s*([ap])(?:m\b|\.m\.))?/inx e.hour = $1.to_i e.min = $2.to_i if $2 e.sec = $3.to_i if $3 e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4 if $5 e.hour %= 12 if $5.downcase == 'p' e.hour += 12 end end true end end =begin def self._parse_beat(str, e) # :nodoc: if str.sub!(/@\s*(\d+)(?:[,.](\d*))?/, ' ') beat = Rational($1.to_i) beat += Rational($2.to_i, 10**$2.size) if $2 secs = Rational(beat, 1000) h, min, s, fr = self.day_fraction_to_time(secs) e.hour = h e.min = min e.sec = s e.sec_fraction = fr * 86400 e.zone = '+01:00' true end end =end def self._parse_eu(str, e) # :nodoc: if str.sub!( /'?(\d+)[^-\d\s]* \s* (#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']* (?: \s* (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))? \s* ('?-?\d+(?:(?:st|nd|rd|th)\b)?) )? /inox, ' ') # ' s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1, $3 && $3[0,1].downcase == 'b') true end end def self._parse_us(str, e) # :nodoc: if str.sub!( /\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']* \s* ('?\d+)[^-\d\s']* (?: \s* (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))? \s* ('?-?\d+) )? /inox, ' ') # ' s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2, $3 && $3[0,1].downcase == 'b') true end end def self._parse_iso(str, e) # :nodoc: if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/n, ' ') s3e(e, $1, $2, $3) true end end def self._parse_iso2(str, e) # :nodoc: if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d))?\b/in, ' ') e.cwyear = $1.to_i if $1 e.cweek = $2.to_i e.cwday = $3.to_i if $3 true elsif str.sub!(/-w-(\d)\b/in, ' ') e.cwday = $1.to_i true elsif str.sub!(/--(\d{2})?-(\d{2})\b/n, ' ') e.mon = $1.to_i if $1 e.mday = $2.to_i true elsif str.sub!(/--(\d{2})(\d{2})?\b/n, ' ') e.mon = $1.to_i e.mday = $2.to_i if $2 true elsif /[,.](\d{2}|\d{4})-\d{3}\b/n !~ str && str.sub!(/\b(\d{2}|\d{4})-(\d{3})\b/n, ' ') e.year = $1.to_i e.yday = $2.to_i true elsif /\d-\d{3}\b/n !~ str && str.sub!(/\b-(\d{3})\b/n, ' ') e.yday = $1.to_i true end end def self._parse_jis(str, e) # :nodoc: if str.sub!(/\b([mtsh])(\d+)\.(\d+)\.(\d+)/in, ' ') era = { 'm'=>1867, 't'=>1911, 's'=>1925, 'h'=>1988 }[$1.downcase] e.year = $2.to_i + era e.mon = $3.to_i e.mday = $4.to_i true end end def self._parse_vms(str, e) # :nodoc: if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]* -('?-?\d+)/inox, ' ') s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1) true elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]* -('?-?\d+)(?:-('?-?\d+))?/inox, ' ') s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2) true end end def self._parse_sla(str, e) # :nodoc: if str.sub!(%r|('?-?\d+)/\s*('?\d+)(?:\D\s*('?-?\d+))?|n, ' ') # ' s3e(e, $3, $1, $2) true end end def self._parse_dot(str, e) # :nodoc: if str.sub!(%r|('?-?\d+)\.\s*('?\d+)\.\s*('?-?\d+)|n, ' ') # ' s3e(e, $1, $2, $3) true end end def self._parse_year(str, e) # :nodoc: if str.sub!(/'(\d+)\b/n, ' ') e.year = $1.to_i true end end def self._parse_mon(str, e) # :nodoc: if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/ino, ' ') e.mon = Format::ABBR_MONTHS[$1.downcase] true end end def self._parse_mday(str, e) # :nodoc: if str.sub!(/(\d+)(st|nd|rd|th)\b/in, ' ') e.mday = $1.to_i true end end def self._parse_ddd(str, e) # :nodoc: if str.sub!( /([-+]?)(\d{2,14}) (?: \s* t? \s* (\d{2,6})?(?:[,.](\d*))? )? (?: \s* ( z\b | [-+]\d{1,4}\b | \[[-+]?\d[^\]]*\] ) )? /inx, ' ') case $2.size when 2 if $3.nil? && $4 e.sec = $2[-2, 2].to_i else e.mday = $2[ 0, 2].to_i end when 4 if $3.nil? && $4 e.sec = $2[-2, 2].to_i e.min = $2[-4, 2].to_i else e.mon = $2[ 0, 2].to_i e.mday = $2[ 2, 2].to_i end when 6 if $3.nil? && $4 e.sec = $2[-2, 2].to_i e.min = $2[-4, 2].to_i e.hour = $2[-6, 2].to_i else e.year = ($1 + $2[ 0, 2]).to_i e.mon = $2[ 2, 2].to_i e.mday = $2[ 4, 2].to_i end when 8, 10, 12, 14 if $3.nil? && $4 e.sec = $2[-2, 2].to_i e.min = $2[-4, 2].to_i e.hour = $2[-6, 2].to_i e.mday = $2[-8, 2].to_i if $2.size >= 10 e.mon = $2[-10, 2].to_i end if $2.size == 12 e.year = ($1 + $2[-12, 2]).to_i end if $2.size == 14 e.year = ($1 + $2[-14, 4]).to_i e._comp = false end else e.year = ($1 + $2[ 0, 4]).to_i e.mon = $2[ 4, 2].to_i e.mday = $2[ 6, 2].to_i e.hour = $2[ 8, 2].to_i if $2.size >= 10 e.min = $2[10, 2].to_i if $2.size >= 12 e.sec = $2[12, 2].to_i if $2.size >= 14 e._comp = false end when 3 if $3.nil? && $4 e.sec = $2[-2, 2].to_i e.min = $2[-3, 1].to_i else e.yday = $2[ 0, 3].to_i end when 5 if $3.nil? && $4 e.sec = $2[-2, 2].to_i e.min = $2[-4, 2].to_i e.hour = $2[-5, 1].to_i else e.year = ($1 + $2[ 0, 2]).to_i e.yday = $2[ 2, 3].to_i end when 7 if $3.nil? && $4 e.sec = $2[-2, 2].to_i e.min = $2[-4, 2].to_i e.hour = $2[-6, 2].to_i e.mday = $2[-7, 1].to_i else e.year = ($1 + $2[ 0, 4]).to_i e.yday = $2[ 4, 3].to_i end end if $3 if $4 case $3.size when 2, 4, 6 e.sec = $3[-2, 2].to_i e.min = $3[-4, 2].to_i if $3.size >= 4 e.hour = $3[-6, 2].to_i if $3.size >= 6 end else case $3.size when 2, 4, 6 e.hour = $3[ 0, 2].to_i e.min = $3[ 2, 2].to_i if $3.size >= 4 e.sec = $3[ 4, 2].to_i if $3.size >= 6 end end end if $4 e.sec_fraction = Rational($4.to_i, 10**$4.size) end if $5 e.zone = $5 if e.zone[0,1] == '[' o, n, = e.zone[1..-2].split(':') e.zone = n || o if /\A\d/ =~ o o = format('+%s', o) end e.offset = zone_to_diff(o) end end true end end private_class_method :_parse_day, :_parse_time, # :_parse_beat, :_parse_eu, :_parse_us, :_parse_iso, :_parse_iso2, :_parse_jis, :_parse_vms, :_parse_sla, :_parse_dot, :_parse_year, :_parse_mon, :_parse_mday, :_parse_ddd def self._parse(str, comp=false) str = str.dup e = Format::Bag.new e._comp = comp str.gsub!(/[^-+',.\/:@[:alnum:]\[\]\x80-\xff]+/n, ' ') _parse_time(str, e) # || _parse_beat(str, e) _parse_day(str, e) _parse_eu(str, e) || _parse_us(str, e) || _parse_iso(str, e) || _parse_jis(str, e) || _parse_vms(str, e) || _parse_sla(str, e) || _parse_dot(str, e) || _parse_iso2(str, e) || _parse_year(str, e) || _parse_mon(str, e) || _parse_mday(str, e) || _parse_ddd(str, e) if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/in, ' ') if e.year e.year = -e.year + 1 end end if str.sub!(/\A\s*(\d{1,2})\s*\z/n, ' ') if e.hour && !e.mday v = $1.to_i if (1..31) === v e.mday = v end end if e.mday && !e.hour v = $1.to_i if (0..24) === v e.hour = v end end end if e._comp if e.cwyear if e.cwyear >= 0 && e.cwyear <= 99 e.cwyear += if e.cwyear >= 69 then 1900 else 2000 end end end if e.year if e.year >= 0 && e.year <= 99 e.year += if e.year >= 69 then 1900 else 2000 end end end end e.offset ||= zone_to_diff(e.zone) if e.zone e.to_hash end def self.zone_to_diff(zone) # :nodoc: zone = zone.downcase if zone.sub!(/\s+(standard|daylight)\s+time\z/, '') dst = $1 == 'daylight' else dst = zone.sub!(/\s+dst\z/, '') end if Format::ZONES.include?(zone) offset = Format::ZONES[zone] offset += 3600 if dst elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '') sign = $1 if zone.include?(':') hour, min, sec, = zone.split(':') elsif zone.include?(',') || zone.include?('.') hour, fr, = zone.split(/[,.]/) min = Rational(fr.to_i, 10**fr.size) * 60 else case zone.size when 3 hour = zone[0,1] min = zone[1,2] else hour = zone[0,2] min = zone[2,2] sec = zone[4,2] end end offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i offset *= -1 if sign == '-' end offset end end class DateTime < Date def strftime(fmt='%FT%T%:z') super(fmt) end def self._strptime(str, fmt='%FT%T%z') super(str, fmt) end =begin def iso8601_timediv(n) # :nodoc: strftime('T%T' + if n < 1 '' else '.%0*d' % [n, (sec_fraction / SECONDS_IN_DAY / (10**n)).round] end + '%:z') end private :iso8601_timediv def iso8601(n=0) super() + iso8601_timediv(n) end def rfc3339(n=0) iso8601(n) end def jisx0301(n=0) super() + iso8601_timediv(n) end =end end PK|]V  cgi-lib.rbnu[warn "Warning:#{caller[0].sub(/:in `.*'\z/, '')}: cgi-lib is deprecated after Ruby 1.8.1; use cgi instead" =begin = simple CGI support library = example == get form values require "cgi-lib.rb" query = CGI.new query['field'] # <== value of 'field' query.keys # <== array of fields and query has Hash class methods == get cookie values require "cgi-lib.rb" query = CGI.new query.cookie['name'] # <== cookie value of 'name' query.cookie.keys # <== all cookie names and query.cookie has Hash class methods == print HTTP header and HTML string to $> require "cgi-lib.rb" CGI::print{ CGI::tag("HTML"){ CGI::tag("HEAD"){ CGI::tag("TITLE"){"TITLE"} } + CGI::tag("BODY"){ CGI::tag("FORM", {"ACTION"=>"test.rb", "METHOD"=>"POST"}){ CGI::tag("INPUT", {"TYPE"=>"submit", "VALUE"=>"submit"}) } + CGI::tag("HR") } } } == make raw cookie string require "cgi-lib.rb" cookie1 = CGI::cookie({'name' => 'name', 'value' => 'value', 'path' => 'path', # optional 'domain' => 'domain', # optional 'expires' => Time.now, # optional 'secure' => true # optional }) CGI::print("Content-Type: text/html", cookie1, cookie2){ "string" } == print HTTP header and string to $> require "cgi-lib.rb" CGI::print{ "string" } # == CGI::print("Content-Type: text/html"){ "string" } CGI::print("Content-Type: text/html", cookie1, cookie2){ "string" } === NPH (no-parse-header) mode require "cgi-lib.rb" CGI::print("nph"){ "string" } # == CGI::print("nph", "Content-Type: text/html"){ "string" } CGI::print("nph", "Content-Type: text/html", cookie1, cookie2){ "string" } == make HTML tag string require "cgi-lib.rb" CGI::tag("element", {"attribute_name"=>"attribute_value"}){"content"} == make HTTP header string require "cgi-lib.rb" CGI::header # == CGI::header("Content-Type: text/html") CGI::header("Content-Type: text/html", cookie1, cookie2) === NPH (no-parse-header) mode CGI::header("nph") # == CGI::header("nph", "Content-Type: text/html") CGI::header("nph", "Content-Type: text/html", cookie1, cookie2) == escape url encode require "cgi-lib.rb" url_encoded_string = CGI::escape("string") == unescape url encoded require "cgi-lib.rb" string = CGI::unescape("url encoded string") == escape HTML &"<> require "cgi-lib.rb" CGI::escapeHTML("string") =end require "delegate" class CGI < SimpleDelegator CR = "\015" LF = "\012" EOL = CR + LF RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ] RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ] # make rfc1123 date string def CGI::rfc1123_date(time) t = time.clone.gmtime return format("%s, %.2d %s %d %.2d:%.2d:%.2d GMT", RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year, t.hour, t.min, t.sec) end # escape url encode def CGI::escape(str) str.gsub(/[^a-zA-Z0-9_\-.]/n){ sprintf("%%%02X", $&.unpack("C")[0]) } end # unescape url encoded def CGI::unescape(str) str.gsub(/\+/, ' ').gsub(/%([0-9a-fA-F]{2})/){ [$1.hex].pack("c") } end # escape HTML def CGI::escapeHTML(str) str.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/" + (iterator? ? yield.to_s + "" : "") end # make raw cookie string def CGI::cookie(options) "Set-Cookie: " + options['name'] + '=' + escape(options['value']) + (options['domain'] ? '; domain=' + options['domain'] : '') + (options['path'] ? '; path=' + options['path'] : '') + (options['expires'] ? '; expires=' + rfc1123_date(options['expires']) : '') + (options['secure'] ? '; secure' : '') end # make HTTP header string def CGI::header(*options) if defined?(MOD_RUBY) options.each{|option| option.sub(/(.*?): (.*)/){ Apache::request.headers_out[$1] = $2 } } Apache::request.send_http_header '' else if options.delete("nph") or (ENV['SERVER_SOFTWARE'] =~ /IIS/) [(ENV['SERVER_PROTOCOL'] or "HTTP/1.0") + " 200 OK", "Date: " + rfc1123_date(Time.now), "Server: " + (ENV['SERVER_SOFTWARE'] or ""), "Connection: close"] + (options.empty? ? ["Content-Type: text/html"] : options) else options.empty? ? ["Content-Type: text/html"] : options end.join(EOL) + EOL + EOL end end # print HTTP header and string to $> def CGI::print(*options) $>.print CGI::header(*options) + yield.to_s end # print message to $> def CGI::message(message, title = "", header = ["Content-Type: text/html"]) if message.kind_of?(Hash) title = message['title'] header = message['header'] message = message['body'] end CGI::print(*header){ CGI::tag("HTML"){ CGI::tag("HEAD"){ CGI.tag("TITLE"){ title } } + CGI::tag("BODY"){ message } } } true end # print error message to $> and exit def CGI::error CGI::message({'title'=>'ERROR', 'body'=> CGI::tag("PRE"){ "ERROR: " + CGI::tag("STRONG"){ escapeHTML($!.to_s) } + "\n" + escapeHTML($@.join("\n")) } }) exit end end PK|]"a  abbrev.rbnu[#!/usr/bin/env ruby =begin # # Copyright (c) 2001,2003 Akinori MUSHA # # All rights reserved. You can redistribute and/or modify it under # the same terms as Ruby. # # $Idaemons: /home/cvs/rb/abbrev.rb,v 1.2 2001/05/30 09:37:45 knu Exp $ # $RoughId: abbrev.rb,v 1.4 2003/10/14 19:45:42 knu Exp $ # $Id: abbrev.rb 11708 2007-02-12 23:01:19Z shyouhei $ =end # Calculate the set of unique abbreviations for a given set of strings. # # require 'abbrev' # require 'pp' # # pp Abbrev::abbrev(['ruby', 'rules']).sort # # Generates: # # [["rub", "ruby"], # ["ruby", "ruby"], # ["rul", "rules"], # ["rule", "rules"], # ["rules", "rules"]] # # Also adds an +abbrev+ method to class +Array+. module Abbrev # Given a set of strings, calculate the set of unambiguous # abbreviations for those strings, and return a hash where the keys # are all the possible abbreviations and the values are the full # strings. Thus, given input of "car" and "cone", the keys pointing # to "car" would be "ca" and "car", while those pointing to "cone" # would be "co", "con", and "cone". # # The optional +pattern+ parameter is a pattern or a string. Only # those input strings matching the pattern, or begging the string, # are considered for inclusion in the output hash def abbrev(words, pattern = nil) table = {} seen = Hash.new(0) if pattern.is_a?(String) pattern = /^#{Regexp.quote(pattern)}/ # regard as a prefix end words.each do |word| next if (abbrev = word).empty? while (len = abbrev.rindex(/[\w\W]\z/)) > 0 abbrev = word[0,len] next if pattern && pattern !~ abbrev case seen[abbrev] += 1 when 1 table[abbrev] = word when 2 table.delete(abbrev) else break end end end words.each do |word| next if pattern && pattern !~ word table[word] = word end table end module_function :abbrev end class Array # Calculates the set of unambiguous abbreviations for the strings in # +self+. If passed a pattern or a string, only the strings matching # the pattern or starting with the string are considered. # # %w{ car cone }.abbrev #=> { "ca" => "car", "car" => "car", # "co" => "cone", "con" => cone", # "cone" => "cone" } def abbrev(pattern = nil) Abbrev::abbrev(self, pattern) end end if $0 == __FILE__ while line = gets hash = line.split.abbrev hash.sort.each do |k, v| puts "#{k} => #{v}" end end end PK|]3dd English.rbnu[# Include the English library file in a Ruby script, and you can # reference the global variables such as \VAR{\$\_} using less # cryptic names, listed in the following table.% \vref{tab:english}. # # Without 'English': # # $\ = ' -- ' # "waterbuffalo" =~ /buff/ # print $", $', $$, "\n" # # With English: # # require "English" # # $OUTPUT_FIELD_SEPARATOR = ' -- ' # "waterbuffalo" =~ /buff/ # print $LOADED_FEATURES, $POSTMATCH, $PID, "\n" # The exception object passed to +raise+. alias $ERROR_INFO $! # The stack backtrace generated by the last # exception. See Kernel.caller for details. Thread local. alias $ERROR_POSITION $@ # The default separator pattern used by String.split. May be # set from the command line using the -F flag. alias $FS $; # The default separator pattern used by String.split. May be # set from the command line using the -F flag. alias $FIELD_SEPARATOR $; # The separator string output between the parameters to methods such # as Kernel.print and Array.join. Defaults to +nil+, # which adds no text. alias $OFS $, # The separator string output between the parameters to methods such # as Kernel.print and Array.join. Defaults to +nil+, # which adds no text. alias $OUTPUT_FIELD_SEPARATOR $, # The input record separator (newline by default). This is the value # that routines such as Kernel.gets use to determine record # boundaries. If set to +nil+, +gets+ will read the entire file. alias $RS $/ # The input record separator (newline by default). This is the value # that routines such as Kernel.gets use to determine record # boundaries. If set to +nil+, +gets+ will read the entire file. alias $INPUT_RECORD_SEPARATOR $/ # The string appended to the output of every call to methods such as # Kernel.print and IO.write. The default value is # +nil+. alias $ORS $\ # The string appended to the output of every call to methods such as # Kernel.print and IO.write. The default value is # +nil+. alias $OUTPUT_RECORD_SEPARATOR $\ # The number of the last line read from the current input file. alias $INPUT_LINE_NUMBER $. # The number of the last line read from the current input file. alias $NR $. # The last line read by Kernel.gets or # Kernel.readline. Many string-related functions in the # +Kernel+ module operate on $_ by default. The variable is # local to the current scope. Thread local. alias $LAST_READ_LINE $_ # The destination of output for Kernel.print # and Kernel.printf. The default value is # $stdout. alias $DEFAULT_OUTPUT $> # An object that provides access to the concatenation # of the contents of all the files # given as command-line arguments, or $stdin # (in the case where there are no # arguments). $< supports methods similar to a # +File+ object: # +inmode+, +close+, # closed?, +each+, # each_byte, each_line, # +eof+, eof?, +file+, # +filename+, +fileno+, # +getc+, +gets+, +lineno+, # lineno=, +path+, # +pos+, pos=, # +read+, +readchar+, # +readline+, +readlines+, # +rewind+, +seek+, +skip+, # +tell+, to_a, to_i, # to_io, to_s, along with the # methods in +Enumerable+. The method +file+ # returns a +File+ object for the file currently # being read. This may change as $< reads # through the files on the command line. Read only. alias $DEFAULT_INPUT $< # The process number of the program being executed. Read only. alias $PID $$ # The process number of the program being executed. Read only. alias $PROCESS_ID $$ # The exit status of the last child process to terminate. Read # only. Thread local. alias $CHILD_STATUS $? # A +MatchData+ object that encapsulates the results of a successful # pattern match. The variables $&, $`, $', # and $1 to $9 are all derived from # $~. Assigning to $~ changes the values of these # derived variables. This variable is local to the current # scope. Thread local. alias $LAST_MATCH_INFO $~ # If set to any value apart from +nil+ or +false+, all pattern matches # will be case insensitive, string comparisons will ignore case, and # string hash values will be case insensitive. Deprecated alias $IGNORECASE $= # An array of strings containing the command-line # options from the invocation of the program. Options # used by the Ruby interpreter will have been # removed. Read only. Also known simply as +ARGV+. alias $ARGV $* # The string matched by the last successful pattern # match. This variable is local to the current # scope. Read only. Thread local. alias $MATCH $& # The string preceding the match in the last # successful pattern match. This variable is local to # the current scope. Read only. Thread local. alias $PREMATCH $` # The string following the match in the last # successful pattern match. This variable is local to # the current scope. Read only. Thread local. alias $POSTMATCH $' # The contents of the highest-numbered group matched in the last # successful pattern match. Thus, in "cat" =~ /(c|a)(t|z)/, # $+ will be set to "t". This variable is local to the # current scope. Read only. Thread local. alias $LAST_PAREN_MATCH $+ PK|]H~qddopen3.rbnu[# # = open3.rb: Popen, but with stderr, too # # Author:: Yukihiro Matsumoto # Documentation:: Konrad Meyer # # Open3 gives you access to stdin, stdout, and stderr when running other # programs. # # # Open3 grants you access to stdin, stdout, and stderr when running another # program. Example: # # require "open3" # include Open3 # # stdin, stdout, stderr = popen3('nroff -man') # # Open3.popen3 can also take a block which will receive stdin, stdout and # stderr as parameters. This ensures stdin, stdout and stderr are closed # once the block exits. Example: # # require "open3" # # Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... } # module Open3 # # Open stdin, stdout, and stderr streams and start external executable. # Non-block form: # # require 'open3' # # stdin, stdout, stderr = Open3.popen3(cmd) # # Block form: # # require 'open3' # # Open3.popen3(cmd) { |stdin, stdout, stderr| ... } # # The parameter +cmd+ is passed directly to Kernel#exec. # # _popen3_ is like _system_ in that you can pass extra parameters, and the # strings won't be mangled by shell expansion. # # stdin, stdout, stderr = Open3.popen3('identify', '/weird path/with spaces/and "strange" characters.jpg') # result = stdout.read # def popen3(*cmd) pw = IO::pipe # pipe[0] for read, pipe[1] for write pr = IO::pipe pe = IO::pipe pid = fork{ # child fork{ # grandchild pw[1].close STDIN.reopen(pw[0]) pw[0].close pr[0].close STDOUT.reopen(pr[1]) pr[1].close pe[0].close STDERR.reopen(pe[1]) pe[1].close exec(*cmd) } exit!(0) } pw[0].close pr[1].close pe[1].close Process.waitpid(pid) pi = [pw[1], pr[0], pe[0]] pw[1].sync = true if defined? yield begin return yield(*pi) ensure pi.each{|p| p.close unless p.closed?} end end pi end module_function :popen3 end if $0 == __FILE__ a = Open3.popen3("nroff -man") Thread.start do while line = gets a[0].print line end a[0].close end while line = a[1].gets print ":", line end end PK|]99rexml/source.rbnu[require 'rexml/encoding' module REXML # Generates Source-s. USE THIS CLASS. class SourceFactory # Generates a Source object # @param arg Either a String, or an IO # @return a Source, or nil if a bad argument was given def SourceFactory::create_from(arg) if arg.kind_of? String Source.new(arg) elsif arg.respond_to? :read and arg.respond_to? :readline and arg.respond_to? :nil? and arg.respond_to? :eof? IOSource.new(arg) elsif arg.kind_of? Source arg else raise "#{arg.class} is not a valid input stream. It must walk \n"+ "like either a String, an IO, or a Source." end end end # A Source can be searched for patterns, and wraps buffers and other # objects and provides consumption of text class Source include Encoding # The current buffer (what we're going to read next) attr_reader :buffer # The line number of the last consumed text attr_reader :line attr_reader :encoding # Constructor # @param arg must be a String, and should be a valid XML document # @param encoding if non-null, sets the encoding of the source to this # value, overriding all encoding detection def initialize(arg, encoding=nil) @orig = @buffer = arg if encoding self.encoding = encoding else self.encoding = check_encoding( @buffer ) end @line = 0 end # Inherited from Encoding # Overridden to support optimized en/decoding def encoding=(enc) return unless super @line_break = encode( '>' ) if enc != UTF_8 @buffer = decode(@buffer) @to_utf = true else @to_utf = false end end # Scans the source for a given pattern. Note, that this is not your # usual scan() method. For one thing, the pattern argument has some # requirements; for another, the source can be consumed. You can easily # confuse this method. Originally, the patterns were easier # to construct and this method more robust, because this method # generated search regexes on the fly; however, this was # computationally expensive and slowed down the entire REXML package # considerably, since this is by far the most commonly called method. # @param pattern must be a Regexp, and must be in the form of # /^\s*(#{your pattern, with no groups})(.*)/. The first group # will be returned; the second group is used if the consume flag is # set. # @param consume if true, the pattern returned will be consumed, leaving # everything after it in the Source. # @return the pattern, if found, or nil if the Source is empty or the # pattern is not found. def scan(pattern, cons=false) return nil if @buffer.nil? rv = @buffer.scan(pattern) @buffer = $' if cons and rv.size>0 rv end def read end def consume( pattern ) @buffer = $' if pattern.match( @buffer ) end def match_to( char, pattern ) return pattern.match(@buffer) end def match_to_consume( char, pattern ) md = pattern.match(@buffer) @buffer = $' return md end def match(pattern, cons=false) md = pattern.match(@buffer) @buffer = $' if cons and md return md end # @return true if the Source is exhausted def empty? @buffer == "" end def position @orig.index( @buffer ) end # @return the current line in the source def current_line lines = @orig.split res = lines.grep @buffer[0..30] res = res[-1] if res.kind_of? Array lines.index( res ) if res end end # A Source that wraps an IO. See the Source class for method # documentation class IOSource < Source #attr_reader :block_size # block_size has been deprecated def initialize(arg, block_size=500, encoding=nil) @er_source = @source = arg @to_utf = false # Determining the encoding is a deceptively difficult issue to resolve. # First, we check the first two bytes for UTF-16. Then we # assume that the encoding is at least ASCII enough for the '>', and # we read until we get one of those. This gives us the XML declaration, # if there is one. If there isn't one, the file MUST be UTF-8, as per # the XML spec. If there is one, we can determine the encoding from # it. @buffer = "" str = @source.read( 2 ) if encoding self.encoding = encoding elsif 0xfe == str[0] && 0xff == str[1] @line_break = "\000>" elsif 0xff == str[0] && 0xfe == str[1] @line_break = ">\000" elsif 0xef == str[0] && 0xbb == str[1] str += @source.read(1) str = '' if (0xbf == str[2]) @line_break = ">" else @line_break = ">" end super str+@source.readline( @line_break ) end def scan(pattern, cons=false) rv = super # You'll notice that this next section is very similar to the same # section in match(), but just a liiittle different. This is # because it is a touch faster to do it this way with scan() # than the way match() does it; enough faster to warrent duplicating # some code if rv.size == 0 until @buffer =~ pattern or @source.nil? begin # READLINE OPT #str = @source.read(@block_size) str = @source.readline(@line_break) str = decode(str) if @to_utf and str @buffer << str rescue Iconv::IllegalSequence raise rescue @source = nil end end rv = super end rv.taint rv end def read begin str = @source.readline(@line_break) str = decode(str) if @to_utf and str @buffer << str rescue Exception, NameError @source = nil end end def consume( pattern ) match( pattern, true ) end def match( pattern, cons=false ) rv = pattern.match(@buffer) @buffer = $' if cons and rv while !rv and @source begin str = @source.readline(@line_break) str = decode(str) if @to_utf and str @buffer << str rv = pattern.match(@buffer) @buffer = $' if cons and rv rescue @source = nil end end rv.taint rv end def empty? super and ( @source.nil? || @source.eof? ) end def position @er_source.stat.pipe? ? 0 : @er_source.pos end # @return the current line in the source def current_line begin pos = @er_source.pos # The byte position in the source lineno = @er_source.lineno # The XML < position in the source @er_source.rewind line = 0 # The \r\n position in the source begin while @er_source.pos < pos @er_source.readline line += 1 end rescue end rescue IOError pos = -1 line = -1 end [pos, lineno, line] end end end PK|]Lrexml/rexml.rbnu[# -*- encoding: utf-8 -*- # REXML is an XML toolkit for Ruby[http://www.ruby-lang.org], in Ruby. # # REXML is a _pure_ Ruby, XML 1.0 conforming, # non-validating[http://www.w3.org/TR/2004/REC-xml-20040204/#sec-conformance] # toolkit with an intuitive API. REXML passes 100% of the non-validating Oasis # tests[http://www.oasis-open.org/committees/xml-conformance/xml-test-suite.shtml], # and provides tree, stream, SAX2, pull, and lightweight APIs. REXML also # includes a full XPath[http://www.w3c.org/tr/xpath] 1.0 implementation. Since # Ruby 1.8, REXML is included in the standard Ruby distribution. # # Main page:: http://www.germane-software.com/software/rexml # Author:: Sean Russell # Version:: 3.1.7.2 # Date:: 2007/275 # Revision:: $Revision: 40812 $ # # This API documentation can be downloaded from the REXML home page, or can # be accessed online[http://www.germane-software.com/software/rexml_doc] # # A tutorial is available in the REXML distribution in docs/tutorial.html, # or can be accessed # online[http://www.germane-software.com/software/rexml/docs/tutorial.html] module REXML COPYRIGHT = "Copyright \xC2\xA9 2001-2006 Sean Russell " VERSION = "3.1.7.3" DATE = "2007/275" REVISION = "$Revision: 40812 $".gsub(/\$Revision:|\$/,'').strip Copyright = COPYRIGHT Version = VERSION @@entity_expansion_text_limit = 10_240 # Set the entity expansion limit. By default the limit is set to 10240. def self.entity_expansion_text_limit=( val ) @@entity_expansion_text_limit = val end # Get the entity expansion limit. By default the limit is set to 10240. def self.entity_expansion_text_limit return @@entity_expansion_text_limit end end PK|]Fykkrexml/dtd/dtd.rbnu[require "rexml/dtd/elementdecl" require "rexml/dtd/entitydecl" require "rexml/comment" require "rexml/dtd/notationdecl" require "rexml/dtd/attlistdecl" require "rexml/parent" module REXML module DTD class Parser def Parser.parse( input ) case input when String parse_helper input when File parse_helper input.read end end # Takes a String and parses it out def Parser.parse_helper( input ) contents = Parent.new while input.size > 0 case input when ElementDecl.PATTERN_RE match = $& source = $' contents << ElementDecl.new( match ) when AttlistDecl.PATTERN_RE matchdata = $~ source = $' contents << AttlistDecl.new( matchdata ) when EntityDecl.PATTERN_RE matchdata = $~ source = $' contents << EntityDecl.new( matchdata ) when Comment.PATTERN_RE matchdata = $~ source = $' contents << Comment.new( matchdata ) when NotationDecl.PATTERN_RE matchdata = $~ source = $' contents << NotationDecl.new( matchdata ) end end contents end end end end PK|]kZ*rexml/dtd/entitydecl.rbnu[require "rexml/child" module REXML module DTD class EntityDecl < Child START = "/um SYSTEM = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+SYSTEM\s+((["']).*?\3)(?:\s+NDATA\s+\w+)?\s*>/um PLAIN = /^\s*#{START}\s+(\w+)\s+((["']).*?\3)\s*>/um PERCENT = /^\s*#{START}\s+%\s+(\w+)\s+((["']).*?\3)\s*>/um # # def initialize src super() md = nil if src.match( PUBLIC ) md = src.match( PUBLIC, true ) @middle = "PUBLIC" @content = "#{md[2]} #{md[4]}" elsif src.match( SYSTEM ) md = src.match( SYSTEM, true ) @middle = "SYSTEM" @content = md[2] elsif src.match( PLAIN ) md = src.match( PLAIN, true ) @middle = "" @content = md[2] elsif src.match( PERCENT ) md = src.match( PERCENT, true ) @middle = "" @content = md[2] end raise ParseException.new("failed Entity match", src) if md.nil? @name = md[1] end def to_s rv = " 0 rv << @content rv end def write( output, indent ) indent( output, indent ) output << to_s end def EntityDecl.parse_source source, listener md = source.match( PATTERN_RE, true ) thing = md[0].squeeze(" \t\n\r") listener.send inspect.downcase, thing end end end end PK|]oarexml/dtd/notationdecl.rbnu[require "rexml/child" module REXML module DTD class NotationDecl < Child START = "/um SYSTEM = /^\s*#{START}\s+(\w[\w-]*)\s+(SYSTEM)\s+((["']).*?\4)\s*>/um def initialize src super() if src.match( PUBLIC ) md = src.match( PUBLIC, true ) elsif src.match( SYSTEM ) md = src.match( SYSTEM, true ) else raise ParseException.new( "error parsing notation: no matching pattern", src ) end @name = md[1] @middle = md[2] @rest = md[3] end def to_s "" end def write( output, indent ) indent( output, indent ) output << to_s end def NotationDecl.parse_source source, listener md = source.match( PATTERN_RE, true ) thing = md[0].squeeze(" \t\n\r") listener.send inspect.downcase, thing end end end end PK|] _rexml/dtd/elementdecl.rbnu[require "rexml/child" module REXML module DTD class ElementDecl < Child START = "/um PATTERN_RE = /^\s*#{START}\s+((?:[:\w_][-\.\w_]*:)?[-!\*\.\w_]*)(.*?)>/ #\s*((((["']).*?\5)|[^\/'">]*)*?)(\/)?>/um, true) def initialize match @name = match[1] @rest = match[2] end end end end PK|]|昶rexml/dtd/attlistdecl.rbnu[require "rexml/child" module REXML module DTD class AttlistDecl < Child START = ")/um end end end PK|]z  rexml/sax2listener.rbnu[module REXML # A template for stream parser listeners. # Note that the declarations (attlistdecl, elementdecl, etc) are trivially # processed; REXML doesn't yet handle doctype entity declarations, so you # have to parse them out yourself. # === Missing methods from SAX2 # ignorable_whitespace # === Methods extending SAX2 # +WARNING+ # These methods are certainly going to change, until DTDs are fully # supported. Be aware of this. # start_document # end_document # doctype # elementdecl # attlistdecl # entitydecl # notationdecl # cdata # xmldecl # comment module SAX2Listener def start_document end def end_document end def start_prefix_mapping prefix, uri end def end_prefix_mapping prefix end def start_element uri, localname, qname, attributes end def end_element uri, localname, qname end def characters text end def processing_instruction target, data end # Handles a doctype declaration. Any attributes of the doctype which are # not supplied will be nil. # EG, # @p name the name of the doctype; EG, "me" # @p pub_sys "PUBLIC", "SYSTEM", or nil. EG, "PUBLIC" # @p long_name the supplied long name, or nil. EG, "foo" # @p uri the uri of the doctype, or nil. EG, "bar" def doctype name, pub_sys, long_name, uri end # If a doctype includes an ATTLIST declaration, it will cause this # method to be called. The content is the declaration itself, unparsed. # EG, will come to this method as "el # attr CDATA #REQUIRED". This is the same for all of the .*decl # methods. def attlistdecl(element, pairs, contents) end # def elementdecl content end # # The argument passed to this method is an array of the entity # declaration. It can be in a number of formats, but in general it # returns (example, result): # # ["%", "YN", "'\"Yes\"'", "\""] # # ["%", "YN", "'Yes'", "s"] # # ["WhatHeSaid", "\"He said %YN;\"", "YN"] # # ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] # # ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] # # ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"] def entitydecl name, decl end # def notationdecl content end # Called when is encountered in a document. # @p content "..." def cdata content end # Called when an XML PI is encountered in the document. # EG: # @p version the version attribute value. EG, "1.0" # @p encoding the encoding attribute value, or nil. EG, "utf" # @p standalone the standalone attribute value, or nil. EG, nil # @p spaced the declaration is followed by a line break def xmldecl version, encoding, standalone end # Called when a comment is encountered. # @p comment The content of the comment def comment comment end def progress position end end end PK|]#&rexml/parseexception.rbnu[module REXML class ParseException < RuntimeError attr_accessor :source, :parser, :continued_exception def initialize( message, source=nil, parser=nil, exception=nil ) super(message) @source = source @parser = parser @continued_exception = exception end def to_s # Quote the original exception, if there was one if @continued_exception err = @continued_exception.inspect err << "\n" err << @continued_exception.backtrace.join("\n") err << "\n...\n" else err = "" end # Get the stack trace and error message err << super # Add contextual information if @source err << "\nLine: #{line}\n" err << "Position: #{position}\n" err << "Last 80 unconsumed characters:\n" err << @source.buffer[0..80].gsub(/\n/, ' ') end err end def position @source.current_line[0] if @source and defined? @source.current_line and @source.current_line end def line @source.current_line[2] if @source and defined? @source.current_line and @source.current_line end def context @source.current_line end end end PK|]) rexml/node.rbnu[require "rexml/parseexception" require "rexml/formatters/pretty" require "rexml/formatters/default" module REXML # Represents a node in the tree. Nodes are never encountered except as # superclasses of other objects. Nodes have siblings. module Node # @return the next sibling (nil if unset) def next_sibling_node return nil if @parent.nil? @parent[ @parent.index(self) + 1 ] end # @return the previous sibling (nil if unset) def previous_sibling_node return nil if @parent.nil? ind = @parent.index(self) return nil if ind == 0 @parent[ ind - 1 ] end # indent:: # *DEPRECATED* This parameter is now ignored. See the formatters in the # REXML::Formatters package for changing the output style. def to_s indent=nil unless indent.nil? Kernel.warn( "#{self.class.name}.to_s(indent) parameter is deprecated" ) f = REXML::Formatters::Pretty.new( indent ) f.write( self, rv = "" ) else f = REXML::Formatters::Default.new f.write( self, rv = "" ) end return rv end def indent to, ind if @parent and @parent.context and not @parent.context[:indentstyle].nil? then indentstyle = @parent.context[:indentstyle] else indentstyle = ' ' end to << indentstyle*ind unless ind<1 end def parent? false; end # Visit all subnodes of +self+ recursively def each_recursive(&block) # :yields: node self.elements.each {|node| block.call(node) node.each_recursive(&block) } end # Find (and return) first subnode (recursively) for which the block # evaluates to true. Returns +nil+ if none was found. def find_first_recursive(&block) # :yields: node each_recursive {|node| return node if block.call(node) } return nil end # Returns the position that +self+ holds in its parent's array, indexed # from 1. def index_in_parent parent.index(self)+1 end end end PK|]ھrexml/syncenumerator.rbnu[module REXML class SyncEnumerator include Enumerable # Creates a new SyncEnumerator which enumerates rows of given # Enumerable objects. def initialize(*enums) @gens = enums @biggest = @gens[0] @gens.each {|x| @biggest = x if x.size > @biggest.size } end # Returns the number of enumerated Enumerable objects, i.e. the size # of each row. def size @gens.size end # Returns the number of enumerated Enumerable objects, i.e. the size # of each row. def length @gens.length end # Enumerates rows of the Enumerable objects. def each @biggest.zip( *@gens ) {|a| yield(*a[1..-1]) } self end end end PK|]`$rexml/undefinednamespaceexception.rbnu[require 'rexml/parseexception' module REXML class UndefinedNamespaceException < ParseException def initialize( prefix, source, parser ) super( "Undefined prefix #{prefix} found" ) end end end PK|]$돇rexml/light/node.rbnu[require 'rexml/xmltokens' require 'rexml/light/node' # [ :element, parent, name, attributes, children* ] # a = Node.new # a << "B" # => B # a.b # => B # a.b[1] # => B # a.b[1]["x"] = "y" # => B # a.b[0].c # => B # a.b.c << "D" # => BD module REXML module Light # Represents a tagged XML element. Elements are characterized by # having children, attributes, and names, and can themselves be # children. class Node NAMESPLIT = /^(?:(#{XMLTokens::NCNAME_STR}):)?(#{XMLTokens::NCNAME_STR})/u PARENTS = [ :element, :document, :doctype ] # Create a new element. def initialize node=nil @node = node if node.kind_of? String node = [ :text, node ] elsif node.nil? node = [ :document, nil, nil ] elsif node[0] == :start_element node[0] = :element elsif node[0] == :start_doctype node[0] = :doctype elsif node[0] == :start_document node[0] = :document end end def size if PARENTS.include? @node[0] @node[-1].size else 0 end end def each( &block ) size.times { |x| yield( at(x+4) ) } end def name at(2) end def name=( name_str, ns=nil ) pfx = '' pfx = "#{prefix(ns)}:" if ns _old_put(2, "#{pfx}#{name_str}") end def parent=( node ) _old_put(1,node) end def local_name namesplit @name end def local_name=( name_str ) _old_put( 1, "#@prefix:#{name_str}" ) end def prefix( namespace=nil ) prefix_of( self, namespace ) end def namespace( prefix=prefix() ) namespace_of( self, prefix ) end def namespace=( namespace ) @prefix = prefix( namespace ) pfx = '' pfx = "#@prefix:" if @prefix.size > 0 _old_put(1, "#{pfx}#@name") end def []( reference, ns=nil ) if reference.kind_of? String pfx = '' pfx = "#{prefix(ns)}:" if ns at(3)["#{pfx}#{reference}"] elsif reference.kind_of? Range _old_get( Range.new(4+reference.begin, reference.end, reference.exclude_end?) ) else _old_get( 4+reference ) end end def =~( path ) XPath.match( self, path ) end # Doesn't handle namespaces yet def []=( reference, ns, value=nil ) if reference.kind_of? String value = ns unless value at( 3 )[reference] = value elsif reference.kind_of? Range _old_put( Range.new(3+reference.begin, reference.end, reference.exclude_end?), ns ) else if value _old_put( 4+reference, ns, value ) else _old_put( 4+reference, ns ) end end end # Append a child to this element, optionally under a provided namespace. # The namespace argument is ignored if the element argument is an Element # object. Otherwise, the element argument is a string, the namespace (if # provided) is the namespace the element is created in. def << element if node_type() == :text at(-1) << element else newnode = Node.new( element ) newnode.parent = self self.push( newnode ) end at(-1) end def node_type _old_get(0) end def text=( foo ) replace = at(4).kind_of?(String)? 1 : 0 self._old_put(4,replace, normalizefoo) end def root context = self context = context.at(1) while context.at(1) end def has_name?( name, namespace = '' ) at(3) == name and namespace() == namespace end def children self end def parent at(1) end def to_s end private def namesplit return if @name.defined? at(2) =~ NAMESPLIT @prefix = '' || $1 @name = $2 end def namespace_of( node, prefix=nil ) if not prefix name = at(2) name =~ NAMESPLIT prefix = $1 end to_find = 'xmlns' to_find = "xmlns:#{prefix}" if not prefix.nil? ns = at(3)[ to_find ] ns ? ns : namespace_of( @node[0], prefix ) end def prefix_of( node, namespace=nil ) if not namespace name = node.name name =~ NAMESPLIT $1 else ns = at(3).find { |k,v| v == namespace } ns ? ns : prefix_of( node.parent, namespace ) end end end end end PK|];ŝrexml/quickpath.rbnu[require 'rexml/functions' require 'rexml/xmltokens' module REXML class QuickPath include Functions include XMLTokens EMPTY_HASH = {} def QuickPath::first element, path, namespaces=EMPTY_HASH match(element, path, namespaces)[0] end def QuickPath::each element, path, namespaces=EMPTY_HASH, &block path = "*" unless path match(element, path, namespaces).each( &block ) end def QuickPath::match element, path, namespaces=EMPTY_HASH raise "nil is not a valid xpath" unless path results = nil Functions::namespace_context = namespaces case path when /^\/([^\/]|$)/u # match on root path = path[1..-1] return [element.root.parent] if path == '' results = filter([element.root], path) when /^[-\w]*::/u results = filter([element], path) when /^\*/u results = filter(element.to_a, path) when /^[\[!\w:]/u # match on child matches = [] children = element.to_a results = filter(children, path) else results = filter([element], path) end return results end # Given an array of nodes it filters the array based on the path. The # result is that when this method returns, the array will contain elements # which match the path def QuickPath::filter elements, path return elements if path.nil? or path == '' or elements.size == 0 case path when /^\/\//u # Descendant return axe( elements, "descendant-or-self", $' ) when /^\/?\b(\w[-\w]*)\b::/u # Axe axe_name = $1 rest = $' return axe( elements, $1, $' ) when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u # Child rest = $' results = [] elements.each do |element| results |= filter( element.to_a, rest ) end return results when /^\/?(\w[-\w]*)\(/u # / Function return function( elements, $1, $' ) when Namespace::NAMESPLIT # Element name name = $2 ns = $1 rest = $' elements.delete_if do |element| !(element.kind_of? Element and (element.expanded_name == name or (element.name == name and element.namespace == Functions.namespace_context[ns]))) end return filter( elements, rest ) when /^\/\[/u matches = [] elements.each do |element| matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element end return matches when /^\[/u # Predicate return predicate( elements, path ) when /^\/?\.\.\./u # Ancestor return axe( elements, "ancestor", $' ) when /^\/?\.\./u # Parent return filter( elements.collect{|e|e.parent}, $' ) when /^\/?\./u # Self return filter( elements, $' ) when /^\*/u # Any results = [] elements.each do |element| results |= filter( [element], $' ) if element.kind_of? Element #if element.kind_of? Element # children = element.to_a # children.delete_if { |child| !child.kind_of?(Element) } # results |= filter( children, $' ) #end end return results end return [] end def QuickPath::axe( elements, axe_name, rest ) matches = [] matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u case axe_name when /^descendant/u elements.each do |element| matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element end when /^ancestor/u elements.each do |element| while element.parent matches << element.parent element = element.parent end end matches = filter( matches, rest ) when "self" matches = filter( elements, rest ) when "child" elements.each do |element| matches |= filter( element.to_a, rest ) if element.kind_of? Element end when "attribute" elements.each do |element| matches << element.attributes[ rest ] if element.kind_of? Element end when "parent" matches = filter(elements.collect{|element| element.parent}.uniq, rest) when "following-sibling" matches = filter(elements.collect{|element| element.next_sibling}.uniq, rest) when "previous-sibling" matches = filter(elements.collect{|element| element.previous_sibling}.uniq, rest ) end return matches.uniq end # A predicate filters a node-set with respect to an axis to produce a # new node-set. For each node in the node-set to be filtered, the # PredicateExpr is evaluated with that node as the context node, with # the number of nodes in the node-set as the context size, and with the # proximity position of the node in the node-set with respect to the # axis as the context position; if PredicateExpr evaluates to true for # that node, the node is included in the new node-set; otherwise, it is # not included. # # A PredicateExpr is evaluated by evaluating the Expr and converting # the result to a boolean. If the result is a number, the result will # be converted to true if the number is equal to the context position # and will be converted to false otherwise; if the result is not a # number, then the result will be converted as if by a call to the # boolean function. Thus a location path para[3] is equivalent to # para[position()=3]. def QuickPath::predicate( elements, path ) ind = 1 bcount = 1 while bcount > 0 bcount += 1 if path[ind] == ?[ bcount -= 1 if path[ind] == ?] ind += 1 end ind -= 1 predicate = path[1..ind-1] rest = path[ind+1..-1] # have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c' predicate.gsub!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/u ) { "#$1 #$2 #$3 and #$3 #$4 #$5" } # Let's do some Ruby trickery to avoid some work: predicate.gsub!( /&/u, "&&" ) predicate.gsub!( /=/u, "==" ) predicate.gsub!( /@(\w[-\w.]*)/u ) { "attribute(\"#$1\")" } predicate.gsub!( /\bmod\b/u, "%" ) predicate.gsub!( /\b(\w[-\w.]*\()/u ) { fname = $1 fname.gsub( /-/u, "_" ) } Functions.pair = [ 0, elements.size ] results = [] elements.each do |element| Functions.pair[0] += 1 Functions.node = element res = eval( predicate ) case res when true results << element when Fixnum results << element if Functions.pair[0] == res when String results << element end end return filter( results, rest ) end def QuickPath::attribute( name ) return Functions.node.attributes[name] if Functions.node.kind_of? Element end def QuickPath::name() return Functions.node.name if Functions.node.kind_of? Element end def QuickPath::method_missing( id, *args ) begin Functions.send( id.id2name, *args ) rescue Exception raise "METHOD: #{id.id2name}(#{args.join ', '})\n#{$!.message}" end end def QuickPath::function( elements, fname, rest ) args = parse_args( elements, rest ) Functions.pair = [0, elements.size] results = [] elements.each do |element| Functions.pair[0] += 1 Functions.node = element res = Functions.send( fname, *args ) case res when true results << element when Fixnum results << element if Functions.pair[0] == res end end return results end def QuickPath::parse_args( element, string ) # /.*?(?:\)|,)/ arguments = [] buffer = "" while string and string != "" c = string[0] string.sub!(/^./u, "") case c when ?, # if depth = 1, then we start a new argument arguments << evaluate( buffer ) #arguments << evaluate( string[0..count] ) when ?( # start a new method call function( element, buffer, string ) buffer = "" when ?) # close the method call and return arguments return arguments else buffer << c end end "" end end end PK|](:2 rexml/xmldecl.rbnu[require 'rexml/encoding' require 'rexml/source' module REXML # NEEDS DOCUMENTATION class XMLDecl < Child include Encoding DEFAULT_VERSION = "1.0"; DEFAULT_ENCODING = "UTF-8"; DEFAULT_STANDALONE = "no"; START = '<\?xml'; STOP = '\?>'; attr_accessor :version, :standalone attr_reader :writeencoding, :writethis def initialize(version=DEFAULT_VERSION, encoding=nil, standalone=nil) @writethis = true @writeencoding = !encoding.nil? if version.kind_of? XMLDecl super() @version = version.version self.encoding = version.encoding @writeencoding = version.writeencoding @standalone = version.standalone else super() @version = version self.encoding = encoding @standalone = standalone end @version = DEFAULT_VERSION if @version.nil? end def clone XMLDecl.new(self) end # indent:: # Ignored. There must be no whitespace before an XML declaration # transitive:: # Ignored # ie_hack:: # Ignored def write(writer, indent=-1, transitive=false, ie_hack=false) return nil unless @writethis or writer.kind_of? Output writer << START.sub(/\\/u, '') if writer.kind_of? Output writer << " #{content writer.encoding}" else writer << " #{content encoding}" end writer << STOP.sub(/\\/u, '') end def ==( other ) other.kind_of?(XMLDecl) and other.version == @version and other.encoding == self.encoding and other.standalone == @standalone end def xmldecl version, encoding, standalone @version = version self.encoding = encoding @standalone = standalone end def node_type :xmldecl end alias :stand_alone? :standalone alias :old_enc= :encoding= def encoding=( enc ) if enc.nil? self.old_enc = "UTF-8" @writeencoding = false else self.old_enc = enc @writeencoding = true end self.dowrite end # Only use this if you do not want the XML declaration to be written; # this object is ignored by the XML writer. Otherwise, instantiate your # own XMLDecl and add it to the document. # # Note that XML 1.1 documents *must* include an XML declaration def XMLDecl.default rv = XMLDecl.new( "1.0" ) rv.nowrite rv end def nowrite @writethis = false end def dowrite @writethis = true end def inspect START.sub(/\\/u, '') + " ... " + STOP.sub(/\\/u, '') end private def content(enc) rv = "version='#@version'" rv << " encoding='#{enc}'" if @writeencoding || enc !~ /utf-8/i rv << " standalone='#@standalone'" if @standalone rv end end end PK|]:irexml/comment.rbnu[require "rexml/child" module REXML ## # Represents an XML comment; that is, text between \ class Comment < Child include Comparable START = "" # The content text attr_accessor :string ## # Constructor. The first argument can be one of three types: # @param first If String, the contents of this comment are set to the # argument. If Comment, the argument is duplicated. If # Source, the argument is scanned for a comment. # @param second If the first argument is a Source, this argument # should be nil, not supplied, or a Parent to be set as the parent # of this object def initialize( first, second = nil ) #puts "IN COMMENT CONSTRUCTOR; SECOND IS #{second.type}" super(second) if first.kind_of? String @string = first elsif first.kind_of? Comment @string = first.string end end def clone Comment.new self end # == DEPRECATED # See REXML::Formatters # # output:: # Where to write the string # indent:: # An integer. If -1, no indenting will be used; otherwise, the # indentation will be this number of spaces, and children will be # indented an additional amount. # transitive:: # Ignored by this class. The contents of comments are never modified. # ie_hack:: # Needed for conformity to the child API, but not used by this class. def write( output, indent=-1, transitive=false, ie_hack=false ) Kernel.warn("Comment.write is deprecated. See REXML::Formatters") indent( output, indent ) output << START output << @string output << STOP end alias :to_s :string ## # Compares this Comment to another; the contents of the comment are used # in the comparison. def <=>(other) other.to_s <=> @string end ## # Compares this Comment to another; the contents of the comment are used # in the comparison. def ==( other ) other.kind_of? Comment and (other <=> self) == 0 end def node_type :comment end end end #vim:ts=2 sw=2 noexpandtab: PK|] rexml/attribute.rbnu[require "rexml/namespace" require 'rexml/text' module REXML # Defines an Element Attribute; IE, a attribute=value pair, as in: # . Attributes can be in their own # namespaces. General users of REXML will not interact with the # Attribute class much. class Attribute include Node include Namespace # The element to which this attribute belongs attr_reader :element # The normalized value of this attribute. That is, the attribute with # entities intact. attr_writer :normalized PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um # Constructor. # FIXME: The parser doesn't catch illegal characters in attributes # # first:: # Either: an Attribute, which this new attribute will become a # clone of; or a String, which is the name of this attribute # second:: # If +first+ is an Attribute, then this may be an Element, or nil. # If nil, then the Element parent of this attribute is the parent # of the +first+ Attribute. If the first argument is a String, # then this must also be a String, and is the content of the attribute. # If this is the content, it must be fully normalized (contain no # illegal characters). # parent:: # Ignored unless +first+ is a String; otherwise, may be the Element # parent of this attribute, or nil. # # # Attribute.new( attribute_to_clone ) # Attribute.new( attribute_to_clone, parent_element ) # Attribute.new( "attr", "attr_value" ) # Attribute.new( "attr", "attr_value", parent_element ) def initialize( first, second=nil, parent=nil ) @normalized = @unnormalized = @element = nil if first.kind_of? Attribute self.name = first.expanded_name @unnormalized = first.value if second.kind_of? Element @element = second else @element = first.element end elsif first.kind_of? String @element = parent self.name = first @normalized = second.to_s else raise "illegal argument #{first.class.name} to Attribute constructor" end end # Returns the namespace of the attribute. # # e = Element.new( "elns:myelement" ) # e.add_attribute( "nsa:a", "aval" ) # e.add_attribute( "b", "bval" ) # e.attributes.get_attribute( "a" ).prefix # -> "nsa" # e.attributes.get_attribute( "b" ).prefix # -> "elns" # a = Attribute.new( "x", "y" ) # a.prefix # -> "" def prefix pf = super if pf == "" pf = @element.prefix if @element end pf end # Returns the namespace URL, if defined, or nil otherwise # # e = Element.new("el") # e.add_attributes({"xmlns:ns", "http://url"}) # e.namespace( "ns" ) # -> "http://url" def namespace arg=nil arg = prefix if arg.nil? @element.namespace arg end # Returns true if other is an Attribute and has the same name and value, # false otherwise. def ==( other ) other.kind_of?(Attribute) and other.name==name and other.value==value end # Creates (and returns) a hash from both the name and value def hash name.hash + value.hash end # Returns this attribute out as XML source, expanding the name # # a = Attribute.new( "x", "y" ) # a.to_string # -> "x='y'" # b = Attribute.new( "ns:x", "y" ) # b.to_string # -> "ns:x='y'" def to_string if @element and @element.context and @element.context[:attribute_quote] == :quote %Q^#@expanded_name="#{to_s().gsub(/"/, '"e;')}"^ else "#@expanded_name='#{to_s().gsub(/'/, ''')}'" end end # Returns the attribute value, with entities replaced def to_s return @normalized if @normalized doctype = nil if @element doc = @element.document doctype = doc.doctype if doc end @normalized = Text::normalize( @unnormalized, doctype ) @unnormalized = nil @normalized end # Returns the UNNORMALIZED value of this attribute. That is, entities # have been expanded to their values def value return @unnormalized if @unnormalized doctype = nil if @element doc = @element.document doctype = doc.doctype if doc end @unnormalized = Text::unnormalize( @normalized, doctype ) @normalized = nil @unnormalized end # Returns a copy of this attribute def clone Attribute.new self end # Sets the element of which this object is an attribute. Normally, this # is not directly called. # # Returns this attribute def element=( element ) @element = element self end # Removes this Attribute from the tree, and returns true if successfull # # This method is usually not called directly. def remove @element.attributes.delete self.name unless @element.nil? end # Writes this attribute (EG, puts 'key="value"' to the output) def write( output, indent=-1 ) output << to_string end def node_type :attribute end def inspect rv = "" write( rv ) rv end def xpath path = @element.xpath path += "/@#{self.expanded_name}" return path end end end #vim:ts=2 sw=2 noexpandtab: PK|] \ rexml/xpath.rbnu[require 'rexml/functions' require 'rexml/xpath_parser' module REXML # Wrapper class. Use this class to access the XPath functions. class XPath include Functions EMPTY_HASH = {} # Finds and returns the first node that matches the supplied xpath. # element:: # The context element # path:: # The xpath to search for. If not supplied or nil, returns the first # node matching '*'. # namespaces:: # If supplied, a Hash which defines a namespace mapping. # # XPath.first( node ) # XPath.first( doc, "//b"} ) # XPath.first( node, "a/x:b", { "x"=>"http://doofus" } ) def XPath::first element, path=nil, namespaces=nil, variables={} raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash) raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash) parser = XPathParser.new parser.namespaces = namespaces parser.variables = variables path = "*" unless path element = [element] unless element.kind_of? Array parser.parse(path, element).flatten[0] end # Iterates over nodes that match the given path, calling the supplied # block with the match. # element:: # The context element # path:: # The xpath to search for. If not supplied or nil, defaults to '*' # namespaces:: # If supplied, a Hash which defines a namespace mapping # # XPath.each( node ) { |el| ... } # XPath.each( node, '/*[@attr='v']' ) { |el| ... } # XPath.each( node, 'ancestor::x' ) { |el| ... } def XPath::each element, path=nil, namespaces=nil, variables={}, &block raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash) raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash) parser = XPathParser.new parser.namespaces = namespaces parser.variables = variables path = "*" unless path element = [element] unless element.kind_of? Array parser.parse(path, element).each( &block ) end # Returns an array of nodes matching a given XPath. def XPath::match element, path=nil, namespaces=nil, variables={} parser = XPathParser.new parser.namespaces = namespaces parser.variables = variables path = "*" unless path element = [element] unless element.kind_of? Array parser.parse(path,element) end end end PK|](;8rexml/encodings/UTF-16.rbnu[module REXML module Encoding def encode_utf16 content array_utf8 = content.unpack("U*") array_enc = [] array_utf8.each do |num| if ((num>>16) > 0) array_enc << 0 array_enc << ?? else array_enc << (num >> 8) array_enc << (num & 0xFF) end end array_enc.pack('C*') end def decode_utf16(str) str = str[2..-1] if /^\376\377/n =~ str array_enc=str.unpack('C*') array_utf8 = [] 0.step(array_enc.size-1, 2){|i| array_utf8 << (array_enc.at(i+1) + array_enc.at(i)*0x100) } array_utf8.pack('U*') end register(UTF_16) do |obj| class << obj alias decode decode_utf16 alias encode encode_utf16 end end end end PK|]3#  rexml/encodings/UTF-8.rbnu[module REXML module Encoding def encode_utf8 content content end def decode_utf8(str) str end register(UTF_8) do |obj| class << obj alias decode decode_utf8 alias encode encode_utf8 end end end end PK|]rexml/encodings/ISO-8859-1.rbnu[require 'rexml/encodings/US-ASCII' module REXML module Encoding register("ISO-8859-1", &encoding_method("US-ASCII")) end end PK|](FSSrexml/encodings/EUC-JP.rbnu[module REXML module Encoding begin require 'uconv' def decode_eucjp(str) Uconv::euctou8(str) end def encode_eucjp content Uconv::u8toeuc(content) end rescue LoadError require 'nkf' EUCTOU8 = '-Ewm0' U8TOEUC = '-Wem0' def decode_eucjp(str) NKF.nkf(EUCTOU8, str) end def encode_eucjp content NKF.nkf(U8TOEUC, content) end end register("EUC-JP") do |obj| class << obj alias decode decode_eucjp alias encode encode_eucjp end end end end PK|]*rexml/encodings/UNILE.rbnu[module REXML module Encoding def encode_unile content array_utf8 = content.unpack("U*") array_enc = [] array_utf8.each do |num| if ((num>>16) > 0) array_enc << ?? array_enc << 0 else array_enc << (num & 0xFF) array_enc << (num >> 8) end end array_enc.pack('C*') end def decode_unile(str) array_enc=str.unpack('C*') array_utf8 = [] 0.step(array_enc.size-1, 2){|i| array_utf8 << (array_enc.at(i) + array_enc.at(i+1)*0x100) } array_utf8.pack('U*') end register(UNILE) do |obj| class << obj alias decode decode_unile alias encode encode_unile end end end end PK|])*rexml/encodings/ICONV.rbnu[require "iconv" raise LoadError unless defined? Iconv module REXML module Encoding def decode_iconv(str) Iconv.conv(UTF_8, @encoding, str) end def encode_iconv(content) Iconv.conv(@encoding, UTF_8, content) end register("ICONV") do |obj| Iconv.conv(UTF_8, obj.encoding, nil) class << obj alias decode decode_iconv alias encode encode_iconv end end end end PK|]F m  rexml/encodings/ISO-8859-15.rbnu[# # This class was contributed by Mikko Tiihonen mikko DOT tiihonen AT hut DOT fi # module REXML module Encoding register("ISO-8859-15") do |o| alias encode to_iso_8859_15 alias decode from_iso_8859_15 end # Convert from UTF-8 def to_iso_8859_15(content) array_utf8 = content.unpack('U*') array_enc = [] array_utf8.each do |num| case num # shortcut first bunch basic characters when 0..0xA3; array_enc << num # characters removed compared to iso-8859-1 when 0xA4; array_enc << '¤' when 0xA6; array_enc << '¦' when 0xA8; array_enc << '¨' when 0xB4; array_enc << '´' when 0xB8; array_enc << '¸' when 0xBC; array_enc << '¼' when 0xBD; array_enc << '½' when 0xBE; array_enc << '¾' # characters added compared to iso-8859-1 when 0x20AC; array_enc << 0xA4 # 0xe2 0x82 0xac when 0x0160; array_enc << 0xA6 # 0xc5 0xa0 when 0x0161; array_enc << 0xA8 # 0xc5 0xa1 when 0x017D; array_enc << 0xB4 # 0xc5 0xbd when 0x017E; array_enc << 0xB8 # 0xc5 0xbe when 0x0152; array_enc << 0xBC # 0xc5 0x92 when 0x0153; array_enc << 0xBD # 0xc5 0x93 when 0x0178; array_enc << 0xBE # 0xc5 0xb8 else # all remaining basic characters can be used directly if num <= 0xFF array_enc << num else # Numeric entity (&#nnnn;); shard by Stefan Scholl array_enc.concat "&\##{num};".unpack('C*') end end end array_enc.pack('C*') end # Convert to UTF-8 def from_iso_8859_15(str) array_latin9 = str.unpack('C*') array_enc = [] array_latin9.each do |num| case num # characters that differ compared to iso-8859-1 when 0xA4; array_enc << 0x20AC when 0xA6; array_enc << 0x0160 when 0xA8; array_enc << 0x0161 when 0xB4; array_enc << 0x017D when 0xB8; array_enc << 0x017E when 0xBC; array_enc << 0x0152 when 0xBD; array_enc << 0x0153 when 0xBE; array_enc << 0x0178 else array_enc << num end end array_enc.pack('U*') end end end PK|]S ŕrexml/parent.rbnu[require "rexml/child" module REXML # A parent has children, and has methods for accessing them. The Parent # class is never encountered except as the superclass for some other # object. class Parent < Child include Enumerable # Constructor # @param parent if supplied, will be set as the parent of this object def initialize parent=nil super(parent) @children = [] end def add( object ) #puts "PARENT GOTS #{size} CHILDREN" object.parent = self @children << object #puts "PARENT NOW GOTS #{size} CHILDREN" object end alias :push :add alias :<< :push def unshift( object ) object.parent = self @children.unshift object end def delete( object ) found = false @children.delete_if {|c| c.equal?(object) and found = true } object.parent = nil if found end def each(&block) @children.each(&block) end def delete_if( &block ) @children.delete_if(&block) end def delete_at( index ) @children.delete_at index end def each_index( &block ) @children.each_index(&block) end # Fetches a child at a given index # @param index the Integer index of the child to fetch def []( index ) @children[index] end alias :each_child :each # Set an index entry. See Array.[]= # @param index the index of the element to set # @param opt either the object to set, or an Integer length # @param child if opt is an Integer, this is the child to set # @return the parent (self) def []=( *args ) args[-1].parent = self @children[*args[0..-2]] = args[-1] end # Inserts an child before another child # @param child1 this is either an xpath or an Element. If an Element, # child2 will be inserted before child1 in the child list of the parent. # If an xpath, child2 will be inserted before the first child to match # the xpath. # @param child2 the child to insert # @return the parent (self) def insert_before( child1, child2 ) if child1.kind_of? String child1 = XPath.first( self, child1 ) child1.parent.insert_before child1, child2 else ind = index(child1) child2.parent.delete(child2) if child2.parent @children[ind,0] = child2 child2.parent = self end self end # Inserts an child after another child # @param child1 this is either an xpath or an Element. If an Element, # child2 will be inserted after child1 in the child list of the parent. # If an xpath, child2 will be inserted after the first child to match # the xpath. # @param child2 the child to insert # @return the parent (self) def insert_after( child1, child2 ) if child1.kind_of? String child1 = XPath.first( self, child1 ) child1.parent.insert_after child1, child2 else ind = index(child1)+1 child2.parent.delete(child2) if child2.parent @children[ind,0] = child2 child2.parent = self end self end def to_a @children.dup end # Fetches the index of a given child # @param child the child to get the index of # @return the index of the child, or nil if the object is not a child # of this parent. def index( child ) count = -1 @children.find { |i| count += 1 ; i.hash == child.hash } count end # @return the number of children of this parent def size @children.size end alias :length :size # Replaces one child with another, making sure the nodelist is correct # @param to_replace the child to replace (must be a Child) # @param replacement the child to insert into the nodelist (must be a # Child) def replace_child( to_replace, replacement ) @children.map! {|c| c.equal?( to_replace ) ? replacement : c } to_replace.parent = nil replacement.parent = self end # Deeply clones this object. This creates a complete duplicate of this # Parent, including all descendants. def deep_clone cl = clone() each do |child| if child.kind_of? Parent cl << child.deep_clone else cl << child.clone end end cl end alias :children :to_a def parent? true end end end PK|]rexml/parsers/sax2parser.rbnu[require 'rexml/parsers/baseparser' require 'rexml/parseexception' require 'rexml/namespace' require 'rexml/text' module REXML module Parsers # SAX2Parser class SAX2Parser def initialize source @parser = BaseParser.new(source) @listeners = [] @procs = [] @namespace_stack = [] @has_listeners = false @tag_stack = [] @entities = {} end def source @parser.source end def add_listener( listener ) @parser.add_listener( listener ) end # Listen arguments: # # Symbol, Array, Block # Listen to Symbol events on Array elements # Symbol, Block # Listen to Symbol events # Array, Listener # Listen to all events on Array elements # Array, Block # Listen to :start_element events on Array elements # Listener # Listen to All events # # Symbol can be one of: :start_element, :end_element, # :start_prefix_mapping, :end_prefix_mapping, :characters, # :processing_instruction, :doctype, :attlistdecl, :elementdecl, # :entitydecl, :notationdecl, :cdata, :xmldecl, :comment # # There is an additional symbol that can be listened for: :progress. # This will be called for every event generated, passing in the current # stream position. # # Array contains regular expressions or strings which will be matched # against fully qualified element names. # # Listener must implement the methods in SAX2Listener # # Block will be passed the same arguments as a SAX2Listener method would # be, where the method name is the same as the matched Symbol. # See the SAX2Listener for more information. def listen( *args, &blok ) if args[0].kind_of? Symbol if args.size == 2 args[1].each { |match| @procs << [args[0], match, blok] } else add( [args[0], nil, blok] ) end elsif args[0].kind_of? Array if args.size == 2 args[0].each { |match| add( [nil, match, args[1]] ) } else args[0].each { |match| add( [ :start_element, match, blok ] ) } end else add([nil, nil, args[0]]) end end def deafen( listener=nil, &blok ) if listener @listeners.delete_if {|item| item[-1] == listener } @has_listeners = false if @listeners.size == 0 else @procs.delete_if {|item| item[-1] == blok } end end def parse @procs.each { |sym,match,block| block.call if sym == :start_document } @listeners.each { |sym,match,block| block.start_document if sym == :start_document or sym.nil? } root = context = [] while true event = @parser.pull case event[0] when :end_document handle( :end_document ) break when :start_doctype handle( :doctype, *event[1..-1]) when :end_doctype context = context[1] when :start_element @tag_stack.push(event[1]) # find the observers for namespaces procs = get_procs( :start_prefix_mapping, event[1] ) listeners = get_listeners( :start_prefix_mapping, event[1] ) if procs or listeners # break out the namespace declarations # The attributes live in event[2] event[2].each {|n, v| event[2][n] = @parser.normalize(v)} nsdecl = event[2].find_all { |n, value| n =~ /^xmlns(:|$)/ } nsdecl.collect! { |n, value| [ n[6..-1], value ] } @namespace_stack.push({}) nsdecl.each do |n,v| @namespace_stack[-1][n] = v # notify observers of namespaces procs.each { |ob| ob.call( n, v ) } if procs listeners.each { |ob| ob.start_prefix_mapping(n, v) } if listeners end end event[1] =~ Namespace::NAMESPLIT prefix = $1 local = $2 uri = get_namespace(prefix) # find the observers for start_element procs = get_procs( :start_element, event[1] ) listeners = get_listeners( :start_element, event[1] ) # notify observers procs.each { |ob| ob.call( uri, local, event[1], event[2] ) } if procs listeners.each { |ob| ob.start_element( uri, local, event[1], event[2] ) } if listeners when :end_element @tag_stack.pop event[1] =~ Namespace::NAMESPLIT prefix = $1 local = $2 uri = get_namespace(prefix) # find the observers for start_element procs = get_procs( :end_element, event[1] ) listeners = get_listeners( :end_element, event[1] ) # notify observers procs.each { |ob| ob.call( uri, local, event[1] ) } if procs listeners.each { |ob| ob.end_element( uri, local, event[1] ) } if listeners namespace_mapping = @namespace_stack.pop # find the observers for namespaces procs = get_procs( :end_prefix_mapping, event[1] ) listeners = get_listeners( :end_prefix_mapping, event[1] ) if procs or listeners namespace_mapping.each do |prefix, uri| # notify observers of namespaces procs.each { |ob| ob.call( prefix ) } if procs listeners.each { |ob| ob.end_prefix_mapping(prefix) } if listeners end end when :text #normalized = @parser.normalize( event[1] ) #handle( :characters, normalized ) copy = event[1].clone @entities.each { |key, value| copy = copy.gsub("&#{key};", value) } copy.gsub!( Text::NUMERICENTITY ) {|m| m=$1 m = "0#{m}" if m[0] == ?x [Integer(m)].pack('U*') } handle( :characters, copy ) when :entitydecl @entities[ event[1] ] = event[2] if event.size == 3 handle( *event ) when :processing_instruction, :comment, :attlistdecl, :elementdecl, :cdata, :notationdecl, :xmldecl handle( *event ) end handle( :progress, @parser.position ) end end private def handle( symbol, *arguments ) tag = @tag_stack[-1] procs = get_procs( symbol, tag ) listeners = get_listeners( symbol, tag ) # notify observers procs.each { |ob| ob.call( *arguments ) } if procs listeners.each { |l| l.send( symbol.to_s, *arguments ) } if listeners end # The following methods are duplicates, but it is faster than using # a helper def get_procs( symbol, name ) return nil if @procs.size == 0 @procs.find_all do |sym, match, block| #puts sym.inspect+"=="+symbol.inspect+ "\t"+match.inspect+"=="+name.inspect+ "\t"+( (sym.nil? or symbol == sym) and ((name.nil? and match.nil?) or match.nil? or ( (name == match) or (match.kind_of? Regexp and name =~ match)))).to_s ( (sym.nil? or symbol == sym) and ((name.nil? and match.nil?) or match.nil? or ( (name == match) or (match.kind_of? Regexp and name =~ match) ) ) ) end.collect{|x| x[-1]} end def get_listeners( symbol, name ) return nil if @listeners.size == 0 @listeners.find_all do |sym, match, block| ( (sym.nil? or symbol == sym) and ((name.nil? and match.nil?) or match.nil? or ( (name == match) or (match.kind_of? Regexp and name =~ match) ) ) ) end.collect{|x| x[-1]} end def add( pair ) if pair[-1].respond_to? :call @procs << pair unless @procs.include? pair else @listeners << pair unless @listeners.include? pair @has_listeners = true end end def get_namespace( prefix ) uris = (@namespace_stack.find_all { |ns| not ns[prefix].nil? }) || (@namespace_stack.find { |ns| not ns[nil].nil? }) uris[-1][prefix] unless uris.nil? or 0 == uris.size end end end end PK|]UHJJrexml/parsers/baseparser.rbnu[require 'rexml/parseexception' require 'rexml/undefinednamespaceexception' require 'rexml/source' require 'set' module REXML module Parsers # = Using the Pull Parser # This API is experimental, and subject to change. # parser = PullParser.new( "texttxet" ) # while parser.has_next? # res = parser.next # puts res[1]['att'] if res.start_tag? and res[0] == 'b' # end # See the PullEvent class for information on the content of the results. # The data is identical to the arguments passed for the various events to # the StreamListener API. # # Notice that: # parser = PullParser.new( "BAD DOCUMENT" ) # while parser.has_next? # res = parser.next # raise res[1] if res.error? # end # # Nat Price gave me some good ideas for the API. class BaseParser NCNAME_STR= '[\w:][\-\w\d.]*' NAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})" UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}" NAMECHAR = '[\-\w\d\.:]' NAME = "([\\w:]#{NAMECHAR}*)" NMTOKEN = "(?:#{NAMECHAR})+" NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*" REFERENCE = "(?:&#{NAME};|&#\\d+;|&#x[0-9a-fA-F]+;)" REFERENCE_RE = /#{REFERENCE}/ DOCTYPE_START = /\A\s*)/um ATTRIBUTE_PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\4/um COMMENT_START = /\A/um CDATA_START = /\A/um CDATA_PATTERN = //um XMLDECL_START = /\A<\?xml\s/u; XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um INSTRUCTION_START = /\A<\?/u INSTRUCTION_PATTERN = /<\?(.*?)(\s+.*?)?\?>/um TAG_MATCH = /^<((?>#{NAME_STR}))\s*((?>\s+#{UNAME_STR}\s*=\s*(["']).*?\5)*)\s*(\/)?>/um CLOSE_MATCH = /^\s*<\/(#{NAME_STR})\s*>/um VERSION = /\bversion\s*=\s*["'](.*?)['"]/um ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um STANDALONE = /\bstandalone\s*=\s["'](.*?)['"]/um ENTITY_START = /^\s*/um SYSTEMENTITY = /^\s*(%.*?;)\s*$/um ENUMERATION = "\\(\\s*#{NMTOKEN}(?:\\s*\\|\\s*#{NMTOKEN})*\\s*\\)" NOTATIONTYPE = "NOTATION\\s+\\(\\s*#{NAME}(?:\\s*\\|\\s*#{NAME})*\\s*\\)" ENUMERATEDTYPE = "(?:(?:#{NOTATIONTYPE})|(?:#{ENUMERATION}))" ATTTYPE = "(CDATA|ID|IDREF|IDREFS|ENTITY|ENTITIES|NMTOKEN|NMTOKENS|#{ENUMERATEDTYPE})" ATTVALUE = "(?:\"((?:[^<&\"]|#{REFERENCE})*)\")|(?:'((?:[^<&']|#{REFERENCE})*)')" DEFAULTDECL = "(#REQUIRED|#IMPLIED|(?:(#FIXED\\s+)?#{ATTVALUE}))" ATTDEF = "\\s+#{NAME}\\s+#{ATTTYPE}\\s+#{DEFAULTDECL}" ATTDEF_RE = /#{ATTDEF}/ ATTLISTDECL_START = /^\s*/um NOTATIONDECL_START = /^\s*/um SYSTEM = /^\s*/um TEXT_PATTERN = /\A([^<]*)/um # Entity constants PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#" SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))} PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')} EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))" NDATADECL = "\\s+NDATA\\s+#{NAME}" PEREFERENCE = "%#{NAME};" ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))} PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})" ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))" PEDECL = "" GEDECL = "" ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um EREFERENCE = /&(?!#{NAME};)/ DEFAULT_ENTITIES = { 'gt' => [/>/, '>', '>', />/], 'lt' => [/</, '<', '<', / [/"/, '"', '"', /"/], "apos" => [/'/, "'", "'", /'/] } ###################################################################### # These are patterns to identify common markup errors, to make the # error messages more informative. ###################################################################### MISSING_ATTRIBUTE_QUOTES = /^<#{NAME_STR}\s+#{NAME_STR}\s*=\s*[^"']/um def initialize( source ) self.stream = source end def add_listener( listener ) if !defined?(@listeners) or !@listeners @listeners = [] instance_eval <<-EOL alias :_old_pull :pull def pull event = _old_pull @listeners.each do |listener| listener.receive event end event end EOL end @listeners << listener end attr_reader :source def stream=( source ) @source = SourceFactory.create_from( source ) @closed = nil @document_status = nil @tags = [] @stack = [] @entities = [] @nsstack = [] end def position if @source.respond_to? :position @source.position else # FIXME 0 end end # Returns true if there are no more events def empty? return (@source.empty? and @stack.empty?) end # Returns true if there are more events. Synonymous with !empty? def has_next? return !(@source.empty? and @stack.empty?) end # Push an event back on the head of the stream. This method # has (theoretically) infinite depth. def unshift token @stack.unshift(token) end # Peek at the +depth+ event in the stack. The first element on the stack # is at depth 0. If +depth+ is -1, will parse to the end of the input # stream and return the last event, which is always :end_document. # Be aware that this causes the stream to be parsed up to the +depth+ # event, so you can effectively pre-parse the entire document (pull the # entire thing into memory) using this method. def peek depth=0 raise %Q[Illegal argument "#{depth}"] if depth < -1 temp = [] if depth == -1 temp.push(pull()) until empty? else while @stack.size+temp.size < depth+1 temp.push(pull()) end end @stack += temp if temp.size > 0 @stack[depth] end # Returns the next event. This is a +PullEvent+ object. def pull if @closed x, @closed = @closed, nil return [ :end_element, x ] end return [ :end_document ] if empty? return @stack.shift if @stack.size > 0 #STDERR.puts @source.encoding @source.read if @source.buffer.size<2 #STDERR.puts "BUFFER = #{@source.buffer.inspect}" if @document_status == nil #@source.consume( /^\s*/um ) word = @source.match( /^((?:\s+)|(?:<[^>]*>))/um ) word = word[1] unless word.nil? #STDERR.puts "WORD = #{word.inspect}" case word when COMMENT_START return [ :comment, @source.match( COMMENT_PATTERN, true )[1] ] when XMLDECL_START #STDERR.puts "XMLDECL" results = @source.match( XMLDECL_PATTERN, true )[1] version = VERSION.match( results ) version = version[1] unless version.nil? encoding = ENCODING.match(results) encoding = encoding[1] unless encoding.nil? @source.encoding = encoding standalone = STANDALONE.match(results) standalone = standalone[1] unless standalone.nil? return [ :xmldecl, version, encoding, standalone ] when INSTRUCTION_START return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ] when DOCTYPE_START md = @source.match( DOCTYPE_PATTERN, true ) @nsstack.unshift(curr_ns=Set.new) identity = md[1] close = md[2] identity =~ IDENTITY name = $1 raise REXML::ParseException.new("DOCTYPE is missing a name") if name.nil? pub_sys = $2.nil? ? nil : $2.strip long_name = $4.nil? ? nil : $4.strip uri = $6.nil? ? nil : $6.strip args = [ :start_doctype, name, pub_sys, long_name, uri ] if close == ">" @document_status = :after_doctype @source.read if @source.buffer.size<2 md = @source.match(/^\s*/um, true) @stack << [ :end_doctype ] else @document_status = :in_doctype end return args when /^\s+/ else @document_status = :after_doctype @source.read if @source.buffer.size<2 md = @source.match(/\s*/um, true) end end if @document_status == :in_doctype md = @source.match(/\s*(.*?>)/um) case md[1] when SYSTEMENTITY match = @source.match( SYSTEMENTITY, true )[1] return [ :externalentity, match ] when ELEMENTDECL_START return [ :elementdecl, @source.match( ELEMENTDECL_PATTERN, true )[1] ] when ENTITY_START match = @source.match( ENTITYDECL, true ).to_a.compact match[0] = :entitydecl ref = false if match[1] == '%' ref = true match.delete_at 1 end # Now we have to sort out what kind of entity reference this is if match[2] == 'SYSTEM' # External reference match[3] = match[3][1..-2] # PUBID match.delete_at(4) if match.size > 4 # Chop out NDATA decl # match is [ :entity, name, SYSTEM, pubid(, ndata)? ] elsif match[2] == 'PUBLIC' # External reference match[3] = match[3][1..-2] # PUBID match[4] = match[4][1..-2] # HREF # match is [ :entity, name, PUBLIC, pubid, href ] else match[2] = match[2][1..-2] match.pop if match.size == 4 # match is [ :entity, name, value ] end match << '%' if ref return match when ATTLISTDECL_START md = @source.match( ATTLISTDECL_PATTERN, true ) raise REXML::ParseException.new( "Bad ATTLIST declaration!", @source ) if md.nil? element = md[1] contents = md[0] pairs = {} values = md[0].scan( ATTDEF_RE ) values.each do |attdef| unless attdef[3] == "#IMPLIED" attdef.compact! val = attdef[3] val = attdef[4] if val == "#FIXED " pairs[attdef[0]] = val if attdef[0] =~ /^xmlns:(.*)/ @nsstack[0] << $1 end end end return [ :attlistdecl, element, pairs, contents ] when NOTATIONDECL_START md = nil if @source.match( PUBLIC ) md = @source.match( PUBLIC, true ) vals = [md[1],md[2],md[4],md[6]] elsif @source.match( SYSTEM ) md = @source.match( SYSTEM, true ) vals = [md[1],md[2],nil,md[4]] else raise REXML::ParseException.new( "error parsing notation: no matching pattern", @source ) end return [ :notationdecl, *vals ] when CDATA_END @document_status = :after_doctype @source.match( CDATA_END, true ) return [ :end_doctype ] end end begin if @source.buffer[0] == ?< if @source.buffer[1] == ?/ @nsstack.shift last_tag = @tags.pop #md = @source.match_to_consume( '>', CLOSE_MATCH) md = @source.match( CLOSE_MATCH, true ) raise REXML::ParseException.new( "Missing end tag for "+ "'#{last_tag}' (got \"#{md[1]}\")", @source) unless last_tag == md[1] return [ :end_element, last_tag ] elsif @source.buffer[1] == ?! md = @source.match(/\A(\s*[^>]*>)/um) #STDERR.puts "SOURCE BUFFER = #{source.buffer}, #{source.buffer.size}" raise REXML::ParseException.new("Malformed node", @source) unless md if md[0][2] == ?- md = @source.match( COMMENT_PATTERN, true ) return [ :comment, md[1] ] if md else md = @source.match( CDATA_PATTERN, true ) return [ :cdata, md[1] ] if md end raise REXML::ParseException.new( "Declarations can only occur "+ "in the doctype declaration.", @source) elsif @source.buffer[1] == ?? md = @source.match( INSTRUCTION_PATTERN, true ) return [ :processing_instruction, md[1], md[2] ] if md raise REXML::ParseException.new( "Bad instruction declaration", @source) else # Get the next tag md = @source.match(TAG_MATCH, true) unless md # Check for missing attribute quotes raise REXML::ParseException.new("missing attribute quote", @source) if @source.match(MISSING_ATTRIBUTE_QUOTES ) raise REXML::ParseException.new("malformed XML: missing tag start", @source) end attributes = {} prefixes = Set.new prefixes << md[2] if md[2] @nsstack.unshift(curr_ns=Set.new) if md[4].size > 0 attrs = md[4].scan( ATTRIBUTE_PATTERN ) raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0 attrs.each { |a,b,c,d,e| if b == "xmlns" if c == "xml" if d != "http://www.w3.org/XML/1998/namespace" msg = "The 'xml' prefix must not be bound to any other namespace "+ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" raise REXML::ParseException.new( msg, @source, self ) end elsif c == "xmlns" msg = "The 'xmlns' prefix must not be declared "+ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" raise REXML::ParseException.new( msg, @source, self) end curr_ns << c elsif b prefixes << b unless b == "xml" end attributes[a] = e } end # Verify that all of the prefixes have been defined for prefix in prefixes unless @nsstack.find{|k| k.member?(prefix)} raise UndefinedNamespaceException.new(prefix,@source,self) end end if md[6] @closed = md[1] @nsstack.shift else @tags.push( md[1] ) end return [ :start_element, md[1], attributes ] end else md = @source.match( TEXT_PATTERN, true ) if md[0].length == 0 @source.match( /(\s+)/, true ) end #STDERR.puts "GOT #{md[1].inspect}" unless md[0].length == 0 #return [ :text, "" ] if md[0].length == 0 # unnormalized = Text::unnormalize( md[1], self ) # return PullEvent.new( :text, md[1], unnormalized ) return [ :text, md[1] ] end rescue REXML::UndefinedNamespaceException raise rescue REXML::ParseException raise rescue Exception, NameError => error raise REXML::ParseException.new( "Exception parsing", @source, self, (error ? error : $!) ) end return [ :dummy ] end def entity( reference, entities ) value = nil value = entities[ reference ] if entities if not value value = DEFAULT_ENTITIES[ reference ] value = value[2] if value end unnormalize( value, entities ) if value end # Escapes all possible entities def normalize( input, entities=nil, entity_filter=nil ) copy = input.clone # Doing it like this rather than in a loop improves the speed copy.gsub!( EREFERENCE, '&' ) entities.each do |key, value| copy.gsub!( value, "&#{key};" ) unless entity_filter and entity_filter.include?(entity) end if entities copy.gsub!( EREFERENCE, '&' ) DEFAULT_ENTITIES.each do |key, value| copy.gsub!( value[3], value[1] ) end copy end # Unescapes all possible entities def unnormalize( string, entities=nil, filter=nil ) rv = string.clone rv.gsub!( /\r\n?/, "\n" ) matches = rv.scan( REFERENCE_RE ) return rv if matches.size == 0 rv.gsub!( /�*((?:\d+)|(?:x[a-fA-F0-9]+));/ ) {|m| m=$1 m = "0#{m}" if m[0] == ?x [Integer(m)].pack('U*') } matches.collect!{|x|x[0]}.compact! if matches.size > 0 matches.each do |entity_reference| unless filter and filter.include?(entity_reference) entity_value = entity( entity_reference, entities ) if entity_value re = /&#{entity_reference};/ rv.gsub!( re, entity_value ) end end end matches.each do |entity_reference| unless filter and filter.include?(entity_reference) er = DEFAULT_ENTITIES[entity_reference] rv.gsub!( er[0], er[2] ) if er end end rv.gsub!( /&/, '&' ) end rv end end end end =begin case event[0] when :start_element when :text when :end_element when :processing_instruction when :cdata when :comment when :xmldecl when :start_doctype when :end_doctype when :externalentity when :elementdecl when :entity when :attlistdecl when :notationdecl when :end_doctype end =end PK|]O"ggrexml/parsers/lightparser.rbnu[require 'rexml/parsers/streamparser' require 'rexml/parsers/baseparser' require 'rexml/light/node' module REXML module Parsers class LightParser def initialize stream @stream = stream @parser = REXML::Parsers::BaseParser.new( stream ) end def add_listener( listener ) @parser.add_listener( listener ) end def rewind @stream.rewind @parser.stream = @stream end def parse root = context = [ :document ] while true event = @parser.pull case event[0] when :end_document break when :end_doctype context = context[1] when :start_element, :start_doctype new_node = event context << new_node new_node[1,0] = [context] context = new_node when :end_element, :end_doctype context = context[1] else new_node = event context << new_node new_node[1,0] = [context] end end root end end # An element is an array. The array contains: # 0 The parent element # 1 The tag name # 2 A hash of attributes # 3..-1 The child elements # An element is an array of size > 3 # Text is a String # PIs are [ :processing_instruction, target, data ] # Comments are [ :comment, data ] # DocTypes are DocType structs # The root is an array with XMLDecls, Text, DocType, Array, Text end end PK|]^=rexml/parsers/streamparser.rbnu[module REXML module Parsers class StreamParser def initialize source, listener @listener = listener @parser = BaseParser.new( source ) end def add_listener( listener ) @parser.add_listener( listener ) end def parse # entity string while true event = @parser.pull case event[0] when :end_document return when :start_element attrs = event[2].each do |n, v| event[2][n] = @parser.unnormalize( v ) end @listener.tag_start( event[1], attrs ) when :end_element @listener.tag_end( event[1] ) when :text normalized = @parser.unnormalize( event[1] ) @listener.text( normalized ) when :processing_instruction @listener.instruction( *event[1,2] ) when :start_doctype @listener.doctype( *event[1..-1] ) when :end_doctype # FIXME: remove this condition for milestone:3.2 @listener.doctype_end if @listener.respond_to? :doctype_end when :comment, :attlistdecl, :cdata, :xmldecl, :elementdecl @listener.send( event[0].to_s, *event[1..-1] ) when :entitydecl, :notationdecl @listener.send( event[0].to_s, event[1..-1] ) end end end end end end PK|]廋z z rexml/parsers/treeparser.rbnu[require 'rexml/validation/validationexception' require 'rexml/undefinednamespaceexception' module REXML module Parsers class TreeParser def initialize( source, build_context = Document.new ) @build_context = build_context @parser = Parsers::BaseParser.new( source ) end def add_listener( listener ) @parser.add_listener( listener ) end def parse tag_stack = [] in_doctype = false entities = nil begin while true event = @parser.pull #STDERR.puts "TREEPARSER GOT #{event.inspect}" case event[0] when :end_document unless tag_stack.empty? #raise ParseException.new("No close tag for #{tag_stack.inspect}") raise ParseException.new("No close tag for #{@build_context.xpath}") end return when :start_element tag_stack.push(event[1]) el = @build_context = @build_context.add_element( event[1], event[2] ) when :end_element tag_stack.pop @build_context = @build_context.parent when :text if not in_doctype if @build_context[-1].instance_of? Text @build_context[-1] << event[1] else @build_context.add( Text.new(event[1], @build_context.whitespace, nil, true) ) unless ( @build_context.ignore_whitespace_nodes and event[1].strip.size==0 ) end end when :comment c = Comment.new( event[1] ) @build_context.add( c ) when :cdata c = CData.new( event[1] ) @build_context.add( c ) when :processing_instruction @build_context.add( Instruction.new( event[1], event[2] ) ) when :end_doctype in_doctype = false entities.each { |k,v| entities[k] = @build_context.entities[k].value } @build_context = @build_context.parent when :start_doctype doctype = DocType.new( event[1..-1], @build_context ) @build_context = doctype entities = {} in_doctype = true when :attlistdecl n = AttlistDecl.new( event[1..-1] ) @build_context.add( n ) when :externalentity n = ExternalEntity.new( event[1] ) @build_context.add( n ) when :elementdecl n = ElementDecl.new( event[1] ) @build_context.add(n) when :entitydecl entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/ @build_context.add(Entity.new(event)) when :notationdecl n = NotationDecl.new( *event[1..-1] ) @build_context.add( n ) when :xmldecl x = XMLDecl.new( event[1], event[2], event[3] ) @build_context.add( x ) end end rescue REXML::Validation::ValidationException raise rescue REXML::UndefinedNamespaceException raise rescue raise ParseException.new( $!.message, @parser.source, @parser, $! ) end end end end end PK|]@H!rexml/parsers/ultralightparser.rbnu[require 'rexml/parsers/streamparser' require 'rexml/parsers/baseparser' module REXML module Parsers class UltraLightParser def initialize stream @stream = stream @parser = REXML::Parsers::BaseParser.new( stream ) end def add_listener( listener ) @parser.add_listener( listener ) end def rewind @stream.rewind @parser.stream = @stream end def parse root = context = [] while true event = @parser.pull case event[0] when :end_document break when :end_doctype context = context[1] when :start_element, :doctype context << event event[1,0] = [context] context = event when :end_element context = context[1] else context << event end end root end end # An element is an array. The array contains: # 0 The parent element # 1 The tag name # 2 A hash of attributes # 3..-1 The child elements # An element is an array of size > 3 # Text is a String # PIs are [ :processing_instruction, target, data ] # Comments are [ :comment, data ] # DocTypes are DocType structs # The root is an array with XMLDecls, Text, DocType, Array, Text end end PK|]LLrexml/parsers/xpathparser.rbnu[require 'rexml/namespace' require 'rexml/xmltokens' module REXML module Parsers # You don't want to use this class. Really. Use XPath, which is a wrapper # for this class. Believe me. You don't want to poke around in here. # There is strange, dark magic at work in this code. Beware. Go back! Go # back while you still can! class XPathParser include XMLTokens LITERAL = /^'([^']*)'|^"([^"]*)"/u def namespaces=( namespaces ) Functions::namespace_context = namespaces @namespaces = namespaces end def parse path path.gsub!(/([\(\[])\s+/, '\1') # Strip ignorable spaces path.gsub!( /\s+([\]\)])/, '\1' ) parsed = [] path = OrExpr(path, parsed) parsed end def predicate path parsed = [] Predicate( "[#{path}]", parsed ) parsed end def abbreviate( path ) path = path.kind_of?(String) ? parse( path ) : path string = "" document = false while path.size > 0 op = path.shift case op when :node when :attribute string << "/" if string.size > 0 string << "@" when :child string << "/" if string.size > 0 when :descendant_or_self string << "/" when :self string << "." when :parent string << ".." when :any string << "*" when :text string << "text()" when :following, :following_sibling, :ancestor, :ancestor_or_self, :descendant, :namespace, :preceding, :preceding_sibling string << "/" unless string.size == 0 string << op.to_s.tr("_", "-") string << "::" when :qname prefix = path.shift name = path.shift string << prefix+":" if prefix.size > 0 string << name when :predicate string << '[' string << predicate_to_string( path.shift ) {|x| abbreviate( x ) } string << ']' when :document document = true when :function string << path.shift string << "( " string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )} string << " )" when :literal string << %Q{ "#{path.shift}" } else string << "/" unless string.size == 0 string << "UNKNOWN(" string << op.inspect string << ")" end end string = "/"+string if document return string end def expand( path ) path = path.kind_of?(String) ? parse( path ) : path string = "" document = false while path.size > 0 op = path.shift case op when :node string << "node()" when :attribute, :child, :following, :following_sibling, :ancestor, :ancestor_or_self, :descendant, :descendant_or_self, :namespace, :preceding, :preceding_sibling, :self, :parent string << "/" unless string.size == 0 string << op.to_s.tr("_", "-") string << "::" when :any string << "*" when :qname prefix = path.shift name = path.shift string << prefix+":" if prefix.size > 0 string << name when :predicate string << '[' string << predicate_to_string( path.shift ) { |x| expand(x) } string << ']' when :document document = true else string << "/" unless string.size == 0 string << "UNKNOWN(" string << op.inspect string << ")" end end string = "/"+string if document return string end def predicate_to_string( path, &block ) string = "" case path[0] when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union op = path.shift case op when :eq op = "=" when :lt op = "<" when :gt op = ">" when :lteq op = "<=" when :gteq op = ">=" when :neq op = "!=" when :union op = "|" end left = predicate_to_string( path.shift, &block ) right = predicate_to_string( path.shift, &block ) string << " " string << left string << " " string << op.to_s string << " " string << right string << " " when :function path.shift name = path.shift string << name string << "( " string << predicate_to_string( path.shift, &block ) string << " )" when :literal path.shift string << " " string << path.shift.inspect string << " " else string << " " string << yield( path ) string << " " end return string.squeeze(" ") end private #LocationPath # | RelativeLocationPath # | '/' RelativeLocationPath? # | '//' RelativeLocationPath def LocationPath path, parsed #puts "LocationPath '#{path}'" path = path.strip if path[0] == ?/ parsed << :document if path[1] == ?/ parsed << :descendant_or_self parsed << :node path = path[2..-1] else path = path[1..-1] end end #puts parsed.inspect return RelativeLocationPath( path, parsed ) if path.size > 0 end #RelativeLocationPath # | Step # | (AXIS_NAME '::' | '@' | '') AxisSpecifier # NodeTest # Predicate # | '.' | '..' AbbreviatedStep # | RelativeLocationPath '/' Step # | RelativeLocationPath '//' Step AXIS = /^(ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|namespace|parent|preceding|preceding-sibling|self)::/ def RelativeLocationPath path, parsed #puts "RelativeLocationPath #{path}" while path.size > 0 # (axis or @ or ) nodetest predicate > # OR > / Step # (. or ..) > if path[0] == ?. if path[1] == ?. parsed << :parent parsed << :node path = path[2..-1] else parsed << :self parsed << :node path = path[1..-1] end else if path[0] == ?@ #puts "ATTRIBUTE" parsed << :attribute path = path[1..-1] # Goto Nodetest elsif path =~ AXIS parsed << $1.tr('-','_').intern path = $' # Goto Nodetest else parsed << :child end #puts "NODETESTING '#{path}'" n = [] path = NodeTest( path, n) #puts "NODETEST RETURNED '#{path}'" if path[0] == ?[ path = Predicate( path, n ) end parsed.concat(n) end if path.size > 0 if path[0] == ?/ if path[1] == ?/ parsed << :descendant_or_self parsed << :node path = path[2..-1] else path = path[1..-1] end else return path end end end return path end # Returns a 1-1 map of the nodeset # The contents of the resulting array are either: # true/false, if a positive match # String, if a name match #NodeTest # | ('*' | NCNAME ':' '*' | QNAME) NameTest # | NODE_TYPE '(' ')' NodeType # | PI '(' LITERAL ')' PI # | '[' expr ']' Predicate NCNAMETEST= /^(#{NCNAME_STR}):\*/u QNAME = Namespace::NAMESPLIT NODE_TYPE = /^(comment|text|node)\(\s*\)/m PI = /^processing-instruction\(/ def NodeTest path, parsed #puts "NodeTest with #{path}" res = nil case path when /^\*/ path = $' parsed << :any when NODE_TYPE type = $1 path = $' parsed << type.tr('-', '_').intern when PI path = $' literal = nil if path !~ /^\s*\)/ path =~ LITERAL literal = $1 path = $' raise ParseException.new("Missing ')' after processing instruction") if path[0] != ?) path = path[1..-1] end parsed << :processing_instruction parsed << (literal || '') when NCNAMETEST #puts "NCNAMETEST" prefix = $1 path = $' parsed << :namespace parsed << prefix when QNAME #puts "QNAME" prefix = $1 name = $2 path = $' prefix = "" unless prefix parsed << :qname parsed << prefix parsed << name end return path end # Filters the supplied nodeset on the predicate(s) def Predicate path, parsed #puts "PREDICATE with #{path}" return nil unless path[0] == ?[ predicates = [] while path[0] == ?[ path, expr = get_group(path) predicates << expr[1..-2] if expr end #puts "PREDICATES = #{predicates.inspect}" predicates.each{ |expr| #puts "ORING #{expr}" preds = [] parsed << :predicate parsed << preds OrExpr(expr, preds) } #puts "PREDICATES = #{predicates.inspect}" path end # The following return arrays of true/false, a 1-1 mapping of the # supplied nodeset, except for axe(), which returns a filtered # nodeset #| OrExpr S 'or' S AndExpr #| AndExpr def OrExpr path, parsed #puts "OR >>> #{path}" n = [] rest = AndExpr( path, n ) #puts "OR <<< #{rest}" if rest != path while rest =~ /^\s*( or )/ n = [ :or, n, [] ] rest = AndExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| AndExpr S 'and' S EqualityExpr #| EqualityExpr def AndExpr path, parsed #puts "AND >>> #{path}" n = [] rest = EqualityExpr( path, n ) #puts "AND <<< #{rest}" if rest != path while rest =~ /^\s*( and )/ n = [ :and, n, [] ] #puts "AND >>> #{rest}" rest = EqualityExpr( $', n[-1] ) #puts "AND <<< #{rest}" end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| EqualityExpr ('=' | '!=') RelationalExpr #| RelationalExpr def EqualityExpr path, parsed #puts "EQUALITY >>> #{path}" n = [] rest = RelationalExpr( path, n ) #puts "EQUALITY <<< #{rest}" if rest != path while rest =~ /^\s*(!?=)\s*/ if $1[0] == ?! n = [ :neq, n, [] ] else n = [ :eq, n, [] ] end rest = RelationalExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| RelationalExpr ('<' | '>' | '<=' | '>=') AdditiveExpr #| AdditiveExpr def RelationalExpr path, parsed #puts "RELATION >>> #{path}" n = [] rest = AdditiveExpr( path, n ) #puts "RELATION <<< #{rest}" if rest != path while rest =~ /^\s*([<>]=?)\s*/ if $1[0] == ?< sym = "lt" else sym = "gt" end sym << "eq" if $1[-1] == ?= n = [ sym.intern, n, [] ] rest = AdditiveExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| AdditiveExpr ('+' | S '-') MultiplicativeExpr #| MultiplicativeExpr def AdditiveExpr path, parsed #puts "ADDITIVE >>> #{path}" n = [] rest = MultiplicativeExpr( path, n ) #puts "ADDITIVE <<< #{rest}" if rest != path while rest =~ /^\s*(\+| -)\s*/ if $1[0] == ?+ n = [ :plus, n, [] ] else n = [ :minus, n, [] ] end rest = MultiplicativeExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| MultiplicativeExpr ('*' | S ('div' | 'mod') S) UnaryExpr #| UnaryExpr def MultiplicativeExpr path, parsed #puts "MULT >>> #{path}" n = [] rest = UnaryExpr( path, n ) #puts "MULT <<< #{rest}" if rest != path while rest =~ /^\s*(\*| div | mod )\s*/ if $1[0] == ?* n = [ :mult, n, [] ] elsif $1.include?( "div" ) n = [ :div, n, [] ] else n = [ :mod, n, [] ] end rest = UnaryExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace(n) elsif n.size > 0 parsed << n end rest end #| '-' UnaryExpr #| UnionExpr def UnaryExpr path, parsed path =~ /^(\-*)/ path = $' if $1 and (($1.size % 2) != 0) mult = -1 else mult = 1 end parsed << :neg if mult < 0 #puts "UNARY >>> #{path}" n = [] path = UnionExpr( path, n ) #puts "UNARY <<< #{path}" parsed.concat( n ) path end #| UnionExpr '|' PathExpr #| PathExpr def UnionExpr path, parsed #puts "UNION >>> #{path}" n = [] rest = PathExpr( path, n ) #puts "UNION <<< #{rest}" if rest != path while rest =~ /^\s*(\|)\s*/ n = [ :union, n, [] ] rest = PathExpr( $', n[-1] ) end end if parsed.size == 0 and n.size != 0 parsed.replace( n ) elsif n.size > 0 parsed << n end rest end #| LocationPath #| FilterExpr ('/' | '//') RelativeLocationPath def PathExpr path, parsed path =~ /^\s*/ path = $' #puts "PATH >>> #{path}" n = [] rest = FilterExpr( path, n ) #puts "PATH <<< '#{rest}'" if rest != path if rest and rest[0] == ?/ return RelativeLocationPath(rest, n) end end #puts "BEFORE WITH '#{rest}'" rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w_*]/ parsed.concat(n) return rest end #| FilterExpr Predicate #| PrimaryExpr def FilterExpr path, parsed #puts "FILTER >>> #{path}" n = [] path = PrimaryExpr( path, n ) #puts "FILTER <<< #{path}" path = Predicate(path, n) if path and path[0] == ?[ #puts "FILTER <<< #{path}" parsed.concat(n) path end #| VARIABLE_REFERENCE #| '(' expr ')' #| LITERAL #| NUMBER #| FunctionCall VARIABLE_REFERENCE = /^\$(#{NAME_STR})/u NUMBER = /^(\d*\.?\d+)/ NT = /^comment|text|processing-instruction|node$/ def PrimaryExpr path, parsed arry = [] case path when VARIABLE_REFERENCE varname = $1 path = $' parsed << :variable parsed << varname #arry << @variables[ varname ] when /^(\w[-\w]*)(?:\()/ #puts "PrimaryExpr :: Function >>> #$1 -- '#$''" fname = $1 tmp = $' #puts "#{fname} =~ #{NT.inspect}" return path if fname =~ NT path = tmp parsed << :function parsed << fname path = FunctionCall(path, parsed) when NUMBER #puts "LITERAL or NUMBER: #$1" varname = $1.nil? ? $2 : $1 path = $' parsed << :literal parsed << (varname.include?('.') ? varname.to_f : varname.to_i) when LITERAL #puts "LITERAL or NUMBER: #$1" varname = $1.nil? ? $2 : $1 path = $' parsed << :literal parsed << varname when /^\(/ #/ path, contents = get_group(path) contents = contents[1..-2] n = [] OrExpr( contents, n ) parsed.concat(n) end path end #| FUNCTION_NAME '(' ( expr ( ',' expr )* )? ')' def FunctionCall rest, parsed path, arguments = parse_args(rest) argset = [] for argument in arguments args = [] OrExpr( argument, args ) argset << args end parsed << argset path end # get_group( '[foo]bar' ) -> ['bar', '[foo]'] def get_group string ind = 0 depth = 0 st = string[0,1] en = (st == "(" ? ")" : "]") begin case string[ind,1] when st depth += 1 when en depth -= 1 end ind += 1 end while depth > 0 and ind < string.length return nil unless depth==0 [string[ind..-1], string[0..ind-1]] end def parse_args( string ) arguments = [] ind = 0 inquot = false inapos = false depth = 1 begin case string[ind] when ?" inquot = !inquot unless inapos when ?' inapos = !inapos unless inquot else unless inquot or inapos case string[ind] when ?( depth += 1 if depth == 1 string = string[1..-1] ind -= 1 end when ?) depth -= 1 if depth == 0 s = string[0,ind].strip arguments << s unless s == "" string = string[ind+1..-1] end when ?, if depth == 1 s = string[0,ind].strip arguments << s unless s == "" string = string[ind+1..-1] ind = -1 end end end end ind += 1 end while depth > 0 and ind < string.length return nil unless depth==0 [string,arguments] end end end end PK|]lWWrexml/parsers/pullparser.rbnu[require 'forwardable' require 'rexml/parseexception' require 'rexml/parsers/baseparser' require 'rexml/xmltokens' module REXML module Parsers # = Using the Pull Parser # This API is experimental, and subject to change. # parser = PullParser.new( "texttxet" ) # while parser.has_next? # res = parser.next # puts res[1]['att'] if res.start_tag? and res[0] == 'b' # end # See the PullEvent class for information on the content of the results. # The data is identical to the arguments passed for the various events to # the StreamListener API. # # Notice that: # parser = PullParser.new( "BAD DOCUMENT" ) # while parser.has_next? # res = parser.next # raise res[1] if res.error? # end # # Nat Price gave me some good ideas for the API. class PullParser include XMLTokens extend Forwardable def_delegators( :@parser, :has_next? ) def_delegators( :@parser, :entity ) def_delegators( :@parser, :empty? ) def_delegators( :@parser, :source ) def initialize stream @entities = {} @listeners = nil @parser = BaseParser.new( stream ) @my_stack = [] end def add_listener( listener ) @listeners = [] unless @listeners @listeners << listener end def each while has_next? yield self.pull end end def peek depth=0 if @my_stack.length <= depth (depth - @my_stack.length + 1).times { e = PullEvent.new(@parser.pull) @my_stack.push(e) } end @my_stack[depth] end def pull return @my_stack.shift if @my_stack.length > 0 event = @parser.pull case event[0] when :entitydecl @entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/ when :text unnormalized = @parser.unnormalize( event[1], @entities ) event << unnormalized end PullEvent.new( event ) end def unshift token @my_stack.unshift token end end # A parsing event. The contents of the event are accessed as an +Array?, # and the type is given either by the ...? methods, or by accessing the # +type+ accessor. The contents of this object vary from event to event, # but are identical to the arguments passed to +StreamListener+s for each # event. class PullEvent # The type of this event. Will be one of :tag_start, :tag_end, :text, # :processing_instruction, :comment, :doctype, :attlistdecl, :entitydecl, # :notationdecl, :entity, :cdata, :xmldecl, or :error. def initialize(arg) @contents = arg end def []( start, endd=nil) if start.kind_of? Range @contents.slice( start.begin+1 .. start.end ) elsif start.kind_of? Numeric if endd.nil? @contents.slice( start+1 ) else @contents.slice( start+1, endd ) end else raise "Illegal argument #{start.inspect} (#{start.class})" end end def event_type @contents[0] end # Content: [ String tag_name, Hash attributes ] def start_element? @contents[0] == :start_element end # Content: [ String tag_name ] def end_element? @contents[0] == :end_element end # Content: [ String raw_text, String unnormalized_text ] def text? @contents[0] == :text end # Content: [ String text ] def instruction? @contents[0] == :processing_instruction end # Content: [ String text ] def comment? @contents[0] == :comment end # Content: [ String name, String pub_sys, String long_name, String uri ] def doctype? @contents[0] == :start_doctype end # Content: [ String text ] def attlistdecl? @contents[0] == :attlistdecl end # Content: [ String text ] def elementdecl? @contents[0] == :elementdecl end # Due to the wonders of DTDs, an entity declaration can be just about # anything. There's no way to normalize it; you'll have to interpret the # content yourself. However, the following is true: # # * If the entity declaration is an internal entity: # [ String name, String value ] # Content: [ String text ] def entitydecl? @contents[0] == :entitydecl end # Content: [ String text ] def notationdecl? @contents[0] == :notationdecl end # Content: [ String text ] def entity? @contents[0] == :entity end # Content: [ String text ] def cdata? @contents[0] == :cdata end # Content: [ String version, String encoding, String standalone ] def xmldecl? @contents[0] == :xmldecl end def error? @contents[0] == :error end def inspect @contents[0].to_s + ": " + @contents[1..-1].inspect end end end end PK|]{{SSrexml/encoding.rbnu[# -*- mode: ruby; ruby-indent-level: 2; indent-tabs-mode: t; tab-width: 2 -*- vim: sw=2 ts=2 module REXML module Encoding @encoding_methods = {} def self.register(enc, &block) @encoding_methods[enc] = block end def self.apply(obj, enc) @encoding_methods[enc][obj] end def self.encoding_method(enc) @encoding_methods[enc] end # Native, default format is UTF-8, so it is declared here rather than in # an encodings/ definition. UTF_8 = 'UTF-8' UTF_16 = 'UTF-16' UNILE = 'UNILE' # ID ---> Encoding name attr_reader :encoding def encoding=( enc ) old_verbosity = $VERBOSE begin $VERBOSE = false enc = enc.nil? ? nil : enc.upcase return false if defined? @encoding and enc == @encoding if enc and enc != UTF_8 @encoding = enc raise ArgumentError, "Bad encoding name #@encoding" unless @encoding =~ /^[\w-]+$/ @encoding.untaint begin require 'rexml/encodings/ICONV.rb' Encoding.apply(self, "ICONV") rescue LoadError, Exception begin enc_file = File.join( "rexml", "encodings", "#@encoding.rb" ) require enc_file Encoding.apply(self, @encoding) rescue LoadError => err puts err.message raise ArgumentError, "No decoder found for encoding #@encoding. Please install iconv." end end else @encoding = UTF_8 require 'rexml/encodings/UTF-8.rb' Encoding.apply(self, @encoding) end ensure $VERBOSE = old_verbosity end true end def check_encoding str # We have to recognize UTF-16, LSB UTF-16, and UTF-8 if str[0] == 0xfe && str[1] == 0xff str[0,2] = "" return UTF_16 elsif str[0] == 0xff && str[1] == 0xfe str[0,2] = "" return UNILE end str =~ /^\s*<\?xml\s+version\s*=\s*(['"]).*?\1\s+encoding\s*=\s*(["'])(.*?)\2/um return $3.upcase if $3 return UTF_8 end end end PK|]xrexml/instruction.rbnu[require "rexml/child" require "rexml/source" module REXML # Represents an XML Instruction; IE, # TODO: Add parent arg (3rd arg) to constructor class Instruction < Child START = '<\?' STOP = '\?>' # target is the "name" of the Instruction; IE, the "tag" in # content is everything else. attr_accessor :target, :content # Constructs a new Instruction # @param target can be one of a number of things. If String, then # the target of this instruction is set to this. If an Instruction, # then the Instruction is shallowly cloned (target and content are # copied). If a Source, then the source is scanned and parsed for # an Instruction declaration. # @param content Must be either a String, or a Parent. Can only # be a Parent if the target argument is a Source. Otherwise, this # String is set as the content of this instruction. def initialize(target, content=nil) if target.kind_of? String super() @target = target @content = content elsif target.kind_of? Instruction super(content) @target = target.target @content = target.content end @content.strip! if @content end def clone Instruction.new self end # == DEPRECATED # See the rexml/formatters package # def write writer, indent=-1, transitive=false, ie_hack=false Kernel.warn( "#{self.class.name}.write is deprecated" ) indent(writer, indent) writer << START.sub(/\\/u, '') writer << @target writer << ' ' writer << @content writer << STOP.sub(/\\/u, '') end # @return true if other is an Instruction, and the content and target # of the other matches the target and content of this object. def ==( other ) other.kind_of? Instruction and other.target == @target and other.content == @content end def node_type :processing_instruction end def inspect "" end end end PK|]Yڑ'rexml/validation/validationexception.rbnu[module REXML module Validation class ValidationException < RuntimeError def initialize msg super end end end end PK|]聓_::rexml/validation/relaxng.rbnu[require "rexml/validation/validation" require "rexml/parsers/baseparser" module REXML module Validation # Implemented: # * empty # * element # * attribute # * text # * optional # * choice # * oneOrMore # * zeroOrMore # * group # * value # * interleave # * mixed # * ref # * grammar # * start # * define # # Not implemented: # * data # * param # * include # * externalRef # * notAllowed # * anyName # * nsName # * except # * name class RelaxNG include Validator INFINITY = 1.0 / 0.0 EMPTY = Event.new( nil ) TEXT = [:start_element, "text"] attr_accessor :current attr_accessor :count attr_reader :references # FIXME: Namespaces def initialize source parser = REXML::Parsers::BaseParser.new( source ) @count = 0 @references = {} @root = @current = Sequence.new(self) @root.previous = true states = [ @current ] begin event = parser.pull case event[0] when :start_element case event[1] when "empty" when "element", "attribute", "text", "value" states[-1] << event when "optional" states << Optional.new( self ) states[-2] << states[-1] when "choice" states << Choice.new( self ) states[-2] << states[-1] when "oneOrMore" states << OneOrMore.new( self ) states[-2] << states[-1] when "zeroOrMore" states << ZeroOrMore.new( self ) states[-2] << states[-1] when "group" states << Sequence.new( self ) states[-2] << states[-1] when "interleave" states << Interleave.new( self ) states[-2] << states[-1] when "mixed" states << Interleave.new( self ) states[-2] << states[-1] states[-1] << TEXT when "define" states << [ event[2]["name"] ] when "ref" states[-1] << Ref.new( event[2]["name"] ) when "anyName" states << AnyName.new( self ) states[-2] << states[-1] when "nsName" when "except" when "name" when "data" when "param" when "include" when "grammar" when "start" when "externalRef" when "notAllowed" end when :end_element case event[1] when "element", "attribute" states[-1] << event when "zeroOrMore", "oneOrMore", "choice", "optional", "interleave", "group", "mixed" states.pop when "define" ref = states.pop @references[ ref.shift ] = ref #when "empty" end when :end_document states[-1] << event when :text states[-1] << event end end while event[0] != :end_document end def receive event validate( event ) end end class State def initialize( context ) @previous = [] @events = [] @current = 0 @count = context.count += 1 @references = context.references @value = false end def reset return if @current == 0 @current = 0 @events.each {|s| s.reset if s.kind_of? State } end def previous=( previous ) @previous << previous end def next( event ) #print "In next with #{event.inspect}. " #puts "Next (#@current) is #{@events[@current]}" #p @previous return @previous.pop.next( event ) if @events[@current].nil? expand_ref_in( @events, @current ) if @events[@current].class == Ref if ( @events[@current].kind_of? State ) @current += 1 @events[@current-1].previous = self return @events[@current-1].next( event ) end #puts "Current isn't a state" if ( @events[@current].matches?(event) ) @current += 1 if @events[@current].nil? #puts "#{inspect[0,5]} 1RETURNING #{@previous.inspect[0,5]}" return @previous.pop elsif @events[@current].kind_of? State @current += 1 #puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}" @events[@current-1].previous = self return @events[@current-1] else #puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}" return self end else return nil end end def to_s # Abbreviated: self.class.name =~ /(?:::)(\w)\w+$/ # Full: #self.class.name =~ /(?:::)(\w+)$/ "#$1.#@count" end def inspect "< #{to_s} #{@events.collect{|e| pre = e == @events[@current] ? '#' : '' pre + e.inspect unless self == e }.join(', ')} >" end def expected return [@events[@current]] end def <<( event ) add_event_to_arry( @events, event ) end protected def expand_ref_in( arry, ind ) new_events = [] @references[ arry[ind].to_s ].each{ |evt| add_event_to_arry(new_events,evt) } arry[ind,1] = new_events end def add_event_to_arry( arry, evt ) evt = generate_event( evt ) if evt.kind_of? String arry[-1].event_arg = evt if arry[-1].kind_of? Event and @value @value = false else arry << evt end end def generate_event( event ) return event if event.kind_of? State or event.class == Ref evt = nil arg = nil case event[0] when :start_element case event[1] when "element" evt = :start_element arg = event[2]["name"] when "attribute" evt = :start_attribute arg = event[2]["name"] when "text" evt = :text when "value" evt = :text @value = true end when :text return event[1] when :end_document return Event.new( event[0] ) else # then :end_element case event[1] when "element" evt = :end_element when "attribute" evt = :end_attribute end end return Event.new( evt, arg ) end end class Sequence < State def matches?(event) @events[@current].matches?( event ) end end class Optional < State def next( event ) if @current == 0 rv = super return rv if rv @prior = @previous.pop return @prior.next( event ) end super end def matches?(event) @events[@current].matches?(event) || (@current == 0 and @previous[-1].matches?(event)) end def expected return [ @prior.expected, @events[0] ].flatten if @current == 0 return [@events[@current]] end end class ZeroOrMore < Optional def next( event ) expand_ref_in( @events, @current ) if @events[@current].class == Ref if ( @events[@current].matches?(event) ) @current += 1 if @events[@current].nil? @current = 0 return self elsif @events[@current].kind_of? State @current += 1 @events[@current-1].previous = self return @events[@current-1] else return self end else @prior = @previous.pop return @prior.next( event ) if @current == 0 return nil end end def expected return [ @prior.expected, @events[0] ].flatten if @current == 0 return [@events[@current]] end end class OneOrMore < State def initialize context super @ord = 0 end def reset super @ord = 0 end def next( event ) expand_ref_in( @events, @current ) if @events[@current].class == Ref if ( @events[@current].matches?(event) ) @current += 1 @ord += 1 if @events[@current].nil? @current = 0 return self elsif @events[@current].kind_of? State @current += 1 @events[@current-1].previous = self return @events[@current-1] else return self end else return @previous.pop.next( event ) if @current == 0 and @ord > 0 return nil end end def matches?( event ) @events[@current].matches?(event) || (@current == 0 and @ord > 0 and @previous[-1].matches?(event)) end def expected if @current == 0 and @ord > 0 return [@previous[-1].expected, @events[0]].flatten else return [@events[@current]] end end end class Choice < State def initialize context super @choices = [] end def reset super @events = [] @choices.each { |c| c.each { |s| s.reset if s.kind_of? State } } end def <<( event ) add_event_to_arry( @choices, event ) end def next( event ) # Make the choice if we haven't if @events.size == 0 c = 0 ; max = @choices.size while c < max if @choices[c][0].class == Ref expand_ref_in( @choices[c], 0 ) @choices += @choices[c] @choices.delete( @choices[c] ) max -= 1 else c += 1 end end @events = @choices.find { |evt| evt[0].matches? event } # Remove the references # Find the events end #puts "In next with #{event.inspect}." #puts "events is #{@events.inspect}" unless @events @events = [] return nil end #puts "current = #@current" super end def matches?( event ) return @events[@current].matches?( event ) if @events.size > 0 !@choices.find{|evt| evt[0].matches?(event)}.nil? end def expected #puts "IN CHOICE EXPECTED" #puts "EVENTS = #{@events.inspect}" return [@events[@current]] if @events.size > 0 return @choices.collect do |x| if x[0].kind_of? State x[0].expected else x[0] end end.flatten end def inspect "< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' or ')} >" end protected def add_event_to_arry( arry, evt ) if evt.kind_of? State or evt.class == Ref arry << [evt] elsif evt[0] == :text if arry[-1] and arry[-1][-1].kind_of?( Event ) and arry[-1][-1].event_type == :text and @value arry[-1][-1].event_arg = evt[1] @value = false end else arry << [] if evt[0] == :start_element arry[-1] << generate_event( evt ) end end end class Interleave < Choice def initialize context super @choice = 0 end def reset @choice = 0 end def next_current( event ) # Expand references c = 0 ; max = @choices.size while c < max if @choices[c][0].class == Ref expand_ref_in( @choices[c], 0 ) @choices += @choices[c] @choices.delete( @choices[c] ) max -= 1 else c += 1 end end @events = @choices[@choice..-1].find { |evt| evt[0].matches? event } @current = 0 if @events # reorder the choices old = @choices[@choice] idx = @choices.index( @events ) @choices[@choice] = @events @choices[idx] = old @choice += 1 end #puts "In next with #{event.inspect}." #puts "events is #{@events.inspect}" @events = [] unless @events end def next( event ) # Find the next series next_current(event) unless @events[@current] return nil unless @events[@current] expand_ref_in( @events, @current ) if @events[@current].class == Ref #puts "In next with #{event.inspect}." #puts "Next (#@current) is #{@events[@current]}" if ( @events[@current].kind_of? State ) @current += 1 @events[@current-1].previous = self return @events[@current-1].next( event ) end #puts "Current isn't a state" return @previous.pop.next( event ) if @events[@current].nil? if ( @events[@current].matches?(event) ) @current += 1 if @events[@current].nil? #puts "#{inspect[0,5]} 1RETURNING self" unless @choices[@choice].nil? return self unless @choices[@choice].nil? #puts "#{inspect[0,5]} 1RETURNING #{@previous[-1].inspect[0,5]}" return @previous.pop elsif @events[@current].kind_of? State @current += 1 #puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}" @events[@current-1].previous = self return @events[@current-1] else #puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}" return self end else return nil end end def matches?( event ) return @events[@current].matches?( event ) if @events[@current] !@choices[@choice..-1].find{|evt| evt[0].matches?(event)}.nil? end def expected #puts "IN CHOICE EXPECTED" #puts "EVENTS = #{@events.inspect}" return [@events[@current]] if @events[@current] return @choices[@choice..-1].collect do |x| if x[0].kind_of? State x[0].expected else x[0] end end.flatten end def inspect "< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' and ')} >" end end class Ref def initialize value @value = value end def to_s @value end def inspect "{#{to_s}}" end end end end PK|]R_55rexml/validation/validation.rbnu[require 'rexml/validation/validationexception' module REXML module Validation module Validator NILEVENT = [ nil ] def reset @current = @root @root.reset @root.previous = true @attr_stack = [] self end def dump puts @root.inspect end def validate( event ) #puts "Current: #@current" #puts "Event: #{event.inspect}" @attr_stack = [] unless defined? @attr_stack match = @current.next(event) raise ValidationException.new( "Validation error. Expected: "+ @current.expected.join( " or " )+" from #{@current.inspect} "+ " but got #{Event.new( event[0], event[1] ).inspect}" ) unless match @current = match # Check for attributes case event[0] when :start_element #puts "Checking attributes" @attr_stack << event[2] begin sattr = [:start_attribute, nil] eattr = [:end_attribute] text = [:text, nil] k,v = event[2].find { |k,v| sattr[1] = k #puts "Looking for #{sattr.inspect}" m = @current.next( sattr ) #puts "Got #{m.inspect}" if m # If the state has text children... #puts "Looking for #{eattr.inspect}" #puts "Expect #{m.expected}" if m.matches?( eattr ) #puts "Got end" @current = m else #puts "Didn't get end" text[1] = v #puts "Looking for #{text.inspect}" m = m.next( text ) #puts "Got #{m.inspect}" text[1] = nil return false unless m @current = m if m end m = @current.next( eattr ) if m @current = m true else false end else false end } event[2].delete(k) if k end while k when :end_element attrs = @attr_stack.pop raise ValidationException.new( "Validation error. Illegal "+ " attributes: #{attrs.inspect}") if attrs.length > 0 end end end class Event def initialize(event_type, event_arg=nil ) @event_type = event_type @event_arg = event_arg end attr_reader :event_type attr_accessor :event_arg def done? @done end def single? return (@event_type != :start_element and @event_type != :start_attribute) end def matches?( event ) #puts "#@event_type =? #{event[0]} && #@event_arg =? #{event[1]} " return false unless event[0] == @event_type case event[0] when nil return true when :start_element return true if event[1] == @event_arg when :end_element return true when :start_attribute return true if event[1] == @event_arg when :end_attribute return true when :end_document return true when :text return (@event_arg.nil? or @event_arg == event[1]) =begin when :processing_instruction false when :xmldecl false when :start_doctype false when :end_doctype false when :externalentity false when :elementdecl false when :entity false when :attlistdecl false when :notationdecl false when :end_doctype false =end else false end end def ==( other ) return false unless other.kind_of? Event @event_type == other.event_type and @event_arg == other.event_arg end def to_s inspect end def inspect "#{@event_type.inspect}( #@event_arg )" end end end end PK|]arexml/namespace.rbnu[require 'rexml/xmltokens' module REXML # Adds named attributes to an object. module Namespace # The name of the object, valid if set attr_reader :name, :expanded_name # The expanded name of the object, valid if name is set attr_accessor :prefix include XMLTokens NAMESPLIT = /^(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})/u # Sets the name and the expanded name def name=( name ) @expanded_name = name name =~ NAMESPLIT if $1 @prefix = $1 else @prefix = "" @namespace = "" end @name = $2 end # Compares names optionally WITH namespaces def has_name?( other, ns=nil ) if ns return (namespace() == ns and name() == other) elsif other.include? ":" return fully_expanded_name == other else return name == other end end alias :local_name :name # Fully expand the name, even if the prefix wasn't specified in the # source file. def fully_expanded_name ns = prefix return "#{ns}:#@name" if ns.size > 0 return @name end end end PK|]Burexml/output.rbnu[require 'rexml/encoding' module REXML class Output include Encoding attr_reader :encoding def initialize real_IO, encd="iso-8859-1" @output = real_IO self.encoding = encd @to_utf = encd == UTF_8 ? false : true end def <<( content ) @output << (@to_utf ? self.encode(content) : content) end def to_s "Output[#{encoding}]" end end end PK|] ddrexml/xpath_parser.rbnu[require 'rexml/namespace' require 'rexml/xmltokens' require 'rexml/attribute' require 'rexml/syncenumerator' require 'rexml/parsers/xpathparser' class Object def dclone clone end end class Symbol def dclone ; self ; end end class Fixnum def dclone ; self ; end end class Float def dclone ; self ; end end class Array def dclone klone = self.clone klone.clear self.each{|v| klone << v.dclone} klone end end module REXML # You don't want to use this class. Really. Use XPath, which is a wrapper # for this class. Believe me. You don't want to poke around in here. # There is strange, dark magic at work in this code. Beware. Go back! Go # back while you still can! class XPathParser include XMLTokens LITERAL = /^'([^']*)'|^"([^"]*)"/u def initialize( ) @parser = REXML::Parsers::XPathParser.new @namespaces = nil @variables = {} end def namespaces=( namespaces={} ) Functions::namespace_context = namespaces @namespaces = namespaces end def variables=( vars={} ) Functions::variables = vars @variables = vars end def parse path, nodeset #puts "#"*40 path_stack = @parser.parse( path ) #puts "PARSE: #{path} => #{path_stack.inspect}" #puts "PARSE: nodeset = #{nodeset.inspect}" match( path_stack, nodeset ) end def get_first path, nodeset #puts "#"*40 path_stack = @parser.parse( path ) #puts "PARSE: #{path} => #{path_stack.inspect}" #puts "PARSE: nodeset = #{nodeset.inspect}" first( path_stack, nodeset ) end def predicate path, nodeset path_stack = @parser.parse( path ) expr( path_stack, nodeset ) end def []=( variable_name, value ) @variables[ variable_name ] = value end # Performs a depth-first (document order) XPath search, and returns the # first match. This is the fastest, lightest way to return a single result. # # FIXME: This method is incomplete! def first( path_stack, node ) #puts "#{depth}) Entering match( #{path.inspect}, #{tree.inspect} )" return nil if path.size == 0 case path[0] when :document # do nothing return first( path[1..-1], node ) when :child for c in node.children #puts "#{depth}) CHILD checking #{name(c)}" r = first( path[1..-1], c ) #puts "#{depth}) RETURNING #{r.inspect}" if r return r if r end when :qname name = path[2] #puts "#{depth}) QNAME #{name(tree)} == #{name} (path => #{path.size})" if node.name == name #puts "#{depth}) RETURNING #{tree.inspect}" if path.size == 3 return node if path.size == 3 return first( path[3..-1], node ) else return nil end when :descendant_or_self r = first( path[1..-1], node ) return r if r for c in node.children r = first( path, c ) return r if r end when :node return first( path[1..-1], node ) when :any return first( path[1..-1], node ) end return nil end def match( path_stack, nodeset ) #puts "MATCH: path_stack = #{path_stack.inspect}" #puts "MATCH: nodeset = #{nodeset.inspect}" r = expr( path_stack, nodeset ) #puts "MAIN EXPR => #{r.inspect}" r end private # Returns a String namespace for a node, given a prefix # The rules are: # # 1. Use the supplied namespace mapping first. # 2. If no mapping was supplied, use the context node to look up the namespace def get_namespace( node, prefix ) if @namespaces return @namespaces[prefix] || '' else return node.namespace( prefix ) if node.node_type == :element return '' end end # Expr takes a stack of path elements and a set of nodes (either a Parent # or an Array and returns an Array of matching nodes ALL = [ :attribute, :element, :text, :processing_instruction, :comment ] ELEMENTS = [ :element ] def expr( path_stack, nodeset, context=nil ) #puts "#"*15 #puts "In expr with #{path_stack.inspect}" #puts "Returning" if path_stack.length == 0 || nodeset.length == 0 node_types = ELEMENTS return nodeset if path_stack.length == 0 || nodeset.length == 0 while path_stack.length > 0 #puts "#"*5 #puts "Path stack = #{path_stack.inspect}" #puts "Nodeset is #{nodeset.inspect}" if nodeset.length == 0 path_stack.clear return [] end case (op = path_stack.shift) when :document nodeset = [ nodeset[0].root_node ] #puts ":document, nodeset = #{nodeset.inspect}" when :qname #puts "IN QNAME" prefix = path_stack.shift name = path_stack.shift nodeset.delete_if do |node| # FIXME: This DOUBLES the time XPath searches take ns = get_namespace( node, prefix ) #puts "NS = #{ns.inspect}" #puts "node.node_type == :element => #{node.node_type == :element}" if node.node_type == :element #puts "node.name == #{name} => #{node.name == name}" if node.name == name #puts "node.namespace == #{ns.inspect} => #{node.namespace == ns}" end end !(node.node_type == :element and node.name == name and node.namespace == ns ) end node_types = ELEMENTS when :any #puts "ANY 1: nodeset = #{nodeset.inspect}" #puts "ANY 1: node_types = #{node_types.inspect}" nodeset.delete_if { |node| !node_types.include?(node.node_type) } #puts "ANY 2: nodeset = #{nodeset.inspect}" when :self # This space left intentionally blank when :processing_instruction target = path_stack.shift nodeset.delete_if do |node| (node.node_type != :processing_instruction) or ( target!='' and ( node.target != target ) ) end when :text nodeset.delete_if { |node| node.node_type != :text } when :comment nodeset.delete_if { |node| node.node_type != :comment } when :node # This space left intentionally blank node_types = ALL when :child new_nodeset = [] nt = nil for node in nodeset nt = node.node_type new_nodeset += node.children if nt == :element or nt == :document end nodeset = new_nodeset node_types = ELEMENTS when :literal return path_stack.shift when :attribute new_nodeset = [] case path_stack.shift when :qname prefix = path_stack.shift name = path_stack.shift for element in nodeset if element.node_type == :element #puts "Element name = #{element.name}" #puts "get_namespace( #{element.inspect}, #{prefix} ) = #{get_namespace(element, prefix)}" attrib = element.attribute( name, get_namespace(element, prefix) ) #puts "attrib = #{attrib.inspect}" new_nodeset << attrib if attrib end end when :any #puts "ANY" for element in nodeset if element.node_type == :element new_nodeset += element.attributes.to_a end end end nodeset = new_nodeset when :parent #puts "PARENT 1: nodeset = #{nodeset}" nodeset = nodeset.collect{|n| n.parent}.compact #nodeset = expr(path_stack.dclone, nodeset.collect{|n| n.parent}.compact) #puts "PARENT 2: nodeset = #{nodeset.inspect}" node_types = ELEMENTS when :ancestor new_nodeset = [] for node in nodeset while node.parent node = node.parent new_nodeset << node unless new_nodeset.include? node end end nodeset = new_nodeset node_types = ELEMENTS when :ancestor_or_self new_nodeset = [] for node in nodeset if node.node_type == :element new_nodeset << node while ( node.parent ) node = node.parent new_nodeset << node unless new_nodeset.include? node end end end nodeset = new_nodeset node_types = ELEMENTS when :predicate new_nodeset = [] subcontext = { :size => nodeset.size } pred = path_stack.shift nodeset.each_with_index { |node, index| subcontext[ :node ] = node #puts "PREDICATE SETTING CONTEXT INDEX TO #{index+1}" subcontext[ :index ] = index+1 pc = pred.dclone #puts "#{node.hash}) Recursing with #{pred.inspect} and [#{node.inspect}]" result = expr( pc, [node], subcontext ) result = result[0] if result.kind_of? Array and result.length == 1 #puts "#{node.hash}) Result = #{result.inspect} (#{result.class.name})" if result.kind_of? Numeric #puts "Adding node #{node.inspect}" if result == (index+1) new_nodeset << node if result == (index+1) elsif result.instance_of? Array if result.size > 0 and result.inject(false) {|k,s| s or k} #puts "Adding node #{node.inspect}" if result.size > 0 new_nodeset << node if result.size > 0 end else #puts "Adding node #{node.inspect}" if result new_nodeset << node if result end } #puts "New nodeset = #{new_nodeset.inspect}" #puts "Path_stack = #{path_stack.inspect}" nodeset = new_nodeset =begin predicate = path_stack.shift ns = nodeset.clone result = expr( predicate, ns ) #puts "Result = #{result.inspect} (#{result.class.name})" #puts "nodeset = #{nodeset.inspect}" if result.kind_of? Array nodeset = result.zip(ns).collect{|m,n| n if m}.compact else nodeset = result ? nodeset : [] end #puts "Outgoing NS = #{nodeset.inspect}" =end when :descendant_or_self rv = descendant_or_self( path_stack, nodeset ) path_stack.clear nodeset = rv node_types = ELEMENTS when :descendant results = [] nt = nil for node in nodeset nt = node.node_type results += expr( path_stack.dclone.unshift( :descendant_or_self ), node.children ) if nt == :element or nt == :document end nodeset = results node_types = ELEMENTS when :following_sibling #puts "FOLLOWING_SIBLING 1: nodeset = #{nodeset}" results = [] nodeset.each do |node| next if node.parent.nil? all_siblings = node.parent.children current_index = all_siblings.index( node ) following_siblings = all_siblings[ current_index+1 .. -1 ] results += expr( path_stack.dclone, following_siblings ) end #puts "FOLLOWING_SIBLING 2: nodeset = #{nodeset}" nodeset = results when :preceding_sibling results = [] nodeset.each do |node| next if node.parent.nil? all_siblings = node.parent.children current_index = all_siblings.index( node ) preceding_siblings = all_siblings[ 0, current_index ].reverse results += preceding_siblings end nodeset = results node_types = ELEMENTS when :preceding new_nodeset = [] for node in nodeset new_nodeset += preceding( node ) end #puts "NEW NODESET => #{new_nodeset.inspect}" nodeset = new_nodeset node_types = ELEMENTS when :following new_nodeset = [] for node in nodeset new_nodeset += following( node ) end nodeset = new_nodeset node_types = ELEMENTS when :namespace #puts "In :namespace" new_nodeset = [] prefix = path_stack.shift for node in nodeset if (node.node_type == :element or node.node_type == :attribute) if @namespaces namespaces = @namespaces elsif (node.node_type == :element) namespaces = node.namespaces else namespaces = node.element.namesapces end #puts "Namespaces = #{namespaces.inspect}" #puts "Prefix = #{prefix.inspect}" #puts "Node.namespace = #{node.namespace}" if (node.namespace == namespaces[prefix]) new_nodeset << node end end end nodeset = new_nodeset when :variable var_name = path_stack.shift return @variables[ var_name ] # :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq # TODO: Special case for :or and :and -- not evaluate the right # operand if the left alone determines result (i.e. is true for # :or and false for :and). when :eq, :neq, :lt, :lteq, :gt, :gteq, :and, :or left = expr( path_stack.shift, nodeset.dup, context ) #puts "LEFT => #{left.inspect} (#{left.class.name})" right = expr( path_stack.shift, nodeset.dup, context ) #puts "RIGHT => #{right.inspect} (#{right.class.name})" res = equality_relational_compare( left, op, right ) #puts "RES => #{res.inspect}" return res when :and left = expr( path_stack.shift, nodeset.dup, context ) #puts "LEFT => #{left.inspect} (#{left.class.name})" if left == false || left.nil? || !left.inject(false) {|a,b| a | b} return [] end right = expr( path_stack.shift, nodeset.dup, context ) #puts "RIGHT => #{right.inspect} (#{right.class.name})" res = equality_relational_compare( left, op, right ) #puts "RES => #{res.inspect}" return res when :div left = Functions::number(expr(path_stack.shift, nodeset, context)).to_f right = Functions::number(expr(path_stack.shift, nodeset, context)).to_f return (left / right) when :mod left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f return (left % right) when :mult left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f return (left * right) when :plus left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f return (left + right) when :minus left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f return (left - right) when :union left = expr( path_stack.shift, nodeset, context ) right = expr( path_stack.shift, nodeset, context ) return (left | right) when :neg res = expr( path_stack, nodeset, context ) return -(res.to_f) when :not when :function func_name = path_stack.shift.tr('-','_') arguments = path_stack.shift #puts "FUNCTION 0: #{func_name}(#{arguments.collect{|a|a.inspect}.join(', ')})" subcontext = context ? nil : { :size => nodeset.size } res = [] cont = context nodeset.each_with_index { |n, i| if subcontext subcontext[:node] = n subcontext[:index] = i cont = subcontext end arg_clone = arguments.dclone args = arg_clone.collect { |arg| #puts "FUNCTION 1: Calling expr( #{arg.inspect}, [#{n.inspect}] )" expr( arg, [n], cont ) } #puts "FUNCTION 2: #{func_name}(#{args.collect{|a|a.inspect}.join(', ')})" Functions.context = cont res << Functions.send( func_name, *args ) #puts "FUNCTION 3: #{res[-1].inspect}" } return res end end # while #puts "EXPR returning #{nodeset.inspect}" return nodeset end ########################################################## # FIXME # The next two methods are BAD MOJO! # This is my achilles heel. If anybody thinks of a better # way of doing this, be my guest. This really sucks, but # it is a wonder it works at all. # ######################################################## def descendant_or_self( path_stack, nodeset ) rs = [] #puts "#"*80 #puts "PATH_STACK = #{path_stack.inspect}" #puts "NODESET = #{nodeset.collect{|n|n.inspect}.inspect}" d_o_s( path_stack, nodeset, rs ) #puts "RS = #{rs.collect{|n|n.inspect}.inspect}" document_order(rs.flatten.compact) #rs.flatten.compact end def d_o_s( p, ns, r ) #puts "IN DOS with #{ns.inspect}; ALREADY HAVE #{r.inspect}" nt = nil ns.each_index do |i| n = ns[i] #puts "P => #{p.inspect}" x = expr( p.dclone, [ n ] ) nt = n.node_type d_o_s( p, n.children, x ) if nt == :element or nt == :document and n.children.size > 0 r.concat(x) if x.size > 0 end end # Reorders an array of nodes so that they are in document order # It tries to do this efficiently. # # FIXME: I need to get rid of this, but the issue is that most of the XPath # interpreter functions as a filter, which means that we lose context going # in and out of function calls. If I knew what the index of the nodes was, # I wouldn't have to do this. Maybe add a document IDX for each node? # Problems with mutable documents. Or, rewrite everything. def document_order( array_of_nodes ) new_arry = [] array_of_nodes.each { |node| node_idx = [] np = node.node_type == :attribute ? node.element : node while np.parent and np.parent.node_type == :element node_idx << np.parent.index( np ) np = np.parent end new_arry << [ node_idx.reverse, node ] } #puts "new_arry = #{new_arry.inspect}" new_arry.sort{ |s1, s2| s1[0] <=> s2[0] }.collect{ |s| s[1] } end def recurse( nodeset, &block ) for node in nodeset yield node recurse( node, &block ) if node.node_type == :element end end # Builds a nodeset of all of the preceding nodes of the supplied node, # in reverse document order # preceding:: includes every element in the document that precedes this node, # except for ancestors def preceding( node ) #puts "IN PRECEDING" ancestors = [] p = node.parent while p ancestors << p p = p.parent end acc = [] p = preceding_node_of( node ) #puts "P = #{p.inspect}" while p if ancestors.include? p ancestors.delete(p) else acc << p end p = preceding_node_of( p ) #puts "P = #{p.inspect}" end acc end def preceding_node_of( node ) #puts "NODE: #{node.inspect}" #puts "PREVIOUS NODE: #{node.previous_sibling_node.inspect}" #puts "PARENT NODE: #{node.parent}" psn = node.previous_sibling_node if psn.nil? if node.parent.nil? or node.parent.class == Document return nil end return node.parent #psn = preceding_node_of( node.parent ) end while psn and psn.kind_of? Element and psn.children.size > 0 psn = psn.children[-1] end psn end def following( node ) #puts "IN PRECEDING" acc = [] p = next_sibling_node( node ) #puts "P = #{p.inspect}" while p acc << p p = following_node_of( p ) #puts "P = #{p.inspect}" end acc end def following_node_of( node ) #puts "NODE: #{node.inspect}" #puts "PREVIOUS NODE: #{node.previous_sibling_node.inspect}" #puts "PARENT NODE: #{node.parent}" if node.kind_of? Element and node.children.size > 0 return node.children[0] end return next_sibling_node(node) end def next_sibling_node(node) psn = node.next_sibling_node while psn.nil? if node.parent.nil? or node.parent.class == Document return nil end node = node.parent psn = node.next_sibling_node #puts "psn = #{psn.inspect}" end return psn end def norm b case b when true, false return b when 'true', 'false' return Functions::boolean( b ) when /^\d+(\.\d+)?$/ return Functions::number( b ) else return Functions::string( b ) end end def equality_relational_compare( set1, op, set2 ) #puts "EQ_REL_COMP(#{set1.inspect} #{op.inspect} #{set2.inspect})" if set1.kind_of? Array and set2.kind_of? Array #puts "#{set1.size} & #{set2.size}" if set1.size == 1 and set2.size == 1 set1 = set1[0] set2 = set2[0] elsif set1.size == 0 or set2.size == 0 nd = set1.size==0 ? set2 : set1 rv = nd.collect { |il| compare( il, op, nil ) } #puts "RV = #{rv.inspect}" return rv else res = [] enum = SyncEnumerator.new( set1, set2 ).each { |i1, i2| #puts "i1 = #{i1.inspect} (#{i1.class.name})" #puts "i2 = #{i2.inspect} (#{i2.class.name})" i1 = norm( i1 ) i2 = norm( i2 ) res << compare( i1, op, i2 ) } return res end end #puts "EQ_REL_COMP: #{set1.inspect} (#{set1.class.name}), #{op}, #{set2.inspect} (#{set2.class.name})" #puts "COMPARING VALUES" # If one is nodeset and other is number, compare number to each item # in nodeset s.t. number op number(string(item)) # If one is nodeset and other is string, compare string to each item # in nodeset s.t. string op string(item) # If one is nodeset and other is boolean, compare boolean to each item # in nodeset s.t. boolean op boolean(item) if set1.kind_of? Array or set2.kind_of? Array #puts "ISA ARRAY" if set1.kind_of? Array a = set1 b = set2 else a = set2 b = set1 end case b when true, false return a.collect {|v| compare( Functions::boolean(v), op, b ) } when Numeric return a.collect {|v| compare( Functions::number(v), op, b )} when /^\d+(\.\d+)?$/ b = Functions::number( b ) #puts "B = #{b.inspect}" return a.collect {|v| compare( Functions::number(v), op, b )} else #puts "Functions::string( #{b}(#{b.class.name}) ) = #{Functions::string(b)}" b = Functions::string( b ) return a.collect { |v| compare( Functions::string(v), op, b ) } end else # If neither is nodeset, # If op is = or != # If either boolean, convert to boolean # If either number, convert to number # Else, convert to string # Else # Convert both to numbers and compare s1 = set1.to_s s2 = set2.to_s #puts "EQ_REL_COMP: #{set1}=>#{s1}, #{set2}=>#{s2}" if s1 == 'true' or s1 == 'false' or s2 == 'true' or s2 == 'false' #puts "Functions::boolean(#{set1})=>#{Functions::boolean(set1)}" #puts "Functions::boolean(#{set2})=>#{Functions::boolean(set2)}" set1 = Functions::boolean( set1 ) set2 = Functions::boolean( set2 ) else if op == :eq or op == :neq if s1 =~ /^\d+(\.\d+)?$/ or s2 =~ /^\d+(\.\d+)?$/ set1 = Functions::number( s1 ) set2 = Functions::number( s2 ) else set1 = Functions::string( set1 ) set2 = Functions::string( set2 ) end else set1 = Functions::number( set1 ) set2 = Functions::number( set2 ) end end #puts "EQ_REL_COMP: #{set1} #{op} #{set2}" #puts ">>> #{compare( set1, op, set2 )}" return compare( set1, op, set2 ) end return false end def compare a, op, b #puts "COMPARE #{a.inspect}(#{a.class.name}) #{op} #{b.inspect}(#{b.class.name})" case op when :eq a == b when :neq a != b when :lt a < b when :lteq a <= b when :gt a > b when :gteq a >= b when :and a and b when :or a or b else false end end end end PK|]"2+2+rexml/functions.rbnu[module REXML # If you add a method, keep in mind two things: # (1) the first argument will always be a list of nodes from which to # filter. In the case of context methods (such as position), the function # should return an array with a value for each child in the array. # (2) all method calls from XML will have "-" replaced with "_". # Therefore, in XML, "local-name()" is identical (and actually becomes) # "local_name()" module Functions @@context = nil @@namespace_context = {} @@variables = {} def Functions::namespace_context=(x) ; @@namespace_context=x ; end def Functions::variables=(x) ; @@variables=x ; end def Functions::namespace_context ; @@namespace_context ; end def Functions::variables ; @@variables ; end def Functions::context=(value); @@context = value; end def Functions::text( ) if @@context[:node].node_type == :element return @@context[:node].find_all{|n| n.node_type == :text}.collect{|n| n.value} elsif @@context[:node].node_type == :text return @@context[:node].value else return false end end def Functions::last( ) @@context[:size] end def Functions::position( ) @@context[:index] end def Functions::count( node_set ) node_set.size end # Since REXML is non-validating, this method is not implemented as it # requires a DTD def Functions::id( object ) end # UNTESTED def Functions::local_name( node_set=nil ) get_namespace( node_set ) do |node| return node.local_name end end def Functions::namespace_uri( node_set=nil ) get_namespace( node_set ) {|node| node.namespace} end def Functions::name( node_set=nil ) get_namespace( node_set ) do |node| node.expanded_name end end # Helper method. def Functions::get_namespace( node_set = nil ) if node_set == nil yield @@context[:node] if defined? @@context[:node].namespace else if node_set.respond_to? :each node_set.each { |node| yield node if defined? node.namespace } elsif node_set.respond_to? :namespace yield node_set end end end # A node-set is converted to a string by returning the string-value of the # node in the node-set that is first in document order. If the node-set is # empty, an empty string is returned. # # A number is converted to a string as follows # # NaN is converted to the string NaN # # positive zero is converted to the string 0 # # negative zero is converted to the string 0 # # positive infinity is converted to the string Infinity # # negative infinity is converted to the string -Infinity # # if the number is an integer, the number is represented in decimal form # as a Number with no decimal point and no leading zeros, preceded by a # minus sign (-) if the number is negative # # otherwise, the number is represented in decimal form as a Number # including a decimal point with at least one digit before the decimal # point and at least one digit after the decimal point, preceded by a # minus sign (-) if the number is negative; there must be no leading zeros # before the decimal point apart possibly from the one required digit # immediately before the decimal point; beyond the one required digit # after the decimal point there must be as many, but only as many, more # digits as are needed to uniquely distinguish the number from all other # IEEE 754 numeric values. # # The boolean false value is converted to the string false. The boolean # true value is converted to the string true. # # An object of a type other than the four basic types is converted to a # string in a way that is dependent on that type. def Functions::string( object=nil ) #object = @context unless object if object.instance_of? Array string( object[0] ) elsif defined? object.node_type if object.node_type == :attribute object.value elsif object.node_type == :element || object.node_type == :document string_value(object) else object.to_s end elsif object.nil? return "" else object.to_s end end def Functions::string_value( o ) rv = "" o.children.each { |e| if e.node_type == :text rv << e.to_s elsif e.node_type == :element rv << string_value( e ) end } rv end # UNTESTED def Functions::concat( *objects ) objects.join end # Fixed by Mike Stok def Functions::starts_with( string, test ) string(string).index(string(test)) == 0 end # Fixed by Mike Stok def Functions::contains( string, test ) string(string).include?(string(test)) end # Kouhei fixed this def Functions::substring_before( string, test ) ruby_string = string(string) ruby_index = ruby_string.index(string(test)) if ruby_index.nil? "" else ruby_string[ 0...ruby_index ] end end # Kouhei fixed this too def Functions::substring_after( string, test ) ruby_string = string(string) test_string = string(test) return $1 if ruby_string =~ /#{test}(.*)/ "" end # Take equal portions of Mike Stok and Sean Russell; mix # vigorously, and pour into a tall, chilled glass. Serves 10,000. def Functions::substring( string, start, length=nil ) ruby_string = string(string) ruby_length = if length.nil? ruby_string.length.to_f else number(length) end ruby_start = number(start) # Handle the special cases return '' if ( ruby_length.nan? or ruby_start.nan? or ruby_start.infinite? ) infinite_length = ruby_length.infinite? == 1 ruby_length = ruby_string.length if infinite_length # Now, get the bounds. The XPath bounds are 1..length; the ruby bounds # are 0..length. Therefore, we have to offset the bounds by one. ruby_start = ruby_start.round - 1 ruby_length = ruby_length.round if ruby_start < 0 ruby_length += ruby_start unless infinite_length ruby_start = 0 end return '' if ruby_length <= 0 ruby_string[ruby_start,ruby_length] end # UNTESTED def Functions::string_length( string ) string(string).length end # UNTESTED def Functions::normalize_space( string=nil ) string = string(@@context[:node]) if string.nil? if string.kind_of? Array string.collect{|x| string.to_s.strip.gsub(/\s+/um, ' ') if string} else string.to_s.strip.gsub(/\s+/um, ' ') end end # This is entirely Mike Stok's beast def Functions::translate( string, tr1, tr2 ) from = string(tr1) to = string(tr2) # the map is our translation table. # # if a character occurs more than once in the # from string then we ignore the second & # subsequent mappings # # if a character maps to nil then we delete it # in the output. This happens if the from # string is longer than the to string # # there's nothing about - or ^ being special in # http://www.w3.org/TR/xpath#function-translate # so we don't build ranges or negated classes map = Hash.new 0.upto(from.length - 1) { |pos| from_char = from[pos] unless map.has_key? from_char map[from_char] = if pos < to.length to[pos] else nil end end } string(string).unpack('U*').collect { |c| if map.has_key? c then map[c] else c end }.compact.pack('U*') end # UNTESTED def Functions::boolean( object=nil ) if object.kind_of? String if object =~ /\d+/u return object.to_f != 0 else return object.size > 0 end elsif object.kind_of? Array object = object.find{|x| x and true} end return object ? true : false end # UNTESTED def Functions::not( object ) not boolean( object ) end # UNTESTED def Functions::true( ) true end # UNTESTED def Functions::false( ) false end # UNTESTED def Functions::lang( language ) lang = false node = @@context[:node] attr = nil until node.nil? if node.node_type == :element attr = node.attributes["xml:lang"] unless attr.nil? lang = compare_language(string(language), attr) break else end end node = node.parent end lang end def Functions::compare_language lang1, lang2 lang2.downcase.index(lang1.downcase) == 0 end # a string that consists of optional whitespace followed by an optional # minus sign followed by a Number followed by whitespace is converted to # the IEEE 754 number that is nearest (according to the IEEE 754 # round-to-nearest rule) to the mathematical value represented by the # string; any other string is converted to NaN # # boolean true is converted to 1; boolean false is converted to 0 # # a node-set is first converted to a string as if by a call to the string # function and then converted in the same way as a string argument # # an object of a type other than the four basic types is converted to a # number in a way that is dependent on that type def Functions::number( object=nil ) object = @@context[:node] unless object case object when true Float(1) when false Float(0) when Array number(string( object )) when Numeric object.to_f else str = string( object ) # If XPath ever gets scientific notation... #if str =~ /^\s*-?(\d*\.?\d+|\d+\.)([Ee]\d*)?\s*$/ if str =~ /^\s*-?(\d*\.?\d+|\d+\.)\s*$/ str.to_f else (0.0 / 0.0) end end end def Functions::sum( nodes ) nodes = [nodes] unless nodes.kind_of? Array nodes.inject(0) { |r,n| r += number(string(n)) } end def Functions::floor( number ) number(number).floor end def Functions::ceiling( number ) number(number).ceil end def Functions::round( number ) begin number(number).round rescue FloatDomainError number(number) end end def Functions::processing_instruction( node ) node.node_type == :processing_instruction end def Functions::method_missing( id ) puts "METHOD MISSING #{id.id2name}" XPath.match( @@context[:node], id.id2name ) end end end PK|] rexml/child.rbnu[require "rexml/node" module REXML ## # A Child object is something contained by a parent, and this class # contains methods to support that. Most user code will not use this # class directly. class Child include Node attr_reader :parent # The Parent of this object # Constructor. Any inheritors of this class should call super to make # sure this method is called. # parent:: # if supplied, the parent of this child will be set to the # supplied value, and self will be added to the parent def initialize( parent = nil ) @parent = nil # Declare @parent, but don't define it. The next line sets the # parent. parent.add( self ) if parent end # Replaces this object with another object. Basically, calls # Parent.replace_child # # Returns:: self def replace_with( child ) @parent.replace_child( self, child ) self end # Removes this child from the parent. # # Returns:: self def remove unless @parent.nil? @parent.delete self end self end # Sets the parent of this child to the supplied argument. # # other:: # Must be a Parent object. If this object is the same object as the # existing parent of this child, no action is taken. Otherwise, this # child is removed from the current parent (if one exists), and is added # to the new parent. # Returns:: The parent added def parent=( other ) return @parent if @parent == other @parent.delete self if defined? @parent and @parent @parent = other end alias :next_sibling :next_sibling_node alias :previous_sibling :previous_sibling_node # Sets the next sibling of this child. This can be used to insert a child # after some other child. # a = Element.new("a") # b = a.add_element("b") # c = Element.new("c") # b.next_sibling = c # # => def next_sibling=( other ) parent.insert_after self, other end # Sets the previous sibling of this child. This can be used to insert a # child before some other child. # a = Element.new("a") # b = a.add_element("b") # c = Element.new("c") # b.previous_sibling = c # # => def previous_sibling=(other) parent.insert_before self, other end # Returns:: the document this child belongs to, or nil if this child # belongs to no document def document return parent.document unless parent.nil? nil end # This doesn't yet handle encodings def bytes encoding = document.encoding to_s end end end PK|]Jq| rexml/cdata.rbnu[require "rexml/text" module REXML class CData < Text START = '' ILLEGAL = /(\]\]>)/ # Constructor. CData is data between # # _Examples_ # CData.new( source ) # CData.new( "Here is some CDATA" ) # CData.new( "Some unprocessed data", respect_whitespace_TF, parent_element ) def initialize( first, whitespace=true, parent=nil ) super( first, whitespace, parent, true, true, ILLEGAL ) end # Make a copy of this object # # _Examples_ # c = CData.new( "Some text" ) # d = c.clone # d.to_s # -> "Some text" def clone CData.new self end # Returns the content of this CData object # # _Examples_ # c = CData.new( "Some text" ) # c.to_s # -> "Some text" def to_s @string end def value @string end # == DEPRECATED # See the rexml/formatters package # # Generates XML output of this object # # output:: # Where to write the string. Defaults to $stdout # indent:: # The amount to indent this node by # transitive:: # Ignored # ie_hack:: # Ignored # # _Examples_ # c = CData.new( " Some text " ) # c.write( $stdout ) #-> def write( output=$stdout, indent=-1, transitive=false, ie_hack=false ) Kernel.warn( "#{self.class.name}.write is deprecated" ) indent( output, indent ) output << START output << @string output << STOP end end end PK|]nFjjrexml/entity.rbnu[require 'rexml/child' require 'rexml/source' require 'rexml/xmltokens' module REXML # God, I hate DTDs. I really do. Why this idiot standard still # plagues us is beyond me. class Entity < Child include XMLTokens PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#" SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))} PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')} EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))" NDATADECL = "\\s+NDATA\\s+#{NAME}" PEREFERENCE = "%#{NAME};" ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))} PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})" ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))" PEDECL = "" GEDECL = "" ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um attr_reader :name, :external, :ref, :ndata, :pubid # Create a new entity. Simple entities can be constructed by passing a # name, value to the constructor; this creates a generic, plain entity # reference. For anything more complicated, you have to pass a Source to # the constructor with the entity definiton, or use the accessor methods. # +WARNING+: There is no validation of entity state except when the entity # is read from a stream. If you start poking around with the accessors, # you can easily create a non-conformant Entity. The best thing to do is # dump the stupid DTDs and use XMLSchema instead. # # e = Entity.new( 'amp', '&' ) def initialize stream, value=nil, parent=nil, reference=false super(parent) @ndata = @pubid = @value = @external = nil if stream.kind_of? Array @name = stream[1] if stream[-1] == '%' @reference = true stream.pop else @reference = false end if stream[2] =~ /SYSTEM|PUBLIC/ @external = stream[2] if @external == 'SYSTEM' @ref = stream[3] @ndata = stream[4] if stream.size == 5 else @pubid = stream[3] @ref = stream[4] end else @value = stream[2] end else @reference = reference @external = nil @name = stream @value = value end end # Evaluates whether the given string matchs an entity definition, # returning true if so, and false otherwise. def Entity::matches? string (ENTITYDECL =~ string) == 0 end # Evaluates to the unnormalized value of this entity; that is, replacing # all entities -- both %ent; and &ent; entities. This differs from # +value()+ in that +value+ only replaces %ent; entities. def unnormalized document.record_entity_expansion unless document.nil? v = value() return nil if v.nil? @unnormalized = Text::unnormalize(v, parent) @unnormalized end #once :unnormalized # Returns the value of this entity unprocessed -- raw. This is the # normalized value; that is, with all %ent; and &ent; entities intact def normalized @value end # Write out a fully formed, correct entity definition (assuming the Entity # object itself is valid.) # # out:: # An object implementing << to which the entity will be # output # indent:: # *DEPRECATED* and ignored def write out, indent=-1 out << '' end # Returns this entity as a string. See write(). def to_s rv = '' write rv rv end PEREFERENCE_RE = /#{PEREFERENCE}/um # Returns the value of this entity. At the moment, only internal entities # are processed. If the value contains internal references (IE, # %blah;), those are replaced with their values. IE, if the doctype # contains: # # # then: # doctype.entity('yada').value #-> "nanoo bar nanoo" def value if @value matches = @value.scan(PEREFERENCE_RE) rv = @value.clone if @parent matches.each do |entity_reference| entity_value = @parent.entity( entity_reference[0] ) rv.gsub!( /%#{entity_reference};/um, entity_value ) end end return rv end nil end end # This is a set of entity constants -- the ones defined in the XML # specification. These are +gt+, +lt+, +amp+, +quot+ and +apos+. module EntityConst # +>+ GT = Entity.new( 'gt', '>' ) # +<+ LT = Entity.new( 'lt', '<' ) # +&+ AMP = Entity.new( 'amp', '&' ) # +"+ QUOT = Entity.new( 'quot', '"' ) # +'+ APOS = Entity.new( 'apos', "'" ) end end PK|]uL rexml/streamlistener.rbnu[module REXML # A template for stream parser listeners. # Note that the declarations (attlistdecl, elementdecl, etc) are trivially # processed; REXML doesn't yet handle doctype entity declarations, so you # have to parse them out yourself. module StreamListener # Called when a tag is encountered. # @p name the tag name # @p attrs an array of arrays of attribute/value pairs, suitable for # use with assoc or rassoc. IE, # will result in # tag_start( "tag", # [["attr1","value1"],["attr2","value2"]]) def tag_start name, attrs end # Called when the end tag is reached. In the case of , tag_end # will be called immidiately after tag_start # @p the name of the tag def tag_end name end # Called when text is encountered in the document # @p text the text content. def text text end # Called when an instruction is encountered. EG: # @p name the instruction name; in the example, "xsl" # @p instruction the rest of the instruction. In the example, # "sheet='foo'" def instruction name, instruction end # Called when a comment is encountered. # @p comment The content of the comment def comment comment end # Handles a doctype declaration. Any attributes of the doctype which are # not supplied will be nil. # EG, # @p name the name of the doctype; EG, "me" # @p pub_sys "PUBLIC", "SYSTEM", or nil. EG, "PUBLIC" # @p long_name the supplied long name, or nil. EG, "foo" # @p uri the uri of the doctype, or nil. EG, "bar" def doctype name, pub_sys, long_name, uri end # Called when the doctype is done def doctype_end end # If a doctype includes an ATTLIST declaration, it will cause this # method to be called. The content is the declaration itself, unparsed. # EG, will come to this method as "el # attr CDATA #REQUIRED". This is the same for all of the .*decl # methods. def attlistdecl element_name, attributes, raw_content end # def elementdecl content end # # The argument passed to this method is an array of the entity # declaration. It can be in a number of formats, but in general it # returns (example, result): # # ["%", "YN", "'\"Yes\"'", "\""] # # ["%", "YN", "'Yes'", "s"] # # ["WhatHeSaid", "\"He said %YN;\"", "YN"] # # ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] # # ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] # # ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"] def entitydecl content end # def notationdecl content end # Called when %foo; is encountered in a doctype declaration. # @p content "foo" def entity content end # Called when is encountered in a document. # @p content "..." def cdata content end # Called when an XML PI is encountered in the document. # EG: # @p version the version attribute value. EG, "1.0" # @p encoding the encoding attribute value, or nil. EG, "utf" # @p standalone the standalone attribute value, or nil. EG, nil def xmldecl version, encoding, standalone end end end PK|]\ bI,, rexml/text.rbnu[require 'rexml/rexml' require 'rexml/entity' require 'rexml/doctype' require 'rexml/child' require 'rexml/doctype' require 'rexml/parseexception' module REXML # Represents text nodes in an XML document class Text < Child include Comparable # The order in which the substitutions occur SPECIALS = [ /&(?!#?[\w-]+;)/u, //u, /"/u, /'/u, /\r/u ] SUBSTITUTES = ['&', '<', '>', '"', ''', ' '] # Characters which are substituted in written strings SLAICEPS = [ '<', '>', '"', "'", '&' ] SETUTITSBUS = [ /</u, />/u, /"/u, /'/u, /&/u ] # If +raw+ is true, then REXML leaves the value alone attr_accessor :raw ILLEGAL = /(<|&(?!(#{Entity::NAME})|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));))/um NUMERICENTITY = /�*((?:\d+)|(?:x[a-fA-F0-9]+));/ # Constructor # +arg+ if a String, the content is set to the String. If a Text, # the object is shallowly cloned. # # +respect_whitespace+ (boolean, false) if true, whitespace is # respected # # +parent+ (nil) if this is a Parent object, the parent # will be set to this. # # +raw+ (nil) This argument can be given three values. # If true, then the value of used to construct this object is expected to # contain no unescaped XML markup, and REXML will not change the text. If # this value is false, the string may contain any characters, and REXML will # escape any and all defined entities whose values are contained in the # text. If this value is nil (the default), then the raw value of the # parent will be used as the raw value for this node. If there is no raw # value for the parent, and no value is supplied, the default is false. # Use this field if you have entities defined for some text, and you don't # want REXML to escape that text in output. # Text.new( "<&", false, nil, false ) #-> "<&" # Text.new( "<&", false, nil, false ) #-> "&lt;&amp;" # Text.new( "<&", false, nil, true ) #-> Parse exception # Text.new( "<&", false, nil, true ) #-> "<&" # # Assume that the entity "s" is defined to be "sean" # # and that the entity "r" is defined to be "russell" # Text.new( "sean russell" ) #-> "&s; &r;" # Text.new( "sean russell", false, nil, true ) #-> "sean russell" # # +entity_filter+ (nil) This can be an array of entities to match in the # supplied text. This argument is only useful if +raw+ is set to false. # Text.new( "sean russell", false, nil, false, ["s"] ) #-> "&s; russell" # Text.new( "sean russell", false, nil, true, ["s"] ) #-> "sean russell" # In the last example, the +entity_filter+ argument is ignored. # # +pattern+ INTERNAL USE ONLY def initialize(arg, respect_whitespace=false, parent=nil, raw=nil, entity_filter=nil, illegal=ILLEGAL ) @raw = false if parent super( parent ) @raw = parent.raw else @parent = nil end @raw = raw unless raw.nil? @entity_filter = entity_filter @normalized = @unnormalized = nil if arg.kind_of? String @string = arg.clone @string.squeeze!(" \n\t") unless respect_whitespace elsif arg.kind_of? Text @string = arg.to_s @raw = arg.raw elsif raise "Illegal argument of type #{arg.type} for Text constructor (#{arg})" end @string.gsub!( /\r\n?/, "\n" ) # check for illegal characters if @raw if @string =~ illegal raise "Illegal character '#{$1}' in raw string \"#{@string}\"" end end end def node_type :text end def empty? @string.size==0 end def clone return Text.new(self) end # Appends text to this text node. The text is appended in the +raw+ mode # of this text node. def <<( to_append ) @string << to_append.gsub( /\r\n?/, "\n" ) end # +other+ a String or a Text # +returns+ the result of (to_s <=> arg.to_s) def <=>( other ) to_s() <=> other.to_s end REFERENCE = /#{Entity::REFERENCE}/ # Returns the string value of this text node. This string is always # escaped, meaning that it is a valid XML text node string, and all # entities that can be escaped, have been inserted. This method respects # the entity filter set in the constructor. # # # Assume that the entity "s" is defined to be "sean", and that the # # entity "r" is defined to be "russell" # t = Text.new( "< & sean russell", false, nil, false, ['s'] ) # t.to_s #-> "< & &s; russell" # t = Text.new( "< & &s; russell", false, nil, false ) # t.to_s #-> "< & &s; russell" # u = Text.new( "sean russell", false, nil, true ) # u.to_s #-> "sean russell" def to_s return @string if @raw return @normalized if @normalized doctype = nil if @parent doc = @parent.document doctype = doc.doctype if doc end @normalized = Text::normalize( @string, doctype, @entity_filter ) end def inspect @string.inspect end # Returns the string value of this text. This is the text without # entities, as it might be used programmatically, or printed to the # console. This ignores the 'raw' attribute setting, and any # entity_filter. # # # Assume that the entity "s" is defined to be "sean", and that the # # entity "r" is defined to be "russell" # t = Text.new( "< & sean russell", false, nil, false, ['s'] ) # t.value #-> "< & sean russell" # t = Text.new( "< & &s; russell", false, nil, false ) # t.value #-> "< & sean russell" # u = Text.new( "sean russell", false, nil, true ) # u.value #-> "sean russell" def value @unnormalized if @unnormalized doctype = nil if @parent doc = @parent.document doctype = doc.doctype if doc end @unnormalized = Text::unnormalize( @string, doctype ) end # Sets the contents of this text node. This expects the text to be # unnormalized. It returns self. # # e = Element.new( "a" ) # e.add_text( "foo" ) # foo # e[0].value = "bar" # bar # e[0].value = "" # <a> def value=( val ) @string = val.gsub( /\r\n?/, "\n" ) @unnormalized = nil @normalized = nil @raw = false end def wrap(string, width, addnewline=false) # Recursively wrap string at width. return string if string.length <= width place = string.rindex(' ', width) # Position in string with last ' ' before cutoff if addnewline then return "\n" + string[0,place] + "\n" + wrap(string[place+1..-1], width) else return string[0,place] + "\n" + wrap(string[place+1..-1], width) end end def indent_text(string, level=1, style="\t", indentfirstline=true) return string if level < 0 new_string = '' string.each { |line| indent_string = style * level new_line = (indent_string + line).sub(/[\s]+$/,'') new_string << new_line } new_string.strip! unless indentfirstline return new_string end # == DEPRECATED # See REXML::Formatters # def write( writer, indent=-1, transitive=false, ie_hack=false ) Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters") formatter = if indent > -1 REXML::Formatters::Pretty.new( indent ) else REXML::Formatters::Default.new end formatter.write( self, writer ) end # FIXME # This probably won't work properly def xpath path = @parent.xpath path += "/text()" return path end # Writes out text, substituting special characters beforehand. # +out+ A String, IO, or any other object supporting <<( String ) # +input+ the text to substitute and the write out # # z=utf8.unpack("U*") # ascOut="" # z.each{|r| # if r < 0x100 # ascOut.concat(r.chr) # else # ascOut.concat(sprintf("&#x%x;", r)) # end # } # puts ascOut def write_with_substitution out, input copy = input.clone # Doing it like this rather than in a loop improves the speed copy.gsub!( SPECIALS[0], SUBSTITUTES[0] ) copy.gsub!( SPECIALS[1], SUBSTITUTES[1] ) copy.gsub!( SPECIALS[2], SUBSTITUTES[2] ) copy.gsub!( SPECIALS[3], SUBSTITUTES[3] ) copy.gsub!( SPECIALS[4], SUBSTITUTES[4] ) copy.gsub!( SPECIALS[5], SUBSTITUTES[5] ) out << copy end # Reads text, substituting entities def Text::read_with_substitution( input, illegal=nil ) copy = input.clone if copy =~ illegal raise ParseException.new( "malformed text: Illegal character #$& in \"#{copy}\"" ) end if illegal copy.gsub!( /\r\n?/, "\n" ) if copy.include? ?& copy.gsub!( SETUTITSBUS[0], SLAICEPS[0] ) copy.gsub!( SETUTITSBUS[1], SLAICEPS[1] ) copy.gsub!( SETUTITSBUS[2], SLAICEPS[2] ) copy.gsub!( SETUTITSBUS[3], SLAICEPS[3] ) copy.gsub!( SETUTITSBUS[4], SLAICEPS[4] ) copy.gsub!( /�*((?:\d+)|(?:x[a-f0-9]+));/ ) {|m| m=$1 #m='0' if m=='' m = "0#{m}" if m[0] == ?x [Integer(m)].pack('U*') } end copy end EREFERENCE = /&(?!#{Entity::NAME};)/ # Escapes all possible entities def Text::normalize( input, doctype=nil, entity_filter=nil ) copy = input.to_s # Doing it like this rather than in a loop improves the speed #copy = copy.gsub( EREFERENCE, '&' ) copy = copy.gsub( "&", "&" ) if doctype # Replace all ampersands that aren't part of an entity doctype.entities.each_value do |entity| copy = copy.gsub( entity.value, "&#{entity.name};" ) if entity.value and not( entity_filter and entity_filter.include?(entity) ) end else # Replace all ampersands that aren't part of an entity DocType::DEFAULT_ENTITIES.each_value do |entity| copy = copy.gsub(entity.value, "&#{entity.name};" ) end end copy end # Unescapes all possible entities def Text::unnormalize( string, doctype=nil, filter=nil, illegal=nil ) sum = 0 string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) { s = Text.expand($&, doctype, filter) if sum + s.bytesize > REXML.entity_expansion_text_limit raise "entity expansion has grown too large" else sum += s.bytesize end s } end def Text.expand(ref, doctype, filter) if ref[1] == ?# if ref[2] == ?x [ref[3...-1].to_i(16)].pack('U*') else [ref[2...-1].to_i].pack('U*') end elsif ref == '&' '&' elsif filter and filter.include?( ref[1...-1] ) ref elsif doctype doctype.entity( ref[1...-1] ) or ref else entity_value = DocType::DEFAULT_ENTITIES[ ref[1...-1] ] entity_value ? entity_value.value : ref end end end end PK|]rexml/element.rbnu[require "rexml/parent" require "rexml/namespace" require "rexml/attribute" require "rexml/cdata" require "rexml/xpath" require "rexml/parseexception" module REXML # An implementation note about namespaces: # As we parse, when we find namespaces we put them in a hash and assign # them a unique ID. We then convert the namespace prefix for the node # to the unique ID. This makes namespace lookup much faster for the # cost of extra memory use. We save the namespace prefix for the # context node and convert it back when we write it. @@namespaces = {} # Represents a tagged XML element. Elements are characterized by # having children, attributes, and names, and can themselves be # children. class Element < Parent include Namespace UNDEFINED = "UNDEFINED"; # The default name # Mechanisms for accessing attributes and child elements of this # element. attr_reader :attributes, :elements # The context holds information about the processing environment, such as # whitespace handling. attr_accessor :context # Constructor # arg:: # if not supplied, will be set to the default value. # If a String, the name of this object will be set to the argument. # If an Element, the object will be shallowly cloned; name, # attributes, and namespaces will be copied. Children will +not+ be # copied. # parent:: # if supplied, must be a Parent, and will be used as # the parent of this object. # context:: # If supplied, must be a hash containing context items. Context items # include: # * :respect_whitespace the value of this is :+all+ or an array of # strings being the names of the elements to respect # whitespace for. Defaults to :+all+. # * :compress_whitespace the value can be :+all+ or an array of # strings being the names of the elements to ignore whitespace on. # Overrides :+respect_whitespace+. # * :ignore_whitespace_nodes the value can be :+all+ or an array # of strings being the names of the elements in which to ignore # whitespace-only nodes. If this is set, Text nodes which contain only # whitespace will not be added to the document tree. # * :raw can be :+all+, or an array of strings being the names of # the elements to process in raw mode. In raw mode, special # characters in text is not converted to or from entities. def initialize( arg = UNDEFINED, parent=nil, context=nil ) super(parent) @elements = Elements.new(self) @attributes = Attributes.new(self) @context = context if arg.kind_of? String self.name = arg elsif arg.kind_of? Element self.name = arg.expanded_name arg.attributes.each_attribute{ |attribute| @attributes << Attribute.new( attribute ) } @context = arg.context end end def inspect rv = "<#@expanded_name" @attributes.each_attribute do |attr| rv << " " attr.write( rv, 0 ) end if children.size > 0 rv << "> ... " else rv << "/>" end end # Creates a shallow copy of self. # d = Document.new "" # new_a = d.root.clone # puts new_a # => "" def clone self.class.new self end # Evaluates to the root node of the document that this element # belongs to. If this element doesn't belong to a document, but does # belong to another Element, the parent's root will be returned, until the # earliest ancestor is found. # # Note that this is not the same as the document element. # In the following example, is the document element, and the root # node is the parent node of the document element. You may ask yourself # why the root node is useful: consider the doctype and XML declaration, # and any processing instructions before the document element... they # are children of the root node, or siblings of the document element. # The only time this isn't true is when an Element is created that is # not part of any Document. In this case, the ancestor that has no # parent acts as the root node. # d = Document.new '' # a = d[1] ; c = a[1][1] # d.root_node == d # TRUE # a.root_node # namely, d # c.root_node # again, d def root_node parent.nil? ? self : parent.root_node end def root return elements[1] if self.kind_of? Document return self if parent.kind_of? Document or parent.nil? return parent.root end # Evaluates to the document to which this element belongs, or nil if this # element doesn't belong to a document. def document rt = root rt.parent if rt end # Evaluates to +true+ if whitespace is respected for this element. This # is the case if: # 1. Neither :+respect_whitespace+ nor :+compress_whitespace+ has any value # 2. The context has :+respect_whitespace+ set to :+all+ or # an array containing the name of this element, and # :+compress_whitespace+ isn't set to :+all+ or an array containing the # name of this element. # The evaluation is tested against +expanded_name+, and so is namespace # sensitive. def whitespace @whitespace = nil if @context if @context[:respect_whitespace] @whitespace = (@context[:respect_whitespace] == :all or @context[:respect_whitespace].include? expanded_name) end @whitespace = false if (@context[:compress_whitespace] and (@context[:compress_whitespace] == :all or @context[:compress_whitespace].include? expanded_name) ) end @whitespace = true unless @whitespace == false @whitespace end def ignore_whitespace_nodes @ignore_whitespace_nodes = false if @context if @context[:ignore_whitespace_nodes] @ignore_whitespace_nodes = (@context[:ignore_whitespace_nodes] == :all or @context[:ignore_whitespace_nodes].include? expanded_name) end end end # Evaluates to +true+ if raw mode is set for this element. This # is the case if the context has :+raw+ set to :+all+ or # an array containing the name of this element. # # The evaluation is tested against +expanded_name+, and so is namespace # sensitive. def raw @raw = (@context and @context[:raw] and (@context[:raw] == :all or @context[:raw].include? expanded_name)) @raw end #once :whitespace, :raw, :ignore_whitespace_nodes ################################################# # Namespaces # ################################################# # Evaluates to an +Array+ containing the prefixes (names) of all defined # namespaces at this context node. # doc = Document.new("") # doc.elements['//b'].prefixes # -> ['x', 'y'] def prefixes prefixes = [] prefixes = parent.prefixes if parent prefixes |= attributes.prefixes return prefixes end def namespaces namespaces = {} namespaces = parent.namespaces if parent namespaces = namespaces.merge( attributes.namespaces ) return namespaces end # Evalutas to the URI for a prefix, or the empty string if no such # namespace is declared for this element. Evaluates recursively for # ancestors. Returns the default namespace, if there is one. # prefix:: # the prefix to search for. If not supplied, returns the default # namespace if one exists # Returns:: # the namespace URI as a String, or nil if no such namespace # exists. If the namespace is undefined, returns an empty string # doc = Document.new("") # b = doc.elements['//b'] # b.namespace # -> '1' # b.namespace("y") # -> '2' def namespace(prefix=nil) if prefix.nil? prefix = prefix() end if prefix == '' prefix = "xmlns" else prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns' end ns = attributes[ prefix ] ns = parent.namespace(prefix) if ns.nil? and parent ns = '' if ns.nil? and prefix == 'xmlns' return ns end # Adds a namespace to this element. # prefix:: # the prefix string, or the namespace URI if +uri+ is not # supplied # uri:: # the namespace URI. May be nil, in which +prefix+ is used as # the URI # Evaluates to: this Element # a = Element.new("a") # a.add_namespace("xmlns:foo", "bar" ) # a.add_namespace("foo", "bar") # shorthand for previous line # a.add_namespace("twiddle") # puts a #-> def add_namespace( prefix, uri=nil ) unless uri @attributes["xmlns"] = prefix else prefix = "xmlns:#{prefix}" unless prefix =~ /^xmlns:/ @attributes[ prefix ] = uri end self end # Removes a namespace from this node. This only works if the namespace is # actually declared in this node. If no argument is passed, deletes the # default namespace. # # Evaluates to: this element # doc = Document.new "" # doc.root.delete_namespace # puts doc # -> # doc.root.delete_namespace 'foo' # puts doc # -> def delete_namespace namespace="xmlns" namespace = "xmlns:#{namespace}" unless namespace == 'xmlns' attribute = attributes.get_attribute(namespace) attribute.remove unless attribute.nil? self end ################################################# # Elements # ################################################# # Adds a child to this element, optionally setting attributes in # the element. # element:: # optional. If Element, the element is added. # Otherwise, a new Element is constructed with the argument (see # Element.initialize). # attrs:: # If supplied, must be a Hash containing String name,value # pairs, which will be used to set the attributes of the new Element. # Returns:: the Element that was added # el = doc.add_element 'my-tag' # el = doc.add_element 'my-tag', {'attr1'=>'val1', 'attr2'=>'val2'} # el = Element.new 'my-tag' # doc.add_element el def add_element element, attrs=nil raise "First argument must be either an element name, or an Element object" if element.nil? el = @elements.add(element) attrs.each do |key, value| el.attributes[key]=Attribute.new(key,value,self) end if attrs.kind_of? Hash el end # Deletes a child element. # element:: # Must be an +Element+, +String+, or +Integer+. If Element, # the element is removed. If String, the element is found (via XPath) # and removed. This means that any parent can remove any # descendant. If Integer, the Element indexed by that number will be # removed. # Returns:: the element that was removed. # doc.delete_element "/a/b/c[@id='4']" # doc.delete_element doc.elements["//k"] # doc.delete_element 1 def delete_element element @elements.delete element end # Evaluates to +true+ if this element has at least one child Element # doc = Document.new "Text" # doc.root.has_elements # -> true # doc.elements["/a/b"].has_elements # -> false # doc.elements["/a/c"].has_elements # -> false def has_elements? !@elements.empty? end # Iterates through the child elements, yielding for each Element that # has a particular attribute set. # key:: # the name of the attribute to search for # value:: # the value of the attribute # max:: # (optional) causes this method to return after yielding # for this number of matching children # name:: # (optional) if supplied, this is an XPath that filters # the children to check. # # doc = Document.new "" # # Yields b, c, d # doc.root.each_element_with_attribute( 'id' ) {|e| p e} # # Yields b, d # doc.root.each_element_with_attribute( 'id', '1' ) {|e| p e} # # Yields b # doc.root.each_element_with_attribute( 'id', '1', 1 ) {|e| p e} # # Yields d # doc.root.each_element_with_attribute( 'id', '1', 0, 'd' ) {|e| p e} def each_element_with_attribute( key, value=nil, max=0, name=nil, &block ) # :yields: Element each_with_something( proc {|child| if value.nil? child.attributes[key] != nil else child.attributes[key]==value end }, max, name, &block ) end # Iterates through the children, yielding for each Element that # has a particular text set. # text:: # the text to search for. If nil, or not supplied, will iterate # over all +Element+ children that contain at least one +Text+ node. # max:: # (optional) causes this method to return after yielding # for this number of matching children # name:: # (optional) if supplied, this is an XPath that filters # the children to check. # # doc = Document.new 'bbd' # # Yields b, c, d # doc.each_element_with_text {|e|p e} # # Yields b, c # doc.each_element_with_text('b'){|e|p e} # # Yields b # doc.each_element_with_text('b', 1){|e|p e} # # Yields d # doc.each_element_with_text(nil, 0, 'd'){|e|p e} def each_element_with_text( text=nil, max=0, name=nil, &block ) # :yields: Element each_with_something( proc {|child| if text.nil? child.has_text? else child.text == text end }, max, name, &block ) end # Synonym for Element.elements.each def each_element( xpath=nil, &block ) # :yields: Element @elements.each( xpath, &block ) end # Synonym for Element.to_a # This is a little slower than calling elements.each directly. # xpath:: any XPath by which to search for elements in the tree # Returns:: an array of Elements that match the supplied path def get_elements( xpath ) @elements.to_a( xpath ) end # Returns the next sibling that is an element, or nil if there is # no Element sibling after this one # doc = Document.new 'text' # doc.root.elements['b'].next_element #-> # doc.root.elements['c'].next_element #-> nil def next_element element = next_sibling element = element.next_sibling until element.nil? or element.kind_of? Element return element end # Returns the previous sibling that is an element, or nil if there is # no Element sibling prior to this one # doc = Document.new 'text' # doc.root.elements['c'].previous_element #-> # doc.root.elements['b'].previous_element #-> nil def previous_element element = previous_sibling element = element.previous_sibling until element.nil? or element.kind_of? Element return element end ################################################# # Text # ################################################# # Evaluates to +true+ if this element has at least one Text child def has_text? not text().nil? end # A convenience method which returns the String value of the _first_ # child text element, if one exists, and +nil+ otherwise. # # Note that an element may have multiple Text elements, perhaps # separated by other children. Be aware that this method only returns # the first Text node. # # This method returns the +value+ of the first text child node, which # ignores the +raw+ setting, so always returns normalized text. See # the Text::value documentation. # # doc = Document.new "

    some text this is bold! more text

    " # # The element 'p' has two text elements, "some text " and " more text". # doc.root.text #-> "some text " def text( path = nil ) rv = get_text(path) return rv.value unless rv.nil? nil end # Returns the first child Text node, if any, or +nil+ otherwise. # This method returns the actual +Text+ node, rather than the String content. # doc = Document.new "

    some text this is bold! more text

    " # # The element 'p' has two text elements, "some text " and " more text". # doc.root.get_text.value #-> "some text " def get_text path = nil rv = nil if path element = @elements[ path ] rv = element.get_text unless element.nil? else rv = @children.find { |node| node.kind_of? Text } end return rv end # Sets the first Text child of this object. See text() for a # discussion about Text children. # # If a Text child already exists, the child is replaced by this # content. This means that Text content can be deleted by calling # this method with a nil argument. In this case, the next Text # child becomes the first Text child. In no case is the order of # any siblings disturbed. # text:: # If a String, a new Text child is created and added to # this Element as the first Text child. If Text, the text is set # as the first Child element. If nil, then any existing first Text # child is removed. # Returns:: this Element. # doc = Document.new '' # doc.root.text = 'Sean' #-> 'Sean' # doc.root.text = 'Elliott' #-> 'Elliott' # doc.root.add_element 'c' #-> 'Elliott' # doc.root.text = 'Russell' #-> 'Russell' # doc.root.text = nil #-> '' def text=( text ) if text.kind_of? String text = Text.new( text, whitespace(), nil, raw() ) elsif !text.nil? and !text.kind_of? Text text = Text.new( text.to_s, whitespace(), nil, raw() ) end old_text = get_text if text.nil? old_text.remove unless old_text.nil? else if old_text.nil? self << text else old_text.replace_with( text ) end end return self end # A helper method to add a Text child. Actual Text instances can # be added with regular Parent methods, such as add() and <<() # text:: # if a String, a new Text instance is created and added # to the parent. If Text, the object is added directly. # Returns:: this Element # e = Element.new('a') #-> # e.add_text 'foo' #-> foo # e.add_text Text.new(' bar') #-> foo bar # Note that at the end of this example, the branch has 3 nodes; the 'e' # element and 2 Text node children. def add_text( text ) if text.kind_of? String if @children[-1].kind_of? Text @children[-1] << text return end text = Text.new( text, whitespace(), nil, raw() ) end self << text unless text.nil? return self end def node_type :element end def xpath path_elements = [] cur = self path_elements << __to_xpath_helper( self ) while cur.parent cur = cur.parent path_elements << __to_xpath_helper( cur ) end return path_elements.reverse.join( "/" ) end ################################################# # Attributes # ################################################# def attribute( name, namespace=nil ) prefix = nil prefix = namespaces.index(namespace) if namespace prefix = nil if prefix == 'xmlns' attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" ) end # Evaluates to +true+ if this element has any attributes set, false # otherwise. def has_attributes? return !@attributes.empty? end # Adds an attribute to this element, overwriting any existing attribute # by the same name. # key:: # can be either an Attribute or a String. If an Attribute, # the attribute is added to the list of Element attributes. If String, # the argument is used as the name of the new attribute, and the value # parameter must be supplied. # value:: # Required if +key+ is a String, and ignored if the first argument is # an Attribute. This is a String, and is used as the value # of the new Attribute. This should be the unnormalized value of the # attribute (without entities). # Returns:: the Attribute added # e = Element.new 'e' # e.add_attribute( 'a', 'b' ) #-> # e.add_attribute( 'x:a', 'c' ) #-> # e.add_attribute Attribute.new('b', 'd') #-> def add_attribute( key, value=nil ) if key.kind_of? Attribute @attributes << key else @attributes[key] = value end end # Add multiple attributes to this element. # hash:: is either a hash, or array of arrays # el.add_attributes( {"name1"=>"value1", "name2"=>"value2"} ) # el.add_attributes( [ ["name1","value1"], ["name2"=>"value2"] ] ) def add_attributes hash if hash.kind_of? Hash hash.each_pair {|key, value| @attributes[key] = value } elsif hash.kind_of? Array hash.each { |value| @attributes[ value[0] ] = value[1] } end end # Removes an attribute # key:: # either an Attribute or a String. In either case, the # attribute is found by matching the attribute name to the argument, # and then removed. If no attribute is found, no action is taken. # Returns:: # the attribute removed, or nil if this Element did not contain # a matching attribute # e = Element.new('E') # e.add_attribute( 'name', 'Sean' ) #-> # r = e.add_attribute( 'sur:name', 'Russell' ) #-> # e.delete_attribute( 'name' ) #-> # e.delete_attribute( r ) #-> def delete_attribute(key) attr = @attributes.get_attribute(key) attr.remove unless attr.nil? end ################################################# # Other Utilities # ################################################# # Get an array of all CData children. # IMMUTABLE def cdatas find_all { |child| child.kind_of? CData }.freeze end # Get an array of all Comment children. # IMMUTABLE def comments find_all { |child| child.kind_of? Comment }.freeze end # Get an array of all Instruction children. # IMMUTABLE def instructions find_all { |child| child.kind_of? Instruction }.freeze end # Get an array of all Text children. # IMMUTABLE def texts find_all { |child| child.kind_of? Text }.freeze end # == DEPRECATED # See REXML::Formatters # # Writes out this element, and recursively, all children. # output:: # output an object which supports '<< string'; this is where the # document will be written. # indent:: # An integer. If -1, no indenting will be used; otherwise, the # indentation will be this number of spaces, and children will be # indented an additional amount. Defaults to -1 # transitive:: # If transitive is true and indent is >= 0, then the output will be # pretty-printed in such a way that the added whitespace does not affect # the parse tree of the document # ie_hack:: # Internet Explorer is the worst piece of crap to have ever been # written, with the possible exception of Windows itself. Since IE is # unable to parse proper XML, we have to provide a hack to generate XML # that IE's limited abilities can handle. This hack inserts a space # before the /> on empty tags. Defaults to false # # out = '' # doc.write( out ) #-> doc is written to the string 'out' # doc.write( $stdout ) #-> doc written to the console def write(writer=$stdout, indent=-1, transitive=false, ie_hack=false) Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters") formatter = if indent > -1 if transitive REXML::Formatters::Transitive.new( indent, ie_hack ) else REXML::Formatters::Pretty.new( indent, ie_hack ) end else REXML::Formatters::Default.new( ie_hack ) end formatter.write( self, output ) end private def __to_xpath_helper node rv = node.expanded_name.clone if node.parent results = node.parent.find_all {|n| n.kind_of?(REXML::Element) and n.expanded_name == node.expanded_name } if results.length > 1 idx = results.index( node ) rv << "[#{idx+1}]" end end rv end # A private helper method def each_with_something( test, max=0, name=nil ) num = 0 child=nil @elements.each( name ){ |child| yield child if test.call(child) and num += 1 return if max>0 and num == max } end end ######################################################################## # ELEMENTS # ######################################################################## # A class which provides filtering of children for Elements, and # XPath search support. You are expected to only encounter this class as # the element.elements object. Therefore, you are # _not_ expected to instantiate this yourself. class Elements include Enumerable # Constructor # parent:: the parent Element def initialize parent @element = parent end # Fetches a child element. Filters only Element children, regardless of # the XPath match. # index:: # the search parameter. This is either an Integer, which # will be used to find the index'th child Element, or an XPath, # which will be used to search for the Element. Because # of the nature of XPath searches, any element in the connected XML # document can be fetched through any other element. The # Integer index is 1-based, not 0-based. This means that the first # child element is at index 1, not 0, and the +n+th element is at index # +n+, not n-1. This is because XPath indexes element children # starting from 1, not 0, and the indexes should be the same. # name:: # optional, and only used in the first argument is an # Integer. In that case, the index'th child Element that has the # supplied name will be returned. Note again that the indexes start at 1. # Returns:: the first matching Element, or nil if no child matched # doc = Document.new '' # doc.root.elements[1] #-> # doc.root.elements['c'] #-> # doc.root.elements[2,'c'] #-> def []( index, name=nil) if index.kind_of? Integer raise "index (#{index}) must be >= 1" if index < 1 name = literalize(name) if name num = 0 child = nil @element.find { |child| child.kind_of? Element and (name.nil? ? true : child.has_name?( name )) and (num += 1) == index } else return XPath::first( @element, index ) #{ |element| # return element if element.kind_of? Element #} #return nil end end # Sets an element, replacing any previous matching element. If no # existing element is found ,the element is added. # index:: Used to find a matching element to replace. See [](). # element:: # The element to replace the existing element with # the previous element # Returns:: nil if no previous element was found. # # doc = Document.new '' # doc.root.elements[10] = Element.new('b') #-> # doc.root.elements[1] #-> # doc.root.elements[1] = Element.new('c') #-> # doc.root.elements['c'] = Element.new('d') #-> def []=( index, element ) previous = self[index] if previous.nil? @element.add element else previous.replace_with element end return previous end # Returns +true+ if there are no +Element+ children, +false+ otherwise def empty? @element.find{ |child| child.kind_of? Element}.nil? end # Returns the index of the supplied child (starting at 1), or -1 if # the element is not a child # element:: an +Element+ child def index element rv = 0 found = @element.find do |child| child.kind_of? Element and (rv += 1) and child == element end return rv if found == element return -1 end # Deletes a child Element # element:: # Either an Element, which is removed directly; an # xpath, where the first matching child is removed; or an Integer, # where the n'th Element is removed. # Returns:: the removed child # doc = Document.new '' # b = doc.root.elements[1] # doc.root.elements.delete b #-> # doc.elements.delete("a/c[@id='1']") #-> # doc.root.elements.delete 1 #-> def delete element if element.kind_of? Element @element.delete element else el = self[element] el.remove if el end end # Removes multiple elements. Filters for Element children, regardless of # XPath matching. # xpath:: all elements matching this String path are removed. # Returns:: an Array of Elements that have been removed # doc = Document.new '' # deleted = doc.elements.delete_all 'a/c' #-> [, , , ] def delete_all( xpath ) rv = [] XPath::each( @element, xpath) {|element| rv << element if element.kind_of? Element } rv.each do |element| @element.delete element element.remove end return rv end # Adds an element # element:: # if supplied, is either an Element, String, or # Source (see Element.initialize). If not supplied or nil, a # new, default Element will be constructed # Returns:: the added Element # a = Element.new('a') # a.elements.add(Element.new('b')) #-> # a.elements.add('c') #-> def add element=nil rv = nil if element.nil? Element.new("", self, @element.context) elsif not element.kind_of?(Element) Element.new(element, self, @element.context) else @element << element element.context = @element.context element end end alias :<< :add # Iterates through all of the child Elements, optionally filtering # them by a given XPath # xpath:: # optional. If supplied, this is a String XPath, and is used to # filter the children, so that only matching children are yielded. Note # that XPaths are automatically filtered for Elements, so that # non-Element children will not be yielded # doc = Document.new 'sean' # doc.root.each {|e|p e} #-> Yields b, c, d, b, c, d elements # doc.root.each('b') {|e|p e} #-> Yields b, b elements # doc.root.each('child::node()') {|e|p e} # #-> Yields , , , , , # XPath.each(doc.root, 'child::node()', &block) # #-> Yields , , , sean, , , def each( xpath=nil, &block) XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element } end def collect( xpath=nil, &block ) collection = [] XPath::each( @element, xpath ) {|e| collection << yield(e) if e.kind_of?(Element) } collection end def inject( xpath=nil, initial=nil, &block ) first = true XPath::each( @element, xpath ) {|e| if (e.kind_of? Element) if (first and initial == nil) initial = e first = false else initial = yield( initial, e ) if e.kind_of? Element end end } initial end # Returns the number of +Element+ children of the parent object. # doc = Document.new 'seanelliottrussell' # doc.root.size #-> 6, 3 element and 3 text nodes # doc.root.elements.size #-> 3 def size count = 0 @element.each {|child| count+=1 if child.kind_of? Element } count end # Returns an Array of Element children. An XPath may be supplied to # filter the children. Only Element children are returned, even if the # supplied XPath matches non-Element children. # doc = Document.new 'seanelliott' # doc.root.elements.to_a #-> [ , ] # doc.root.elements.to_a("child::node()") #-> [ , ] # XPath.match(doc.root, "child::node()") #-> [ sean, , elliott, ] def to_a( xpath=nil ) rv = XPath.match( @element, xpath ) return rv.find_all{|e| e.kind_of? Element} if xpath rv end private # Private helper class. Removes quotes from quoted strings def literalize name name = name[1..-2] if name[0] == ?' or name[0] == ?" #' name end end ######################################################################## # ATTRIBUTES # ######################################################################## # A class that defines the set of Attributes of an Element and provides # operations for accessing elements in that set. class Attributes < Hash # Constructor # element:: the Element of which this is an Attribute def initialize element @element = element end # Fetches an attribute value. If you want to get the Attribute itself, # use get_attribute() # name:: an XPath attribute name. Namespaces are relevant here. # Returns:: # the String value of the matching attribute, or +nil+ if no # matching attribute was found. This is the unnormalized value # (with entities expanded). # # doc = Document.new "" # doc.root.attributes['att'] #-> '<' # doc.root.attributes['bar:att'] #-> '2' def [](name) attr = get_attribute(name) return attr.value unless attr.nil? return nil end def to_a values.flatten end # Returns the number of attributes the owning Element contains. # doc = Document "" # doc.root.attributes.length #-> 3 def length c = 0 each_attribute { c+=1 } c end alias :size :length # Iterates over the attributes of an Element. Yields actual Attribute # nodes, not String values. # # doc = Document.new '' # doc.root.attributes.each_attribute {|attr| # p attr.expanded_name+" => "+attr.value # } def each_attribute # :yields: attribute each_value do |val| if val.kind_of? Attribute yield val else val.each_value { |atr| yield atr } end end end # Iterates over each attribute of an Element, yielding the expanded name # and value as a pair of Strings. # # doc = Document.new '' # doc.root.attributes.each {|name, value| p name+" => "+value } def each each_attribute do |attr| yield attr.expanded_name, attr.value end end # Fetches an attribute # name:: # the name by which to search for the attribute. Can be a # prefix:name namespace name. # Returns:: The first matching attribute, or nil if there was none. This # value is an Attribute node, not the String value of the attribute. # doc = Document.new '' # doc.root.attributes.get_attribute("foo").value #-> "2" # doc.root.attributes.get_attribute("x:foo").value #-> "1" def get_attribute( name ) attr = fetch( name, nil ) if attr.nil? return nil if name.nil? # Look for prefix name =~ Namespace::NAMESPLIT prefix, n = $1, $2 if prefix attr = fetch( n, nil ) # check prefix if attr == nil elsif attr.kind_of? Attribute return attr if prefix == attr.prefix else attr = attr[ prefix ] return attr end end element_document = @element.document if element_document and element_document.doctype expn = @element.expanded_name expn = element_document.doctype.name if expn.size == 0 attr_val = element_document.doctype.attribute_of(expn, name) return Attribute.new( name, attr_val ) if attr_val end return nil end if attr.kind_of? Hash attr = attr[ @element.prefix ] end return attr end # Sets an attribute, overwriting any existing attribute value by the # same name. Namespace is significant. # name:: the name of the attribute # value:: # (optional) If supplied, the value of the attribute. If # nil, any existing matching attribute is deleted. # Returns:: # Owning element # doc = Document.new "" # doc.root.attributes['y:foo'] = '2' # doc.root.attributes['foo'] = '4' # doc.root.attributes['x:foo'] = nil def []=( name, value ) if value.nil? # Delete the named attribute attr = get_attribute(name) delete attr return end element_document = @element.document unless value.kind_of? Attribute if @element.document and @element.document.doctype value = Text::normalize( value, @element.document.doctype ) else value = Text::normalize( value, nil ) end value = Attribute.new(name, value) end value.element = @element old_attr = fetch(value.name, nil) if old_attr.nil? store(value.name, value) elsif old_attr.kind_of? Hash old_attr[value.prefix] = value elsif old_attr.prefix != value.prefix # Check for conflicting namespaces raise ParseException.new( "Namespace conflict in adding attribute \"#{value.name}\": "+ "Prefix \"#{old_attr.prefix}\" = "+ "\"#{@element.namespace(old_attr.prefix)}\" and prefix "+ "\"#{value.prefix}\" = \"#{@element.namespace(value.prefix)}\"") if value.prefix != "xmlns" and old_attr.prefix != "xmlns" and @element.namespace( old_attr.prefix ) == @element.namespace( value.prefix ) store value.name, { old_attr.prefix => old_attr, value.prefix => value } else store value.name, value end return @element end # Returns an array of Strings containing all of the prefixes declared # by this set of # attributes. The array does not include the default # namespace declaration, if one exists. # doc = Document.new("") # prefixes = doc.root.attributes.prefixes #-> ['x', 'y'] def prefixes ns = [] each_attribute do |attribute| ns << attribute.name if attribute.prefix == 'xmlns' end if @element.document and @element.document.doctype expn = @element.expanded_name expn = @element.document.doctype.name if expn.size == 0 @element.document.doctype.attributes_of(expn).each { |attribute| ns << attribute.name if attribute.prefix == 'xmlns' } end ns end def namespaces namespaces = {} each_attribute do |attribute| namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns' end if @element.document and @element.document.doctype expn = @element.expanded_name expn = @element.document.doctype.name if expn.size == 0 @element.document.doctype.attributes_of(expn).each { |attribute| namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns' } end namespaces end # Removes an attribute # attribute:: # either a String, which is the name of the attribute to remove -- # namespaces are significant here -- or the attribute to remove. # Returns:: the owning element # doc = Document.new "" # doc.root.attributes.delete 'foo' #-> " # doc.root.attributes.delete 'x:foo' #-> " # attr = doc.root.attributes.get_attribute('y:foo') # doc.root.attributes.delete attr #-> " def delete( attribute ) name = nil prefix = nil if attribute.kind_of? Attribute name = attribute.name prefix = attribute.prefix else attribute =~ Namespace::NAMESPLIT prefix, name = $1, $2 prefix = '' unless prefix end old = fetch(name, nil) attr = nil if old.kind_of? Hash # the supplied attribute is one of many attr = old.delete(prefix) if old.size == 1 repl = nil old.each_value{|v| repl = v} store name, repl end elsif old.nil? return @element else # the supplied attribute is a top-level one attr = old res = super(name) end @element end # Adds an attribute, overriding any existing attribute by the # same name. Namespaces are significant. # attribute:: An Attribute def add( attribute ) self[attribute.name] = attribute end alias :<< :add # Deletes all attributes matching a name. Namespaces are significant. # name:: # A String; all attributes that match this path will be removed # Returns:: an Array of the Attributes that were removed def delete_all( name ) rv = [] each_attribute { |attribute| rv << attribute if attribute.expanded_name == name } rv.each{ |attr| attr.remove } return rv end # The +get_attribute_ns+ method retrieves a method by its namespace # and name. Thus it is possible to reliably identify an attribute # even if an XML processor has changed the prefix. # # Method contributed by Henrik Martensson def get_attribute_ns(namespace, name) each_attribute() { |attribute| if name == attribute.name && namespace == attribute.namespace() return attribute end } nil end end end PK|] S__rexml/formatters/pretty.rbnu[require 'rexml/formatters/default' module REXML module Formatters # Pretty-prints an XML document. This destroys whitespace in text nodes # and will insert carriage returns and indentations. # # TODO: Add an option to print attributes on new lines class Pretty < Default # If compact is set to true, then the formatter will attempt to use as # little space as possible attr_accessor :compact # The width of a page. Used for formatting text attr_accessor :width # Create a new pretty printer. # # output:: # An object implementing '<<(String)', to which the output will be written. # indentation:: # An integer greater than 0. The indentation of each level will be # this number of spaces. If this is < 1, the behavior of this object # is undefined. Defaults to 2. # ie_hack:: # If true, the printer will insert whitespace before closing empty # tags, thereby allowing Internet Explorer's feeble XML parser to # function. Defaults to false. def initialize( indentation=2, ie_hack=false ) @indentation = indentation @level = 0 @ie_hack = ie_hack @width = 80 end protected def write_element(node, output) output << ' '*@level output << "<#{node.expanded_name}" node.attributes.each_attribute do |attr| output << " " attr.write( output ) end unless node.attributes.empty? if node.children.empty? if @ie_hack output << " " end output << "/" else output << ">" # If compact and all children are text, and if the formatted output # is less than the specified width, then try to print everything on # one line skip = false if compact if node.children.inject(true) {|s,c| s & c.kind_of?(Text)} string = "" old_level = @level @level = 0 node.children.each { |child| write( child, string ) } @level = old_level if string.length < @width output << string skip = true end end end unless skip output << "\n" @level += @indentation node.children.each { |child| next if child.kind_of?(Text) and child.to_s.strip.length == 0 write( child, output ) output << "\n" } @level -= @indentation output << ' '*@level end output << "" end def write_text( node, output ) s = node.to_s() s.gsub!(/\s/,' ') s.squeeze!(" ") s = wrap(s, 80-@level) s = indent_text(s, @level, " ", true) output << (' '*@level + s) end def write_comment( node, output) output << ' ' * @level super end def write_cdata( node, output) output << ' ' * @level super end def write_document( node, output ) # Ok, this is a bit odd. All XML documents have an XML declaration, # but it may not write itself if the user didn't specifically add it, # either through the API or in the input document. If it doesn't write # itself, then we don't need a carriage return... which makes this # logic more complex. node.children.each { |child| next if child == node.children[-1] and child.instance_of?(Text) unless child == node.children[0] or child.instance_of?(Text) or (child == node.children[1] and !node.children[0].writethis) output << "\n" end write( child, output ) } end private def indent_text(string, level=1, style="\t", indentfirstline=true) return string if level < 0 string.gsub(/\n/, "\n#{style*level}") end def wrap(string, width) # Recursively wrap string at width. return string if string.length <= width place = string.rindex(' ', width) # Position in string with last ' ' before cutoff return string if place.nil? return string[0,place] + "\n" + wrap(string[place+1..-1], width) end end end end PK|]W rexml/formatters/default.rbnu[module REXML module Formatters class Default # Prints out the XML document with no formatting -- except if id_hack is # set. # # ie_hack:: # If set to true, then inserts whitespace before the close of an empty # tag, so that IE's bad XML parser doesn't choke. def initialize( ie_hack=false ) @ie_hack = ie_hack end # Writes the node to some output. # # node:: # The node to write # output:: # A class implementing <<. Pass in an Output object to # change the output encoding. def write( node, output ) case node when Document if node.xml_decl.encoding != "UTF-8" && !output.kind_of?(Output) output = Output.new( output, node.xml_decl.encoding ) end write_document( node, output ) when Element write_element( node, output ) when Declaration, ElementDecl, NotationDecl, ExternalEntity, Entity, Attribute, AttlistDecl node.write( output,-1 ) when Instruction write_instruction( node, output ) when DocType, XMLDecl node.write( output ) when Comment write_comment( node, output ) when CData write_cdata( node, output ) when Text write_text( node, output ) else raise Exception.new("XML FORMATTING ERROR") end end protected def write_document( node, output ) node.children.each { |child| write( child, output ) } end def write_element( node, output ) output << "<#{node.expanded_name}" node.attributes.each_attribute do |attr| output << " " attr.write( output ) end unless node.attributes.empty? if node.children.empty? output << " " if @ie_hack output << "/" else output << ">" node.children.each { |child| write( child, output ) } output << "" end def write_text( node, output ) output << node.to_s() end def write_comment( node, output ) output << Comment::START output << node.to_s output << Comment::STOP end def write_cdata( node, output ) output << CData::START output << node.to_s output << CData::STOP end def write_instruction( node, output ) output << Instruction::START.sub(/\\/u, '') output << node.target output << ' ' output << node.content output << Instruction::STOP.sub(/\\/u, '') end end end end PK|]˂o-rexml/formatters/transitive.rbnu[require 'rexml/formatters/pretty' module REXML module Formatters # The Transitive formatter writes an XML document that parses to an # identical document as the source document. This means that no extra # whitespace nodes are inserted, and whitespace within text nodes is # preserved. Within these constraints, the document is pretty-printed, # with whitespace inserted into the metadata to introduce formatting. # # Note that this is only useful if the original XML is not already # formatted. Since this formatter does not alter whitespace nodes, the # results of formatting already formatted XML will be odd. class Transitive < Default def initialize( indentation=2 ) @indentation = indentation @level = 0 end protected def write_element( node, output ) output << "<#{node.expanded_name}" node.attributes.each_attribute do |attr| output << " " attr.write( output ) end unless node.attributes.empty? output << "\n" output << ' '*@level if node.children.empty? output << "/" else output << ">" # If compact and all children are text, and if the formatted output # is less than the specified width, then try to print everything on # one line skip = false @level += @indentation node.children.each { |child| write( child, output ) } @level -= @indentation output << "" end def write_text( node, output ) output << node.to_s() end end end end PK|]rexml/doctype.rbnu[require "rexml/parent" require "rexml/parseexception" require "rexml/namespace" require 'rexml/entity' require 'rexml/attlistdecl' require 'rexml/xmltokens' module REXML # Represents an XML DOCTYPE declaration; that is, the contents of . DOCTYPES can be used to declare the DTD of a document, as well as # being used to declare entities used in the document. class DocType < Parent include XMLTokens START = "" SYSTEM = "SYSTEM" PUBLIC = "PUBLIC" DEFAULT_ENTITIES = { 'gt'=>EntityConst::GT, 'lt'=>EntityConst::LT, 'quot'=>EntityConst::QUOT, "apos"=>EntityConst::APOS } # name is the name of the doctype # external_id is the referenced DTD, if given attr_reader :name, :external_id, :entities, :namespaces # Constructor # # dt = DocType.new( 'foo', '-//I/Hate/External/IDs' ) # # # dt = DocType.new( doctype_to_clone ) # # Incomplete. Shallow clone of doctype # # +Note+ that the constructor: # # Doctype.new( Source.new( "" ) ) # # is _deprecated_. Do not use it. It will probably disappear. def initialize( first, parent=nil ) @entities = DEFAULT_ENTITIES @long_name = @uri = nil if first.kind_of? String super() @name = first @external_id = parent elsif first.kind_of? DocType super( parent ) @name = first.name @external_id = first.external_id elsif first.kind_of? Array super( parent ) @name = first[0] @external_id = first[1] @long_name = first[2] @uri = first[3] elsif first.kind_of? Source super( parent ) parser = Parsers::BaseParser.new( first ) event = parser.pull if event[0] == :start_doctype @name, @external_id, @long_name, @uri, = event[1..-1] end else super() end end def node_type :doctype end def attributes_of element rv = [] each do |child| child.each do |key,val| rv << Attribute.new(key,val) end if child.kind_of? AttlistDecl and child.element_name == element end rv end def attribute_of element, attribute att_decl = find do |child| child.kind_of? AttlistDecl and child.element_name == element and child.include? attribute end return nil unless att_decl att_decl[attribute] end def clone DocType.new self end # output:: # Where to write the string # indent:: # An integer. If -1, no indentation will be used; otherwise, the # indentation will be this number of spaces, and children will be # indented an additional amount. # transitive:: # Ignored # ie_hack:: # Ignored def write( output, indent=0, transitive=false, ie_hack=false ) f = REXML::Formatters::Default.new indent( output, indent ) output << START output << ' ' output << @name output << " #@external_id" if @external_id output << " #{@long_name.inspect}" if @long_name output << " #{@uri.inspect}" if @uri unless @children.empty? next_indent = indent + 1 output << ' [' child = nil # speed @children.each { |child| output << "\n" f.write( child, output ) } output << "\n]" end output << STOP end def context @parent.context end def entity( name ) @entities[name].unnormalized if @entities[name] end def add child super(child) @entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES @entities[ child.name ] = child if child.kind_of? Entity end # This method retrieves the public identifier identifying the document's # DTD. # # Method contributed by Henrik Martensson def public case @external_id when "SYSTEM" nil when "PUBLIC" strip_quotes(@long_name) end end # This method retrieves the system identifier identifying the document's DTD # # Method contributed by Henrik Martensson def system case @external_id when "SYSTEM" strip_quotes(@long_name) when "PUBLIC" @uri.kind_of?(String) ? strip_quotes(@uri) : nil end end # This method returns a list of notations that have been declared in the # _internal_ DTD subset. Notations in the external DTD subset are not # listed. # # Method contributed by Henrik Martensson def notations children().select {|node| node.kind_of?(REXML::NotationDecl)} end # Retrieves a named notation. Only notations declared in the internal # DTD subset can be retrieved. # # Method contributed by Henrik Martensson def notation(name) notations.find { |notation_decl| notation_decl.name == name } end private # Method contributed by Henrik Martensson def strip_quotes(quoted_string) quoted_string =~ /^[\'\"].*[\´\"]$/ ? quoted_string[1, quoted_string.length-2] : quoted_string end end # We don't really handle any of these since we're not a validating # parser, so we can be pretty dumb about them. All we need to be able # to do is spew them back out on a write() # This is an abstract class. You never use this directly; it serves as a # parent class for the specific declarations. class Declaration < Child def initialize src super() @string = src end def to_s @string+'>' end # == DEPRECATED # See REXML::Formatters # def write( output, indent ) output << to_s end end public class ElementDecl < Declaration def initialize( src ) super end end class ExternalEntity < Child def initialize( src ) super() @entity = src end def to_s @entity end def write( output, indent ) output << @entity end end class NotationDecl < Child attr_accessor :public, :system def initialize name, middle, pub, sys super(nil) @name = name @middle = middle @public = pub @system = sys end def to_s "" end def write( output, indent=-1 ) output << to_s end # This method retrieves the name of the notation. # # Method contributed by Henrik Martensson def name @name end end end PK|]K7rexml/document.rbnu[require "rexml/element" require "rexml/xmldecl" require "rexml/source" require "rexml/comment" require "rexml/doctype" require "rexml/instruction" require "rexml/rexml" require "rexml/parseexception" require "rexml/output" require "rexml/parsers/baseparser" require "rexml/parsers/streamparser" require "rexml/parsers/treeparser" module REXML # Represents a full XML document, including PIs, a doctype, etc. A # Document has a single child that can be accessed by root(). # Note that if you want to have an XML declaration written for a document # you create, you must add one; REXML documents do not write a default # declaration for you. See |DECLARATION| and |write|. class Document < Element # A convenient default XML declaration. If you want an XML declaration, # the easiest way to add one is mydoc << Document::DECLARATION # +DEPRECATED+ # Use: mydoc << XMLDecl.default DECLARATION = XMLDecl.default # Constructor # @param source if supplied, must be a Document, String, or IO. # Documents have their context and Element attributes cloned. # Strings are expected to be valid XML documents. IOs are expected # to be sources of valid XML documents. # @param context if supplied, contains the context of the document; # this should be a Hash. def initialize( source = nil, context = {} ) @entity_expansion_count = 0 super() @context = context return if source.nil? if source.kind_of? Document @context = source.context super source else build( source ) end end def node_type :document end # Should be obvious def clone Document.new self end # According to the XML spec, a root node has no expanded name def expanded_name '' #d = doc_type #d ? d.name : "UNDEFINED" end alias :name :expanded_name # We override this, because XMLDecls and DocTypes must go at the start # of the document def add( child ) if child.kind_of? XMLDecl @children.unshift child child.parent = self elsif child.kind_of? DocType # Find first Element or DocType node and insert the decl right # before it. If there is no such node, just insert the child at the # end. If there is a child and it is an DocType, then replace it. insert_before_index = 0 @children.find { |x| insert_before_index += 1 x.kind_of?(Element) || x.kind_of?(DocType) } if @children[ insert_before_index ] # Not null = not end of list if @children[ insert_before_index ].kind_of DocType @children[ insert_before_index ] = child else @children[ index_before_index-1, 0 ] = child end else # Insert at end of list @children[insert_before_index] = child end child.parent = self else rv = super raise "attempted adding second root element to document" if @elements.size > 1 rv end end alias :<< :add def add_element(arg=nil, arg2=nil) rv = super raise "attempted adding second root element to document" if @elements.size > 1 rv end # @return the root Element of the document, or nil if this document # has no children. def root elements[1] #self #@children.find { |item| item.kind_of? Element } end # @return the DocType child of the document, if one exists, # and nil otherwise. def doctype @children.find { |item| item.kind_of? DocType } end # @return the XMLDecl of this document; if no XMLDecl has been # set, the default declaration is returned. def xml_decl rv = @children[0] return rv if rv.kind_of? XMLDecl rv = @children.unshift(XMLDecl.default)[0] end # @return the XMLDecl version of this document as a String. # If no XMLDecl has been set, returns the default version. def version xml_decl().version end # @return the XMLDecl encoding of this document as a String. # If no XMLDecl has been set, returns the default encoding. def encoding xml_decl().encoding end # @return the XMLDecl standalone value of this document as a String. # If no XMLDecl has been set, returns the default setting. def stand_alone? xml_decl().stand_alone? end # Write the XML tree out, optionally with indent. This writes out the # entire XML document, including XML declarations, doctype declarations, # and processing instructions (if any are given). # # A controversial point is whether Document should always write the XML # declaration () whether or not one is given by the # user (or source document). REXML does not write one if one was not # specified, because it adds unnecessary bandwidth to applications such # as XML-RPC. # # See also the classes in the rexml/formatters package for the proper way # to change the default formatting of XML output # # _Examples_ # Document.new("").serialize # # output_string = "" # tr = Transitive.new( output_string ) # Document.new("").serialize( tr ) # # output:: # output an object which supports '<< string'; this is where the # document will be written. # indent:: # An integer. If -1, no indenting will be used; otherwise, the # indentation will be twice this number of spaces, and children will be # indented an additional amount. For a value of 3, every item will be # indented 3 more levels, or 6 more spaces (2 * 3). Defaults to -1 # trans:: # If transitive is true and indent is >= 0, then the output will be # pretty-printed in such a way that the added whitespace does not affect # the absolute *value* of the document -- that is, it leaves the value # and number of Text nodes in the document unchanged. # ie_hack:: # Internet Explorer is the worst piece of crap to have ever been # written, with the possible exception of Windows itself. Since IE is # unable to parse proper XML, we have to provide a hack to generate XML # that IE's limited abilities can handle. This hack inserts a space # before the /> on empty tags. Defaults to false def write( output=$stdout, indent=-1, trans=false, ie_hack=false ) if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output) output = Output.new( output, xml_decl.encoding ) end formatter = if indent > -1 if trans REXML::Formatters::Transitive.new( indent, ie_hack ) else REXML::Formatters::Pretty.new( indent, ie_hack ) end else REXML::Formatters::Default.new( ie_hack ) end formatter.write( self, output ) end def Document::parse_stream( source, listener ) Parsers::StreamParser.new( source, listener ).parse end @@entity_expansion_limit = 10_000 # Set the entity expansion limit. By default the limit is set to 10000. def Document::entity_expansion_limit=( val ) @@entity_expansion_limit = val end # Get the entity expansion limit. By default the limit is set to 10000. def Document::entity_expansion_limit return @@entity_expansion_limit end # Set the entity expansion limit. By default the limit is set to 10240. # # Deprecated. Use REXML.entity_expansion_text_limit= instead. def Document::entity_expansion_text_limit=( val ) REXML.entity_expansion_text_limit = val end # Get the entity expansion limit. By default the limit is set to 10000. # # Deprecated. Use REXML.entity_expansion_text_limit instead. def Document::entity_expansion_text_limit return REXML.entity_expansion_text_limit end attr_reader :entity_expansion_count def record_entity_expansion @entity_expansion_count += 1 if @entity_expansion_count > @@entity_expansion_limit raise "number of entity expansions exceeded, processing aborted." end end private def build( source ) Parsers::TreeParser.new( source, self ).parse end end end PK|]3%rexml/xmltokens.rbnu[module REXML # Defines a number of tokens used for parsing XML. Not for general # consumption. module XMLTokens NCNAME_STR= '[\w:][\-\w\d.]*' NAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}" NAMECHAR = '[\-\w\d\.:]' NAME = "([\\w:]#{NAMECHAR}*)" NMTOKEN = "(?:#{NAMECHAR})+" NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*" REFERENCE = "(?:&#{NAME};|&#\\d+;|&#x[0-9a-fA-F]+;)" #REFERENCE = "(?:#{ENTITYREF}|#{CHARREF})" #ENTITYREF = "&#{NAME};" #CHARREF = "&#\\d+;|&#x[0-9a-fA-F]+;" end end PK|]4 a..rexml/attlistdecl.rbnu[#vim:ts=2 sw=2 noexpandtab: require 'rexml/child' require 'rexml/source' module REXML # This class needs: # * Documentation # * Work! Not all types of attlists are intelligently parsed, so we just # spew back out what we get in. This works, but it would be better if # we formatted the output ourselves. # # AttlistDecls provide *just* enough support to allow namespace # declarations. If you need some sort of generalized support, or have an # interesting idea about how to map the hideous, terrible design of DTD # AttlistDecls onto an intuitive Ruby interface, let me know. I'm desperate # for anything to make DTDs more palateable. class AttlistDecl < Child include Enumerable # What is this? Got me. attr_reader :element_name # Create an AttlistDecl, pulling the information from a Source. Notice # that this isn't very convenient; to create an AttlistDecl, you basically # have to format it yourself, and then have the initializer parse it. # Sorry, but for the forseeable future, DTD support in REXML is pretty # weak on convenience. Have I mentioned how much I hate DTDs? def initialize(source) super() if (source.kind_of? Array) @element_name, @pairs, @contents = *source end end # Access the attlist attribute/value pairs. # value = attlist_decl[ attribute_name ] def [](key) @pairs[key] end # Whether an attlist declaration includes the given attribute definition # if attlist_decl.include? "xmlns:foobar" def include?(key) @pairs.keys.include? key end # Iterate over the key/value pairs: # attlist_decl.each { |attribute_name, attribute_value| ... } def each(&block) @pairs.each(&block) end # Write out exactly what we got in. def write out, indent=-1 out << @contents end def node_type :attlistdecl end end end PK|]WR gserver.rbnu[# # Copyright (C) 2001 John W. Small All Rights Reserved # # Author:: John W. Small # Documentation:: Gavin Sinclair # Licence:: Freeware. # # See the class GServer for documentation. # require "socket" require "thread" # # GServer implements a generic server, featuring thread pool management, # simple logging, and multi-server management. See HttpServer in # xmlrpc/httpserver.rb in the Ruby standard library for an example of # GServer in action. # # Any kind of application-level server can be implemented using this class. # It accepts multiple simultaneous connections from clients, up to an optional # maximum number. Several _services_ (i.e. one service per TCP port) can be # run simultaneously, and stopped at any time through the class method # GServer.stop(port). All the threading issues are handled, saving # you the effort. All events are optionally logged, but you can provide your # own event handlers if you wish. # # === Example # # Using GServer is simple. Below we implement a simple time server, run it, # query it, and shut it down. Try this code in +irb+: # # require 'gserver' # # # # # A server that returns the time in seconds since 1970. # # # class TimeServer < GServer # def initialize(port=10001, *args) # super(port, *args) # end # def serve(io) # io.puts(Time.now.to_i) # end # end # # # Run the server with logging enabled (it's a separate thread). # server = TimeServer.new # server.audit = true # Turn logging on. # server.start # # # *** Now point your browser to http://localhost:10001 to see it working *** # # # See if it's still running. # GServer.in_service?(10001) # -> true # server.stopped? # -> false # # # Shut the server down gracefully. # server.shutdown # # # Alternatively, stop it immediately. # GServer.stop(10001) # # or, of course, "server.stop". # # All the business of accepting connections and exception handling is taken # care of. All we have to do is implement the method that actually serves the # client. # # === Advanced # # As the example above shows, the way to use GServer is to subclass it to # create a specific server, overriding the +serve+ method. You can override # other methods as well if you wish, perhaps to collect statistics, or emit # more detailed logging. # # connecting # disconnecting # starting # stopping # # The above methods are only called if auditing is enabled. # # You can also override +log+ and +error+ if, for example, you wish to use a # more sophisticated logging system. # class GServer DEFAULT_HOST = "127.0.0.1" def serve(io) end @@services = {} # Hash of opened ports, i.e. services @@servicesMutex = Mutex.new def GServer.stop(port, host = DEFAULT_HOST) @@servicesMutex.synchronize { @@services[host][port].stop } end def GServer.in_service?(port, host = DEFAULT_HOST) @@services.has_key?(host) and @@services[host].has_key?(port) end def stop @connectionsMutex.synchronize { if @tcpServerThread @tcpServerThread.raise "stop" end } end def stopped? @tcpServerThread == nil end def shutdown @shutdown = true end def connections @connections.size end def join @tcpServerThread.join if @tcpServerThread end attr_reader :port, :host, :maxConnections attr_accessor :stdlog, :audit, :debug def connecting(client) addr = client.peeraddr log("#{self.class.to_s} #{@host}:#{@port} client:#{addr[1]} " + "#{addr[2]}<#{addr[3]}> connect") true end def disconnecting(clientPort) log("#{self.class.to_s} #{@host}:#{@port} " + "client:#{clientPort} disconnect") end protected :connecting, :disconnecting def starting() log("#{self.class.to_s} #{@host}:#{@port} start") end def stopping() log("#{self.class.to_s} #{@host}:#{@port} stop") end protected :starting, :stopping def error(detail) log(detail.backtrace.join("\n")) end def log(msg) if @stdlog @stdlog.puts("[#{Time.new.ctime}] %s" % msg) @stdlog.flush end end protected :error, :log def initialize(port, host = DEFAULT_HOST, maxConnections = 4, stdlog = $stderr, audit = false, debug = false) @tcpServerThread = nil @port = port @host = host @maxConnections = maxConnections @connections = [] @connectionsMutex = Mutex.new @connectionsCV = ConditionVariable.new @stdlog = stdlog @audit = audit @debug = debug end def start(maxConnections = -1) raise "running" if !stopped? @shutdown = false @maxConnections = maxConnections if maxConnections > 0 @@servicesMutex.synchronize { if GServer.in_service?(@port,@host) raise "Port already in use: #{host}:#{@port}!" end @tcpServer = TCPServer.new(@host,@port) @port = @tcpServer.addr[1] @@services[@host] = {} unless @@services.has_key?(@host) @@services[@host][@port] = self; } @tcpServerThread = Thread.new { begin starting if @audit while !@shutdown @connectionsMutex.synchronize { while @connections.size >= @maxConnections @connectionsCV.wait(@connectionsMutex) end } client = @tcpServer.accept @connections << Thread.new(client) { |myClient| begin myPort = myClient.peeraddr[1] serve(myClient) if !@audit or connecting(myClient) rescue => detail error(detail) if @debug ensure begin myClient.close rescue end @connectionsMutex.synchronize { @connections.delete(Thread.current) @connectionsCV.signal } disconnecting(myPort) if @audit end } end rescue => detail error(detail) if @debug ensure begin @tcpServer.close rescue end if @shutdown @connectionsMutex.synchronize { while @connections.size > 0 @connectionsCV.wait(@connectionsMutex) end } else @connections.each { |c| c.raise "stop" } end @tcpServerThread = nil @@servicesMutex.synchronize { @@services[@host].delete(@port) } stopping if @audit end } self end end PK|].4!!soap/parser.rbnu[# SOAP4R - SOAP XML Instance Parser library. # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/ns' require 'xsd/xmlparser' require 'soap/soap' require 'soap/baseData' require 'soap/encodingstyle/handler' module SOAP class Parser include SOAP class ParseError < Error; end class FormatDecodeError < ParseError; end class UnexpectedElementError < ParseError; end private class ParseFrame attr_reader :node attr_reader :name attr_reader :ns, :encodingstyle class NodeContainer def initialize(node) @node = node end def node @node end def replace_node(node) @node = node end end public def initialize(ns, name, node, encodingstyle) @ns = ns @name = name self.node = node @encodingstyle = encodingstyle end def node=(node) @node = NodeContainer.new(node) end end public attr_accessor :envelopenamespace attr_accessor :default_encodingstyle attr_accessor :decode_typemap attr_accessor :allow_unqualified_element def initialize(opt = {}) @opt = opt @parser = XSD::XMLParser.create_parser(self, opt) @parsestack = nil @lastnode = nil @handlers = {} @envelopenamespace = opt[:envelopenamespace] || EnvelopeNamespace @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace @decode_typemap = opt[:decode_typemap] || nil @allow_unqualified_element = opt[:allow_unqualified_element] || false end def charset @parser.charset end def parse(string_or_readable) @parsestack = [] @lastnode = nil @handlers.each do |uri, handler| handler.decode_prologue end @parser.do_parse(string_or_readable) unless @parsestack.empty? raise FormatDecodeError.new("Unbalanced tag in XML.") end @handlers.each do |uri, handler| handler.decode_epilogue end @lastnode end def start_element(name, attrs) lastframe = @parsestack.last ns = parent = parent_encodingstyle = nil if lastframe ns = lastframe.ns.clone_ns parent = lastframe.node parent_encodingstyle = lastframe.encodingstyle else ns = XSD::NS.new parent = ParseFrame::NodeContainer.new(nil) parent_encodingstyle = nil end attrs = XSD::XMLParser.filter_ns(ns, attrs) encodingstyle = find_encodingstyle(ns, attrs) # Children's encodingstyle is derived from its parent. if encodingstyle.nil? if parent.node.is_a?(SOAPHeader) encodingstyle = LiteralNamespace else encodingstyle = parent_encodingstyle || @default_encodingstyle end end node = decode_tag(ns, name, attrs, parent, encodingstyle) @parsestack << ParseFrame.new(ns, name, node, encodingstyle) end def characters(text) lastframe = @parsestack.last if lastframe # Need not to be cloned because character does not have attr. decode_text(lastframe.ns, text, lastframe.encodingstyle) else # Ignore Text outside of SOAP Envelope. p text if $DEBUG end end def end_element(name) lastframe = @parsestack.pop unless name == lastframe.name raise UnexpectedElementError.new("Closing element name '#{ name }' does not match with opening element '#{ lastframe.name }'.") end decode_tag_end(lastframe.ns, lastframe.node, lastframe.encodingstyle) @lastnode = lastframe.node.node end private def find_encodingstyle(ns, attrs) attrs.each do |key, value| if (ns.compare(@envelopenamespace, AttrEncodingStyle, key)) return value end end nil end def decode_tag(ns, name, attrs, parent, encodingstyle) ele = ns.parse(name) # Envelope based parsing. if ((ele.namespace == @envelopenamespace) || (@allow_unqualified_element && ele.namespace.nil?)) o = decode_soap_envelope(ns, ele, attrs, parent) return o if o end # Encoding based parsing. handler = find_handler(encodingstyle) if handler return handler.decode_tag(ns, ele, attrs, parent) else raise FormatDecodeError.new("Unknown encodingStyle: #{ encodingstyle }.") end end def decode_tag_end(ns, node, encodingstyle) return unless encodingstyle handler = find_handler(encodingstyle) if handler return handler.decode_tag_end(ns, node) else raise FormatDecodeError.new("Unknown encodingStyle: #{ encodingstyle }.") end end def decode_text(ns, text, encodingstyle) handler = find_handler(encodingstyle) if handler handler.decode_text(ns, text) else # How should I do? end end def decode_soap_envelope(ns, ele, attrs, parent) o = nil if ele.name == EleEnvelope o = SOAPEnvelope.new if ext = @opt[:external_content] ext.each do |k, v| o.external_content[k] = v end end elsif ele.name == EleHeader unless parent.node.is_a?(SOAPEnvelope) raise FormatDecodeError.new("Header should be a child of Envelope.") end o = SOAPHeader.new parent.node.header = o elsif ele.name == EleBody unless parent.node.is_a?(SOAPEnvelope) raise FormatDecodeError.new("Body should be a child of Envelope.") end o = SOAPBody.new parent.node.body = o elsif ele.name == EleFault unless parent.node.is_a?(SOAPBody) raise FormatDecodeError.new("Fault should be a child of Body.") end o = SOAPFault.new parent.node.fault = o end o end def find_handler(encodingstyle) unless @handlers.key?(encodingstyle) handler_factory = SOAP::EncodingStyle::Handler.handler(encodingstyle) || SOAP::EncodingStyle::Handler.handler(EncodingNamespace) handler = handler_factory.new(@parser.charset) handler.decode_typemap = @decode_typemap handler.decode_prologue @handlers[encodingstyle] = handler end @handlers[encodingstyle] end end end PK|]^??soap/wsdlDriver.rbnu[# SOAP4R - SOAP WSDL driver # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/parser' require 'wsdl/importer' require 'xsd/qname' require 'xsd/codegen/gensupport' require 'soap/mapping/wsdlencodedregistry' require 'soap/mapping/wsdlliteralregistry' require 'soap/rpc/driver' require 'wsdl/soap/methodDefCreator' module SOAP class WSDLDriverFactory class FactoryError < StandardError; end attr_reader :wsdl def initialize(wsdl) @wsdl = import(wsdl) @methoddefcreator = WSDL::SOAP::MethodDefCreator.new(@wsdl) end def inspect "#<#{self.class}:#{@wsdl.name}>" end def create_rpc_driver(servicename = nil, portname = nil) port = find_port(servicename, portname) drv = SOAP::RPC::Driver.new(port.soap_address.location) init_driver(drv, port) add_operation(drv, port) drv end # depricated old interface def create_driver(servicename = nil, portname = nil) warn("WSDLDriverFactory#create_driver is depricated. Use create_rpc_driver instead.") port = find_port(servicename, portname) WSDLDriver.new(@wsdl, port, nil) end # Backward compatibility. alias createDriver create_driver private def find_port(servicename = nil, portname = nil) service = port = nil if servicename service = @wsdl.service( XSD::QName.new(@wsdl.targetnamespace, servicename)) else service = @wsdl.services[0] end if service.nil? raise FactoryError.new("service #{servicename} not found in WSDL") end if portname port = service.ports[XSD::QName.new(@wsdl.targetnamespace, portname)] if port.nil? raise FactoryError.new("port #{portname} not found in WSDL") end else port = service.ports.find { |port| !port.soap_address.nil? } if port.nil? raise FactoryError.new("no ports have soap:address") end end if port.soap_address.nil? raise FactoryError.new("soap:address element not found in WSDL") end port end def init_driver(drv, port) wsdl_elements = @wsdl.collect_elements wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes rpc_decode_typemap = wsdl_types + @wsdl.soap_rpc_complextypes(port.find_binding) drv.proxy.mapping_registry = Mapping::WSDLEncodedRegistry.new(rpc_decode_typemap) drv.proxy.literal_mapping_registry = Mapping::WSDLLiteralRegistry.new(wsdl_types, wsdl_elements) end def add_operation(drv, port) port.find_binding.operations.each do |op_bind| op_name = op_bind.soapoperation_name soapaction = op_bind.soapaction || '' orgname = op_name.name name = XSD::CodeGen::GenSupport.safemethodname(orgname) param_def = create_param_def(op_bind) opt = { :request_style => op_bind.soapoperation_style, :response_style => op_bind.soapoperation_style, :request_use => op_bind.input.soapbody_use, :response_use => op_bind.output.soapbody_use, :elementformdefault => false, :attributeformdefault => false } if op_bind.soapoperation_style == :rpc drv.add_rpc_operation(op_name, soapaction, name, param_def, opt) else drv.add_document_operation(soapaction, name, param_def, opt) end if orgname != name and orgname.capitalize == name.capitalize ::SOAP::Mapping.define_singleton_method(drv, orgname) do |*arg| __send__(name, *arg) end end end end def import(location) WSDL::Importer.import(location) end def create_param_def(op_bind) op = op_bind.find_operation if op_bind.soapoperation_style == :rpc param_def = @methoddefcreator.collect_rpcparameter(op) else param_def = @methoddefcreator.collect_documentparameter(op) end # the first element of typedef in param_def is a String like # "::SOAP::SOAPStruct". turn this String to a class. param_def.collect { |io, name, typedef| typedef[0] = Mapping.class_from_name(typedef[0]) [io, name, typedef] } end def partqname(part) if part.type part.type else part.element end end def param_def(type, name, klass, partqname) [type, name, [klass, partqname.namespace, partqname.name]] end def filter_parts(partsdef, partssource) parts = partsdef.split(/\s+/) partssource.find_all { |part| parts.include?(part.name) } end end class WSDLDriver class << self if RUBY_VERSION >= "1.7.0" def __attr_proxy(symbol, assignable = false) name = symbol.to_s define_method(name) { @servant.__send__(name) } if assignable aname = name + '=' define_method(aname) { |rhs| @servant.__send__(aname, rhs) } end end else def __attr_proxy(symbol, assignable = false) name = symbol.to_s module_eval <<-EOS def #{name} @servant.#{name} end EOS if assignable module_eval <<-EOS def #{name}=(value) @servant.#{name} = value end EOS end end end end __attr_proxy :options __attr_proxy :headerhandler __attr_proxy :streamhandler __attr_proxy :test_loopback_response __attr_proxy :endpoint_url, true __attr_proxy :mapping_registry, true # for RPC unmarshal __attr_proxy :wsdl_mapping_registry, true # for RPC marshal __attr_proxy :default_encodingstyle, true __attr_proxy :generate_explicit_type, true __attr_proxy :allow_unqualified_element, true def httpproxy @servant.options["protocol.http.proxy"] end def httpproxy=(httpproxy) @servant.options["protocol.http.proxy"] = httpproxy end def wiredump_dev @servant.options["protocol.http.wiredump_dev"] end def wiredump_dev=(wiredump_dev) @servant.options["protocol.http.wiredump_dev"] = wiredump_dev end def mandatorycharset @servant.options["protocol.mandatorycharset"] end def mandatorycharset=(mandatorycharset) @servant.options["protocol.mandatorycharset"] = mandatorycharset end def wiredump_file_base @servant.options["protocol.wiredump_file_base"] end def wiredump_file_base=(wiredump_file_base) @servant.options["protocol.wiredump_file_base"] = wiredump_file_base end def initialize(wsdl, port, logdev) @servant = Servant__.new(self, wsdl, port, logdev) end def inspect "#<#{self.class}:#{@servant.port.name}>" end def reset_stream @servant.reset_stream end # Backward compatibility. alias generateEncodeType= generate_explicit_type= class Servant__ include SOAP attr_reader :options attr_reader :port attr_accessor :soapaction attr_accessor :default_encodingstyle attr_accessor :allow_unqualified_element attr_accessor :generate_explicit_type attr_accessor :mapping_registry attr_accessor :wsdl_mapping_registry def initialize(host, wsdl, port, logdev) @host = host @wsdl = wsdl @port = port @logdev = logdev @soapaction = nil @options = setup_options @default_encodingstyle = nil @allow_unqualified_element = nil @generate_explicit_type = false @mapping_registry = nil # for rpc unmarshal @wsdl_mapping_registry = nil # for rpc marshal @wiredump_file_base = nil @mandatorycharset = nil @wsdl_elements = @wsdl.collect_elements @wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes @rpc_decode_typemap = @wsdl_types + @wsdl.soap_rpc_complextypes(port.find_binding) @wsdl_mapping_registry = Mapping::WSDLEncodedRegistry.new( @rpc_decode_typemap) @doc_mapper = Mapping::WSDLLiteralRegistry.new( @wsdl_types, @wsdl_elements) endpoint_url = @port.soap_address.location # Convert a map which key is QName, to a Hash which key is String. @operation = {} @port.inputoperation_map.each do |op_name, op_info| orgname = op_name.name name = XSD::CodeGen::GenSupport.safemethodname(orgname) @operation[name] = @operation[orgname] = op_info add_method_interface(op_info) end @proxy = ::SOAP::RPC::Proxy.new(endpoint_url, @soapaction, @options) end def inspect "#<#{self.class}:#{@proxy.inspect}>" end def endpoint_url @proxy.endpoint_url end def endpoint_url=(endpoint_url) @proxy.endpoint_url = endpoint_url end def headerhandler @proxy.headerhandler end def streamhandler @proxy.streamhandler end def test_loopback_response @proxy.test_loopback_response end def reset_stream @proxy.reset_stream end def rpc_call(name, *values) set_wiredump_file_base(name) unless op_info = @operation[name] raise RuntimeError, "method: #{name} not defined" end req_header = create_request_header req_body = create_request_body(op_info, *values) reqopt = create_options({ :soapaction => op_info.soapaction || @soapaction}) resopt = create_options({ :decode_typemap => @rpc_decode_typemap}) env = @proxy.route(req_header, req_body, reqopt, resopt) raise EmptyResponseError unless env receive_headers(env.header) begin @proxy.check_fault(env.body) rescue ::SOAP::FaultError => e Mapping.fault2exception(e) end ret = env.body.response ? Mapping.soap2obj(env.body.response, @mapping_registry) : nil if env.body.outparams outparams = env.body.outparams.collect { |outparam| Mapping.soap2obj(outparam) } return [ret].concat(outparams) else return ret end end # req_header: [[element, mustunderstand, encodingstyle(QName/String)], ...] # req_body: SOAPBasetype/SOAPCompoundtype def document_send(name, header_obj, body_obj) set_wiredump_file_base(name) unless op_info = @operation[name] raise RuntimeError, "method: #{name} not defined" end req_header = header_obj ? header_from_obj(header_obj, op_info) : nil req_body = body_from_obj(body_obj, op_info) opt = create_options({ :soapaction => op_info.soapaction || @soapaction, :decode_typemap => @wsdl_types}) env = @proxy.invoke(req_header, req_body, opt) raise EmptyResponseError unless env if env.body.fault raise ::SOAP::FaultError.new(env.body.fault) end res_body_obj = env.body.response ? Mapping.soap2obj(env.body.response, @mapping_registry) : nil return env.header, res_body_obj end private def create_options(hash = nil) opt = {} opt[:default_encodingstyle] = @default_encodingstyle opt[:allow_unqualified_element] = @allow_unqualified_element opt[:generate_explicit_type] = @generate_explicit_type opt.update(hash) if hash opt end def set_wiredump_file_base(name) if @wiredump_file_base @proxy.set_wiredump_file_base(@wiredump_file_base + "_#{name}") end end def create_request_header headers = @proxy.headerhandler.on_outbound if headers.empty? nil else h = SOAPHeader.new headers.each do |header| h.add(header.elename.name, header) end h end end def receive_headers(headers) @proxy.headerhandler.on_inbound(headers) if headers end def create_request_body(op_info, *values) method = create_method_struct(op_info, *values) SOAPBody.new(method) end def create_method_struct(op_info, *params) parts_names = op_info.bodyparts.collect { |part| part.name } obj = create_method_obj(parts_names, params) method = Mapping.obj2soap(obj, @wsdl_mapping_registry, op_info.op_name) if method.members.size != parts_names.size new_method = SOAPStruct.new method.each do |key, value| if parts_names.include?(key) new_method.add(key, value) end end method = new_method end method.elename = op_info.op_name method.type = XSD::QName.new # Request should not be typed. method end def create_method_obj(names, params) o = Object.new idx = 0 while idx < params.length o.instance_variable_set('@' + names[idx], params[idx]) idx += 1 end o end def header_from_obj(obj, op_info) if obj.is_a?(SOAPHeader) obj elsif op_info.headerparts.empty? if obj.nil? nil else raise RuntimeError.new("no header definition in schema: #{obj}") end elsif op_info.headerparts.size == 1 part = op_info.headerparts[0] header = SOAPHeader.new() header.add(headeritem_from_obj(obj, part.element || part.eletype)) header else header = SOAPHeader.new() op_info.headerparts.each do |part| child = Mapping.get_attribute(obj, part.name) ele = headeritem_from_obj(child, part.element || part.eletype) header.add(part.name, ele) end header end end def headeritem_from_obj(obj, name) if obj.nil? SOAPElement.new(name) elsif obj.is_a?(SOAPHeaderItem) obj else Mapping.obj2soap(obj, @doc_mapper, name) end end def body_from_obj(obj, op_info) if obj.is_a?(SOAPBody) obj elsif op_info.bodyparts.empty? if obj.nil? nil else raise RuntimeError.new("no body found in schema") end elsif op_info.bodyparts.size == 1 part = op_info.bodyparts[0] ele = bodyitem_from_obj(obj, part.element || part.type) SOAPBody.new(ele) else body = SOAPBody.new op_info.bodyparts.each do |part| child = Mapping.get_attribute(obj, part.name) ele = bodyitem_from_obj(child, part.element || part.type) body.add(ele.elename.name, ele) end body end end def bodyitem_from_obj(obj, name) if obj.nil? SOAPElement.new(name) elsif obj.is_a?(SOAPElement) obj else Mapping.obj2soap(obj, @doc_mapper, name) end end def add_method_interface(op_info) name = XSD::CodeGen::GenSupport.safemethodname(op_info.op_name.name) orgname = op_info.op_name.name parts_names = op_info.bodyparts.collect { |part| part.name } case op_info.style when :document if orgname != name and orgname.capitalize == name.capitalize add_document_method_interface(orgname, parts_names) end add_document_method_interface(name, parts_names) when :rpc if orgname != name and orgname.capitalize == name.capitalize add_rpc_method_interface(orgname, parts_names) end add_rpc_method_interface(name, parts_names) else raise RuntimeError.new("unknown style: #{op_info.style}") end end def add_rpc_method_interface(name, parts_names) ::SOAP::Mapping.define_singleton_method(@host, name) do |*arg| unless arg.size == parts_names.size raise ArgumentError.new( "wrong number of arguments (#{arg.size} for #{parts_names.size})") end @servant.rpc_call(name, *arg) end @host.method(name) end def add_document_method_interface(name, parts_names) ::SOAP::Mapping.define_singleton_method(@host, name) do |h, b| @servant.document_send(name, h, b) end @host.method(name) end def setup_options if opt = Property.loadproperty(::SOAP::PropertyName) opt = opt["client"] end opt ||= Property.new opt.add_hook("protocol.mandatorycharset") do |key, value| @mandatorycharset = value end opt.add_hook("protocol.wiredump_file_base") do |key, value| @wiredump_file_base = value end opt["protocol.http.charset"] ||= XSD::Charset.xml_encoding_label opt["protocol.http.proxy"] ||= Env::HTTP_PROXY opt["protocol.http.no_proxy"] ||= Env::NO_PROXY opt end end end end PK|] R&&soap/rpc/rpc.rbnu[# SOAP4R - RPC utility. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP module RPC ServerException = Mapping::MappedException def self.defined_methods(obj) if obj.is_a?(Module) obj.methods - Module.methods else obj.methods - Object.instance_methods(true) end end end end PK|]x soap/rpc/httpserver.rbnu[# SOAP4R - WEBrick HTTP Server # Copyright (C) 2003, 2004 by NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'logger' require 'soap/rpc/soaplet' require 'soap/streamHandler' require 'webrick' module SOAP module RPC class HTTPServer < Logger::Application attr_reader :server attr_accessor :default_namespace def initialize(config) super(config[:SOAPHTTPServerApplicationName] || self.class.name) @default_namespace = config[:SOAPDefaultNamespace] @webrick_config = config.dup self.level = Logger::Severity::ERROR # keep silent by default @webrick_config[:Logger] ||= @log @log = @webrick_config[:Logger] # sync logger of App and HTTPServer @router = ::SOAP::RPC::Router.new(self.class.name) @soaplet = ::SOAP::RPC::SOAPlet.new(@router) on_init @server = WEBrick::HTTPServer.new(@webrick_config) @server.mount('/', @soaplet) end def on_init # do extra initialization in a derived class if needed. end def status @server.status if @server end def shutdown @server.shutdown if @server end def mapping_registry @router.mapping_registry end def mapping_registry=(mapping_registry) @router.mapping_registry = mapping_registry end def generate_explicit_type @router.generate_explicit_type end def generate_explicit_type=(generate_explicit_type) @router.generate_explicit_type = generate_explicit_type end # servant entry interface def add_rpc_request_servant(factory, namespace = @default_namespace) @router.add_rpc_request_servant(factory, namespace) end def add_rpc_servant(obj, namespace = @default_namespace) @router.add_rpc_servant(obj, namespace) end def add_request_headerhandler(factory) @router.add_request_headerhandler(factory) end def add_headerhandler(obj) @router.add_headerhandler(obj) end alias add_rpc_headerhandler add_headerhandler # method entry interface def add_rpc_method(obj, name, *param) add_rpc_method_as(obj, name, name, *param) end alias add_method add_rpc_method def add_rpc_method_as(obj, name, name_as, *param) qname = XSD::QName.new(@default_namespace, name_as) soapaction = nil param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param) @router.add_rpc_operation(obj, qname, soapaction, name, param_def) end alias add_method_as add_rpc_method_as def add_document_method(obj, soapaction, name, req_qnames, res_qnames) param_def = SOAPMethod.create_doc_param_def(req_qnames, res_qnames) @router.add_document_operation(obj, soapaction, name, param_def) end def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {}) @router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt) end def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {}) @router.add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt) end def add_document_operation(receiver, soapaction, name, param_def, opt = {}) @router.add_document_operation(receiver, soapaction, name, param_def, opt) end def add_document_request_operation(factory, soapaction, name, param_def, opt = {}) @router.add_document_request_operation(factory, soapaction, name, param_def, opt) end private def run @server.start end end end end PK|]0c+FFsoap/rpc/router.rbnu[# SOAP4R - RPC Routing library # Copyright (C) 2001, 2002, 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/processor' require 'soap/mapping' require 'soap/mapping/wsdlliteralregistry' require 'soap/rpc/rpc' require 'soap/rpc/element' require 'soap/streamHandler' require 'soap/mimemessage' require 'soap/header/handlerset' module SOAP module RPC class Router include SOAP attr_reader :actor attr_accessor :mapping_registry attr_accessor :literal_mapping_registry attr_accessor :generate_explicit_type attr_accessor :external_ces def initialize(actor) @actor = actor @mapping_registry = nil @headerhandler = Header::HandlerSet.new @literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new @generate_explicit_type = true @external_ces = nil @operation_by_soapaction = {} @operation_by_qname = {} @headerhandlerfactory = [] end ### ## header handler interface # def add_request_headerhandler(factory) unless factory.respond_to?(:create) raise TypeError.new("factory must respond to 'create'") end @headerhandlerfactory << factory end def add_headerhandler(handler) @headerhandler.add(handler) end ### ## servant definition interface # def add_rpc_request_servant(factory, namespace) unless factory.respond_to?(:create) raise TypeError.new("factory must respond to 'create'") end obj = factory.create # a dummy instance for introspection ::SOAP::RPC.defined_methods(obj).each do |name| begin qname = XSD::QName.new(namespace, name) param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name) opt = create_styleuse_option(:rpc, :encoded) add_rpc_request_operation(factory, qname, nil, name, param_def, opt) rescue SOAP::RPC::MethodDefinitionError => e p e if $DEBUG end end end def add_rpc_servant(obj, namespace) ::SOAP::RPC.defined_methods(obj).each do |name| begin qname = XSD::QName.new(namespace, name) param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name) opt = create_styleuse_option(:rpc, :encoded) add_rpc_operation(obj, qname, nil, name, param_def, opt) rescue SOAP::RPC::MethodDefinitionError => e p e if $DEBUG end end end alias add_servant add_rpc_servant ### ## operation definition interface # def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {}) ensure_styleuse_option(opt, :rpc, :encoded) opt[:request_qname] = qname op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def, opt) if opt[:request_style] != :rpc raise RPCRoutingError.new("illegal request_style given") end assign_operation(soapaction, qname, op) end alias add_method add_rpc_operation alias add_rpc_method add_rpc_operation def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {}) ensure_styleuse_option(opt, :rpc, :encoded) opt[:request_qname] = qname op = RequestScopeOperation.new(soapaction, factory, name, param_def, opt) if opt[:request_style] != :rpc raise RPCRoutingError.new("illegal request_style given") end assign_operation(soapaction, qname, op) end def add_document_operation(receiver, soapaction, name, param_def, opt = {}) # # adopt workaround for doc/lit wrapper method # (you should consider to simply use rpc/lit service) # #unless soapaction # raise RPCRoutingError.new("soapaction is a must for document method") #end ensure_styleuse_option(opt, :document, :literal) op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def, opt) if opt[:request_style] != :document raise RPCRoutingError.new("illegal request_style given") end assign_operation(soapaction, first_input_part_qname(param_def), op) end alias add_document_method add_document_operation def add_document_request_operation(factory, soapaction, name, param_def, opt = {}) # # adopt workaround for doc/lit wrapper method # (you should consider to simply use rpc/lit service) # #unless soapaction # raise RPCRoutingError.new("soapaction is a must for document method") #end ensure_styleuse_option(opt, :document, :literal) op = RequestScopeOperation.new(soapaction, receiver, name, param_def, opt) if opt[:request_style] != :document raise RPCRoutingError.new("illegal request_style given") end assign_operation(soapaction, first_input_part_qname(param_def), op) end def route(conn_data) # we cannot set request_default_encodingsyle before parsing the content. env = unmarshal(conn_data) if env.nil? raise ArgumentError.new("illegal SOAP marshal format") end op = lookup_operation(conn_data.soapaction, env.body) headerhandler = @headerhandler.dup @headerhandlerfactory.each do |f| headerhandler.add(f.create) end receive_headers(headerhandler, env.header) soap_response = default_encodingstyle = nil begin soap_response = op.call(env.body, @mapping_registry, @literal_mapping_registry, create_mapping_opt) default_encodingstyle = op.response_default_encodingstyle rescue Exception soap_response = fault($!) default_encodingstyle = nil end conn_data.is_fault = true if soap_response.is_a?(SOAPFault) header = call_headers(headerhandler) body = SOAPBody.new(soap_response) env = SOAPEnvelope.new(header, body) marshal(conn_data, env, default_encodingstyle) end # Create fault response string. def create_fault_response(e) env = SOAPEnvelope.new(SOAPHeader.new, SOAPBody.new(fault(e))) opt = {} opt[:external_content] = nil response_string = Processor.marshal(env, opt) conn_data = StreamHandler::ConnectionData.new(response_string) conn_data.is_fault = true if ext = opt[:external_content] mimeize(conn_data, ext) end conn_data end private def first_input_part_qname(param_def) param_def.each do |inout, paramname, typeinfo| if inout == SOAPMethod::IN klass, nsdef, namedef = typeinfo return XSD::QName.new(nsdef, namedef) end end nil end def create_styleuse_option(style, use) opt = {} opt[:request_style] = opt[:response_style] = style opt[:request_use] = opt[:response_use] = use opt end def ensure_styleuse_option(opt, style, use) opt[:request_style] ||= style opt[:response_style] ||= style opt[:request_use] ||= use opt[:response_use] ||= use end def assign_operation(soapaction, qname, op) assigned = false if soapaction and !soapaction.empty? @operation_by_soapaction[soapaction] = op assigned = true end if qname @operation_by_qname[qname] = op assigned = true end unless assigned raise RPCRoutingError.new("cannot assign operation") end end def lookup_operation(soapaction, body) if op = @operation_by_soapaction[soapaction] return op end qname = body.root_node.elename if op = @operation_by_qname[qname] return op end if soapaction raise RPCRoutingError.new( "operation: #{soapaction} #{qname} not supported") else raise RPCRoutingError.new("operation: #{qname} not supported") end end def call_headers(headerhandler) headers = headerhandler.on_outbound if headers.empty? nil else h = ::SOAP::SOAPHeader.new headers.each do |header| h.add(header.elename.name, header) end h end end def receive_headers(headerhandler, headers) headerhandler.on_inbound(headers) if headers end def unmarshal(conn_data) opt = {} contenttype = conn_data.receive_contenttype if /#{MIMEMessage::MultipartContentType}/i =~ contenttype opt[:external_content] = {} mime = MIMEMessage.parse("Content-Type: " + contenttype, conn_data.receive_string) mime.parts.each do |part| value = Attachment.new(part.content) value.contentid = part.contentid obj = SOAPAttachment.new(value) opt[:external_content][value.contentid] = obj if value.contentid end opt[:charset] = StreamHandler.parse_media_type(mime.root.headers['content-type'].str) env = Processor.unmarshal(mime.root.content, opt) else opt[:charset] = ::SOAP::StreamHandler.parse_media_type(contenttype) env = Processor.unmarshal(conn_data.receive_string, opt) end charset = opt[:charset] conn_data.send_contenttype = "text/xml; charset=\"#{charset}\"" env end def marshal(conn_data, env, default_encodingstyle = nil) opt = {} opt[:external_content] = nil opt[:default_encodingstyle] = default_encodingstyle opt[:generate_explicit_type] = @generate_explicit_type response_string = Processor.marshal(env, opt) conn_data.send_string = response_string if ext = opt[:external_content] mimeize(conn_data, ext) end conn_data end def mimeize(conn_data, ext) mime = MIMEMessage.new ext.each do |k, v| mime.add_attachment(v.data) end mime.add_part(conn_data.send_string + "\r\n") mime.close conn_data.send_string = mime.content_str conn_data.send_contenttype = mime.headers['content-type'].str conn_data end # Create fault response. def fault(e) detail = Mapping::SOAPException.new(e) SOAPFault.new( SOAPString.new('Server'), SOAPString.new(e.to_s), SOAPString.new(@actor), Mapping.obj2soap(detail, @mapping_registry)) end def create_mapping_opt { :external_ces => @external_ces } end class Operation attr_reader :name attr_reader :soapaction attr_reader :request_style attr_reader :response_style attr_reader :request_use attr_reader :response_use def initialize(soapaction, name, param_def, opt) @soapaction = soapaction @name = name @request_style = opt[:request_style] @response_style = opt[:response_style] @request_use = opt[:request_use] @response_use = opt[:response_use] check_style(@request_style) check_style(@response_style) check_use(@request_use) check_use(@response_use) if @response_style == :rpc request_qname = opt[:request_qname] or raise @rpc_method_factory = RPC::SOAPMethodRequest.new(request_qname, param_def, @soapaction) @rpc_response_qname = opt[:response_qname] else @doc_request_qnames = [] @doc_request_qualified = [] @doc_response_qnames = [] @doc_response_qualified = [] param_def.each do |inout, paramname, typeinfo, eleinfo| klass, nsdef, namedef = typeinfo qualified = eleinfo case inout when SOAPMethod::IN @doc_request_qnames << XSD::QName.new(nsdef, namedef) @doc_request_qualified << qualified when SOAPMethod::OUT @doc_response_qnames << XSD::QName.new(nsdef, namedef) @doc_response_qualified << qualified else raise ArgumentError.new( "illegal inout definition for document style: #{inout}") end end end end def request_default_encodingstyle (@request_use == :encoded) ? EncodingNamespace : LiteralNamespace end def response_default_encodingstyle (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace end def call(body, mapping_registry, literal_mapping_registry, opt) if @request_style == :rpc values = request_rpc(body, mapping_registry, literal_mapping_registry, opt) else values = request_document(body, mapping_registry, literal_mapping_registry, opt) end result = receiver.method(@name.intern).call(*values) return result if result.is_a?(SOAPFault) if @response_style == :rpc response_rpc(result, mapping_registry, literal_mapping_registry, opt) else response_doc(result, mapping_registry, literal_mapping_registry, opt) end end private def receiver raise NotImplementedError.new('must be defined in derived class') end def request_rpc(body, mapping_registry, literal_mapping_registry, opt) request = body.request unless request.is_a?(SOAPStruct) raise RPCRoutingError.new("not an RPC style") end if @request_use == :encoded request_rpc_enc(request, mapping_registry, opt) else request_rpc_lit(request, literal_mapping_registry, opt) end end def request_document(body, mapping_registry, literal_mapping_registry, opt) # ToDo: compare names with @doc_request_qnames if @request_use == :encoded request_doc_enc(body, mapping_registry, opt) else request_doc_lit(body, literal_mapping_registry, opt) end end def request_rpc_enc(request, mapping_registry, opt) param = Mapping.soap2obj(request, mapping_registry, nil, opt) request.collect { |key, value| param[key] } end def request_rpc_lit(request, mapping_registry, opt) request.collect { |key, value| Mapping.soap2obj(value, mapping_registry, nil, opt) } end def request_doc_enc(body, mapping_registry, opt) body.collect { |key, value| Mapping.soap2obj(value, mapping_registry, nil, opt) } end def request_doc_lit(body, mapping_registry, opt) body.collect { |key, value| Mapping.soap2obj(value, mapping_registry, nil, opt) } end def response_rpc(result, mapping_registry, literal_mapping_registry, opt) if @response_use == :encoded response_rpc_enc(result, mapping_registry, opt) else response_rpc_lit(result, literal_mapping_registry, opt) end end def response_doc(result, mapping_registry, literal_mapping_registry, opt) if @doc_response_qnames.size == 1 and !result.is_a?(Array) result = [result] end if result.size != @doc_response_qnames.size raise "required #{@doc_response_qnames.size} responses " + "but #{result.size} given" end if @response_use == :encoded response_doc_enc(result, mapping_registry, opt) else response_doc_lit(result, literal_mapping_registry, opt) end end def response_rpc_enc(result, mapping_registry, opt) soap_response = @rpc_method_factory.create_method_response(@rpc_response_qname) if soap_response.have_outparam? unless result.is_a?(Array) raise RPCRoutingError.new("out parameter was not returned") end outparams = {} i = 1 soap_response.output_params.each do |outparam| outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry, nil, opt) i += 1 end soap_response.set_outparam(outparams) soap_response.retval = Mapping.obj2soap(result[0], mapping_registry, nil, opt) else soap_response.retval = Mapping.obj2soap(result, mapping_registry, nil, opt) end soap_response end def response_rpc_lit(result, mapping_registry, opt) soap_response = @rpc_method_factory.create_method_response(@rpc_response_qname) if soap_response.have_outparam? unless result.is_a?(Array) raise RPCRoutingError.new("out parameter was not returned") end outparams = {} i = 1 soap_response.output_params.each do |outparam| outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry, XSD::QName.new(nil, outparam), opt) i += 1 end soap_response.set_outparam(outparams) soap_response.retval = Mapping.obj2soap(result[0], mapping_registry, XSD::QName.new(nil, soap_response.elename), opt) else soap_response.retval = Mapping.obj2soap(result, mapping_registry, XSD::QName.new(nil, soap_response.elename), opt) end soap_response end def response_doc_enc(result, mapping_registry, opt) (0...result.size).collect { |idx| ele = Mapping.obj2soap(result[idx], mapping_registry, nil, opt) ele.elename = @doc_response_qnames[idx] ele } end def response_doc_lit(result, mapping_registry, opt) (0...result.size).collect { |idx| ele = Mapping.obj2soap(result[idx], mapping_registry, @doc_response_qnames[idx]) ele.encodingstyle = LiteralNamespace if ele.respond_to?(:qualified) ele.qualified = @doc_response_qualified[idx] end ele } end def check_style(style) unless [:rpc, :document].include?(style) raise ArgumentError.new("unknown style: #{style}") end end def check_use(use) unless [:encoded, :literal].include?(use) raise ArgumentError.new("unknown use: #{use}") end end end class ApplicationScopeOperation < Operation def initialize(soapaction, receiver, name, param_def, opt) super(soapaction, name, param_def, opt) @receiver = receiver end private def receiver @receiver end end class RequestScopeOperation < Operation def initialize(soapaction, receiver_factory, name, param_def, opt) super(soapaction, name, param_def, opt) unless receiver_factory.respond_to?(:create) raise TypeError.new("factory must respond to 'create'") end @receiver_factory = receiver_factory end private def receiver @receiver_factory.create end end end end end PK|]lsoap/rpc/cgistub.rbnu[# SOAP4R - CGI/mod_ruby stub library # Copyright (C) 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/streamHandler' require 'webrick/httpresponse' require 'webrick/httpstatus' require 'logger' require 'soap/rpc/soaplet' module SOAP module RPC ### # SYNOPSIS # CGIStub.new # # DESCRIPTION # To be written... # class CGIStub < Logger::Application include SOAP include WEBrick class SOAPRequest attr_reader :body def [](var); end def meta_vars; end end class SOAPStdinRequest < SOAPRequest attr_reader :body def initialize(stream) size = ENV['CONTENT_LENGTH'].to_i || 0 @body = stream.read(size) end def [](var) ENV[var.gsub(/-/, '_').upcase] end def meta_vars { 'HTTP_SOAPACTION' => ENV['HTTP_SOAPAction'] } end end class SOAPFCGIRequest < SOAPRequest attr_reader :body def initialize(request) @request = request @body = @request.in.read end def [](var) @request.env[var.gsub(/-/, '_').upcase] end def meta_vars { 'HTTP_SOAPACTION' => @request.env['HTTP_SOAPAction'] } end end def initialize(appname, default_namespace) super(appname) set_log(STDERR) self.level = ERROR @default_namespace = default_namespace @remote_host = ENV['REMOTE_HOST'] || ENV['REMOTE_ADDR'] || 'unknown' @router = ::SOAP::RPC::Router.new(self.class.name) @soaplet = ::SOAP::RPC::SOAPlet.new(@router) on_init end def on_init # do extra initialization in a derived class if needed. end def mapping_registry @router.mapping_registry end def mapping_registry=(value) @router.mapping_registry = value end def generate_explicit_type @router.generate_explicit_type end def generate_explicit_type=(generate_explicit_type) @router.generate_explicit_type = generate_explicit_type end # servant entry interface def add_rpc_servant(obj, namespace = @default_namespace) @router.add_rpc_servant(obj, namespace) end alias add_servant add_rpc_servant def add_headerhandler(obj) @router.add_headerhandler(obj) end alias add_rpc_headerhandler add_headerhandler # method entry interface def add_rpc_method(obj, name, *param) add_rpc_method_with_namespace_as(@default_namespace, obj, name, name, *param) end alias add_method add_rpc_method def add_rpc_method_as(obj, name, name_as, *param) add_rpc_method_with_namespace_as(@default_namespace, obj, name, name_as, *param) end alias add_method_as add_rpc_method_as def add_rpc_method_with_namespace(namespace, obj, name, *param) add_rpc_method_with_namespace_as(namespace, obj, name, name, *param) end alias add_method_with_namespace add_rpc_method_with_namespace def add_rpc_method_with_namespace_as(namespace, obj, name, name_as, *param) qname = XSD::QName.new(namespace, name_as) soapaction = nil param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param) @router.add_rpc_operation(obj, qname, soapaction, name, param_def) end alias add_method_with_namespace_as add_rpc_method_with_namespace_as def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {}) @router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt) end def add_document_operation(receiver, soapaction, name, param_def, opt = {}) @router.add_document_operation(receiver, soapaction, name, param_def, opt) end def set_fcgi_request(request) @fcgi = request end private HTTPVersion = WEBrick::HTTPVersion.new('1.0') # dummy; ignored def run res = WEBrick::HTTPResponse.new({:HTTPVersion => HTTPVersion}) begin @log.info { "received a request from '#{ @remote_host }'" } if @fcgi req = SOAPFCGIRequest.new(@fcgi) else req = SOAPStdinRequest.new($stdin) end @soaplet.do_POST(req, res) rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex res.set_error(ex) rescue HTTPStatus::Error => ex res.set_error(ex) rescue HTTPStatus::Status => ex res.status = ex.code rescue StandardError, NameError => ex # for Ruby 1.6 res.set_error(ex, true) ensure if defined?(MOD_RUBY) r = Apache.request r.status = res.status r.content_type = res.content_type r.send_http_header buf = res.body else buf = '' res.send_response(buf) buf.sub!(/^[^\r]+\r\n/, '') # Trim status line. end @log.debug { "SOAP CGI Response:\n#{ buf }" } if @fcgi @fcgi.out.print buf @fcgi.finish @fcgi = nil else print buf end end 0 end end end end PK|]$soap/rpc/standaloneServer.rbnu[# SOAP4R - WEBrick Server # Copyright (C) 2003 by NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/rpc/httpserver' module SOAP module RPC class StandaloneServer < HTTPServer def initialize(appname, default_namespace, host = "0.0.0.0", port = 8080) @appname = appname @default_namespace = default_namespace @host = host @port = port super(create_config) end alias add_servant add_rpc_servant alias add_headerhandler add_rpc_headerhandler private def create_config { :BindAddress => @host, :Port => @port, :AccessLog => [], :SOAPDefaultNamespace => @default_namespace, :SOAPHTTPServerApplicationName => @appname, } end end end end PK|]psoap/rpc/soaplet.rbnu[# SOAP4R - SOAP handler servlet for WEBrick # Copyright (C) 2001-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'webrick/httpservlet/abstract' require 'webrick/httpstatus' require 'soap/rpc/router' require 'soap/streamHandler' begin require 'stringio' require 'zlib' rescue LoadError warn("Loading stringio or zlib failed. No gzipped response supported.") if $DEBUG end warn("Overriding WEBrick::Log#debug") if $DEBUG require 'webrick/log' module WEBrick class Log < BasicLog alias __debug debug def debug(msg = nil) if block_given? and msg.nil? __debug(yield) else __debug(msg) end end end end module SOAP module RPC class SOAPlet < WEBrick::HTTPServlet::AbstractServlet public attr_reader :options def initialize(router = nil) @router = router || ::SOAP::RPC::Router.new(self.class.name) @options = {} @config = {} end # for backward compatibility def app_scope_router @router end # for backward compatibility def add_servant(obj, namespace) @router.add_rpc_servant(obj, namespace) end def allow_content_encoding_gzip=(allow) @options[:allow_content_encoding_gzip] = allow end ### ## Servlet interfaces for WEBrick. # def get_instance(config, *options) @config = config self end def require_path_info? false end def do_GET(req, res) res.header['Allow'] = 'POST' raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed" end def do_POST(req, res) logger.debug { "SOAP request: " + req.body } if logger begin conn_data = ::SOAP::StreamHandler::ConnectionData.new setup_req(conn_data, req) @router.external_ces = @options[:external_ces] conn_data = @router.route(conn_data) setup_res(conn_data, req, res) rescue Exception => e conn_data = @router.create_fault_response(e) res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR res.body = conn_data.send_string res['content-type'] = conn_data.send_contenttype || "text/xml" end if res.body.is_a?(IO) res.chunked = true logger.debug { "SOAP response: (chunked response not logged)" } if logger else logger.debug { "SOAP response: " + res.body } if logger end end private def logger @config[:Logger] end def setup_req(conn_data, req) conn_data.receive_string = req.body conn_data.receive_contenttype = req['content-type'] conn_data.soapaction = parse_soapaction(req.meta_vars['HTTP_SOAPACTION']) end def setup_res(conn_data, req, res) res['content-type'] = conn_data.send_contenttype if conn_data.is_fault res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR end if outstring = encode_gzip(req, conn_data.send_string) res['content-encoding'] = 'gzip' res['content-length'] = outstring.size res.body = outstring else res.body = conn_data.send_string end end def parse_soapaction(soapaction) if !soapaction.nil? and !soapaction.empty? if /^"(.+)"$/ =~ soapaction return $1 end end nil end def encode_gzip(req, outstring) unless encode_gzip?(req) return nil end begin ostream = StringIO.new gz = Zlib::GzipWriter.new(ostream) gz.write(outstring) ostream.string ensure gz.close end end def encode_gzip?(req) @options[:allow_content_encoding_gzip] and defined?(::Zlib) and req['accept-encoding'] and req['accept-encoding'].split(/,\s*/).include?('gzip') end end end end PK|]W*::soap/rpc/proxy.rbnu[# SOAP4R - RPC Proxy library. # Copyright (C) 2000, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/processor' require 'soap/mapping' require 'soap/rpc/rpc' require 'soap/rpc/element' require 'soap/streamHandler' require 'soap/mimemessage' module SOAP module RPC class Proxy include SOAP public attr_accessor :soapaction attr_accessor :mandatorycharset attr_accessor :allow_unqualified_element attr_accessor :default_encodingstyle attr_accessor :generate_explicit_type attr_reader :headerhandler attr_reader :streamhandler attr_accessor :mapping_registry attr_accessor :literal_mapping_registry attr_reader :operation def initialize(endpoint_url, soapaction, options) @endpoint_url = endpoint_url @soapaction = soapaction @options = options @streamhandler = HTTPStreamHandler.new( @options["protocol.http"] ||= ::SOAP::Property.new) @operation = {} @mandatorycharset = nil @allow_unqualified_element = true @default_encodingstyle = nil @generate_explicit_type = true @headerhandler = Header::HandlerSet.new @mapping_registry = nil @literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new end def inspect "#<#{self.class}:#{@endpoint_url}>" end def endpoint_url @endpoint_url end def endpoint_url=(endpoint_url) @endpoint_url = endpoint_url reset_stream end def reset_stream @streamhandler.reset(@endpoint_url) end def set_wiredump_file_base(wiredump_file_base) @streamhandler.wiredump_file_base = wiredump_file_base end def test_loopback_response @streamhandler.test_loopback_response end def add_rpc_operation(qname, soapaction, name, param_def, opt = {}) opt[:request_qname] = qname opt[:request_style] ||= :rpc opt[:response_style] ||= :rpc opt[:request_use] ||= :encoded opt[:response_use] ||= :encoded @operation[name] = Operation.new(soapaction, param_def, opt) end def add_document_operation(soapaction, name, param_def, opt = {}) opt[:request_style] ||= :document opt[:response_style] ||= :document opt[:request_use] ||= :literal opt[:response_use] ||= :literal # default values of these values are unqualified in XML Schema. # set true for backward compatibility. unless opt.key?(:elementformdefault) opt[:elementformdefault] = true end unless opt.key?(:attributeformdefault) opt[:attributeformdefault] = true end @operation[name] = Operation.new(soapaction, param_def, opt) end # add_method is for shortcut of typical rpc/encoded method definition. alias add_method add_rpc_operation alias add_rpc_method add_rpc_operation alias add_document_method add_document_operation def invoke(req_header, req_body, opt = nil) opt ||= create_encoding_opt route(req_header, req_body, opt, opt) end def call(name, *params) unless op_info = @operation[name] raise MethodDefinitionError, "method: #{name} not defined" end mapping_opt = create_mapping_opt req_header = create_request_header req_body = SOAPBody.new( op_info.request_body(params, @mapping_registry, @literal_mapping_registry, mapping_opt) ) reqopt = create_encoding_opt( :soapaction => op_info.soapaction || @soapaction, :envelopenamespace => @options["soap.envelope.requestnamespace"], :default_encodingstyle => @default_encodingstyle || op_info.request_default_encodingstyle, :elementformdefault => op_info.elementformdefault, :attributeformdefault => op_info.attributeformdefault ) resopt = create_encoding_opt( :envelopenamespace => @options["soap.envelope.responsenamespace"], :default_encodingstyle => @default_encodingstyle || op_info.response_default_encodingstyle, :elementformdefault => op_info.elementformdefault, :attributeformdefault => op_info.attributeformdefault ) env = route(req_header, req_body, reqopt, resopt) raise EmptyResponseError unless env receive_headers(env.header) begin check_fault(env.body) rescue ::SOAP::FaultError => e op_info.raise_fault(e, @mapping_registry, @literal_mapping_registry) end op_info.response_obj(env.body, @mapping_registry, @literal_mapping_registry, mapping_opt) end def route(req_header, req_body, reqopt, resopt) req_env = ::SOAP::SOAPEnvelope.new(req_header, req_body) unless reqopt[:envelopenamespace].nil? set_envelopenamespace(req_env, reqopt[:envelopenamespace]) end reqopt[:external_content] = nil conn_data = marshal(req_env, reqopt) if ext = reqopt[:external_content] mime = MIMEMessage.new ext.each do |k, v| mime.add_attachment(v.data) end mime.add_part(conn_data.send_string + "\r\n") mime.close conn_data.send_string = mime.content_str conn_data.send_contenttype = mime.headers['content-type'].str end conn_data = @streamhandler.send(@endpoint_url, conn_data, reqopt[:soapaction]) if conn_data.receive_string.empty? return nil end unmarshal(conn_data, resopt) end def check_fault(body) if body.fault raise SOAP::FaultError.new(body.fault) end end private def set_envelopenamespace(env, namespace) env.elename = XSD::QName.new(namespace, env.elename.name) if env.header env.header.elename = XSD::QName.new(namespace, env.header.elename.name) end if env.body env.body.elename = XSD::QName.new(namespace, env.body.elename.name) end end def create_request_header headers = @headerhandler.on_outbound if headers.empty? nil else h = ::SOAP::SOAPHeader.new headers.each do |header| h.add(header.elename.name, header) end h end end def receive_headers(headers) @headerhandler.on_inbound(headers) if headers end def marshal(env, opt) send_string = Processor.marshal(env, opt) StreamHandler::ConnectionData.new(send_string) end def unmarshal(conn_data, opt) contenttype = conn_data.receive_contenttype if /#{MIMEMessage::MultipartContentType}/i =~ contenttype opt[:external_content] = {} mime = MIMEMessage.parse("Content-Type: " + contenttype, conn_data.receive_string) mime.parts.each do |part| value = Attachment.new(part.content) value.contentid = part.contentid obj = SOAPAttachment.new(value) opt[:external_content][value.contentid] = obj if value.contentid end opt[:charset] = @mandatorycharset || StreamHandler.parse_media_type(mime.root.headers['content-type'].str) env = Processor.unmarshal(mime.root.content, opt) else opt[:charset] = @mandatorycharset || ::SOAP::StreamHandler.parse_media_type(contenttype) env = Processor.unmarshal(conn_data.receive_string, opt) end unless env.is_a?(::SOAP::SOAPEnvelope) raise ResponseFormatError.new( "response is not a SOAP envelope: #{conn_data.receive_string}") end env end def create_header(headers) header = SOAPHeader.new() headers.each do |content, mustunderstand, encodingstyle| header.add(SOAPHeaderItem.new(content, mustunderstand, encodingstyle)) end header end def create_encoding_opt(hash = nil) opt = {} opt[:default_encodingstyle] = @default_encodingstyle opt[:allow_unqualified_element] = @allow_unqualified_element opt[:generate_explicit_type] = @generate_explicit_type opt[:no_indent] = @options["soap.envelope.no_indent"] opt[:use_numeric_character_reference] = @options["soap.envelope.use_numeric_character_reference"] opt.update(hash) if hash opt end def create_mapping_opt(hash = nil) opt = { :external_ces => @options["soap.mapping.external_ces"] } opt.update(hash) if hash opt end class Operation attr_reader :soapaction attr_reader :request_style attr_reader :response_style attr_reader :request_use attr_reader :response_use attr_reader :elementformdefault attr_reader :attributeformdefault def initialize(soapaction, param_def, opt) @soapaction = soapaction @request_style = opt[:request_style] @response_style = opt[:response_style] @request_use = opt[:request_use] @response_use = opt[:response_use] # set nil(unqualified) by default @elementformdefault = opt[:elementformdefault] @attributeformdefault = opt[:attributeformdefault] check_style(@request_style) check_style(@response_style) check_use(@request_use) check_use(@response_use) if @request_style == :rpc @rpc_request_qname = opt[:request_qname] if @rpc_request_qname.nil? raise MethodDefinitionError.new("rpc_request_qname must be given") end @rpc_method_factory = RPC::SOAPMethodRequest.new(@rpc_request_qname, param_def, @soapaction) else @doc_request_qnames = [] @doc_request_qualified = [] @doc_response_qnames = [] @doc_response_qualified = [] param_def.each do |inout, paramname, typeinfo, eleinfo| klass_not_used, nsdef, namedef = typeinfo qualified = eleinfo if namedef.nil? raise MethodDefinitionError.new("qname must be given") end case inout when SOAPMethod::IN @doc_request_qnames << XSD::QName.new(nsdef, namedef) @doc_request_qualified << qualified when SOAPMethod::OUT @doc_response_qnames << XSD::QName.new(nsdef, namedef) @doc_response_qualified << qualified else raise MethodDefinitionError.new( "illegal inout definition for document style: #{inout}") end end end end def request_default_encodingstyle (@request_use == :encoded) ? EncodingNamespace : LiteralNamespace end def response_default_encodingstyle (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace end def request_body(values, mapping_registry, literal_mapping_registry, opt) if @request_style == :rpc request_rpc(values, mapping_registry, literal_mapping_registry, opt) else request_doc(values, mapping_registry, literal_mapping_registry, opt) end end def response_obj(body, mapping_registry, literal_mapping_registry, opt) if @response_style == :rpc response_rpc(body, mapping_registry, literal_mapping_registry, opt) else response_doc(body, mapping_registry, literal_mapping_registry, opt) end end def raise_fault(e, mapping_registry, literal_mapping_registry) if @response_style == :rpc Mapping.fault2exception(e, mapping_registry) else Mapping.fault2exception(e, literal_mapping_registry) end end private def check_style(style) unless [:rpc, :document].include?(style) raise MethodDefinitionError.new("unknown style: #{style}") end end def check_use(use) unless [:encoded, :literal].include?(use) raise MethodDefinitionError.new("unknown use: #{use}") end end def request_rpc(values, mapping_registry, literal_mapping_registry, opt) if @request_use == :encoded request_rpc_enc(values, mapping_registry, opt) else request_rpc_lit(values, literal_mapping_registry, opt) end end def request_doc(values, mapping_registry, literal_mapping_registry, opt) if @request_use == :encoded request_doc_enc(values, mapping_registry, opt) else request_doc_lit(values, literal_mapping_registry, opt) end end def request_rpc_enc(values, mapping_registry, opt) method = @rpc_method_factory.dup names = method.input_params obj = create_request_obj(names, values) soap = Mapping.obj2soap(obj, mapping_registry, @rpc_request_qname, opt) method.set_param(soap) method end def request_rpc_lit(values, mapping_registry, opt) method = @rpc_method_factory.dup params = {} idx = 0 method.input_params.each do |name| params[name] = Mapping.obj2soap(values[idx], mapping_registry, XSD::QName.new(nil, name), opt) idx += 1 end method.set_param(params) method end def request_doc_enc(values, mapping_registry, opt) (0...values.size).collect { |idx| ele = Mapping.obj2soap(values[idx], mapping_registry, nil, opt) ele.elename = @doc_request_qnames[idx] ele } end def request_doc_lit(values, mapping_registry, opt) (0...values.size).collect { |idx| ele = Mapping.obj2soap(values[idx], mapping_registry, @doc_request_qnames[idx], opt) ele.encodingstyle = LiteralNamespace if ele.respond_to?(:qualified) ele.qualified = @doc_request_qualified[idx] end ele } end def response_rpc(body, mapping_registry, literal_mapping_registry, opt) if @response_use == :encoded response_rpc_enc(body, mapping_registry, opt) else response_rpc_lit(body, literal_mapping_registry, opt) end end def response_doc(body, mapping_registry, literal_mapping_registry, opt) if @response_use == :encoded return *response_doc_enc(body, mapping_registry, opt) else return *response_doc_lit(body, literal_mapping_registry, opt) end end def response_rpc_enc(body, mapping_registry, opt) ret = nil if body.response ret = Mapping.soap2obj(body.response, mapping_registry, @rpc_method_factory.retval_class_name, opt) end if body.outparams outparams = body.outparams.collect { |outparam| Mapping.soap2obj(outparam, mapping_registry, nil, opt) } [ret].concat(outparams) else ret end end def response_rpc_lit(body, mapping_registry, opt) body.root_node.collect { |key, value| Mapping.soap2obj(value, mapping_registry, @rpc_method_factory.retval_class_name, opt) } end def response_doc_enc(body, mapping_registry, opt) body.collect { |key, value| Mapping.soap2obj(value, mapping_registry, nil, opt) } end def response_doc_lit(body, mapping_registry, opt) body.collect { |key, value| Mapping.soap2obj(value, mapping_registry) } end def create_request_obj(names, params) o = Object.new idx = 0 while idx < params.length o.instance_variable_set('@' + names[idx], params[idx]) idx += 1 end o end end end end end PK|]mT׋soap/rpc/element.rbnu[# SOAP4R - RPC element definition. # Copyright (C) 2000, 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/baseData' module SOAP # Add method definitions for RPC to common definition in element.rb class SOAPBody < SOAPStruct public def request root_node end def response root = root_node if !@is_fault if root.nil? nil elsif root.is_a?(SOAPBasetype) root else # Initial element is [retval]. root[0] end else root end end def outparams root = root_node if !@is_fault and !root.nil? and !root.is_a?(SOAPBasetype) op = root[1..-1] op = nil if op && op.empty? op else nil end end def fault if @is_fault self['fault'] else nil end end def fault=(fault) @is_fault = true add_member('fault', fault) end end module RPC class RPCError < Error; end class MethodDefinitionError < RPCError; end class ParameterError < RPCError; end class SOAPMethod < SOAPStruct RETVAL = 'retval' IN = 'in' OUT = 'out' INOUT = 'inout' attr_reader :param_def attr_reader :inparam attr_reader :outparam attr_reader :retval_name attr_reader :retval_class_name def initialize(qname, param_def = nil) super(nil) @elename = qname @encodingstyle = nil @param_def = param_def @signature = [] @inparam_names = [] @inoutparam_names = [] @outparam_names = [] @inparam = {} @outparam = {} @retval_name = nil @retval_class_name = nil init_param(@param_def) if @param_def end def have_outparam? @outparam_names.size > 0 end def input_params collect_params(IN, INOUT) end def output_params collect_params(OUT, INOUT) end def set_param(params) params.each do |param, data| @inparam[param] = data data.elename.name = param data.parent = self end end def set_outparam(params) params.each do |param, data| @outparam[param] = data data.elename.name = param end end def SOAPMethod.param_count(param_def, *type) count = 0 param_def.each do |io_type, name, param_type| if type.include?(io_type) count += 1 end end count end def SOAPMethod.derive_rpc_param_def(obj, name, *param) if param.size == 1 and param[0].is_a?(Array) return param[0] end if param.empty? method = obj.method(name) param_names = (1..method.arity.abs).collect { |i| "p#{i}" } else param_names = param end create_rpc_param_def(param_names) end def SOAPMethod.create_rpc_param_def(param_names) param_def = [] param_names.each do |param_name| param_def.push([IN, param_name, nil]) end param_def.push([RETVAL, 'return', nil]) param_def end def SOAPMethod.create_doc_param_def(req_qnames, res_qnames) req_qnames = [req_qnames] if req_qnames.is_a?(XSD::QName) res_qnames = [res_qnames] if res_qnames.is_a?(XSD::QName) param_def = [] req_qnames.each do |qname| param_def << [IN, qname.name, [nil, qname.namespace, qname.name]] end res_qnames.each do |qname| param_def << [OUT, qname.name, [nil, qname.namespace, qname.name]] end param_def end private def collect_params(*type) names = [] @signature.each do |io_type, name, param_type| names << name if type.include?(io_type) end names end def init_param(param_def) param_def.each do |io_type, name, param_type| case io_type when IN @signature.push([IN, name, param_type]) @inparam_names.push(name) when OUT @signature.push([OUT, name, param_type]) @outparam_names.push(name) when INOUT @signature.push([INOUT, name, param_type]) @inoutparam_names.push(name) when RETVAL if @retval_name raise MethodDefinitionError.new('duplicated retval') end @retval_name = name @retval_class_name = nil if param_type if param_type[0].is_a?(String) @retval_class_name = Mapping.class_from_name(param_type[0]) else @retval_class_name = param_type[0] end end else raise MethodDefinitionError.new("unknown type: #{io_type}") end end end end class SOAPMethodRequest < SOAPMethod attr_accessor :soapaction def SOAPMethodRequest.create_request(qname, *params) param_def = [] param_value = [] i = 0 params.each do |param| param_name = "p#{i}" i += 1 param_def << [IN, param_name, nil] param_value << [param_name, param] end param_def << [RETVAL, 'return', nil] o = new(qname, param_def) o.set_param(param_value) o end def initialize(qname, param_def = nil, soapaction = nil) check_elename(qname) super(qname, param_def) @soapaction = soapaction end def each input_params.each do |name| unless @inparam[name] raise ParameterError.new("parameter: #{name} was not given") end yield(name, @inparam[name]) end end def dup req = self.class.new(@elename.dup, @param_def, @soapaction) req.encodingstyle = @encodingstyle req end def create_method_response(response_name = nil) response_name ||= XSD::QName.new(@elename.namespace, @elename.name + 'Response') SOAPMethodResponse.new(response_name, @param_def) end private def check_elename(qname) # NCName & ruby's method name unless /\A[\w_][\w\d_\-]*\z/ =~ qname.name raise MethodDefinitionError.new("element name '#{qname.name}' not allowed") end end end class SOAPMethodResponse < SOAPMethod def initialize(qname, param_def = nil) super(qname, param_def) @retval = nil end def retval=(retval) @retval = retval @retval.elename = @retval.elename.dup_name(@retval_name || 'return') retval.parent = self retval end def each if @retval_name and !@retval.is_a?(SOAPVoid) yield(@retval_name, @retval) end output_params.each do |name| unless @outparam[name] raise ParameterError.new("parameter: #{name} was not given") end yield(name, @outparam[name]) end end end # To return(?) void explicitly. # def foo(input_var) # ... # return SOAP::RPC::SOAPVoid.new # end class SOAPVoid < XSD::XSDAnySimpleType include SOAPBasetype extend SOAPModuleUtils Name = XSD::QName.new(Mapping::RubyCustomTypeNamespace, nil) public def initialize() @elename = Name @id = nil @precedents = [] @parent = nil end end end end PK|]|@KKsoap/rpc/driver.rbnu[# SOAP4R - SOAP RPC driver # Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/mapping' require 'soap/mapping/wsdlliteralregistry' require 'soap/rpc/rpc' require 'soap/rpc/proxy' require 'soap/rpc/element' require 'soap/streamHandler' require 'soap/property' require 'soap/header/handlerset' module SOAP module RPC class Driver class << self if RUBY_VERSION >= "1.7.0" def __attr_proxy(symbol, assignable = false) name = symbol.to_s define_method(name) { @proxy.__send__(name) } if assignable aname = name + '=' define_method(aname) { |rhs| @proxy.__send__(aname, rhs) } end end else def __attr_proxy(symbol, assignable = false) name = symbol.to_s module_eval <<-EOS def #{name} @proxy.#{name} end EOS if assignable module_eval <<-EOS def #{name}=(value) @proxy.#{name} = value end EOS end end end end __attr_proxy :endpoint_url, true __attr_proxy :mapping_registry, true __attr_proxy :default_encodingstyle, true __attr_proxy :generate_explicit_type, true __attr_proxy :allow_unqualified_element, true __attr_proxy :headerhandler __attr_proxy :streamhandler __attr_proxy :test_loopback_response __attr_proxy :reset_stream attr_reader :proxy attr_reader :options attr_accessor :soapaction def inspect "#<#{self.class}:#{@proxy.inspect}>" end def httpproxy options["protocol.http.proxy"] end def httpproxy=(httpproxy) options["protocol.http.proxy"] = httpproxy end def wiredump_dev options["protocol.http.wiredump_dev"] end def wiredump_dev=(wiredump_dev) options["protocol.http.wiredump_dev"] = wiredump_dev end def mandatorycharset options["protocol.mandatorycharset"] end def mandatorycharset=(mandatorycharset) options["protocol.mandatorycharset"] = mandatorycharset end def wiredump_file_base options["protocol.wiredump_file_base"] end def wiredump_file_base=(wiredump_file_base) options["protocol.wiredump_file_base"] = wiredump_file_base end def initialize(endpoint_url, namespace = nil, soapaction = nil) @namespace = namespace @soapaction = soapaction @options = setup_options @wiredump_file_base = nil @proxy = Proxy.new(endpoint_url, @soapaction, @options) end def loadproperty(propertyname) unless options.loadproperty(propertyname) raise LoadError.new("No such property to load -- #{propertyname}") end end def add_rpc_method(name, *params) add_rpc_method_with_soapaction_as(name, name, @soapaction, *params) end def add_rpc_method_as(name, name_as, *params) add_rpc_method_with_soapaction_as(name, name_as, @soapaction, *params) end def add_rpc_method_with_soapaction(name, soapaction, *params) add_rpc_method_with_soapaction_as(name, name, soapaction, *params) end def add_rpc_method_with_soapaction_as(name, name_as, soapaction, *params) param_def = SOAPMethod.create_rpc_param_def(params) qname = XSD::QName.new(@namespace, name_as) @proxy.add_rpc_method(qname, soapaction, name, param_def) add_rpc_method_interface(name, param_def) end # add_method is for shortcut of typical rpc/encoded method definition. alias add_method add_rpc_method alias add_method_as add_rpc_method_as alias add_method_with_soapaction add_rpc_method_with_soapaction alias add_method_with_soapaction_as add_rpc_method_with_soapaction_as def add_document_method(name, soapaction, req_qname, res_qname) param_def = SOAPMethod.create_doc_param_def(req_qname, res_qname) @proxy.add_document_method(soapaction, name, param_def) add_document_method_interface(name, param_def) end def add_rpc_operation(qname, soapaction, name, param_def, opt = {}) @proxy.add_rpc_operation(qname, soapaction, name, param_def, opt) add_rpc_method_interface(name, param_def) end def add_document_operation(soapaction, name, param_def, opt = {}) @proxy.add_document_operation(soapaction, name, param_def, opt) add_document_method_interface(name, param_def) end def invoke(headers, body) if headers and !headers.is_a?(SOAPHeader) headers = create_header(headers) end set_wiredump_file_base(body.elename.name) env = @proxy.invoke(headers, body) if env.nil? return nil, nil else return env.header, env.body end end def call(name, *params) set_wiredump_file_base(name) @proxy.call(name, *params) end private def set_wiredump_file_base(name) if @wiredump_file_base @proxy.set_wiredump_file_base("#{@wiredump_file_base}_#{name}") end end def create_header(headers) header = SOAPHeader.new() headers.each do |content, mustunderstand, encodingstyle| header.add(SOAPHeaderItem.new(content, mustunderstand, encodingstyle)) end header end def setup_options if opt = Property.loadproperty(::SOAP::PropertyName) opt = opt["client"] end opt ||= Property.new opt.add_hook("protocol.mandatorycharset") do |key, value| @proxy.mandatorycharset = value end opt.add_hook("protocol.wiredump_file_base") do |key, value| @wiredump_file_base = value end opt["protocol.http.charset"] ||= XSD::Charset.xml_encoding_label opt["protocol.http.proxy"] ||= Env::HTTP_PROXY opt["protocol.http.no_proxy"] ||= Env::NO_PROXY opt end def add_rpc_method_interface(name, param_def) param_count = RPC::SOAPMethod.param_count(param_def, RPC::SOAPMethod::IN, RPC::SOAPMethod::INOUT) add_method_interface(name, param_count) end def add_document_method_interface(name, param_def) param_count = RPC::SOAPMethod.param_count(param_def, RPC::SOAPMethod::IN) add_method_interface(name, param_count) end if RUBY_VERSION > "1.7.0" def add_method_interface(name, param_count) ::SOAP::Mapping.define_singleton_method(self, name) do |*arg| unless arg.size == param_count raise ArgumentError.new( "wrong number of arguments (#{arg.size} for #{param_count})") end call(name, *arg) end self.method(name) end else def add_method_interface(name, param_count) instance_eval <<-EOS def #{name}(*arg) unless arg.size == #{param_count} raise ArgumentError.new( "wrong number of arguments (\#{arg.size} for #{param_count})") end call(#{name.dump}, *arg) end EOS self.method(name) end end end end end PK|] j soap/soap.rbnu[# soap/soap.rb: SOAP4R - Base definitions. # Copyright (C) 2000-2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/charset' module SOAP VERSION = Version = '1.5.5' PropertyName = 'soap/property' EnvelopeNamespace = 'http://schemas.xmlsoap.org/soap/envelope/' EncodingNamespace = 'http://schemas.xmlsoap.org/soap/encoding/' LiteralNamespace = 'http://xml.apache.org/xml-soap/literalxml' NextActor = 'http://schemas.xmlsoap.org/soap/actor/next' EleEnvelope = 'Envelope' EleHeader = 'Header' EleBody = 'Body' EleFault = 'Fault' EleFaultString = 'faultstring' EleFaultActor = 'faultactor' EleFaultCode = 'faultcode' EleFaultDetail = 'detail' AttrMustUnderstand = 'mustUnderstand' AttrEncodingStyle = 'encodingStyle' AttrActor = 'actor' AttrRoot = 'root' AttrArrayType = 'arrayType' AttrOffset = 'offset' AttrPosition = 'position' ValueArray = 'Array' EleEnvelopeName = XSD::QName.new(EnvelopeNamespace, EleEnvelope).freeze EleHeaderName = XSD::QName.new(EnvelopeNamespace, EleHeader).freeze EleBodyName = XSD::QName.new(EnvelopeNamespace, EleBody).freeze EleFaultName = XSD::QName.new(EnvelopeNamespace, EleFault).freeze EleFaultStringName = XSD::QName.new(nil, EleFaultString).freeze EleFaultActorName = XSD::QName.new(nil, EleFaultActor).freeze EleFaultCodeName = XSD::QName.new(nil, EleFaultCode).freeze EleFaultDetailName = XSD::QName.new(nil, EleFaultDetail).freeze AttrMustUnderstandName = XSD::QName.new(EnvelopeNamespace, AttrMustUnderstand).freeze AttrEncodingStyleName = XSD::QName.new(EnvelopeNamespace, AttrEncodingStyle).freeze AttrRootName = XSD::QName.new(EncodingNamespace, AttrRoot).freeze AttrArrayTypeName = XSD::QName.new(EncodingNamespace, AttrArrayType).freeze AttrOffsetName = XSD::QName.new(EncodingNamespace, AttrOffset).freeze AttrPositionName = XSD::QName.new(EncodingNamespace, AttrPosition).freeze ValueArrayName = XSD::QName.new(EncodingNamespace, ValueArray).freeze Base64Literal = 'base64' SOAPNamespaceTag = 'env' XSDNamespaceTag = 'xsd' XSINamespaceTag = 'xsi' MediaType = 'text/xml' class Error < StandardError; end class StreamError < Error; end class HTTPStreamError < StreamError; end class PostUnavailableError < HTTPStreamError; end class MPostUnavailableError < HTTPStreamError; end class ArrayIndexOutOfBoundsError < Error; end class ArrayStoreError < Error; end class RPCRoutingError < Error; end class EmptyResponseError < Error; end class ResponseFormatError < Error; end class UnhandledMustUnderstandHeaderError < Error; end class FaultError < Error attr_reader :faultcode attr_reader :faultstring attr_reader :faultactor attr_accessor :detail def initialize(fault) @faultcode = fault.faultcode @faultstring = fault.faultstring @faultactor = fault.faultactor @detail = fault.detail super(self.to_s) end def to_s str = nil if @faultstring and @faultstring.respond_to?('data') str = @faultstring.data end str || '(No faultstring)' end end module Env def self.getenv(name) ENV[name.downcase] || ENV[name.upcase] end use_proxy = getenv('soap_use_proxy') == 'on' HTTP_PROXY = use_proxy ? getenv('http_proxy') : nil NO_PROXY = use_proxy ? getenv('no_proxy') : nil end end unless Object.respond_to?(:instance_variable_get) class Object def instance_variable_get(ivarname) instance_eval(ivarname) end def instance_variable_set(ivarname, value) instance_eval("#{ivarname} = value") end end end unless Kernel.respond_to?(:warn) module Kernel def warn(msg) STDERR.puts(msg + "\n") unless $VERBOSE.nil? end end end PK|]$r }}soap/processor.rbnu[# SOAP4R - marshal/unmarshal interface. # Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' require 'soap/soap' require 'soap/element' require 'soap/parser' require 'soap/generator' require 'soap/encodingstyle/soapHandler' require 'soap/encodingstyle/literalHandler' require 'soap/encodingstyle/aspDotNetHandler' module SOAP module Processor @@default_parser_option = {} class << self public def marshal(env, opt = {}, io = nil) generator = create_generator(opt) marshalled_str = generator.generate(env, io) unless env.external_content.empty? opt[:external_content] = env.external_content end marshalled_str end def unmarshal(stream, opt = {}) parser = create_parser(opt) parser.parse(stream) end def default_parser_option=(rhs) @@default_parser_option = rhs end def default_parser_option @@default_parser_option end private def create_generator(opt) SOAPGenerator.new(opt) end def create_parser(opt) if opt.empty? opt = @@default_parser_option end ::SOAP::Parser.new(opt) end end end end PK|]/~αsoap/property.rbnu[# soap/property.rb: SOAP4R - Property implementation. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP # Property stream format: # # line separator is \r?\n. 1 line per a property. # line which begins with '#' is a comment line. empty line is ignored, too. # key/value separator is ':' or '='. # '\' as escape character. but line separator cannot be escaped. # \s at the head/tail of key/value are trimmed. # # '[' + key + ']' indicates property section. for example, # # [aaa.bbb] # ccc = ddd # eee.fff = ggg # [] # aaa.hhh = iii # # is the same as; # # aaa.bbb.ccc = ddd # aaa.bbb.eee.fff = ggg # aaa.hhh = iii # class Property FrozenError = (RUBY_VERSION >= "1.9.0") ? RuntimeError : TypeError include Enumerable module Util def const_from_name(fqname) fqname.split("::").inject(Kernel) { |klass, name| klass.const_get(name) } end module_function :const_from_name def require_from_name(fqname) require File.join(fqname.split("::").collect { |ele| ele.downcase }) end module_function :require_from_name end def self.load(stream) new.load(stream) end def self.loadproperty(propname) new.loadproperty(propname) end def initialize @store = Hash.new @hook = Hash.new @self_hook = Array.new @locked = false end KEY_REGSRC = '([^=:\\\\]*(?:\\\\.[^=:\\\\]*)*)' DEF_REGSRC = '\\s*' + KEY_REGSRC + '\\s*[=:]\\s*(.*)' COMMENT_REGEXP = Regexp.new('^(?:#.*|)$') CATDEF_REGEXP = Regexp.new("^\\[\\s*#{KEY_REGSRC}\\s*\\]$") LINE_REGEXP = Regexp.new("^#{DEF_REGSRC}$") def load(stream) key_prefix = "" stream.each_with_index do |line, lineno| line.sub!(/\r?\n\z/, '') case line when COMMENT_REGEXP next when CATDEF_REGEXP key_prefix = $1.strip when LINE_REGEXP key, value = $1.strip, $2.strip key = "#{key_prefix}.#{key}" unless key_prefix.empty? key, value = loadstr(key), loadstr(value) self[key] = value else raise TypeError.new( "property format error at line #{lineno + 1}: `#{line}'") end end self end # find property from $:. def loadproperty(propname) return loadpropertyfile(propname) if File.file?(propname) $:.each do |path| if File.file?(file = File.join(path, propname)) return loadpropertyfile(file) end end nil end # name: a Symbol, String or an Array def [](name) referent(name_to_a(name)) end # name: a Symbol, String or an Array # value: an Object def []=(name, value) name_pair = name_to_a(name).freeze hooks = assign(name_pair, value) hooks.each do |hook| hook.call(name_pair, value) end value end # value: an Object # key is generated by property def <<(value) self[generate_new_key] = value end # name: a Symbol, String or an Array; nil means hook to the root # cascade: true/false; for cascading hook of sub key # hook: block which will be called with 2 args, name and value def add_hook(name = nil, cascade = false, &hook) if name == nil or name == true or name == false cascade = name assign_self_hook(cascade, &hook) else assign_hook(name_to_a(name), cascade, &hook) end end def each @store.each do |key, value| yield(key, value) end end def empty? @store.empty? end def keys @store.keys end def values @store.values end def lock(cascade = false) if cascade each_key do |key| key.lock(cascade) end end @locked = true self end def unlock(cascade = false) @locked = false if cascade each_key do |key| key.unlock(cascade) end end self end def locked? @locked end protected def deref_key(key) check_lock(key) ref = @store[key] ||= self.class.new unless propkey?(ref) raise ArgumentError.new("key `#{key}' already defined as a value") end ref end def local_referent(key) check_lock(key) if propkey?(@store[key]) and @store[key].locked? raise FrozenError.new("cannot split any key from locked property") end @store[key] end def local_assign(key, value) check_lock(key) if @locked if propkey?(value) raise FrozenError.new("cannot add any key to locked property") elsif propkey?(@store[key]) raise FrozenError.new("cannot override any key in locked property") end end @store[key] = value end def local_hook(key, direct) hooks = [] (@self_hook + (@hook[key] || NO_HOOK)).each do |hook, cascade| hooks << hook if direct or cascade end hooks end def local_assign_hook(key, cascade, &hook) check_lock(key) @store[key] ||= nil (@hook[key] ||= []) << [hook, cascade] end private NO_HOOK = [].freeze def referent(ary) ary[0..-2].inject(self) { |ref, name| ref.deref_key(to_key(name)) }.local_referent(to_key(ary.last)) end def assign(ary, value) ref = self hook = NO_HOOK ary[0..-2].each do |name| key = to_key(name) hook += ref.local_hook(key, false) ref = ref.deref_key(key) end last_key = to_key(ary.last) ref.local_assign(last_key, value) hook + ref.local_hook(last_key, true) end def assign_hook(ary, cascade, &hook) ary[0..-2].inject(self) { |ref, name| ref.deref_key(to_key(name)) }.local_assign_hook(to_key(ary.last), cascade, &hook) end def assign_self_hook(cascade, &hook) check_lock(nil) @self_hook << [hook, cascade] end def each_key self.each do |key, value| if propkey?(value) yield(value) end end end def check_lock(key) if @locked and (key.nil? or !@store.key?(key)) raise FrozenError.new("cannot add any key to locked property") end end def propkey?(value) value.is_a?(::SOAP::Property) end def name_to_a(name) case name when Symbol [name] when String name.scan(/[^.\\]+(?:\\.[^.\\])*/) # split with unescaped '.' when Array name else raise ArgumentError.new("Unknown name #{name}(#{name.class})") end end def to_key(name) name.to_s.downcase end def generate_new_key if @store.empty? "0" else (key_max + 1).to_s end end def key_max (@store.keys.max { |l, r| l.to_s.to_i <=> r.to_s.to_i }).to_s.to_i end def loadpropertyfile(file) puts "find property at #{file}" if $DEBUG File.open(file) do |f| load(f) end end def loadstr(str) str.gsub(/\\./) { |c| eval("\"#{c}\"") } end end end # for ruby/1.6. unless Enumerable.instance_methods.include?('inject') module Enumerable def inject(init) result = init each do |item| result = yield(result, item) end result end end end PK|]Wsoap/netHttpClient.rbnu[# SOAP4R - net/http wrapper # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'net/http' module SOAP class NetHttpClient SSLEnabled = begin require 'net/https' true rescue LoadError false end attr_reader :proxy attr_accessor :no_proxy attr_accessor :debug_dev attr_accessor :ssl_config # ignored for now. attr_accessor :protocol_version # ignored for now. attr_accessor :connect_timeout attr_accessor :send_timeout # ignored for now. attr_accessor :receive_timeout def initialize(proxy = nil, agent = nil) @proxy = proxy ? URI.parse(proxy) : nil @agent = agent @debug_dev = nil @session_manager = SessionManager.new @no_proxy = @ssl_config = @protocol_version = nil @connect_timeout = @send_timeout = @receive_timeout = nil end def test_loopback_response raise NotImplementedError.new("not supported for now") end def proxy=(proxy) if proxy.nil? @proxy = nil else if proxy.is_a?(URI) @proxy = proxy else @proxy = URI.parse(proxy) end if @proxy.scheme == nil or @proxy.scheme.downcase != 'http' or @proxy.host == nil or @proxy.port == nil raise ArgumentError.new("unsupported proxy `#{proxy}'") end end reset_all @proxy end def set_basic_auth(uri, user_id, passwd) # net/http does not handle url. @basic_auth = [user_id, passwd] raise NotImplementedError.new("basic_auth is not supported under soap4r + net/http.") end def set_cookie_store(filename) raise NotImplementedError.new end def save_cookie_store(filename) raise NotImplementedError.new end def reset(url) # no persistent connection. ignored. end def reset_all # no persistent connection. ignored. end def post(url, req_body, header = {}) unless url.is_a?(URI) url = URI.parse(url) end extra = header.dup extra['User-Agent'] = @agent if @agent res = start(url) { |http| http.post(url.request_uri, req_body, extra) } Response.new(res) end def get_content(url, header = {}) unless url.is_a?(URI) url = URI.parse(url) end extra = header.dup extra['User-Agent'] = @agent if @agent res = start(url) { |http| http.get(url.request_uri, extra) } res.body end private def start(url) http = create_connection(url) response = nil http.start { |worker| response = yield(worker) worker.finish } @debug_dev << response.body if @debug_dev response end def create_connection(url) proxy_host = proxy_port = nil unless no_proxy?(url) proxy_host = @proxy.host proxy_port = @proxy.port end http = Net::HTTP::Proxy(proxy_host, proxy_port).new(url.host, url.port) if http.respond_to?(:set_debug_output) http.set_debug_output(@debug_dev) end http.open_timeout = @connect_timeout if @connect_timeout http.read_timeout = @receive_timeout if @receive_timeout case url when URI::HTTPS if SSLEnabled http.use_ssl = true else raise RuntimeError.new("Cannot connect to #{url} (OpenSSL is not installed.)") end when URI::HTTP # OK else raise RuntimeError.new("Cannot connect to #{url} (Not HTTP.)") end http end NO_PROXY_HOSTS = ['localhost'] def no_proxy?(uri) if !@proxy or NO_PROXY_HOSTS.include?(uri.host) return true end if @no_proxy @no_proxy.scan(/([^:,]*)(?::(\d+))?/) do |host, port| if /(\A|\.)#{Regexp.quote(host)}\z/i =~ uri.host && (!port || uri.port == port.to_i) return true end end else false end end class SessionManager attr_accessor :connect_timeout attr_accessor :send_timeout attr_accessor :receive_timeout end class Response attr_reader :content attr_reader :status attr_reader :reason attr_reader :contenttype def initialize(res) @status = res.code.to_i @reason = res.message @contenttype = res['content-type'] @content = res.body end end end end PK|]Ԫ[:soap/marshal.rbnu[# SOAP4R - Marshalling/Unmarshalling Ruby's object using SOAP Encoding. # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require "soap/mapping" require "soap/processor" module SOAP module Marshal # Trying xsd:dateTime data to be recovered as aTime. MarshalMappingRegistry = Mapping::Registry.new( :allow_original_mapping => true) MarshalMappingRegistry.add( Time, ::SOAP::SOAPDateTime, ::SOAP::Mapping::Registry::DateTimeFactory ) class << self public def dump(obj, io = nil) marshal(obj, MarshalMappingRegistry, io) end def load(stream) unmarshal(stream, MarshalMappingRegistry) end def marshal(obj, mapping_registry = MarshalMappingRegistry, io = nil) elename = Mapping.name2elename(obj.class.to_s) soap_obj = Mapping.obj2soap(obj, mapping_registry) body = SOAPBody.new body.add(elename, soap_obj) env = SOAPEnvelope.new(nil, body) SOAP::Processor.marshal(env, {}, io) end def unmarshal(stream, mapping_registry = MarshalMappingRegistry) env = SOAP::Processor.unmarshal(stream) if env.nil? raise ArgumentError.new("Illegal SOAP marshal format.") end Mapping.soap2obj(env.body.root_node, mapping_registry) end end end end SOAPMarshal = SOAP::Marshal PK|]U}}soap/mapping.rbnu[# SOAP4R - Ruby type mapping utility. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/mapping/mapping' require 'soap/mapping/registry' PK|]2CBBsoap/baseData.rbnu[# soap/baseData.rb: SOAP4R - Base type library # Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' require 'soap/soap' module SOAP ### ## Mix-in module for SOAP base type classes. # module SOAPModuleUtils include SOAP public def decode(elename) d = self.new d.elename = elename d end end ### ## for SOAP type(base and compound) # module SOAPType attr_accessor :encodingstyle attr_accessor :elename attr_accessor :id attr_reader :precedents attr_accessor :root attr_accessor :parent attr_accessor :position attr_reader :extraattr attr_accessor :definedtype def initialize(*arg) super @encodingstyle = nil @elename = XSD::QName::EMPTY @id = nil @precedents = [] @root = false @parent = nil @position = nil @definedtype = nil @extraattr = {} end def inspect if self.is_a?(XSD::NSDBase) sprintf("#<%s:0x%x %s %s>", self.class.name, __id__, self.elename, self.type) else sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename) end end def rootnode node = self while node = node.parent break if SOAPEnvelope === node end node end end ### ## for SOAP base type # module SOAPBasetype include SOAPType include SOAP def initialize(*arg) super end end ### ## for SOAP compound type # module SOAPCompoundtype include SOAPType include SOAP def initialize(*arg) super end end ### ## Convenience datatypes. # class SOAPReference < XSD::NSDBase include SOAPBasetype extend SOAPModuleUtils public attr_accessor :refid # Override the definition in SOAPBasetype. def initialize(obj = nil) super() @type = XSD::QName::EMPTY @refid = nil @obj = nil __setobj__(obj) if obj end def __getobj__ @obj end def __setobj__(obj) @obj = obj @refid = @obj.id || SOAPReference.create_refid(@obj) @obj.id = @refid unless @obj.id @obj.precedents << self # Copies NSDBase information @obj.type = @type unless @obj.type end # Why don't I use delegate.rb? # -> delegate requires target object type at initialize time. # Why don't I use forwardable.rb? # -> forwardable requires a list of forwarding methods. # # ToDo: Maybe I should use forwardable.rb and give it a methods list like # delegate.rb... # def method_missing(msg_id, *params) if @obj @obj.send(msg_id, *params) else nil end end def refidstr '#' + @refid end def self.create_refid(obj) 'id' + obj.__id__.to_s end def self.decode(elename, refidstr) if /\A#(.*)\z/ =~ refidstr refid = $1 elsif /\Acid:(.*)\z/ =~ refidstr refid = $1 else raise ArgumentError.new("illegal refid #{refidstr}") end d = super(elename) d.refid = refid d end end class SOAPExternalReference < XSD::NSDBase include SOAPBasetype extend SOAPModuleUtils def initialize super() @type = XSD::QName::EMPTY end def referred rootnode.external_content[external_contentid] = self end def refidstr 'cid:' + external_contentid end private def external_contentid raise NotImplementedError.new end end class SOAPNil < XSD::XSDNil include SOAPBasetype extend SOAPModuleUtils end # SOAPRawString is for sending raw string. In contrast to SOAPString, # SOAP4R does not do XML encoding and does not convert its CES. The string it # holds is embedded to XML instance directly as a 'xsd:string'. class SOAPRawString < XSD::XSDString include SOAPBasetype extend SOAPModuleUtils end ### ## Basic datatypes. # class SOAPAnySimpleType < XSD::XSDAnySimpleType include SOAPBasetype extend SOAPModuleUtils end class SOAPString < XSD::XSDString include SOAPBasetype extend SOAPModuleUtils end class SOAPBoolean < XSD::XSDBoolean include SOAPBasetype extend SOAPModuleUtils end class SOAPDecimal < XSD::XSDDecimal include SOAPBasetype extend SOAPModuleUtils end class SOAPFloat < XSD::XSDFloat include SOAPBasetype extend SOAPModuleUtils end class SOAPDouble < XSD::XSDDouble include SOAPBasetype extend SOAPModuleUtils end class SOAPDuration < XSD::XSDDuration include SOAPBasetype extend SOAPModuleUtils end class SOAPDateTime < XSD::XSDDateTime include SOAPBasetype extend SOAPModuleUtils end class SOAPTime < XSD::XSDTime include SOAPBasetype extend SOAPModuleUtils end class SOAPDate < XSD::XSDDate include SOAPBasetype extend SOAPModuleUtils end class SOAPGYearMonth < XSD::XSDGYearMonth include SOAPBasetype extend SOAPModuleUtils end class SOAPGYear < XSD::XSDGYear include SOAPBasetype extend SOAPModuleUtils end class SOAPGMonthDay < XSD::XSDGMonthDay include SOAPBasetype extend SOAPModuleUtils end class SOAPGDay < XSD::XSDGDay include SOAPBasetype extend SOAPModuleUtils end class SOAPGMonth < XSD::XSDGMonth include SOAPBasetype extend SOAPModuleUtils end class SOAPHexBinary < XSD::XSDHexBinary include SOAPBasetype extend SOAPModuleUtils end class SOAPBase64 < XSD::XSDBase64Binary include SOAPBasetype extend SOAPModuleUtils Type = QName.new(EncodingNamespace, Base64Literal) public # Override the definition in SOAPBasetype. def initialize(value = nil) super(value) @type = Type end def as_xsd @type = XSD::XSDBase64Binary::Type end end class SOAPAnyURI < XSD::XSDAnyURI include SOAPBasetype extend SOAPModuleUtils end class SOAPQName < XSD::XSDQName include SOAPBasetype extend SOAPModuleUtils end class SOAPInteger < XSD::XSDInteger include SOAPBasetype extend SOAPModuleUtils end class SOAPNonPositiveInteger < XSD::XSDNonPositiveInteger include SOAPBasetype extend SOAPModuleUtils end class SOAPNegativeInteger < XSD::XSDNegativeInteger include SOAPBasetype extend SOAPModuleUtils end class SOAPLong < XSD::XSDLong include SOAPBasetype extend SOAPModuleUtils end class SOAPInt < XSD::XSDInt include SOAPBasetype extend SOAPModuleUtils end class SOAPShort < XSD::XSDShort include SOAPBasetype extend SOAPModuleUtils end class SOAPByte < XSD::XSDByte include SOAPBasetype extend SOAPModuleUtils end class SOAPNonNegativeInteger < XSD::XSDNonNegativeInteger include SOAPBasetype extend SOAPModuleUtils end class SOAPUnsignedLong < XSD::XSDUnsignedLong include SOAPBasetype extend SOAPModuleUtils end class SOAPUnsignedInt < XSD::XSDUnsignedInt include SOAPBasetype extend SOAPModuleUtils end class SOAPUnsignedShort < XSD::XSDUnsignedShort include SOAPBasetype extend SOAPModuleUtils end class SOAPUnsignedByte < XSD::XSDUnsignedByte include SOAPBasetype extend SOAPModuleUtils end class SOAPPositiveInteger < XSD::XSDPositiveInteger include SOAPBasetype extend SOAPModuleUtils end ### ## Compound datatypes. # class SOAPStruct < XSD::NSDBase include SOAPCompoundtype include Enumerable public def initialize(type = nil) super() @type = type || XSD::QName::EMPTY @array = [] @data = [] end def to_s() str = '' self.each do |key, data| str << "#{key}: #{data}\n" end str end def add(name, value) add_member(name, value) end def [](idx) if idx.is_a?(Range) @data[idx] elsif idx.is_a?(Integer) if (idx > @array.size) raise ArrayIndexOutOfBoundsError.new('In ' << @type.name) end @data[idx] else if @array.include?(idx) @data[@array.index(idx)] else nil end end end def []=(idx, data) if @array.include?(idx) data.parent = self if data.respond_to?(:parent=) @data[@array.index(idx)] = data else add(idx, data) end end def key?(name) @array.include?(name) end def members @array end def to_obj hash = {} proptype = {} each do |k, v| value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s case proptype[k] when :single hash[k] = [hash[k], value] proptype[k] = :multi when :multi hash[k] << value else hash[k] = value proptype[k] = :single end end hash end def each idx = 0 while idx < @array.length yield(@array[idx], @data[idx]) idx += 1 end end def replace members.each do |member| self[member] = yield(self[member]) end end def self.decode(elename, type) s = SOAPStruct.new(type) s.elename = elename s end private def add_member(name, value = nil) value = SOAPNil.new() if value.nil? @array.push(name) value.elename = value.elename.dup_name(name) @data.push(value) value.parent = self if value.respond_to?(:parent=) value end end # SOAPElement is not typed so it is not derived from NSDBase. class SOAPElement include Enumerable attr_accessor :encodingstyle attr_accessor :elename attr_accessor :id attr_reader :precedents attr_accessor :root attr_accessor :parent attr_accessor :position attr_accessor :extraattr attr_accessor :qualified def initialize(elename, text = nil) if !elename.is_a?(XSD::QName) elename = XSD::QName.new(nil, elename) end @encodingstyle = LiteralNamespace @elename = elename @id = nil @precedents = [] @root = false @parent = nil @position = nil @extraattr = {} @qualified = nil @array = [] @data = [] @text = text end def inspect sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename) end # Text interface. attr_accessor :text alias data text # Element interfaces. def add(value) add_member(value.elename.name, value) end def [](idx) if @array.include?(idx) @data[@array.index(idx)] else nil end end def []=(idx, data) if @array.include?(idx) data.parent = self if data.respond_to?(:parent=) @data[@array.index(idx)] = data else add(data) end end def key?(name) @array.include?(name) end def members @array end def to_obj if members.empty? @text else hash = {} proptype = {} each do |k, v| value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s case proptype[k] when :single hash[k] = [hash[k], value] proptype[k] = :multi when :multi hash[k] << value else hash[k] = value proptype[k] = :single end end hash end end def each idx = 0 while idx < @array.length yield(@array[idx], @data[idx]) idx += 1 end end def self.decode(elename) o = SOAPElement.new(elename) o end def self.from_obj(obj, namespace = nil) o = SOAPElement.new(nil) case obj when nil o.text = nil when Hash obj.each do |elename, value| if value.is_a?(Array) value.each do |subvalue| child = from_obj(subvalue, namespace) child.elename = to_elename(elename, namespace) o.add(child) end else child = from_obj(value, namespace) child.elename = to_elename(elename, namespace) o.add(child) end end else o.text = obj.to_s end o end def self.to_elename(obj, namespace = nil) if obj.is_a?(XSD::QName) obj elsif /\A(.+):([^:]+)\z/ =~ obj.to_s XSD::QName.new($1, $2) else XSD::QName.new(namespace, obj.to_s) end end private def add_member(name, value) add_accessor(name) @array.push(name) @data.push(value) value.parent = self if value.respond_to?(:parent=) value end if RUBY_VERSION > "1.7.0" def add_accessor(name) methodname = name if self.respond_to?(methodname) methodname = safe_accessor_name(methodname) end Mapping.define_singleton_method(self, methodname) do @data[@array.index(name)] end Mapping.define_singleton_method(self, methodname + '=') do |value| @data[@array.index(name)] = value end end else def add_accessor(name) methodname = safe_accessor_name(name) instance_eval <<-EOS def #{methodname} @data[@array.index(#{name.dump})] end def #{methodname}=(value) @data[@array.index(#{name.dump})] = value end EOS end end def safe_accessor_name(name) "var_" << name.gsub(/[^a-zA-Z0-9_]/, '') end end class SOAPArray < XSD::NSDBase include SOAPCompoundtype include Enumerable public attr_accessor :sparse attr_reader :offset, :rank attr_accessor :size, :size_fixed attr_reader :arytype def initialize(type = nil, rank = 1, arytype = nil) super() @type = type || ValueArrayName @rank = rank @data = Array.new @sparse = false @offset = Array.new(rank, 0) @size = Array.new(rank, 0) @size_fixed = false @position = nil @arytype = arytype end def offset=(var) @offset = var @sparse = true end def add(value) self[*(@offset)] = value end def [](*idxary) if idxary.size != @rank raise ArgumentError.new("given #{idxary.size} params does not match rank: #{@rank}") end retrieve(idxary) end def []=(*idxary) value = idxary.slice!(-1) if idxary.size != @rank raise ArgumentError.new("given #{idxary.size} params(#{idxary})" + " does not match rank: #{@rank}") end idx = 0 while idx < idxary.size if idxary[idx] + 1 > @size[idx] @size[idx] = idxary[idx] + 1 end idx += 1 end data = retrieve(idxary[0, idxary.size - 1]) data[idxary.last] = value if value.is_a?(SOAPType) value.elename = ITEM_NAME # Sync type unless @type.name @type = XSD::QName.new(value.type.namespace, SOAPArray.create_arytype(value.type.name, @rank)) end value.type ||= @type end @offset = idxary value.parent = self if value.respond_to?(:parent=) offsetnext end def each @data.each do |data| yield(data) end end def to_a @data.dup end def replace @data = deep_map(@data) do |ele| yield(ele) end end def deep_map(ary, &block) ary.collect do |ele| if ele.is_a?(Array) deep_map(ele, &block) else new_obj = block.call(ele) new_obj.elename = ITEM_NAME new_obj end end end def include?(var) traverse_data(@data) do |v, *rank| if v.is_a?(SOAPBasetype) && v.data == var return true end end false end def traverse traverse_data(@data) do |v, *rank| unless @sparse yield(v) else yield(v, *rank) if v && !v.is_a?(SOAPNil) end end end def soap2array(ary) traverse_data(@data) do |v, *position| iteary = ary rank = 1 while rank < position.size idx = position[rank - 1] if iteary[idx].nil? iteary = iteary[idx] = Array.new else iteary = iteary[idx] end rank += 1 end if block_given? iteary[position.last] = yield(v) else iteary[position.last] = v end end end def position @position end private ITEM_NAME = XSD::QName.new(nil, 'item') def retrieve(idxary) data = @data rank = 1 while rank <= idxary.size idx = idxary[rank - 1] if data[idx].nil? data = data[idx] = Array.new else data = data[idx] end rank += 1 end data end def traverse_data(data, rank = 1) idx = 0 while idx < ranksize(rank) if rank < @rank traverse_data(data[idx], rank + 1) do |*v| v[1, 0] = idx yield(*v) end else yield(data[idx], idx) end idx += 1 end end def ranksize(rank) @size[rank - 1] end def offsetnext move = false idx = @offset.size - 1 while !move && idx >= 0 @offset[idx] += 1 if @size_fixed if @offset[idx] < @size[idx] move = true else @offset[idx] = 0 idx -= 1 end else move = true end end end # Module function public def self.decode(elename, type, arytype) typestr, nofary = parse_type(arytype.name) rank = nofary.count(',') + 1 plain_arytype = XSD::QName.new(arytype.namespace, typestr) o = SOAPArray.new(type, rank, plain_arytype) size = [] nofary.split(',').each do |s| if s.empty? size.clear break else size << s.to_i end end unless size.empty? o.size = size o.size_fixed = true end o.elename = elename o end private def self.create_arytype(typename, rank) "#{typename}[" << ',' * (rank - 1) << ']' end TypeParseRegexp = Regexp.new('^(.+)\[([\d,]*)\]$') def self.parse_type(string) TypeParseRegexp =~ string return $1, $2 end end require 'soap/mapping/typeMap' end PK|]C`pppsoap/streamHandler.rbnu[# SOAP4R - Stream handler. # Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/httpconfigloader' begin require 'stringio' require 'zlib' rescue LoadError warn("Loading stringio or zlib failed. No gzipped response support.") if $DEBUG end module SOAP class StreamHandler RUBY_VERSION_STRING = "ruby #{ RUBY_VERSION } (#{ RUBY_RELEASE_DATE }) [#{ RUBY_PLATFORM }]" class ConnectionData attr_accessor :send_string attr_accessor :send_contenttype attr_accessor :receive_string attr_accessor :receive_contenttype attr_accessor :is_fault attr_accessor :soapaction def initialize(send_string = nil) @send_string = send_string @send_contenttype = nil @receive_string = nil @receive_contenttype = nil @is_fault = false @soapaction = nil end end def self.parse_media_type(str) if /^#{ MediaType }(?:\s*;\s*charset=([^"]+|"[^"]+"))?$/i !~ str return nil end charset = $1 charset.gsub!(/"/, '') if charset charset || 'us-ascii' end def self.create_media_type(charset) "#{ MediaType }; charset=#{ charset }" end end class HTTPStreamHandler < StreamHandler include SOAP begin require 'http-access2' if HTTPAccess2::VERSION < "2.0" raise LoadError.new("http-access/2.0 or later is required.") end Client = HTTPAccess2::Client RETRYABLE = true rescue LoadError warn("Loading http-access2 failed. Net/http is used.") if $DEBUG require 'soap/netHttpClient' Client = SOAP::NetHttpClient RETRYABLE = false end public attr_reader :client attr_accessor :wiredump_file_base MAX_RETRY_COUNT = 10 # [times] def initialize(options) super() @client = Client.new(nil, "SOAP4R/#{ Version }") @wiredump_file_base = nil @charset = @wiredump_dev = nil @options = options set_options @client.debug_dev = @wiredump_dev @cookie_store = nil @accept_encoding_gzip = false end def test_loopback_response @client.test_loopback_response end def accept_encoding_gzip=(allow) @accept_encoding_gzip = allow end def inspect "#<#{self.class}>" end def send(endpoint_url, conn_data, soapaction = nil, charset = @charset) conn_data.soapaction ||= soapaction # for backward conpatibility send_post(endpoint_url, conn_data, charset) end def reset(endpoint_url = nil) if endpoint_url.nil? @client.reset_all else @client.reset(endpoint_url) end @client.save_cookie_store if @cookie_store end private def set_options HTTPConfigLoader.set_options(@client, @options) @charset = @options["charset"] || XSD::Charset.xml_encoding_label @options.add_hook("charset") do |key, value| @charset = value end @wiredump_dev = @options["wiredump_dev"] @options.add_hook("wiredump_dev") do |key, value| @wiredump_dev = value @client.debug_dev = @wiredump_dev end set_cookie_store_file(@options["cookie_store_file"]) @options.add_hook("cookie_store_file") do |key, value| set_cookie_store_file(value) end ssl_config = @options["ssl_config"] basic_auth = @options["basic_auth"] @options.lock(true) ssl_config.unlock basic_auth.unlock end def set_cookie_store_file(value) value = nil if value and value.empty? @cookie_store = value @client.set_cookie_store(@cookie_store) if @cookie_store end def send_post(endpoint_url, conn_data, charset) conn_data.send_contenttype ||= StreamHandler.create_media_type(charset) if @wiredump_file_base filename = @wiredump_file_base + '_request.xml' f = File.open(filename, "w") f << conn_data.send_string f.close end extra = {} extra['Content-Type'] = conn_data.send_contenttype extra['SOAPAction'] = "\"#{ conn_data.soapaction }\"" extra['Accept-Encoding'] = 'gzip' if send_accept_encoding_gzip? send_string = conn_data.send_string @wiredump_dev << "Wire dump:\n\n" if @wiredump_dev begin retry_count = 0 while true res = @client.post(endpoint_url, send_string, extra) if RETRYABLE and HTTP::Status.redirect?(res.status) retry_count += 1 if retry_count >= MAX_RETRY_COUNT raise HTTPStreamError.new("redirect count exceeded") end endpoint_url = res.header["location"][0] puts "redirected to #{endpoint_url}" if $DEBUG else break end end rescue @client.reset(endpoint_url) raise end @wiredump_dev << "\n\n" if @wiredump_dev receive_string = res.content if @wiredump_file_base filename = @wiredump_file_base + '_response.xml' f = File.open(filename, "w") f << receive_string f.close end case res.status when 405 raise PostUnavailableError.new("#{ res.status }: #{ res.reason }") when 200, 500 # Nothing to do. else raise HTTPStreamError.new("#{ res.status }: #{ res.reason }") end if res.respond_to?(:header) and !res.header['content-encoding'].empty? and res.header['content-encoding'][0].downcase == 'gzip' receive_string = decode_gzip(receive_string) end conn_data.receive_string = receive_string conn_data.receive_contenttype = res.contenttype conn_data end def send_accept_encoding_gzip? @accept_encoding_gzip and defined?(::Zlib) end def decode_gzip(instring) unless send_accept_encoding_gzip? raise HTTPStreamError.new("Gzipped response content.") end begin gz = Zlib::GzipReader.new(StringIO.new(instring)) gz.read ensure gz.close end end end end PK|]X'soap/mimemessage.rbnu[# SOAP4R - MIME Message implementation. # Copyright (C) 2002 Jamie Herre. # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/attachment' module SOAP # Classes for MIME message handling. Should be put somewhere else! # Tried using the 'tmail' module but found that I needed something # lighter in weight. class MIMEMessage class MIMEMessageError < StandardError; end MultipartContentType = 'multipart/\w+' class Header attr_accessor :str, :key, :root def initialize @attrs = {} end def [](key) @attrs[key] end def []=(key, value) @attrs[key] = value end def to_s @key + ": " + @str end end class Headers < Hash def self.parse(str) new.parse(str) end def parse(str) header_cache = nil str.each do |line| case line when /^\A[^\: \t]+:\s*.+$/ parse_line(header_cache) if header_cache header_cache = line.sub(/\r?\n\z/, '') when /^\A\s+(.*)$/ # a continuous line at the beginning line crashes here. header_cache << line else raise RuntimeError.new("unexpected header: #{line.inspect}") end end parse_line(header_cache) if header_cache self end def parse_line(line) if /^\A([^\: \t]+):\s*(.+)\z/ =~ line header = parse_rhs($2.strip) header.key = $1.strip self[header.key.downcase] = header else raise RuntimeError.new("unexpected header line: #{line.inspect}") end end def parse_rhs(str) a = str.split(/;+\s+/) header = Header.new header.str = str header.root = a.shift a.each do |pair| if pair =~ /(\w+)\s*=\s*"?([^"]+)"?/ header[$1.downcase] = $2 else raise RuntimeError.new("unexpected header component: #{pair.inspect}") end end header end def add(key, value) if key != nil and value != nil header = parse_rhs(value) header.key = key self[key.downcase] = header end end def to_s self.values.collect { |hdr| hdr.to_s }.join("\r\n") end end class Part attr_accessor :headers, :body def initialize @headers = Headers.new @headers.add("Content-Transfer-Encoding", "8bit") @body = nil @contentid = nil end def self.parse(str) new.parse(str) end def parse(str) headers, body = str.split(/\r\n\r\n/s) if headers != nil and body != nil @headers = Headers.parse(headers) @body = body.sub(/\r\n\z/, '') else raise RuntimeError.new("unexpected part: #{str.inspect}") end self end def contentid if @contentid == nil and @headers.key?('content-id') @contentid = @headers['content-id'].str @contentid = $1 if @contentid =~ /^<(.+)>$/ end @contentid end alias content body def to_s @headers.to_s + "\r\n\r\n" + @body end end def initialize @parts = [] @headers = Headers.new @root = nil end def self.parse(head, str) new.parse(head, str) end attr_reader :parts, :headers def close @headers.add( "Content-Type", "multipart/related; type=\"text/xml\"; boundary=\"#{boundary}\"; start=\"#{@parts[0].contentid}\"" ) end def parse(head, str) @headers = Headers.parse(head + "\r\n" + "From: jfh\r\n") boundary = @headers['content-type']['boundary'] if boundary != nil parts = str.split(/--#{Regexp.quote(boundary)}\s*(?:\r\n|--\r\n)/) part = parts.shift # preamble must be ignored. @parts = parts.collect { |part| Part.parse(part) } else @parts = [Part.parse(str)] end if @parts.length < 1 raise MIMEMessageError.new("This message contains no valid parts!") end self end def root if @root == nil start = @headers['content-type']['start'] @root = (start && @parts.find { |prt| prt.contentid == start }) || @parts[0] end @root end def boundary if @boundary == nil @boundary = "----=Part_" + __id__.to_s + rand.to_s end @boundary end def add_part(content) part = Part.new part.headers.add("Content-Type", "text/xml; charset=" + XSD::Charset.xml_encoding_label) part.headers.add("Content-ID", Attachment.contentid(part)) part.body = content @parts.unshift(part) end def add_attachment(attach) part = Part.new part.headers.add("Content-Type", attach.contenttype) part.headers.add("Content-ID", attach.mime_contentid) part.body = attach.content @parts.unshift(part) end def has_parts? (@parts.length > 0) end def headers_str @headers.to_s end def content_str str = '' @parts.each do |prt| str << "--" + boundary + "\r\n" str << prt.to_s + "\r\n" end str << '--' + boundary + "--\r\n" str end def to_s str = headers_str + "\r\n\r\n" + content_str end end end PK|]usoap/generator.rbnu[# SOAP4R - SOAP XML Instance Generator library. # Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/ns' require 'soap/soap' require 'soap/baseData' require 'soap/encodingstyle/handler' module SOAP ### ## CAUTION: MT-unsafe # class SOAPGenerator include SOAP class FormatEncodeError < Error; end public attr_accessor :charset attr_accessor :default_encodingstyle attr_accessor :generate_explicit_type attr_accessor :use_numeric_character_reference def initialize(opt = {}) @reftarget = nil @handlers = {} @charset = opt[:charset] || XSD::Charset.xml_encoding_label @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace @generate_explicit_type = opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true @elementformdefault = opt[:elementformdefault] @attributeformdefault = opt[:attributeformdefault] @use_numeric_character_reference = opt[:use_numeric_character_reference] @indentstr = opt[:no_indent] ? '' : ' ' @buf = @indent = @curr = nil end def generate(obj, io = nil) @buf = io || '' @indent = '' prologue @handlers.each do |uri, handler| handler.encode_prologue end ns = XSD::NS.new @buf << xmldecl encode_data(ns, obj, nil) @handlers.each do |uri, handler| handler.encode_epilogue end epilogue @buf end def encode_data(ns, obj, parent) if obj.is_a?(SOAPEnvelopeElement) encode_element(ns, obj, parent) return end if @reftarget && !obj.precedents.empty? add_reftarget(obj.elename.name, obj) ref = SOAPReference.new(obj) ref.elename = ref.elename.dup_name(obj.elename.name) obj.precedents.clear # Avoid cyclic delay. obj.encodingstyle = parent.encodingstyle # SOAPReference is encoded here. obj = ref end encodingstyle = obj.encodingstyle # Children's encodingstyle is derived from its parent. encodingstyle ||= parent.encodingstyle if parent obj.encodingstyle = encodingstyle handler = find_handler(encodingstyle || @default_encodingstyle) unless handler raise FormatEncodeError.new("Unknown encodingStyle: #{ encodingstyle }.") end if !obj.elename.name raise FormatEncodeError.new("Element name not defined: #{ obj }.") end handler.encode_data(self, ns, obj, parent) handler.encode_data_end(self, ns, obj, parent) end def add_reftarget(name, node) unless @reftarget raise FormatEncodeError.new("Reftarget is not defined.") end @reftarget.add(name, node) end def encode_child(ns, child, parent) indent_backup, @indent = @indent, @indent + @indentstr encode_data(ns.clone_ns, child, parent) @indent = indent_backup end def encode_element(ns, obj, parent) attrs = {} if obj.is_a?(SOAPBody) @reftarget = obj obj.encode(self, ns, attrs) do |child| indent_backup, @indent = @indent, @indent + @indentstr encode_data(ns.clone_ns, child, obj) @indent = indent_backup end @reftarget = nil else if obj.is_a?(SOAPEnvelope) # xsi:nil="true" can appear even if dumping without explicit type. SOAPGenerator.assign_ns(attrs, ns, XSD::InstanceNamespace, XSINamespaceTag) if @generate_explicit_type SOAPGenerator.assign_ns(attrs, ns, XSD::Namespace, XSDNamespaceTag) end end obj.encode(self, ns, attrs) do |child| indent_backup, @indent = @indent, @indent + @indentstr encode_data(ns.clone_ns, child, obj) @indent = indent_backup end end end def encode_name(ns, data, attrs) if element_local?(data) data.elename.name else if element_qualified?(data) SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace, '') else SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace) end ns.name(data.elename) end end def encode_name_end(ns, data) if element_local?(data) data.elename.name else ns.name(data.elename) end end def encode_tag(elename, attrs = nil) if !attrs or attrs.empty? @buf << "\n#{ @indent }<#{ elename }>" elsif attrs.size == 1 key, value = attrs.shift @buf << %Q[\n#{ @indent }<#{ elename } #{ key }="#{ value }">] else @buf << "\n#{ @indent }<#{ elename } " << attrs.collect { |key, value| %Q[#{ key }="#{ value }"] }.join("\n#{ @indent }#{ @indentstr * 2 }") << '>' end end def encode_tag_end(elename, cr = nil) if cr @buf << "\n#{ @indent }" else @buf << "" end end def encode_rawstring(str) @buf << str end EncodeMap = { '&' => '&', '<' => '<', '>' => '>', '"' => '"', '\'' => ''', "\r" => ' ' } EncodeCharRegexp = Regexp.new("[#{EncodeMap.keys.join}]") def encode_string(str) if @use_numeric_character_reference and !XSD::Charset.is_us_ascii(str) str.gsub!(EncodeCharRegexp) { |c| EncodeMap[c] } @buf << str.unpack("U*").collect { |c| if c == 0x9 or c == 0xa or c == 0xd or (c >= 0x20 and c <= 0x7f) c.chr else sprintf("&#x%x;", c) end }.join else @buf << str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] } end end def element_local?(element) element.elename.namespace.nil? end def element_qualified?(element) if element.respond_to?(:qualified) if element.qualified.nil? @elementformdefault else element.qualified end else @elementformdefault end end def self.assign_ns(attrs, ns, namespace, tag = nil) if namespace.nil? raise FormatEncodeError.new("empty namespace") end unless ns.assigned?(namespace) tag = ns.assign(namespace, tag) if tag == '' attr = 'xmlns' else attr = "xmlns:#{tag}" end attrs[attr] = namespace end end private def prologue end def epilogue end def find_handler(encodingstyle) unless @handlers.key?(encodingstyle) handler = SOAP::EncodingStyle::Handler.handler(encodingstyle).new(@charset) handler.generate_explicit_type = @generate_explicit_type handler.encode_prologue @handlers[encodingstyle] = handler end @handlers[encodingstyle] end def xmldecl if @charset %Q[] else %Q[] end end end end PK|]Tsoap/header/handler.rbnu[# SOAP4R - SOAP Header handler item # Copyright (C) 2003, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/element' module SOAP module Header class Handler attr_reader :elename attr_reader :mustunderstand attr_reader :encodingstyle def initialize(elename) @elename = elename @mustunderstand = false @encodingstyle = nil end # Should return a SOAP/OM, a SOAPHeaderItem or nil. def on_outbound nil end # Given header is a SOAPHeaderItem or nil. def on_inbound(header, mustunderstand = false) # do something. end def on_outbound_headeritem item = on_outbound if item.nil? nil elsif item.is_a?(::SOAP::SOAPHeaderItem) item.elename = @elename item else item.elename = @elename ::SOAP::SOAPHeaderItem.new(item, @mustunderstand, @encodingstyle) end end def on_inbound_headeritem(header) on_inbound(header.element, header.mustunderstand) end end end end PK|]!--soap/header/handlerset.rbnu[# SOAP4R - SOAP Header handler set # Copyright (C) 2003, 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/namedelements' module SOAP module Header class HandlerSet def initialize @store = XSD::NamedElements.new end def dup obj = HandlerSet.new obj.store = @store.dup obj end def add(handler) @store << handler end alias << add def delete(handler) @store.delete(handler) end def include?(handler) @store.include?(handler) end # returns: Array of SOAPHeaderItem def on_outbound @store.collect { |handler| handler.on_outbound_headeritem }.compact end # headers: SOAPHeaderItem enumerable object def on_inbound(headers) headers.each do |name, item| handler = @store.find { |handler| handler.elename == item.element.elename } if handler handler.on_inbound_headeritem(item) elsif item.mustunderstand raise UnhandledMustUnderstandHeaderError.new(item.element.elename.to_s) end end end protected def store=(store) @store = store end end end end PK|]Nܣsoap/header/simplehandler.rbnu[# SOAP4R - SOAP Simple header item handler # Copyright (C) 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/header/handler' require 'soap/baseData' module SOAP module Header class SimpleHandler < SOAP::Header::Handler def initialize(elename) super(elename) end # Should return a Hash, String or nil. def on_simple_outbound nil end # Given header is a Hash, String or nil. def on_simple_inbound(header, mustunderstand) end def on_outbound h = on_simple_outbound h ? SOAPElement.from_obj(h, elename.namespace) : nil end def on_inbound(header, mustunderstand) h = header.respond_to?(:to_obj) ? header.to_obj : header.data on_simple_inbound(h, mustunderstand) end end end end PK|]&mBW @ @soap/mapping/registry.rbnu[# SOAP4R - Mapping registry. # Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/baseData' require 'soap/mapping/mapping' require 'soap/mapping/typeMap' require 'soap/mapping/factory' require 'soap/mapping/rubytypeFactory' module SOAP module Marshallable # @@type_ns = Mapping::RubyCustomTypeNamespace end module Mapping module MappedException; end RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType') RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends') RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars') # Inner class to pass an exception. class SOAPException; include Marshallable attr_reader :excn_type_name, :cause def initialize(e) @excn_type_name = Mapping.name2elename(e.class.to_s) @cause = e end def to_e if @cause.is_a?(::Exception) @cause.extend(::SOAP::Mapping::MappedException) return @cause elsif @cause.respond_to?(:message) and @cause.respond_to?(:backtrace) e = RuntimeError.new(@cause.message) e.set_backtrace(@cause.backtrace) return e end klass = Mapping.class_from_name(Mapping.elename2name(@excn_type_name.to_s)) if klass.nil? or not klass <= ::Exception return RuntimeError.new(@cause.inspect) end obj = klass.new(@cause.message) obj.extend(::SOAP::Mapping::MappedException) obj end end # For anyType object: SOAP::Mapping::Object not ::Object class Object; include Marshallable def initialize @__xmlele_type = {} @__xmlele = [] @__xmlattr = {} end def inspect sprintf("#<%s:0x%x%s>", self.class.name, __id__, @__xmlele.collect { |name, value| " #{name}=#{value.inspect}" }.join) end def __xmlattr @__xmlattr end def __xmlele @__xmlele end def [](qname) unless qname.is_a?(XSD::QName) qname = XSD::QName.new(nil, qname) end @__xmlele.each do |k, v| return v if k == qname end # fallback @__xmlele.each do |k, v| return v if k.name == qname.name end nil end def []=(qname, value) unless qname.is_a?(XSD::QName) qname = XSD::QName.new(nil, qname) end found = false @__xmlele.each do |pair| if pair[0] == qname found = true pair[1] = value end end unless found __define_attr_accessor(qname) @__xmlele << [qname, value] end @__xmlele_type[qname] = :single end def __add_xmlele_value(qname, value) found = false @__xmlele.map! do |k, v| if k == qname found = true [k, __set_xmlele_value(k, v, value)] else [k, v] end end unless found __define_attr_accessor(qname) @__xmlele << [qname, value] @__xmlele_type[qname] = :single end value end private if RUBY_VERSION > "1.7.0" def __define_attr_accessor(qname) name = XSD::CodeGen::GenSupport.safemethodname(qname.name) Mapping.define_attr_accessor(self, name, proc { self[qname] }, proc { |value| self[qname] = value }) end else def __define_attr_accessor(qname) name = XSD::CodeGen::GenSupport.safemethodname(qname.name) instance_eval <<-EOS def #{name} self[#{qname.dump}] end def #{name}=(value) self[#{qname.dump}] = value end EOS end end def __set_xmlele_value(key, org, value) case @__xmlele_type[key] when :multi org << value org when :single @__xmlele_type[key] = :multi [org, value] else raise RuntimeError.new("unknown type") end end end class MappingError < Error; end class Registry class Map def initialize(registry) @obj2soap = {} @soap2obj = {} @registry = registry end def obj2soap(obj) klass = obj.class if map = @obj2soap[klass] map.each do |soap_class, factory, info| ret = factory.obj2soap(soap_class, obj, info, @registry) return ret if ret end end ancestors = klass.ancestors ancestors.delete(klass) ancestors.delete(::Object) ancestors.delete(::Kernel) ancestors.each do |klass| if map = @obj2soap[klass] map.each do |soap_class, factory, info| if info[:derived_class] ret = factory.obj2soap(soap_class, obj, info, @registry) return ret if ret end end end end nil end def soap2obj(node, klass = nil) if map = @soap2obj[node.class] map.each do |obj_class, factory, info| next if klass and obj_class != klass conv, obj = factory.soap2obj(obj_class, node, info, @registry) return true, obj if conv end end return false, nil end # Give priority to former entry. def init(init_map = []) clear init_map.reverse_each do |obj_class, soap_class, factory, info| add(obj_class, soap_class, factory, info) end end # Give priority to latter entry. def add(obj_class, soap_class, factory, info) info ||= {} (@obj2soap[obj_class] ||= []).unshift([soap_class, factory, info]) (@soap2obj[soap_class] ||= []).unshift([obj_class, factory, info]) end def clear @obj2soap.clear @soap2obj.clear end def find_mapped_soap_class(target_obj_class) map = @obj2soap[target_obj_class] map.empty? ? nil : map[0][1] end def find_mapped_obj_class(target_soap_class) map = @soap2obj[target_soap_class] map.empty? ? nil : map[0][0] end end StringFactory = StringFactory_.new BasetypeFactory = BasetypeFactory_.new DateTimeFactory = DateTimeFactory_.new ArrayFactory = ArrayFactory_.new Base64Factory = Base64Factory_.new URIFactory = URIFactory_.new TypedArrayFactory = TypedArrayFactory_.new TypedStructFactory = TypedStructFactory_.new HashFactory = HashFactory_.new SOAPBaseMap = [ [::NilClass, ::SOAP::SOAPNil, BasetypeFactory], [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory], [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory], [::String, ::SOAP::SOAPString, StringFactory], [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory], [::Date, ::SOAP::SOAPDate, DateTimeFactory], [::Time, ::SOAP::SOAPDateTime, DateTimeFactory], [::Time, ::SOAP::SOAPTime, DateTimeFactory], [::Float, ::SOAP::SOAPDouble, BasetypeFactory, {:derived_class => true}], [::Float, ::SOAP::SOAPFloat, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPInt, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPLong, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPShort, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPByte, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory, {:derived_class => true}], [::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory, {:derived_class => true}], [::String, ::SOAP::SOAPBase64, Base64Factory], [::String, ::SOAP::SOAPHexBinary, Base64Factory], [::String, ::SOAP::SOAPDecimal, BasetypeFactory], [::String, ::SOAP::SOAPDuration, BasetypeFactory], [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory], [::String, ::SOAP::SOAPGYear, BasetypeFactory], [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory], [::String, ::SOAP::SOAPGDay, BasetypeFactory], [::String, ::SOAP::SOAPGMonth, BasetypeFactory], [::String, ::SOAP::SOAPQName, BasetypeFactory], [::Hash, ::SOAP::SOAPArray, HashFactory], [::Hash, ::SOAP::SOAPStruct, HashFactory], [::Array, ::SOAP::SOAPArray, ArrayFactory, {:derived_class => true}], [::SOAP::Mapping::SOAPException, ::SOAP::SOAPStruct, TypedStructFactory, {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}], ] RubyOriginalMap = [ [::NilClass, ::SOAP::SOAPNil, BasetypeFactory], [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory], [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory], [::String, ::SOAP::SOAPString, StringFactory], [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory], [::Date, ::SOAP::SOAPDate, DateTimeFactory], [::Time, ::SOAP::SOAPDateTime, DateTimeFactory], [::Time, ::SOAP::SOAPTime, DateTimeFactory], [::Float, ::SOAP::SOAPDouble, BasetypeFactory, {:derived_class => true}], [::Float, ::SOAP::SOAPFloat, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPInt, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPLong, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPShort, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPByte, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory, {:derived_class => true}], [::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory, {:derived_class => true}], [::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory, {:derived_class => true}], [::String, ::SOAP::SOAPBase64, Base64Factory], [::String, ::SOAP::SOAPHexBinary, Base64Factory], [::String, ::SOAP::SOAPDecimal, BasetypeFactory], [::String, ::SOAP::SOAPDuration, BasetypeFactory], [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory], [::String, ::SOAP::SOAPGYear, BasetypeFactory], [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory], [::String, ::SOAP::SOAPGDay, BasetypeFactory], [::String, ::SOAP::SOAPGMonth, BasetypeFactory], [::String, ::SOAP::SOAPQName, BasetypeFactory], [::Hash, ::SOAP::SOAPArray, HashFactory], [::Hash, ::SOAP::SOAPStruct, HashFactory], # Does not allow Array's subclass here. [::Array, ::SOAP::SOAPArray, ArrayFactory], [::SOAP::Mapping::SOAPException, ::SOAP::SOAPStruct, TypedStructFactory, {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}], ] attr_accessor :default_factory attr_accessor :excn_handler_obj2soap attr_accessor :excn_handler_soap2obj def initialize(config = {}) @config = config @map = Map.new(self) if @config[:allow_original_mapping] @allow_original_mapping = true @map.init(RubyOriginalMap) else @allow_original_mapping = false @map.init(SOAPBaseMap) end @allow_untyped_struct = @config.key?(:allow_untyped_struct) ? @config[:allow_untyped_struct] : true @rubytype_factory = RubytypeFactory.new( :allow_untyped_struct => @allow_untyped_struct, :allow_original_mapping => @allow_original_mapping ) @default_factory = @rubytype_factory @excn_handler_obj2soap = nil @excn_handler_soap2obj = nil end def add(obj_class, soap_class, factory, info = nil) @map.add(obj_class, soap_class, factory, info) end alias set add # general Registry ignores type_qname def obj2soap(obj, type_qname = nil) soap = _obj2soap(obj) if @allow_original_mapping addextend2soap(soap, obj) end soap end def soap2obj(node, klass = nil) obj = _soap2obj(node, klass) if @allow_original_mapping addextend2obj(obj, node.extraattr[RubyExtendName]) addiv2obj(obj, node.extraattr[RubyIVarName]) end obj end def find_mapped_soap_class(obj_class) @map.find_mapped_soap_class(obj_class) end def find_mapped_obj_class(soap_class) @map.find_mapped_obj_class(soap_class) end private def _obj2soap(obj) ret = nil if obj.is_a?(SOAPStruct) or obj.is_a?(SOAPArray) obj.replace do |ele| Mapping._obj2soap(ele, self) end return obj elsif obj.is_a?(SOAPBasetype) return obj end begin ret = @map.obj2soap(obj) || @default_factory.obj2soap(nil, obj, nil, self) return ret if ret rescue MappingError end if @excn_handler_obj2soap ret = @excn_handler_obj2soap.call(obj) { |yield_obj| Mapping._obj2soap(yield_obj, self) } return ret if ret end raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.") end # Might return nil as a mapping result. def _soap2obj(node, klass = nil) if node.extraattr.key?(RubyTypeName) conv, obj = @rubytype_factory.soap2obj(nil, node, nil, self) return obj if conv else conv, obj = @map.soap2obj(node, klass) return obj if conv conv, obj = @default_factory.soap2obj(nil, node, nil, self) return obj if conv end if @excn_handler_soap2obj begin return @excn_handler_soap2obj.call(node) { |yield_node| Mapping._soap2obj(yield_node, self) } rescue Exception end end raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.") end def addiv2obj(obj, attr) return unless attr vars = {} attr.__getobj__.each do |name, value| vars[name] = Mapping._soap2obj(value, self) end Mapping.set_attributes(obj, vars) end if RUBY_VERSION >= '1.8.0' def addextend2obj(obj, attr) return unless attr attr.split(/ /).reverse_each do |mstr| obj.extend(Mapping.module_from_name(mstr)) end end else # (class < false; self; end).ancestors includes "TrueClass" under 1.6... def addextend2obj(obj, attr) return unless attr attr.split(/ /).reverse_each do |mstr| m = Mapping.module_from_name(mstr) obj.extend(m) end end end def addextend2soap(node, obj) return if obj.is_a?(Symbol) or obj.is_a?(Fixnum) list = (class << obj; self; end).ancestors - obj.class.ancestors unless list.empty? node.extraattr[RubyExtendName] = list.collect { |c| if c.name.empty? raise TypeError.new("singleton can't be dumped #{ obj }") end c.name }.join(" ") end end end DefaultRegistry = Registry.new RubyOriginalRegistry = Registry.new(:allow_original_mapping => true) end end PK|]X&++soap/mapping/mapping.rbnu[# SOAP4R - Ruby type mapping utility. # Copyright (C) 2000, 2001, 2003-2005 NAKAMURA Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' module SOAP module Mapping RubyTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/1.6' RubyTypeInstanceNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type-instance' RubyCustomTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/custom' ApacheSOAPTypeNamespace = 'http://xml.apache.org/xml-soap' # TraverseSupport breaks following thread variables. # Thread.current[:SOAPMarshalDataKey] module TraverseSupport def mark_marshalled_obj(obj, soap_obj) raise if obj.nil? Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj end def mark_unmarshalled_obj(node, obj) return if obj.nil? # node.id is not Object#id but SOAPReference#id Thread.current[:SOAPMarshalDataKey][node.id] = obj end end EMPTY_OPT = {} def self.obj2soap(obj, registry = nil, type = nil, opt = EMPTY_OPT) registry ||= Mapping::DefaultRegistry soap_obj = nil protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do Thread.current[:SOAPMarshalDataKey] = {} Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] soap_obj = _obj2soap(obj, registry, type) end soap_obj end def self.soap2obj(node, registry = nil, klass = nil, opt = EMPTY_OPT) registry ||= Mapping::DefaultRegistry obj = nil protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do Thread.current[:SOAPMarshalDataKey] = {} Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] obj = _soap2obj(node, registry, klass) end obj end def self.ary2soap(ary, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT) registry ||= Mapping::DefaultRegistry type = XSD::QName.new(type_ns, typename) soap_ary = SOAPArray.new(ValueArrayName, 1, type) protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do Thread.current[:SOAPMarshalDataKey] = {} Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] ary.each do |ele| soap_ary.add(_obj2soap(ele, registry, type)) end end soap_ary end def self.ary2md(ary, rank, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT) registry ||= Mapping::DefaultRegistry type = XSD::QName.new(type_ns, typename) md_ary = SOAPArray.new(ValueArrayName, rank, type) protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do Thread.current[:SOAPMarshalDataKey] = {} Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] add_md_ary(md_ary, ary, [], registry) end md_ary end def self.fault2exception(fault, registry = nil) registry ||= Mapping::DefaultRegistry detail = if fault.detail soap2obj(fault.detail, registry) || "" else "" end if detail.is_a?(Mapping::SOAPException) begin e = detail.to_e remote_backtrace = e.backtrace e.set_backtrace(nil) raise e # ruby sets current caller as local backtrace of e => e2. rescue Exception => e e.set_backtrace(remote_backtrace + e.backtrace[1..-1]) raise end else fault.detail = detail fault.set_backtrace( if detail.is_a?(Array) detail else [detail.to_s] end ) raise end end def self._obj2soap(obj, registry, type = nil) if referent = Thread.current[:SOAPMarshalDataKey][obj.__id__] and !Thread.current[:SOAPMarshalNoReference] SOAPReference.new(referent) elsif registry registry.obj2soap(obj, type) else raise MappingError.new("no mapping registry given") end end def self._soap2obj(node, registry, klass = nil) if node.nil? return nil elsif node.is_a?(SOAPReference) target = node.__getobj__ # target.id is not Object#id but SOAPReference#id if referent = Thread.current[:SOAPMarshalDataKey][target.id] and !Thread.current[:SOAPMarshalNoReference] return referent else return _soap2obj(target, registry, klass) end end return registry.soap2obj(node, klass) end if Object.respond_to?(:allocate) # ruby/1.7 or later. def self.create_empty_object(klass) klass.allocate end else MARSHAL_TAG = { String => ['"', 1], Regexp => ['/', 2], Array => ['[', 1], Hash => ['{', 1] } def self.create_empty_object(klass) if klass <= Struct name = klass.name return ::Marshal.load(sprintf("\004\006S:%c%s\000", name.length + 5, name)) end if MARSHAL_TAG.has_key?(klass) tag, terminate = MARSHAL_TAG[klass] return ::Marshal.load(sprintf("\004\006%s%s", tag, "\000" * terminate)) end MARSHAL_TAG.each do |k, v| if klass < k name = klass.name tag, terminate = v return ::Marshal.load(sprintf("\004\006C:%c%s%s%s", name.length + 5, name, tag, "\000" * terminate)) end end name = klass.name ::Marshal.load(sprintf("\004\006o:%c%s\000", name.length + 5, name)) end end # Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here. # Caution: '.' is not allowed here. # To follow XML spec., it should be NCName. # (denied chars) => .[0-F][0-F] # ex. a.b => a.2eb # def self.name2elename(name) name.gsub(/([^a-zA-Z0-9:_\-]+)/n) { '.' << $1.unpack('H2' * $1.size).join('.') }.gsub(/::/n, '..') end def self.elename2name(name) name.gsub(/\.\./n, '::').gsub(/((?:\.[0-9a-fA-F]{2})+)/n) { [$1.delete('.')].pack('H*') } end def self.const_from_name(name, lenient = false) const = ::Object name.sub(/\A::/, '').split('::').each do |const_str| if XSD::CodeGen::GenSupport.safeconstname?(const_str) if const.const_defined?(const_str) const = const.const_get(const_str) next end elsif lenient const_str = XSD::CodeGen::GenSupport.safeconstname(const_str) if const.const_defined?(const_str) const = const.const_get(const_str) next end end return nil end const end def self.class_from_name(name, lenient = false) const = const_from_name(name, lenient) if const.is_a?(::Class) const else nil end end def self.module_from_name(name, lenient = false) const = const_from_name(name, lenient) if const.is_a?(::Module) const else nil end end def self.class2qname(klass) name = schema_type_definition(klass) namespace = schema_ns_definition(klass) XSD::QName.new(namespace, name) end def self.class2element(klass) type = Mapping.class2qname(klass) type.name ||= Mapping.name2elename(klass.name) type.namespace ||= RubyCustomTypeNamespace type end def self.obj2element(obj) name = namespace = nil ivars = obj.instance_variables if ivars.include?('@schema_type') name = obj.instance_variable_get('@schema_type') end if ivars.include?('@schema_ns') namespace = obj.instance_variable_get('@schema_ns') end if !name or !namespace class2qname(obj.class) else XSD::QName.new(namespace, name) end end def self.define_singleton_method(obj, name, &block) sclass = (class << obj; self; end) sclass.class_eval { define_method(name, &block) } end def self.get_attribute(obj, attr_name) if obj.is_a?(::Hash) obj[attr_name] || obj[attr_name.intern] else name = XSD::CodeGen::GenSupport.safevarname(attr_name) if obj.instance_variables.include?('@' + name) obj.instance_variable_get('@' + name) elsif ((obj.is_a?(::Struct) or obj.is_a?(Marshallable)) and obj.respond_to?(name)) obj.__send__(name) end end end def self.set_attributes(obj, values) if obj.is_a?(::SOAP::Mapping::Object) values.each do |attr_name, value| obj.__add_xmlele_value(attr_name, value) end else values.each do |attr_name, value| name = XSD::CodeGen::GenSupport.safevarname(attr_name) setter = name + "=" if obj.respond_to?(setter) obj.__send__(setter, value) else obj.instance_variable_set('@' + name, value) begin define_attr_accessor(obj, name, proc { instance_variable_get('@' + name) }, proc { |value| instance_variable_set('@' + name, value) }) rescue TypeError # singleton class may not exist (e.g. Float) end end end end end def self.define_attr_accessor(obj, name, getterproc, setterproc = nil) define_singleton_method(obj, name, &getterproc) define_singleton_method(obj, name + '=', &setterproc) if setterproc end def self.schema_type_definition(klass) class_schema_variable(:schema_type, klass) end def self.schema_ns_definition(klass) class_schema_variable(:schema_ns, klass) end def self.schema_element_definition(klass) schema_element = class_schema_variable(:schema_element, klass) or return nil schema_ns = schema_ns_definition(klass) elements = [] as_array = [] schema_element.each do |varname, definition| class_name, name = definition if /\[\]$/ =~ class_name class_name = class_name.sub(/\[\]$/, '') as_array << (name ? name.name : varname) end elements << [name || XSD::QName.new(schema_ns, varname), class_name] end [elements, as_array] end def self.schema_attribute_definition(klass) class_schema_variable(:schema_attribute, klass) end class << Mapping private def class_schema_variable(sym, klass) var = "@@#{sym}" klass.class_variables.include?(var) ? klass.class_eval(var) : nil end def protect_threadvars(*symbols) backup = {} begin symbols.each do |sym| backup[sym] = Thread.current[sym] end yield ensure symbols.each do |sym| Thread.current[sym] = backup[sym] end end end def add_md_ary(md_ary, ary, indices, registry) for idx in 0..(ary.size - 1) if ary[idx].is_a?(Array) add_md_ary(md_ary, ary[idx], indices + [idx], registry) else md_ary[*(indices + [idx])] = _obj2soap(ary[idx], registry) end end end end end end PK|]P|-|-#soap/mapping/wsdlliteralregistry.rbnu[# SOAP4R - WSDL literal mapping registry. # Copyright (C) 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/baseData' require 'soap/mapping/mapping' require 'soap/mapping/typeMap' require 'xsd/codegen/gensupport' require 'xsd/namedelements' module SOAP module Mapping class WSDLLiteralRegistry < Registry attr_reader :definedelements attr_reader :definedtypes attr_accessor :excn_handler_obj2soap attr_accessor :excn_handler_soap2obj def initialize(definedtypes = XSD::NamedElements::Empty, definedelements = XSD::NamedElements::Empty) @definedtypes = definedtypes @definedelements = definedelements @excn_handler_obj2soap = nil @excn_handler_soap2obj = nil @schema_element_cache = {} @schema_attribute_cache = {} end def obj2soap(obj, qname) soap_obj = nil if ele = @definedelements[qname] soap_obj = obj2elesoap(obj, ele) elsif type = @definedtypes[qname] soap_obj = obj2typesoap(obj, type, true) else soap_obj = any2soap(obj, qname) end return soap_obj if soap_obj if @excn_handler_obj2soap soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| Mapping.obj2soap(yield_obj, nil, nil, MAPPING_OPT) } return soap_obj if soap_obj end raise MappingError.new("cannot map #{obj.class.name} as #{qname}") end # node should be a SOAPElement def soap2obj(node, obj_class = nil) # obj_class is given when rpc/literal service. but ignored for now. begin return any2obj(node) rescue MappingError end if @excn_handler_soap2obj begin return @excn_handler_soap2obj.call(node) { |yield_node| Mapping.soap2obj(yield_node, nil, nil, MAPPING_OPT) } rescue Exception end end if node.respond_to?(:type) raise MappingError.new("cannot map #{node.type.name} to Ruby object") else raise MappingError.new("cannot map #{node.elename.name} to Ruby object") end end private MAPPING_OPT = { :no_reference => true } def obj2elesoap(obj, ele) o = nil qualified = (ele.elementform == 'qualified') if ele.type if type = @definedtypes[ele.type] o = obj2typesoap(obj, type, qualified) elsif type = TypeMap[ele.type] o = base2soap(obj, type) else raise MappingError.new("cannot find type #{ele.type}") end elsif ele.local_complextype o = obj2typesoap(obj, ele.local_complextype, qualified) add_attributes2soap(obj, o) elsif ele.local_simpletype o = obj2typesoap(obj, ele.local_simpletype, qualified) else raise MappingError.new('illegal schema?') end o.elename = ele.name o end def obj2typesoap(obj, type, qualified) if type.is_a?(::WSDL::XMLSchema::SimpleType) simpleobj2soap(obj, type) else complexobj2soap(obj, type, qualified) end end def simpleobj2soap(obj, type) type.check_lexical_format(obj) return SOAPNil.new if obj.nil? # ToDo: check nillable. o = base2soap(obj, TypeMap[type.base]) o end def complexobj2soap(obj, type, qualified) o = SOAPElement.new(type.name) o.qualified = qualified type.each_element do |child_ele| child = Mapping.get_attribute(obj, child_ele.name.name) if child.nil? if child_ele.nillable # ToDo: test # add empty element child_soap = obj2elesoap(nil, child_ele) o.add(child_soap) elsif Integer(child_ele.minoccurs) == 0 # nothing to do else raise MappingError.new("nil not allowed: #{child_ele.name.name}") end elsif child_ele.map_as_array? child.each do |item| child_soap = obj2elesoap(item, child_ele) o.add(child_soap) end else child_soap = obj2elesoap(child, child_ele) o.add(child_soap) end end o end def any2soap(obj, qname) if obj.is_a?(SOAPElement) obj elsif obj.class.class_variables.include?('@@schema_element') stubobj2soap(obj, qname) elsif obj.is_a?(SOAP::Mapping::Object) mappingobj2soap(obj, qname) elsif obj.is_a?(Hash) ele = SOAPElement.from_obj(obj) ele.elename = qname ele else # expected to be a basetype or an anyType. # SOAPStruct, etc. is used instead of SOAPElement. begin ele = Mapping.obj2soap(obj, nil, nil, MAPPING_OPT) ele.elename = qname ele rescue MappingError ele = SOAPElement.new(qname, obj.to_s) end if obj.respond_to?(:__xmlattr) obj.__xmlattr.each do |key, value| ele.extraattr[key] = value end end ele end end def stubobj2soap(obj, qname) ele = SOAPElement.new(qname) ele.qualified = (obj.class.class_variables.include?('@@schema_qualified') and obj.class.class_eval('@@schema_qualified')) add_elements2soap(obj, ele) add_attributes2soap(obj, ele) ele end def mappingobj2soap(obj, qname) ele = SOAPElement.new(qname) obj.__xmlele.each do |key, value| if value.is_a?(::Array) value.each do |item| ele.add(obj2soap(item, key)) end else ele.add(obj2soap(value, key)) end end obj.__xmlattr.each do |key, value| ele.extraattr[key] = value end ele end def add_elements2soap(obj, ele) elements, as_array = schema_element_definition(obj.class) if elements elements.each do |elename, type| if child = Mapping.get_attribute(obj, elename.name) if as_array.include?(elename.name) child.each do |item| ele.add(obj2soap(item, elename)) end else ele.add(obj2soap(child, elename)) end elsif obj.is_a?(::Array) and as_array.include?(elename.name) obj.each do |item| ele.add(obj2soap(item, elename)) end end end end end def add_attributes2soap(obj, ele) attributes = schema_attribute_definition(obj.class) if attributes attributes.each do |qname, param| attr = obj.__send__('xmlattr_' + XSD::CodeGen::GenSupport.safevarname(qname.name)) ele.extraattr[qname] = attr end end end def base2soap(obj, type) soap_obj = nil if type <= XSD::XSDString str = XSD::Charset.encoding_conv(obj.to_s, Thread.current[:SOAPExternalCES], XSD::Charset.encoding) soap_obj = type.new(str) else soap_obj = type.new(obj) end soap_obj end def anytype2obj(node) if node.is_a?(::SOAP::SOAPBasetype) return node.data end klass = ::SOAP::Mapping::Object obj = klass.new obj end def any2obj(node, obj_class = nil) unless obj_class typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name) obj_class = Mapping.class_from_name(typestr) end if obj_class and obj_class.class_variables.include?('@@schema_element') soapele2stubobj(node, obj_class) elsif node.is_a?(SOAPElement) or node.is_a?(SOAPStruct) # SOAPArray for literal? soapele2plainobj(node) else obj = Mapping.soap2obj(node, nil, obj_class, MAPPING_OPT) add_attributes2plainobj(node, obj) obj end end def soapele2stubobj(node, obj_class) obj = Mapping.create_empty_object(obj_class) add_elements2stubobj(node, obj) add_attributes2stubobj(node, obj) obj end def soapele2plainobj(node) obj = anytype2obj(node) add_elements2plainobj(node, obj) add_attributes2plainobj(node, obj) obj end def add_elements2stubobj(node, obj) elements, as_array = schema_element_definition(obj.class) vars = {} node.each do |name, value| item = elements.find { |k, v| k.name == name } if item elename, class_name = item if klass = Mapping.class_from_name(class_name) # klass must be a SOAPBasetype or a class if klass.ancestors.include?(::SOAP::SOAPBasetype) if value.respond_to?(:data) child = klass.new(value.data).data else child = klass.new(nil).data end else child = any2obj(value, klass) end elsif klass = Mapping.module_from_name(class_name) # simpletype if value.respond_to?(:data) child = value.data else raise MappingError.new( "cannot map to a module value: #{class_name}") end else raise MappingError.new("unknown class/module: #{class_name}") end else # untyped element is treated as anyType. child = any2obj(value) end if as_array.include?(elename.name) (vars[name] ||= []) << child else vars[name] = child end end Mapping.set_attributes(obj, vars) end def add_attributes2stubobj(node, obj) if attributes = schema_attribute_definition(obj.class) define_xmlattr(obj) attributes.each do |qname, class_name| attr = node.extraattr[qname] next if attr.nil? or attr.empty? klass = Mapping.class_from_name(class_name) if klass.ancestors.include?(::SOAP::SOAPBasetype) child = klass.new(attr).data else child = attr end obj.__xmlattr[qname] = child define_xmlattr_accessor(obj, qname) end end end def add_elements2plainobj(node, obj) node.each do |name, value| obj.__add_xmlele_value(value.elename, any2obj(value)) end end def add_attributes2plainobj(node, obj) return if node.extraattr.empty? define_xmlattr(obj) node.extraattr.each do |qname, value| obj.__xmlattr[qname] = value define_xmlattr_accessor(obj, qname) end end if RUBY_VERSION > "1.7.0" def define_xmlattr_accessor(obj, qname) name = XSD::CodeGen::GenSupport.safemethodname(qname.name) Mapping.define_attr_accessor(obj, 'xmlattr_' + name, proc { @__xmlattr[qname] }, proc { |value| @__xmlattr[qname] = value }) end else def define_xmlattr_accessor(obj, qname) name = XSD::CodeGen::GenSupport.safemethodname(qname.name) obj.instance_eval <<-EOS def #{name} @__xmlattr[#{qname.dump}] end def #{name}=(value) @__xmlattr[#{qname.dump}] = value end EOS end end if RUBY_VERSION > "1.7.0" def define_xmlattr(obj) obj.instance_variable_set('@__xmlattr', {}) unless obj.respond_to?(:__xmlattr) Mapping.define_attr_accessor(obj, :__xmlattr, proc { @__xmlattr }) end end else def define_xmlattr(obj) obj.instance_variable_set('@__xmlattr', {}) unless obj.respond_to?(:__xmlattr) obj.instance_eval <<-EOS def __xmlattr @__xmlattr end EOS end end end # it caches @@schema_element. this means that @@schema_element must not be # changed while a lifetime of a WSDLLiteralRegistry. def schema_element_definition(klass) @schema_element_cache[klass] ||= Mapping.schema_element_definition(klass) end def schema_attribute_definition(klass) @schema_attribute_cache[klass] ||= Mapping.schema_attribute_definition(klass) end end end end PK|]\##soap/mapping/factory.rbnu[# SOAP4R - Mapping factory. # Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP module Mapping class Factory include TraverseSupport def initialize # nothing to do end def obj2soap(soap_class, obj, info, map) raise NotImplementError.new # return soap_obj end def soap2obj(obj_class, node, info, map) raise NotImplementError.new # return convert_succeeded_or_not, obj end def setiv2obj(obj, node, map) return if node.nil? if obj.is_a?(Array) setiv2ary(obj, node, map) else setiv2struct(obj, node, map) end end def setiv2soap(node, obj, map) if obj.class.class_variables.include?('@@schema_element') obj.class.class_eval('@@schema_element').each do |name, info| type, qname = info if qname elename = qname.name else elename = Mapping.name2elename(name) end node.add(elename, Mapping._obj2soap(obj.instance_variable_get('@' + name), map)) end else # should we sort instance_variables? obj.instance_variables.each do |var| name = var.sub(/^@/, '') elename = Mapping.name2elename(name) node.add(elename, Mapping._obj2soap(obj.instance_variable_get(var), map)) end end end private def setiv2ary(obj, node, map) node.each do |name, value| Array.instance_method(:<<).bind(obj).call(Mapping._soap2obj(value, map)) end end def setiv2struct(obj, node, map) vars = {} node.each do |name, value| vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map) end Mapping.set_attributes(obj, vars) end end class StringFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end begin unless XSD::Charset.is_ces(obj, Thread.current[:SOAPExternalCES]) return nil end encoded = XSD::Charset.encoding_conv(obj, Thread.current[:SOAPExternalCES], XSD::Charset.encoding) soap_obj = soap_class.new(encoded) rescue XSD::ValueSpaceError return nil end mark_marshalled_obj(obj, soap_obj) soap_obj end def soap2obj(obj_class, node, info, map) obj = Mapping.create_empty_object(obj_class) decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, Thread.current[:SOAPExternalCES]) obj.replace(decoded) mark_unmarshalled_obj(node, obj) return true, obj end end class BasetypeFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end soap_obj = nil begin soap_obj = soap_class.new(obj) rescue XSD::ValueSpaceError return nil end if @allow_original_mapping # Basetype except String should not be multiref-ed in SOAP/1.1. mark_marshalled_obj(obj, soap_obj) end soap_obj end def soap2obj(obj_class, node, info, map) obj = node.data mark_unmarshalled_obj(node, obj) return true, obj end end class DateTimeFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and Time === obj and !obj.instance_variables.empty? return nil end soap_obj = nil begin soap_obj = soap_class.new(obj) rescue XSD::ValueSpaceError return nil end mark_marshalled_obj(obj, soap_obj) soap_obj end def soap2obj(obj_class, node, info, map) if node.respond_to?(:to_obj) obj = node.to_obj(obj_class) return false if obj.nil? mark_unmarshalled_obj(node, obj) return true, obj else return false end end end class Base64Factory_ < Factory def obj2soap(soap_class, obj, info, map) return nil unless obj.instance_variables.empty? soap_obj = soap_class.new(obj) mark_marshalled_obj(obj, soap_obj) if soap_obj soap_obj end def soap2obj(obj_class, node, info, map) obj = node.string mark_unmarshalled_obj(node, obj) return true, obj end end class URIFactory_ < Factory def obj2soap(soap_class, obj, info, map) soap_obj = soap_class.new(obj) mark_marshalled_obj(obj, soap_obj) if soap_obj soap_obj end def soap2obj(obj_class, node, info, map) obj = node.data mark_unmarshalled_obj(node, obj) return true, obj end end class ArrayFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end # [[1], [2]] is converted to Array of Array, not 2-D Array. # To create M-D Array, you must call Mapping.ary2md. def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end arytype = Mapping.obj2element(obj) if arytype.name arytype.namespace ||= RubyTypeNamespace else arytype = XSD::AnyTypeName end soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) mark_marshalled_obj(obj, soap_obj) obj.each do |item| soap_obj.add(Mapping._obj2soap(item, map)) end soap_obj end def soap2obj(obj_class, node, info, map) obj = Mapping.create_empty_object(obj_class) mark_unmarshalled_obj(node, obj) node.soap2array(obj) do |elem| elem ? Mapping._soap2obj(elem, map) : nil end return true, obj end end class TypedArrayFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end arytype = info[:type] || info[0] soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) mark_marshalled_obj(obj, soap_obj) obj.each do |var| soap_obj.add(Mapping._obj2soap(var, map)) end soap_obj end def soap2obj(obj_class, node, info, map) if node.rank > 1 return false end arytype = info[:type] || info[0] unless node.arytype == arytype return false end obj = Mapping.create_empty_object(obj_class) mark_unmarshalled_obj(node, obj) node.soap2array(obj) do |elem| elem ? Mapping._soap2obj(elem, map) : nil end return true, obj end end class TypedStructFactory_ < Factory def obj2soap(soap_class, obj, info, map) type = info[:type] || info[0] soap_obj = soap_class.new(type) mark_marshalled_obj(obj, soap_obj) if obj.class <= SOAP::Marshallable setiv2soap(soap_obj, obj, map) else setiv2soap(soap_obj, obj, map) end soap_obj end def soap2obj(obj_class, node, info, map) type = info[:type] || info[0] unless node.type == type return false end obj = Mapping.create_empty_object(obj_class) mark_unmarshalled_obj(node, obj) setiv2obj(obj, node, map) return true, obj end end MapQName = XSD::QName.new(ApacheSOAPTypeNamespace, 'Map') class HashFactory_ < Factory def initialize(allow_original_mapping = false) super() @allow_original_mapping = allow_original_mapping end def obj2soap(soap_class, obj, info, map) if !@allow_original_mapping and !obj.instance_variables.empty? return nil end if !obj.default.nil? or (obj.respond_to?(:default_proc) and obj.default_proc) return nil end soap_obj = SOAPStruct.new(MapQName) mark_marshalled_obj(obj, soap_obj) obj.each do |key, value| elem = SOAPStruct.new elem.add("key", Mapping._obj2soap(key, map)) elem.add("value", Mapping._obj2soap(value, map)) # ApacheAxis allows only 'item' here. soap_obj.add("item", elem) end soap_obj end def soap2obj(obj_class, node, info, map) unless node.type == MapQName return false end if node.class == SOAPStruct and node.key?('default') return false end obj = Mapping.create_empty_object(obj_class) mark_unmarshalled_obj(node, obj) if node.class == SOAPStruct node.each do |key, value| obj[Mapping._soap2obj(value['key'], map)] = Mapping._soap2obj(value['value'], map) end else node.each do |value| obj[Mapping._soap2obj(value['key'], map)] = Mapping._soap2obj(value['value'], map) end end return true, obj end end end end PK|]ue,,#soap/mapping/wsdlencodedregistry.rbnu[# SOAP4R - WSDL encoded mapping registry. # Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/namedelements' require 'soap/baseData' require 'soap/mapping/mapping' require 'soap/mapping/typeMap' module SOAP module Mapping class WSDLEncodedRegistry < Registry include TraverseSupport attr_reader :definedelements attr_reader :definedtypes attr_accessor :excn_handler_obj2soap attr_accessor :excn_handler_soap2obj def initialize(definedtypes = XSD::NamedElements::Empty) @definedtypes = definedtypes # @definedelements = definedelements needed? @excn_handler_obj2soap = nil @excn_handler_soap2obj = nil # For mapping AnyType element. @rubytype_factory = RubytypeFactory.new( :allow_untyped_struct => true, :allow_original_mapping => true ) @schema_element_cache = {} end def obj2soap(obj, qname = nil) soap_obj = nil if type = @definedtypes[qname] soap_obj = obj2typesoap(obj, type) else soap_obj = any2soap(obj, qname) end return soap_obj if soap_obj if @excn_handler_obj2soap soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| Mapping._obj2soap(yield_obj, self) } return soap_obj if soap_obj end if qname raise MappingError.new("cannot map #{obj.class.name} as #{qname}") else raise MappingError.new("cannot map #{obj.class.name} to SOAP/OM") end end # map anything for now: must refer WSDL while mapping. [ToDo] def soap2obj(node, obj_class = nil) begin return any2obj(node, obj_class) rescue MappingError end if @excn_handler_soap2obj begin return @excn_handler_soap2obj.call(node) { |yield_node| Mapping._soap2obj(yield_node, self) } rescue Exception end end raise MappingError.new("cannot map #{node.type.name} to Ruby object") end private def any2soap(obj, qname) if obj.nil? SOAPNil.new elsif qname.nil? or qname == XSD::AnyTypeName @rubytype_factory.obj2soap(nil, obj, nil, self) elsif obj.is_a?(XSD::NSDBase) soap2soap(obj, qname) elsif (type = TypeMap[qname]) base2soap(obj, type) else nil end end def soap2soap(obj, type_qname) if obj.is_a?(SOAPBasetype) obj elsif obj.is_a?(SOAPStruct) && (type = @definedtypes[type_qname]) soap_obj = obj mark_marshalled_obj(obj, soap_obj) elements2soap(obj, soap_obj, type.content.elements) soap_obj elsif obj.is_a?(SOAPArray) && (type = @definedtypes[type_qname]) soap_obj = obj contenttype = type.child_type mark_marshalled_obj(obj, soap_obj) obj.replace do |ele| Mapping._obj2soap(ele, self, contenttype) end soap_obj else nil end end def obj2typesoap(obj, type) if type.is_a?(::WSDL::XMLSchema::SimpleType) simpleobj2soap(obj, type) else complexobj2soap(obj, type) end end def simpleobj2soap(obj, type) type.check_lexical_format(obj) return SOAPNil.new if obj.nil? # ToDo: check nillable. o = base2soap(obj, TypeMap[type.base]) o end def complexobj2soap(obj, type) case type.compoundtype when :TYPE_STRUCT struct2soap(obj, type.name, type) when :TYPE_ARRAY array2soap(obj, type.name, type) when :TYPE_MAP map2soap(obj, type.name, type) when :TYPE_SIMPLE simpleobj2soap(obj, type.simplecontent) when :TYPE_EMPTY raise MappingError.new("should be empty") unless obj.nil? SOAPNil.new else raise MappingError.new("unknown compound type: #{type.compoundtype}") end end def base2soap(obj, type) soap_obj = nil if type <= XSD::XSDString str = XSD::Charset.encoding_conv(obj.to_s, Thread.current[:SOAPExternalCES], XSD::Charset.encoding) soap_obj = type.new(str) mark_marshalled_obj(obj, soap_obj) else soap_obj = type.new(obj) end soap_obj end def struct2soap(obj, type_qname, type) return SOAPNil.new if obj.nil? # ToDo: check nillable. soap_obj = SOAPStruct.new(type_qname) unless obj.nil? mark_marshalled_obj(obj, soap_obj) elements2soap(obj, soap_obj, type.content.elements) end soap_obj end def array2soap(obj, type_qname, type) return SOAPNil.new if obj.nil? # ToDo: check nillable. arytype = type.child_type soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) unless obj.nil? mark_marshalled_obj(obj, soap_obj) obj.each do |item| soap_obj.add(Mapping._obj2soap(item, self, arytype)) end end soap_obj end MapKeyName = XSD::QName.new(nil, "key") MapValueName = XSD::QName.new(nil, "value") def map2soap(obj, type_qname, type) return SOAPNil.new if obj.nil? # ToDo: check nillable. keytype = type.child_type(MapKeyName) || XSD::AnyTypeName valuetype = type.child_type(MapValueName) || XSD::AnyTypeName soap_obj = SOAPStruct.new(MapQName) unless obj.nil? mark_marshalled_obj(obj, soap_obj) obj.each do |key, value| elem = SOAPStruct.new elem.add("key", Mapping._obj2soap(key, self, keytype)) elem.add("value", Mapping._obj2soap(value, self, valuetype)) # ApacheAxis allows only 'item' here. soap_obj.add("item", elem) end end soap_obj end def elements2soap(obj, soap_obj, elements) elements.each do |element| name = element.name.name child_obj = Mapping.get_attribute(obj, name) soap_obj.add(name, Mapping._obj2soap(child_obj, self, element.type || element.name)) end end def any2obj(node, obj_class) unless obj_class typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name) obj_class = Mapping.class_from_name(typestr) end if obj_class and obj_class.class_variables.include?('@@schema_element') soap2stubobj(node, obj_class) else Mapping._soap2obj(node, Mapping::DefaultRegistry, obj_class) end end def soap2stubobj(node, obj_class) obj = Mapping.create_empty_object(obj_class) unless node.is_a?(SOAPNil) add_elements2stubobj(node, obj) end obj end def add_elements2stubobj(node, obj) elements, as_array = schema_element_definition(obj.class) vars = {} node.each do |name, value| item = elements.find { |k, v| k.name == name } if item elename, class_name = item if klass = Mapping.class_from_name(class_name) # klass must be a SOAPBasetype or a class if klass.ancestors.include?(::SOAP::SOAPBasetype) if value.respond_to?(:data) child = klass.new(value.data).data else child = klass.new(nil).data end else child = Mapping._soap2obj(value, self, klass) end elsif klass = Mapping.module_from_name(class_name) # simpletype if value.respond_to?(:data) child = value.data else raise MappingError.new( "cannot map to a module value: #{class_name}") end else raise MappingError.new("unknown class: #{class_name}") end else # untyped element is treated as anyType. child = Mapping._soap2obj(value, self) end vars[name] = child end Mapping.set_attributes(obj, vars) end # it caches @@schema_element. this means that @@schema_element must not be # changed while a lifetime of a WSDLLiteralRegistry. def schema_element_definition(klass) @schema_element_cache[klass] ||= Mapping.schema_element_definition(klass) end end end end PK|].C-soap/mapping/typeMap.rbnu[# SOAP4R - Base type mapping definition # Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP TypeMap = { XSD::XSDAnySimpleType::Type => SOAPAnySimpleType, XSD::XSDString::Type => SOAPString, XSD::XSDBoolean::Type => SOAPBoolean, XSD::XSDDecimal::Type => SOAPDecimal, XSD::XSDFloat::Type => SOAPFloat, XSD::XSDDouble::Type => SOAPDouble, XSD::XSDDuration::Type => SOAPDuration, XSD::XSDDateTime::Type => SOAPDateTime, XSD::XSDTime::Type => SOAPTime, XSD::XSDDate::Type => SOAPDate, XSD::XSDGYearMonth::Type => SOAPGYearMonth, XSD::XSDGYear::Type => SOAPGYear, XSD::XSDGMonthDay::Type => SOAPGMonthDay, XSD::XSDGDay::Type => SOAPGDay, XSD::XSDGMonth::Type => SOAPGMonth, XSD::XSDHexBinary::Type => SOAPHexBinary, XSD::XSDBase64Binary::Type => SOAPBase64, XSD::XSDAnyURI::Type => SOAPAnyURI, XSD::XSDQName::Type => SOAPQName, XSD::XSDInteger::Type => SOAPInteger, XSD::XSDNonPositiveInteger::Type => SOAPNonPositiveInteger, XSD::XSDNegativeInteger::Type => SOAPNegativeInteger, XSD::XSDLong::Type => SOAPLong, XSD::XSDInt::Type => SOAPInt, XSD::XSDShort::Type => SOAPShort, XSD::XSDByte::Type => SOAPByte, XSD::XSDNonNegativeInteger::Type => SOAPNonNegativeInteger, XSD::XSDUnsignedLong::Type => SOAPUnsignedLong, XSD::XSDUnsignedInt::Type => SOAPUnsignedInt, XSD::XSDUnsignedShort::Type => SOAPUnsignedShort, XSD::XSDUnsignedByte::Type => SOAPUnsignedByte, XSD::XSDPositiveInteger::Type => SOAPPositiveInteger, SOAP::SOAPBase64::Type => SOAPBase64, } end PK|]ʻ$oB<B<soap/mapping/rubytypeFactory.rbnu[# SOAP4R - Ruby type mapping factory. # Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module SOAP module Mapping class RubytypeFactory < Factory TYPE_STRING = XSD::QName.new(RubyTypeNamespace, 'String') TYPE_TIME = XSD::QName.new(RubyTypeNamespace, 'Time') TYPE_ARRAY = XSD::QName.new(RubyTypeNamespace, 'Array') TYPE_REGEXP = XSD::QName.new(RubyTypeNamespace, 'Regexp') TYPE_RANGE = XSD::QName.new(RubyTypeNamespace, 'Range') TYPE_CLASS = XSD::QName.new(RubyTypeNamespace, 'Class') TYPE_MODULE = XSD::QName.new(RubyTypeNamespace, 'Module') TYPE_SYMBOL = XSD::QName.new(RubyTypeNamespace, 'Symbol') TYPE_STRUCT = XSD::QName.new(RubyTypeNamespace, 'Struct') TYPE_HASH = XSD::QName.new(RubyTypeNamespace, 'Map') def initialize(config = {}) @config = config @allow_untyped_struct = @config.key?(:allow_untyped_struct) ? @config[:allow_untyped_struct] : true @allow_original_mapping = @config.key?(:allow_original_mapping) ? @config[:allow_original_mapping] : false @string_factory = StringFactory_.new(true) @basetype_factory = BasetypeFactory_.new(true) @datetime_factory = DateTimeFactory_.new(true) @array_factory = ArrayFactory_.new(true) @hash_factory = HashFactory_.new(true) end def obj2soap(soap_class, obj, info, map) param = nil case obj when ::String unless @allow_original_mapping return nil end param = @string_factory.obj2soap(SOAPString, obj, info, map) if obj.class != String param.extraattr[RubyTypeName] = obj.class.name end addiv2soapattr(param, obj, map) when ::Time unless @allow_original_mapping return nil end param = @datetime_factory.obj2soap(SOAPDateTime, obj, info, map) if obj.class != Time param.extraattr[RubyTypeName] = obj.class.name end addiv2soapattr(param, obj, map) when ::Array unless @allow_original_mapping return nil end param = @array_factory.obj2soap(nil, obj, info, map) if obj.class != Array param.extraattr[RubyTypeName] = obj.class.name end addiv2soapattr(param, obj, map) when ::NilClass unless @allow_original_mapping return nil end param = @basetype_factory.obj2soap(SOAPNil, obj, info, map) addiv2soapattr(param, obj, map) when ::FalseClass, ::TrueClass unless @allow_original_mapping return nil end param = @basetype_factory.obj2soap(SOAPBoolean, obj, info, map) addiv2soapattr(param, obj, map) when ::Integer unless @allow_original_mapping return nil end param = @basetype_factory.obj2soap(SOAPInt, obj, info, map) param ||= @basetype_factory.obj2soap(SOAPInteger, obj, info, map) param ||= @basetype_factory.obj2soap(SOAPDecimal, obj, info, map) addiv2soapattr(param, obj, map) when ::Float unless @allow_original_mapping return nil end param = @basetype_factory.obj2soap(SOAPDouble, obj, info, map) if obj.class != Float param.extraattr[RubyTypeName] = obj.class.name end addiv2soapattr(param, obj, map) when ::Hash unless @allow_original_mapping return nil end if obj.respond_to?(:default_proc) && obj.default_proc raise TypeError.new("cannot dump hash with default proc") end param = SOAPStruct.new(TYPE_HASH) mark_marshalled_obj(obj, param) if obj.class != Hash param.extraattr[RubyTypeName] = obj.class.name end obj.each do |key, value| elem = SOAPStruct.new # Undefined type. elem.add("key", Mapping._obj2soap(key, map)) elem.add("value", Mapping._obj2soap(value, map)) param.add("item", elem) end param.add('default', Mapping._obj2soap(obj.default, map)) addiv2soapattr(param, obj, map) when ::Regexp unless @allow_original_mapping return nil end param = SOAPStruct.new(TYPE_REGEXP) mark_marshalled_obj(obj, param) if obj.class != Regexp param.extraattr[RubyTypeName] = obj.class.name end param.add('source', SOAPBase64.new(obj.source)) if obj.respond_to?('options') # Regexp#options is from Ruby/1.7 options = obj.options else options = 0 obj.inspect.sub(/^.*\//, '').each_byte do |c| options += case c when ?i 1 when ?x 2 when ?m 4 when ?n 16 when ?e 32 when ?s 48 when ?u 64 end end end param.add('options', SOAPInt.new(options)) addiv2soapattr(param, obj, map) when ::Range unless @allow_original_mapping return nil end param = SOAPStruct.new(TYPE_RANGE) mark_marshalled_obj(obj, param) if obj.class != Range param.extraattr[RubyTypeName] = obj.class.name end param.add('begin', Mapping._obj2soap(obj.begin, map)) param.add('end', Mapping._obj2soap(obj.end, map)) param.add('exclude_end', SOAP::SOAPBoolean.new(obj.exclude_end?)) addiv2soapattr(param, obj, map) when ::Class unless @allow_original_mapping return nil end if obj.to_s[0] == ?# raise TypeError.new("can't dump anonymous class #{obj}") end param = SOAPStruct.new(TYPE_CLASS) mark_marshalled_obj(obj, param) param.add('name', SOAPString.new(obj.name)) addiv2soapattr(param, obj, map) when ::Module unless @allow_original_mapping return nil end if obj.to_s[0] == ?# raise TypeError.new("can't dump anonymous module #{obj}") end param = SOAPStruct.new(TYPE_MODULE) mark_marshalled_obj(obj, param) param.add('name', SOAPString.new(obj.name)) addiv2soapattr(param, obj, map) when ::Symbol unless @allow_original_mapping return nil end param = SOAPStruct.new(TYPE_SYMBOL) mark_marshalled_obj(obj, param) param.add('id', SOAPString.new(obj.id2name)) addiv2soapattr(param, obj, map) when ::Struct unless @allow_original_mapping # treat it as an user defined class. [ruby-talk:104980] #param = unknownobj2soap(soap_class, obj, info, map) param = SOAPStruct.new(XSD::AnyTypeName) mark_marshalled_obj(obj, param) obj.members.each do |member| param.add(Mapping.name2elename(member), Mapping._obj2soap(obj[member], map)) end else param = SOAPStruct.new(TYPE_STRUCT) mark_marshalled_obj(obj, param) param.add('type', ele_type = SOAPString.new(obj.class.to_s)) ele_member = SOAPStruct.new obj.members.each do |member| ele_member.add(Mapping.name2elename(member), Mapping._obj2soap(obj[member], map)) end param.add('member', ele_member) addiv2soapattr(param, obj, map) end when ::IO, ::Binding, ::Continuation, ::Data, ::Dir, ::File::Stat, ::MatchData, Method, ::Proc, ::Thread, ::ThreadGroup # from 1.8: Process::Status, UnboundMethod return nil when ::SOAP::Mapping::Object param = SOAPStruct.new(XSD::AnyTypeName) mark_marshalled_obj(obj, param) obj.__xmlele.each do |key, value| param.add(key.name, Mapping._obj2soap(value, map)) end obj.__xmlattr.each do |key, value| param.extraattr[key] = value end when ::Exception typestr = Mapping.name2elename(obj.class.to_s) param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr)) mark_marshalled_obj(obj, param) param.add('message', Mapping._obj2soap(obj.message, map)) param.add('backtrace', Mapping._obj2soap(obj.backtrace, map)) addiv2soapattr(param, obj, map) else param = unknownobj2soap(soap_class, obj, info, map) end param end def soap2obj(obj_class, node, info, map) rubytype = node.extraattr[RubyTypeName] if rubytype or node.type.namespace == RubyTypeNamespace rubytype2obj(node, info, map, rubytype) elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName anytype2obj(node, info, map) else unknowntype2obj(node, info, map) end end private def addiv2soapattr(node, obj, map) return if obj.instance_variables.empty? ivars = SOAPStruct.new # Undefined type. setiv2soap(ivars, obj, map) node.extraattr[RubyIVarName] = ivars end def unknownobj2soap(soap_class, obj, info, map) if obj.class.name.empty? raise TypeError.new("can't dump anonymous class #{obj}") end singleton_class = class << obj; self; end if !singleton_methods_true(obj).empty? or !singleton_class.instance_variables.empty? raise TypeError.new("singleton can't be dumped #{obj}") end if !(singleton_class.ancestors - obj.class.ancestors).empty? typestr = Mapping.name2elename(obj.class.to_s) type = XSD::QName.new(RubyTypeNamespace, typestr) else type = Mapping.class2element(obj.class) end param = SOAPStruct.new(type) mark_marshalled_obj(obj, param) setiv2soap(param, obj, map) param end if RUBY_VERSION >= '1.8.0' def singleton_methods_true(obj) obj.singleton_methods(true) end else def singleton_methods_true(obj) obj.singleton_methods end end def rubytype2obj(node, info, map, rubytype) klass = rubytype ? Mapping.class_from_name(rubytype) : nil obj = nil case node when SOAPString return @string_factory.soap2obj(klass || String, node, info, map) when SOAPDateTime #return @datetime_factory.soap2obj(klass || Time, node, info, map) klass ||= Time t = node.to_time arg = [t.year, t.month, t.mday, t.hour, t.min, t.sec, t.usec] obj = t.gmt? ? klass.gm(*arg) : klass.local(*arg) mark_unmarshalled_obj(node, obj) return true, obj when SOAPArray return @array_factory.soap2obj(klass || Array, node, info, map) when SOAPNil, SOAPBoolean, SOAPInt, SOAPInteger, SOAPDecimal, SOAPDouble return @basetype_factory.soap2obj(nil, node, info, map) when SOAPStruct return rubytypestruct2obj(node, info, map, rubytype) else raise end end def rubytypestruct2obj(node, info, map, rubytype) klass = rubytype ? Mapping.class_from_name(rubytype) : nil obj = nil case node.type when TYPE_HASH klass = rubytype ? Mapping.class_from_name(rubytype) : Hash obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) node.each do |key, value| next unless key == 'item' obj[Mapping._soap2obj(value['key'], map)] = Mapping._soap2obj(value['value'], map) end if node.key?('default') obj.default = Mapping._soap2obj(node['default'], map) end when TYPE_REGEXP klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) source = node['source'].string options = node['options'].data || 0 Regexp.instance_method(:initialize).bind(obj).call(source, options) when TYPE_RANGE klass = rubytype ? Mapping.class_from_name(rubytype) : Range obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) first = Mapping._soap2obj(node['begin'], map) last = Mapping._soap2obj(node['end'], map) exclude_end = node['exclude_end'].data Range.instance_method(:initialize).bind(obj).call(first, last, exclude_end) when TYPE_CLASS obj = Mapping.class_from_name(node['name'].data) when TYPE_MODULE obj = Mapping.class_from_name(node['name'].data) when TYPE_SYMBOL obj = node['id'].data.intern when TYPE_STRUCT typestr = Mapping.elename2name(node['type'].data) klass = Mapping.class_from_name(typestr) if klass.nil? return false end unless klass <= ::Struct return false end obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) node['member'].each do |name, value| obj[Mapping.elename2name(name)] = Mapping._soap2obj(value, map) end else return unknowntype2obj(node, info, map) end return true, obj end def anytype2obj(node, info, map) case node when SOAPBasetype return true, node.data when SOAPStruct klass = ::SOAP::Mapping::Object obj = klass.new mark_unmarshalled_obj(node, obj) node.each do |name, value| obj.__add_xmlele_value(XSD::QName.new(nil, name), Mapping._soap2obj(value, map)) end unless node.extraattr.empty? obj.instance_variable_set('@__xmlattr', node.extraattr) end return true, obj else return false end end def unknowntype2obj(node, info, map) case node when SOAPBasetype return true, node.data when SOAPArray return @array_factory.soap2obj(Array, node, info, map) when SOAPStruct obj = unknownstruct2obj(node, info, map) return true, obj if obj if !@allow_untyped_struct return false end return anytype2obj(node, info, map) else # Basetype which is not defined... return false end end def unknownstruct2obj(node, info, map) unless node.type.name return nil end typestr = Mapping.elename2name(node.type.name) klass = Mapping.class_from_name(typestr) if klass.nil? and @allow_untyped_struct klass = Mapping.class_from_name(typestr, true) # lenient end if klass.nil? return nil end if klass <= ::Exception return exception2obj(klass, node, map) end klass_type = Mapping.class2qname(klass) return nil unless node.type.match(klass_type) obj = nil begin obj = Mapping.create_empty_object(klass) rescue # type name "data" tries Data.new which raises TypeError nil end mark_unmarshalled_obj(node, obj) setiv2obj(obj, node, map) obj end def exception2obj(klass, node, map) message = Mapping._soap2obj(node['message'], map) backtrace = Mapping._soap2obj(node['backtrace'], map) obj = Mapping.create_empty_object(klass) obj = obj.exception(message) mark_unmarshalled_obj(node, obj) obj.set_backtrace(backtrace) obj end # Only creates empty array. Do String#replace it with real string. def array2obj(node, map, rubytype) klass = rubytype ? Mapping.class_from_name(rubytype) : Array obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) obj end # Only creates empty string. Do String#replace it with real string. def string2obj(node, map, rubytype) klass = rubytype ? Mapping.class_from_name(rubytype) : String obj = Mapping.create_empty_object(klass) mark_unmarshalled_obj(node, obj) obj end end end end PK|]b,X??soap/encodingstyle/handler.rbnu[# SOAP4R - EncodingStyle handler library # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/soap' require 'soap/baseData' require 'soap/element' module SOAP module EncodingStyle class Handler @@handlers = {} class EncodingStyleError < Error; end class << self def uri self::Namespace end def handler(uri) @@handlers[uri] end def each @@handlers.each do |key, value| yield(value) end end private def add_handler @@handlers[self.uri] = self end end attr_reader :charset attr_accessor :generate_explicit_type def decode_typemap=(definedtypes) @decode_typemap = definedtypes end def initialize(charset) @charset = charset @generate_explicit_type = true @decode_typemap = nil end ### ## encode interface. # # Returns a XML instance as a string. def encode_data(generator, ns, data, parent) raise NotImplementError end def encode_data_end(generator, ns, data, parent) raise NotImplementError end def encode_prologue end def encode_epilogue end ### ## decode interface. # # Returns SOAP/OM data. def decode_tag(ns, name, attrs, parent) raise NotImplementError.new('Method decode_tag must be defined in derived class.') end def decode_tag_end(ns, name) raise NotImplementError.new('Method decode_tag_end must be defined in derived class.') end def decode_text(ns, text) raise NotImplementError.new('Method decode_text must be defined in derived class.') end def decode_prologue end def decode_epilogue end end end end PK|]ҍɜ&soap/encodingstyle/aspDotNetHandler.rbnu[# SOAP4R - ASP.NET EncodingStyle handler library # Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/encodingstyle/handler' module SOAP module EncodingStyle class ASPDotNetHandler < Handler Namespace = 'http://tempuri.org/ASP.NET' add_handler def initialize(charset = nil) super(charset) @textbuf = '' @decode_typemap = nil end ### ## encode interface. # def encode_data(generator, ns, data, parent) attrs = {} # ASPDotNetHandler is intended to be used for accessing an ASP.NET doc/lit # service as an rpc/encoded service. in the situation, local elements # should be qualified. propagate parent's namespace to children. if data.elename.namespace.nil? data.elename.namespace = parent.elename.namespace end name = generator.encode_name(ns, data, attrs) case data when SOAPRawString generator.encode_tag(name, attrs) generator.encode_rawstring(data.to_s) when XSD::XSDString generator.encode_tag(name, attrs) generator.encode_string(@charset ? XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s) when XSD::XSDAnySimpleType generator.encode_tag(name, attrs) generator.encode_string(data.to_s) when SOAPStruct generator.encode_tag(name, attrs) data.each do |key, value| generator.encode_child(ns, value, data) end when SOAPArray generator.encode_tag(name, attrs) data.traverse do |child, *rank| data.position = nil generator.encode_child(ns, child, data) end else raise EncodingStyleError.new( "unknown object:#{data} in this encodingStyle") end end def encode_data_end(generator, ns, data, parent) name = generator.encode_name_end(ns, data) cr = data.is_a?(SOAPCompoundtype) generator.encode_tag_end(name, cr) end ### ## decode interface. # class SOAPTemporalObject attr_accessor :parent def initialize @parent = nil end end class SOAPUnknown < SOAPTemporalObject def initialize(handler, elename) super() @handler = handler @elename = elename end def as_struct o = SOAPStruct.decode(@elename, XSD::AnyTypeName) o.parent = @parent o.type.name = @name @handler.decode_parent(@parent, o) o end def as_string o = SOAPString.decode(@elename) o.parent = @parent @handler.decode_parent(@parent, o) o end def as_nil o = SOAPNil.decode(@elename) o.parent = @parent @handler.decode_parent(@parent, o) o end end def decode_tag(ns, elename, attrs, parent) @textbuf = '' o = SOAPUnknown.new(self, elename) o.parent = parent o end def decode_tag_end(ns, node) o = node.node if o.is_a?(SOAPUnknown) newnode = o.as_string # if /\A\s*\z/ =~ @textbuf # o.as_struct # else # o.as_string # end node.replace_node(newnode) o = node.node end decode_textbuf(o) @textbuf = '' end def decode_text(ns, text) # @textbuf is set at decode_tag_end. @textbuf << text end def decode_prologue end def decode_epilogue end def decode_parent(parent, node) case parent.node when SOAPUnknown newparent = parent.node.as_struct node.parent = newparent parent.replace_node(newparent) decode_parent(parent, node) when SOAPStruct data = parent.node[node.elename.name] case data when nil parent.node.add(node.elename.name, node) when SOAPArray name, type_ns = node.elename.name, node.type.namespace data.add(node) node.elename, node.type.namespace = name, type_ns else parent.node[node.elename.name] = SOAPArray.new name, type_ns = data.elename.name, data.type.namespace parent.node[node.elename.name].add(data) data.elename.name, data.type.namespace = name, type_ns name, type_ns = node.elename.name, node.type.namespace parent.node[node.elename.name].add(node) node.elename.name, node.type.namespace = name, type_ns end when SOAPArray if node.position parent.node[*(decode_arypos(node.position))] = node parent.node.sparse = true else parent.node.add(node) end when SOAPBasetype raise EncodingStyleError.new("SOAP base type must not have a child") else # SOAPUnknown does not have parent. # raise EncodingStyleError.new("illegal parent: #{parent}") end end private def decode_textbuf(node) if node.is_a?(XSD::XSDString) if @charset node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset)) else node.set(@textbuf) end else # Nothing to do... end end end ASPDotNetHandler.new end end PK|]s33$soap/encodingstyle/literalHandler.rbnu[# SOAP4R - XML Literal EncodingStyle handler library # Copyright (C) 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/encodingstyle/handler' module SOAP module EncodingStyle class LiteralHandler < Handler Namespace = SOAP::LiteralNamespace add_handler def initialize(charset = nil) super(charset) @textbuf = '' end ### ## encode interface. # def encode_data(generator, ns, data, parent) attrs = {} name = generator.encode_name(ns, data, attrs) data.extraattr.each do |k, v| # ToDo: check generator.attributeformdefault here if k.is_a?(XSD::QName) if k.namespace SOAPGenerator.assign_ns(attrs, ns, k.namespace) k = ns.name(k) else k = k.name end end attrs[k] = v end case data when SOAPRawString generator.encode_tag(name, attrs) generator.encode_rawstring(data.to_s) when XSD::XSDString generator.encode_tag(name, attrs) str = data.to_s str = XSD::Charset.encoding_to_xml(str, @charset) if @charset generator.encode_string(str) when XSD::XSDAnySimpleType generator.encode_tag(name, attrs) generator.encode_string(data.to_s) when SOAPStruct generator.encode_tag(name, attrs) data.each do |key, value| generator.encode_child(ns, value, data) end when SOAPArray generator.encode_tag(name, attrs) data.traverse do |child, *rank| data.position = nil generator.encode_child(ns, child, data) end when SOAPElement # passes 2 times for simplifying namespace definition data.each do |key, value| if value.elename.namespace SOAPGenerator.assign_ns(attrs, ns, value.elename.namespace) end end generator.encode_tag(name, attrs) generator.encode_rawstring(data.text) if data.text data.each do |key, value| generator.encode_child(ns, value, data) end else raise EncodingStyleError.new( "unknown object:#{data} in this encodingStyle") end end def encode_data_end(generator, ns, data, parent) name = generator.encode_name_end(ns, data) cr = (data.is_a?(SOAPCompoundtype) or (data.is_a?(SOAPElement) and !data.text)) generator.encode_tag_end(name, cr) end ### ## decode interface. # class SOAPTemporalObject attr_accessor :parent def initialize @parent = nil end end class SOAPUnknown < SOAPTemporalObject def initialize(handler, elename, extraattr) super() @handler = handler @elename = elename @extraattr = extraattr end def as_element o = SOAPElement.decode(@elename) o.parent = @parent o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end def as_string o = SOAPString.decode(@elename) o.parent = @parent o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end def as_nil o = SOAPNil.decode(@elename) o.parent = @parent o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end end def decode_tag(ns, elename, attrs, parent) @textbuf = '' o = SOAPUnknown.new(self, elename, decode_attrs(ns, attrs)) o.parent = parent o end def decode_tag_end(ns, node) o = node.node if o.is_a?(SOAPUnknown) newnode = if /\A\s*\z/ =~ @textbuf o.as_element else o.as_string end node.replace_node(newnode) o = node.node end decode_textbuf(o) @textbuf = '' end def decode_text(ns, text) # @textbuf is set at decode_tag_end. @textbuf << text end def decode_attrs(ns, attrs) extraattr = {} attrs.each do |key, value| qname = ns.parse_local(key) extraattr[qname] = value end extraattr end def decode_prologue end def decode_epilogue end def decode_parent(parent, node) return unless parent.node case parent.node when SOAPUnknown newparent = parent.node.as_element node.parent = newparent parent.replace_node(newparent) decode_parent(parent, node) when SOAPElement parent.node.add(node) node.parent = parent.node when SOAPStruct parent.node.add(node.elename.name, node) node.parent = parent.node when SOAPArray if node.position parent.node[*(decode_arypos(node.position))] = node parent.node.sparse = true else parent.node.add(node) end node.parent = parent.node else raise EncodingStyleError.new("illegal parent: #{parent.node}") end end private def decode_textbuf(node) if node.is_a?(XSD::XSDString) if @charset node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset)) else node.set(@textbuf) end else # Nothing to do... end end end LiteralHandler.new end end PK|]dS9S9!soap/encodingstyle/soapHandler.rbnu[# SOAP4R - SOAP EncodingStyle handler library # Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/encodingstyle/handler' module SOAP module EncodingStyle class SOAPHandler < Handler Namespace = SOAP::EncodingNamespace add_handler def initialize(charset = nil) super(charset) @refpool = [] @idpool = [] @textbuf = '' @is_first_top_ele = true end ### ## encode interface. # def encode_data(generator, ns, data, parent) attrs = encode_attrs(generator, ns, data, parent) if parent && parent.is_a?(SOAPArray) && parent.position attrs[ns.name(AttrPositionName)] = "[#{parent.position.join(',')}]" end name = generator.encode_name(ns, data, attrs) case data when SOAPReference attrs['href'] = data.refidstr generator.encode_tag(name, attrs) when SOAPExternalReference data.referred attrs['href'] = data.refidstr generator.encode_tag(name, attrs) when SOAPRawString generator.encode_tag(name, attrs) generator.encode_rawstring(data.to_s) when XSD::XSDString generator.encode_tag(name, attrs) generator.encode_string(@charset ? XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s) when XSD::XSDAnySimpleType generator.encode_tag(name, attrs) generator.encode_string(data.to_s) when SOAPStruct generator.encode_tag(name, attrs) data.each do |key, value| generator.encode_child(ns, value, data) end when SOAPArray generator.encode_tag(name, attrs) data.traverse do |child, *rank| data.position = data.sparse ? rank : nil generator.encode_child(ns, child, data) end else raise EncodingStyleError.new( "unknown object:#{data} in this encodingStyle") end end def encode_data_end(generator, ns, data, parent) name = generator.encode_name_end(ns, data) cr = data.is_a?(SOAPCompoundtype) generator.encode_tag_end(name, cr) end ### ## decode interface. # class SOAPTemporalObject attr_accessor :parent attr_accessor :position attr_accessor :id attr_accessor :root def initialize @parent = nil @position = nil @id = nil @root = nil end end class SOAPUnknown < SOAPTemporalObject attr_reader :type attr_accessor :definedtype attr_reader :extraattr def initialize(handler, elename, type, extraattr) super() @handler = handler @elename = elename @type = type @extraattr = extraattr @definedtype = nil end def as_struct o = SOAPStruct.decode(@elename, @type) o.id = @id o.root = @root o.parent = @parent o.position = @position o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end def as_string o = SOAPString.decode(@elename) o.id = @id o.root = @root o.parent = @parent o.position = @position o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end def as_nil o = SOAPNil.decode(@elename) o.id = @id o.root = @root o.parent = @parent o.position = @position o.extraattr.update(@extraattr) @handler.decode_parent(@parent, o) o end end def decode_tag(ns, elename, attrs, parent) @textbuf = '' is_nil, type, arytype, root, offset, position, href, id, extraattr = decode_attrs(ns, attrs) o = nil if is_nil o = SOAPNil.decode(elename) elsif href o = SOAPReference.decode(elename, href) @refpool << o elsif @decode_typemap o = decode_tag_by_wsdl(ns, elename, type, parent.node, arytype, extraattr) else o = decode_tag_by_type(ns, elename, type, parent.node, arytype, extraattr) end if o.is_a?(SOAPArray) if offset o.offset = decode_arypos(offset) o.sparse = true else o.sparse = false end end o.parent = parent o.id = id o.root = root o.position = position unless o.is_a?(SOAPTemporalObject) @idpool << o if o.id decode_parent(parent, o) end o end def decode_tag_end(ns, node) o = node.node if o.is_a?(SOAPUnknown) newnode = if /\A\s*\z/ =~ @textbuf o.as_struct else o.as_string end if newnode.id @idpool << newnode end node.replace_node(newnode) o = node.node end decode_textbuf(o) # unlink definedtype o.definedtype = nil end def decode_text(ns, text) @textbuf << text end def decode_prologue @refpool.clear @idpool.clear @is_first_top_ele = true end def decode_epilogue decode_resolve_id end def decode_parent(parent, node) return unless parent.node case parent.node when SOAPUnknown newparent = parent.node.as_struct node.parent = newparent if newparent.id @idpool << newparent end parent.replace_node(newparent) decode_parent(parent, node) when SOAPStruct parent.node.add(node.elename.name, node) node.parent = parent.node when SOAPArray if node.position parent.node[*(decode_arypos(node.position))] = node parent.node.sparse = true else parent.node.add(node) end node.parent = parent.node else raise EncodingStyleError.new("illegal parent: #{parent.node}") end end private def content_ranksize(typename) typename.scan(/\[[\d,]*\]$/)[0] end def content_typename(typename) typename.sub(/\[,*\]$/, '') end def create_arytype(ns, data) XSD::QName.new(data.arytype.namespace, content_typename(data.arytype.name) + "[#{data.size.join(',')}]") end def encode_attrs(generator, ns, data, parent) attrs = {} return attrs if data.is_a?(SOAPReference) if !parent || parent.encodingstyle != EncodingNamespace if @generate_explicit_type SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace) attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace end data.encodingstyle = EncodingNamespace end if data.is_a?(SOAPNil) attrs[ns.name(XSD::AttrNilName)] = XSD::NilValue elsif @generate_explicit_type if data.type.namespace SOAPGenerator.assign_ns(attrs, ns, data.type.namespace) end if data.is_a?(SOAPArray) if data.arytype.namespace SOAPGenerator.assign_ns(attrs, ns, data.arytype.namespace) end SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace) attrs[ns.name(AttrArrayTypeName)] = ns.name(create_arytype(ns, data)) if data.type.name attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type) end elsif parent && parent.is_a?(SOAPArray) && (parent.arytype == data.type) # No need to add. elsif !data.type.namespace # No need to add. else attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type) end end data.extraattr.each do |key, value| SOAPGenerator.assign_ns(attrs, ns, key.namespace) attrs[ns.name(key)] = encode_attr_value(generator, ns, key, value) end if data.id attrs['id'] = data.id end attrs end def encode_attr_value(generator, ns, qname, value) if value.is_a?(SOAPType) ref = SOAPReference.new(value) generator.add_reftarget(qname.name, value) ref.refidstr else value.to_s end end def decode_tag_by_wsdl(ns, elename, typestr, parent, arytypestr, extraattr) o = nil if parent.class == SOAPBody # root element: should branch by root attribute? if @is_first_top_ele # Unqualified name is allowed here. @is_first_top_ele = false type = @decode_typemap[elename] || @decode_typemap.find_name(elename.name) if type o = SOAPStruct.new(elename) o.definedtype = type return o end end # multi-ref element. if typestr typename = ns.parse(typestr) typedef = @decode_typemap[typename] if typedef return decode_definedtype(elename, typename, typedef, arytypestr) end end return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) end if parent.type == XSD::AnyTypeName return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) end # parent.definedtype == nil means the parent is SOAPUnknown. SOAPUnknown # is generated by decode_tag_by_type when its type is anyType. parenttype = parent.definedtype || @decode_typemap[parent.type] unless parenttype return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) end definedtype_name = parenttype.child_type(elename) if definedtype_name and (klass = TypeMap[definedtype_name]) return decode_basetype(klass, elename) elsif definedtype_name == XSD::AnyTypeName return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) end if definedtype_name typedef = @decode_typemap[definedtype_name] else typedef = parenttype.child_defined_complextype(elename) end decode_definedtype(elename, definedtype_name, typedef, arytypestr) end def decode_definedtype(elename, typename, typedef, arytypestr) unless typedef raise EncodingStyleError.new("unknown type '#{typename}'") end if typedef.is_a?(::WSDL::XMLSchema::SimpleType) decode_defined_simpletype(elename, typename, typedef, arytypestr) else decode_defined_complextype(elename, typename, typedef, arytypestr) end end def decode_basetype(klass, elename) klass.decode(elename) end def decode_defined_simpletype(elename, typename, typedef, arytypestr) o = decode_basetype(TypeMap[typedef.base], elename) o.definedtype = typedef o end def decode_defined_complextype(elename, typename, typedef, arytypestr) case typedef.compoundtype when :TYPE_STRUCT, :TYPE_MAP o = SOAPStruct.decode(elename, typename) o.definedtype = typedef return o when :TYPE_ARRAY expected_arytype = typedef.find_arytype if arytypestr actual_arytype = XSD::QName.new(expected_arytype.namespace, content_typename(expected_arytype.name) << content_ranksize(arytypestr)) o = SOAPArray.decode(elename, typename, actual_arytype) else o = SOAPArray.new(typename, 1, expected_arytype) o.elename = elename end o.definedtype = typedef return o when :TYPE_EMPTY o = SOAPNil.decode(elename) o.definedtype = typedef return o else raise RuntimeError.new( "Unknown kind of complexType: #{typedef.compoundtype}") end nil end def decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) if arytypestr type = typestr ? ns.parse(typestr) : ValueArrayName node = SOAPArray.decode(elename, type, ns.parse(arytypestr)) node.extraattr.update(extraattr) return node end type = nil if typestr type = ns.parse(typestr) elsif parent.is_a?(SOAPArray) type = parent.arytype else # Since it's in dynamic(without any type) encoding process, # assumes entity as its type itself. # => type Array in SOAP-ENC. # => type Country in foo. type = elename end if (klass = TypeMap[type]) node = decode_basetype(klass, elename) node.extraattr.update(extraattr) return node end # Unknown type... Struct or String SOAPUnknown.new(self, elename, type, extraattr) end def decode_textbuf(node) case node when XSD::XSDHexBinary, XSD::XSDBase64Binary node.set_encoded(@textbuf) when XSD::XSDString if @charset @textbuf = XSD::Charset.encoding_from_xml(@textbuf, @charset) end if node.definedtype node.definedtype.check_lexical_format(@textbuf) end node.set(@textbuf) when SOAPNil # Nothing to do. when SOAPBasetype node.set(@textbuf) else # Nothing to do... end @textbuf = '' end NilLiteralMap = { 'true' => true, '1' => true, 'false' => false, '0' => false } RootLiteralMap = { '1' => 1, '0' => 0 } def decode_attrs(ns, attrs) is_nil = false type = nil arytype = nil root = nil offset = nil position = nil href = nil id = nil extraattr = {} attrs.each do |key, value| qname = ns.parse(key) case qname.namespace when XSD::InstanceNamespace case qname.name when XSD::NilLiteral is_nil = NilLiteralMap[value] or raise EncodingStyleError.new("cannot accept attribute value: #{value} as the value of xsi:#{XSD::NilLiteral} (expected 'true', 'false', '1', or '0')") next when XSD::AttrType type = value next end when EncodingNamespace case qname.name when AttrArrayType arytype = value next when AttrRoot root = RootLiteralMap[value] or raise EncodingStyleError.new( "illegal root attribute value: #{value}") next when AttrOffset offset = value next when AttrPosition position = value next end end if key == 'href' href = value next elsif key == 'id' id = value next end qname = ns.parse_local(key) extraattr[qname] = decode_attr_value(ns, qname, value) end return is_nil, type, arytype, root, offset, position, href, id, extraattr end def decode_attr_value(ns, qname, value) if /\A#/ =~ value o = SOAPReference.decode(nil, value) @refpool << o o else value end end def decode_arypos(position) /^\[(.+)\]$/ =~ position $1.split(',').collect { |s| s.to_i } end def decode_resolve_id count = @refpool.length # To avoid infinite loop while !@refpool.empty? && count > 0 @refpool = @refpool.find_all { |ref| o = @idpool.find { |item| item.id == ref.refid } if o.is_a?(SOAPReference) true # link of link. elsif o ref.__setobj__(o) false elsif o = ref.rootnode.external_content[ref.refid] ref.__setobj__(o) false else raise EncodingStyleError.new("unresolved reference: #{ref.refid}") end } count -= 1 end end end SOAPHandler.new end end PK|]soap/element.rbnu[# SOAP4R - SOAP elements library # Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'soap/baseData' module SOAP ### ## SOAP elements # module SOAPEnvelopeElement; end class SOAPFault < SOAPStruct include SOAPEnvelopeElement include SOAPCompoundtype public def faultcode self['faultcode'] end def faultstring self['faultstring'] end def faultactor self['faultactor'] end def detail self['detail'] end def faultcode=(rhs) self['faultcode'] = rhs end def faultstring=(rhs) self['faultstring'] = rhs end def faultactor=(rhs) self['faultactor'] = rhs end def detail=(rhs) self['detail'] = rhs end def initialize(faultcode = nil, faultstring = nil, faultactor = nil, detail = nil) super(EleFaultName) @elename = EleFaultName @encodingstyle = EncodingNamespace if faultcode self.faultcode = faultcode self.faultstring = faultstring self.faultactor = faultactor self.detail = detail self.faultcode.elename = EleFaultCodeName if self.faultcode self.faultstring.elename = EleFaultStringName if self.faultstring self.faultactor.elename = EleFaultActorName if self.faultactor self.detail.elename = EleFaultDetailName if self.detail end faultcode.parent = self if faultcode faultstring.parent = self if faultstring faultactor.parent = self if faultactor detail.parent = self if detail end def encode(generator, ns, attrs = {}) SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace) SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace) attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace name = ns.name(@elename) generator.encode_tag(name, attrs) yield(self.faultcode) yield(self.faultstring) yield(self.faultactor) yield(self.detail) if self.detail generator.encode_tag_end(name, true) end end class SOAPBody < SOAPStruct include SOAPEnvelopeElement def initialize(data = nil, is_fault = false) super(nil) @elename = EleBodyName @encodingstyle = nil if data if data.respond_to?(:elename) add(data.elename.name, data) else data.to_a.each do |datum| add(datum.elename.name, datum) end end end @is_fault = is_fault end def encode(generator, ns, attrs = {}) name = ns.name(@elename) generator.encode_tag(name, attrs) if @is_fault yield(@data) else @data.each do |data| yield(data) end end generator.encode_tag_end(name, true) end def root_node @data.each do |node| if node.root == 1 return node end end # No specified root... @data.each do |node| if node.root != 0 return node end end raise Parser::FormatDecodeError.new('no root element') end end class SOAPHeaderItem < XSD::NSDBase include SOAPEnvelopeElement include SOAPCompoundtype public attr_accessor :element attr_accessor :mustunderstand attr_accessor :encodingstyle def initialize(element, mustunderstand = true, encodingstyle = nil) super() @type = nil @element = element @mustunderstand = mustunderstand @encodingstyle = encodingstyle element.parent = self if element end def encode(generator, ns, attrs = {}) attrs.each do |key, value| @element.extraattr[key] = value end @element.extraattr[ns.name(AttrMustUnderstandName)] = (@mustunderstand ? '1' : '0') if @encodingstyle @element.extraattr[ns.name(AttrEncodingStyleName)] = @encodingstyle end @element.encodingstyle = @encodingstyle if !@element.encodingstyle yield(@element) end end class SOAPHeader < SOAPStruct include SOAPEnvelopeElement def initialize super(nil) @elename = EleHeaderName @encodingstyle = nil end def encode(generator, ns, attrs = {}) name = ns.name(@elename) generator.encode_tag(name, attrs) @data.each do |data| yield(data) end generator.encode_tag_end(name, true) end def add(name, value) mu = (value.extraattr[AttrMustUnderstandName] == '1') encstyle = value.extraattr[AttrEncodingStyleName] item = SOAPHeaderItem.new(value, mu, encstyle) super(name, item) end def length @data.length end alias size length end class SOAPEnvelope < XSD::NSDBase include SOAPEnvelopeElement include SOAPCompoundtype attr_reader :header attr_reader :body attr_reader :external_content def initialize(header = nil, body = nil) super() @type = nil @elename = EleEnvelopeName @encodingstyle = nil @header = header @body = body @external_content = {} header.parent = self if header body.parent = self if body end def header=(header) header.parent = self @header = header end def body=(body) body.parent = self @body = body end def encode(generator, ns, attrs = {}) SOAPGenerator.assign_ns(attrs, ns, elename.namespace, SOAPNamespaceTag) name = ns.name(@elename) generator.encode_tag(name, attrs) yield(@header) if @header and @header.length > 0 yield(@body) generator.encode_tag_end(name, true) end def to_ary [header, body] end end end PK|]Ysoap/attachment.rbnu[# soap/attachment.rb: SOAP4R - SwA implementation. # Copyright (C) 2002, 2003 Jamie Herre and NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/baseData' require 'soap/mapping' module SOAP class SOAPAttachment < SOAPExternalReference attr_reader :data def initialize(value) super() @data = value end private def external_contentid @data.contentid end end class Attachment attr_reader :io attr_accessor :contenttype def initialize(string_or_readable = nil) @string_or_readable = string_or_readable @contenttype = "application/octet-stream" @contentid = nil end def contentid @contentid ||= Attachment.contentid(self) end def contentid=(contentid) @contentid = contentid end def mime_contentid '<' + contentid + '>' end def content if @content == nil and @string_or_readable != nil @content = @string_or_readable.respond_to?(:read) ? @string_or_readable.read : @string_or_readable end @content end def to_s content end def write(out) out.write(content) end def save(filename) File.open(filename, "wb") do |f| write(f) end end def self.contentid(obj) # this needs to be fixed [obj.__id__.to_s, Process.pid.to_s].join('.') end def self.mime_contentid(obj) '<' + contentid(obj) + '>' end end module Mapping class AttachmentFactory < SOAP::Mapping::Factory def obj2soap(soap_class, obj, info, map) soap_obj = soap_class.new(obj) mark_marshalled_obj(obj, soap_obj) soap_obj end def soap2obj(obj_class, node, info, map) obj = node.data mark_unmarshalled_obj(node, obj) return true, obj end end DefaultRegistry.add(::SOAP::Attachment, ::SOAP::SOAPAttachment, AttachmentFactory.new, nil) end end PK|]Ꞙ soap/httpconfigloader.rbnu[# SOAP4R - HTTP config loader. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/property' module SOAP module HTTPConfigLoader module_function def set_options(client, options) client.proxy = options["proxy"] options.add_hook("proxy") do |key, value| client.proxy = value end client.no_proxy = options["no_proxy"] options.add_hook("no_proxy") do |key, value| client.no_proxy = value end if client.respond_to?(:protocol_version=) client.protocol_version = options["protocol_version"] options.add_hook("protocol_version") do |key, value| client.protocol_version = value end end ssl_config = options["ssl_config"] ||= ::SOAP::Property.new set_ssl_config(client, ssl_config) ssl_config.add_hook(true) do |key, value| set_ssl_config(client, ssl_config) end basic_auth = options["basic_auth"] ||= ::SOAP::Property.new set_basic_auth(client, basic_auth) basic_auth.add_hook do |key, value| set_basic_auth(client, basic_auth) end options.add_hook("connect_timeout") do |key, value| client.connect_timeout = value end options.add_hook("send_timeout") do |key, value| client.send_timeout = value end options.add_hook("receive_timeout") do |key, value| client.receive_timeout = value end end def set_basic_auth(client, basic_auth) basic_auth.values.each do |url, userid, passwd| client.set_basic_auth(url, userid, passwd) end end def set_ssl_config(client, ssl_config) ssl_config.each do |key, value| cfg = client.ssl_config if cfg.nil? raise NotImplementedError.new("SSL not supported") end case key when 'client_cert' cfg.client_cert = cert_from_file(value) when 'client_key' cfg.client_key = key_from_file(value) when 'client_ca' cfg.client_ca = value when 'ca_path' cfg.set_trust_ca(value) when 'ca_file' cfg.set_trust_ca(value) when 'crl' cfg.set_crl(value) when 'verify_mode' cfg.verify_mode = ssl_config_int(value) when 'verify_depth' cfg.verify_depth = ssl_config_int(value) when 'options' cfg.options = value when 'ciphers' cfg.ciphers = value when 'verify_callback' cfg.verify_callback = value when 'cert_store' cfg.cert_store = value else raise ArgumentError.new("unknown ssl_config property #{key}") end end end def ssl_config_int(value) if value.nil? or value.to_s.empty? nil else begin Integer(value) rescue ArgumentError ::SOAP::Property::Util.const_from_name(value.to_s) end end end def cert_from_file(filename) OpenSSL::X509::Certificate.new(File.open(filename) { |f| f.read }) end def key_from_file(filename) OpenSSL::PKey::RSA.new(File.open(filename) { |f| f.read }) end end end PK|] bigdecimal/math.rbnu[# #-- # Contents: # sqrt(x, prec) # sin (x, prec) # cos (x, prec) # atan(x, prec) Note: |x|<1, x=0.9999 may not converge. # exp (x, prec) # log (x, prec) # PI (prec) # E (prec) == exp(1.0,prec) # # where: # x ... BigDecimal number to be computed. # |x| must be small enough to get convergence. # prec ... Number of digits to be obtained. #++ # # Provides mathematical functions. # # Example: # # require "bigdecimal" # require "bigdecimal/math" # # include BigMath # # a = BigDecimal((PI(100)/2).to_s) # puts sin(a,100) # -> 0.10000000000000000000......E1 # module BigMath # Computes the square root of x to the specified number of digits of # precision. # # BigDecimal.new('2').sqrt(16).to_s # -> "0.14142135623730950488016887242096975E1" # def sqrt(x,prec) x.sqrt(prec) end # Computes the sine of x to the specified number of digits of precision. # # If x is infinite or NaN, returns NaN. def sin(x, prec) raise ArgumentError, "Zero or negative precision for sin" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") two = BigDecimal("2") x1 = x x2 = x.mult(x,n) sign = 1 y = x d = y i = one z = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig sign = -sign x1 = x2.mult(x1,n) i += two z *= (i-one) * i d = sign * x1.div(z,m) y += d end y end # Computes the cosine of x to the specified number of digits of precision. # # If x is infinite or NaN, returns NaN. def cos(x, prec) raise ArgumentError, "Zero or negative precision for cos" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") two = BigDecimal("2") x1 = one x2 = x.mult(x,n) sign = 1 y = one d = y i = BigDecimal("0") z = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig sign = -sign x1 = x2.mult(x1,n) i += two z *= (i-one) * i d = sign * x1.div(z,m) y += d end y end # Computes the arctangent of x to the specified number of digits of precision. # # If x is infinite or NaN, returns NaN. # Raises an argument error if x > 1. def atan(x, prec) raise ArgumentError, "Zero or negative precision for atan" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? raise ArgumentError, "x.abs must be less than 1.0" if x.abs>=1 n = prec + BigDecimal.double_fig y = x d = y t = x r = BigDecimal("3") x2 = x.mult(x,n) while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = -t.mult(x2,n) d = t.div(r,m) y += d r += 2 end y end # Computes the value of e (the base of natural logarithms) raised to the # power of x, to the specified number of digits of precision. # # If x is infinite or NaN, returns NaN. # # BigMath::exp(BigDecimal.new('1'), 10).to_s # -> "0.271828182845904523536028752390026306410273E1" def exp(x, prec) raise ArgumentError, "Zero or negative precision for exp" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? n = prec + BigDecimal.double_fig one = BigDecimal("1") x1 = one y = one d = y z = one i = 0 while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig x1 = x1.mult(x,n) i += 1 z *= i d = x1.div(z,m) y += d end y end # Computes the natural logarithm of x to the specified number of digits # of precision. # # Returns x if x is infinite or NaN. # def log(x, prec) raise ArgumentError, "Zero or negative argument for log" if x <= 0 || prec <= 0 return x if x.infinite? || x.nan? one = BigDecimal("1") two = BigDecimal("2") n = prec + BigDecimal.double_fig x = (x - one).div(x + one,n) x2 = x.mult(x,n) y = x d = y i = one while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig x = x2.mult(x,n) i += two d = x.div(i,m) y += d end y*two end # Computes the value of pi to the specified number of digits of precision. def PI(prec) raise ArgumentError, "Zero or negative argument for PI" if prec <= 0 n = prec + BigDecimal.double_fig zero = BigDecimal("0") one = BigDecimal("1") two = BigDecimal("2") m25 = BigDecimal("-0.04") m57121 = BigDecimal("-57121") pi = zero d = one k = one w = one t = BigDecimal("-80") while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = t*m25 d = t.div(k,m) k = k+two pi = pi + d end d = one k = one w = one t = BigDecimal("956") while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig t = t.div(m57121,n) d = t.div(k,m) pi = pi + d k = k+two end pi end # Computes e (the base of natural logarithms) to the specified number of # digits of precision. def E(prec) raise ArgumentError, "Zero or negative precision for E" if prec <= 0 n = prec + BigDecimal.double_fig one = BigDecimal("1") y = one d = y z = one i = 0 while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) m = BigDecimal.double_fig if m < BigDecimal.double_fig i += 1 z *= i d = one.div(z,m) y += d end y end end PK|]ybigdecimal/jacobian.rbnu[# # require 'bigdecimal/jacobian' # # Provides methods to compute the Jacobian matrix of a set of equations at a # point x. In the methods below: # # f is an Object which is used to compute the Jacobian matrix of the equations. # It must provide the following methods: # # f.values(x):: returns the values of all functions at x # # f.zero:: returns 0.0 # f.one:: returns 1.0 # f.two:: returns 1.0 # f.ten:: returns 10.0 # # f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. # # x is the point at which to compute the Jacobian. # # fx is f.values(x). # module Jacobian #-- def isEqual(a,b,zero=0.0,e=1.0e-8) aa = a.abs bb = b.abs if aa == zero && bb == zero then true else if ((a-b)/(aa+bb)).abs < e then true else false end end end #++ # Computes the derivative of f[i] at x[i]. # fx is the value of f at x. def dfdxi(f,fx,x,i) nRetry = 0 n = x.size xSave = x[i] ok = 0 ratio = f.ten*f.ten*f.ten dx = x[i].abs/ratio dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps) dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps) until ok>0 do s = f.zero deriv = [] if(nRetry>100) then raize "Singular Jacobian matrix. No change at x[" + i.to_s + "]" end dx = dx*f.two x[i] += dx fxNew = f.values(x) for j in 0...n do if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then ok += 1 deriv <<= (fxNew[j]-fx[j])/dx else deriv <<= f.zero end end x[i] = xSave end deriv end # Computes the Jacobian of f at x. fx is the value of f at x. def jacobian(f,fx,x) n = x.size dfdx = Array::new(n*n) for i in 0...n do df = dfdxi(f,fx,x,i) for j in 0...n do dfdx[j*n+i] = df[j] end end dfdx end end PK|]:OObigdecimal/ludcmp.rbnu[# # Solves a*x = b for x, using LU decomposition. # module LUSolve # Performs LU decomposition of the n by n matrix a. def ludecomp(a,n,zero=0,one=1) prec = BigDecimal.limit(nil) ps = [] scales = [] for i in 0...n do # pick up largest(abs. val.) element in each row. ps <<= i nrmrow = zero ixn = i*n for j in 0...n do biggst = a[ixn+j].abs nrmrow = biggst if biggst>nrmrow end if nrmrow>zero then scales <<= one.div(nrmrow,prec) else raise "Singular matrix" end end n1 = n - 1 for k in 0...n1 do # Gaussian elimination with partial pivoting. biggst = zero; for i in k...n do size = a[ps[i]*n+k].abs*scales[ps[i]] if size>biggst then biggst = size pividx = i end end raise "Singular matrix" if biggst<=zero if pividx!=k then j = ps[k] ps[k] = ps[pividx] ps[pividx] = j end pivot = a[ps[k]*n+k] for i in (k+1)...n do psin = ps[i]*n a[psin+k] = mult = a[psin+k].div(pivot,prec) if mult!=zero then pskn = ps[k]*n for j in (k+1)...n do a[psin+j] -= mult.mult(a[pskn+j],prec) end end end end raise "Singular matrix" if a[ps[n1]*n+n1] == zero ps end # Solves a*x = b for x, using LU decomposition. # # a is a matrix, b is a constant vector, x is the solution vector. # # ps is the pivot, a vector which indicates the permutation of rows performed # during LU decomposition. def lusolve(a,b,ps,zero=0.0) prec = BigDecimal.limit(nil) n = ps.size x = [] for i in 0...n do dot = zero psin = ps[i]*n for j in 0...i do dot = a[psin+j].mult(x[j],prec) + dot end x <<= b[ps[i]] - dot end (n-1).downto(0) do |i| dot = zero psin = ps[i]*n for j in (i+1)...n do dot = a[psin+j].mult(x[j],prec) + dot end x[i] = (x[i]-dot).div(a[psin+i],prec) end x end end PK|]Јbigdecimal/newton.rbnu[# # newton.rb # # Solves the nonlinear algebraic equation system f = 0 by Newton's method. # This program is not dependent on BigDecimal. # # To call: # n = nlsolve(f,x) # where n is the number of iterations required, # x is the initial value vector # f is an Object which is used to compute the values of the equations to be solved. # It must provide the following methods: # # f.values(x):: returns the values of all functions at x # # f.zero:: returns 0.0 # f.one:: returns 1.0 # f.two:: returns 1.0 # f.ten:: returns 10.0 # # f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. # # On exit, x is the solution vector. # require "bigdecimal/ludcmp" require "bigdecimal/jacobian" module Newton include LUSolve include Jacobian def norm(fv,zero=0.0) s = zero n = fv.size for i in 0...n do s += fv[i]*fv[i] end s end def nlsolve(f,x) nRetry = 0 n = x.size f0 = f.values(x) zero = f.zero one = f.one two = f.two p5 = one/two d = norm(f0,zero) minfact = f.ten*f.ten*f.ten minfact = one/minfact e = f.eps while d >= e do nRetry += 1 # Not yet converged. => Compute Jacobian matrix dfdx = jacobian(f,f0,x) # Solve dfdx*dx = -f0 to estimate dx dx = lusolve(dfdx,f0,ludecomp(dfdx,n,zero,one),zero) fact = two xs = x.dup begin fact *= p5 if fact < minfact then raise "Failed to reduce function values." end for i in 0...n do x[i] = xs[i] - dx[i]*fact end f0 = f.values(x) dn = norm(f0,zero) end while(dn>=d) d = dn end nRetry end end PK|]!bigdecimal/util.rbnu[# # BigDecimal utility library. # # To use these functions, require 'bigdecimal/util' # # The following methods are provided to convert other types to BigDecimals: # # String#to_d -> BigDecimal # Float#to_d -> BigDecimal # Rational#to_d -> BigDecimal # # The following method is provided to convert BigDecimals to other types: # # BigDecimal#to_r -> Rational # # ---------------------------------------------------------------------- # class Float < Numeric def to_d BigDecimal(self.to_s) end end class String def to_d BigDecimal(self) end end class BigDecimal < Numeric # Converts a BigDecimal to a String of the form "nnnnnn.mmm". # This method is deprecated; use BigDecimal#to_s("F") instead. def to_digits if self.nan? || self.infinite? || self.zero? self.to_s else i = self.to_i.to_s s,f,y,z = self.frac.split i + "." + ("0"*(-z)) + f end end # Converts a BigDecimal to a Rational. def to_r sign,digits,base,power = self.split numerator = sign*digits.to_i denomi_power = power - digits.size # base is always 10 if denomi_power < 0 Rational(numerator,base ** (-denomi_power)) else Rational(numerator * (base ** denomi_power),1) end end end class Rational < Numeric # Converts a Rational to a BigDecimal def to_d(nFig=0) num = self.numerator.to_s if nFig<=0 nFig = BigDecimal.double_fig*2+1 end BigDecimal.new(num).div(self.denominator,nFig) end end PK|]g~^ZZrunit/testresult.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/testresult' module RUNIT class TestResult < Test::Unit::TestResult attr_reader(:errors, :failures) def succeed? return passed? end def failure_size return failure_count end def run_asserts return assertion_count end def error_size return error_count end def run_tests return run_count end def add_failure(failure) def failure.at return location end def failure.err return message end super(failure) end def add_error(error) def error.at return location end def error.err return exception end super(error) end end end PK|]}3$runit/error.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/assertionfailederror.rb' module RUNIT AssertionFailedError = Test::Unit::AssertionFailedError end PK|]2'Lrunit/testsuite.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/testsuite' module RUNIT class TestSuite < Test::Unit::TestSuite def add_test(*args) add(*args) end def add(*args) self.<<(*args) end def count_test_cases return size end def run(result, &progress_block) progress_block = proc {} unless (block_given?) super(result, &progress_block) end end end PK|]0runit/testcase.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'runit/testresult' require 'runit/testsuite' require 'runit/assert' require 'runit/error' require 'test/unit/testcase' module RUNIT class TestCase < Test::Unit::TestCase include RUNIT::Assert def self.suite method_names = instance_methods(true) tests = method_names.delete_if { |method_name| method_name !~ /^test/ } suite = TestSuite.new(name) tests.each { |test| catch(:invalid_test) { suite << new(test, name) } } return suite end def initialize(test_name, suite_name=self.class.name) super(test_name) end def assert_equals(*args) assert_equal(*args) end def name super.sub(/^(.*?)\((.*)\)$/, '\2#\1') end def run(result, &progress_block) progress_block = proc {} unless (block_given?) super(result, &progress_block) end end end PK|]Ϋ arunit/topublic.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. module RUNIT module ToPublic end end PK|]?Wrunit/cui/testrunner.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/ui/console/testrunner' require 'runit/testresult' module RUNIT module CUI class TestRunner < Test::Unit::UI::Console::TestRunner @@quiet_mode = false def self.run(suite) self.new().run(suite) end def initialize super nil end def run(suite, quiet_mode=@@quiet_mode) @suite = suite def @suite.suite self end @output_level = (quiet_mode ? Test::Unit::UI::PROGRESS_ONLY : Test::Unit::UI::VERBOSE) start end def create_mediator(suite) mediator = Test::Unit::UI::TestRunnerMediator.new(suite) class << mediator attr_writer :result_delegate def create_result return @result_delegate.create_result end end mediator.result_delegate = self return mediator end def create_result return RUNIT::TestResult.new end def self.quiet_mode=(boolean) @@quiet_mode = boolean end end end end PK|]>@ //runit/assert.rbnu[# Author:: Nathaniel Talbott. # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. # License:: Ruby license. require 'test/unit/assertions' require 'runit/error' module RUNIT module Assert include Test::Unit::Assertions def setup_assert end def assert_no_exception(*args, &block) assert_nothing_raised(*args, &block) end # To deal with the fact that RubyUnit does not check that the # regular expression is, indeed, a regular expression, if it is # not, we do our own assertion using the same semantics as # RubyUnit def assert_match(actual_string, expected_re, message="") _wrap_assertion { full_message = build_message(message, "Expected to match ", actual_string, expected_re) assert_block(full_message) { expected_re =~ actual_string } Regexp.last_match } end def assert_not_nil(actual, message="") assert(!actual.nil?, message) end def assert_not_match(actual_string, expected_re, message="") assert_no_match(expected_re, actual_string, message) end def assert_matches(*args) assert_match(*args) end def assert_fail(message="") flunk(message) end def assert_equal_float(expected, actual, delta, message="") assert_in_delta(expected, actual, delta, message) end def assert_send(object, method, *args) super([object, method, *args]) end def assert_exception(exception, message="", &block) assert_raises(exception, message, &block) end def assert_respond_to(method, object, message="") if (called_internally?) super else super(object, method, message) end end def called_internally? /assertions\.rb/.match(caller[1]) end end end PK|]"drb/timeridconv.rbnu[require 'drb/drb' require 'monitor' module DRb class TimerIdConv < DRbIdConv class TimerHolder2 include MonitorMixin class InvalidIndexError < RuntimeError; end def initialize(timeout=600) super() @sentinel = Object.new @gc = {} @curr = {} @renew = {} @timeout = timeout @keeper = keeper end def add(obj) synchronize do key = obj.__id__ @curr[key] = obj return key end end def fetch(key, dv=@sentinel) synchronize do obj = peek(key) if obj == @sentinel return dv unless dv == @sentinel raise InvalidIndexError end @renew[key] = obj # KeepIt return obj end end def include?(key) synchronize do obj = peek(key) return false if obj == @sentinel true end end def peek(key) synchronize do return @curr.fetch(key, @renew.fetch(key, @gc.fetch(key, @sentinel))) end end private def alternate synchronize do @gc = @curr # GCed @curr = @renew @renew = {} end end def keeper Thread.new do loop do size = alternate sleep(@timeout) end end end end def initialize(timeout=600) @holder = TimerHolder2.new(timeout) end def to_obj(ref) return super if ref.nil? @holder.fetch(ref) rescue TimerHolder2::InvalidIndexError raise "invalid reference" end def to_id(obj) return @holder.add(obj) end end end # DRb.install_id_conv(TimerIdConv.new) PK|]>2ggdrb/extservm.rbnu[=begin external service manager Copyright (c) 2000 Masatoshi SEKI =end require 'drb/drb' require 'thread' require 'monitor' module DRb class ExtServManager include DRbUndumped include MonitorMixin @@command = {} def self.command @@command end def self.command=(cmd) @@command = cmd end def initialize super() @cond = new_cond @servers = {} @waiting = [] @queue = Queue.new @thread = invoke_thread @uri = nil end attr_accessor :uri def service(name) synchronize do while true server = @servers[name] return server if server && server.alive? invoke_service(name) @cond.wait end end end def regist(name, ro) synchronize do @servers[name] = ro @cond.signal end self end def unregist(name) synchronize do @servers.delete(name) end end private def invoke_thread Thread.new do while true name = @queue.pop invoke_service_command(name, @@command[name]) end end end def invoke_service(name) @queue.push(name) end def invoke_service_command(name, command) raise "invalid command. name: #{name}" unless command synchronize do return if @servers.include?(name) @servers[name] = false end uri = @uri || DRb.uri if RUBY_PLATFORM =~ /mswin32/ && /NT/ =~ ENV["OS"] system(%Q'cmd /c start "ruby" /b #{command} #{uri} #{name}') else system("#{command} #{uri} #{name} &") end end end end PK|]j drb/gw.rbnu[require 'drb/drb' require 'monitor' module DRb class GWIdConv < DRbIdConv def to_obj(ref) if Array === ref && ref[0] == :DRbObject return DRbObject.new_with(ref[1], ref[2]) end super(ref) end end class GW include MonitorMixin def initialize super() @hash = {} end def [](key) synchronize do @hash[key] end end def []=(key, v) synchronize do @hash[key] = v end end end class DRbObject def self._load(s) uri, ref = Marshal.load(s) if DRb.uri == uri return ref ? DRb.to_obj(ref) : DRb.front end self.new_with(DRb.uri, [:DRbObject, uri, ref]) end def _dump(lv) if DRb.uri == @uri if Array === @ref && @ref[0] == :DRbObject Marshal.dump([@ref[1], @ref[2]]) else Marshal.dump([@uri, @ref]) # ?? end else Marshal.dump([DRb.uri, [:DRbObject, @uri, @ref]]) end end end end =begin DRb.install_id_conv(DRb::GWIdConv.new) front = DRb::GW.new s1 = DRb::DRbServer.new('drbunix:/tmp/gw_b_a', front) s2 = DRb::DRbServer.new('drbunix:/tmp/gw_b_c', front) s1.thread.join s2.thread.join =end =begin # foo.rb require 'drb/drb' class Foo include DRbUndumped def initialize(name, peer=nil) @name = name @peer = peer end def ping(obj) puts "#{@name}: ping: #{obj.inspect}" @peer.ping(self) if @peer end end =end =begin # gw_a.rb require 'drb/unix' require 'foo' obj = Foo.new('a') DRb.start_service("drbunix:/tmp/gw_a", obj) robj = DRbObject.new_with_uri('drbunix:/tmp/gw_b_a') robj[:a] = obj DRb.thread.join =end =begin # gw_c.rb require 'drb/unix' require 'foo' foo = Foo.new('c', nil) DRb.start_service("drbunix:/tmp/gw_c", nil) robj = DRbObject.new_with_uri("drbunix:/tmp/gw_b_c") puts "c->b" a = robj[:a] sleep 2 a.ping(foo) DRb.thread.join =end PK|]$УS S drb/acl.rbnu[# acl-2.0 - simple Access Control List # # Copyright (c) 2000,2002,2003 Masatoshi SEKI # # acl.rb is copyrighted free software by Masatoshi SEKI. # You can redistribute it and/or modify it under the same terms as Ruby. require 'ipaddr' class ACL VERSION=["2.0.0"] class ACLEntry def initialize(str) if str == '*' or str == 'all' @pat = [:all] elsif str.include?('*') @pat = [:name, dot_pat(str)] else begin @pat = [:ip, IPAddr.new(str)] rescue ArgumentError @pat = [:name, dot_pat(str)] end end end private def dot_pat_str(str) list = str.split('.').collect { |s| (s == '*') ? '.+' : s } list.join("\\.") end private def dot_pat(str) exp = "^" + dot_pat_str(str) + "$" Regexp.new(exp) end public def match(addr) case @pat[0] when :all true when :ip begin ipaddr = IPAddr.new(addr[3]) ipaddr = ipaddr.ipv4_mapped if @pat[1].ipv6? && ipaddr.ipv4? rescue ArgumentError return false end (@pat[1].include?(ipaddr)) ? true : false when :name (@pat[1] =~ addr[2]) ? true : false else false end end end class ACLList def initialize @list = [] end public def match(addr) @list.each do |e| return true if e.match(addr) end false end public def add(str) @list.push(ACLEntry.new(str)) end end DENY_ALLOW = 0 ALLOW_DENY = 1 def initialize(list=nil, order = DENY_ALLOW) @order = order @deny = ACLList.new @allow = ACLList.new install_list(list) if list end public def allow_socket?(soc) allow_addr?(soc.peeraddr) end public def allow_addr?(addr) case @order when DENY_ALLOW return true if @allow.match(addr) return false if @deny.match(addr) return true when ALLOW_DENY return false if @deny.match(addr) return true if @allow.match(addr) return false else false end end public def install_list(list) i = 0 while i < list.size permission, domain = list.slice(i,2) case permission.downcase when 'allow' @allow.add(domain) when 'deny' @deny.add(domain) else raise "Invalid ACL entry #{list.to_s}" end i += 2 end end end if __FILE__ == $0 # example list = %w(deny all allow 192.168.1.1 allow ::ffff:192.168.1.2 allow 192.168.1.3 ) addr = ["AF_INET", 10, "lc630", "192.168.1.3"] acl = ACL.new p acl.allow_addr?(addr) acl = ACL.new(list, ACL::DENY_ALLOW) p acl.allow_addr?(addr) end PK|]5s drb/ssl.rbnu[require 'socket' require 'openssl' require 'drb/drb' require 'singleton' module DRb class DRbSSLSocket < DRbTCPSocket class SSLConfig DEFAULT = { :SSLCertificate => nil, :SSLPrivateKey => nil, :SSLClientCA => nil, :SSLCACertificatePath => nil, :SSLCACertificateFile => nil, :SSLVerifyMode => ::OpenSSL::SSL::VERIFY_NONE, :SSLVerifyDepth => nil, :SSLVerifyCallback => nil, # custom verification :SSLCertificateStore => nil, # Must specify if you use auto generated certificate. :SSLCertName => nil, # e.g. [["CN","fqdn.example.com"]] :SSLCertComment => "Generated by Ruby/OpenSSL" } def initialize(config) @config = config @cert = config[:SSLCertificate] @pkey = config[:SSLPrivateKey] @ssl_ctx = nil end def [](key); @config[key] || DEFAULT[key] end def connect(tcp) ssl = ::OpenSSL::SSL::SSLSocket.new(tcp, @ssl_ctx) ssl.sync = true ssl.connect ssl end def accept(tcp) ssl = OpenSSL::SSL::SSLSocket.new(tcp, @ssl_ctx) ssl.sync = true ssl.accept ssl end def setup_certificate if @cert && @pkey return end rsa = OpenSSL::PKey::RSA.new(512){|p, n| next unless self[:verbose] case p when 0; $stderr.putc "." # BN_generate_prime when 1; $stderr.putc "+" # BN_generate_prime when 2; $stderr.putc "*" # searching good prime, # n = #of try, # but also data from BN_generate_prime when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q, # but also data from BN_generate_prime else; $stderr.putc "*" # BN_generate_prime end } cert = OpenSSL::X509::Certificate.new cert.version = 3 cert.serial = 0 name = OpenSSL::X509::Name.new(self[:SSLCertName]) cert.subject = name cert.issuer = name cert.not_before = Time.now cert.not_after = Time.now + (365*24*60*60) cert.public_key = rsa.public_key ef = OpenSSL::X509::ExtensionFactory.new(nil,cert) cert.extensions = [ ef.create_extension("basicConstraints","CA:FALSE"), ef.create_extension("subjectKeyIdentifier", "hash") ] ef.issuer_certificate = cert cert.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")) if comment = self[:SSLCertComment] cert.add_extension(ef.create_extension("nsComment", comment)) end cert.sign(rsa, OpenSSL::Digest::SHA1.new) @cert = cert @pkey = rsa end def setup_ssl_context ctx = ::OpenSSL::SSL::SSLContext.new ctx.cert = @cert ctx.key = @pkey ctx.client_ca = self[:SSLClientCA] ctx.ca_path = self[:SSLCACertificatePath] ctx.ca_file = self[:SSLCACertificateFile] ctx.verify_mode = self[:SSLVerifyMode] ctx.verify_depth = self[:SSLVerifyDepth] ctx.verify_callback = self[:SSLVerifyCallback] ctx.cert_store = self[:SSLCertificateStore] @ssl_ctx = ctx end end def self.parse_uri(uri) if uri =~ /^drbssl:\/\/(.*?):(\d+)(\?(.*))?$/ host = $1 port = $2.to_i option = $4 [host, port, option] else raise(DRbBadScheme, uri) unless uri =~ /^drbssl:/ raise(DRbBadURI, 'can\'t parse uri:' + uri) end end def self.open(uri, config) host, port, option = parse_uri(uri) host.untaint port.untaint soc = TCPSocket.open(host, port) ssl_conf = SSLConfig::new(config) ssl_conf.setup_ssl_context ssl = ssl_conf.connect(soc) self.new(uri, ssl, ssl_conf, true) end def self.open_server(uri, config) uri = 'drbssl://:0' unless uri host, port, opt = parse_uri(uri) if host.size == 0 host = getservername soc = open_server_inaddr_any(host, port) else soc = TCPServer.open(host, port) end port = soc.addr[1] if port == 0 @uri = "drbssl://#{host}:#{port}" ssl_conf = SSLConfig.new(config) ssl_conf.setup_certificate ssl_conf.setup_ssl_context self.new(@uri, soc, ssl_conf, false) end def self.uri_option(uri, config) host, port, option = parse_uri(uri) return "drbssl://#{host}:#{port}", option end def initialize(uri, soc, config, is_established) @ssl = is_established ? soc : nil super(uri, soc.to_io, config) end def stream; @ssl; end def close if @ssl @ssl.close @ssl = nil end super end def accept begin while true soc = @socket.accept break if (@acl ? @acl.allow_socket?(soc) : true) soc.close end ssl = @config.accept(soc) self.class.new(uri, ssl, @config, true) rescue OpenSSL::SSL::SSLError warn("#{__FILE__}:#{__LINE__}: warning: #{$!.message} (#{$!.class})") if @config[:verbose] retry end end end DRbProtocol.add_protocol(DRbSSLSocket) end PK|]M} drb/unix.rbnu[require 'socket' require 'drb/drb' require 'tmpdir' raise(LoadError, "UNIXServer is required") unless defined?(UNIXServer) module DRb class DRbUNIXSocket < DRbTCPSocket def self.parse_uri(uri) if /^drbunix:(.*?)(\?(.*))?$/ =~ uri filename = $1 option = $3 [filename, option] else raise(DRbBadScheme, uri) unless uri =~ /^drbunix:/ raise(DRbBadURI, 'can\'t parse uri:' + uri) end end def self.open(uri, config) filename, option = parse_uri(uri) filename.untaint soc = UNIXSocket.open(filename) self.new(uri, soc, config) end def self.open_server(uri, config) filename, option = parse_uri(uri) if filename.size == 0 soc = temp_server filename = soc.path uri = 'drbunix:' + soc.path else soc = UNIXServer.open(filename) end owner = config[:UNIXFileOwner] group = config[:UNIXFileGroup] if owner || group require 'etc' owner = Etc.getpwnam( owner ).uid if owner group = Etc.getgrnam( group ).gid if group File.chown owner, group, filename end mode = config[:UNIXFileMode] File.chmod(mode, filename) if mode self.new(uri, soc, config, true) end def self.uri_option(uri, config) filename, option = parse_uri(uri) return "drbunix:#{filename}", option end def initialize(uri, soc, config={}, server_mode = false) super(uri, soc, config) set_sockopt(@socket) @server_mode = server_mode @acl = nil end # import from tempfile.rb Max_try = 10 private def self.temp_server tmpdir = Dir::tmpdir n = 0 while true begin tmpname = sprintf('%s/druby%d.%d', tmpdir, $$, n) lock = tmpname + '.lock' unless File.exist?(tmpname) or File.exist?(lock) Dir.mkdir(lock) break end rescue raise "cannot generate tempfile `%s'" % tmpname if n >= Max_try #sleep(1) end n += 1 end soc = UNIXServer.new(tmpname) Dir.rmdir(lock) soc end public def close return unless @socket path = @socket.path if @server_mode @socket.close File.unlink(path) if @server_mode @socket = nil end def accept s = @socket.accept self.class.new(nil, s, @config) end def set_sockopt(soc) soc.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::FD_CLOEXEC end end DRbProtocol.add_protocol(DRbUNIXSocket) end PK|]pgVqqdrb/observer.rbnu[require 'observer' module DRb module DRbObservable include Observable def notify_observers(*arg) if defined? @observer_state and @observer_state if defined? @observer_peers for i in @observer_peers.dup begin i.update(*arg) rescue delete_observer(i) end end end @observer_state = false end end end end PK|]+6{99drb/extserv.rbnu[=begin external service Copyright (c) 2000,2002 Masatoshi SEKI =end require 'drb/drb' module DRb class ExtServ include DRbUndumped def initialize(there, name, server=nil) @server = server || DRb::primary_server @name = name ro = DRbObject.new(nil, there) @invoker = ro.regist(name, DRbObject.new(self, @server.uri)) end attr_reader :server def front DRbObject.new(nil, @server.uri) end def stop_service @invoker.unregist(@name) server = @server @server = nil server.stop_service true end def alive? @server ? @server.alive? : false end end end if __FILE__ == $0 class Foo include DRbUndumped def initialize(str) @str = str end def hello(it) "#{it}: #{self}" end def to_s @str end end cmd = ARGV.shift case cmd when 'itest1', 'itest2' front = Foo.new(cmd) manager = DRb::DRbServer.new(nil, front) es = DRb::ExtServ.new(ARGV.shift, ARGV.shift, manager) es.server.thread.join end end PK|]vg'Fdrb/invokemethod.rbnu[# for ruby-1.8.0 module DRb class DRbServer module InvokeMethod18Mixin def block_yield(x) if x.size == 1 && x[0].class == Array x[0] = DRbArray.new(x[0]) end block_value = @block.call(*x) end def perform_with_block @obj.__send__(@msg_id, *@argv) do |*x| jump_error = nil begin block_value = block_yield(x) rescue LocalJumpError jump_error = $! end if jump_error case jump_error.reason when :retry retry when :break break(jump_error.exit_value) else raise jump_error end end block_value end end end end end PK|]܉̕ drb/eq.rbnu[require 'drb/drb' module DRb class DRbObject def ==(other) return false unless DRbObject === other (@ref == other.__drbref) && (@uri == other.__drburi) end def hash [@uri, @ref].hash end alias eql? == end end PK|]WJ drb/drb.rbnu[# # = drb/drb.rb # # Distributed Ruby: _dRuby_ version 2.0.4 # # Copyright (c) 1999-2003 Masatoshi SEKI. You can redistribute it and/or # modify it under the same terms as Ruby. # # Author:: Masatoshi SEKI # # Documentation:: William Webber (william@williamwebber.com) # # == Overview # # dRuby is a distributed object system for Ruby. It allows an object in one # Ruby process to invoke methods on an object in another Ruby process on the # same or a different machine. # # The Ruby standard library contains the core classes of the dRuby package. # However, the full package also includes access control lists and the # Rinda tuple-space distributed task management system, as well as a # large number of samples. The full dRuby package can be downloaded from # the dRuby home page (see *References*). # # For an introduction and examples of usage see the documentation to the # DRb module. # # == References # # [http://www2a.biglobe.ne.jp/~seki/ruby/druby.html] # The dRuby home page, in Japanese. Contains the full dRuby package # and links to other Japanese-language sources. # # [http://www2a.biglobe.ne.jp/~seki/ruby/druby.en.html] # The English version of the dRuby home page. # # [http://www.chadfowler.com/ruby/drb.html] # A quick tutorial introduction to using dRuby by Chad Fowler. # # [http://www.linux-mag.com/2002-09/ruby_05.html] # A tutorial introduction to dRuby in Linux Magazine by Dave Thomas. # Includes a discussion of Rinda. # # [http://www.eng.cse.dmu.ac.uk/~hgs/ruby/dRuby/] # Links to English-language Ruby material collected by Hugh Sasse. # # [http://www.rubycentral.com/book/ospace.html] # The chapter from *Programming* *Ruby* by Dave Thomas and Andy Hunt # which discusses dRuby. # # [http://www.clio.ne.jp/home/web-i31s/Flotuard/Ruby/PRC2K_seki/dRuby.en.html] # Translation of presentation on Ruby by Masatoshi Seki. require 'socket' require 'thread' require 'fcntl' require 'drb/eq' # # == Overview # # dRuby is a distributed object system for Ruby. It is written in # pure Ruby and uses its own protocol. No add-in services are needed # beyond those provided by the Ruby runtime, such as TCP sockets. It # does not rely on or interoperate with other distributed object # systems such as CORBA, RMI, or .NET. # # dRuby allows methods to be called in one Ruby process upon a Ruby # object located in another Ruby process, even on another machine. # References to objects can be passed between processes. Method # arguments and return values are dumped and loaded in marshalled # format. All of this is done transparently to both the caller of the # remote method and the object that it is called upon. # # An object in a remote process is locally represented by a # DRb::DRbObject instance. This acts as a sort of proxy for the # remote object. Methods called upon this DRbObject instance are # forwarded to its remote object. This is arranged dynamically at run # time. There are no statically declared interfaces for remote # objects, such as CORBA's IDL. # # dRuby calls made into a process are handled by a DRb::DRbServer # instance within that process. This reconstitutes the method call, # invokes it upon the specified local object, and returns the value to # the remote caller. Any object can receive calls over dRuby. There # is no need to implement a special interface, or mixin special # functionality. Nor, in the general case, does an object need to # explicitly register itself with a DRbServer in order to receive # dRuby calls. # # One process wishing to make dRuby calls upon another process must # somehow obtain an initial reference to an object in the remote # process by some means other than as the return value of a remote # method call, as there is initially no remote object reference it can # invoke a method upon. This is done by attaching to the server by # URI. Each DRbServer binds itself to a URI such as # 'druby://example.com:8787'. A DRbServer can have an object attached # to it that acts as the server's *front* *object*. A DRbObject can # be explicitly created from the server's URI. This DRbObject's # remote object will be the server's front object. This front object # can then return references to other Ruby objects in the DRbServer's # process. # # Method calls made over dRuby behave largely the same as normal Ruby # method calls made within a process. Method calls with blocks are # supported, as are raising exceptions. In addition to a method's # standard errors, a dRuby call may also raise one of the # dRuby-specific errors, all of which are subclasses of DRb::DRbError. # # Any type of object can be passed as an argument to a dRuby call or # returned as its return value. By default, such objects are dumped # or marshalled at the local end, then loaded or unmarshalled at the # remote end. The remote end therefore receives a copy of the local # object, not a distributed reference to it; methods invoked upon this # copy are executed entirely in the remote process, not passed on to # the local original. This has semantics similar to pass-by-value. # # However, if an object cannot be marshalled, a dRuby reference to it # is passed or returned instead. This will turn up at the remote end # as a DRbObject instance. All methods invoked upon this remote proxy # are forwarded to the local object, as described in the discussion of # DRbObjects. This has semantics similar to the normal Ruby # pass-by-reference. # # The easiest way to signal that we want an otherwise marshallable # object to be passed or returned as a DRbObject reference, rather # than marshalled and sent as a copy, is to include the # DRb::DRbUndumped mixin module. # # dRuby supports calling remote methods with blocks. As blocks (or # rather the Proc objects that represent them) are not marshallable, # the block executes in the local, not the remote, context. Each # value yielded to the block is passed from the remote object to the # local block, then the value returned by each block invocation is # passed back to the remote execution context to be collected, before # the collected values are finally returned to the local context as # the return value of the method invocation. # # == Examples of usage # # For more dRuby samples, see the +samples+ directory in the full # dRuby distribution. # # === dRuby in client/server mode # # This illustrates setting up a simple client-server drb # system. Run the server and client code in different terminals, # starting the server code first. # # ==== Server code # # require 'drb/drb' # # # The URI for the server to connect to # URI="druby://localhost:8787" # # class TimeServer # # def get_current_time # return Time.now # end # # end # # # The object that handles requests on the server # FRONT_OBJECT=TimeServer.new # # $SAFE = 1 # disable eval() and friends # # DRb.start_service(URI, FRONT_OBJECT) # # Wait for the drb server thread to finish before exiting. # DRb.thread.join # # ==== Client code # # require 'drb/drb' # # # The URI to connect to # SERVER_URI="druby://localhost:8787" # # # Start a local DRbServer to handle callbacks. # # # # Not necessary for this small example, but will be required # # as soon as we pass a non-marshallable object as an argument # # to a dRuby call. # DRb.start_service # # timeserver = DRbObject.new_with_uri(SERVER_URI) # puts timeserver.get_current_time # # === Remote objects under dRuby # # This example illustrates returning a reference to an object # from a dRuby call. The Logger instances live in the server # process. References to them are returned to the client process, # where methods can be invoked upon them. These methods are # executed in the server process. # # ==== Server code # # require 'drb/drb' # # URI="druby://localhost:8787" # # class Logger # # # Make dRuby send Logger instances as dRuby references, # # not copies. # include DRb::DRbUndumped # # def initialize(n, fname) # @name = n # @filename = fname # end # # def log(message) # File.open(@filename, "a") do |f| # f.puts("#{Time.now}: #{@name}: #{message}") # end # end # # end # # # We have a central object for creating and retrieving loggers. # # This retains a local reference to all loggers created. This # # is so an existing logger can be looked up by name, but also # # to prevent loggers from being garbage collected. A dRuby # # reference to an object is not sufficient to prevent it being # # garbage collected! # class LoggerFactory # # def initialize(bdir) # @basedir = bdir # @loggers = {} # end # # def get_logger(name) # if !@loggers.has_key? name # # make the filename safe, then declare it to be so # fname = name.gsub(/[.\/]/, "_").untaint # @loggers[name] = Logger.new(name, @basedir + "/" + fname) # end # return @loggers[name] # end # # end # # FRONT_OBJECT=LoggerFactory.new("/tmp/dlog") # # $SAFE = 1 # disable eval() and friends # # DRb.start_service(URI, FRONT_OBJECT) # DRb.thread.join # # ==== Client code # # require 'drb/drb' # # SERVER_URI="druby://localhost:8787" # # DRb.start_service # # log_service=DRbObject.new_with_uri(SERVER_URI) # # ["loga", "logb", "logc"].each do |logname| # # logger=log_service.get_logger(logname) # # logger.log("Hello, world!") # logger.log("Goodbye, world!") # logger.log("=== EOT ===") # # end # # == Security # # As with all network services, security needs to be considered when # using dRuby. By allowing external access to a Ruby object, you are # not only allowing outside clients to call the methods you have # defined for that object, but by default to execute arbitrary Ruby # code on your server. Consider the following: # # # !!! UNSAFE CODE !!! # ro = DRbObject::new_with_uri("druby://your.server.com:8989") # class << ro # undef :instance_eval # force call to be passed to remote object # end # ro.instance_eval("`rm -rf *`") # # The dangers posed by instance_eval and friends are such that a # DRbServer should generally be run with $SAFE set to at least # level 1. This will disable eval() and related calls on strings # passed across the wire. The sample usage code given above follows # this practice. # # A DRbServer can be configured with an access control list to # selectively allow or deny access from specified IP addresses. The # main druby distribution provides the ACL class for this purpose. In # general, this mechanism should only be used alongside, rather than # as a replacement for, a good firewall. # # == dRuby internals # # dRuby is implemented using three main components: a remote method # call marshaller/unmarshaller; a transport protocol; and an # ID-to-object mapper. The latter two can be directly, and the first # indirectly, replaced, in order to provide different behaviour and # capabilities. # # Marshalling and unmarshalling of remote method calls is performed by # a DRb::DRbMessage instance. This uses the Marshal module to dump # the method call before sending it over the transport layer, then # reconstitute it at the other end. There is normally no need to # replace this component, and no direct way is provided to do so. # However, it is possible to implement an alternative marshalling # scheme as part of an implementation of the transport layer. # # The transport layer is responsible for opening client and server # network connections and forwarding dRuby request across them. # Normally, it uses DRb::DRbMessage internally to manage marshalling # and unmarshalling. The transport layer is managed by # DRb::DRbProtocol. Multiple protocols can be installed in # DRbProtocol at the one time; selection between them is determined by # the scheme of a dRuby URI. The default transport protocol is # selected by the scheme 'druby:', and implemented by # DRb::DRbTCPSocket. This uses plain TCP/IP sockets for # communication. An alternative protocol, using UNIX domain sockets, # is implemented by DRb::DRbUNIXSocket in the file drb/unix.rb, and # selected by the scheme 'drbunix:'. A sample implementation over # HTTP can be found in the samples accompanying the main dRuby # distribution. # # The ID-to-object mapping component maps dRuby object ids to the # objects they refer to, and vice versa. The implementation to use # can be specified as part of a DRb::DRbServer's configuration. The # default implementation is provided by DRb::DRbIdConv. It uses an # object's ObjectSpace id as its dRuby id. This means that the dRuby # reference to that object only remains meaningful for the lifetime of # the object's process and the lifetime of the object within that # process. A modified implementation is provided by DRb::TimerIdConv # in the file drb/timeridconv.rb. This implementation retains a local # reference to all objects exported over dRuby for a configurable # period of time (defaulting to ten minutes), to prevent them being # garbage-collected within this time. Another sample implementation # is provided in sample/name.rb in the main dRuby distribution. This # allows objects to specify their own id or "name". A dRuby reference # can be made persistent across processes by having each process # register an object using the same dRuby name. # module DRb # Superclass of all errors raised in the DRb module. class DRbError < RuntimeError; end # Error raised when an error occurs on the underlying communication # protocol. class DRbConnError < DRbError; end # Class responsible for converting between an object and its id. # # This, the default implementation, uses an object's local ObjectSpace # __id__ as its id. This means that an object's identification over # drb remains valid only while that object instance remains alive # within the server runtime. # # For alternative mechanisms, see DRb::TimerIdConv in rdb/timeridconv.rb # and DRbNameIdConv in sample/name.rb in the full drb distribution. class DRbIdConv # Convert an object reference id to an object. # # This implementation looks up the reference id in the local object # space and returns the object it refers to. def to_obj(ref) ObjectSpace._id2ref(ref) end # Convert an object into a reference id. # # This implementation returns the object's __id__ in the local # object space. def to_id(obj) obj.nil? ? nil : obj.__id__ end end # Mixin module making an object undumpable or unmarshallable. # # If an object which includes this module is returned by method # called over drb, then the object remains in the server space # and a reference to the object is returned, rather than the # object being marshalled and moved into the client space. module DRbUndumped def _dump(dummy) # :nodoc: raise TypeError, 'can\'t dump' end end # Error raised by the DRb module when an attempt is made to refer to # the context's current drb server but the context does not have one. # See #current_server. class DRbServerNotFound < DRbError; end # Error raised by the DRbProtocol module when it cannot find any # protocol implementation support the scheme specified in a URI. class DRbBadURI < DRbError; end # Error raised by a dRuby protocol when it doesn't support the # scheme specified in a URI. See DRb::DRbProtocol. class DRbBadScheme < DRbError; end # An exception wrapping a DRb::DRbUnknown object class DRbUnknownError < DRbError # Create a new DRbUnknownError for the DRb::DRbUnknown object +unknown+ def initialize(unknown) @unknown = unknown super(unknown.name) end # Get the wrapped DRb::DRbUnknown object. attr_reader :unknown def self._load(s) # :nodoc: Marshal::load(s) end def _dump(lv) # :nodoc: Marshal::dump(@unknown) end end # An exception wrapping an error object class DRbRemoteError < DRbError def initialize(error) @reason = error.class.to_s super("#{error.message} (#{error.class})") set_backtrace(error.backtrace) end # the class of the error, as a string. attr_reader :reason end # Class wrapping a marshalled object whose type is unknown locally. # # If an object is returned by a method invoked over drb, but the # class of the object is unknown in the client namespace, or # the object is a constant unknown in the client namespace, then # the still-marshalled object is returned wrapped in a DRbUnknown instance. # # If this object is passed as an argument to a method invoked over # drb, then the wrapped object is passed instead. # # The class or constant name of the object can be read from the # +name+ attribute. The marshalled object is held in the +buf+ # attribute. class DRbUnknown # Create a new DRbUnknown object. # # +buf+ is a string containing a marshalled object that could not # be unmarshalled. +err+ is the error message that was raised # when the unmarshalling failed. It is used to determine the # name of the unmarshalled object. def initialize(err, buf) case err.to_s when /uninitialized constant (\S+)/ @name = $1 when /undefined class\/module (\S+)/ @name = $1 else @name = nil end @buf = buf end # The name of the unknown thing. # # Class name for unknown objects; variable name for unknown # constants. attr_reader :name # Buffer contained the marshalled, unknown object. attr_reader :buf def self._load(s) # :nodoc: begin Marshal::load(s) rescue NameError, ArgumentError DRbUnknown.new($!, s) end end def _dump(lv) # :nodoc: @buf end # Attempt to load the wrapped marshalled object again. # # If the class of the object is now known locally, the object # will be unmarshalled and returned. Otherwise, a new # but identical DRbUnknown object will be returned. def reload self.class._load(@buf) end # Create a DRbUnknownError exception containing this object. def exception DRbUnknownError.new(self) end end class DRbArray def initialize(ary) @ary = ary.collect { |obj| if obj.kind_of? DRbUndumped DRbObject.new(obj) else begin Marshal.dump(obj) obj rescue DRbObject.new(obj) end end } end def self._load(s) Marshal::load(s) end def _dump(lv) Marshal.dump(@ary) end end # Handler for sending and receiving drb messages. # # This takes care of the low-level marshalling and unmarshalling # of drb requests and responses sent over the wire between server # and client. This relieves the implementor of a new drb # protocol layer with having to deal with these details. # # The user does not have to directly deal with this object in # normal use. class DRbMessage def initialize(config) # :nodoc: @load_limit = config[:load_limit] @argc_limit = config[:argc_limit] end def dump(obj, error=false) # :nodoc: obj = make_proxy(obj, error) if obj.kind_of? DRbUndumped begin str = Marshal::dump(obj) rescue str = Marshal::dump(make_proxy(obj, error)) end [str.size].pack('N') + str end def load(soc) # :nodoc: begin sz = soc.read(4) # sizeof (N) rescue raise(DRbConnError, $!.message, $!.backtrace) end raise(DRbConnError, 'connection closed') if sz.nil? raise(DRbConnError, 'premature header') if sz.size < 4 sz = sz.unpack('N')[0] raise(DRbConnError, "too large packet #{sz}") if @load_limit < sz begin str = soc.read(sz) rescue raise(DRbConnError, $!.message, $!.backtrace) end raise(DRbConnError, 'connection closed') if str.nil? raise(DRbConnError, 'premature marshal format(can\'t read)') if str.size < sz DRb.mutex.synchronize do begin save = Thread.current[:drb_untaint] Thread.current[:drb_untaint] = [] Marshal::load(str) rescue NameError, ArgumentError DRbUnknown.new($!, str) ensure Thread.current[:drb_untaint].each do |x| x.untaint end Thread.current[:drb_untaint] = save end end end def send_request(stream, ref, msg_id, arg, b) # :nodoc: ary = [] ary.push(dump(ref.__drbref)) ary.push(dump(msg_id.id2name)) ary.push(dump(arg.length)) arg.each do |e| ary.push(dump(e)) end ary.push(dump(b)) stream.write(ary.join('')) rescue raise(DRbConnError, $!.message, $!.backtrace) end def recv_request(stream) # :nodoc: ref = load(stream) ro = DRb.to_obj(ref) msg = load(stream) argc = load(stream) raise ArgumentError, 'too many arguments' if @argc_limit < argc argv = Array.new(argc, nil) argc.times do |n| argv[n] = load(stream) end block = load(stream) return ro, msg, argv, block end def send_reply(stream, succ, result) # :nodoc: stream.write(dump(succ) + dump(result, !succ)) rescue raise(DRbConnError, $!.message, $!.backtrace) end def recv_reply(stream) # :nodoc: succ = load(stream) result = load(stream) [succ, result] end private def make_proxy(obj, error=false) if error DRbRemoteError.new(obj) else DRbObject.new(obj) end end end # Module managing the underlying network protocol(s) used by drb. # # By default, drb uses the DRbTCPSocket protocol. Other protocols # can be defined. A protocol must define the following class methods: # # [open(uri, config)] Open a client connection to the server at +uri+, # using configuration +config+. Return a protocol # instance for this connection. # [open_server(uri, config)] Open a server listening at +uri+, # using configuration +config+. Return a # protocol instance for this listener. # [uri_option(uri, config)] Take a URI, possibly containing an option # component (e.g. a trailing '?param=val'), # and return a [uri, option] tuple. # # All of these methods should raise a DRbBadScheme error if the URI # does not identify the protocol they support (e.g. "druby:" for # the standard Ruby protocol). This is how the DRbProtocol module, # given a URI, determines which protocol implementation serves that # protocol. # # The protocol instance returned by #open_server must have the # following methods: # # [accept] Accept a new connection to the server. Returns a protocol # instance capable of communicating with the client. # [close] Close the server connection. # [uri] Get the URI for this server. # # The protocol instance returned by #open must have the following methods: # # [send_request (ref, msg_id, arg, b)] # Send a request to +ref+ with the given message id and arguments. # This is most easily implemented by calling DRbMessage.send_request, # providing a stream that sits on top of the current protocol. # [recv_reply] # Receive a reply from the server and return it as a [success-boolean, # reply-value] pair. This is most easily implemented by calling # DRb.recv_reply, providing a stream that sits on top of the # current protocol. # [alive?] # Is this connection still alive? # [close] # Close this connection. # # The protocol instance returned by #open_server().accept() must have # the following methods: # # [recv_request] # Receive a request from the client and return a [object, message, # args, block] tuple. This is most easily implemented by calling # DRbMessage.recv_request, providing a stream that sits on top of # the current protocol. # [send_reply(succ, result)] # Send a reply to the client. This is most easily implemented # by calling DRbMessage.send_reply, providing a stream that sits # on top of the current protocol. # [close] # Close this connection. # # A new protocol is registered with the DRbProtocol module using # the add_protocol method. # # For examples of other protocols, see DRbUNIXSocket in drb/unix.rb, # and HTTP0 in sample/http0.rb and sample/http0serv.rb in the full # drb distribution. module DRbProtocol # Add a new protocol to the DRbProtocol module. def add_protocol(prot) @protocol.push(prot) end module_function :add_protocol # Open a client connection to +uri+ with the configuration +config+. # # The DRbProtocol module asks each registered protocol in turn to # try to open the URI. Each protocol signals that it does not handle that # URI by raising a DRbBadScheme error. If no protocol recognises the # URI, then a DRbBadURI error is raised. If a protocol accepts the # URI, but an error occurs in opening it, a DRbConnError is raised. def open(uri, config, first=true) @protocol.each do |prot| begin return prot.open(uri, config) rescue DRbBadScheme rescue DRbConnError raise($!) rescue raise(DRbConnError, "#{uri} - #{$!.inspect}") end end if first && (config[:auto_load] != false) auto_load(uri, config) return open(uri, config, false) end raise DRbBadURI, 'can\'t parse uri:' + uri end module_function :open # Open a server listening for connections at +uri+ with # configuration +config+. # # The DRbProtocol module asks each registered protocol in turn to # try to open a server at the URI. Each protocol signals that it does # not handle that URI by raising a DRbBadScheme error. If no protocol # recognises the URI, then a DRbBadURI error is raised. If a protocol # accepts the URI, but an error occurs in opening it, the underlying # error is passed on to the caller. def open_server(uri, config, first=true) @protocol.each do |prot| begin return prot.open_server(uri, config) rescue DRbBadScheme end end if first && (config[:auto_load] != false) auto_load(uri, config) return open_server(uri, config, false) end raise DRbBadURI, 'can\'t parse uri:' + uri end module_function :open_server # Parse +uri+ into a [uri, option] pair. # # The DRbProtocol module asks each registered protocol in turn to # try to parse the URI. Each protocol signals that it does not handle that # URI by raising a DRbBadScheme error. If no protocol recognises the # URI, then a DRbBadURI error is raised. def uri_option(uri, config, first=true) @protocol.each do |prot| begin uri, opt = prot.uri_option(uri, config) # opt = nil if opt == '' return uri, opt rescue DRbBadScheme end end if first && (config[:auto_load] != false) auto_load(uri, config) return uri_option(uri, config, false) end raise DRbBadURI, 'can\'t parse uri:' + uri end module_function :uri_option def auto_load(uri, config) # :nodoc: if uri =~ /^drb([a-z0-9]+):/ require("drb/#{$1}") rescue nil end end module_function :auto_load end # The default drb protocol. # # Communicates over a TCP socket. class DRbTCPSocket private def self.parse_uri(uri) if uri =~ /^druby:\/\/(.*?):(\d+)(\?(.*))?$/ host = $1 port = $2.to_i option = $4 [host, port, option] else raise(DRbBadScheme, uri) unless uri =~ /^druby:/ raise(DRbBadURI, 'can\'t parse uri:' + uri) end end public # Open a client connection to +uri+ using configuration +config+. def self.open(uri, config) host, port, option = parse_uri(uri) host.untaint port.untaint soc = TCPSocket.open(host, port) self.new(uri, soc, config) end def self.getservername host = Socket::gethostname begin Socket::gethostbyname(host)[0] rescue 'localhost' end end def self.open_server_inaddr_any(host, port) infos = Socket::getaddrinfo(host, nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE) families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten] return TCPServer.open('0.0.0.0', port) if families.has_key?('AF_INET') return TCPServer.open('::', port) if families.has_key?('AF_INET6') return TCPServer.open(port) end # Open a server listening for connections at +uri+ using # configuration +config+. def self.open_server(uri, config) uri = 'druby://:0' unless uri host, port, opt = parse_uri(uri) config = {:tcp_original_host => host}.update(config) if host.size == 0 host = getservername soc = open_server_inaddr_any(host, port) else soc = TCPServer.open(host, port) end port = soc.addr[1] if port == 0 config[:tcp_port] = port uri = "druby://#{host}:#{port}" self.new(uri, soc, config) end # Parse +uri+ into a [uri, option] pair. def self.uri_option(uri, config) host, port, option = parse_uri(uri) return "druby://#{host}:#{port}", option end # Create a new DRbTCPSocket instance. # # +uri+ is the URI we are connected to. # +soc+ is the tcp socket we are bound to. +config+ is our # configuration. def initialize(uri, soc, config={}) @uri = uri @socket = soc @config = config @acl = config[:tcp_acl] @msg = DRbMessage.new(config) set_sockopt(@socket) end # Get the URI that we are connected to. attr_reader :uri # Get the address of our TCP peer (the other end of the socket # we are bound to. def peeraddr @socket.peeraddr end # Get the socket. def stream; @socket; end # On the client side, send a request to the server. def send_request(ref, msg_id, arg, b) @msg.send_request(stream, ref, msg_id, arg, b) end # On the server side, receive a request from the client. def recv_request @msg.recv_request(stream) end # On the server side, send a reply to the client. def send_reply(succ, result) @msg.send_reply(stream, succ, result) end # On the client side, receive a reply from the server. def recv_reply @msg.recv_reply(stream) end public # Close the connection. # # If this is an instance returned by #open_server, then this stops # listening for new connections altogether. If this is an instance # returned by #open or by #accept, then it closes this particular # client-server session. def close if @socket @socket.close @socket = nil end end # On the server side, for an instance returned by #open_server, # accept a client connection and return a new instance to handle # the server's side of this client-server session. def accept while true s = @socket.accept break if (@acl ? @acl.allow_socket?(s) : true) s.close end if @config[:tcp_original_host].to_s.size == 0 uri = "druby://#{s.addr[3]}:#{@config[:tcp_port]}" else uri = @uri end self.class.new(uri, s, @config) end # Check to see if this connection is alive. def alive? return false unless @socket if IO.select([@socket], nil, nil, 0) close return false end true end def set_sockopt(soc) # :nodoc: soc.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) soc.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::FD_CLOEXEC end end module DRbProtocol @protocol = [DRbTCPSocket] # default end class DRbURIOption # :nodoc: I don't understand the purpose of this class... def initialize(option) @option = option.to_s end attr :option def to_s; @option; end def ==(other) return false unless DRbURIOption === other @option == other.option end def hash @option.hash end alias eql? == end # Object wrapping a reference to a remote drb object. # # Method calls on this object are relayed to the remote # object that this object is a stub for. class DRbObject # Unmarshall a marshalled DRbObject. # # If the referenced object is located within the local server, then # the object itself is returned. Otherwise, a new DRbObject is # created to act as a stub for the remote referenced object. def self._load(s) uri, ref = Marshal.load(s) if DRb.here?(uri) obj = DRb.to_obj(ref) if ((! obj.tainted?) && Thread.current[:drb_untaint]) Thread.current[:drb_untaint].push(obj) end return obj end self.new_with(uri, ref) end def self.new_with(uri, ref) it = self.allocate it.instance_variable_set('@uri', uri) it.instance_variable_set('@ref', ref) it end # Create a new DRbObject from a URI alone. def self.new_with_uri(uri) self.new(nil, uri) end # Marshall this object. # # The URI and ref of the object are marshalled. def _dump(lv) Marshal.dump([@uri, @ref]) end # Create a new remote object stub. # # +obj+ is the (local) object we want to create a stub for. Normally # this is +nil+. +uri+ is the URI of the remote object that this # will be a stub for. def initialize(obj, uri=nil) @uri = nil @ref = nil if obj.nil? return if uri.nil? @uri, option = DRbProtocol.uri_option(uri, DRb.config) @ref = DRbURIOption.new(option) unless option.nil? else @uri = uri ? uri : (DRb.uri rescue nil) @ref = obj ? DRb.to_id(obj) : nil end end # Get the URI of the remote object. def __drburi @uri end # Get the reference of the object, if local. def __drbref @ref end undef :to_s undef :to_a if respond_to?(:to_a) def respond_to?(msg_id, priv=false) case msg_id when :_dump true when :marshal_dump false else method_missing(:respond_to?, msg_id, priv) end end # Routes method calls to the referenced object. def method_missing(msg_id, *a, &b) if DRb.here?(@uri) obj = DRb.to_obj(@ref) DRb.current_server.check_insecure_method(obj, msg_id) return obj.__send__(msg_id, *a, &b) end succ, result = self.class.with_friend(@uri) do DRbConn.open(@uri) do |conn| conn.send_message(self, msg_id, a, b) end end if succ return result elsif DRbUnknown === result raise result else bt = self.class.prepare_backtrace(@uri, result) result.set_backtrace(bt + caller) raise result end end def self.with_friend(uri) friend = DRb.fetch_server(uri) return yield() unless friend save = Thread.current['DRb'] Thread.current['DRb'] = { 'server' => friend } return yield ensure Thread.current['DRb'] = save if friend end def self.prepare_backtrace(uri, result) prefix = "(#{uri}) " bt = [] result.backtrace.each do |x| break if /`__send__'$/ =~ x if /^\(druby:\/\// =~ x bt.push(x) else bt.push(prefix + x) end end bt end def pretty_print(q) # :nodoc: q.pp_object(self) end def pretty_print_cycle(q) # :nodoc: q.object_address_group(self) { q.breakable q.text '...' } end end # Class handling the connection between a DRbObject and the # server the real object lives on. # # This class maintains a pool of connections, to reduce the # overhead of starting and closing down connections for each # method call. # # This class is used internally by DRbObject. The user does # not normally need to deal with it directly. class DRbConn POOL_SIZE = 16 # :nodoc: @mutex = Mutex.new @pool = [] def self.open(remote_uri) # :nodoc: begin conn = nil @mutex.synchronize do #FIXME new_pool = [] @pool.each do |c| if conn.nil? and c.uri == remote_uri conn = c if c.alive? else new_pool.push c end end @pool = new_pool end conn = self.new(remote_uri) unless conn succ, result = yield(conn) return succ, result ensure if conn if succ @mutex.synchronize do @pool.unshift(conn) @pool.pop.close while @pool.size > POOL_SIZE end else conn.close end end end end def initialize(remote_uri) # :nodoc: @uri = remote_uri @protocol = DRbProtocol.open(remote_uri, DRb.config) end attr_reader :uri # :nodoc: def send_message(ref, msg_id, arg, block) # :nodoc: @protocol.send_request(ref, msg_id, arg, block) @protocol.recv_reply end def close # :nodoc: @protocol.close @protocol = nil end def alive? # :nodoc: return false unless @protocol @protocol.alive? end end # Class representing a drb server instance. # # A DRbServer must be running in the local process before any incoming # dRuby calls can be accepted, or any local objects can be passed as # dRuby references to remote processes, even if those local objects are # never actually called remotely. You do not need to start a DRbServer # in the local process if you are only making outgoing dRuby calls # passing marshalled parameters. # # Unless multiple servers are being used, the local DRbServer is normally # started by calling DRb.start_service. class DRbServer @@acl = nil @@idconv = DRbIdConv.new @@secondary_server = nil @@argc_limit = 256 @@load_limit = 256 * 102400 @@verbose = false @@safe_level = 0 # Set the default value for the :argc_limit option. # # See #new(). The initial default value is 256. def self.default_argc_limit(argc) @@argc_limit = argc end # Set the default value for the :load_limit option. # # See #new(). The initial default value is 25 MB. def self.default_load_limit(sz) @@load_limit = sz end # Set the default value for the :acl option. # # See #new(). The initial default value is nil. def self.default_acl(acl) @@acl = acl end # Set the default value for the :id_conv option. # # See #new(). The initial default value is a DRbIdConv instance. def self.default_id_conv(idconv) @@idconv = idconv end def self.default_safe_level(level) @@safe_level = level end # Set the default value of the :verbose option. # # See #new(). The initial default value is false. def self.verbose=(on) @@verbose = on end # Get the default value of the :verbose option. def self.verbose @@verbose end def self.make_config(hash={}) # :nodoc: default_config = { :idconv => @@idconv, :verbose => @@verbose, :tcp_acl => @@acl, :load_limit => @@load_limit, :argc_limit => @@argc_limit, :safe_level => @@safe_level } default_config.update(hash) end # Create a new DRbServer instance. # # +uri+ is the URI to bind to. This is normally of the form # 'druby://:' where is a hostname of # the local machine. If nil, then the system's default hostname # will be bound to, on a port selected by the system; these value # can be retrieved from the +uri+ attribute. 'druby:' specifies # the default dRuby transport protocol: another protocol, such # as 'drbunix:', can be specified instead. # # +front+ is the front object for the server, that is, the object # to which remote method calls on the server will be passed. If # nil, then the server will not accept remote method calls. # # If +config_or_acl+ is a hash, it is the configuration to # use for this server. The following options are recognised: # # :idconv :: an id-to-object conversion object. This defaults # to an instance of the class DRb::DRbIdConv. # :verbose :: if true, all unsuccessful remote calls on objects # in the server will be logged to $stdout. false # by default. # :tcp_acl :: the access control list for this server. See # the ACL class from the main dRuby distribution. # :load_limit :: the maximum message size in bytes accepted by # the server. Defaults to 25 MB (26214400). # :argc_limit :: the maximum number of arguments to a remote # method accepted by the server. Defaults to # 256. # # The default values of these options can be modified on # a class-wide basis by the class methods #default_argc_limit, # #default_load_limit, #default_acl, #default_id_conv, # and #verbose= # # If +config_or_acl+ is not a hash, but is not nil, it is # assumed to be the access control list for this server. # See the :tcp_acl option for more details. # # If no other server is currently set as the primary server, # this will become the primary server. # # The server will immediately start running in its own thread. def initialize(uri=nil, front=nil, config_or_acl=nil) if Hash === config_or_acl config = config_or_acl.dup else acl = config_or_acl || @@acl config = { :tcp_acl => acl } end @config = self.class.make_config(config) @protocol = DRbProtocol.open_server(uri, @config) @uri = @protocol.uri @front = front @idconv = @config[:idconv] @safe_level = @config[:safe_level] @grp = ThreadGroup.new @thread = run DRb.regist_server(self) end # The URI of this DRbServer. attr_reader :uri # The main thread of this DRbServer. # # This is the thread that listens for and accepts connections # from clients, not that handles each client's request-response # session. attr_reader :thread # The front object of the DRbServer. # # This object receives remote method calls made on the server's # URI alone, with an object id. attr_reader :front # The configuration of this DRbServer attr_reader :config attr_reader :safe_level # Set whether to operate in verbose mode. # # In verbose mode, failed calls are logged to stdout. def verbose=(v); @config[:verbose]=v; end # Get whether the server is in verbose mode. # # In verbose mode, failed calls are logged to stdout. def verbose; @config[:verbose]; end # Is this server alive? def alive? @thread.alive? end # Stop this server. def stop_service DRb.remove_server(self) if Thread.current['DRb'] && Thread.current['DRb']['server'] == self Thread.current['DRb']['stop_service'] = true else @thread.kill end end # Convert a dRuby reference to the local object it refers to. def to_obj(ref) return front if ref.nil? return front[ref.to_s] if DRbURIOption === ref @idconv.to_obj(ref) end # Convert a local object to a dRuby reference. def to_id(obj) return nil if obj.__id__ == front.__id__ @idconv.to_id(obj) end private def kill_sub_thread Thread.new do grp = ThreadGroup.new grp.add(Thread.current) list = @grp.list while list.size > 0 list.each do |th| th.kill if th.alive? end list = @grp.list end end end def run Thread.start do begin while true main_loop end ensure @protocol.close if @protocol kill_sub_thread end end end # List of insecure methods. # # These methods are not callable via dRuby. INSECURE_METHOD = [ :__send__ ] # Has a method been included in the list of insecure methods? def insecure_method?(msg_id) INSECURE_METHOD.include?(msg_id) end # Coerce an object to a string, providing our own representation if # to_s is not defined for the object. def any_to_s(obj) obj.to_s + ":#{obj.class}" rescue sprintf("#<%s:0x%lx>", obj.class, obj.__id__) end # Check that a method is callable via dRuby. # # +obj+ is the object we want to invoke the method on. +msg_id+ is the # method name, as a Symbol. # # If the method is an insecure method (see #insecure_method?) a # SecurityError is thrown. If the method is private or undefined, # a NameError is thrown. def check_insecure_method(obj, msg_id) return true if Proc === obj && msg_id == :__drb_yield raise(ArgumentError, "#{any_to_s(msg_id)} is not a symbol") unless Symbol == msg_id.class raise(SecurityError, "insecure method `#{msg_id}'") if insecure_method?(msg_id) if obj.private_methods.include?(msg_id.to_s) desc = any_to_s(obj) raise NoMethodError, "private method `#{msg_id}' called for #{desc}" elsif obj.protected_methods.include?(msg_id.to_s) desc = any_to_s(obj) raise NoMethodError, "protected method `#{msg_id}' called for #{desc}" else true end end public :check_insecure_method class InvokeMethod # :nodoc: def initialize(drb_server, client) @drb_server = drb_server @safe_level = drb_server.safe_level @client = client end def perform @result = nil @succ = false setup_message if $SAFE < @safe_level info = Thread.current['DRb'] if @block @result = Thread.new { Thread.current['DRb'] = info $SAFE = @safe_level perform_with_block }.value else @result = Thread.new { Thread.current['DRb'] = info $SAFE = @safe_level perform_without_block }.value end else if @block @result = perform_with_block else @result = perform_without_block end end @succ = true if @msg_id == :to_ary && @result.class == Array @result = DRbArray.new(@result) end return @succ, @result rescue StandardError, ScriptError, Interrupt @result = $! return @succ, @result end private def init_with_client obj, msg, argv, block = @client.recv_request @obj = obj @msg_id = msg.intern @argv = argv @block = block end def check_insecure_method @drb_server.check_insecure_method(@obj, @msg_id) end def setup_message init_with_client check_insecure_method end def perform_without_block if Proc === @obj && @msg_id == :__drb_yield if @argv.size == 1 ary = @argv else ary = [@argv] end ary.collect(&@obj)[0] else @obj.__send__(@msg_id, *@argv) end end end if RUBY_VERSION >= '1.8' require 'drb/invokemethod' class InvokeMethod include InvokeMethod18Mixin end else require 'drb/invokemethod16' class InvokeMethod include InvokeMethod16Mixin end end # The main loop performed by a DRbServer's internal thread. # # Accepts a connection from a client, and starts up its own # thread to handle it. This thread loops, receiving requests # from the client, invoking them on a local object, and # returning responses, until the client closes the connection # or a local method call fails. def main_loop Thread.start(@protocol.accept) do |client| @grp.add Thread.current Thread.current['DRb'] = { 'client' => client , 'server' => self } loop do begin succ = false invoke_method = InvokeMethod.new(self, client) succ, result = invoke_method.perform if !succ && verbose p result result.backtrace.each do |x| puts x end end client.send_reply(succ, result) rescue nil ensure client.close unless succ if Thread.current['DRb']['stop_service'] Thread.new { stop_service } end break unless succ end end end end end @primary_server = nil # Start a dRuby server locally. # # The new dRuby server will become the primary server, even # if another server is currently the primary server. # # +uri+ is the URI for the server to bind to. If nil, # the server will bind to random port on the default local host # name and use the default dRuby protocol. # # +front+ is the server's front object. This may be nil. # # +config+ is the configuration for the new server. This may # be nil. # # See DRbServer::new. def start_service(uri=nil, front=nil, config=nil) @primary_server = DRbServer.new(uri, front, config) end module_function :start_service # The primary local dRuby server. # # This is the server created by the #start_service call. attr_accessor :primary_server module_function :primary_server=, :primary_server # Get the 'current' server. # # In the context of execution taking place within the main # thread of a dRuby server (typically, as a result of a remote # call on the server or one of its objects), the current # server is that server. Otherwise, the current server is # the primary server. # # If the above rule fails to find a server, a DRbServerNotFound # error is raised. def current_server drb = Thread.current['DRb'] server = (drb && drb['server']) ? drb['server'] : @primary_server raise DRbServerNotFound unless server return server end module_function :current_server # Stop the local dRuby server. # # This operates on the primary server. If there is no primary # server currently running, it is a noop. def stop_service @primary_server.stop_service if @primary_server @primary_server = nil end module_function :stop_service # Get the URI defining the local dRuby space. # # This is the URI of the current server. See #current_server. def uri drb = Thread.current['DRb'] client = (drb && drb['client']) if client uri = client.uri return uri if uri end current_server.uri end module_function :uri # Is +uri+ the URI for the current local server? def here?(uri) (current_server.uri rescue nil) == uri end module_function :here? # Get the configuration of the current server. # # If there is no current server, this returns the default configuration. # See #current_server and DRbServer::make_config. def config current_server.config rescue DRbServer.make_config end module_function :config # Get the front object of the current server. # # This raises a DRbServerNotFound error if there is no current server. # See #current_server. def front current_server.front end module_function :front # Convert a reference into an object using the current server. # # This raises a DRbServerNotFound error if there is no current server. # See #current_server. def to_obj(ref) current_server.to_obj(ref) end # Get a reference id for an object using the current server. # # This raises a DRbServerNotFound error if there is no current server. # See #current_server. def to_id(obj) current_server.to_id(obj) end module_function :to_id module_function :to_obj # Get the thread of the primary server. # # This returns nil if there is no primary server. See #primary_server. def thread @primary_server ? @primary_server.thread : nil end module_function :thread # Set the default id conv object. # # See DRbServer#default_id_conv. def install_id_conv(idconv) DRbServer.default_id_conv(idconv) end module_function :install_id_conv # Set the default acl. # # See DRb::DRbServer.default_acl. def install_acl(acl) DRbServer.default_acl(acl) end module_function :install_acl @mutex = Mutex.new def mutex @mutex end module_function :mutex @server = {} def regist_server(server) @server[server.uri] = server mutex.synchronize do @primary_server = server unless @primary_server end end module_function :regist_server def remove_server(server) @server.delete(server.uri) end module_function :remove_server def fetch_server(uri) @server[uri] end module_function :fetch_server end DRbObject = DRb::DRbObject DRbUndumped = DRb::DRbUndumped DRbIdConv = DRb::DRbIdConv PK|] wsdl/parser.rbnu[# WSDL4R - WSDL XML Instance parser library. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/ns' require 'xsd/charset' require 'xsd/datatypes' require 'xsd/xmlparser' require 'wsdl/wsdl' require 'wsdl/data' require 'wsdl/xmlSchema/data' require 'wsdl/soap/data' module WSDL class Parser include WSDL class ParseError < Error; end class FormatDecodeError < ParseError; end class UnknownElementError < FormatDecodeError; end class UnknownAttributeError < FormatDecodeError; end class UnexpectedElementError < FormatDecodeError; end class ElementConstraintError < FormatDecodeError; end class AttributeConstraintError < FormatDecodeError; end private class ParseFrame attr_reader :ns attr_reader :name attr_accessor :node private def initialize(ns, name, node) @ns = ns @name = name @node = node end end public def initialize(opt = {}) @parser = XSD::XMLParser.create_parser(self, opt) @parsestack = nil @lastnode = nil @ignored = {} @location = opt[:location] @originalroot = opt[:originalroot] end def parse(string_or_readable) @parsestack = [] @lastnode = nil @textbuf = '' @parser.do_parse(string_or_readable) @lastnode end def charset @parser.charset end def start_element(name, attrs) lastframe = @parsestack.last ns = parent = nil if lastframe ns = lastframe.ns.clone_ns parent = lastframe.node else ns = XSD::NS.new parent = nil end attrs = XSD::XMLParser.filter_ns(ns, attrs) node = decode_tag(ns, name, attrs, parent) @parsestack << ParseFrame.new(ns, name, node) end def characters(text) lastframe = @parsestack.last if lastframe # Need not to be cloned because character does not have attr. ns = lastframe.ns decode_text(ns, text) else p text if $DEBUG end end def end_element(name) lastframe = @parsestack.pop unless name == lastframe.name raise UnexpectedElementError.new("closing element name '#{name}' does not match with opening element '#{lastframe.name}'") end decode_tag_end(lastframe.ns, lastframe.node) @lastnode = lastframe.node end private def decode_tag(ns, name, attrs, parent) o = nil elename = ns.parse(name) if !parent if elename == DefinitionsName o = Definitions.parse_element(elename) o.location = @location else raise UnknownElementError.new("unknown element: #{elename}") end o.root = @originalroot if @originalroot # o.root = o otherwise else if elename == XMLSchema::AnnotationName # only the first annotation element is allowed for each xsd element. o = XMLSchema::Annotation.new else o = parent.parse_element(elename) end unless o unless @ignored.key?(elename) warn("ignored element: #{elename}") @ignored[elename] = elename end o = Documentation.new # which accepts any element. end # node could be a pseudo element. pseudo element has its own parent. o.root = parent.root o.parent = parent if o.parent.nil? end attrs.each do |key, value| attr_ele = ns.parse(key, true) value_ele = ns.parse(value, true) value_ele.source = value # for recovery; value may not be a QName unless o.parse_attr(attr_ele, value_ele) unless @ignored.key?(attr_ele) warn("ignored attr: #{attr_ele}") @ignored[attr_ele] = attr_ele end end end o end def decode_tag_end(ns, node) node.parse_epilogue end def decode_text(ns, text) @textbuf << text end end end PK|] _WAAwsdl/documentation.rbnu[# WSDL4R - WSDL SOAP documentation element. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Documentation < Info def initialize super end def parse_element(element) # Accepts any element. self end def parse_attr(attr, value) # Accepts any attribute. true end end end PK|]Bwsdl/binding.rbnu[# WSDL4R - WSDL binding definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL class Binding < Info attr_reader :name # required attr_reader :type # required attr_reader :operations attr_reader :soapbinding def initialize super @name = nil @type = nil @operations = XSD::NamedElements.new @soapbinding = nil end def targetnamespace parent.targetnamespace end def parse_element(element) case element when OperationName o = OperationBinding.new @operations << o o when SOAPBindingName o = WSDL::SOAP::Binding.new @soapbinding = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when TypeAttrName @type = value else nil end end end end PK|]f   wsdl/wsdl.rbnu[# WSDL4R - Base definitions. # Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' module WSDL Version = '0.0.2' Namespace = 'http://schemas.xmlsoap.org/wsdl/' SOAPBindingNamespace ='http://schemas.xmlsoap.org/wsdl/soap/' class Error < StandardError; end end PK|]U%wsdl/xmlSchema/enumeration.rbnu[# WSDL4R - XMLSchema enumeration definition for WSDL. # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Enumeration < Info def initialize super end def parse_element(element) nil end def parse_attr(attr, value) case attr when ValueAttrName parent.enumeration << value.source value.source end end end end end PK|]]]wsdl/xmlSchema/content.rbnu[# WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Content < Info attr_accessor :final attr_accessor :mixed attr_accessor :type attr_reader :contents attr_reader :elements def initialize super() @final = nil @mixed = false @type = nil @contents = [] @elements = [] end def targetnamespace parent.targetnamespace end def <<(content) @contents << content update_elements end def each @contents.each do |content| yield content end end def parse_element(element) case element when AllName, SequenceName, ChoiceName o = Content.new o.type = element.name @contents << o o when AnyName o = Any.new @contents << o o when ElementName o = Element.new @contents << o o else nil end end def parse_attr(attr, value) case attr when FinalAttrName @final = value.source when MixedAttrName @mixed = (value.source == 'true') else nil end end def parse_epilogue update_elements end private def update_elements @elements = [] @contents.each do |content| if content.is_a?(Element) @elements << [content.name, content] end end end end end end PK|].Owsdl/xmlSchema/parser.rbnu[# WSDL4R - WSDL XML Instance parser library. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'xsd/ns' require 'xsd/charset' require 'xsd/datatypes' require 'xsd/xmlparser' require 'wsdl/xmlSchema/data' module WSDL module XMLSchema class Parser include XSD class ParseError < Error; end class FormatDecodeError < ParseError; end class UnknownElementError < FormatDecodeError; end class UnknownAttributeError < FormatDecodeError; end class UnexpectedElementError < FormatDecodeError; end class ElementConstraintError < FormatDecodeError; end class AttributeConstraintError < FormatDecodeError; end private class ParseFrame attr_reader :ns attr_reader :name attr_accessor :node private def initialize(ns, name, node) @ns = ns @name = name @node = node end end public def initialize(opt = {}) @parser = XSD::XMLParser.create_parser(self, opt) @parsestack = nil @lastnode = nil @ignored = {} @location = opt[:location] @originalroot = opt[:originalroot] end def parse(string_or_readable) @parsestack = [] @lastnode = nil @textbuf = '' @parser.do_parse(string_or_readable) @lastnode end def charset @parser.charset end def start_element(name, attrs) lastframe = @parsestack.last ns = parent = nil if lastframe ns = lastframe.ns.clone_ns parent = lastframe.node else ns = XSD::NS.new parent = nil end attrs = XSD::XMLParser.filter_ns(ns, attrs) node = decode_tag(ns, name, attrs, parent) @parsestack << ParseFrame.new(ns, name, node) end def characters(text) lastframe = @parsestack.last if lastframe # Need not to be cloned because character does not have attr. ns = lastframe.ns decode_text(ns, text) else p text if $DEBUG end end def end_element(name) lastframe = @parsestack.pop unless name == lastframe.name raise UnexpectedElementError.new("closing element name '#{name}' does not match with opening element '#{lastframe.name}'") end decode_tag_end(lastframe.ns, lastframe.node) @lastnode = lastframe.node end private def decode_tag(ns, name, attrs, parent) o = nil elename = ns.parse(name) if !parent if elename == SchemaName o = Schema.parse_element(elename) o.location = @location else raise UnknownElementError.new("unknown element: #{elename}") end o.root = @originalroot if @originalroot # o.root = o otherwise else if elename == AnnotationName # only the first annotation element is allowed for each element. o = Annotation.new else o = parent.parse_element(elename) end unless o unless @ignored.key?(elename) warn("ignored element: #{elename} of #{parent.class}") @ignored[elename] = elename end o = Documentation.new # which accepts any element. end # node could be a pseudo element. pseudo element has its own parent. o.root = parent.root o.parent = parent if o.parent.nil? end attrs.each do |key, value| attr_ele = ns.parse(key, true) value_ele = ns.parse(value, true) value_ele.source = value # for recovery; value may not be a QName if attr_ele == IdAttrName o.id = value_ele else unless o.parse_attr(attr_ele, value_ele) unless @ignored.key?(attr_ele) warn("ignored attr: #{attr_ele}") @ignored[attr_ele] = attr_ele end end end end o end def decode_tag_end(ns, node) node.parse_epilogue end def decode_text(ns, text) @textbuf << text end end end end PK|]HHwsdl/xmlSchema/unique.rbnu[# WSDL4R - XMLSchema unique element. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Unique < Info def initialize super end def parse_element(element) # Accepts any element. self end def parse_attr(attr, value) # Accepts any attribute. true end end end end PK|] 6%wsdl/xmlSchema/sequence.rbnu[# WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Sequence < Info attr_reader :minoccurs attr_reader :maxoccurs attr_reader :elements def initialize super() @minoccurs = '1' @maxoccurs = '1' @elements = [] end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def <<(element) @elements << element end def parse_element(element) case element when AnyName o = Any.new @elements << o o when ElementName o = Element.new @elements << o o else nil end end def parse_attr(attr, value) case attr when MaxOccursAttrName @maxoccurs = value.source when MinOccursAttrName @minoccurs = value.source else nil end end end end end PK|]  wsdl/xmlSchema/attribute.rbnu[# WSDL4R - XMLSchema attribute definition for WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Attribute < Info class << self if RUBY_VERSION > "1.7.0" def attr_reader_ref(symbol) name = symbol.to_s define_method(name) { instance_variable_get("@#{name}") || (refelement ? refelement.__send__(name) : nil) } end else def attr_reader_ref(symbol) name = symbol.to_s module_eval <<-EOS def #{name} @#{name} || (refelement ? refelement.#{name} : nil) end EOS end end end attr_writer :use attr_writer :form attr_writer :name attr_writer :type attr_writer :local_simpletype attr_writer :default attr_writer :fixed attr_reader_ref :use attr_reader_ref :form attr_reader_ref :name attr_reader_ref :type attr_reader_ref :local_simpletype attr_reader_ref :default attr_reader_ref :fixed attr_accessor :ref attr_accessor :arytype def initialize super @use = nil @form = nil @name = nil @type = nil @local_simpletype = nil @default = nil @fixed = nil @ref = nil @refelement = nil @arytype = nil end def refelement @refelement ||= root.collect_attributes[@ref] end def targetnamespace parent.targetnamespace end def parse_element(element) case element when SimpleTypeName @local_simpletype = SimpleType.new @local_simpletype end end def parse_attr(attr, value) case attr when RefAttrName @ref = value when UseAttrName @use = value.source when FormAttrName @form = value.source when NameAttrName if directelement? @name = XSD::QName.new(targetnamespace, value.source) else @name = XSD::QName.new(nil, value.source) end when TypeAttrName @type = value when DefaultAttrName @default = value.source when FixedAttrName @fixed = value.source when ArrayTypeAttrName @arytype = if value.namespace.nil? XSD::QName.new(XSD::Namespace, value.source) else value end else nil end end private def directelement? parent.is_a?(Schema) end end end end PK|]Lwsdl/xmlSchema/include.rbnu[# WSDL4R - XMLSchema include definition. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/xmlSchema/importer' module WSDL module XMLSchema class Include < Info attr_reader :schemalocation attr_reader :content def initialize super @schemalocation = nil @content = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when SchemaLocationAttrName @schemalocation = URI.parse(value.source) if @schemalocation.relative? @schemalocation = parent.location + @schemalocation end @content = import(@schemalocation) @schemalocation else nil end end private def import(location) Importer.import(location) end end end end PK|]֩Dwsdl/xmlSchema/pattern.rbnu[# WSDL4R - XMLSchema pattern definition for WSDL. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Pattern < Info def initialize super end def parse_element(element) nil end def parse_attr(attr, value) case attr when ValueAttrName parent.pattern = /\A#{value.source}\z/n value.source end end end end end PK|]#~~wsdl/xmlSchema/simpleType.rbnu[# WSDL4R - XMLSchema simpleType definition for WSDL. # Copyright (C) 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class SimpleType < Info attr_accessor :name attr_reader :restriction def check_lexical_format(value) if @restriction check_restriction(value) else raise ArgumentError.new("incomplete simpleType") end end def base if @restriction @restriction.base else raise ArgumentError.new("incomplete simpleType") end end def initialize(name = nil) super() @name = name @restriction = nil end def targetnamespace parent.targetnamespace end def parse_element(element) case element when RestrictionName @restriction = SimpleRestriction.new @restriction end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) end end private def check_restriction(value) unless @restriction.valid?(value) raise XSD::ValueSpaceError.new("#{@name}: cannot accept '#{value}'") end end end end end PK|]8nwsdl/xmlSchema/simpleContent.rbnu[# WSDL4R - XMLSchema simpleContent definition for WSDL. # Copyright (C) 2004, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class SimpleContent < Info attr_reader :restriction attr_reader :extension def check_lexical_format(value) check(value) end def initialize super @restriction = nil @extension = nil end def base content.base end def targetnamespace parent.targetnamespace end def parse_element(element) case element when RestrictionName @restriction = SimpleRestriction.new @restriction when ExtensionName @extension = SimpleExtension.new @extension end end private def content @restriction || @extension end def check(value) unless content.valid?(value) raise XSD::ValueSpaceError.new("#{@name}: cannot accept '#{value}'") end end end end end PK|] t  wsdl/xmlSchema/data.rbnu[# WSDL4R - XMLSchema data definitions. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/datatypes' require 'wsdl/xmlSchema/annotation' require 'wsdl/xmlSchema/schema' require 'wsdl/xmlSchema/import' require 'wsdl/xmlSchema/include' require 'wsdl/xmlSchema/simpleType' require 'wsdl/xmlSchema/simpleRestriction' require 'wsdl/xmlSchema/simpleExtension' require 'wsdl/xmlSchema/complexType' require 'wsdl/xmlSchema/complexContent' require 'wsdl/xmlSchema/simpleContent' require 'wsdl/xmlSchema/any' require 'wsdl/xmlSchema/element' require 'wsdl/xmlSchema/all' require 'wsdl/xmlSchema/choice' require 'wsdl/xmlSchema/sequence' require 'wsdl/xmlSchema/attribute' require 'wsdl/xmlSchema/unique' require 'wsdl/xmlSchema/enumeration' require 'wsdl/xmlSchema/length' require 'wsdl/xmlSchema/pattern' module WSDL module XMLSchema AllName = XSD::QName.new(XSD::Namespace, 'all') AnnotationName = XSD::QName.new(XSD::Namespace, 'annotation') AnyName = XSD::QName.new(XSD::Namespace, 'any') AttributeName = XSD::QName.new(XSD::Namespace, 'attribute') ChoiceName = XSD::QName.new(XSD::Namespace, 'choice') ComplexContentName = XSD::QName.new(XSD::Namespace, 'complexContent') ComplexTypeName = XSD::QName.new(XSD::Namespace, 'complexType') ElementName = XSD::QName.new(XSD::Namespace, 'element') EnumerationName = XSD::QName.new(XSD::Namespace, 'enumeration') ExtensionName = XSD::QName.new(XSD::Namespace, 'extension') ImportName = XSD::QName.new(XSD::Namespace, 'import') IncludeName = XSD::QName.new(XSD::Namespace, 'include') LengthName = XSD::QName.new(XSD::Namespace, 'length') PatternName = XSD::QName.new(XSD::Namespace, 'pattern') RestrictionName = XSD::QName.new(XSD::Namespace, 'restriction') SequenceName = XSD::QName.new(XSD::Namespace, 'sequence') SchemaName = XSD::QName.new(XSD::Namespace, 'schema') SimpleContentName = XSD::QName.new(XSD::Namespace, 'simpleContent') SimpleTypeName = XSD::QName.new(XSD::Namespace, 'simpleType') UniqueName = XSD::QName.new(XSD::Namespace, 'unique') AttributeFormDefaultAttrName = XSD::QName.new(nil, 'attributeFormDefault') BaseAttrName = XSD::QName.new(nil, 'base') DefaultAttrName = XSD::QName.new(nil, 'default') ElementFormDefaultAttrName = XSD::QName.new(nil, 'elementFormDefault') FinalAttrName = XSD::QName.new(nil, 'final') FixedAttrName = XSD::QName.new(nil, 'fixed') FormAttrName = XSD::QName.new(nil, 'form') IdAttrName = XSD::QName.new(nil, 'id') MaxOccursAttrName = XSD::QName.new(nil, 'maxOccurs') MinOccursAttrName = XSD::QName.new(nil, 'minOccurs') MixedAttrName = XSD::QName.new(nil, 'mixed') NameAttrName = XSD::QName.new(nil, 'name') NamespaceAttrName = XSD::QName.new(nil, 'namespace') NillableAttrName = XSD::QName.new(nil, 'nillable') ProcessContentsAttrName = XSD::QName.new(nil, 'processContents') RefAttrName = XSD::QName.new(nil, 'ref') SchemaLocationAttrName = XSD::QName.new(nil, 'schemaLocation') TargetNamespaceAttrName = XSD::QName.new(nil, 'targetNamespace') TypeAttrName = XSD::QName.new(nil, 'type') UseAttrName = XSD::QName.new(nil, 'use') ValueAttrName = XSD::QName.new(nil, 'value') end end PK|]Iƽ&ee wsdl/xmlSchema/complexContent.rbnu[# WSDL4R - XMLSchema complexContent definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class ComplexContent < Info attr_accessor :base attr_reader :derivetype attr_reader :content attr_reader :attributes def initialize super @base = nil @derivetype = nil @content = nil @attributes = XSD::NamedElements.new @basetype = nil end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def basetype @basetype ||= root.collect_complextypes[@base] end def parse_element(element) case element when RestrictionName, ExtensionName @derivetype = element.name self when AllName if @derivetype.nil? raise Parser::ElementConstraintError.new("base attr not found.") end @content = All.new @content when SequenceName if @derivetype.nil? raise Parser::ElementConstraintError.new("base attr not found.") end @content = Sequence.new @content when ChoiceName if @derivetype.nil? raise Parser::ElementConstraintError.new("base attr not found.") end @content = Choice.new @content when AttributeName if @derivetype.nil? raise Parser::ElementConstraintError.new("base attr not found.") end o = Attribute.new @attributes << o o end end def parse_attr(attr, value) if @derivetype.nil? return nil end case attr when BaseAttrName @base = value else nil end end end end end PK|]@wsdl/xmlSchema/importer.rbnu[# WSDL4R - XSD importer library. # Copyright (C) 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'soap/httpconfigloader' require 'wsdl/xmlSchema/parser' module WSDL module XMLSchema class Importer def self.import(location, originalroot = nil) new.import(location, originalroot) end def initialize @web_client = nil end def import(location, originalroot = nil) unless location.is_a?(URI) location = URI.parse(location) end content = parse(fetch(location), location, originalroot) content.location = location content end private def parse(content, location, originalroot) opt = { :location => location, :originalroot => originalroot } WSDL::XMLSchema::Parser.new(opt).parse(content) end def fetch(location) warn("importing: #{location}") if $DEBUG content = nil if location.scheme == 'file' or (location.relative? and FileTest.exist?(location.path)) content = File.open(location.path).read elsif location.scheme and location.scheme.size == 1 and FileTest.exist?(location.to_s) # ToDo: remove this ugly workaround for a path with drive letter # (D://foo/bar) content = File.open(location.to_s).read else client = web_client.new(nil, "WSDL4R") client.proxy = ::SOAP::Env::HTTP_PROXY client.no_proxy = ::SOAP::Env::NO_PROXY if opt = ::SOAP::Property.loadproperty(::SOAP::PropertyName) ::SOAP::HTTPConfigLoader.set_options(client, opt["client.protocol.http"]) end content = client.get_content(location) end content end def web_client @web_client ||= begin require 'http-access2' if HTTPAccess2::VERSION < "2.0" raise LoadError.new("http-access/2.0 or later is required.") end HTTPAccess2::Client rescue LoadError warn("Loading http-access2 failed. Net/http is used.") if $DEBUG require 'soap/netHttpClient' ::SOAP::NetHttpClient end @web_client end end end end PK|]Z TTwsdl/xmlSchema/xsd2ruby.rbnu[# XSD4R - XSD to ruby mapping library. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/codegen/gensupport' require 'wsdl/xmlSchema/importer' require 'wsdl/soap/classDefCreator' module WSDL module XMLSchema class XSD2Ruby attr_accessor :location attr_reader :opt attr_accessor :logger attr_accessor :basedir def run unless @location raise RuntimeError, "XML Schema location not given" end @xsd = import(@location) @name = create_classname(@xsd) create_file end private def initialize @location = nil @opt = {} @logger = Logger.new(STDERR) @basedir = nil @xsd = nil @name = nil end def create_file create_classdef end def create_classdef @logger.info { "Creating class definition." } @classdef_filename = @name + '.rb' check_file(@classdef_filename) or return write_file(@classdef_filename) do |f| f << WSDL::SOAP::ClassDefCreator.new(@xsd).dump end end def write_file(filename) if @basedir filename = File.join(basedir, filename) end File.open(filename, "w") do |f| yield f end end def check_file(filename) if @basedir filename = File.join(basedir, filename) end if FileTest.exist?(filename) if @opt.key?('force') @logger.warn { "File '#{filename}' exists but overrides it." } true else @logger.warn { "File '#{filename}' exists. #{$0} did not override it." } false end else @logger.info { "Creates file '#{filename}'." } true end end def create_classname(xsd) name = nil if xsd.targetnamespace name = xsd.targetnamespace.scan(/[a-zA-Z0-9]+$/)[0] end if name.nil? 'default' else XSD::CodeGen::GenSupport.safevarname(name) end end def import(location) WSDL::XMLSchema::Importer.import(location) end end end end PK|]Σu/wsdl/xmlSchema/all.rbnu[# WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class All < Info attr_reader :minoccurs attr_reader :maxoccurs attr_reader :elements def initialize super() @minoccurs = '1' @maxoccurs = '1' @elements = [] end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def <<(element) @elements << element end def parse_element(element) case element when AnyName o = Any.new @elements << o o when ElementName o = Element.new @elements << o o else nil end end def parse_attr(attr, value) case attr when MaxOccursAttrName @maxoccurs = value.source when MinOccursAttrName @minoccurs = value.source else nil end end end end end PK|]pwsdl/xmlSchema/import.rbnu[# WSDL4R - XMLSchema import definition. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/xmlSchema/importer' module WSDL module XMLSchema class Import < Info attr_reader :namespace attr_reader :schemalocation attr_reader :content def initialize super @namespace = nil @schemalocation = nil @content = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when NamespaceAttrName @namespace = value.source when SchemaLocationAttrName @schemalocation = URI.parse(value.source) if @schemalocation.relative? and !parent.location.nil? and !parent.location.relative? @schemalocation = parent.location + @schemalocation end if root.importedschema.key?(@schemalocation) @content = root.importedschema[@schemalocation] else root.importedschema[@schemalocation] = nil # placeholder @content = import(@schemalocation) root.importedschema[@schemalocation] = @content end @schemalocation else nil end end private def import(location) Importer.import(location, root) end end end end PK|]TS  wsdl/xmlSchema/schema.rbnu[# WSDL4R - XMLSchema schema definition for WSDL. # Copyright (C) 2002, 2003-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class Schema < Info attr_reader :targetnamespace # required attr_reader :complextypes attr_reader :simpletypes attr_reader :elements attr_reader :attributes attr_reader :imports attr_accessor :attributeformdefault attr_accessor :elementformdefault attr_reader :importedschema def initialize super @targetnamespace = nil @complextypes = XSD::NamedElements.new @simpletypes = XSD::NamedElements.new @elements = XSD::NamedElements.new @attributes = XSD::NamedElements.new @imports = [] @attributeformdefault = "unqualified" @elementformdefault = "unqualified" @importedschema = {} @location = nil @root = self end def location @location || (root.nil? ? nil : root.location) end def location=(location) @location = location end def parse_element(element) case element when ImportName o = Import.new @imports << o o when IncludeName o = Include.new @imports << o o when ComplexTypeName o = ComplexType.new @complextypes << o o when SimpleTypeName o = SimpleType.new @simpletypes << o o when ElementName o = Element.new @elements << o o when AttributeName o = Attribute.new @attributes << o o else nil end end def parse_attr(attr, value) case attr when TargetNamespaceAttrName @targetnamespace = value.source when AttributeFormDefaultAttrName @attributeformdefault = value.source when ElementFormDefaultAttrName @elementformdefault = value.source else nil end end def collect_attributes result = XSD::NamedElements.new result.concat(@attributes) @imports.each do |import| result.concat(import.content.collect_attributes) if import.content end result end def collect_elements result = XSD::NamedElements.new result.concat(@elements) @imports.each do |import| result.concat(import.content.collect_elements) if import.content end result end def collect_complextypes result = XSD::NamedElements.new result.concat(@complextypes) @imports.each do |import| result.concat(import.content.collect_complextypes) if import.content end result end def collect_simpletypes result = XSD::NamedElements.new result.concat(@simpletypes) @imports.each do |import| result.concat(import.content.collect_simpletypes) if import.content end result end def self.parse_element(element) if element == SchemaName Schema.new else nil end end end end end PK|]@@wsdl/xmlSchema/any.rbnu[# WSDL4R - XMLSchema any definition for WSDL. # Copyright (C) 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Any < Info attr_accessor :maxoccurs attr_accessor :minoccurs attr_accessor :namespace attr_accessor :process_contents def initialize super() @maxoccurs = '1' @minoccurs = '1' @namespace = '##any' @process_contents = 'strict' end def targetnamespace parent.targetnamespace end def parse_element(element) nil end def parse_attr(attr, value) case attr when MaxOccursAttrName @maxoccurs = value.source when MinOccursAttrName @minoccurs = value.source when NamespaceAttrName @namespace = value.source when ProcessContentsAttrName @process_contents = value.source else nil end end end end end PK|]#*{A A wsdl/xmlSchema/element.rbnu[# WSDL4R - XMLSchema element definition for WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Element < Info class << self if RUBY_VERSION > "1.7.0" def attr_reader_ref(symbol) name = symbol.to_s define_method(name) { instance_variable_get("@#{name}") || (refelement ? refelement.__send__(name) : nil) } end else def attr_reader_ref(symbol) name = symbol.to_s module_eval <<-EOS def #{name} @#{name} || (refelement ? refelement.#{name} : nil) end EOS end end end attr_writer :name # required attr_writer :form attr_writer :type attr_writer :local_simpletype attr_writer :local_complextype attr_writer :constraint attr_writer :maxoccurs attr_writer :minoccurs attr_writer :nillable attr_reader_ref :name attr_reader_ref :form attr_reader_ref :type attr_reader_ref :local_simpletype attr_reader_ref :local_complextype attr_reader_ref :constraint attr_reader_ref :maxoccurs attr_reader_ref :minoccurs attr_reader_ref :nillable attr_accessor :ref def initialize(name = nil, type = nil) super() @name = name @form = nil @type = type @local_simpletype = @local_complextype = nil @constraint = nil @maxoccurs = '1' @minoccurs = '1' @nillable = nil @ref = nil @refelement = nil end def refelement @refelement ||= (@ref ? root.collect_elements[@ref] : nil) end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def elementform self.form.nil? ? parent.elementformdefault : self.form end def parse_element(element) case element when SimpleTypeName @local_simpletype = SimpleType.new @local_simpletype when ComplexTypeName @type = nil @local_complextype = ComplexType.new @local_complextype when UniqueName @constraint = Unique.new @constraint else nil end end def parse_attr(attr, value) case attr when NameAttrName # namespace may be nil if directelement? or elementform == 'qualified' @name = XSD::QName.new(targetnamespace, value.source) else @name = XSD::QName.new(nil, value.source) end when FormAttrName @form = value.source when TypeAttrName @type = value when RefAttrName @ref = value when MaxOccursAttrName if parent.is_a?(All) if value.source != '1' raise Parser::AttrConstraintError.new( "cannot parse #{value} for #{attr}") end end @maxoccurs = value.source when MinOccursAttrName if parent.is_a?(All) unless ['0', '1'].include?(value.source) raise Parser::AttrConstraintError.new( "cannot parse #{value} for #{attr}") end end @minoccurs = value.source when NillableAttrName @nillable = (value.source == 'true') else nil end end private def directelement? parent.is_a?(Schema) end end end end PK|]#wsdl/xmlSchema/simpleRestriction.rbnu[# WSDL4R - XMLSchema simpleContent restriction definition for WSDL. # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class SimpleRestriction < Info attr_reader :base attr_reader :enumeration attr_accessor :length attr_accessor :pattern def initialize super @base = nil @enumeration = [] # NamedElements? @length = nil @pattern = nil end def valid?(value) return false unless check_restriction(value) return false unless check_length(value) return false unless check_pattern(value) true end def parse_element(element) case element when EnumerationName Enumeration.new # just a parsing handler when LengthName Length.new # just a parsing handler when PatternName Pattern.new # just a parsing handler end end def parse_attr(attr, value) case attr when BaseAttrName @base = value end end private def check_restriction(value) @enumeration.empty? or @enumeration.include?(value) end def check_length(value) @length.nil? or value.size == @length end def check_pattern(value) @pattern.nil? or @pattern =~ value end end end end PK|]#wsdl/xmlSchema/choice.rbnu[# WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Choice < Info attr_reader :minoccurs attr_reader :maxoccurs attr_reader :elements def initialize super() @minoccurs = '1' @maxoccurs = '1' @elements = [] end def targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end def <<(element) @elements << element end def parse_element(element) case element when AnyName o = Any.new @elements << o o when ElementName o = Element.new @elements << o o else nil end end def parse_attr(attr, value) case attr when MaxOccursAttrName @maxoccurs = value.source when MinOccursAttrName @minoccurs = value.source else nil end end end end end PK|](RRwsdl/xmlSchema/length.rbnu[# WSDL4R - XMLSchema length definition for WSDL. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Length < Info def initialize super end def parse_element(element) nil end def parse_attr(attr, value) case attr when ValueAttrName value.source end end end end end PK|]fU wsdl/xmlSchema/complexType.rbnu[# WSDL4R - XMLSchema complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/xmlSchema/content' require 'wsdl/xmlSchema/element' require 'xsd/namedelements' module WSDL module XMLSchema class ComplexType < Info attr_accessor :name attr_accessor :complexcontent attr_accessor :simplecontent attr_reader :content attr_accessor :final attr_accessor :mixed attr_reader :attributes def initialize(name = nil) super() @name = name @complexcontent = nil @simplecontent = nil @content = nil @final = nil @mixed = false @attributes = XSD::NamedElements.new end def targetnamespace # inner elements can be qualified # parent.is_a?(WSDL::XMLSchema::Element) ? nil : parent.targetnamespace parent.targetnamespace end def elementformdefault parent.elementformdefault end AnyAsElement = Element.new(XSD::QName.new(nil, 'any'), XSD::AnyTypeName) def each_element if content content.elements.each do |element| if element.is_a?(Any) yield(AnyAsElement) else yield(element) end end end end def find_element(name) if content content.elements.each do |element| if element.is_a?(Any) return AnyAsElement if name == AnyAsElement.name else return element if name == element.name end end end nil end def find_element_by_name(name) if content content.elements.each do |element| if element.is_a?(Any) return AnyAsElement if name == AnyAsElement.name.name else return element if name == element.name.name end end end nil end def sequence_elements=(elements) @content = Sequence.new elements.each do |element| @content << element end end def all_elements=(elements) @content = All.new elements.each do |element| @content << element end end def parse_element(element) case element when AllName @content = All.new when SequenceName @content = Sequence.new when ChoiceName @content = Choice.new when ComplexContentName @complexcontent = ComplexContent.new when SimpleContentName @simplecontent = SimpleContent.new when AttributeName o = Attribute.new @attributes << o o else nil end end def parse_attr(attr, value) case attr when FinalAttrName @final = value.source when MixedAttrName @mixed = (value.source == 'true') when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end end PK|]=t!wsdl/xmlSchema/simpleExtension.rbnu[# WSDL4R - XMLSchema simpleType extension definition for WSDL. # Copyright (C) 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL module XMLSchema class SimpleExtension < Info attr_reader :base attr_reader :attributes def initialize super @base = nil @attributes = XSD::NamedElements.new end def targetnamespace parent.targetnamespace end def valid?(value) true end def parse_element(element) case element when AttributeName o = Attribute.new @attributes << o o end end def parse_attr(attr, value) case attr when BaseAttrName @base = value end end end end end PK|]rYYwsdl/xmlSchema/annotation.rbnu[# WSDL4R - WSDL SOAP documentation element. # Copyright (C) 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module XMLSchema class Annotation < Info def initialize super end def parse_element(element) # Accepts any element. self end def parse_attr(attr, value) # Accepts any attribute. true end end end end PK|]>w@1 1 wsdl/data.rbnu[# WSDL4R - WSDL data definitions. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'wsdl/documentation' require 'wsdl/definitions' require 'wsdl/types' require 'wsdl/message' require 'wsdl/part' require 'wsdl/portType' require 'wsdl/operation' require 'wsdl/param' require 'wsdl/binding' require 'wsdl/operationBinding' require 'wsdl/service' require 'wsdl/port' require 'wsdl/import' module WSDL ArrayTypeAttrName = XSD::QName.new(Namespace, 'arrayType') BindingName = XSD::QName.new(Namespace, 'binding') DefinitionsName = XSD::QName.new(Namespace, 'definitions') DocumentationName = XSD::QName.new(Namespace, 'documentation') FaultName = XSD::QName.new(Namespace, 'fault') ImportName = XSD::QName.new(Namespace, 'import') InputName = XSD::QName.new(Namespace, 'input') MessageName = XSD::QName.new(Namespace, 'message') OperationName = XSD::QName.new(Namespace, 'operation') OutputName = XSD::QName.new(Namespace, 'output') PartName = XSD::QName.new(Namespace, 'part') PortName = XSD::QName.new(Namespace, 'port') PortTypeName = XSD::QName.new(Namespace, 'portType') ServiceName = XSD::QName.new(Namespace, 'service') TypesName = XSD::QName.new(Namespace, 'types') SchemaName = XSD::QName.new(XSD::Namespace, 'schema') SOAPAddressName = XSD::QName.new(SOAPBindingNamespace, 'address') SOAPBindingName = XSD::QName.new(SOAPBindingNamespace, 'binding') SOAPHeaderName = XSD::QName.new(SOAPBindingNamespace, 'header') SOAPBodyName = XSD::QName.new(SOAPBindingNamespace, 'body') SOAPFaultName = XSD::QName.new(SOAPBindingNamespace, 'fault') SOAPOperationName = XSD::QName.new(SOAPBindingNamespace, 'operation') BindingAttrName = XSD::QName.new(nil, 'binding') ElementAttrName = XSD::QName.new(nil, 'element') LocationAttrName = XSD::QName.new(nil, 'location') MessageAttrName = XSD::QName.new(nil, 'message') NameAttrName = XSD::QName.new(nil, 'name') NamespaceAttrName = XSD::QName.new(nil, 'namespace') ParameterOrderAttrName = XSD::QName.new(nil, 'parameterOrder') TargetNamespaceAttrName = XSD::QName.new(nil, 'targetNamespace') TypeAttrName = XSD::QName.new(nil, 'type') end PK|]y5 5 wsdl/operation.rbnu[# WSDL4R - WSDL operation definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Operation < Info class NameInfo attr_reader :op_name attr_reader :optype_name attr_reader :parts def initialize(op_name, optype_name, parts) @op_name = op_name @optype_name = optype_name @parts = parts end end attr_reader :name # required attr_reader :parameter_order # optional attr_reader :input attr_reader :output attr_reader :fault attr_reader :type # required def initialize super @name = nil @type = nil @parameter_order = nil @input = nil @output = nil @fault = [] end def targetnamespace parent.targetnamespace end def input_info typename = input.find_message.name NameInfo.new(@name, typename, inputparts) end def output_info typename = output.find_message.name NameInfo.new(@name, typename, outputparts) end def inputparts sort_parts(input.find_message.parts) end def inputname XSD::QName.new(targetnamespace, input.name ? input.name.name : @name.name) end def outputparts sort_parts(output.find_message.parts) end def outputname XSD::QName.new(targetnamespace, output.name ? output.name.name : @name.name + 'Response') end def parse_element(element) case element when InputName o = Param.new @input = o o when OutputName o = Param.new @output = o o when FaultName o = Param.new @fault << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when TypeAttrName @type = value when ParameterOrderAttrName @parameter_order = value.source.split(/\s+/) else nil end end private def sort_parts(parts) return parts.dup unless parameter_order result = [] parameter_order.each do |orderitem| if (ele = parts.find { |part| part.name == orderitem }) result << ele end end if result.length == 0 return parts.dup end # result length can be shorter than parts's. # return part must not be a part of the parameterOrder. result end end end PK|]J;wsdl/definitions.rbnu[# WSDL4R - WSDL definitions. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL class Definitions < Info attr_reader :name attr_reader :targetnamespace attr_reader :imports attr_accessor :location attr_reader :importedschema def initialize super @name = nil @targetnamespace = nil @location = nil @importedschema = {} @types = nil @imports = [] @messages = XSD::NamedElements.new @porttypes = XSD::NamedElements.new @bindings = XSD::NamedElements.new @services = XSD::NamedElements.new @anontypes = XSD::NamedElements.new @root = self end def inspect sprintf("#<%s:0x%x %s>", self.class.name, __id__, @name || '(unnamed)') end def targetnamespace=(targetnamespace) @targetnamespace = targetnamespace if @name @name = XSD::QName.new(@targetnamespace, @name.name) end end def collect_attributes result = XSD::NamedElements.new if @types @types.schemas.each do |schema| result.concat(schema.collect_attributes) end end @imports.each do |import| result.concat(import.content.collect_attributes) end result end def collect_elements result = XSD::NamedElements.new if @types @types.schemas.each do |schema| result.concat(schema.collect_elements) end end @imports.each do |import| result.concat(import.content.collect_elements) end result end def collect_complextypes result = @anontypes.dup if @types @types.schemas.each do |schema| result.concat(schema.collect_complextypes) end end @imports.each do |import| result.concat(import.content.collect_complextypes) end result end def collect_simpletypes result = XSD::NamedElements.new if @types @types.schemas.each do |schema| result.concat(schema.collect_simpletypes) end end @imports.each do |import| result.concat(import.content.collect_simpletypes) end result end # ToDo: simpletype must be accepted... def add_type(complextype) @anontypes << complextype end def messages result = @messages.dup @imports.each do |import| result.concat(import.content.messages) if self.class === import.content end result end def porttypes result = @porttypes.dup @imports.each do |import| result.concat(import.content.porttypes) if self.class === import.content end result end def bindings result = @bindings.dup @imports.each do |import| result.concat(import.content.bindings) if self.class === import.content end result end def services result = @services.dup @imports.each do |import| result.concat(import.content.services) if self.class === import.content end result end def message(name) message = @messages[name] return message if message @imports.each do |import| message = import.content.message(name) if self.class === import.content return message if message end nil end def porttype(name) porttype = @porttypes[name] return porttype if porttype @imports.each do |import| porttype = import.content.porttype(name) if self.class === import.content return porttype if porttype end nil end def binding(name) binding = @bindings[name] return binding if binding @imports.each do |import| binding = import.content.binding(name) if self.class === import.content return binding if binding end nil end def service(name) service = @services[name] return service if service @imports.each do |import| service = import.content.service(name) if self.class === import.content return service if service end nil end def porttype_binding(name) binding = @bindings.find { |item| item.type == name } return binding if binding @imports.each do |import| binding = import.content.porttype_binding(name) if self.class === import.content return binding if binding end nil end def parse_element(element) case element when ImportName o = Import.new @imports << o o when TypesName o = Types.new @types = o o when MessageName o = Message.new @messages << o o when PortTypeName o = PortType.new @porttypes << o o when BindingName o = Binding.new @bindings << o o when ServiceName o = Service.new @services << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when TargetNamespaceAttrName self.targetnamespace = value.source else nil end end def self.parse_element(element) if element == DefinitionsName Definitions.new else nil end end private end end PK|]UIlaawsdl/service.rbnu[# WSDL4R - WSDL service definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL class Service < Info attr_reader :name # required attr_reader :ports attr_reader :soap_address def initialize super @name = nil @ports = XSD::NamedElements.new @soap_address = nil end def targetnamespace parent.targetnamespace end def parse_element(element) case element when PortName o = Port.new @ports << o o when SOAPAddressName o = WSDL::SOAP::Address.new @soap_address = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end PK|])J wsdl/param.rbnu[# WSDL4R - WSDL param definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Param < Info attr_reader :message # required attr_reader :name # optional but required for fault. attr_reader :soapbody attr_reader :soapheader attr_reader :soapfault def initialize super @message = nil @name = nil @soapbody = nil @soapheader = [] @soapfault = nil end def targetnamespace parent.targetnamespace end def find_message root.message(@message) or raise RuntimeError.new("#{@message} not found") end def soapbody_use if @soapbody @soapbody.use || :literal else raise RuntimeError.new("soap:body not found") end end def parse_element(element) case element when SOAPBodyName o = WSDL::SOAP::Body.new @soapbody = o o when SOAPHeaderName o = WSDL::SOAP::Header.new @soapheader << o o when SOAPFaultName o = WSDL::SOAP::Fault.new @soap_fault = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when MessageAttrName if value.namespace.nil? value = XSD::QName.new(targetnamespace, value.source) end @message = value when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end PK|]4wsdl/operationBinding.rbnu[# WSDL4R - WSDL bound operation definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class OperationBinding < Info attr_reader :name # required attr_reader :input attr_reader :output attr_reader :fault attr_reader :soapoperation def initialize super @name = nil @input = nil @output = nil @fault = [] @soapoperation = nil end def targetnamespace parent.targetnamespace end def porttype root.porttype(parent.type) end def find_operation porttype.operations[@name] or raise RuntimeError.new("#{@name} not found") end def soapoperation_name if @soapoperation @soapoperation.input_info.op_name else find_operation.name end end def soapoperation_style style = nil if @soapoperation style = @soapoperation.operation_style elsif parent.soapbinding style = parent.soapbinding.style else raise TypeError.new("operation style definition not found") end style || :document end def soapaction if @soapoperation @soapoperation.soapaction else nil end end def parse_element(element) case element when InputName o = Param.new @input = o o when OutputName o = Param.new @output = o o when FaultName o = Param.new @fault << o o when SOAPOperationName o = WSDL::SOAP::Operation.new @soapoperation = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end PK|]}@99wsdl/importer.rbnu[# WSDL4R - WSDL importer library. # Copyright (C) 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/xmlSchema/importer' require 'wsdl/parser' module WSDL class Importer < WSDL::XMLSchema::Importer def self.import(location, originalroot = nil) new.import(location, originalroot) end private def parse(content, location, originalroot) opt = { :location => location, :originalroot => originalroot } begin WSDL::Parser.new(opt).parse(content) rescue WSDL::Parser::ParseError super(content, location, originalroot) end end end end PK|]׎1 wsdl/part.rbnu[# WSDL4R - WSDL part definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Part < Info attr_reader :name # required attr_reader :element # optional attr_reader :type # optional def initialize super @name = nil @element = nil @type = nil end def parse_element(element) case element when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = value.source when ElementAttrName @element = value when TypeAttrName @type = value else nil end end end end PK|] [ wsdl/types.rbnu[# WSDL4R - WSDL types definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Types < Info attr_reader :schemas def initialize super @schemas = [] end def parse_element(element) case element when SchemaName o = XMLSchema::Schema.new @schemas << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) nil end end end PK|],;wsdl/portType.rbnu[# WSDL4R - WSDL portType definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' module WSDL class PortType < Info attr_reader :name # required attr_reader :operations def targetnamespace parent.targetnamespace end def initialize super @name = nil @operations = XSD::NamedElements.new end def find_binding root.bindings.find { |item| item.type == @name } or raise RuntimeError.new("#{@name} not found") end def locations bind_name = find_binding.name result = [] root.services.each do |service| service.ports.each do |port| if port.binding == bind_name result << port.soap_address.location if port.soap_address end end end result end def parse_element(element) case element when OperationName o = Operation.new @operations << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) else nil end end end end PK|]˃ʱwsdl/import.rbnu[# WSDL4R - WSDL import definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/importer' module WSDL class Import < Info attr_reader :namespace attr_reader :location attr_reader :content def initialize super @namespace = nil @location = nil @content = nil @web_client = nil end def parse_element(element) case element when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NamespaceAttrName @namespace = value.source if @content @content.targetnamespace = @namespace end @namespace when LocationAttrName @location = URI.parse(value.source) if @location.relative? and !parent.location.nil? and !parent.location.relative? @location = parent.location + @location end if root.importedschema.key?(@location) @content = root.importedschema[@location] else root.importedschema[@location] = nil # placeholder @content = import(@location) if @content.is_a?(Definitions) @content.root = root if @namespace @content.targetnamespace = @namespace end end root.importedschema[@location] = @content end @location else nil end end private def import(location) Importer.import(location, root) end end end PK|]^Dff wsdl/port.rbnu[# WSDL4R - WSDL port definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Port < Info attr_reader :name # required attr_reader :binding # required attr_reader :soap_address def initialize super @name = nil @binding = nil @soap_address = nil end def targetnamespace parent.targetnamespace end def porttype root.porttype(find_binding.type) end def find_binding root.binding(@binding) or raise RuntimeError.new("#{@binding} not found") end def inputoperation_map result = {} find_binding.operations.each do |op_bind| op_info = op_bind.soapoperation.input_info result[op_info.op_name] = op_info end result end def outputoperation_map result = {} find_binding.operations.each do |op_bind| op_info = op_bind.soapoperation.output_info result[op_info.op_name] = op_info end result end def parse_element(element) case element when SOAPAddressName o = WSDL::SOAP::Address.new @soap_address = o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when BindingAttrName @binding = value else nil end end end end PK|]Xd wsdl/soap/driverCreator.rbnu[# WSDL4R - Creating driver code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/mappingRegistryCreator' require 'wsdl/soap/methodDefCreator' require 'wsdl/soap/classDefCreatorSupport' require 'xsd/codegen' module WSDL module SOAP class DriverCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(porttype = nil) if porttype.nil? result = "" @definitions.porttypes.each do |type| result << dump_porttype(type.name) result << "\n" end else result = dump_porttype(porttype) end result end private def dump_porttype(name) class_name = create_class_name(name) methoddef, types = MethodDefCreator.new(@definitions).dump(name) mr_creator = MappingRegistryCreator.new(@definitions) binding = @definitions.bindings.find { |item| item.type == name } return '' unless binding.soapbinding # not a SOAP binding address = @definitions.porttype(name).locations[0] c = XSD::CodeGen::ClassDef.new(class_name, "::SOAP::RPC::Driver") c.def_require("soap/rpc/driver") c.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new") c.def_const("DefaultEndpointUrl", ndq(address)) c.def_code(mr_creator.dump(types)) c.def_code <<-EOD Methods = [ #{methoddef.gsub(/^/, " ")} ] EOD c.def_method("initialize", "endpoint_url = nil") do <<-EOD endpoint_url ||= DefaultEndpointUrl super(endpoint_url, nil) self.mapping_registry = MappingRegistry init_methods EOD end c.def_privatemethod("init_methods") do <<-EOD Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document add_document_operation(*definitions) else add_rpc_operation(*definitions) qname = definitions[0] name = definitions[2] if qname.name != name and qname.name.capitalize == name.capitalize ::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg| __send__(name, *arg) end end end end EOD end c.dump end end end end PK|]S!S!wsdl/soap/classDefCreator.rbnu[# WSDL4R - Creating class definition from WSDL # Copyright (C) 2002, 2003, 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/data' require 'wsdl/soap/classDefCreatorSupport' require 'xsd/codegen' module WSDL module SOAP class ClassDefCreator include ClassDefCreatorSupport def initialize(definitions) @elements = definitions.collect_elements @simpletypes = definitions.collect_simpletypes @complextypes = definitions.collect_complextypes @faulttypes = nil if definitions.respond_to?(:collect_faulttypes) @faulttypes = definitions.collect_faulttypes end end def dump(type = nil) result = "require 'xsd/qname'\n" if type result = dump_classdef(type.name, type) else str = dump_element unless str.empty? result << "\n" unless result.empty? result << str end str = dump_complextype unless str.empty? result << "\n" unless result.empty? result << str end str = dump_simpletype unless str.empty? result << "\n" unless result.empty? result << str end end result end private def dump_element @elements.collect { |ele| if ele.local_complextype dump_classdef(ele.name, ele.local_complextype, ele.elementform == 'qualified') elsif ele.local_simpletype dump_simpletypedef(ele.name, ele.local_simpletype) else nil end }.compact.join("\n") end def dump_simpletype @simpletypes.collect { |type| dump_simpletypedef(type.name, type) }.compact.join("\n") end def dump_complextype @complextypes.collect { |type| case type.compoundtype when :TYPE_STRUCT, :TYPE_EMPTY dump_classdef(type.name, type) when :TYPE_ARRAY dump_arraydef(type) when :TYPE_SIMPLE dump_simpleclassdef(type) when :TYPE_MAP # mapped as a general Hash nil else raise RuntimeError.new( "unknown kind of complexContent: #{type.compoundtype}") end }.compact.join("\n") end def dump_simpletypedef(qname, simpletype) if !simpletype.restriction or simpletype.restriction.enumeration.empty? return nil end c = XSD::CodeGen::ModuleDef.new(create_class_name(qname)) c.comment = "#{qname}" const = {} simpletype.restriction.enumeration.each do |value| constname = safeconstname(value) const[constname] ||= 0 if (const[constname] += 1) > 1 constname += "_#{const[constname]}" end c.def_const(constname, ndq(value)) end c.dump end def dump_simpleclassdef(type_or_element) qname = type_or_element.name base = create_class_name(type_or_element.simplecontent.base) c = XSD::CodeGen::ClassDef.new(create_class_name(qname), base) c.comment = "#{qname}" c.dump end def dump_classdef(qname, typedef, qualified = false) if @faulttypes and @faulttypes.index(qname) c = XSD::CodeGen::ClassDef.new(create_class_name(qname), '::StandardError') else c = XSD::CodeGen::ClassDef.new(create_class_name(qname)) end c.comment = "#{qname}" c.def_classvar('schema_type', ndq(qname.name)) c.def_classvar('schema_ns', ndq(qname.namespace)) c.def_classvar('schema_qualified', dq('true')) if qualified schema_element = [] init_lines = '' params = [] typedef.each_element do |element| if element.type == XSD::AnyTypeName type = nil elsif klass = element_basetype(element) type = klass.name elsif element.type type = create_class_name(element.type) else type = nil # means anyType. # do we define a class for local complexType from it's name? # type = create_class_name(element.name) # # # # # end name = name_element(element).name attrname = safemethodname?(name) ? name : safemethodname(name) varname = safevarname(name) c.def_attr(attrname, true, varname) init_lines << "@#{varname} = #{varname}\n" if element.map_as_array? params << "#{varname} = []" type << '[]' if type else params << "#{varname} = nil" end # nil means @@schema_ns + varname eleqname = (varname == name && element.name.namespace == qname.namespace) ? nil : element.name schema_element << [varname, eleqname, type] end unless typedef.attributes.empty? define_attribute(c, typedef.attributes) init_lines << "@__xmlattr = {}\n" end c.def_classvar('schema_element', '[' + schema_element.collect { |varname, name, type| '[' + ( if name varname.dump + ', [' + ndq(type) + ', ' + dqname(name) + ']' else varname.dump + ', ' + ndq(type) end ) + ']' }.join(', ') + ']' ) c.def_method('initialize', *params) do init_lines end c.dump end def element_basetype(ele) if klass = basetype_class(ele.type) klass elsif ele.local_simpletype basetype_class(ele.local_simpletype.base) else nil end end def attribute_basetype(attr) if klass = basetype_class(attr.type) klass elsif attr.local_simpletype basetype_class(attr.local_simpletype.base) else nil end end def basetype_class(type) return nil if type.nil? if simpletype = @simpletypes[type] basetype_mapped_class(simpletype.base) else basetype_mapped_class(type) end end def define_attribute(c, attributes) schema_attribute = [] attributes.each do |attribute| name = name_attribute(attribute) if klass = attribute_basetype(attribute) type = klass.name else type = nil end methodname = safemethodname('xmlattr_' + name.name) c.def_method(methodname) do <<-__EOD__ (@__xmlattr ||= {})[#{dqname(name)}] __EOD__ end c.def_method(methodname + '=', 'value') do <<-__EOD__ (@__xmlattr ||= {})[#{dqname(name)}] = value __EOD__ end schema_attribute << [name, type] end c.def_classvar('schema_attribute', '{' + schema_attribute.collect { |name, type| dqname(name) + ' => ' + ndq(type) }.join(', ') + '}' ) end def name_element(element) return element.name if element.name return element.ref if element.ref raise RuntimeError.new("cannot define name of #{element}") end def name_attribute(attribute) return attribute.name if attribute.name return attribute.ref if attribute.ref raise RuntimeError.new("cannot define name of #{attribute}") end DEFAULT_ITEM_NAME = XSD::QName.new(nil, 'item') def dump_arraydef(complextype) qname = complextype.name c = XSD::CodeGen::ClassDef.new(create_class_name(qname), '::Array') c.comment = "#{qname}" child_type = complextype.child_type c.def_classvar('schema_type', ndq(child_type.name)) c.def_classvar('schema_ns', ndq(child_type.namespace)) child_element = complextype.find_aryelement schema_element = [] if child_type == XSD::AnyTypeName type = nil elsif child_element and (klass = element_basetype(child_element)) type = klass.name elsif child_type type = create_class_name(child_type) else type = nil end if child_element if child_element.map_as_array? type << '[]' if type end child_element_name = child_element.name else child_element_name = DEFAULT_ITEM_NAME end schema_element << [child_element_name.name, child_element_name, type] c.def_classvar('schema_element', '[' + schema_element.collect { |varname, name, type| '[' + ( if name varname.dump + ', [' + ndq(type) + ', ' + dqname(name) + ']' else varname.dump + ', ' + ndq(type) end ) + ']' }.join(', ') + ']' ) c.dump end end end end PK|]q wsdl/soap/header.rbnu[# WSDL4R - WSDL SOAP body definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Header < Info attr_reader :headerfault attr_reader :message # required attr_reader :part # required attr_reader :use # required attr_reader :encodingstyle attr_reader :namespace def initialize super @message = nil @part = nil @use = nil @encodingstyle = nil @namespace = nil @headerfault = nil end def targetnamespace parent.targetnamespace end def find_message root.message(@message) or raise RuntimeError.new("#{@message} not found") end def find_part find_message.parts.each do |part| if part.name == @part return part end end raise RuntimeError.new("#{@part} not found") end def parse_element(element) case element when HeaderFaultName o = WSDL::SOAP::HeaderFault.new @headerfault = o o else nil end end def parse_attr(attr, value) case attr when MessageAttrName if value.namespace.nil? value = XSD::QName.new(targetnamespace, value.source) end @message = value when PartAttrName @part = value.source when UseAttrName @use = value.source when EncodingStyleAttrName @encodingstyle = value.source when NamespaceAttrName @namespace = value.source else nil end end end end end PK|]^8 #wsdl/soap/classDefCreatorSupport.rbnu[# WSDL4R - Creating class code support from WSDL. # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'soap/mapping' require 'soap/mapping/typeMap' require 'xsd/codegen/gensupport' module WSDL module SOAP module ClassDefCreatorSupport include XSD::CodeGen::GenSupport def create_class_name(qname) if klass = basetype_mapped_class(qname) ::SOAP::Mapping::DefaultRegistry.find_mapped_obj_class(klass).name else safeconstname(qname.name) end end def basetype_mapped_class(name) ::SOAP::TypeMap[name] end def dump_method_signature(operation) name = operation.name.name input = operation.input output = operation.output fault = operation.fault signature = "#{ name }#{ dump_inputparam(input) }" str = <<__EOD__ # SYNOPSIS # #{name}#{dump_inputparam(input)} # # ARGS #{dump_inout_type(input).chomp} # # RETURNS #{dump_inout_type(output).chomp} # __EOD__ unless fault.empty? faultstr = (fault.collect { |f| dump_inout_type(f).chomp }).join(', ') str <<<<__EOD__ # RAISES # #{faultstr} # __EOD__ end str end def dq(ele) ele.dump end def ndq(ele) ele.nil? ? 'nil' : dq(ele) end def sym(ele) ':' + ele end def dqname(qname) qname.dump end private def dump_inout_type(param) if param message = param.find_message params = "" message.parts.each do |part| name = safevarname(part.name) if part.type typename = safeconstname(part.type.name) params << add_at("# #{name}", "#{typename} - #{part.type}\n", 20) elsif part.element typename = safeconstname(part.element.name) params << add_at("# #{name}", "#{typename} - #{part.element}\n", 20) end end unless params.empty? return params end end "# N/A\n" end def dump_inputparam(input) message = input.find_message params = "" message.parts.each do |part| params << ", " unless params.empty? params << safevarname(part.name) end if params.empty? "" else "(#{ params })" end end def add_at(base, str, pos) if base.size >= pos base + ' ' + str else base + ' ' * (pos - base.size) + str end end end end end PK|]8P#wsdl/soap/mappingRegistryCreator.rbnu[# WSDL4R - Creating MappingRegistry code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/classDefCreatorSupport' module WSDL module SOAP class MappingRegistryCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions @complextypes = @definitions.collect_complextypes @types = nil end def dump(types) @types = types map_cache = [] map = "" @types.each do |type| if map_cache.index(type).nil? map_cache << type if type.namespace != XSD::Namespace if typemap = dump_typemap(type) map << typemap end end end end return map end private def dump_typemap(type) if definedtype = @complextypes[type] case definedtype.compoundtype when :TYPE_STRUCT dump_struct_typemap(definedtype) when :TYPE_ARRAY dump_array_typemap(definedtype) when :TYPE_MAP, :TYPE_EMPTY nil else raise NotImplementedError.new("must not reach here") end end end def dump_struct_typemap(definedtype) ele = definedtype.name return <<__EOD__ MappingRegistry.set( #{create_class_name(ele)}, ::SOAP::SOAPStruct, ::SOAP::Mapping::Registry::TypedStructFactory, { :type => #{dqname(ele)} } ) __EOD__ end def dump_array_typemap(definedtype) ele = definedtype.name arytype = definedtype.find_arytype || XSD::AnyTypeName type = XSD::QName.new(arytype.namespace, arytype.name.sub(/\[(?:,)*\]$/, '')) @types << type return <<__EOD__ MappingRegistry.set( #{create_class_name(ele)}, ::SOAP::SOAPArray, ::SOAP::Mapping::Registry::TypedArrayFactory, { :type => #{dqname(type)} } ) __EOD__ end end end end PK|]u?D!wsdl/soap/clientSkeltonCreator.rbnu[# WSDL4R - Creating client skelton code from WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/classDefCreatorSupport' module WSDL module SOAP class ClientSkeltonCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(service_name) result = "" @definitions.service(service_name).ports.each do |port| result << dump_porttype(port.porttype.name) result << "\n" end result end private def dump_porttype(name) drv_name = create_class_name(name) result = "" result << <<__EOD__ endpoint_url = ARGV.shift obj = #{ drv_name }.new(endpoint_url) # run ruby with -d to see SOAP wiredumps. obj.wiredump_dev = STDERR if $DEBUG __EOD__ @definitions.porttype(name).operations.each do |operation| result << dump_method_signature(operation) result << dump_input_init(operation.input) << "\n" result << dump_operation(operation) << "\n\n" end result end def dump_operation(operation) name = operation.name input = operation.input "puts obj.#{ safemethodname(name.name) }#{ dump_inputparam(input) }" end def dump_input_init(input) result = input.find_message.parts.collect { |part| safevarname(part.name) }.join(" = ") if result.empty? "" else result << " = nil" end result end end end end PK|]7 (wsdl/soap/address.rbnu[# WSDL4R - WSDL SOAP address definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Address < Info attr_reader :location def initialize super @location = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when LocationAttrName @location = value.source else nil end end end end end PK|]X Lwsdl/soap/binding.rbnu[# WSDL4R - WSDL SOAP binding definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Binding < Info attr_reader :style attr_reader :transport def initialize super @style = nil @transport = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when StyleAttrName if ["document", "rpc"].include?(value.source) @style = value.source.intern else raise Parser::AttributeConstraintError.new( "Unexpected value #{ value }.") end when TransportAttrName @transport = value.source else nil end end end end end PK|]Q  wsdl/soap/data.rbnu[# WSDL4R - WSDL SOAP binding data definitions. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'xsd/qname' require 'wsdl/soap/definitions' require 'wsdl/soap/binding' require 'wsdl/soap/operation' require 'wsdl/soap/body' require 'wsdl/soap/element' require 'wsdl/soap/header' require 'wsdl/soap/headerfault' require 'wsdl/soap/fault' require 'wsdl/soap/address' require 'wsdl/soap/complexType' module WSDL module SOAP HeaderFaultName = XSD::QName.new(SOAPBindingNamespace, 'headerfault') LocationAttrName = XSD::QName.new(nil, 'location') StyleAttrName = XSD::QName.new(nil, 'style') TransportAttrName = XSD::QName.new(nil, 'transport') UseAttrName = XSD::QName.new(nil, 'use') PartsAttrName = XSD::QName.new(nil, 'parts') PartAttrName = XSD::QName.new(nil, 'part') NameAttrName = XSD::QName.new(nil, 'name') MessageAttrName = XSD::QName.new(nil, 'message') EncodingStyleAttrName = XSD::QName.new(nil, 'encodingStyle') NamespaceAttrName = XSD::QName.new(nil, 'namespace') SOAPActionAttrName = XSD::QName.new(nil, 'soapAction') end end PK|]RG wsdl/soap/operation.rbnu[# WSDL4R - WSDL SOAP operation definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Operation < Info class OperationInfo attr_reader :style attr_reader :op_name attr_reader :optype_name attr_reader :headerparts attr_reader :bodyparts attr_reader :faultpart attr_reader :soapaction def initialize(style, op_name, optype_name, headerparts, bodyparts, faultpart, soapaction) @style = style @op_name = op_name @optype_name = optype_name @headerparts = headerparts @bodyparts = bodyparts @faultpart = faultpart @soapaction = soapaction end end attr_reader :soapaction attr_reader :style def initialize super @soapaction = nil @style = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when StyleAttrName if ["document", "rpc"].include?(value.source) @style = value.source.intern else raise Parser::AttributeConstraintError.new( "Unexpected value #{ value }.") end when SOAPActionAttrName @soapaction = value.source else nil end end def input_info name_info = parent.find_operation.input_info param_info(name_info, parent.input) end def output_info name_info = parent.find_operation.output_info param_info(name_info, parent.output) end def operation_style return @style if @style if parent_binding.soapbinding return parent_binding.soapbinding.style end nil end private def parent_binding parent.parent end def param_info(name_info, param) op_name = name_info.op_name optype_name = name_info.optype_name soapheader = param.soapheader headerparts = soapheader.collect { |item| item.find_part } soapbody = param.soapbody if soapbody.encodingstyle and soapbody.encodingstyle != ::SOAP::EncodingNamespace raise NotImplementedError.new( "EncodingStyle '#{ soapbody.encodingstyle }' not supported.") end if soapbody.namespace op_name = XSD::QName.new(soapbody.namespace, op_name.name) end if soapbody.parts target = soapbody.parts.split(/\s+/) bodyparts = name_info.parts.find_all { |part| target.include?(part.name) } else bodyparts = name_info.parts end faultpart = nil OperationInfo.new(operation_style, op_name, optype_name, headerparts, bodyparts, faultpart, parent.soapaction) end end end end PK|]Z~~wsdl/soap/definitions.rbnu[# WSDL4R - WSDL additional definitions for SOAP. # Copyright (C) 2002-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'xsd/namedelements' require 'soap/mapping' module WSDL class Definitions < Info def self.soap_rpc_complextypes types = XSD::NamedElements.new types << array_complextype types << fault_complextype types << exception_complextype types end def self.array_complextype type = XMLSchema::ComplexType.new(::SOAP::ValueArrayName) type.complexcontent = XMLSchema::ComplexContent.new type.complexcontent.base = ::SOAP::ValueArrayName attr = XMLSchema::Attribute.new attr.ref = ::SOAP::AttrArrayTypeName anytype = XSD::AnyTypeName.dup anytype.name += '[]' attr.arytype = anytype type.complexcontent.attributes << attr type end =begin =end def self.fault_complextype type = XMLSchema::ComplexType.new(::SOAP::EleFaultName) faultcode = XMLSchema::Element.new(::SOAP::EleFaultCodeName, XSD::XSDQName::Type) faultstring = XMLSchema::Element.new(::SOAP::EleFaultStringName, XSD::XSDString::Type) faultactor = XMLSchema::Element.new(::SOAP::EleFaultActorName, XSD::XSDAnyURI::Type) faultactor.minoccurs = 0 detail = XMLSchema::Element.new(::SOAP::EleFaultDetailName, XSD::AnyTypeName) detail.minoccurs = 0 type.all_elements = [faultcode, faultstring, faultactor, detail] type.final = 'extension' type end def self.exception_complextype type = XMLSchema::ComplexType.new(XSD::QName.new( ::SOAP::Mapping::RubyCustomTypeNamespace, 'SOAPException')) excn_name = XMLSchema::Element.new(XSD::QName.new(nil, 'excn_type_name'), XSD::XSDString::Type) cause = XMLSchema::Element.new(XSD::QName.new(nil, 'cause'), XSD::AnyTypeName) backtrace = XMLSchema::Element.new(XSD::QName.new(nil, 'backtrace'), ::SOAP::ValueArrayName) message = XMLSchema::Element.new(XSD::QName.new(nil, 'message'), XSD::XSDString::Type) type.all_elements = [excn_name, cause, backtrace, message] type end def soap_rpc_complextypes(binding) types = rpc_operation_complextypes(binding) types + self.class.soap_rpc_complextypes end def collect_faulttypes result = [] collect_fault_messages.each do |name| faultparts = message(name).parts if faultparts.size != 1 raise RuntimeError.new("expecting fault message to have only 1 part") end if result.index(faultparts[0].type).nil? result << faultparts[0].type end end result end private def collect_fault_messages result = [] porttypes.each do |porttype| porttype.operations.each do |operation| operation.fault.each do |fault| if result.index(fault.message).nil? result << fault.message end end end end result end def rpc_operation_complextypes(binding) types = XSD::NamedElements.new binding.operations.each do |op_bind| if op_bind_rpc?(op_bind) operation = op_bind.find_operation if op_bind.input type = XMLSchema::ComplexType.new(op_bind.soapoperation_name) message = messages[operation.input.message] type.sequence_elements = elements_from_message(message) types << type end if op_bind.output type = XMLSchema::ComplexType.new(operation.outputname) message = messages[operation.output.message] type.sequence_elements = elements_from_message(message) types << type end end end types end def op_bind_rpc?(op_bind) op_bind.soapoperation_style == :rpc end def elements_from_message(message) message.parts.collect { |part| if part.element collect_elements[part.element] elsif part.name.nil? or part.type.nil? raise RuntimeError.new("part of a message must be an element or typed") else qname = XSD::QName.new(nil, part.name) XMLSchema::Element.new(qname, part.type) end } end end end PK|]#{((wsdl/soap/fault.rbnu[# WSDL4R - WSDL SOAP body definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Fault < Info attr_reader :name # required attr_reader :use # required attr_reader :encodingstyle attr_reader :namespace def initialize super @name = nil @use = nil @encodingstyle = nil @namespace = nil end def targetnamespace parent.targetnamespace end def parse_element(element) nil end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(targetnamespace, value.source) when UseAttrName @use = value.source when EncodingStyleAttrName @encodingstyle = value.source when NamespaceAttrName @namespace = value.source else nil end end end end end PK|]G (wsdl/soap/standaloneServerStubCreator.rbnu[# WSDL4R - Creating standalone server stub code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/mappingRegistryCreator' require 'wsdl/soap/methodDefCreator' require 'wsdl/soap/classDefCreatorSupport' module WSDL module SOAP class StandaloneServerStubCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(service_name) warn("- Standalone stub can have only 1 port for now. So creating stub for the first port and rests are ignored.") warn("- Standalone server stub ignores port location defined in WSDL. Location is http://localhost:10080/ by default. Generated client from WSDL must be configured to point this endpoint manually.") port = @definitions.service(service_name).ports[0] dump_porttype(port.porttype.name) end private def dump_porttype(name) class_name = create_class_name(name) methoddef, types = MethodDefCreator.new(@definitions).dump(name) mr_creator = MappingRegistryCreator.new(@definitions) c1 = XSD::CodeGen::ClassDef.new(class_name) c1.def_require("soap/rpc/standaloneServer") c1.def_require("soap/mapping/registry") c1.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new") c1.def_code(mr_creator.dump(types)) c1.def_code <<-EOD Methods = [ #{methoddef.gsub(/^/, " ")} ] EOD c2 = XSD::CodeGen::ClassDef.new(class_name + "App", "::SOAP::RPC::StandaloneServer") c2.def_method("initialize", "*arg") do <<-EOD super(*arg) servant = #{class_name}.new #{class_name}::Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document @router.add_document_operation(servant, *definitions) else @router.add_rpc_operation(servant, *definitions) end end self.mapping_registry = #{class_name}::MappingRegistry EOD end c1.dump + "\n" + c2.dump + format(<<-EOD) if $0 == __FILE__ # Change listen port. server = #{class_name}App.new('app', nil, '0.0.0.0', 10080) trap(:INT) do server.shutdown end server.start end EOD end end end end PK|]٢I"rrwsdl/soap/methodDefCreator.rbnu[# WSDL4R - Creating driver code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/classDefCreatorSupport' require 'soap/rpc/element' module WSDL module SOAP class MethodDefCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions @simpletypes = @definitions.collect_simpletypes @complextypes = @definitions.collect_complextypes @elements = @definitions.collect_elements @types = [] end def dump(porttype) @types.clear result = "" operations = @definitions.porttype(porttype).operations binding = @definitions.porttype_binding(porttype) operations.each do |operation| op_bind = binding.operations[operation.name] next unless op_bind # no binding is defined next unless op_bind.soapoperation # not a SOAP operation binding result << ",\n" unless result.empty? result << dump_method(operation, op_bind).chomp end return result, @types end def collect_rpcparameter(operation) result = operation.inputparts.collect { |part| collect_type(part.type) param_set(::SOAP::RPC::SOAPMethod::IN, part.name, rpcdefinedtype(part)) } outparts = operation.outputparts if outparts.size > 0 retval = outparts[0] collect_type(retval.type) result << param_set(::SOAP::RPC::SOAPMethod::RETVAL, retval.name, rpcdefinedtype(retval)) cdr(outparts).each { |part| collect_type(part.type) result << param_set(::SOAP::RPC::SOAPMethod::OUT, part.name, rpcdefinedtype(part)) } end result end def collect_documentparameter(operation) param = [] operation.inputparts.each do |input| param << param_set(::SOAP::RPC::SOAPMethod::IN, input.name, documentdefinedtype(input), elementqualified(input)) end operation.outputparts.each do |output| param << param_set(::SOAP::RPC::SOAPMethod::OUT, output.name, documentdefinedtype(output), elementqualified(output)) end param end private def dump_method(operation, binding) name = safemethodname(operation.name.name) name_as = operation.name.name style = binding.soapoperation_style inputuse = binding.input.soapbody_use outputuse = binding.output.soapbody_use namespace = binding.input.soapbody.namespace if style == :rpc qname = XSD::QName.new(namespace, name_as) paramstr = param2str(collect_rpcparameter(operation)) else qname = nil paramstr = param2str(collect_documentparameter(operation)) end if paramstr.empty? paramstr = '[]' else paramstr = "[ " << paramstr.split(/\r?\n/).join("\n ") << " ]" end definitions = <<__EOD__ #{ndq(binding.soapaction)}, #{dq(name)}, #{paramstr}, { :request_style => #{sym(style.id2name)}, :request_use => #{sym(inputuse.id2name)}, :response_style => #{sym(style.id2name)}, :response_use => #{sym(outputuse.id2name)} } __EOD__ if style == :rpc return <<__EOD__ [ #{qname.dump}, #{definitions}] __EOD__ else return <<__EOD__ [ #{definitions}] __EOD__ end end def rpcdefinedtype(part) if mapped = basetype_mapped_class(part.type) ['::' + mapped.name] elsif definedtype = @simpletypes[part.type] ['::' + basetype_mapped_class(definedtype.base).name] elsif definedtype = @elements[part.element] #['::SOAP::SOAPStruct', part.element.namespace, part.element.name] ['nil', part.element.namespace, part.element.name] elsif definedtype = @complextypes[part.type] case definedtype.compoundtype when :TYPE_STRUCT, :TYPE_EMPTY # ToDo: empty should be treated as void. type = create_class_name(part.type) [type, part.type.namespace, part.type.name] when :TYPE_MAP [Hash.name, part.type.namespace, part.type.name] when :TYPE_ARRAY arytype = definedtype.find_arytype || XSD::AnyTypeName ns = arytype.namespace name = arytype.name.sub(/\[(?:,)*\]$/, '') type = create_class_name(XSD::QName.new(ns, name)) [type + '[]', ns, name] else raise NotImplementedError.new("must not reach here") end else raise RuntimeError.new("part: #{part.name} cannot be resolved") end end def documentdefinedtype(part) if mapped = basetype_mapped_class(part.type) ['::' + mapped.name, nil, part.name] elsif definedtype = @simpletypes[part.type] ['::' + basetype_mapped_class(definedtype.base).name, nil, part.name] elsif definedtype = @elements[part.element] ['::SOAP::SOAPElement', part.element.namespace, part.element.name] elsif definedtype = @complextypes[part.type] ['::SOAP::SOAPElement', part.type.namespace, part.type.name] else raise RuntimeError.new("part: #{part.name} cannot be resolved") end end def elementqualified(part) if mapped = basetype_mapped_class(part.type) false elsif definedtype = @simpletypes[part.type] false elsif definedtype = @elements[part.element] definedtype.elementform == 'qualified' elsif definedtype = @complextypes[part.type] false else raise RuntimeError.new("part: #{part.name} cannot be resolved") end end def param_set(io_type, name, type, ele = nil) [io_type, name, type, ele] end def collect_type(type) # ignore inline type definition. return if type.nil? return if @types.include?(type) @types << type return unless @complextypes[type] @complextypes[type].each_element do |element| collect_type(element.type) end end def param2str(params) params.collect { |param| io, name, type, ele = param unless ele.nil? "[#{dq(io)}, #{dq(name)}, #{type2str(type)}, #{ele2str(ele)}]" else "[#{dq(io)}, #{dq(name)}, #{type2str(type)}]" end }.join(",\n") end def type2str(type) if type.size == 1 "[#{dq(type[0])}]" else "[#{dq(type[0])}, #{ndq(type[1])}, #{dq(type[2])}]" end end def ele2str(ele) qualified = ele if qualified "true" else "false" end end def cdr(ary) result = ary.dup result.shift result end end end end PK|]7K::wsdl/soap/headerfault.rbnu[# WSDL4R - WSDL SOAP body definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class HeaderFault < Info attr_reader :message # required attr_reader :part # required attr_reader :use # required attr_reader :encodingstyle attr_reader :namespace def initialize super @message = nil @part = nil @use = nil @encodingstyle = nil @namespace = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when MessageAttrName @message = value when PartAttrName @part = value.source when UseAttrName @use = value.source when EncodingStyleAttrName @encodingstyle = value.source when NamespaceAttrName @namespace = value.source else nil end end end end end PK|]6vqqwsdl/soap/wsdl2ruby.rbnu[# WSDL4R - WSDL to ruby mapping library. # Copyright (C) 2002-2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'logger' require 'xsd/qname' require 'wsdl/importer' require 'wsdl/soap/classDefCreator' require 'wsdl/soap/servantSkeltonCreator' require 'wsdl/soap/driverCreator' require 'wsdl/soap/clientSkeltonCreator' require 'wsdl/soap/standaloneServerStubCreator' require 'wsdl/soap/cgiStubCreator' module WSDL module SOAP class WSDL2Ruby attr_accessor :location attr_reader :opt attr_accessor :logger attr_accessor :basedir def run unless @location raise RuntimeError, "WSDL location not given" end @wsdl = import(@location) @name = @wsdl.name ? @wsdl.name.name : 'default' create_file end private def initialize @location = nil @opt = {} @logger = Logger.new(STDERR) @basedir = nil @wsdl = nil @name = nil end def create_file create_classdef if @opt.key?('classdef') create_servant_skelton(@opt['servant_skelton']) if @opt.key?('servant_skelton') create_cgi_stub(@opt['cgi_stub']) if @opt.key?('cgi_stub') create_standalone_server_stub(@opt['standalone_server_stub']) if @opt.key?('standalone_server_stub') create_driver(@opt['driver']) if @opt.key?('driver') create_client_skelton(@opt['client_skelton']) if @opt.key?('client_skelton') end def create_classdef @logger.info { "Creating class definition." } @classdef_filename = @name + '.rb' check_file(@classdef_filename) or return write_file(@classdef_filename) do |f| f << WSDL::SOAP::ClassDefCreator.new(@wsdl).dump end end def create_client_skelton(servicename) @logger.info { "Creating client skelton." } servicename ||= @wsdl.services[0].name.name @client_skelton_filename = servicename + 'Client.rb' check_file(@client_skelton_filename) or return write_file(@client_skelton_filename) do |f| f << shbang << "\n" f << "require '#{@driver_filename}'\n\n" if @driver_filename f << WSDL::SOAP::ClientSkeltonCreator.new(@wsdl).dump( create_name(servicename)) end end def create_servant_skelton(porttypename) @logger.info { "Creating servant skelton." } @servant_skelton_filename = (porttypename || @name + 'Servant') + '.rb' check_file(@servant_skelton_filename) or return write_file(@servant_skelton_filename) do |f| f << "require '#{@classdef_filename}'\n\n" if @classdef_filename f << WSDL::SOAP::ServantSkeltonCreator.new(@wsdl).dump( create_name(porttypename)) end end def create_cgi_stub(servicename) @logger.info { "Creating CGI stub." } servicename ||= @wsdl.services[0].name.name @cgi_stubFilename = servicename + '.cgi' check_file(@cgi_stubFilename) or return write_file(@cgi_stubFilename) do |f| f << shbang << "\n" if @servant_skelton_filename f << "require '#{@servant_skelton_filename}'\n\n" end f << WSDL::SOAP::CGIStubCreator.new(@wsdl).dump(create_name(servicename)) end end def create_standalone_server_stub(servicename) @logger.info { "Creating standalone stub." } servicename ||= @wsdl.services[0].name.name @standalone_server_stub_filename = servicename + '.rb' check_file(@standalone_server_stub_filename) or return write_file(@standalone_server_stub_filename) do |f| f << shbang << "\n" f << "require '#{@servant_skelton_filename}'\n\n" if @servant_skelton_filename f << WSDL::SOAP::StandaloneServerStubCreator.new(@wsdl).dump( create_name(servicename)) end end def create_driver(porttypename) @logger.info { "Creating driver." } @driver_filename = (porttypename || @name) + 'Driver.rb' check_file(@driver_filename) or return write_file(@driver_filename) do |f| f << "require '#{@classdef_filename}'\n\n" if @classdef_filename f << WSDL::SOAP::DriverCreator.new(@wsdl).dump( create_name(porttypename)) end end def write_file(filename) if @basedir filename = File.join(basedir, filename) end File.open(filename, "w") do |f| yield f end end def check_file(filename) if @basedir filename = File.join(basedir, filename) end if FileTest.exist?(filename) if @opt.key?('force') @logger.warn { "File '#{filename}' exists but overrides it." } true else @logger.warn { "File '#{filename}' exists. #{$0} did not override it." } false end else @logger.info { "Creates file '#{filename}'." } true end end def shbang "#!/usr/bin/env ruby" end def create_name(name) name ? XSD::QName.new(@wsdl.targetnamespace, name) : nil end def import(location) WSDL::Importer.import(location) end end end end PK|]P0Y"wsdl/soap/servantSkeltonCreator.rbnu[# WSDL4R - Creating servant skelton code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/classDefCreatorSupport' require 'xsd/codegen' module WSDL module SOAP class ServantSkeltonCreator include ClassDefCreatorSupport include XSD::CodeGen::GenSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(porttype = nil) if porttype.nil? result = "" @definitions.porttypes.each do |type| result << dump_porttype(type.name) result << "\n" end else result = dump_porttype(porttype) end result end private def dump_porttype(name) class_name = create_class_name(name) c = XSD::CodeGen::ClassDef.new(class_name) operations = @definitions.porttype(name).operations operations.each do |operation| name = safemethodname(operation.name.name) input = operation.input params = input.find_message.parts.collect { |part| safevarname(part.name) } m = XSD::CodeGen::MethodDef.new(name, params) do <<-EOD p [#{params.join(", ")}] raise NotImplementedError.new EOD end m.comment = dump_method_signature(operation) c.add_method(m) end c.dump end end end end PK|]&wsdl/soap/element.rbnu[# WSDL4R - XMLSchema element definition for WSDL. # Copyright (C) 2004 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/xmlSchema/element' module WSDL module XMLSchema class Element < Info def map_as_array? maxoccurs != '1' end def attributes @local_complextype.attributes end end end end PK|]R͛wsdl/soap/complexType.rbnu[# WSDL4R - SOAP complexType definition for WSDL. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/xmlSchema/complexType' require 'soap/mapping' module WSDL module XMLSchema class ComplexType < Info def compoundtype @compoundtype ||= check_type end def check_type if content if attributes.empty? and content.elements.size == 1 and content.elements[0].maxoccurs != '1' if name == ::SOAP::Mapping::MapQName :TYPE_MAP else :TYPE_ARRAY end else :TYPE_STRUCT end elsif complexcontent if complexcontent.base == ::SOAP::ValueArrayName :TYPE_ARRAY else complexcontent.basetype.check_type end elsif simplecontent :TYPE_SIMPLE elsif !attributes.empty? :TYPE_STRUCT else # empty complexType definition (seen in partner.wsdl of salesforce) :TYPE_EMPTY end end def child_type(name = nil) case compoundtype when :TYPE_STRUCT if ele = find_element(name) ele.type elsif ele = find_element_by_name(name.name) ele.type end when :TYPE_ARRAY @contenttype ||= content_arytype when :TYPE_MAP item_ele = find_element_by_name("item") or raise RuntimeError.new("'item' element not found in Map definition.") content = item_ele.local_complextype or raise RuntimeError.new("No complexType definition for 'item'.") if ele = content.find_element(name) ele.type elsif ele = content.find_element_by_name(name.name) ele.type end else raise NotImplementedError.new("Unknown kind of complexType.") end end def child_defined_complextype(name) ele = nil case compoundtype when :TYPE_STRUCT, :TYPE_MAP unless ele = find_element(name) if name.namespace.nil? ele = find_element_by_name(name.name) end end when :TYPE_ARRAY if content.elements.size == 1 ele = content.elements[0] else raise RuntimeError.new("Assert: must not reach.") end else raise RuntimeError.new("Assert: Not implemented.") end unless ele raise RuntimeError.new("Cannot find #{name} as a children of #{@name}.") end ele.local_complextype end def find_arytype unless compoundtype == :TYPE_ARRAY raise RuntimeError.new("Assert: not for array") end if complexcontent complexcontent.attributes.each do |attribute| if attribute.ref == ::SOAP::AttrArrayTypeName return attribute.arytype end end if check_array_content(complexcontent.content) return element_simpletype(complexcontent.content.elements[0]) end elsif check_array_content(content) return element_simpletype(content.elements[0]) end raise RuntimeError.new("Assert: Unknown array definition.") end def find_aryelement unless compoundtype == :TYPE_ARRAY raise RuntimeError.new("Assert: not for array") end if complexcontent if check_array_content(complexcontent.content) return complexcontent.content.elements[0] end elsif check_array_content(content) return content.elements[0] end nil # use default item name end private def element_simpletype(element) if element.type element.type elsif element.local_simpletype element.local_simpletype.base else nil end end def check_array_content(content) content and content.elements.size == 1 and content.elements[0].maxoccurs != '1' end def content_arytype if arytype = find_arytype ns = arytype.namespace name = arytype.name.sub(/\[(?:,)*\]$/, '') XSD::QName.new(ns, name) else nil end end end end end PK|]L!``wsdl/soap/cgiStubCreator.rbnu[# WSDL4R - Creating CGI stub code from WSDL. # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' require 'wsdl/soap/mappingRegistryCreator' require 'wsdl/soap/methodDefCreator' require 'wsdl/soap/classDefCreatorSupport' module WSDL module SOAP class CGIStubCreator include ClassDefCreatorSupport attr_reader :definitions def initialize(definitions) @definitions = definitions end def dump(service_name) warn("CGI stub can have only 1 port. Creating stub for the first port... Rests are ignored.") port = @definitions.service(service_name).ports[0] dump_porttype(port.porttype.name) end private def dump_porttype(name) class_name = create_class_name(name) methoddef, types = MethodDefCreator.new(@definitions).dump(name) mr_creator = MappingRegistryCreator.new(@definitions) c1 = XSD::CodeGen::ClassDef.new(class_name) c1.def_require("soap/rpc/cgistub") c1.def_require("soap/mapping/registry") c1.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new") c1.def_code(mr_creator.dump(types)) c1.def_code <<-EOD Methods = [ #{methoddef.gsub(/^/, " ")} ] EOD c2 = XSD::CodeGen::ClassDef.new(class_name + "App", "::SOAP::RPC::CGIStub") c2.def_method("initialize", "*arg") do <<-EOD super(*arg) servant = #{class_name}.new #{class_name}::Methods.each do |definitions| opt = definitions.last if opt[:request_style] == :document @router.add_document_operation(servant, *definitions) else @router.add_rpc_operation(servant, *definitions) end end self.mapping_registry = #{class_name}::MappingRegistry self.level = Logger::Severity::ERROR EOD end c1.dump + "\n" + c2.dump + format(<<-EOD) #{class_name}App.new('app', nil).start EOD end end end end PK|]#Phhwsdl/soap/body.rbnu[# WSDL4R - WSDL SOAP body definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL module SOAP class Body < Info attr_reader :parts attr_reader :use # required attr_reader :encodingstyle attr_reader :namespace def initialize super @parts = nil @use = nil @encodingstyle = nil @namespace = nil end def parse_element(element) nil end def parse_attr(attr, value) case attr when PartsAttrName @parts = value.source when UseAttrName if ['literal', 'encoded'].include?(value.source) @use = value.source.intern else raise RuntimeError.new("unknown use of soap:body: #{value.source}") end when EncodingStyleAttrName @encodingstyle = value.source when NamespaceAttrName @namespace = value.source else nil end end end end end PK|];pnwsdl/message.rbnu[# WSDL4R - WSDL message definition. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/info' module WSDL class Message < Info attr_reader :name # required attr_reader :parts def initialize super @name = nil @parts = [] end def targetnamespace parent.targetnamespace end def parse_element(element) case element when PartName o = Part.new @parts << o o when DocumentationName o = Documentation.new o else nil end end def parse_attr(attr, value) case attr when NameAttrName @name = XSD::QName.new(parent.targetnamespace, value.source) else nil end end end end PK|]^00 wsdl/info.rbnu[# WSDL4R - WSDL information base. # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. module WSDL class Info attr_accessor :root attr_accessor :parent attr_accessor :id def initialize @root = nil @parent = nil @id = nil end def inspect if self.respond_to?(:name) sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.name) else sprintf("#<%s:0x%x>", self.class.name, __id__) end end def parse_element(element); end # abstract def parse_attr(attr, value); end # abstract def parse_epilogue; end # abstract end end PK|]-qEnv.rbnu[# Env.rb -- imports environment variables as global variables, Perlish ;( # Usage: # # require 'Env' # p $USER # $USER = "matz" # p ENV["USER"] require 'importenv' if __FILE__ == $0 p $TERM $TERM = nil p $TERM p ENV["TERM"] $TERM = "foo" p ENV["TERM"] end PK|]?? openssl.rbnu[=begin = $RCSfile$ -- Loader for all OpenSSL C-space and Ruby-space definitions = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos All rights reserved. = Licence This program is licenced under the same licence as Ruby. (See the file 'LICENCE'.) = Version $Id: openssl.rb 29856 2010-11-22 07:21:45Z shyouhei $ =end require 'openssl.so' require 'openssl/bn' require 'openssl/cipher' require 'openssl/config' require 'openssl/digest' require 'openssl/pkcs7' require 'openssl/ssl-internal' require 'openssl/x509-internal' PK|]Esecurerandom.rbnu[# = Secure random number generator interface. # # This library is an interface for secure random number generator which is # suitable for generating session key in HTTP cookies, etc. # # It supports following secure random number generators. # # * openssl # * /dev/urandom # # == Example # # # random hexadecimal string. # p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362" # p SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559" # p SecureRandom.hex(11) #=> "6aca1b5c58e4863e6b81b8" # p SecureRandom.hex(12) #=> "94b2fff3e7fd9b9c391a2306" # p SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23" # ... # # # random base64 string. # p SecureRandom.base64(10) #=> "EcmTPZwWRAozdA==" # p SecureRandom.base64(10) #=> "9b0nsevdwNuM/w==" # p SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg==" # p SecureRandom.base64(11) #=> "l7XEiFja+8EKEtY=" # p SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8" # p SecureRandom.base64(13) #=> "vKLJ0tXBHqQOuIcSIg==" # ... # # # random binary string. # p SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301" # p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337" # ... begin require 'openssl' rescue LoadError end module SecureRandom # SecureRandom.random_bytes generates a random binary string. # # The argument n specifies the length of the result string. # # If n is not specified, 16 is assumed. # It may be larger in future. # # If secure random number generator is not available, # NotImplementedError is raised. def self.random_bytes(n=nil) n ||= 16 if defined? OpenSSL::Random @pid = 0 if !defined?(@pid) pid = $$ if @pid != pid now = Time.now ary = [now.to_i, now.usec, @pid, pid] OpenSSL::Random.seed(ary.join('.')) @pid = pid end return OpenSSL::Random.random_bytes(n) end if !defined?(@has_urandom) || @has_urandom @has_urandom = false flags = File::RDONLY flags |= File::NONBLOCK if defined? File::NONBLOCK flags |= File::NOCTTY if defined? File::NOCTTY flags |= File::NOFOLLOW if defined? File::NOFOLLOW begin File.open("/dev/urandom", flags) {|f| unless f.stat.chardev? raise Errno::ENOENT end @has_urandom = true ret = f.readpartial(n) if ret.length != n raise NotImplementedError, "Unexpected partial read from random device" end return ret } rescue Errno::ENOENT raise NotImplementedError, "No random device" end end raise NotImplementedError, "No random device" end # SecureRandom.hex generates a random hex string. # # The argument n specifies the length of the random length. # The length of the result string is twice of n. # # If n is not specified, 16 is assumed. # It may be larger in future. # # If secure random number generator is not available, # NotImplementedError is raised. def self.hex(n=nil) random_bytes(n).unpack("H*")[0] end # SecureRandom.base64 generates a random base64 string. # # The argument n specifies the length of the random length. # The length of the result string is about 4/3 of n. # # If n is not specified, 16 is assumed. # It may be larger in future. # # If secure random number generator is not available, # NotImplementedError is raised. def self.base64(n=nil) [random_bytes(n)].pack("m*").delete("\n") end # SecureRandom.random_number generates a random number. # # If an positive integer is given as n, # SecureRandom.random_number returns an integer: # 0 <= SecureRandom.random_number(n) < n. # # If 0 is given or an argument is not given, # SecureRandom.random_number returns an float: # 0.0 <= SecureRandom.random_number() < 1.0. def self.random_number(n=0) if 0 < n hex = n.to_s(16) hex = '0' + hex if (hex.length & 1) == 1 bin = [hex].pack("H*") mask = bin[0] mask |= mask >> 1 mask |= mask >> 2 mask |= mask >> 4 begin rnd = SecureRandom.random_bytes(bin.length) rnd[0] = (rnd[0] & mask).chr end until rnd < bin rnd.unpack("H*")[0].hex else # assumption: Float::MANT_DIG <= 64 i64 = SecureRandom.random_bytes(8).unpack("Q")[0] Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG) end end end PK|]ʜayy digest.rbnu[require 'digest.so' module Digest def self.const_missing(name) case name when :SHA256, :SHA384, :SHA512 lib = 'digest/sha2.so' else lib = File.join('digest', name.to_s.downcase) end begin require lib rescue LoadError => e raise LoadError, "library not found for class Digest::#{name} -- #{lib}", caller(1) end unless Digest.const_defined?(name) raise NameError, "uninitialized constant Digest::#{name}", caller(1) end Digest.const_get(name) end class ::Digest::Class # creates a digest object and reads a given file, _name_. # # p Digest::SHA256.file("X11R6.8.2-src.tar.bz2").hexdigest # # => "f02e3c85572dc9ad7cb77c2a638e3be24cc1b5bea9fdbb0b0299c9668475c534" def self.file(name) new.file(name) end end module Instance # updates the digest with the contents of a given file _name_ and # returns self. def file(name) File.open(name, "rb") {|f| buf = "" while f.read(16384, buf) update buf end } self end end end def Digest(name) Digest.const_get(name) end PK|]nII dl/win32.rbnu[# -*- ruby -*- require 'dl' class Win32API DLL = {} def initialize(dllname, func, import, export = "0") prototype = (export + import.to_s).tr("VPpNnLlIi", "0SSI").sub(/^(.)0*$/, '\1') handle = DLL[dllname] ||= DL::Handle.new(dllname) @sym = handle.sym(func, prototype) end def call(*args) import = @sym.proto.split("", 2)[1] args.each_with_index do |x, i| args[i] = nil if x == 0 and import[i] == ?S args[i], = [x].pack("I").unpack("i") if import[i] == ?I end ret, = @sym.call(*args) return ret || 0 end alias Call call end PK|]b dl/types.rbnu[# -*- ruby -*- require 'dl' module DL class Types TYPES = [ # FORMAT: # ["alias name", # "type name", encoding_method, decoding_method, for function prototypes # "type name", encoding_method, decoding_method] for structures (not implemented) # for Windows ["DWORD", "unsigned long", nil, nil, "unsigned long", nil, nil], ["PDWORD", "unsigned long *", nil, nil, "unsigned long *", nil, nil], ["WORD", "unsigned short", nil, nil, "unsigned short", nil, nil], ["PWORD", "unsigned int *", nil, nil, "unsigned int *", nil, nil], ["BYTE", "unsigned char", nil, nil, "unsigned char", nil, nil], ["PBYTE", "unsigned char *", nil, nil, "unsigned char *", nil, nil], ["BOOL", "ibool", nil, nil, "ibool", nil, nil], ["ATOM", "int", nil, nil, "int", nil, nil], ["BYTE", "unsigned char", nil, nil, "unsigned char", nil, nil], ["PBYTE", "unsigned char *", nil, nil, "unsigned char *", nil, nil], ["UINT", "unsigned int", nil, nil, "unsigned int", nil, nil], ["ULONG", "unsigned long", nil, nil, "unsigned long", nil, nil], ["UCHAR", "unsigned char", nil, nil, "unsigned char", nil, nil], ["HANDLE", "unsigned long", nil, nil, "unsigned long", nil, nil], ["PHANDLE","void*", nil, nil, "void*", nil, nil], ["PVOID", "void*", nil, nil, "void*", nil, nil], ["LPCSTR", "char*", nil, nil, "char*", nil, nil], ["HDC", "unsigned int", nil, nil, "unsigned int", nil, nil], ["HWND", "unsigned int", nil, nil, "unsigned int", nil, nil], # Others ["uint", "unsigned int", nil, nil, "unsigned int", nil, nil], ["u_int", "unsigned int", nil, nil, "unsigned int", nil, nil], ["ulong", "unsigned long", nil, nil, "unsigned long", nil, nil], ["u_long", "unsigned long", nil, nil, "unsigned long", nil, nil], # DL::Importable primitive types ["ibool", "I", proc{|v| v ? 1 : 0}, proc{|v| (v != 0) ? true : false}, "I", proc{|v| v ? 1 : 0 }, proc{|v| (v != 0) ? true : false} ], ["cbool", "C", proc{|v| v ? 1 : 0}, proc{|v| (v != 0) ? true : false}, "C", proc{|v,len| v ? 1 : 0}, proc{|v,len| (v != 0) ? true : false}], ["lbool", "L", proc{|v| v ? 1 : 0}, proc{|v| (v != 0) ? true : false}, "L", proc{|v,len| v ? 1 : 0}, proc{|v,len| (v != 0) ? true : false}], ["unsigned char", "C", proc{|v| [v].pack("C").unpack("c")[0]}, proc{|v| [v].pack("c").unpack("C")[0]}, "C", proc{|v| [v].pack("C").unpack("c")[0]}, proc{|v| [v].pack("c").unpack("C")[0]}], ["unsigned short", "H", proc{|v| [v].pack("S").unpack("s")[0]}, proc{|v| [v].pack("s").unpack("S")[0]}, "H", proc{|v| [v].pack("S").unpack("s")[0]}, proc{|v| [v].pack("s").unpack("S")[0]}], ["unsigned int", "I", proc{|v| [v].pack("I").unpack("i")[0]}, proc{|v| [v].pack("i").unpack("I")[0]}, "I", proc{|v| [v].pack("I").unpack("i")[0]}, proc{|v| [v].pack("i").unpack("I")[0]}], ["unsigned long", "L", proc{|v| [v].pack("L").unpack("l")[0]}, proc{|v| [v].pack("l").unpack("L")[0]}, "L", proc{|v| [v].pack("L").unpack("l")[0]}, proc{|v| [v].pack("l").unpack("L")[0]}], ["unsigned char ref", "c", proc{|v| [v].pack("C").unpack("c")[0]}, proc{|v| [v].pack("c").unpack("C")[0]}, nil, nil, nil], ["unsigned int ref", "i", proc{|v| [v].pack("I").unpack("i")[0]}, proc{|v| [v].pack("i").unpack("I")[0]}, nil, nil, nil], ["unsigned long ref", "l", proc{|v| [v].pack("L").unpack("l")[0]}, proc{|v| [v].pack("l").unpack("L")[0]}, nil, nil, nil], ["char ref", "c", nil, nil, nil, nil, nil], ["short ref", "h", nil, nil, nil, nil, nil], ["int ref", "i", nil, nil, nil, nil, nil], ["long ref", "l", nil, nil, nil, nil, nil], ["float ref", "f", nil, nil, nil, nil, nil], ["double ref","d", nil, nil, nil, nil, nil], ["char", "C", nil, nil, "C", nil, nil], ["short", "H", nil, nil, "H", nil, nil], ["int", "I", nil, nil, "I", nil, nil], ["long", "L", nil, nil, "L", nil, nil], ["float", "F", nil, nil, "F", nil, nil], ["double", "D", nil, nil, "D", nil, nil], [/^char\s*\*$/,"s",nil, nil, "S",nil, nil], [/^const char\s*\*$/,"S",nil, nil, "S",nil, nil], [/^.+\*$/, "P", nil, nil, "P", nil, nil], [/^.+\[\]$/, "a", nil, nil, "a", nil, nil], ["void", "0", nil, nil, nil, nil, nil], ] def initialize init_types() end def typealias(ty1, ty2, enc=nil, dec=nil, ty3=nil, senc=nil, sdec=nil) @TYDEFS.unshift([ty1, ty2, enc, dec, ty3, senc, sdec]) end def init_types @TYDEFS = TYPES.dup end def encode_argument_type(alias_type) proc_encode = nil proc_decode = nil @TYDEFS.each{|aty,ty,enc,dec,_,_,_| if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) ) alias_type = alias_type.gsub(aty,ty) if ty alias_type.strip! if alias_type if( proc_encode ) if( enc ) conv1 = proc_encode proc_encode = proc{|v| enc.call(conv1.call(v))} end else if( enc ) proc_encode = enc end end if( proc_decode ) if( dec ) conv2 = proc_decode proc_decode = proc{|v| dec.call(conv2.call(v))} end else if( dec ) proc_decode = dec end end end } return [alias_type, proc_encode, proc_decode] end def encode_return_type(ty) ty, enc, dec = encode_argument_type(ty) return [ty, enc, dec] end def encode_struct_type(alias_type) proc_encode = nil proc_decode = nil @TYDEFS.each{|aty,_,_,_,ty,enc,dec| if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) ) alias_type = alias_type.gsub(aty,ty) if ty alias_type.strip! if alias_type if( proc_encode ) if( enc ) conv1 = proc_encode proc_encode = proc{|v| enc.call(conv1.call(v))} end else if( enc ) proc_encode = enc end end if( proc_decode ) if( dec ) conv2 = proc_decode proc_decode = proc{|v| dec.call(conv2.call(v))} end else if( dec ) proc_decode = dec end end end } return [alias_type, proc_encode, proc_decode] end end # end of Types end PK|]Y'C dl/import.rbnu[# -*- ruby -*- require 'dl' require 'dl/types' module DL module Importable LIB_MAP = {} module Internal def init_types() @types ||= ::DL::Types.new end def init_sym() @SYM ||= {} end def [](name) return @SYM[name.to_s][0] end def dlload(*libnames) if( !defined?(@LIBS) ) @LIBS = [] end libnames.each{|libname| if( !LIB_MAP[libname] ) LIB_MAP[libname] = DL.dlopen(libname) end @LIBS.push(LIB_MAP[libname]) } end alias dllink :dlload def parse_cproto(proto) proto = proto.gsub(/\s+/, " ").strip case proto when /^([\d\w\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/ ret = $1 args = $2.strip() ret = ret.split(/\s+/) args = args.split(/\s*,\s*/) func = ret.pop() if( func =~ /^\*/ ) func.gsub!(/^\*+/,"") ret.push("*") end ret = ret.join(" ") return [func, ret, args] else raise(RuntimeError,"can't parse the function prototype: #{proto}") end end # example: # extern "int strlen(char*)" # def extern(proto) func,ret,args = parse_cproto(proto) return import(func, ret, args) end # example: # callback "int method_name(int, char*)" # def callback(proto) func,ret,args = parse_cproto(proto) init_types() init_sym() rty,renc,rdec = @types.encode_return_type(ret) if( !rty ) raise(TypeError, "unsupported type: #{ret}") end ty,enc,dec = encode_argument_types(args) symty = rty + ty module_eval("module_function :#{func}") sym = module_eval([ "DL::callback(\"#{symty}\"){|*args|", " sym,rdec,enc,dec = @SYM['#{func}']", " args = enc.call(args) if enc", " r,rs = #{func}(*args)", " r = renc.call(r) if rdec", " rs = dec.call(rs) if (dec && rs)", " @retval = r", " @args = rs", " r", "}", ].join("\n")) @SYM[func] = [sym,rdec,enc,dec] return sym end # example: # typealias("uint", "unsigned int") # def typealias(alias_type, ty1, enc1=nil, dec1=nil, ty2=nil, enc2=nil, dec2=nil) init_types() @types.typealias(alias_type, ty1, enc1, dec1, ty2||ty1, enc2, dec2) end # example: # symbol "foo_value" # symbol "foo_func", "IIP" # def symbol(name, ty = nil) sym = nil @LIBS.each{|lib| begin if( ty ) sym = lib[name, ty] else sym = lib[name] end rescue next end } if( !sym ) raise(RuntimeError, "can't find the symbol `#{name}'") end return sym end # example: # import("get_length", "int", ["void*", "int"]) # def import(name, rettype, argtypes = nil) init_types() init_sym() rty,_,rdec = @types.encode_return_type(rettype) if( !rty ) raise(TypeError, "unsupported type: #{rettype}") end ty,enc,dec = encode_argument_types(argtypes) symty = rty + ty sym = symbol(name, symty) mname = name.dup if( ?A <= mname[0] && mname[0] <= ?Z ) mname[0,1] = mname[0,1].downcase end @SYM[mname] = [sym,rdec,enc,dec] module_eval [ "def #{mname}(*args)", " sym,rdec,enc,dec = @SYM['#{mname}']", " args = enc.call(args) if enc", if( $DEBUG ) " p \"[DL] call #{mname} with \#{args.inspect}\"" else "" end, " r,rs = sym.call(*args)", if( $DEBUG ) " p \"[DL] retval=\#{r.inspect} args=\#{rs.inspect}\"" else "" end, " r = rdec.call(r) if rdec", " rs = dec.call(rs) if dec", " @retval = r", " @args = rs", " return r", "end", "module_function :#{mname}", ].join("\n") return sym end def _args_ return @args end def _retval_ return @retval end def encode_argument_types(tys) init_types() encty = [] enc = nil dec = nil tys.each_with_index{|ty,idx| ty,c1,c2 = @types.encode_argument_type(ty) if( !ty ) raise(TypeError, "unsupported type: #{ty}") end encty.push(ty) if( enc ) if( c1 ) conv1 = enc enc = proc{|v| v = conv1.call(v); v[idx] = c1.call(v[idx]); v} end else if( c1 ) enc = proc{|v| v[idx] = c1.call(v[idx]); v} end end if( dec ) if( c2 ) conv2 = dec dec = proc{|v| v = conv2.call(v); v[idx] = c2.call(v[idx]); v} end else if( c2 ) dec = proc{|v| v[idx] = c2.call(v[idx]); v} end end } return [encty.join, enc, dec] end end # end of Internal include Internal end # end of Importable end PK|]+  dl/struct.rbnu[# -*- ruby -*- require 'dl' require 'dl/import' module DL module Importable module Internal def define_struct(contents) init_types() Struct.new(@types, contents) end alias struct define_struct def define_union(contents) init_types() Union.new(@types, contents) end alias union define_union class Memory def initialize(ptr, names, ty, len, enc, dec) @ptr = ptr @names = names @ty = ty @len = len @enc = enc @dec = dec # define methods @names.each{|name| instance_eval [ "def #{name}", " v = @ptr[\"#{name}\"]", " if( @len[\"#{name}\"] )", " v = v.collect{|x| @dec[\"#{name}\"] ? @dec[\"#{name}\"].call(x) : x }", " else", " v = @dec[\"#{name}\"].call(v) if @dec[\"#{name}\"]", " end", " return v", "end", "def #{name}=(v)", " if( @len[\"#{name}\"] )", " v = v.collect{|x| @enc[\"#{name}\"] ? @enc[\"#{name}\"].call(x) : x }", " else", " v = @enc[\"#{name}\"].call(v) if @enc[\"#{name}\"]", " end", " @ptr[\"#{name}\"] = v", " return v", "end", ].join("\n") } end def to_ptr return @ptr end def size return @ptr.size end end class Struct def initialize(types, contents) @names = [] @ty = {} @len = {} @enc = {} @dec = {} @size = 0 @tys = "" @types = types parse(contents) end def size return @size end def members return @names end # ptr must be a PtrData object. def new(ptr) ptr.struct!(@tys, *@names) mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec) return mem end def malloc(size = nil) if( !size ) size = @size end ptr = DL::malloc(size) return new(ptr) end def parse(contents) contents.each{|elem| name,ty,num,enc,dec = parse_elem(elem) @names.push(name) @ty[name] = ty @len[name] = num @enc[name] = enc @dec[name] = dec if( num ) @tys += "#{ty}#{num}" else @tys += ty end } @size = DL.sizeof(@tys) end def parse_elem(elem) elem.strip! case elem when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)$/ ty = ($1 + $2).strip name = $3 num = nil; when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)\[(\d+)\]$/ ty = ($1 + $2).strip name = $3 num = $4.to_i else raise(RuntimeError, "invalid element: #{elem}") end ty,enc,dec = @types.encode_struct_type(ty) if( !ty ) raise(TypeError, "unsupported type: #{ty}") end return [name,ty,num,enc,dec] end end # class Struct class Union < Struct def new ptr = DL::malloc(@size) ptr.union!(@tys, *@names) mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec) return mem end end end # module Internal end # module Importable end # module DL PK|]Րkdrb.rbnu[require 'drb/drb' PK|]$+jirb.rbnu[PK|]\ rdoc/usage.rbnu[PK|]w4,, 2rdoc/markup/test/TestParse.rbnu[PK|]Z //#_rdoc/markup/test/AllTests.rbnu[PK|]=  _rdoc/markup/test/TestInline.rbnu[PK|]8aU~~$ trdoc/markup/simple_markup/to_flow.rbnu[PK|]sp--$ޅrdoc/markup/simple_markup/to_html.rbnu[PK|]Vڹ'_rdoc/markup/simple_markup/preprocess.rbnu[PK|]""#rdoc/markup/simple_markup/inline.rbnu[PK|])&rdoc/markup/simple_markup/fragments.rbnu[PK|]7^!!%5rdoc/markup/simple_markup/to_latex.rbnu[PK|]k " rdoc/markup/simple_markup/lines.rbnu[PK|]v??rdoc/markup/sample/sample.rbnu[PK|]^ zrdoc/markup/sample/rdoc2latex.rbnu[PK|]8TR8R8\rdoc/markup/simple_markup.rbnu[PK|]R|K a aUrdoc/parsers/parse_c.rbnu[PK|]T??Lrdoc/parsers/parse_rb.rbnu[PK|]8Ye\''Ӣrdoc/parsers/parse_simple.rbnu[PK|] kU Frdoc/parsers/parserfactory.rbnu[PK|]G%rdoc/parsers/parse_f95.rbnu[PK|]9O99[rdoc/ri/ri_formatter.rbnu[PK|] 4rdoc/ri/ri_descriptions.rbnu[PK|] 988Urdoc/ri/ri_cache.rbnu[PK|]`\lrdoc/ri/ri_display.rbnu[PK|]>ꞗ rdoc/ri/ri_paths.rbnu[PK|]O7urdoc/ri/ri_driver.rbnu[PK|] <*}/rdoc/ri/ri_reader.rbnu[PK|]|Qi"i"~8rdoc/ri/ri_options.rbnu[PK|]/,[rdoc/ri/ri_writer.rbnu[PK|]sbbuardoc/ri/ri_util.rbnu[PK|]%#H#Hjrdoc/code_objects.rbnu[PK|]Lف//rdoc/diagram.rbnu[PK|]@K{{brdoc/dot/dot.rbnu[PK|]%l@@rdoc/template.rbnu[PK|]!! rdoc/rdoc.rbnu[PK|]%`CC)s4rdoc/generators/template/html/old_html.rbnu[PK|]aV""&xrdoc/generators/template/html/hefss.rbnu[PK|](g%O#O#'śrdoc/generators/template/html/kilmer.rbnu[PK|]d8f?f?%krdoc/generators/template/html/html.rbnu[PK|].S͇.&rdoc/generators/template/html/one_page_html.rbnu[PK|]%6ww#(rdoc/generators/template/xml/xml.rbnu[PK|]Og  #rdoc/generators/template/xml/rdf.rbnu[PK|]#[rdoc/generators/template/chm/chm.rbnu[PK|]>4__ rdoc/generators/ri_generator.rbnu[PK|]&5L L I=rdoc/generators/chm_generator.rbnu[PK|]M)Męę!Hrdoc/generators/html_generator.rbnu[PK|]^.s  rdoc/generators/xml_generator.rbnu[PK|];gDDhrdoc/options.rbnu[PK|]%Ȅ2rdoc/tokenstream.rbnu[PK|]BDD 5thwait.rbnu[PK|]VCGmathn.rbnu[PK|];N-- \yaml/error.rbnu[PK|]7O O Rayaml/tag.rbnu[PK|]C00 myaml/ypath.rbnu[PK|] 8O4 Isyaml/dbm.rbnu[PK|]t~|yaml/yamlnode.rbnu[PK|]Uyy~yaml/baseemitter.rbnu[PK|]uo]]:yaml/encoding.rbnu[PK|]k"u((ךyaml/loader.rbnu[PK|]! =yaml/store.rbnu[PK|]]9yaml/constants.rbnu[PK|] yaml/syck.rbnu[PK|]3vgyaml/stream.rbnu[PK|]Rayaml/basenode.rbnu[PK|]b\1 yaml/types.rbnu[PK|]g\22Xyaml/rubytypes.rbnu[PK|]׏yaml/stringio.rbnu[PK|]uSɂ;; ugetoptlong.rbnu[PK|]a ? 4Kfileutils.rbnu[PK|]??Zpp.rbnu[PK|]z l4 openssl/bn.rbnu[PK|]837 openssl/ssl-internal.rbnu[PK|]` XJ openssl/cipher.rbnu[PK|])s9Q openssl/ssl.rbnu[PK|]  Q openssl/x509-internal.rbnu[PK|]0 ))b openssl/pkcs7.rbnu[PK|])sDe openssl/x509.rbnu[PK|]p3`e openssl/buffering.rbnu[PK|]E=LLt openssl/config.rbnu[PK|]=fH openssl/digest.rbnu[PK|] P tmpdir.rbnu[PK|]qc P finalize.rbnu[PK|]v%&&  e2mmap.rbnu[PK|]]&&k un.rbnu[PK|]G io/nonblock.rbnu[PK|]?JJJ  mutex_m.rbnu[PK|]+0    timeout.rbnu[PK|]8hh _ thread.rbnu[PK|]xCRR scanf.rbnu[PK|]ojVI md5.rbnu[PK|]'66K resolv-replace.rbnu[PK|]f*=ll R matrix.rbnu[PK|])oŝ x86_64-linux/dlconfig.hnu[PK|] (h@h@ x86_64-linux/pty.sonuȯPK|]g<## x86_64-linux/regex.hnu[PK|]Х x86_64-linux/nkf.sonuȯPK|])/6x86_64-linux/util.hnu[PK|]..<x86_64-linux/io/wait.sonuȯPK|]a7`bbkx86_64-linux/gdbm.sonuȯPK|]L@@x86_64-linux/syslog.sonuȯPK|]ʏx86_64-linux/re.hnu[PK|]|qq x86_64-linux/stringio.sonuȯPK|]`<,,1x86_64-linux/version.hnu[PK|]Kaax86_64-linux/readline.sonuȯPK|]uRx86_64-linux/fcntl.sonuȯPK|]@@ x86_64-linux/etc.sonuȯPK|]39 SIx86_64-linux/missing.hnu[PK|]ߖ P P{Tx86_64-linux/racc/cparse.sonuȯPK|]kkP8WWx86_64-linux/ruby.hnu[PK|]}= x86_64-linux/zlib.sonuȯPK|]qA8a8aβx86_64-linux/dbm.sonuȯPK|]f""Ix86_64-linux/rbconfig.rbnu[PK|]N 7x86_64-linux/digest/sha1.sonuȯPK|]v AAbXx86_64-linux/digest/sha2.sonuȯPK|]7Ǡ ex86_64-linux/digest/md5.sonuȯPK|]pC Ox86_64-linux/digest/rmd160.sonuȯPK|];..#<x86_64-linux/digest/bubblebabble.sonuȯPK|]: r rw x86_64-linux/sdbm.sonuȯPK|]!""}x86_64-linux/dl.hnu[PK|]O   x86_64-linux/dln.hnu[PK|]Q)33$x86_64-linux/node.hnu[PK|]xJHMHMx86_64-linux/intern.hnu[PK|]MVpPP%x86_64-linux/st.hnu[PK|].v>J J -x86_64-linux/rubysig.hnu[PK|]wAC8x86_64-linux/curses.sonuȯPK|]$ūx86_64-linux/defines.hnu[PK|]2x86_64-linux/syck.sonuȯPK|]mɐ x86_64-linux/bigdecimal.sonuȯPK|]˚bbx86_64-linux/strscan.sonuȯPK|]ʈxx-Jx86_64-linux/env.hnu[PK|]kBQQNx86_64-linux/thread.sonuȯPK|]M3e@@Šx86_64-linux/digest.sonuȯPK|]Xx86_64-linux/socket.sonuȯPK|]  x86_64-linux/openssl.sonuȯPK|] %0Q0Q(x86_64-linux/iconv.sonuȯPK|]VEB{{x86_64-linux/digest.hnu[PK|]ve]x86_64-linux/dl.sonuȯPK|]{!x86_64-linux/config.hnu[PK|]M{ !x86_64-linux/rubyio.hnu[PK|]rFO O ǜ!singleton.rbnu[PK|]x6&OSS R!resolv.rbnu[PK|]usKK ޠ"rss/atom.rbnu[PK|]%I{"rss/dublincore.rbnu[PK|] "rss/xml-stylesheet.rbnu[PK|]/H#rss/content.rbnu[PK|]Y%%  #rss/0.9.rbnu[PK|]Ye 0#rss/xml.rbnu[PK|]T6#rss/dublincore/atom.rbnu[PK|]G//y7#rss/dublincore/1.0.rbnu[PK|]]S8#rss/dublincore/2.0.rbnu[PK|]*>>::  :#rss/parser.rbnu[PK|](||t#rss/xmlscanner.rbnu[PK|]LN{ { }#rss/utils.rbnu[PK|]o T#rss/slash.rbnu[PK|]Vq@@ m#rss/rss.rbnu[PK|]J"u"u" $rss/1.0.rbnu[PK|]DG`4$rss/maker/atom.rbnu[PK|]-cF$rss/maker/dublincore.rbnu[PK|]ëV$rss/maker/content.rbnu[PK|])j,,X$rss/maker/0.9.rbnu[PK|]$rss/maker/slash.rbnu[PK|]Fv((ʈ$rss/maker/1.0.rbnu[PK|]ц22!$rss/maker/feed.rbnu[PK|]ئf f $rss/maker/image.rbnu[PK|]g  $rss/maker/itunes.rbnu[PK|]tPP %rss/maker/trackback.rbnu[PK|]r]]t%rss/maker/syndication.rbnu[PK|]}Z[[%rss/maker/base.rbnu[PK|]_ p%rss/maker/taxonomy.rbnu[PK|]ƾ}%rss/maker/entry.rbnu[PK|]*:e  %rss/maker/2.0.rbnu[PK|] # 3%rss/maker.rbnu[PK|];}Pxx )%rss/image.rbnu[PK|]9'' ݾ%rss/itunes.rbnu[PK|]vEJJ%rss/xmlparser.rbnu[PK|]V v%rss/trackback.rbnu[PK|]#  g&rss/syndication.rbnu[PK|]P&rss/converter.rbnu[PK|]&@  &rss/taxonomy.rbnu[PK|] /+&rss/content/1.0.rbnu[PK|]?y,&rss/content/2.0.rbnu[PK|]>sqq-&rss/rexmlparser.rbnu[PK|]$@ @ 1&rss/2.0.rbnu[PK|]_B;&shell/error.rbnu[PK|]DN_::>&shell/version.rbnu[PK|]n n {?&shell/system-command.rbnu[PK|]Z>!0M&shell/filter.rbnu[PK|]Ro JT&shell/builtin-command.rbnu[PK|]Pʷ;;i^&shell/command-processor.rbnu[PK|]iij&shell/process-controller.rbnu[PK|]=RnpRpR&debug.rbnu[PK|][k k 'ostruct.rbnu[PK|]?߅k'optparse/version.rbnu[PK|]7&'optparse/time.rbnu[PK|][hzdd'optparse/uri.rbnu[PK|];EE='optparse/date.rbnu[PK|]Zvvyy'optparse/shellwords.rbnu[PK|]}y4 'tracer.rbnu[PK|]܃t3030 &'rational.rbnu[PK|]zn@ ??W'rinda/rinda.rbnu[PK|]гJ77n'rinda/tuplespace.rbnu[PK|]88 x'rinda/ring.rbnu[PK|]C 'eregex.rbnu[PK|]>,,  'pstore.rbnu[PK|]1P77 'parsearg.rbnu[PK|]u--Q'racc/parser.rbnu[PK|]y|8XXa!(find.rbnu[PK|]?rK[[ ((profiler.rbnu[PK|] 1w/(rss.rbnu[PK|]  1(monitor.rbnu[PK|]ln[3[3 Q(complex.rbnu[PK|]3);#;# 7(delegate.rbnu[PK|]"HZZ (profile.rbnu[PK|]OA(mkmf.rbnu[PK|]H&t)xsd/codegen.rbnu[PK|]@{ژv)xsd/namedelements.rbnu[PK|]w^^{)xsd/codegen/commentdef.rbnu[PK|]Sb4;~)xsd/codegen/moduledef.rbnu[PK|]Y Y y)xsd/codegen/gensupport.rbnu[PK|]uD<)xsd/codegen/methoddef.rbnu[PK|]b ))0)xsd/codegen/classdef.rbnu[PK|])xsd/mapping.rbnu[PK|]'t``)xsd/datatypes.rbnu[PK|]);T__*xsd/xmlparser/parser.rbnu[PK|]8v  *xsd/xmlparser/xmlscanner.rbnu[PK|]Vnn'*xsd/xmlparser/xmlparser.rbnu[PK|]hGG,*xsd/xmlparser/rexmlparser.rbnu[PK|]OG1*xsd/charset.rbnu[PK|]o]:F*xsd/xmlparser.rbnu[PK|]h GK*xsd/qname.rbnu[PK|]E+GQ*xsd/iconvcharset.rbnu[PK|]r CT*xsd/ns.rbnu[PK|]LYP_*xsd/datatypes1999.rbnu[PK|]N7NlNl3b*set.rbnu[PK|]:*digest/sha2.rbnu[PK|]/+rRFF *benchmark.rbnu[PK|] & yy +expect.rbnu[PK|]_QQ +open-uri.rbnu[PK|]8Fc  p+getopts.rbnu[PK|]XZFZF y+logger.rbnu[PK|]y3 3 +test/unit/util/observable.rbnu[PK|]}hUU+test/unit/util/procwrapper.rbnu[PK|]!+test/unit/util/backtracefilter.rbnu[PK|]ݮ?3G3G +test/unit/assertions.rbnu[PK|]K4,test/unit/testresult.rbnu[PK|]%,test/unit/error.rbnu[PK|]Fӥ+,test/unit/testsuite.rbnu[PK|]x3,test/unit/testcase.rbnu[PK|]aAmVVE,test/unit/autorunner.rbnu[PK|]=!n n m`,test/unit/collector/dir.rbnu[PK|]++"%m,test/unit/collector/objectspace.rbnu[PK|] J))!p,test/unit/assertionfailederror.rbnu[PK|]&&r,test/unit/failure.rbnu[PK|]\~!~!w,test/unit/ui/fox/testrunner.rbnu[PK|]2>>R,test/unit/ui/gtk2/testrunner.rbnu[PK|]`Dc"c"[,test/unit/ui/tk/testrunner.rbnu[PK|]K# ,test/unit/ui/testrunnerutilities.rbnu[PK|]9977,test/unit/ui/gtk/testrunner.rbnu[PK|]o/"7-test/unit/ui/console/testrunner.rbnu[PK|] 000"F-test/unit/ui/testrunnermediator.rbnu[PK|]2Vii O-test/unit/collector.rbnu[PK|]$q+q+ R-test/unit.rbnu[PK|]-!~aa|~-csv.rbnu[PK|]P EEE-cgi/session.rbnu[PK|]T#p4 4 %.cgi/session/pstore.rbnu[PK|]^f%++ P2.webrick.rbnu[PK|]/7lOO 5.parsedate.rbnu[PK|]}@;.date2.rbnu[PK|]8 ;.observer.rbnu[PK|]}ޢf f P.generator.rbnu[PK|]̛&&sq.cgi.rbnu[PK|]OGR~R~/time.rbnu[PK|]{7NN %0importenv.rbnu[PK|]U0sha1.rbnu[PK|]>O10uri.rbnu[PK|]ܽ0date.rbnu[PK|]ԌI  0kconv.rbnu[PK|]"g001jcode.rbnu[PK|]g## $1mailread.rbnu[PK|]Q Q*1rubyunit.rbnu[PK|]_&ݧ@+1forwardable.rbnu[PK|]Iُُ %D1net/imap.rbnu[PK|]ҝff 92net/pop.rbnu[PK|]e;V;V `;3net/ftp.rbnu[PK|]^/Yapp Ց3net/smtp.rbnu[PK|]C~~ 4net/telnet.rbnu[PK|]f 4net/http.rbnu[PK|]@ @5net/ftptls.rbnu[PK|]/;  [5net/https.rbnu[PK|]w;`5net/protocol.rbnu[PK|]QCC5net/telnets.rbnu[PK|]8`XX 5sync.rbnu[PK|]{aCC 5readbytes.rbnu[PK|]р 5ftools.rbnu[PK|]G,rr  6tempfile.rbnu[PK|]!{ { 6base64.rbnu[PK|]|| a,6optparse.rbnu[PK|]KC̼ 6weakref.rbnu[PK|]6tsort.rbnu[PK|]N>el1l1?7yaml.rbnu[PK|]P-wuu E7pathname.rbnu[PK|]rO7webrick/server.rbnu[PK|]~7webrick/httpproxy.rbnu[PK|]DgQ, , "7webrick/utils.rbnu[PK|]!G7webrick/httpserver.rbnu[PK|]W''Z8webrick/httputils.rbnu[PK|] t8y88webrick/ssl.rbnu[PK|]O-I8webrick/accesslog.rbnu[PK|]VLR8webrick/httpauth/userdb.rbnu[PK|]wwU8webrick/httpauth/htdigest.rbnu[PK|]U؝m^8webrick/httpauth/htpasswd.rbnu[PK|]x{,,f8webrick/httpauth/digestauth.rbnu[PK|]9 E E !8webrick/httpauth/authenticator.rbnu[PK|]^8webrick/httpauth/basicauth.rbnu[PK|][ؤ8webrick/httpauth/htgroup.rbnu[PK|]-G__Ū8webrick/version.rbnu[PK|]F! ! f8webrick/cookie.rbnu[PK|]بj##ȸ8webrick/log.rbnu[PK|]2)8webrick/httpresponse.rbnu[PK|]buM''H8webrick/httprequest.rbnu[PK|]ɒQ== 9webrick/httpauth.rbnu[PK|]ͩ9webrick/cgi.rbnu[PK|]{L  *9webrick/httpstatus.rbnu[PK|]6f|u:99webrick/compat.rbnu[PK|]/ݔvv/;9webrick/httpversion.rbnu[PK|] _?9webrick/https.rbnu[PK|] n>F9webrick/httpservlet.rbnu[PK|]8iɚ!I9webrick/httpservlet/erbhandler.rbnu[PK|]-!!O9webrick/httpservlet/cgi_runner.rbnu[PK|]XgV  !S9webrick/httpservlet/cgihandler.rbnu[PK|]'66""a9webrick/httpservlet/filehandler.rbnu[PK|]`T9webrick/httpservlet/abstract.rbnu[PK|]Bh"9webrick/httpservlet/prochandler.rbnu[PK|]`>HH9webrick/htmlutils.rbnu[PK|]=%w 99webrick/config.rbnu[PK|]UWIWI9prettyprint.rbnu[PK|]Fb9shell.rbnu[PK|]Vp:irb/context.rbnu[PK|]&FF &:irb/help.rbnu[PK|]nX>):irb/lc/error.rbnu[PK|]*O..-:irb/lc/ja/error.rbnu[PK|]1:irb/lc/ja/help-messagenu[PK|].._8:irb/lc/help-messagenu[PK|](_;;=:irb/input-method.rbnu[PK|]cqqNE:irb/ext/math-mode.rbnu[PK|]> H:irb/ext/tracer.rbnu[PK|]  L:irb/ext/loader.rbnu[PK|]G.V:irb/ext/change-ws.rbnu[PK|]Jxx[:irb/ext/save-history.rbnu[PK|]+c:irb/ext/multi-irb.rbnu[PK|]I|SSw:irb/ext/use-loader.rbnu[PK|]|:irb/ext/workspaces.rbnu[PK|]|Ӑ~yy:irb/ext/history.rbnu[PK|]DmUUq:irb/ruby-lex.rbnu[PK|]6| | 7:irb/locale.rbnu[PK|]SWW :irb/init.rbnu[PK|]L MM;irb/cmd/help.rbnu[PK|]ิ;irb/cmd/load.rbnu[PK|]oo ;irb/cmd/fork.rbnu[PK|]k=  ;irb/cmd/chws.rbnu[PK|]r)XX;irb/cmd/nop.rbnu[PK|]E1;irb/cmd/pushws.rbnu[PK|]$b W;irb/cmd/subirb.rbnu[PK|]. *;irb/xmp.rbnu[PK|]\·Q;irb/ruby-token.rbnu[PK|]z//I=;irb/version.rbnu[PK|]shh>;irb/completion.rbnu[PK|]L(EE _R;irb/slex.rbnu[PK|]S0 0 j;irb/workspace.rbnu[PK|]B Ou;irb/frame.rbnu[PK|]~Wz;irb/extend-command.rbnu[PK|]1Ix;irb/ws-for-case-2.rbnu[PK|]--;irb/output-method.rbnu[PK|]fC U /;irb/notifier.rbnu[PK|]4q G;shellwords.rbnu[PK|]_ttz;xmlrpc/datetime.rbnu[PK|]JJ0;xmlrpc/client.rbnu[PK|]K;%HWHWB<xmlrpc/server.rbnu[PK|]XWHHk<xmlrpc/parser.rbnu[PK|]`% <xmlrpc/utils.rbnu[PK|]s<xmlrpc/httpserver.rbnu[PK|]` <xmlrpc/create.rbnu[PK|]j?;;<xmlrpc/marshal.rbnu[PK|] <xmlrpc/base64.rbnu[PK|]$<xmlrpc/config.rbnu[PK|]<ping.rbnu[PK|]5# =uri/mailto.rbnu[PK|]͇MX^X^L=uri/generic.rbnu[PK|]OKi  {=uri/ldap.rbnu[PK|]? +=uri/ldaps.rbnu[PK|]UT =uri/ftp.rbnu[PK|]/[DD C=uri/common.rbnu[PK|](p0Z Z  =uri/http.rbnu[PK|]U =uri/https.rbnu[PK|]a WW =ipaddr.rbnu[PK|]zUUH>erb.rbnu[PK|]0mrr>date/format.rbnu[PK|]V  ?cgi-lib.rbnu[PK|]"a  ,?abbrev.rbnu[PK|]3dd 6?English.rbnu[PK|]H~qddM?open3.rbnu[PK|]990V?rexml/source.rbnu[PK|]Lr?rexml/rexml.rbnu[PK|]Fykky?rexml/dtd/dtd.rbnu[PK|]kZ*j~?rexml/dtd/entitydecl.rbnu[PK|]oa}?rexml/dtd/notationdecl.rbnu[PK|] _}?rexml/dtd/elementdecl.rbnu[PK|]|昶F?rexml/dtd/attlistdecl.rbnu[PK|]z  D?rexml/sax2listener.rbnu[PK|]#&R?rexml/parseexception.rbnu[PK|]) i?rexml/node.rbnu[PK|]ھa?rexml/syncenumerator.rbnu[PK|]`$y?rexml/undefinednamespaceexception.rbnu[PK|]$돇?rexml/light/node.rbnu[PK|];ŝi?rexml/quickpath.rbnu[PK|](:2 H?rexml/xmldecl.rbnu[PK|]:i ?rexml/comment.rbnu[PK|] \?rexml/attribute.rbnu[PK|] \ @rexml/xpath.rbnu[PK|](;8{ @rexml/encodings/UTF-16.rbnu[PK|]3#  @rexml/encodings/UTF-8.rbnu[PK|]&@rexml/encodings/ISO-8859-1.rbnu[PK|](FSS'@rexml/encodings/EUC-JP.rbnu[PK|]*,*@rexml/encodings/UNILE.rbnu[PK|])*^-@rexml/encodings/ICONV.rbnu[PK|]F m  W/@rexml/encodings/ISO-8859-15.rbnu[PK|]S ŕ8@rexml/parent.rbnu[PK|]|J@rexml/parsers/sax2parser.rbnu[PK|]UHJJh@rexml/parsers/baseparser.rbnu[PK|]O"gg@rexml/parsers/lightparser.rbnu[PK|]^=O@rexml/parsers/streamparser.rbnu[PK|]廋z z /@rexml/parsers/treeparser.rbnu[PK|]@H!@rexml/parsers/ultralightparser.rbnu[PK|]LL@rexml/parsers/xpathparser.rbnu[PK|]lWW=Arexml/parsers/pullparser.rbnu[PK|]{{SS3Arexml/encoding.rbnu[PK|]xs@ //Grunit/assert.rbnu[PK|]"Gdrb/timeridconv.rbnu[PK|]>2gg8Gdrb/extservm.rbnu[PK|]j Gdrb/gw.rbnu[PK|]$УS S Gdrb/acl.rbnu[PK|]5s )Hdrb/ssl.rbnu[PK|]M} Hdrb/unix.rbnu[PK|]pgVqq!Hdrb/observer.rbnu[PK|]+6{99#Hdrb/extserv.rbnu[PK|]vg'F(Hdrb/invokemethod.rbnu[PK|]܉̕ ]+Hdrb/eq.rbnu[PK|]WJ ,Hdrb/drb.rbnu[PK|] Hwsdl/parser.rbnu[PK|] _WAAi Iwsdl/documentation.rbnu[PK|]BIwsdl/binding.rbnu[PK|]f   Iwsdl/wsdl.rbnu[PK|]U%OIwsdl/xmlSchema/enumeration.rbnu[PK|]]]!Iwsdl/xmlSchema/content.rbnu[PK|].O Iwsdl/xmlSchema/parser.rbnu[PK|]HH0Iwsdl/xmlSchema/unique.rbnu[PK|] 6%F3Iwsdl/xmlSchema/sequence.rbnu[PK|]  ,8Iwsdl/xmlSchema/attribute.rbnu[PK|]LBIwsdl/xmlSchema/include.rbnu[PK|]֩DFIwsdl/xmlSchema/pattern.rbnu[PK|]#~~IIwsdl/xmlSchema/simpleType.rbnu[PK|]8n`OIwsdl/xmlSchema/simpleContent.rbnu[PK|] t  DTIwsdl/xmlSchema/data.rbnu[PK|]Iƽ&ee aIwsdl/xmlSchema/complexContent.rbnu[PK|]@AiIwsdl/xmlSchema/importer.rbnu[PK|]Z TTCrIwsdl/xmlSchema/xsd2ruby.rbnu[PK|]Σu/zIwsdl/xmlSchema/all.rbnu[PK|]pIwsdl/xmlSchema/import.rbnu[PK|]TS  Iwsdl/xmlSchema/schema.rbnu[PK|]@@Iwsdl/xmlSchema/any.rbnu[PK|]#*{A A Iwsdl/xmlSchema/element.rbnu[PK|]#"Iwsdl/xmlSchema/simpleRestriction.rbnu[PK|]#HIwsdl/xmlSchema/choice.rbnu[PK|](RR*Iwsdl/xmlSchema/length.rbnu[PK|]fU ıIwsdl/xmlSchema/complexType.rbnu[PK|]=t!Iwsdl/xmlSchema/simpleExtension.rbnu[PK|]rYYIwsdl/xmlSchema/annotation.rbnu[PK|]>w@1 1 VIwsdl/data.rbnu[PK|]y5 5 Iwsdl/operation.rbnu[PK|]J;9Iwsdl/definitions.rbnu[PK|]UIlaaOIwsdl/service.rbnu[PK|])J Iwsdl/param.rbnu[PK|]4Iwsdl/operationBinding.rbnu[PK|]}@99Jwsdl/importer.rbnu[PK|]׎1 WJwsdl/part.rbnu[PK|] [ /Jwsdl/types.rbnu[PK|],;D Jwsdl/portType.rbnu[PK|]˃ʱJwsdl/import.rbnu[PK|]^Dff Jwsdl/port.rbnu[PK|]Xd Jwsdl/soap/driverCreator.rbnu[PK|]S!S!(Jwsdl/soap/classDefCreator.rbnu[PK|]q JJwsdl/soap/header.rbnu[PK|]^8 #eQJwsdl/soap/classDefCreatorSupport.rbnu[PK|]8P#[Jwsdl/soap/mappingRegistryCreator.rbnu[PK|]u?D!cJwsdl/soap/clientSkeltonCreator.rbnu[PK|]7 (jJwsdl/soap/address.rbnu[PK|]X LmJwsdl/soap/binding.rbnu[PK|]Q  qJwsdl/soap/data.rbnu[PK|]RG vJwsdl/soap/operation.rbnu[PK|]Z~~ Jwsdl/soap/definitions.rbnu[PK|]#{((ѓJwsdl/soap/fault.rbnu[PK|]G (;Jwsdl/soap/standaloneServerStubCreator.rbnu[PK|]٢I"rr~Jwsdl/soap/methodDefCreator.rbnu[PK|]7K::=Jwsdl/soap/headerfault.rbnu[PK|]6vqqJwsdl/soap/wsdl2ruby.rbnu[PK|]P0Y"vJwsdl/soap/servantSkeltonCreator.rbnu[PK|]&Jwsdl/soap/element.rbnu[PK|]R͛@Jwsdl/soap/complexType.rbnu[PK|]L!``6Jwsdl/soap/cgiStubCreator.rbnu[PK|]#PhhJwsdl/soap/body.rbnu[PK|];pnJwsdl/message.rbnu[PK|]^00 qJwsdl/info.rbnu[PK|]-qKEnv.rbnu[PK|]?? %Kopenssl.rbnu[PK|]EKsecurerandom.rbnu[PK|]ʜayy Kdigest.rbnu[PK|]nII Kdl/win32.rbnu[PK|]b $Kdl/types.rbnu[PK|]Y'C c:Kdl/import.rbnu[PK|]+  |LKdl/struct.rbnu[PK|]Րk7XKdrb.rbnu[PKTTXK