hydra-collections 7.0.0 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/Changelog.md +5 -4
  4. data/Gemfile +2 -1
  5. data/README.md +2 -11
  6. data/app/controllers/concerns/hydra/collections_controller_behavior.rb +18 -8
  7. data/app/helpers/collections_helper.rb +6 -2
  8. data/app/models/concerns/hydra/collections/metadata.rb +2 -2
  9. data/app/views/collections/_button_remove_from_collection.html.erb +4 -6
  10. data/app/views/collections/_document_header.html.erb +1 -4
  11. data/app/views/collections/_form.html.erb +7 -7
  12. data/app/views/collections/_search_form.html.erb +4 -4
  13. data/app/views/collections/show.html.erb +29 -5
  14. data/app/views/layouts/collections.html.erb +0 -1
  15. data/hydra-collections.gemspec +1 -0
  16. data/lib/hydra-collections.rb +0 -1
  17. data/lib/hydra/collections/version.rb +1 -1
  18. data/solr/config/_rest_managed.json +3 -0
  19. data/solr/config/admin-extra.html +31 -0
  20. data/solr/config/elevate.xml +36 -0
  21. data/solr/config/mapping-ISOLatin1Accent.txt +246 -0
  22. data/solr/config/protwords.txt +21 -0
  23. data/solr/config/schema.xml +372 -0
  24. data/solr/config/scripts.conf +24 -0
  25. data/solr/config/solrconfig.xml +300 -0
  26. data/solr/config/spellings.txt +2 -0
  27. data/solr/config/stopwords.txt +58 -0
  28. data/solr/config/stopwords_en.txt +58 -0
  29. data/solr/config/synonyms.txt +31 -0
  30. data/solr/config/xslt/example.xsl +132 -0
  31. data/solr/config/xslt/example_atom.xsl +67 -0
  32. data/solr/config/xslt/example_rss.xsl +66 -0
  33. data/solr/config/xslt/luke.xsl +337 -0
  34. data/spec/controllers/catalog_controller_spec.rb +6 -14
  35. data/spec/controllers/collections_controller_spec.rb +67 -61
  36. data/spec/controllers/other_collections_controller_spec.rb +1 -1
  37. data/spec/controllers/selects_collections_spec.rb +33 -33
  38. data/spec/factories.rb +10 -1
  39. data/spec/factories/users.rb +1 -11
  40. data/spec/features/create_collection_spec.rb +17 -0
  41. data/spec/helpers/collections_helper_spec.rb +44 -35
  42. data/spec/models/collection_spec.rb +8 -10
  43. data/spec/spec_helper.rb +9 -0
  44. data/spec/test_app_templates/app/views/catalog/_sort_and_per_page.html.erb +2 -3
  45. data/spec/test_app_templates/lib/generators/test_app_generator.rb +0 -4
  46. data/spec/views/collections/_form.html.erb_spec.rb +15 -0
  47. data/spec/views/collections/show.html.erb_spec.rb +1 -1
  48. data/tasks/hydra-collections-dev.rake +6 -6
  49. metadata +37 -14
  50. data/app/helpers/collections_search_helper.rb +0 -11
  51. data/app/models/concerns/hydra/collections/actions.rb +0 -22
  52. data/config/jetty.yml +0 -6
  53. data/lib/hydra/collections/collectible.rb +0 -25
  54. data/spec/helpers/collections_search_helper_spec.rb +0 -16
  55. data/spec/lib/collectible_spec.rb +0 -39
  56. data/spec/test_app_templates/config/blacklight.yml +0 -22
  57. data/tasks/jetty.rake +0 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ebe55db03846ed51118593543505434956f99125
4
- data.tar.gz: db11d0ff1b2513f376e5e381eba5bf32e1bebdfb
3
+ metadata.gz: 5f0a6d73f747ff5aaa1026b064e55730c1605f36
4
+ data.tar.gz: 8e5a8f2069f9fc74e661eb2389a4ea6e0b164421
5
5
  SHA512:
6
- metadata.gz: 4798abcfddaaabe9bb8f63f3cc82bc214f70ead4a5f80a04a2388dc166ed1f8985e96ecb2b672c5f30d260b636e7aa8a5fdb35874b37cadf77ce4b497cf59b2d
7
- data.tar.gz: 730fea9bd4c25e8887373e7c04b67be671c5a0d59f495f39b7a36760995471cebbcb73f4ebbaf30d1caafc294319fb9d6e2f99b155c4b7d2af4ed58bb618cf1a
6
+ metadata.gz: fd07c424bb502667e7cb2cb48aba65de9e14785df444d16a816a7d4169c81a886aa0aaff8e2fcc7ce754fbec0651e7fcf2de3b0e8ee03355d625c21b4db08a19
7
+ data.tar.gz: 045f31a8e3b174596bcc985be730f642dc3b7beea5b1fb134758fc67050ecde128b9158ffb5706c1f5a3dce138148600c963527bd496fbbe87daccd596929bf7
data/.gitignore CHANGED
@@ -19,4 +19,4 @@ test/tmp
19
19
  test/version_tmp
20
20
  tmp
21
21
  .internal_test_app
22
- jetty
22
+ fcrepo4-test-data
@@ -1,4 +1,8 @@
1
- # 6.0.0.rc1
1
+ # 7.0.0
2
+
3
+ * Update to Blacklight 6.0.0 [Justin Coyne]
4
+
5
+ # 6.0.0
2
6
  Hydra::Collections 6.0.0 is the first release that sits atop the Portland Common Data Model. It includes the following changes:
3
7
 
4
8
  * Update for hydra-works 0.2.0 [Justin Coyne]
@@ -6,9 +10,6 @@ Hydra::Collections 6.0.0 is the first release that sits atop the Portland Common
6
10
  collection [E. Lynette Rayle]
7
11
  * Pass the document_counter to index_default [Justin Coyne]
8
12
  * Update changelog with v6.0.0.alpha entry [Michael J. Giarlo]
9
-
10
- # 6.0.0.alpha
11
-
12
13
  * Depend upon hydra-works 0.1.0, which brings PCDM-related dependencies. Collections defined by Hydra::Collections are now PCDM collections.
13
14
  * Add ParentCollectionAssociation#count_records to calculate the number of a collection's members.
14
15
  * Change the default join column for querying members of a collection (was `hasCollectionMember_ssim`, is now `member_ids_ssim`)
data/Gemfile CHANGED
@@ -8,7 +8,8 @@ group :development, :test do
8
8
  gem "factory_girl_rails"
9
9
  gem 'devise'
10
10
  gem 'capybara'
11
- gem 'jettywrapper'
11
+ gem 'fcrepo_wrapper'
12
+ gem 'solr_wrapper'
12
13
  gem 'byebug', require: false unless ENV['CI']
13
14
  gem 'coveralls', require: false
14
15
  gem 'rspec-activemodel-mocks'
data/README.md CHANGED
@@ -2,10 +2,6 @@
2
2
 
3
3
  Add collections to your Hydra application. These collections are typically created by depositors (instead of librarians or curators). Any collectible item can belong to many different collections. The collection does not confer access rights onto any of the members of the collections.
4
4
 
