rof 0.0.1.pre → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +12 -2
  4. data/Gemfile +1 -0
  5. data/README.md +87 -0
  6. data/bin/.ruby-version +1 -0
  7. data/bin/csv_to_rof +26 -0
  8. data/bin/fedora_to_rof +57 -0
  9. data/bin/osf_to_rof +40 -0
  10. data/bin/rof +78 -0
  11. data/bulk-ingest.md +242 -0
  12. data/labels.md +111 -0
  13. data/lib/rof.rb +20 -1
  14. data/lib/rof/access.rb +57 -0
  15. data/lib/rof/cli.rb +122 -0
  16. data/lib/rof/collection.rb +109 -0
  17. data/lib/rof/compare_rof.rb +92 -0
  18. data/lib/rof/filters/bendo.rb +33 -0
  19. data/lib/rof/filters/date_stamp.rb +36 -0
  20. data/lib/rof/filters/file_to_url.rb +27 -0
  21. data/lib/rof/filters/label.rb +153 -0
  22. data/lib/rof/filters/work.rb +111 -0
  23. data/lib/rof/get_from_fedora.rb +196 -0
  24. data/lib/rof/ingest.rb +204 -0
  25. data/lib/rof/ingesters/rels_ext_ingester.rb +78 -0
  26. data/lib/rof/ingesters/rights_metadata_ingester.rb +68 -0
  27. data/lib/rof/osf_context.rb +19 -0
  28. data/lib/rof/osf_to_rof.rb +122 -0
  29. data/lib/rof/rdf_context.rb +36 -0
  30. data/lib/rof/translate_csv.rb +112 -0
  31. data/lib/rof/utility.rb +84 -0
  32. data/lib/rof/version.rb +2 -2
  33. data/rof.gemspec +17 -0
  34. data/spec/fixtures/a.json +4 -0
  35. data/spec/fixtures/label.json +20 -0
  36. data/spec/fixtures/osf/b6psa.tar.gz +0 -0
  37. data/spec/fixtures/rof/dev0012829m.rof +45 -0
  38. data/spec/fixtures/vcr_tests/fedora_to_rof1.yml +5274 -0
  39. data/spec/fixtures/vecnet-citation.json +73 -0
  40. data/spec/lib/rof/access_spec.rb +36 -0
  41. data/spec/lib/rof/cli_spec.rb +66 -0
  42. data/spec/lib/rof/collection_spec.rb +90 -0
  43. data/spec/lib/rof/compare_rof_spec.rb +263 -0
  44. data/spec/lib/rof/filters/date_stamp_spec.rb +90 -0
  45. data/spec/lib/rof/filters/file_to_url_spec.rb +70 -0
  46. data/spec/lib/rof/filters/label_spec.rb +94 -0
  47. data/spec/lib/rof/filters/work_spec.rb +87 -0
  48. data/spec/lib/rof/ingest_spec.rb +117 -0
  49. data/spec/lib/rof/ingesters/rels_ext_ingester_spec.rb +62 -0
  50. data/spec/lib/rof/ingesters/rights_metadata_ingester_spec.rb +114 -0
  51. data/spec/lib/rof/osf_to_rof_spec.rb +76 -0
  52. data/spec/lib/rof/translate_csv_spec.rb +109 -0
  53. data/spec/lib/rof/utility_spec.rb +64 -0
  54. data/spec/lib/rof_spec.rb +14 -0
  55. data/spec/spec_helper.rb +11 -11
  56. metadata +283 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6145cfdc51338425ae4adccfd527266debd1c608
4
- data.tar.gz: 04df2645bb27e387a870448c1e9e4adcea60cc63
3
+ metadata.gz: 33761b71b6e080540bbab28fa0516ae9f327b496
4
+ data.tar.gz: d8dc2c60c38574a5a872622f5a0e7bdfdf7ededd
5
5
  SHA512:
6
- metadata.gz: 4ec14945f0f0a5ecd2e7026b680a7fb0cc991f6489bb9e681aefd55b28425f750c79ca0b2c602e6f67334ee840f97993b71665887ad3b1ac103487abdceaa4d2
7
- data.tar.gz: 8206903744fd358fdd419c9313fcb45b00001e464ea364a36e48d2da6da571b82d9550907b9e5f5bfeab24f6290522e3ef001d9df7f660b5e47e13030ec37a3f
6
+ metadata.gz: baa4c3529a273e6de117e1070fb7fde0eb70a50c398238b95243eae326ea34a9ba4fd2200c59b11b332b93e061cddb1f2947d9d56de0c5d3794141f875665f51
7
+ data.tar.gz: 9e78181e99a5516a1389b8895a74c51b20a790f1e3fa7fa38563d1e5ac2cf9e98370457d8d2255be78cb792cbcc2db60e4f502a47cf70efee9bfbc8e8e6ad43b
@@ -1 +1 @@
1
- 2.0.0
1
+ 2.2.2
@@ -1,12 +1,22 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "1.9.3"
4
3
  - "2.0.0"
4
+ - "2.1.1"
5
+ - "2.2.4"
6
+ - "2.3.0"
5
7
 
6
- script: "rspec"
8
+ matrix:
9
+ allow_failures:
10
+ - rvm: "2.3.0"
11
+ - rvm: "2.2.4"
12
+
13
+ script: "bundle exec rspec"
7
14
 
8
15
  notifications:
9
16
  irc: "irc.freenode.org#ndlib"
10
17
 
11
18
  before_install:
12
19
  - gem install bundler
20
+
21
+ sudo: false
22
+ cache: bundler
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :test do
7
+ gem 'byebug'
7
8
  end
8
9
 
9
10
  group :doc do
