rsutphin-cf_case_check 0.0.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,3 +1,25 @@
1
+ 0.1.2 / 2009-09-23
2
+ ==================
3
+ * Ignore createObject("java", ...) calls (instead of warning about them)
4
+
5
+ 0.1.1 / 2009-09-23
6
+ ==================
7
+ * Support unquoted attributes in tags
8
+ * Do not abort on an analysis exception -- print the exception and continue
9
+ with the next file
10
+
11
+ 0.1.0 / 2008-12-15
12
+ ==================
13
+ * Add support for configurable substitutions for, e.g., application variable
14
+ use in references
15
+ * Include 'tem' (along with 'cfm' and 'cfc') in the list of extensions to use
16
+ when looking for CF source
17
+ * Ensure that source filenames are globbed case-insensitively
18
+
19
+ 0.0.2 / 2008-12-15
20
+ ==================
21
+ * Resolve CFCs in the same directory as the source
22
+
1
23
  0.0.1 / 2008-12-14
2
24
  ==================
3
25
  * Fix recursion bug in CaseCheck::exit
data/Rakefile CHANGED
@@ -22,7 +22,7 @@ PROJ.url = 'http://github.com/rsutphin/cf_case_check'
22
22
  PROJ.version = CaseCheck::VERSION
23
23
  # PROJ.rubyforge.name = 'cf_case_check'
24
24
  PROJ.description = "A utility which walks a ColdFusion application's source and determines which includes, custom tags, etc, will not work with a case-sensitive filesystem"
25
- PROJ.exclude << "gem$" << "gemspec$"
25
+ PROJ.exclude << "gem$" << "gemspec$" << ".DS*" << '.git*'
26
26
 
27
27
  PROJ.ruby_opts = [] # There are a bunch of warnings in rspec, so setting -w isn't useful
28
28
  PROJ.spec.opts << '--color'
@@ -33,6 +33,7 @@ PROJ.gem.dependencies << 'activesupport'
33
33
  desc 'Regenerate the gemspec for github'
34
34
  task :'gem:spec' => 'gem:prereqs' do
35
35
  PROJ.gem._spec.files = PROJ.gem._spec.files.reject { |f| f =~ /^tasks/ }
36
+ PROJ.gem._spec.rubyforge_project = nil
36
37
  File.open("#{PROJ.name}.gemspec", 'w') do |gemspec|
37
38
  gemspec.puts PROJ.gem._spec.to_ruby
38
39
  end
data/lib/case_check.rb CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  module CaseCheck
3
3
  # :stopdoc:
4
- VERSION = '0.0.1'.freeze
4
+ VERSION = '0.1.2'.freeze
5
5
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
6
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
7
  # :startdoc:
@@ -16,8 +16,13 @@ class ColdfusionSource
16
16
  end
17
17
 
18
18
  def analyze
19
- [CustomTag, Cfmodule, Cfinclude, Cfc].each do |reftype|
20
- internal_references.concat reftype.search(self)
19
+ begin
20
+ [CustomTag, Cfmodule, Cfinclude, Cfc].each do |reftype|
21
+ internal_references.concat reftype.search(self)
22
+ end
23
+ rescue => e
24
+ $stderr.puts "Analyzing #{filename} failed: #{e}"
25
+ e.backtrace.each { |l| $stderr.puts " #{l}" }
21
26
  end
22
27
  end
23
28
 
@@ -72,16 +77,24 @@ class ColdfusionSource
72
77
  # attributes, and the line number back to the provided block.
73
78
  def scan_for_tag(tag, &block)