5
- ## CAVEAT (READ THIS)
6
-
7
- If you do **not** require PCDM, or do not know what PCDM is, please disregard this README (which is for a release candidate version of Hydra::Collections that relies upon a new stack of gems in support of PCDM) and use [Hydra::Collections' latest stable branch README](https://github.com/projecthydra/hydra-collections/blob/5.0-stable/README.md) instead.
8
-
9
5
  ## Installation
10
6
 
11
7
  Add this line to your application's Gemfile:
@@ -124,7 +120,7 @@ Add `updates-batches` class to your button for submitting the batch
124
120
  Example:
125
121
  ```erb
126
122
  <%= button_to label, collections.collection_path(collection_id), method: :put,
127
- class: "btn btn-primary updates-collection submits-batches collection-update",
123
+ class: "btn btn-primary updates-collection submits-batches collection-update",
128
124
  'data-behavior'=>'hydra-collections', id: 'hydra-collection-update' %>
129
125
  ```
130
126
 
@@ -143,12 +139,7 @@ In order to make modifications to the gem code and run the tests, clone the repo
143
139
 
144
140
  ```
145
141
  $ bundle install
146
- $ rake jetty:unzip
147
- $ rake jetty:config
148
- $ rake jetty:start
149
- $ rake engine_cart:clean
150
- $ rake engine_cart:generate
151
- $ rake spec
142
+ $ bundle exec rake ci
152
143
  ```
153
144
 
154
145
  ## License
@@ -130,22 +130,32 @@ module Hydra
130
130
  protected
131
131
 
132
132
  def collection_params
133
- params.require(:collection).permit(:part_of, :contributor, :creator, :title,
134
- :description, :publisher, :date_created, :subject, :language, :rights,
135
- :resource_type, :identifier, :based_near, :tag, :related_url, :members)
133
+ params.require(:collection).permit(:part_of, :contributor, :creator,
134
+ :publisher, :date_created, :subject, :language, :rights,
135
+ :resource_type, :identifier, :based_near, :tag, :related_url, :members,
136
+ title: [], description: [])
136
137
  end
137
138
 
138
139
  # Queries Solr for members of the collection.
139
140
  # Populates @response and @member_docs similar to Blacklight Catalog#index populating @response and @documents
140
141
  def query_collection_members
141
- solr_params = params.symbolize_keys.merge(q: params[:cq])
142
-
143
- # run the solr query to find the collection members
144
- query = collection_member_search_builder.with(solr_params).query
145
- @response = repository.search(query)
142
+ @response = repository.search(query_for_collection_members)
146
143
  @member_docs = @response.documents
147
144
  end
148
145
 
146
+ # @return <Hash> a representation of the solr query that find the collection members
147
+ def query_for_collection_members
148
+ collection_member_search_builder.with(params_for_members_query).query
149
+ end
150
+
151
+ # You can override this method if you need to provide additional inputs to the search
152
+ # builder. For example:
153
+ # search_field: 'all_fields'
154
+ # @return <Hash> the inputs required for the collection member search builder
155
+ def params_for_members_query
156
+ params.symbolize_keys.merge(q: params[:cq])
157
+ end
158
+
149
159
  def collection_member_search_builder_class
150
160
  Hydra::Collections::MemberSearchBuilder
151
161
  end
@@ -1,5 +1,9 @@
1
1
  # View Helpers for Hydra Collections functionality
2
2
  module CollectionsHelper
3
+ def has_collection_search_parameters?
4
+ !params[:cq].blank?
5
+ end
6
+
3
7
  # Displays the Collections create collection button. Put this in your search result page template. We recommend putting it in catalog/_sort_and_per_page.html.erb
4
8
  def button_for_create_collection(label = 'Create Collection')
5
9
  render '/collections/button_create_collection', label: label
@@ -15,8 +19,8 @@ module CollectionsHelper
15
19
  render '/collections/button_for_delete_collection', collection: collection, label: label, confirm: confirm
16
20
  end
17
21
 
18
- def button_for_remove_from_collection(document, label = 'Remove From Collection')
19
- render '/collections/button_remove_from_collection', label: label, document: document
22
+ def button_for_remove_from_collection(collection, document, label = 'Remove From Collection')
23
+ render '/collections/button_remove_from_collection', collection: collection, label: label, document: document
20
24
  end
21
25
 
22
26
  def button_for_remove_selected_from_collection(collection, label = 'Remove From Collection')
@@ -16,11 +16,11 @@ module Hydra::Collections
16
16
  index.as :stored_searchable, :facetable
17
17
  end
18
18
 
19
- property :title, predicate: RDF::Vocab::DC.title, multiple: false do |index|
19
+ property :title, predicate: RDF::Vocab::DC.title do |index|
20
20
  index.as :stored_searchable, :sortable
21
21
  end
22
22
 
23
- property :description, predicate: RDF::Vocab::DC.description, multiple: false do |index|
23
+ property :description, predicate: RDF::Vocab::DC.description do |index|
24
24
  index.type :text
25
25
  index.as :stored_searchable
26
26
  end
@@ -1,6 +1,4 @@
1
- <%#= button_to label, , :class=>"btn btn-primary collection-remove", 'data-behavior'=>'hydra-collections-remove', members:"delete", batch_document_ids:[document.id] %>
2
-
3
- <%= form_for @collection, url:collections.collection_path(@collection.id), :method=>:put, as:'collection' do |f| %>
4
- <%= single_item_action_remove_form_fields(f,document) %>
5
- <%= f.submit label, :class => "btn btn-primary collection-remove" %>
6
- <% end %>
1
+ <%= form_for collection, url: collections.collection_path(collection), method: :put, as: 'collection' do |f| %>
2
+ <%= single_item_action_remove_form_fields(f, document) %>
3
+ <%= f.submit label, class: "btn btn-primary collection-remove" %>
4
+ <% end %>
@@ -1,12 +1,9 @@
1
-
2
1
  <% # header bar for doc items in index view -%>
3
2
  <div class="documentHeader clearfix">
4
-
5
3
  <% # main title container for doc partial view -%>
6
4
  <h5 class="index_title"><%= t('blacklight.search.documents.counter', :counter => (document_counter + 1 + @response.params[:start].to_i)) %><%= link_to_document document, :label=>document_show_link_field(document), :counter => (document_counter + 1 + @response.params[:start].to_i) %></h5>
7
5
 
8
6
  <div class="documentFunctions span2">
9
- <%= button_for_remove_from_collection(document) %>
7
+ <%= button_for_remove_from_collection(@collection, document) %>
10
8
  </div>
11
9
  </div>
12
-
@@ -14,17 +14,17 @@
14
14
  <% end %>
15
15
 
16
16
  <div class="field">
17
- <%= f.label :title %><br />
18
- <%= f.text_field :title %>
17
+ <%= label_tag 'collection_title', 'Title' %><br />
18
+ <%= text_field_tag 'collection[title][]', nil, id: 'collection_title' %>
19
19
  </div>
20
-
20
+
21
21
  <div class="field">
22
- <%= f.label :description %><br />
23
- <%= f.text_area :description %>
22
+ <%= label_tag 'collection_description', 'Description' %><br />
23
+ <%= text_area_tag 'collection[description][]', nil, id: 'collection_description' %>
24
24
  </div>
25
-
25
+
26
26
  <%= hidden_collection_members %>
27
-
27
+
28
28
  <div class="actions">
29
29
  <%= f.submit %>
30
30
  </div>
@@ -1,9 +1,9 @@
1
1
  <div style="float: right;" >
2
- <%= form_for([collections, @collection] , :method => :get, :class => "well form-search") do |f| %>
2
+ <%= form_for [collections, @collection], method: :get, class: "well form-search" do |f| %>
3
3
 
4
- <label class="accessible-hidden">Search Collection <%=@collection.title %></label>
5
- <%= text_field_tag :cq, params[:cq], :class => "collection-query", :placeholder => "Search Collection", :size => '30', :type => "search", :id => "collection_search" %>
6
- <%= hidden_field_tag :sort, params[:sort], :id => 'collection_sort' %>
4
+ <label class="accessible-hidden">Search Collection <%= @collection.title.first %></label>
5
+ <%= text_field_tag :cq, params[:cq], class: "collection-query", placeholder: "Search Collection", size: '30', type: "search", id: "collection_search" %>
6
+ <%= hidden_field_tag :sort, params[:sort], id: 'collection_sort' %>
7
7
  <%= render_hash_as_hidden_fields(search_state.params_for_search.except(:cq, :sort, :qt, :page)) %>
8
8
  <button type="submit" class="btn btn-primary" id="collection_submit"><i class="icon-search"></i> Go</button>
9
9
  <% end %>
@@ -1,5 +1,29 @@
1
- <h1><%=@collection.title%><h1>
2
- <h3><%=@collection.description%> </h3>
3
- <h3><u>Contained Files</u></h3>
4
- <%= render 'search_form'%>
5
- <%= render 'document_list', documents: @member_docs %>
1
+ <div id="sidebar" class="col-md-3 col-sm-4">
2
+ <%= render 'search_sidebar' %>
3
+ </div>
4
+
5
+ <div id="content" class="col-md-9 col-sm-8">
6
+ <div itemscope itemtype="http://schema.org/CollectionPage" class="row">
7
+ <header>
8
+ <h1><%= @collection.title.first %></h1>
9
+ <p class="collection_description"><%= Array(@collection.description).join("\n") %></p>
10
+ </header>
11
+ </div>
12
+
13
+ <%= render 'sort_and_per_page' %>
14
+
15
+
16
+ <div>
17
+ <!-- Use CSS class h2 rather than HTML h2 tag to allow header and search box to align vertically -->
18
+ <span class="h2">
19
+ <% if has_collection_search_parameters? %>
20
+ <%= "Search Results within this Collection" %>
21
+ <% else %>
22
+ <%= "Items in this Collection" %>
23
+ <% end %>
24
+ </span>
25
+ <%= render 'search_form' %>
26
+ </div>
27
+
28
+ <%= render_document_index @member_docs %>
29
+ </div>
@@ -17,7 +17,6 @@
17
17
  <![endif]-->
18
18
 
19
19
  <title><%= render_page_title %></title>
20
- <%= opensearch_description_tag application_name, opensearch_catalog_url(:format => 'xml') %>
21
20
  <%= favicon_link_tag 'favicon.ico' %>
22
21
  <%= stylesheet_link_tag "application", media: "all" %>
23
22
  <%= javascript_include_tag "application" %>
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency 'hydra-head', '~> 9.1'
22
+ spec.add_dependency 'active-fedora', '~> 9.9'
22
23
  spec.add_dependency 'deprecation', '~> 0.1'
23
24
  spec.add_dependency 'blacklight', '~> 6.0'
24
25
  spec.add_dependency 'hydra-works', '~> 0.4'
@@ -5,7 +5,6 @@ module Hydra
5
5
  module Collections
6
6
  extend ActiveSupport::Autoload
7
7
  autoload :Version
8
- autoload :Collectible
9
8
  autoload :SearchService
10
9
  autoload :AcceptsBatches
11
10
 
@@ -1,5 +1,5 @@
1
1
  module Hydra
2
2
  module Collections
3
- VERSION = "7.0.0"
3
+ VERSION = "8.0.0"
4
4
  end
5
5
  end
@@ -0,0 +1,3 @@
1
+ {
2
+ "initArgs":{},
3
+ "managedList":[]}
@@ -0,0 +1,31 @@
1
+ <!--
2
+ Licensed to the Apache Software Foundation (ASF) under one or more
3
+ contributor license agreements. See the NOTICE file distributed with
4
+ this work for additional information regarding copyright ownership.
5
+ The ASF licenses this file to You under the Apache License, Version 2.0
6
+ (the "License"); you may not use this file except in compliance with
7
+ the License. You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ -->
17
+
18
+ <!-- The content of this page will be statically included into the top
19
+ of the admin page. Uncomment this as an example to see there the content
20
+ will show up.
21
+
22
+ <hr>
23
+ <i>This line will appear before the first table</i>
24
+ <tr>
25
+ <td colspan="2">
26
+ This row will be appended to the end of the first table
27
+ </td>
28
+ </tr>
29
+ <hr>
30
+
31
+ -->
@@ -0,0 +1,36 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <!--
3
+ Licensed to the Apache Software Foundation (ASF) under one or more
4
+ contributor license agreements. See the NOTICE file distributed with
5
+ this work for additional information regarding copyright ownership.
6
+ The ASF licenses this file to You under the Apache License, Version 2.0
7
+ (the "License"); you may not use this file except in compliance with
8
+ the License. You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ -->
18
+
19
+ <!-- If this file is found in the config directory, it will only be
20
+ loaded once at startup. If it is found in Solr's data
21
+ directory, it will be re-loaded every commit.
22
+ -->
23
+
24
+ <elevate>
25
+ <query text="foo bar">
26
+ <doc id="1" />
27
+ <doc id="2" />
28
+ <doc id="3" />
29
+ </query>
30
+
31
+ <query text="ipod">
32
+ <doc id="MA147LL/A" /> <!-- put the actual ipod at the top -->
33
+ <doc id="IW-02" exclude="true" /> <!-- exclude this cable -->
34
+ </query>
35
+
36
+ </elevate>
@@ -0,0 +1,246 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ # Syntax:
14
+ # "source" => "target"
15
+ # "source".length() > 0 (source cannot be empty.)
16
+ # "target".length() >= 0 (target can be empty.)
17
+
18
+ # example:
19
+ # "??" => "A"
20
+ # "\u00C0" => "A"
21
+ # "\u00C0" => "\u0041"
22
+ # "??" => "ss"
23
+ # "\t" => " "
24
+ # "\n" => ""
25
+
26
+ # ?? => A
27
+ "\u00C0" => "A"
28
+
29
+ # ?? => A
30
+ "\u00C1" => "A"
31
+
32
+ # ?? => A
33
+ "\u00C2" => "A"
34
+
35
+ # ?? => A
36
+ "\u00C3" => "A"
37
+
38
+ # ?? => A
39
+ "\u00C4" => "A"
40
+
41
+ # ?? => A
42
+ "\u00C5" => "A"
43
+
44
+ # ?? => AE
45
+ "\u00C6" => "AE"
46
+
47
+ # ?? => C
48
+ "\u00C7" => "C"
49
+
50
+ # ?? => E
51
+ "\u00C8" => "E"
52
+
53
+ # ?? => E
54
+ "\u00C9" => "E"
55
+
56
+ # ?? => E
57
+ "\u00CA" => "E"
58
+
59
+ # ?? => E
60
+ "\u00CB" => "E"
61
+
62
+ # ?? => I
63
+ "\u00CC" => "I"
64
+
65
+ # ?? => I
66
+ "\u00CD" => "I"
67
+
68
+ # ?? => I
69
+ "\u00CE" => "I"
70
+
71
+ # ?? => I
72
+ "\u00CF" => "I"
73
+
74
+ # ?? => IJ
75
+ "\u0132" => "IJ"
76
+
77
+ # ?? => D
78
+ "\u00D0" => "D"
79
+
80
+ # ?? => N
81
+ "\u00D1" => "N"
82
+
83
+ # ?? => O
84
+ "\u00D2" => "O"
85
+
86
+ # ?? => O
87
+ "\u00D3" => "O"
88
+
89
+ # ?? => O
90
+ "\u00D4" => "O"
91
+
92
+ # ?? => O
93
+ "\u00D5" => "O"
94
+
95
+ # ?? => O
96
+ "\u00D6" => "O"
97
+
98
+ # ?? => O
99
+ "\u00D8" => "O"
100
+
101
+ # ?? => OE
102
+ "\u0152" => "OE"
103
+
104
+ # ??
105
+ "\u00DE" => "TH"
106
+
107
+ # ?? => U
108
+ "\u00D9" => "U"
109
+
110
+ # ?? => U
111
+ "\u00DA" => "U"
112
+
113
+ # ?? => U
114
+ "\u00DB" => "U"
115
+
116
+ # ?? => U
117
+ "\u00DC" => "U"
118
+
119
+ # ?? => Y
120
+ "\u00DD" => "Y"
121
+
122
+ # ?? => Y
123
+ "\u0178" => "Y"
124
+
125
+ # ?? => a
126
+ "\u00E0" => "a"
127
+
128
+ # ?? => a
129
+ "\u00E1" => "a"
130
+
131
+ # ?? => a
132
+ "\u00E2" => "a"
133
+
134
+ # ?? => a
135
+ "\u00E3" => "a"
136
+
137
+ # ?? => a
138
+ "\u00E4" => "a"
139
+
140
+ # ?? => a
141
+ "\u00E5" => "a"
142
+
143
+ # ?? => ae
144
+ "\u00E6" => "ae"
145
+
146
+ # ?? => c
147
+ "\u00E7" => "c"
148
+
149
+ # ?? => e
150
+ "\u00E8" => "e"
151
+
152
+ # ?? => e
153
+ "\u00E9" => "e"
154
+
155
+ # ?? => e
156
+ "\u00EA" => "e"
157
+
158
+ # ?? => e
159
+ "\u00EB" => "e"
160
+
161
+ # ?? => i
162
+ "\u00EC" => "i"
163
+
164
+ # ?? => i
165
+ "\u00ED" => "i"
166
+
167
+ # ?? => i
168
+ "\u00EE" => "i"
169
+
170
+ # ?? => i
171
+ "\u00EF" => "i"
172
+
173
+ # ?? => ij
174
+ "\u0133" => "ij"
175
+
176
+ # ?? => d
177
+ "\u00F0" => "d"
178
+
179
+ # ?? => n
180
+ "\u00F1" => "n"
181
+
182
+ # ?? => o
183
+ "\u00F2" => "o"
184
+
185
+ # ?? => o
186
+ "\u00F3" => "o"
187
+
188
+ # ?? => o
189
+ "\u00F4" => "o"
190
+
191
+ # ?? => o
192
+ "\u00F5" => "o"
193
+
194
+ # ?? => o
195
+ "\u00F6" => "o"
196
+
197
+ # ?? => o
198
+ "\u00F8" => "o"
199
+
200
+ # ?? => oe
201
+ "\u0153" => "oe"
202
+
203
+ # ?? => ss
204
+ "\u00DF" => "ss"
205
+
206
+ # ?? => th
207
+ "\u00FE" => "th"
208
+
209
+ # ?? => u
210
+ "\u00F9" => "u"
211
+
212
+ # ?? => u
213
+ "\u00FA" => "u"
214
+
215
+ # ?? => u
216
+ "\u00FB" => "u"
217
+
218
+ # ?? => u
219
+ "\u00FC" => "u"
220
+
221
+ # ?? => y
222
+ "\u00FD" => "y"
223
+
224
+ # ?? => y
225
+ "\u00FF" => "y"
226
+
227
+ # ??? => ff
228
+ "\uFB00" => "ff"
229
+
230
+ # ??? => fi
231
+ "\uFB01" => "fi"
232
+
233
+ # ??? => fl
234
+ "\uFB02" => "fl"
235
+
236
+ # ??? => ffi
237
+ "\uFB03" => "ffi"
238
+
239
+ # ??? => ffl
240
+ "\uFB04" => "ffl"
241
+
242
+ # ??? => ft
243
+ "\uFB05" => "ft"
244
+
245
+ # ??? => st
246
+ "\uFB06" => "st"