har 0.0.1.dev

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. data/.gitignore +4 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +24 -0
  5. data/README.mdown +36 -0
  6. data/Rakefile +28 -0
  7. data/bin/har +4 -0
  8. data/har.gemspec +27 -0
  9. data/lib/har.rb +32 -0
  10. data/lib/har/archive.rb +135 -0
  11. data/lib/har/page.rb +19 -0
  12. data/lib/har/schema_type.rb +78 -0
  13. data/lib/har/schemas/browserType +19 -0
  14. data/lib/har/schemas/cacheEntryType +25 -0
  15. data/lib/har/schemas/cacheType +15 -0
  16. data/lib/har/schemas/contentType +26 -0
  17. data/lib/har/schemas/cookieType +32 -0
  18. data/lib/har/schemas/creatorType +18 -0
  19. data/lib/har/schemas/entryType +46 -0
  20. data/lib/har/schemas/logType +40 -0
  21. data/lib/har/schemas/pageTimingsType +17 -0
  22. data/lib/har/schemas/pageType +29 -0
  23. data/lib/har/schemas/postDataType +38 -0
  24. data/lib/har/schemas/recordType +17 -0
  25. data/lib/har/schemas/requestType +53 -0
  26. data/lib/har/schemas/responseType +51 -0
  27. data/lib/har/schemas/timingsType +43 -0
  28. data/lib/har/serializable.rb +22 -0
  29. data/lib/har/version.rb +3 -0
  30. data/lib/har/viewer.rb +99 -0
  31. data/lib/har/viewer/css/SyntaxHighlighter.css +1 -0
  32. data/lib/har/viewer/css/aboutTab.css +1 -0
  33. data/lib/har/viewer/css/domTab.css +1 -0
  34. data/lib/har/viewer/css/domTree.css +1 -0
  35. data/lib/har/viewer/css/harPreview.css +1 -0
  36. data/lib/har/viewer/css/harView.css +1 -0
  37. data/lib/har/viewer/css/harViewer.css +1 -0
  38. data/lib/har/viewer/css/homeTab.css +1 -0
  39. data/lib/har/viewer/css/images/ajax-loader.gif +0 -0
  40. data/lib/har/viewer/css/images/bg-button.gif +0 -0
  41. data/lib/har/viewer/css/images/blank.gif +0 -0
  42. data/lib/har/viewer/css/images/button-background.png +0 -0
  43. data/lib/har/viewer/css/images/checkmark.gif +0 -0
  44. data/lib/har/viewer/css/images/checkmark.png +0 -0
  45. data/lib/har/viewer/css/images/close-sprites.png +0 -0
  46. data/lib/har/viewer/css/images/contextMenuTarget.png +0 -0
  47. data/lib/har/viewer/css/images/contextMenuTargetHover.png +0 -0
  48. data/lib/har/viewer/css/images/download-sprites.png +0 -0
  49. data/lib/har/viewer/css/images/downloadButtons-aero.png +0 -0
  50. data/lib/har/viewer/css/images/group.gif +0 -0
  51. data/lib/har/viewer/css/images/loading_16.gif +0 -0
  52. data/lib/har/viewer/css/images/menu/Thumbs.db +0 -0
  53. data/lib/har/viewer/css/images/menu/shadowAlpha.png +0 -0
  54. data/lib/har/viewer/css/images/menu/tabMenuCheckbox.png +0 -0
  55. data/lib/har/viewer/css/images/menu/tabMenuPin.png +0 -0
  56. data/lib/har/viewer/css/images/menu/tabMenuRadio.png +0 -0
  57. data/lib/har/viewer/css/images/netBarBlocking.gif +0 -0
  58. data/lib/har/viewer/css/images/netBarBlocking2.gif +0 -0
  59. data/lib/har/viewer/css/images/netBarCached.gif +0 -0
  60. data/lib/har/viewer/css/images/netBarConnecting.gif +0 -0
  61. data/lib/har/viewer/css/images/netBarLoaded.gif +0 -0
  62. data/lib/har/viewer/css/images/netBarReceiving.gif +0 -0
  63. data/lib/har/viewer/css/images/netBarResolving.gif +0 -0
  64. data/lib/har/viewer/css/images/netBarResponded.gif +0 -0
  65. data/lib/har/viewer/css/images/netBarSending.gif +0 -0
  66. data/lib/har/viewer/css/images/netBarWaiting.gif +0 -0
  67. data/lib/har/viewer/css/images/page-timeline.png +0 -0
  68. data/lib/har/viewer/css/images/save.png +0 -0
  69. data/lib/har/viewer/css/images/spriteArrows.gif +0 -0
  70. data/lib/har/viewer/css/images/spriteArrows.png +0 -0
  71. data/lib/har/viewer/css/images/tabEnabled.png +0 -0
  72. data/lib/har/viewer/css/images/timeline-sprites.png +0 -0
  73. data/lib/har/viewer/css/images/tooltipConnectorUp.png +0 -0
  74. data/lib/har/viewer/css/images/twisty-sprites.png +0 -0
  75. data/lib/har/viewer/css/images/twistyClosed.png +0 -0
  76. data/lib/har/viewer/css/images/twistyOpen.png +0 -0
  77. data/lib/har/viewer/css/infoTip.css +1 -0
  78. data/lib/har/viewer/css/pageList.css +1 -0
  79. data/lib/har/viewer/css/pageStats.css +1 -0
  80. data/lib/har/viewer/css/pageTimeline.css +1 -0
  81. data/lib/har/viewer/css/popupMenu.css +1 -0
  82. data/lib/har/viewer/css/previewTab.css +1 -0
  83. data/lib/har/viewer/css/requestBody.css +1 -0
  84. data/lib/har/viewer/css/requestList.css +1 -0
  85. data/lib/har/viewer/css/schemaTab.css +1 -0
  86. data/lib/har/viewer/css/tabView.css +1 -0
  87. data/lib/har/viewer/css/toolTip.css +1 -0
  88. data/lib/har/viewer/css/toolbar.css +1 -0
  89. data/lib/har/viewer/css/xhrSpy.css +1 -0
  90. data/lib/har/viewer/index.html +13 -0
  91. data/lib/har/viewer/scripts/app.build.js +0 -0
  92. data/lib/har/viewer/scripts/core/cookies.js +2 -0
  93. data/lib/har/viewer/scripts/core/lib.js +23 -0
  94. data/lib/har/viewer/scripts/core/trace.js +26 -0
  95. data/lib/har/viewer/scripts/domplate/domTree.js +5 -0
  96. data/lib/har/viewer/scripts/domplate/domplate.js +263 -0
  97. data/lib/har/viewer/scripts/domplate/infoTip.js +4 -0
  98. data/lib/har/viewer/scripts/domplate/popupMenu.js +14 -0
  99. data/lib/har/viewer/scripts/domplate/tabView.js +6 -0
  100. data/lib/har/viewer/scripts/domplate/toolTip.js +3 -0
  101. data/lib/har/viewer/scripts/domplate/toolbar.js +3 -0
  102. data/lib/har/viewer/scripts/downloadify/LICENSE.txt +22 -0
  103. data/lib/har/viewer/scripts/downloadify/README.textile +89 -0
  104. data/lib/har/viewer/scripts/downloadify/js/downloadify.min.js +6 -0
  105. data/lib/har/viewer/scripts/downloadify/js/swfobject.js +18 -0
  106. data/lib/har/viewer/scripts/downloadify/media/downloadify.swf +0 -0
  107. data/lib/har/viewer/scripts/downloadify/src/Downloadify.as +162 -0
  108. data/lib/har/viewer/scripts/downloadify/src/downloadify.js +6 -0
  109. data/lib/har/viewer/scripts/excanvas/excanvas.js +21 -0
  110. data/lib/har/viewer/scripts/harPreview.js +149 -0
  111. data/lib/har/viewer/scripts/harViewer.js +244 -0
  112. data/lib/har/viewer/scripts/jquery-plugins/jquery.json.js +6 -0
  113. data/lib/har/viewer/scripts/nls/harViewer.js +1 -0
  114. data/lib/har/viewer/scripts/nls/homeTab.js +1 -0
  115. data/lib/har/viewer/scripts/nls/pageStats.js +2 -0
  116. data/lib/har/viewer/scripts/nls/pageTimeline.js +1 -0
  117. data/lib/har/viewer/scripts/nls/previewTab.js +1 -0
  118. data/lib/har/viewer/scripts/nls/requestBody.js +1 -0
  119. data/lib/har/viewer/scripts/nls/requestList.js +2 -0
  120. data/lib/har/viewer/scripts/preview/harModel.js +7 -0
  121. data/lib/har/viewer/scripts/preview/harSchema.js +308 -0
  122. data/lib/har/viewer/scripts/preview/jsonSchema.js +7 -0
  123. data/lib/har/viewer/scripts/preview/pageList.js +4 -0
  124. data/lib/har/viewer/scripts/preview/ref.js +5 -0
  125. data/lib/har/viewer/scripts/preview/requestBody.js +11 -0
  126. data/lib/har/viewer/scripts/preview/requestList.js +27 -0
  127. data/lib/har/viewer/scripts/requireplugins-jquery-1.4.2.js +204 -0
  128. data/lib/har/viewer/scripts/syntax-highlighter/README.txt +9 -0
  129. data/lib/har/viewer/scripts/syntax-highlighter/shCore.js +20 -0
  130. data/lib/har/viewer/scripts/tabs/aboutTab.html +93 -0
  131. data/lib/har/viewer/scripts/tabs/aboutTab.js +2 -0
  132. data/lib/har/viewer/scripts/tabs/domTab.js +1 -0
  133. data/lib/har/viewer/scripts/tabs/homeTab.html +34 -0
  134. data/lib/har/viewer/scripts/tabs/homeTab.js +5 -0
  135. data/lib/har/viewer/scripts/tabs/pageStats.js +14 -0
  136. data/lib/har/viewer/scripts/tabs/pageTimeline.js +10 -0
  137. data/lib/har/viewer/scripts/tabs/previewTab.js +6 -0
  138. data/lib/har/viewer/scripts/tabs/schemaTab.js +2 -0
  139. data/lib/har/viewer/scripts/xhr-spy/spy.js +2 -0
  140. data/lib/har/viewer/scripts/xhr-spy/spy.php +13 -0
  141. data/lib/har/viewer/scripts/xhr-spy/xhr.js +6 -0
  142. data/lib/har/viewer/scripts/xhr-spy/xhrSpyBookmarklet.js +1 -0
  143. data/schema.json +201 -0
  144. data/spec/fixtures/entry1.json +124 -0
  145. data/spec/fixtures/hars/bad.har +2563 -0
  146. data/spec/fixtures/hars/browser-blocking-time.har +2567 -0
  147. data/spec/fixtures/hars/google.com.har +612 -0
  148. data/spec/fixtures/hars/inline-scripts-block.har +1066 -0
  149. data/spec/fixtures/hars/softwareishard.com.har +5323 -0
  150. data/spec/har/archive_spec.rb +130 -0
  151. data/spec/har/entry_spec.rb +16 -0
  152. data/spec/har/page_spec.rb +24 -0
  153. data/spec/har/viewer_spec.rb +17 -0
  154. data/spec/spec_helper.rb +34 -0
  155. metadata +283 -0
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in har.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2010 Jari Bakken
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ harviewer by Jan Odvarko is covered by the New BSD License
23
+ http://www.opensource.org/licenses/bsd-license.php
24
+ http://code.google.com/p/harviewer/
@@ -0,0 +1,36 @@
1
+ HAR
2
+ ===
3
+
4
+ Ruby library to work with and view HTTP archives.
5
+ This includes [harviewer](http://code.google.com/p/harviewer/), which can be launched through the "har" command.
6
+
7
+ Usage
8
+ =============
9
+
10
+ HAR::Archive.from_string(json) #=> #<Har::Archive:0x5e7cac>
11
+ HAR::Archive.from_file(path) #=> #<Har::Archive:0x5e7cac>
12
+
13
+ Or from command the command line:
14
+
15
+ har /path/to/some.har
16
+
17
+ Links
18
+ =====
19
+
20
+ * [harviewer](http://code.google.com/p/harviewer/)
21
+
22
+ Note on Patches/Pull Requests
23
+ =============================
24
+
25
+ * Fork the project.
26
+ * Make your feature addition or bug fix.
27
+ * Add tests for it. This is important so I don't break it in a
28
+ future version unintentionally.
29
+ * Commit, do not mess with rakefile, version, or history.
30
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
31
+ * Send me a pull request. Bonus points for topic branches.
32
+
33
+ Copyright
34
+ =========
35
+
36
+ Copyright (c) 2010 Jari Bakken. See LICENSE for details.
@@ -0,0 +1,28 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new
6
+
7
+ desc 'Regenerate the schema files'
8
+ task :schema do
9
+ require "json"
10
+
11
+ out = File.expand_path("../lib/har/schemas", __FILE__)
12
+ schema = JSON.parse(File.read("schema.json"))
13
+
14
+ # cleanup
15
+ Dir[File.join(out, "*.json")].each { |f|
16
+ rm f
17
+ }
18
+
19
+ # generate
20
+ schema.each do |type, schema|
21
+ path = File.join(out, type)
22
+ puts path
23
+
24
+ File.open(path, "w") { |file|
25
+ file << JSON.pretty_generate(schema)
26
+ }
27
+ end
28
+ end
data/bin/har ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "har"
4
+ HAR::Viewer.new(ARGV).show
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "har/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "har"
7
+ s.version = HAR::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Jari Bakken"]
10
+ s.email = ["jari.bakken@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Ruby library to work with HTTP archives}
13
+ s.description = %q{Ruby library to work with HTTP archives}
14
+
15
+ s.rubyforge_project = "har"
16
+
17
+ s.add_dependency "json"
18
+ s.add_dependency "json-schema"
19
+ s.add_dependency "launchy"
20
+
21
+ s.add_development_dependency "rspec", "~> 2.0"
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
@@ -0,0 +1,32 @@
1
+ require 'json'
2
+ require 'json-schema'
3
+ require 'time'
4
+
5
+ module HAR
6
+ class Error < StandardError; end
7
+ class ValidationError < StandardError; end
8
+ end
9
+
10
+ require 'har/serializable'
11
+ require 'har/schema_type'
12
+ require 'har/page'
13
+ require 'har/archive'
14
+ require 'har/viewer'
15
+
16
+ module Enumerable
17
+ def group_by
18
+ assoc = {}
19
+
20
+ each do |element|
21
+ key = yield(element)
22
+
23
+ if assoc.has_key?(key)
24
+ assoc[key] << element
25
+ else
26
+ assoc[key] = [element]
27
+ end
28
+ end
29
+
30
+ assoc
31
+ end unless [].respond_to?(:group_by)
32
+ end
@@ -0,0 +1,135 @@
1
+ module HAR
2
+ class Archive
3
+ include Serializable
4
+
5
+ def self.from_string(str, uri = nil)
6
+ new JSON.parse(str), uri
7
+ end
8
+
9
+ def self.from_file(path)
10
+ from_string File.read(path), path
11
+ end
12
+
13
+ attr_reader :uri
14
+
15
+ def initialize(input, uri = nil)
16
+ @data = input
17
+ @uri = uri
18
+ end
19
+
20
+ def pages
21
+ @pages ||= raw_log.fetch('pages').map { |page|
22
+ Page.new page, entries_for(page['id'])
23
+ }
24
+ end
25
+
26
+ def entries
27
+ @entries ||= raw_entries.map { |e| Entry.new(e) }
28
+ end
29
+
30
+ # create a new archive by merging this and another archive
31
+
32
+ def merge(other)
33
+ assert_archive other
34
+
35
+ data = deep_clone(@data)
36
+ merge_data data, other.as_json, other.uri
37
+
38
+ self.class.new data
39
+ end
40
+
41
+ # destructively merge this with the given archive
42
+
43
+ def merge!(other)
44
+ assert_archive other
45
+ clear_caches
46
+
47
+ merge_data @data, other.as_json, other.uri
48
+ nil
49
+ end
50
+
51
+ def save_to(path)
52
+ File.open(path, "w") { |io| io << @data.to_json }
53
+ end
54
+
55
+ def valid?
56
+ JSON::Validator.validate schema_file, @data
57
+ end
58
+
59
+ def validate!
60
+ JSON::Validator.validate2 schema_file, @data
61
+ rescue JSON::ValidationError => ex
62
+ # add archive uri to the message
63
+ if @uri
64
+ raise ValidationError, "#{@uri}: #{ex.message}"
65
+ else
66
+ raise ValidationError, ex.message
67
+ end
68
+ end
69
+
70
+ protected
71
+
72
+ private
73
+
74
+ def schema_file
75
+ @schema_file ||= File.expand_path("../schemas/logType", __FILE__)
76
+ end
77
+
78
+ def merge_data(left, right, uri)
79
+ log = left.fetch('log')
80
+ other_log = right.fetch('log')
81
+
82
+ pages = log.fetch('pages')
83
+ entries = log.fetch('entries')
84
+
85
+ other_pages = other_log.fetch("pages")
86
+ other_entries = other_log.fetch("entries")
87
+
88
+ if uri
89
+ deep_clone(other_pages).each do |page|
90
+ c = page['comment'] ||= ''
91
+ c << "(merged from #{File.basename uri})"
92
+
93
+ pages << page
94
+ end
95
+ else
96
+ pages.concat other_pages
97
+ end
98
+
99
+ entries.concat other_entries
100
+ end
101
+
102
+ def assert_archive(other)
103
+ unless other.kind_of?(self.class)
104
+ raise TypeError, "expected #{self.class}"
105
+ end
106
+ end
107
+
108
+ def clear_caches
109
+ @raw_entries = @entries_map = @pages = @entries = @log = nil
110
+ end
111
+
112
+ def entries_for(page_id)
113
+ entries = entries_map[page_id] || []
114
+ entries.map { |e| Entry.new(e) }
115
+ end
116
+
117
+ def raw_entries
118
+ @raw_entries ||= raw_log.fetch('entries')
119
+ end
120
+
121
+ def raw_log
122
+ @raw_log ||= @data.fetch 'log'
123
+ end
124
+
125
+ def entries_map
126
+ @entries_map ||= raw_entries.group_by { |e| e['pageref'] }
127
+ end
128
+
129
+ def deep_clone(obj)
130
+ Marshal.load Marshal.dump(obj)
131
+ end
132
+
133
+ end # Archive
134
+ end # HAR
135
+
@@ -0,0 +1,19 @@
1
+ module HAR
2
+ class Page < SchemaType
3
+
4
+ attr_reader :entries
5
+
6
+ def initialize(input, entries)
7
+ super(input)
8
+ @entries = entries
9
+ end
10
+
11
+ def title
12
+ @data.fetch 'title'
13
+ end
14
+
15
+ # a little sugar
16
+ alias_method :timings, :page_timings
17
+
18
+ end
19
+ end
@@ -0,0 +1,78 @@
1
+ require "pp"
2
+
3
+ module HAR
4
+ class SchemaType
5
+ include Serializable
6
+
7
+ class << self
8
+ private
9
+
10
+ def load_from(file)
11
+ schema = JSON.parse(File.read(file))
12
+
13
+ klass = Class.new(self) do
14
+ schema['properties'].each do |name, definition|
15
+ define_property name, definition
16
+ end
17
+ end
18
+
19
+ HAR.const_set type_name_from(schema['id']), klass
20
+ end
21
+
22
+ def define_property(name, definition)
23
+ required = definition['required']
24
+ type = definition['type']
25
+
26
+ wrapper = extract_wrapper(name, definition)
27
+
28
+ fetch_code = required ? "@data.fetch(#{name.inspect})" : "@data[#{name.inspect}]"
29
+ fetch_code = "#{wrapper} #{fetch_code}" if wrapper
30
+
31
+ class_eval "
32
+ def #{snake_case name}
33
+ @#{name} ||= #{fetch_code}
34
+ end
35
+ "
36
+ end
37
+
38
+ def extract_wrapper(name, definition)
39
+ type = definition['type']
40
+
41
+ case type
42
+ when 'object'
43
+ return "#{name.capitalize}.new"
44
+ when 'string'
45
+ if definition['format'] == 'date-time'
46
+ return 'Time.parse'
47
+ end
48
+ when Hash
49
+ ref = type['$ref']
50
+ when nil
51
+ ref = definition['$ref']
52
+ end
53
+
54
+ "#{type_name_from(ref)}.new" if ref
55
+ end
56
+
57
+ def type_name_from(str)
58
+ t = str[/^(.+)Type/, 1] or raise Error, "could not extract type name from #{str.inspect}"
59
+ t[0] = t[0].chr.upcase
60
+
61
+ t
62
+ end
63
+
64
+ def snake_case(str)
65
+ str.gsub(/\B[A-Z][^A-Z]/, '_\&').downcase.gsub(' ', '_')
66
+ end
67
+ end
68
+
69
+ def initialize(data)
70
+ @data = data
71
+ end
72
+
73
+ # load in schemas
74
+ Dir[File.expand_path("../schemas/*", __FILE__)].each do |file|
75
+ load_from file
76
+ end
77
+ end # SchemaType
78
+ end # HAR
@@ -0,0 +1,19 @@
1
+ {
2
+ "id": "browserType",
3
+ "description": "Name and version info of used browser.",
4
+ "type": "object",
5
+ "optional": true,
6
+ "properties": {
7
+ "name": {
8
+ "type": "string",
9
+ "required": true
10
+ },
11
+ "version": {
12
+ "type": "string",
13
+ "required": true
14
+ },
15
+ "comment": {
16
+ "type": "string"
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "id": "cacheEntryType",
3
+ "optional": true,
4
+ "description": "Info about cache entry.",
5
+ "properties": {
6
+ "expires": {
7
+ "type": "string"
8
+ },
9
+ "lastAccess": {
10
+ "type": "string",
11
+ "required": true
12
+ },
13
+ "eTag": {
14
+ "type": "string",
15
+ "required": true
16
+ },
17
+ "hitCount": {
18
+ "type": "integer",
19
+ "required": true
20
+ },
21
+ "comment": {
22
+ "type": "string"
23
+ }
24
+ }
25
+ }