74
79
  scan(/<#{tag}(.*?)>/mi) do |md, l|
75
- attributes = %w(' ").collect do |q|
76
- /(\w+)\s*=\s*#{q}([^#{q}]*?)#{q}/.scan(md[1].gsub(%r(/$), ''))
77
- end.flatten.inject({}) do |attrs, amd|
80
+ attributes = ['"', "'", nil].collect { |q|
81
+ attribute_re(q).scan(md[1].gsub(%r(/$), ''))
82
+ }.flatten.inject({}) { |attrs, amd|
78
83
  attrs[normalize_attribute_key(amd[1])] = amd[2]
79
84
  attrs
80
- end
85
+ }
81
86
  yield md[0], attributes, l
82
87
  end
83
88
  end
84
89
 
90
+ def attribute_re(q)
91
+ if q
92
+ /(\w+)\s*=\s*#{q}([^#{q}]*?)#{q}/
93
+ else
94
+ /(\w+)\s*=\s*([^'"\s]+)/
95
+ end
96
+ end
97
+
85
98
  private
86
99
 
87
100
  def normalize_attribute_key(key)
@@ -64,10 +64,15 @@ module CaseCheck
64
64
  def initialize(params)
65
65
  @params = params
66
66
  CaseCheck.status_stream.print "Reading source files "
67
- @sources = Dir["#{params.directory}/**/*.cf[mc]"].collect do |f|
68
- CaseCheck.status_stream.print '.'
69
- ColdfusionSource.create(f)
70
- end
67
+ @sources = extensions.collect {
68
+ |ext| [ext, Dir.glob("#{params.directory}/**/*.#{ext}", File::FNM_CASEFOLD)]
69
+ }.collect do |ext, files|
70
+ CaseCheck.status_stream.print "#{ext}: " unless files.empty?
71
+ files.collect do |f|
72
+ CaseCheck.status_stream.print '.'
73
+ ColdfusionSource.create(f)
74
+ end
75
+ end.flatten
71
76
  CaseCheck.status_stream.puts
72
77
  CaseCheck.status_stream.print "Analyzing "
73
78
  @sources.each do |s|
@@ -85,6 +90,10 @@ module CaseCheck
85
90
  def reference_count
86
91
  sources.inject(0) { |c, s| c + s.internal_references.size }
87
92
  end
93
+
94
+ def extensions
95
+ %w(cfm cfc tem)
96
+ end
88
97
  end
89
98
 
90
99
  class FilteredSource
@@ -10,15 +10,12 @@ class Configuration
10
10
  apply
11
11
  end
12
12
 
13
- def [](k)
14
- @doc[k]
15
- end
16
-
17
13
  private
18
14
 
19
15
  def apply
20
16
  read_custom_tag_dirs
21
17
  read_cfc_dirs
18
+ read_substitutions
22
19
  end
23
20
 
24
21
  def read_custom_tag_dirs
@@ -29,6 +26,14 @@ class Configuration
29
26
  Cfc.directories = absolutize_directories(@doc['cfc_directories'] || [])
30
27
  end
31
28
 
29
+ def read_substitutions
30
+ if @doc['substitutions']
31
+ @doc['substitutions'].each_pair do |re, repl|
32
+ CaseCheck::Reference.substitutions << [Regexp.new(re, Regexp::IGNORECASE), repl]
33
+ end
34
+ end
35
+ end
36
+
32
37
  private
33
38
 
34
39
  def absolutize_directories(dirs)
@@ -5,8 +5,14 @@ require 'activesupport'
5
5
 
6
6
  module CaseCheck
7
7
 
8
- # base class
8
+ # abstract base class
9
9
  class Reference < Struct.new(:source, :text, :line)
10
+ class << self
11
+ def substitutions
12
+ @substitutions ||= []
13
+ end
14
+ end
15
+
10
16
  # abstract methods
11
17
  # - expected_path
12
18
  # returns the exact relative path to which this reference refers
@@ -43,6 +49,15 @@ class Reference < Struct.new(:source, :text, :line)
43
49
  self.class.name.split('::').last.underscore.gsub('_', ' ')
44
50
  end
45
51
 
52
+ def substituted_text
53
+ re, sub = CaseCheck::Reference.substitutions.detect { |expr, _| expr =~ text }
54
+ if re
55
+ text.sub(re, sub)
56
+ else
57
+ text
58
+ end
59
+ end
60
+
46
61
  protected
47
62
 
48
63
  def case_sensitive_match?
@@ -14,24 +14,32 @@ module CaseCheck
14
14
  def search(source)
15
15
  source.scan(/createObject\((.*?)\)/mi) do |match, l|
16
16
  args = match[1].split(/\s*,\s*/).collect { |a| a.gsub(/['"]/, '') }
17
- unless args.size == 2 && args.first =~ /component/i
17
+ if args.size == 2 && args.first =~ /component/i
18
+ new(source, args.last, l)
19
+ elsif args.first =~ /java/
20
+ # quietly skip
21
+ else
22
+ # loudly skip
18
23
  $stderr.puts "Non-CFC call on line #{l} of #{source.filename}: #{match[0]}"
19
24
  end
20
- new(source, args.last, l)
21
- end
25
+ end.compact
22
26
  end
23
27
  end
24
28
 
25
29
  def initialize(source, text, line_number)
26
30
  super
27
- @expected_path = text.gsub('.', '/') + ".cfc"
28
- @resolved_to = self.class.directories.inject(nil) do |resolved, dir|
31
+ @expected_path = substituted_text.gsub('.', '/') + ".cfc"
32
+ @resolved_to = search_path.inject(nil) do |resolved, dir|
29
33
  resolved || resolve_in(dir)
30
34
  end
31
35
  end
32
36
 
33
37
  protected
34
38
 
39
+ def search_path
40
+ [File.dirname(source.filename)] + self.class.directories
41
+ end
42
+
35
43
  def case_sensitive_match?
36
44
  return true if super
37
45
  # According to the CF docs:
@@ -12,7 +12,7 @@ module CaseCheck
12
12
 
13
13
  def initialize(source, text, line)
14
14
  super
15
- @expected_path = text
15
+ @expected_path = substituted_text
16
16
  @resolved_to = resolve_in(File.dirname(source.filename))
17
17
  end
18
18
  end
@@ -21,7 +21,7 @@ module CaseCheck
21
21
  class Name < Cfmodule
22
22
  def initialize(source, text, line)
23
23
  super
24
- @expected_path = text.gsub('.', '/') + ".cfm"
24
+ @expected_path = substituted_text.gsub('.', '/') + ".cfm"
25
25
  @resolved_to = CustomTag.directories.inject(nil) do |resolved, dir|
26
26
  resolved || resolve_in(dir)
27
27
  end
@@ -35,7 +35,7 @@ module CaseCheck
35
35
  class Template < Cfmodule
36
36
  def initialize(source, text, line)
37
37
  super
38
- @expected_path = text
38
+ @expected_path = substituted_text
39
39
  @resolved_to = resolve_in(File.dirname(source.filename))
40
40
  end
41
41
 
@@ -137,11 +137,22 @@ describe ColdfusionSource do
137
137
  actual = perform_scan(<<-CFM, "cfparam")
138
138
  <cfparam name ="foo" default= "42">
139
139
  <cfparam name="bar" default = "11">
140
+ <cfparam name= baz default = 19>
140
141
  CFM
141
- actual.should have(2).matches
142
+ actual.should have(3).matches
142
143
  actual[0][:attributes].should == { :name => 'foo', :default => '42' }
143
144
  actual[1][:attributes].should == { :name => 'bar', :default => '11' }
144
- actual[1][:line_number].should == 2
145
+ actual[2][:attributes].should == { :name => 'baz', :default => '19' }
146
+ end
147
+
148
+ it "matches unquoted attributes" do
149
+ actual = perform_scan(<<-CFM, "cfinclude")
150
+ <cfinclude template=GetAccountIDStringMatch.cfm >
151
+ <cfinclude template=alpha option=beta>
152
+ CFM
153
+ actual.should have(2).matches
154
+ actual[0][:attributes].should == { :template => 'GetAccountIDStringMatch.cfm' }
155
+ actual[1][:attributes].should == { :template => 'alpha', :option => 'beta' }
145
156
  end
146
157
 
147
158
  it "downcases attribute keys" do
@@ -39,4 +39,23 @@ describe CaseCheck::Configuration do
39
39
  read_config
40
40
  CaseCheck::CustomTag.directories.should == %w(/tmp/cf_case_check/zappo/customtags)
41
41
  end
42
+
43
+ it "reads substitutions" do
44
+ config_file <<-YAML
45
+ substitutions:
46
+ '#application.cfcPath#': /var/www/cfcs
47
+ YAML
48
+ read_config
49
+ CaseCheck::Reference.should have(1).substitutions
50
+ end
51
+
52
+ it "interprets substitution patterns as case insensitive REs" do
53
+ config_file <<-YAML
54
+ substitutions:
55
+ '#application.cfcPath#': /var/www/cfcs
56
+ YAML
57
+ read_config
58
+ CaseCheck::Reference.substitutions.first.should == [/#application.cfcPath#/i, '/var/www/cfcs']
59
+ CaseCheck::Reference.substitutions.first.first.should be_casefold
60
+ end
42
61
  end
@@ -68,5 +68,32 @@ describe File, ' extensions ' do
68
68
  touch("baz/bar/foo/quux")
69
69
  File.case_insensitive_canonical_name(testfile("baz/bar/quod/../fOO/quux")).should == testfile("baz/bar/foo/quux")
70
70
  end
71
+
72
+ describe "with symlinks" do
73
+ before do
74
+ @actual_dir = File.join(@tmpdir, "A")
75
+ FileUtils.mkdir_p @actual_dir
76
+ @linked_dir = File.join(@tmpdir, "B")
77
+ FileUtils.ln_s(@actual_dir, @linked_dir)
78
+ end
79
+
80
+ it "finds exact matches" do
81
+ expected = File.join(@linked_dir, "foo.cfm")
82
+ FileUtils.touch expected
83
+ File.case_insensitive_canonical_name(expected).should == expected
84
+ end
85
+
86
+ it "finds case-insensitive matches where the filename case differs" do
87
+ expected = File.join(@linked_dir, "Foo.cfm")
88
+ FileUtils.touch expected
89
+ File.case_insensitive_canonical_name(File.join(@linked_dir, "foo.cfm")).should == expected
90
+ end
91
+
92
+ it "finds case-insensitive matches where the symlink case differs" do
93
+ expected = File.join(@linked_dir, "foo.cfm")
94
+ FileUtils.touch expected
95
+ File.case_insensitive_canonical_name(File.join(@tmpdir, 'b', "foo.cfm")).should == expected
96
+ end
97
+ end
71
98
  end
72
99
  end
@@ -32,6 +32,21 @@ describe CaseCheck::Reference do
32
32
  end
33
33
  end
34
34
 
35
+ describe "text substitution" do
36
+ it "has none by default" do
37
+ CaseCheck::Reference.substitutions.should == []
38
+ end
39
+
40
+ it "subs in the first matching option" do
41
+ CaseCheck::Reference.substitutions << [/#application#/i, 'foo'] << [/#app.*?#/i, 'bar']
42
+ SampleReference.new(nil, nil, 0, "#application#/quux").substituted_text.should == "foo/quux"
43
+ end
44
+
45
+ it "returns the original text if there are no matching subs" do
46
+ SampleReference.new(nil, nil, 0, "#application#/quux").substituted_text.should == "#application#/quux"
47
+ end
48
+ end
49
+
35
50
  describe 'default message' do
36
51
  it "indicates when it is unresolved" do
37
52
  SampleReference.new("/foo/patient.cfm", nil, 11, "FOO_Patient").message.should ==
@@ -11,6 +11,7 @@ describe CaseCheck::Cfc do
11
11
  <cfscript>
12
12
  utilsObj = CreateObject("component","bspore.Utils").init(datasource=application.personnel_db,username=session.netid,userIP=cgi.remote_addr);
13
13
  summaryObj = createObject("component","bspore.Summary").init(datasource=application.db,username=session.netid,userIP=cgi.remote_addr);
14
+ color = createObject("java","org.apache.poi.hssf.util.HSSFColor$CORAL");
14
15
  </cfscript>
15
16
  CFM
16
17
  end
@@ -31,6 +32,10 @@ describe CaseCheck::Cfc do
31
32
  actual_search.should have(2).references
32
33
  end
33
34
 
35
+ it "ignores java invocations" do
36
+ actual_search.detect { |s| s.expected_path =~ /CORAL/ }.should be_nil
37
+ end
38
+
34
39
  it "finds lower case createObject style" do
35
40
  actual_search.last.expected_path.should == "bspore/Summary.cfc"
36
41
  end
@@ -59,4 +64,19 @@ describe CaseCheck::Cfc do
59
64
  actual_search.first.resolved_to.should == expected_file
60
65
  actual_search.first.resolution.should == :case_insensitive
61
66
  end
67
+
68
+ it "resolves against a match in the same directory as the file" do
69
+ expected_file = File.join(File.dirname(@source.filename), 'bspore/Utils.cfc')
70
+ touch expected_file
71
+ actual_search.first.resolved_to.should == expected_file
72
+ actual_search.first.resolution.should == :exact
73
+ end
74
+
75
+ it "performs substitutions before attempting to resolve" do
76
+ @source.content = <<-CFM
77
+ CreateObject("component", application.pathToComponents&"Personnel")
78
+ CFM
79
+ CaseCheck::Reference.substitutions << [/application.pathToComponents&/i, "pipes."]
80
+ actual_search.first.expected_path.should == "pipes/Personnel.cfc"
81
+ end
62
82
  end
@@ -63,4 +63,12 @@ describe CaseCheck::Cfinclude do
63
63
  CFM
64
64
  actual_search.should have(1).reference
65
65
  end
66
+
67
+ it "performs substitutions before resolving" do
68
+ @source.content = <<-CFM
69
+ <cfinclude template="#application.myroot#whatever.cfm">
70
+ CFM
71
+ CaseCheck::Reference.substitutions << [/#application.myroot#/, 'etc/']
72
+ actual_search.first.expected_path.should == 'etc/whatever.cfm'
73
+ end
66
74
  end
@@ -76,6 +76,14 @@ describe CaseCheck::Cfmodule::Name do
76
76
  CFM
77
77
  actual_search.should have(1).reference
78
78
  end
79
+
80
+ it "performs substitutions before resolving" do
81
+ @source.content = <<-CFM
82
+ <cfmodule name="#application.myroot#whatever">
83
+ CFM
84
+ CaseCheck::Reference.substitutions << [/#application.myroot#/, 'etc.']
85
+ actual_search.first.expected_path.should == 'etc/whatever.cfm'
86
+ end
79
87
  end
80
88
 
81
89
  describe CaseCheck::Cfmodule::Template do
@@ -136,4 +144,13 @@ describe CaseCheck::Cfmodule::Template do
136
144
  CFM
137
145
  actual_search.should have(1).reference
138
146
  end
147
+
148
+
149
+ it "performs substitutions before resolving" do
150
+ @source.content = <<-CFM
151
+ <cfmodule template="#application.somePath#whatever.cfm">
152
+ CFM
153
+ CaseCheck::Reference.substitutions << [/#application.somePath#/, 'etc/']
154
+ actual_search.first.expected_path.should == 'etc/whatever.cfm'
155
+ end
139
156
  end
data/spec/spec_helper.rb CHANGED
@@ -9,6 +9,7 @@ Spec::Runner.configure do |config|
9
9
 
10
10
  config.after do
11
11
  CaseCheck.status_stream = nil
12
+ CaseCheck::Reference.substitutions.clear
12
13
  end
13
14
 
14
15
  # == Mock Framework
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsutphin-cf_case_check
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rhett Sutphin
@@ -9,11 +9,12 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-12-14 00:00:00 -08:00
12
+ date: 2009-09-23 00:00:00 -07:00
13
13
  default_executable: cf_case_check
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -23,12 +24,13 @@ dependencies:
23
24
  version:
24
25
  - !ruby/object:Gem::Dependency
25
26
  name: bones
27
+ type: :development
26
28
  version_requirement:
27
29
  version_requirements: !ruby/object:Gem::Requirement
28
30
  requirements:
29
31
  - - ">="
30
32
  - !ruby/object:Gem::Version
31
- version: 2.1.0
33
+ version: 2.5.0
32
34
  version:
33
35
  description: A utility which walks a ColdFusion application's source and determines which includes, custom tags, etc, will not work with a case-sensitive filesystem
34
36
  email: rhett@detailedbalance.net
@@ -38,13 +40,11 @@ extensions: []
38
40
 
39
41
  extra_rdoc_files:
40
42
  - History.txt
41
- - README.txt
43
+ - Manifest.txt
42
44
  - bin/cf_case_check
43
45
  files:
44
- - .gitignore
45
46
  - History.txt
46
47
  - Manifest.txt
47
- - README.txt
48
48
  - Rakefile
49
49
  - bin/cf_case_check
50
50
  - lib/case_check.rb
@@ -67,8 +67,9 @@ files:
67
67
  - spec/references/cfmodule_spec.rb
68
68
  - spec/references/custom_tag_spec.rb
69
69
  - spec/spec_helper.rb
70
- has_rdoc: true
70
+ has_rdoc: false
71
71
  homepage: http://github.com/rsutphin/cf_case_check
72
+ licenses:
72
73
  post_install_message:
73
74
  rdoc_options:
74
75
  - --main
@@ -89,12 +90,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
90
  version:
90
91
  requirements: []
91
92
 
92
- rubyforge_project: !binary |
93
- AA==
94
-
95
- rubygems_version: 1.2.0
93
+ rubyforge_project:
94
+ rubygems_version: 1.3.5
96
95
  signing_key:
97
- specification_version: 2
96
+ specification_version: 3
98
97
  summary: A utility which walks a ColdFusion application's source and determines which includes, custom tags, etc, will not work with a case-sensitive filesystem
99
98
  test_files: []
100
99
 
data/.gitignore DELETED
@@ -1,3 +0,0 @@
1
- pkg
2
- coverage
3
- *.gem
data/README.txt DELETED
@@ -1,75 +0,0 @@
1
- `cf_case_check`
2
- ===============
3
- http://github.com/rsutphin/cf_case_check
4
-
5
- Description
6
- -----------
7
-
8
- `cf_case_check` is a utility which walks a ColdFusion application's source and
9
- determines which references to other files will not work with a case-sensitive
10
- filesystem. Its intended audience is developers/sysadmins who are migrating
11
- a CF application from Windows hosting to Linux or another UNIX.
12
-
13
- `cf_case_check` was developed at the [Northwestern University Biomedical
14
- Informatics Center][NUBIC].
15
-
16
- [NUBIC]: http://www.nucats.northwestern.edu/centers/nubic/index.html
17
-
18
- Features
19
- --------
20
-
21
- * Resolves references of the following types:
22
- - `CF_`-style custom tags
23
- - `cfinclude`
24
- - `cfmodule` (both `template` and `name`)
25
- - `createObject` (for CFCs only)
26
- * Prints report to stdout
27
- * Allows for designation of custom tag & CFC search paths outside the
28
- application root
29
-
30
- Synopsis
31
- --------
32
-
33
- myapp$ cf_case_check
34
-
35
- For command-line options, do:
36
-
37
- $ cf_case_check --help
38
-
39
- Requirements
40
- ------------
41
-
42
- * Ruby 1.8.6 or later (may work with earlier, but not tested)
43
-
44
- Install
45
- -------
46
-
47
- Follow the GitHub rubygems [setup directions](http://gems.github.com/), then
48
-
49
- $ sudo gem install rsutphin-cf_case_check
50
-
51
- License
52
- -------
53
-
54
- (The MIT License)
55
-
56
- Copyright (c) 2008 Rhett Sutphin
57
-
58
- Permission is hereby granted, free of charge, to any person obtaining
59
- a copy of this software and associated documentation files (the
60
- 'Software'), to deal in the Software without restriction, including
61
- without limitation the rights to use, copy, modify, merge, publish,
62
- distribute, sublicense, and/or sell copies of the Software, and to
63
- permit persons to whom the Software is furnished to do so, subject to
64
- the following conditions:
65
-
66
- The above copyright notice and this permission notice shall be
67
- included in all copies or substantial portions of the Software.
68
-
69
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
70
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
71
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
72
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
73
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
74
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
75
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.