data/README.md CHANGED
@@ -1,3 +1,90 @@
1
1
  # Raw Object Format
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rof.png)](http://badge.fury.io/rb/rof)
4
+
5
+ This is a pilot project to produce an intermediate data format that makes the
6
+ bulk ingest of data into the Fedora Commons repository software simple. While the goal
7
+ is to provide as simple of a format as possible, some affordances are made for
8
+ defining standard datastreams used by Hydra project front-ends, such as the
9
+ `rightsMetadata` datastream.
10
+
11
+ See `spec/fixtures/vecnet-citation.json` as a sample two object model.
12
+ An overview of the format is in [bulk-ingest.md](bulk-ingest.md).
13
+
14
+ Sample command line usage:
15
+
16
+ ```
17
+ $ bin/rof ingest --fedora 'http://localhost:8983/fedora' --user fedoraAdmin:fedoraAdmin spec/fixtures/vecnet-citation.json
18
+ 1. Ingesting vecnet:d217qs82g ...ok. 0.882s
19
+ 2. Ingesting vecnet:h415pf50x ...ok. 0.283s
20
+ Total time 1.165s
21
+ 0 errors
22
+ ```
23
+
24
+ ROF does more than just ingesting.
25
+ Should an object already exist in Fedora, it will be updated to match what is provided in the source file.
26
+ (However, this only applies to datastreams which are mentioned in the source file. Unmentioned datastreams
27
+ are untouched).
28
+
29
+ If the fedora path and user are omitted then rof lints the json file.
30
+
31
+ ```
32
+ $ bin/rof ingest spec/fixtures/vecnet-citation.json
33
+ 1. Verifying vecnet:d217qs82g ...ok. 0.108s
34
+ 2. Verifying vecnet:h415pf50x ...ok. 0.002s
35
+ Total time 0.111s
36
+ 0 errors
37
+ ```
38
+
39
+ There is a filter which will assign objects identifiers. This requires an external [noids](https://github.com/ndlib/noids) service to provide the identifiers.
40
+ See [labels.md](labels.md).
41
+
42
+ ```
43
+ $ bin/rof filter label spec/fixtures/label.json --noids localhost:13001:test-pool --prefix temp
44
+ [
45
+ {
46
+ "type": "fobject",
47
+ "pid": "temp:0k225999n60"
48
+ },
49
+ {
50
+ "type": "fobject",
51
+ "rels-ext": {
52
+ "partOf": [
53
+ "temp:0k225999n60"
54
+ ],
55
+ "refines": [
56
+ "temp:0r96736668t"
57
+ ]
58
+ },
59
+ "pid": "temp:0p096682x75"
60
+ },
61
+ {
62
+ "type": "fobject",
63
+ "pid": "temp:0r96736668t",
64
+ "rels-ext": {
65
+ "partOf": [
66
+ "temp:0r96736668t",
67
+ "temp:0k225999n60",
68
+ "another"
69
+ ]
70
+ }
71
+ }
72
+ ]
73
+ ```
74
+
75
+ It is envisioned that there could be higher level objects, and that the ingesting into fedora done by this utility
76
+ will be simply the final step of many.
77
+ Other ideas for transformations:
78
+
79
+ * A service to expand higher-level objects, say an `image-collection`, into a sequence of `fobjects`.
80
+ * The ability to run file characterizations and create derivatives before ingest.
81
+
82
+ # Other
83
+
84
+ Since the files are JSON, any tool for working with JSON files will work with these.
85
+ For example, the [jq](http://stedolan.github.io/jq/) tool makes it easy to extract all
86
+ the `pid` field from every object in a file, and return it as a JSON array:
87
+
88
+ ```
89
+ jq '[.[]|.pid]' < spec/fixtures/vecnet-citation.json
90
+ ```
@@ -0,0 +1 @@
1
+ 2.2.2
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby -Ilib
2
+
3
+ require 'rof'
4
+ require 'optparse'
5
+ require 'json'
6
+
7
+ opt = OptionParser.new do |opts|
8
+ opts.banner = %q{Usage: csv_to_rof
9
+ Reads a CSV file from stdin.
10
+ Writes a ROF file to stdout.
11
+
12
+ In case of an error, a message is written to stderr and the program
13
+ exits with a non-zero status.
14
+ }
15
+ end
16
+
17
+ opt.parse!
18
+
19
+ if ARGV.length != 0
20
+ abort opt.help
21
+ end
22
+
23
+ STDIN.set_encoding("UTF-8")
24
+ csv_contents = STDIN.read
25
+ rof = ROF::TranslateCSV.run(csv_contents)
26
+ puts JSON.pretty_generate(rof)
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby -Ilib
2
+
3
+ require 'rof'
4
+ require 'optparse'
5
+
6
+ # assign default parameter values
7
+ fedora_info = {}
8
+ config = {}
9
+ file_path = STDOUT
10
+ config['download'] = false
11
+ config['inline'] = false
12
+ config['download_path'] = '.'
13
+
14
+ # parse the command line
15
+ #
16
+ opt = OptionParser.new do |opts|
17
+ opts.banner = %q{Usage: fedora_to_rof --fedora URL --user STRING --output DIR [--download | --inline] PID [PID2 ...]
18
+
19
+ Read the given PIDs from the given Fedora 3 instance, and then output them as
20
+ ROF objects. By default output will be STDOUT, pass a directory in `--output`
21
+ to save them as files. Datastreams smaller than 1024 bytes are added to the ROF
22
+ file. Larger ones may either be included inline or saved as auxillary files.
23
+ Use `--inline` to include them inline and use `--download` to save them as
24
+ files. The files will have a name in the form `<pid>-<dsname>`.
25
+ }
26
+
27
+ opts.on("", "--fedora URL", "Base Fedora URL (including port number)") do |url|
28
+ fedora_info[:url] = url
29
+ end
30
+ opts.on("", "--user STRING", "Username and password (colon separated) for fedora") do |u|
31
+ fedora_info[:user], fedora_info[:password] = u.split(':')
32
+ end
33
+ opts.on("", "--download DIRECTORY", "Save datastreams >1K in size to files (defaults to false)") do |directory|
34
+ config['download'] = true
35
+ config['download_path'] = directory
36
+ end
37
+ opts.on("", "--inline", "Include datastreams >1K in size in ROF output (defaults to false)") do
38
+ config['inline'] = true
39
+ end
40
+ opts.on("", "--outfile FILENAME", "File to save ROF to") do |output|
41
+ file_path = output
42
+ end
43
+ end
44
+
45
+ opt.parse!
46
+
47
+ pids = ARGV
48
+ fedora_info = nil if fedora_info.empty?
49
+
50
+ # without a fedora and a pid, there is no reason to proceed
51
+ if fedora_info == nil || pids.empty? then
52
+ STDERR.puts opt.help
53
+ exit 1
54
+ end
55
+
56
+ # perform conversion
57
+ ROF::CLI.convert_to_rof(pids, fedora_info, file_path, config)
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby -Ilib
2
+ #Command Line Tool to convert and Open Science Farmework Archive Package to an ROF file
3
+
4
+ require 'rof'
5
+ require 'optparse'
6
+
7
+ # assign default parameter values
8
+ config = {}
9
+ file_path = STDOUT
10
+ config['project_file'] = './osf_projects'
11
+ config['package_dir'] = './FROM_OSF'
12
+ config['output_dir'] = '.'
13
+
14
+ # parse the command line
15
+ #
16
+ opt = OptionParser.new do |opts|
17
+ opts.banner = %q{Usage: osf_to_rof --projectfile file --packagedir DIR --outputdir DIR
18
+ }
19
+
20
+ opts.on("", "--project_file project_file", "osf_projects file provided by requestor (required)") do |project_file|
21
+ config['project_file'] = project_file
22
+ end
23
+ opts.on("", "--package_dir package_dir", "directory OSF packages were downloaded (defaults to ./FROM_OSF)") do |package_dir|
24
+ config['package_dir'] = package_dir
25
+ end
26
+ opts.on("", "--output_dir output_dir", "Directory to save ROF to (defaults to .)") do |output_dir|
27
+ config['output_dir'] = output_dir
28
+ end
29
+ end
30
+
31
+ opt.parse!
32
+
33
+ # without a project file there is no reason to proceed
34
+ if !FileTest.exists?(config['project_file']) then
35
+ STDERR.puts opt.help
36
+ exit 1
37
+ end
38
+
39
+ # perform conversion
40
+ ROF::CLI.osf_to_rof(config)
data/bin/rof ADDED
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env ruby -Ilib
2
+
3
+ require 'rof'
4
+ require 'optparse'
5
+
6
+ fedora_info = {}
7
+ noids = {}
8
+ prefix = nil
9
+ bendo_info = nil
10
+ search_path = ["."]
11
+ opt = OptionParser.new do |opts|
12
+ opts.banner = %q{Usage: rof [options] <command> <input files>
13
+ command is one of:
14
+ compare
15
+ ingest
16
+ validate
17
+ filter <filter name>
18
+
19
+ Filtering sends transformed objects to stdout.
20
+
21
+ Possible filters are:
22
+ bendo, collections, datestamp, file-to-url, label, work}
23
+
24
+ opts.on("", "--fedora URL", "Base Fedora URL") do |url|
25
+ fedora_info[:url] = url
26
+ end
27
+ opts.on("", "--bendo URL", "Base Bendo URL") do |url|
28
+ bendo_info = url
29
+ end
30
+ opts.on("", "--user STRING", "Username and password (colon separated) for fedora") do |u|
31
+ fedora_info[:user], fedora_info[:password] = u.split(':')
32
+ end
33
+ opts.on("", "--noids STRING", "Noids server path and pool name (colon separated)") do |u|
34
+ noids[:noid_server], _, noids[:pool_name] = u.rpartition(':')
35
+ end
36
+ opts.on("", "--prefix STRING", "Prefix for label identifiers") do |s|
37
+ prefix = s
38
+ end
39
+ opts.on("", "--path PATH", "Colon seperated search path for files for ingest or validation. Defaults to the current directory") do |s|
40
+ search_path = s.split(":")
41
+ end
42
+ end
43
+
44
+ opt.parse!
45
+
46
+ fedora_info = nil if fedora_info.empty?
47
+
48
+ case ARGV[0]
49
+ when "compare"
50
+ error_count = ROF::CLI.compare_files(ARGV[1], ARGV[2], STDOUT, fedora_info, bendo_info)
51
+ exit 1 if error_count > 0
52
+ when "ingest", "validate"
53
+ error_count = ROF::CLI.ingest_file(ARGV[1], search_path, STDOUT, fedora_info, bendo_info)
54
+ exit 1 if error_count > 0
55
+ when "filter"
56
+ filter = case ARGV[1]
57
+ when "bendo"
58
+ ROF::Filters::Bendo.new(bendo_info)
59
+ when "collections"
60
+ ROF::Filters::Collections.new
61
+ when "datestamp"
62
+ ROF::Filters::DateStamp.new
63
+ when "file-to-url"
64
+ ROF::Filters::FileToUrl.new
65
+ when "label"
66
+ ROF::Filters::Label.new(prefix, noids)
67
+ when "work"
68
+ ROF::Filters::Work.new
69
+ else
70
+ STDERR.puts "Unknown filter #{ARGV[1]}"
71
+ exit 3
72
+ end
73
+ ROF::CLI.filter_file(filter, ARGV[2], STDOUT)
74
+ else
75
+ STDERR.puts "Unknown command #{ARGV[0]}"
76
+ STDERR.puts opt.help
77
+ exit 3
78
+ end
@@ -0,0 +1,242 @@
1
+ # Bulk Ingest
2
+
3
+ Q. What does this hope to be?
4
+ A. An intermediate representation we can use to process ingests to fedora. The
5
+ idea is that we can accept any crazy format for bulk data and translate it into
6
+ this format. Then another piece can load this format into Fedora. Perhaps it
7
+ can also be used as an export format.
8
+
9
+ Q. What is its name?
10
+ A. I don't know. I was calling it ROF for Raw Object Format. I'm open to
11
+ suggestions. Jeremy?
12
+
13
+ Q. What is it?
14
+ A. ROF hopes to support many levels of abstraction. To begin with, it only
15
+ specifies a low level format based around the Fedora object model, whereby one
16
+ lists all the data streams which constitute each object. It handles some mild
17
+ translating for hydra rights metadata, but otherwise it is as dumb as a box of
18
+ rocks. It is designed to be easy for machines to process (NOT humans) and is
19
+ uses JSON format as its base. I see it supporting more abstract data elements,
20
+ say "article + dataset" in time.
21
+
22
+ Q. At what level does it hope to model objects? That is, why not just use FOXML?
23
+ A. Ideally, this will model our content using our data models. Unfortunately,
24
+ our data models are not well defined, and are still changing. Because of this,
25
+ if we did model the content at the data model level we would need to change the
26
+ loader whenever we add a new model. To begin with, ROF will describe what items
27
+ should look like in Fedora, in terms of Fedora objects. FOXML is too detailed
28
+ for our purpurses since it includes previous versions of content and an audit
29
+ log. Additionally, Hydra only uses a subset of Fedora. ROF will focus on the
30
+ parts which are important to us. And then we can extend it over time to handle
31
+ more abstract objects.
32
+
33
+ Q. So what are the problems with this format?
34
+ A. Ideally the interchange format should match our semantic object model, not
35
+ the way things are laid out in fedora. I see this being addressed in time.
36
+ Also, this is another format for which we will need to develop tools to
37
+ support.
38
+
39
+ Q. Ok, enough already, what is the actual format?
40
+ A. It uses JSON, so a valid ROF file will also be a valid JSON document. The
41
+ reverse is not true, though. These are the restrictions.
42
+
43
+
44
+ 1. A ROF file consists of a top-level JSON array. Each element in the array
45
+ is a JSON object.
46
+
47
+ 2. The only essential property of the object is "type", which indicates the
48
+ type of the record. The other fields depend on the type field. Right now there
49
+ is only the type "fobject". As the content models are developed, we can add
50
+ more types to represent the models.
51
+
52
+ The "fobject" type represents a basic fedora object. Each "fobject" record
53
+ represents a single fedora object. It recognizes the following additional
54
+ fields. A star is a wildcard and represents any sequence of characters.
55
+
56
+ Field | Description
57
+ ----------|--------------
58
+ pid | The pid to use for the object. If it includes a prefix, e.g. "vecnet:12bc34g", then that is the objects fedora id. It it doesn'thave a prefix, then the prefix "und:" is added.
59
+ rights | The hydra rights of this object. Takes an object. See §Rights below.
60
+ rels-ext | The rels-ext data stream of this object. Takes an object. See §Rels-ext below.
61
+ metadata | Contents for the 'descMetadata' data stream. Takes an object. It is given in JSON-LD, and translated to N3 format to be saved into fedora.
62
+ *-file | Gives a filename to save as the contents of a data stream given. Takes a string. This overwrites the previous content. For example, the field 'hello-file' will save the file's contents into the data stream 'hello'.
63
+ *-meta | Gives the fedora metadata for a given data stream. Takes an object. See §Meta below.
64
+ * | Assigns the content directly to the named data stream. Takes a string.
65
+
66
+
67
+ # Rights
68
+
69
+ Rights are given as a object with the keys "discover", "discover-groups",
70
+ "read", "read-groups", "edit", and "edit-groups". Each key takes an array of strings,
71
+ which are taken to be a list of group or user names.
72
+ In Hydra rightsMetadata, the groups "public" and "registered" have special meaning.
73
+ The key "embargo-date", if provided, will be saved. It must be in the form _year-month-day_, e.g. "2015-01-24" for January 24, 2015.
74
+ The semantics are, the item is considered viewable only by the editors until the embargo date, after which the rest of the rights take effect.
75
+ ROF does *not* validate the date provided is in the correct format.
76
+
77
+ Example: This object is viewable by anyone and editable only by the user `dbrower`.
78
+ ````json
79
+ {
80
+ "read-groups" : ["public"],
81
+ "edit" : ["dbrower"]
82
+ }
83
+ ````
84
+
85
+ Example: This object is embargoed until Jan 24, 2015. Before that date it is viewable and editable only by user `dbrower`, afterward it is viewable by any logged in user and editable by user `dbrower`.
86
+ ````json
87
+ {
88
+ "read-groups" : ["registered"],
89
+ "edit" : ["dbrower"],
90
+ "embargo-date" : "2015-01-24"
91
+ }
92
+ ````
93
+
94
+ # Rels-Ext
95
+
96
+ Rels-ext are given as an object where each key is a relation, and takes either
97
+ an array of strings. The strings are fedora object pids, which indicate which
98
+ objects this one is connected to.
99
+
100
+
101
+ Example:
102
+ ````json
103
+ {
104
+ "isMemberOf" : ["xv57n93k"],
105
+ "relatedTo": ["user:12345"]
106
+ }
107
+ ````
108
+
109
+ More complicated relationships can be defined by using a JSON-LD `@context` element:
110
+
111
+ ````json
112
+ {
113
+ "@context" : {
114
+ "hydra" : "http://project-hydra.org"
115
+ },
116
+ "hydra:hasEditor" : ["user:12345"]
117
+ }
118
+ ````
119
+
120
+ # Meta
121
+ The Metadata field is not for an object's descriptive metadata, rather it is
122
+ for the metadata associated to a specific fedora data stream. The data is given
123
+ as pairs, the possible pairs are listed below, as well as the defaults. (TODO:
124
+ this list is incomplete.)
125
+
126
+ Field Name Default Description
127
+ mime-type "text/plain" The mime-type of this data stream. The default is
128
+ adjusted for the special data streams of
129
+ "descMetadata", "rightsMetadata" and "RELS-EXT".
130
+ label "" The label for this datastream
131
+ versioned true Whether this data stream's content is versioned.
132
+ storage "M" The Fedora storage class of this data stream.
133
+ checksum "SHA-1" What checksum to use, or empty string to turn off.
134
+
135
+
136
+ # Example ROF File
137
+ This is not normative. There are probably errors. The JSON-LD sections are
138
+ likely wrong.
139
+
140
+ ```json
141
+ [{
142
+ "type" : "fobject",
143
+ "pid" : "vecnet:d217qs82g",
144
+ "af-model" : "Citation",
145
+ "rights" : {
146
+ "read-groups" : ["public"],
147
+ "edit" : ["vecnet_batchuser"]
148
+ },
149
+ "metadata" : {
150
+ "@context" : {
151
+ "dc" : "http://purl.org/dc/terms/",
152
+ "rdfs" : "http://www.w3.org/2000/01/rdf-schema#"
153
+ },
154
+ "dc:title" : "Molecular systematics and insecticide resistance in the major African malaria vector Anopheles funestus",
155
+ "dc:creator" : ["Coetzee, M.", "Koekemoer, L. L."],
156
+ "dc:identifier" : ["doi:10.1146/annurev-ento-120811-153628", "issn:1545-4487 (Electronic)", "issn:0066-4170 (Linking)", "23317045"],
157
+ "dc:description" : "Anopheles funestus is one of three major African vectors of malaria. Its distribution extends over much of the tropics and subtropics wherever suitable swampy breeding habitats are present. As with members of the Anopheles gambiae complex, An. funestus shows marked genetic heterogeneity across its range. Currently, two unnamed species are recognized in the group, with molecular and cytogenetic data indicating that more may be present. The control of malaria vectors in Africa has received increased attention in the past decade with the scaling up of insecticide-treated bed nets and indoor residual house spraying. Also in the past decade, the frequency of insecticide-resistant mosquitoes has increased exponentially. Whether this increase is in response to vector control initiatives or because of insecticide use in agriculture is debatable. In this article we examine the progress made on the systematics of the An. funestus group and review research on insecticide resistance and its mechanisms.",
158
+ "dc:language" : "eng",
159
+ "dc:type" : "Article",
160
+ "dc:source" : "Annual review of entomology",
161
+ "dc:references" : "Molecu2013",
162
+ "dc:bibliographicCitation" : "Annu Rev Entomol 58, 393-412. (2013)",
163
+ "rdf:seeAlso" : "http://www.ncbi.nlm.nih.gov/pubmed/23317045",
164
+ "dc:created" : "2013",
165
+ "dc:modified" : {
166
+ "@value":"2014-03-17Z",
167
+ "@type":"http://www.w3.org/2001/XMLSchema#date"
168
+ },
169
+ "rdf:domain" : "Citation"
170
+ },
171
+ "properties-meta" : {
172
+ "mime-type" : "text/xml"
173
+ },
174
+ "properties" : "<fields><depositor>vecnet_batchuser</depositor></fields>"
175
+ },
176
+ {
177
+ "type" : "fobject",
178
+ "pid" : "vecnet:h415pf50x",
179
+ "af-model" : "CitationFile",
180
+ "rights" : {
181
+ "read-groups" : ["registered"],
182
+ "edit" : ["vecnet_batchuser"]
183
+ },
184
+ "metadata" : {
185
+ "@context" : {
186
+ "dc" : "http://purl.org/dc/terms/",
187
+ "rdfs" : "http://www.w3.org/2000/01/rdf-schema#"
188
+ },
189
+ "dc:type" : "CitationFile",
190
+ "dc:dateSubmitted" : {
191
+ "@value" : "2014-03-17Z",
192
+ "@type" : "http://www.w3.org/2001/XMLSchema#date"
193
+ },
194
+ "dc:modified" : {
195
+ "@value" : "2014-03-17Z",
196
+ "@type" : "http://www.w3.org/2001/XMLSchema#date"
197
+ },
198
+ "dc:creator" : [ "Vecnet Batchuser", "Maureen Coetzee and Lizette L. Koekemoer" ],
199
+ "dc:title" : "Molecular Systematics and Insecticide Resistance in the Major African Malaria Vector Anopheles funestus"
200
+ },
201
+ "rels-ext" : {
202
+ "isPartOf" : ["vecnet:d217qs82g"]
203
+ },
204
+ "properties" : "<fields><depositor>vecnet_batchuser</depositor></fields>",
205
+ "properties-meta" : {
206
+ "mime-type": "text/xml",
207
+ "checksum" : ""
208
+ },
209
+ "content-meta" : {
210
+ "mime-type": "application/pdf",
211
+ "label" : "5772.pdf",
212
+ "checksum": ""
213
+ },
214
+ "content-file" : "/opt/citations/pdf/5772.pdf",
215
+ "full_text-file" : "/opt/citations/text/5772.txt",
216
+ "full_text-meta" : {
217
+ "label" : "File Datastream",
218
+ "checksum" : ""
219
+ },
220
+ "characterization-meta" : {
221
+ "mime-type" : "text/xml"
222
+ },
223
+ "thumbnail-meta" : {
224
+ "mime-type" : "image/png",
225
+ "label" : "File Datastream",
226
+ "checksum" : ""
227
+ },
228
+ "thumbnail-file" : "/opt/citations/thumb/5772.png"
229
+ }]
230
+ ````
231
+
232
+
233
+ # Extensions
234
+ I would call a ROF file containing only "fobjects" and not using labels a
235
+ level-0 ROF file. Higher level ROF files would introduce more complicated and
236
+ abstract structures, which can ultimately be reduced to a level-0 file by
237
+ processing. Then the level-0 file can be directly ingested into Fedora with no
238
+ thought whatsoever.
239
+
240
+ We can even export fedora objects as ROF files. These files would not retain
241
+ any previous versions of data streams or the audit history, since ROF does not
242
+ capture the entirety of FOXML.