blacklight-access_controls 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/Gemfile +32 -0
  4. data/README.textile +74 -0
  5. data/Rakefile +47 -0
  6. data/VERSION +1 -0
  7. data/blacklight-access_controls.gemspec +29 -0
  8. data/lib/blacklight-access_controls.rb +23 -0
  9. data/lib/blacklight/access_controls.rb +14 -0
  10. data/lib/blacklight/access_controls/ability.rb +148 -0
  11. data/lib/blacklight/access_controls/catalog.rb +27 -0
  12. data/lib/blacklight/access_controls/config.rb +39 -0
  13. data/lib/blacklight/access_controls/enforcement.rb +103 -0
  14. data/lib/blacklight/access_controls/permissions_cache.rb +19 -0
  15. data/lib/blacklight/access_controls/permissions_query.rb +53 -0
  16. data/lib/blacklight/access_controls/permissions_solr_document.rb +2 -0
  17. data/lib/blacklight/access_controls/user.rb +23 -0
  18. data/lib/generators/blacklight/ability.rb +4 -0
  19. data/lib/generators/blacklight/access_controls_generator.rb +49 -0
  20. data/solr_conf/conf/abc123 +0 -0
  21. data/solr_conf/conf/admin-extra.html +24 -0
  22. data/solr_conf/conf/admin-extra.menu-bottom.html +25 -0
  23. data/solr_conf/conf/admin-extra.menu-top.html +25 -0
  24. data/solr_conf/conf/clustering/carrot2/kmeans-attributes.xml +19 -0
  25. data/solr_conf/conf/clustering/carrot2/lingo-attributes.xml +24 -0
  26. data/solr_conf/conf/clustering/carrot2/stc-attributes.xml +19 -0
  27. data/solr_conf/conf/currency.xml +67 -0
  28. data/solr_conf/conf/dataimport.properties +3 -0
  29. data/solr_conf/conf/db-data-config.xml +93 -0
  30. data/solr_conf/conf/elevate.xml +38 -0
  31. data/solr_conf/conf/lang/contractions_ca.txt +8 -0
  32. data/solr_conf/conf/lang/contractions_fr.txt +15 -0
  33. data/solr_conf/conf/lang/contractions_ga.txt +5 -0
  34. data/solr_conf/conf/lang/contractions_it.txt +23 -0
  35. data/solr_conf/conf/lang/hyphenations_ga.txt +5 -0
  36. data/solr_conf/conf/lang/stemdict_nl.txt +6 -0
  37. data/solr_conf/conf/lang/stoptags_ja.txt +420 -0
  38. data/solr_conf/conf/lang/stopwords_ar.txt +125 -0
  39. data/solr_conf/conf/lang/stopwords_bg.txt +193 -0
  40. data/solr_conf/conf/lang/stopwords_ca.txt +220 -0
  41. data/solr_conf/conf/lang/stopwords_ckb.txt +136 -0
  42. data/solr_conf/conf/lang/stopwords_cz.txt +172 -0
  43. data/solr_conf/conf/lang/stopwords_da.txt +110 -0
  44. data/solr_conf/conf/lang/stopwords_de.txt +294 -0
  45. data/solr_conf/conf/lang/stopwords_el.txt +78 -0
  46. data/solr_conf/conf/lang/stopwords_en.txt +54 -0
  47. data/solr_conf/conf/lang/stopwords_es.txt +356 -0
  48. data/solr_conf/conf/lang/stopwords_eu.txt +99 -0
  49. data/solr_conf/conf/lang/stopwords_fa.txt +313 -0
  50. data/solr_conf/conf/lang/stopwords_fi.txt +97 -0
  51. data/solr_conf/conf/lang/stopwords_fr.txt +186 -0
  52. data/solr_conf/conf/lang/stopwords_ga.txt +110 -0
  53. data/solr_conf/conf/lang/stopwords_gl.txt +161 -0
  54. data/solr_conf/conf/lang/stopwords_hi.txt +235 -0
  55. data/solr_conf/conf/lang/stopwords_hu.txt +211 -0
  56. data/solr_conf/conf/lang/stopwords_hy.txt +46 -0
  57. data/solr_conf/conf/lang/stopwords_id.txt +359 -0
  58. data/solr_conf/conf/lang/stopwords_it.txt +303 -0
  59. data/solr_conf/conf/lang/stopwords_ja.txt +127 -0
  60. data/solr_conf/conf/lang/stopwords_lv.txt +172 -0
  61. data/solr_conf/conf/lang/stopwords_nl.txt +119 -0
  62. data/solr_conf/conf/lang/stopwords_no.txt +194 -0
  63. data/solr_conf/conf/lang/stopwords_pt.txt +253 -0
  64. data/solr_conf/conf/lang/stopwords_ro.txt +233 -0
  65. data/solr_conf/conf/lang/stopwords_ru.txt +243 -0
  66. data/solr_conf/conf/lang/stopwords_sv.txt +133 -0
  67. data/solr_conf/conf/lang/stopwords_th.txt +119 -0
  68. data/solr_conf/conf/lang/stopwords_tr.txt +212 -0
  69. data/solr_conf/conf/lang/userdict_ja.txt +29 -0
  70. data/solr_conf/conf/mapping-FoldToASCII.txt +3813 -0
  71. data/solr_conf/conf/mapping-ISOLatin1Accent.txt +246 -0
  72. data/solr_conf/conf/protwords.txt +21 -0
  73. data/solr_conf/conf/schema.blacklight.xml +724 -0
  74. data/solr_conf/conf/schema.xml +1268 -0
  75. data/solr_conf/conf/schema.xml.orig +1524 -0
  76. data/solr_conf/conf/solrconfig.adams.xml +1903 -0
  77. data/solr_conf/conf/solrconfig.blacklight.xml +411 -0
  78. data/solr_conf/conf/solrconfig.old.xml +1634 -0
  79. data/solr_conf/conf/solrconfig.xml +332 -0
  80. data/solr_conf/conf/solrconfig.xml.orig +3531 -0
  81. data/solr_conf/conf/spellings.txt +2 -0
  82. data/solr_conf/conf/stopwords.txt +14 -0
  83. data/solr_conf/conf/synonyms.txt +29 -0
  84. data/solr_conf/conf/update-script.js +53 -0
  85. data/solr_conf/conf/xslt/example.xsl +132 -0
  86. data/solr_conf/conf/xslt/example_atom.xsl +67 -0
  87. data/solr_conf/conf/xslt/example_rss.xsl +66 -0
  88. data/solr_conf/conf/xslt/luke.xsl +337 -0
  89. data/solr_conf/conf/xslt/updateXml.xsl +70 -0
  90. data/spec/factories/user.rb +6 -0
  91. data/spec/spec_helper.rb +29 -0
  92. data/spec/support/solr_support.rb +11 -0
  93. data/spec/test_app_templates/blacklight.yml +18 -0
  94. data/spec/test_app_templates/lib/generators/test_app_generator.rb +25 -0
  95. data/spec/unit/ability_spec.rb +202 -0
  96. data/spec/unit/catalog_spec.rb +41 -0
  97. data/spec/unit/config_spec.rb +69 -0
  98. data/spec/unit/enforcement_spec.rb +147 -0
  99. metadata +265 -0
@@ -0,0 +1,103 @@
1
+ module Blacklight
2
+ module AccessControls
3
+ module Enforcement
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ attr_writer :current_ability
8
+ class_attribute :solr_access_filters_logic
9
+
10
+ # Set defaults. Each symbol identifies a _method_ that must be in
11
+ # this class, taking one parameter (permission_types)
12
+ # Can be changed in local apps or by plugins, eg:
13
+ # CatalogController.include ModuleDefiningNewMethod
14
+ # CatalogController.solr_access_filters_logic += [:new_method]
15
+ # CatalogController.solr_access_filters_logic.delete(:we_dont_want)
16
+ self.solr_access_filters_logic = [:apply_group_permissions, :apply_user_permissions]
17
+
18
+ # Apply appropriate access controls to all solr queries
19
+ self.default_processor_chain += [:add_access_controls_to_solr_params] if respond_to?(:default_processor_chain)
20
+ end
21
+
22
+ def current_ability
23
+ @current_ability || raise("current_ability has not been set on #{self}")
24
+ end
25
+
26
+ protected
27
+
28
+ def gated_discovery_filters(permission_types = discovery_permissions, ability = current_ability)
29
+ user_access_filters = []
30
+
31
+ # Grant access based on user id & group
32
+ solr_access_filters_logic.each do |method_name|
33
+ user_access_filters += send(method_name, permission_types, ability)
34
+ end
35
+ user_access_filters
36
+ end
37
+
38
+ #
39
+ # Solr query modifications
40
+ #
41
+
42
+ # Set solr_parameters to enforce appropriate permissions
43
+ # * Applies a lucene query to the solr :q parameter for gated discovery
44
+ # * Uses public_qt search handler if user does not have "read" permissions
45
+ # @param solr_parameters the current solr parameters
46
+ def add_access_controls_to_solr_params(solr_parameters)
47
+ apply_gated_discovery(solr_parameters)
48
+ end
49
+
50
+ # Which permission levels (logical OR) will grant you the ability to discover documents in a search.
51
+ # Override this method if you want it to be something other than the default
52
+ def discovery_permissions
53
+ @discovery_permissions ||= ["discover","read"]
54
+ end
55
+ def discovery_permissions= (permissions)
56
+ @discovery_permissions = permissions
57
+ end
58
+
59
+ # Controller before filter that sets up access-controlled lucene query in order to provide gated discovery behavior
60
+ # @param solr_parameters the current solr parameters
61
+ def apply_gated_discovery(solr_parameters)
62
+ solr_parameters[:fq] ||= []
63
+ solr_parameters[:fq] << gated_discovery_filters.join(" OR ")
64
+ Rails.logger.debug("Solr parameters: #{ solr_parameters.inspect }")
65
+ end
66
+
67
+ def apply_group_permissions(permission_types, ability = current_ability)
68
+ # for groups
69
+ user_access_filters = []
70
+ ability.user_groups.each_with_index do |group, i|
71
+ permission_types.each do |type|
72
+ user_access_filters << escape_filter(solr_field_for(type, 'group'), group)
73
+ end
74
+ end
75
+ user_access_filters
76
+ end
77
+
78
+ def apply_user_permissions(permission_types, ability = current_ability)
79
+ # for individual user access
80
+ user_access_filters = []
81
+ user = ability.current_user
82
+ if user && user.user_key.present?
83
+ permission_types.each do |type|
84
+ user_access_filters << escape_filter(solr_field_for(type, 'user'), user.user_key)
85
+ end
86
+ end
87
+ user_access_filters
88
+ end
89
+
90
+ # Find the name of the solr field for this type of permission.
91
+ # e.g. "read_access_group_ssim" or "discover_access_person_ssim".
92
+ def solr_field_for(permission_type, permission_category)
93
+ method_name = "#{permission_type}_#{permission_category}_field".to_sym
94
+ Blacklight::AccessControls.config.send(method_name)
95
+ end
96
+
97
+ def escape_filter(key, value)
98
+ [key, value.gsub(/[ :\/]/, ' ' => '\ ', '/' => '\/', ':' => '\:')].join(':')
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,19 @@
1
+ class Blacklight::AccessControls::PermissionsCache
2
+
3
+ def initialize
4
+ clear
5
+ end
6
+
7
+ def get(pid)
8
+ @cache[pid]
9
+ end
10
+
11
+ def put(pid, doc)
12
+ @cache[pid] = doc
13
+ end
14
+
15
+ def clear
16
+ @cache = {}
17
+ end
18
+
19
+ end
@@ -0,0 +1,53 @@
1
+ module Blacklight::AccessControls
2
+ module PermissionsQuery
3
+ extend ActiveSupport::Concern
4
+
5
+ def permissions_doc(pid)
6
+ doc = cache.get(pid)
7
+ unless doc
8
+ doc = get_permissions_solr_response_for_doc_id(pid)
9
+ cache.put(pid, doc)
10
+ end
11
+ doc
12
+ end
13
+
14
+ def permissions_document_class
15
+ Blacklight::AccessControls::PermissionsSolrDocument
16
+ end
17
+
18
+ protected
19
+
20
+ # a solr query method
21
+ # retrieve a solr document, given the doc id
22
+ # Modeled on Blacklight::SolrHelper.get_permissions_solr_response_for_doc_id
23
+ # @param [String] id of the documetn to retrieve
24
+ # @param [Hash] extra_controller_params (optional)
25
+ def get_permissions_solr_response_for_doc_id(id=nil, extra_controller_params={})
26
+ raise Blacklight::Exceptions::InvalidSolrID.new("The application is trying to retrieve permissions without specifying an asset id") if id.nil?
27
+ solr_opts = permissions_solr_doc_params(id).merge(extra_controller_params)
28
+ response = Blacklight.default_index.connection.get('select', :params=> solr_opts)
29
+ solr_response = Blacklight::Solr::Response.new(response, solr_opts)
30
+
31
+ raise Blacklight::Exceptions::InvalidSolrID.new("The solr permissions search handler didn't return anything for id \"#{id}\"") if solr_response.docs.empty?
32
+ permissions_document_class.new(solr_response.docs.first, solr_response)
33
+ end
34
+
35
+ #
36
+ # Solr integration
37
+ #
38
+
39
+ # returns a params hash with the permissions info for a single solr document
40
+ # If the id arg is nil, then the value is fetched from params[:id]
41
+ # This method is primary called by the get_permissions_solr_response_for_doc_id method.
42
+ # Modeled on Blacklight::SolrHelper.solr_doc_params
43
+ # @param [String] id of the documetn to retrieve
44
+ def permissions_solr_doc_params(id=nil)
45
+ id ||= params[:id]
46
+ # just to be consistent with the other solr param methods:
47
+ {
48
+ :qt => :permissions,
49
+ :id => id # this assumes the document request handler will map the 'id' param to the unique key field
50
+ }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,2 @@
1
+ class Blacklight::AccessControls::PermissionsSolrDocument < SolrDocument
2
+ end
@@ -0,0 +1,23 @@
1
+ # Injects behaviors into User model so that it will work with
2
+ # Blacklight Access Controls. By default, this module assumes
3
+ # you are using the User model created by Blacklight, which uses
4
+ # Devise.
5
+ # To integrate your own User implementation into Blacklight,
6
+ # override this module or define your own User model in
7
+ # app/models/user.rb within your Blacklight application.
8
+
9
+ module Blacklight
10
+ module AccessControls
11
+ module User
12
+ extend ActiveSupport::Concern
13
+
14
+ # This method should display the unique identifier for
15
+ # this user as defined by devise. The unique identifier
16
+ # is what access controls will be enforced against.
17
+ def user_key
18
+ send(Devise.authentication_keys.first)
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ class Ability
2
+ include CanCan::Ability
3
+ include Blacklight::AccessControls::Ability
4
+ end
@@ -0,0 +1,49 @@
1
+ module Blacklight
2
+ class AccessControlsGenerator < Rails::Generators::Base
3
+
4
+ desc "This generator makes the following changes to your application:
5
+
6
+ 1. Includes Blacklight::AccessControls::User in the User class.
7
+ 2. Includes Blacklight::AccessControls::Enforcement in the SearchBuilder class.
8
+ 3. Adds access controls to CatalogController.
9
+ 4. Adds Ability class."
10
+
11
+
12
+ source_root File.expand_path("..", __FILE__)
13
+
14
+ def add_access_controls_to_user
15
+ say_status('status', 'ADD ACCESS CONTROLS TO USER', :yellow)
16
+ insert_into_file 'app/models/user.rb',
17
+ " include Blacklight::AccessControls::User\n\n",
18
+ after: "include Blacklight::User\n"
19
+ end
20
+
21
+ def add_access_controls_to_search_builder
22
+ say_status('status', 'ADDING ACCESS CONTROLS TO SEARCH BUILDER', :yellow)
23
+ insert_into_file 'app/models/search_builder.rb',
24
+ " include Blacklight::AccessControls::Enforcement\n",
25
+ before: "end"
26
+ end
27
+
28
+ def add_access_controls_to_catalog_controller
29
+ say_status('status', 'ADDING ACCESS CONTROLS TO CATALOG CONTROLLER', :yellow)
30
+
31
+ string_to_insert = <<-EOS
32
+ include Blacklight::AccessControls::Catalog
33
+
34
+ # Apply the blacklight-access_controls
35
+ before_filter :enforce_show_permissions, only: :show
36
+
37
+ EOS
38
+
39
+ insert_into_file 'app/controllers/catalog_controller.rb',
40
+ string_to_insert, after: "include Blacklight::Catalog\n"
41
+ end
42
+
43
+ def add_cancan_ability
44
+ say_status('status', 'ADDING CANCAN ABILITY', :yellow)
45
+ copy_file 'ability.rb', 'app/models/ability.rb'
46
+ end
47
+
48
+ end
49
+ end
File without changes
@@ -0,0 +1,24 @@
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
+ right box of the cores overview page. Uncomment this as an example to
20
+ see there the content will show up.
21
+
22
+ <img src="img/ico/construction.png"> This line will appear at the top-
23
+ right box on collection1's Overview
24
+ -->
@@ -0,0 +1,25 @@
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
+ <!-- admin-extra.menu-bottom.html -->
19
+ <!--
20
+ <li>
21
+ <a href="#" style="background-image: url(img/ico/construction.png);">
22
+ LAST ITEM
23
+ </a>
24
+ </li>
25
+ -->
@@ -0,0 +1,25 @@
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
+ <!-- admin-extra.menu-top.html -->
19
+ <!--
20
+ <li>
21
+ <a href="#" style="background-image: url(img/ico/construction.png);">
22
+ FIRST ITEM
23
+ </a>
24
+ </li>
25
+ -->
@@ -0,0 +1,19 @@
1
+ <!--
2
+ Default configuration for the bisecting k-means clustering algorithm.
3
+
4
+ This file can be loaded (and saved) by Carrot2 Workbench.
5
+ http://project.carrot2.org/download.html
6
+ -->
7
+ <attribute-sets default="attributes">
8
+ <attribute-set id="attributes">
9
+ <value-set>
10
+ <label>attributes</label>
11
+ <attribute key="MultilingualClustering.defaultLanguage">
12
+ <value type="org.carrot2.core.LanguageCode" value="ENGLISH"/>
13
+ </attribute>
14
+ <attribute key="MultilingualClustering.languageAggregationStrategy">
15
+ <value type="org.carrot2.text.clustering.MultilingualClustering$LanguageAggregationStrategy" value="FLATTEN_MAJOR_LANGUAGE"/>
16
+ </attribute>
17
+ </value-set>
18
+ </attribute-set>
19
+ </attribute-sets>
@@ -0,0 +1,24 @@
1
+ <!--
2
+ Default configuration for the Lingo clustering algorithm.
3
+
4
+ This file can be loaded (and saved) by Carrot2 Workbench.
5
+ http://project.carrot2.org/download.html
6
+ -->
7
+ <attribute-sets default="attributes">
8
+ <attribute-set id="attributes">
9
+ <value-set>
10
+ <label>attributes</label>
11
+ <!--
12
+ The language to assume for clustered documents.
13
+ For a list of allowed values, see:
14
+ http://download.carrot2.org/stable/manual/#section.attribute.lingo.MultilingualClustering.defaultLanguage
15
+ -->
16
+ <attribute key="MultilingualClustering.defaultLanguage">
17
+ <value type="org.carrot2.core.LanguageCode" value="ENGLISH"/>
18
+ </attribute>
19
+ <attribute key="LingoClusteringAlgorithm.desiredClusterCountBase">
20
+ <value type="java.lang.Integer" value="20"/>
21
+ </attribute>
22
+ </value-set>
23
+ </attribute-set>
24
+ </attribute-sets>
@@ -0,0 +1,19 @@
1
+ <!--
2
+ Default configuration for the STC clustering algorithm.
3
+
4
+ This file can be loaded (and saved) by Carrot2 Workbench.
5
+ http://project.carrot2.org/download.html
6
+ -->
7
+ <attribute-sets default="attributes">
8
+ <attribute-set id="attributes">
9
+ <value-set>
10
+ <label>attributes</label>
11
+ <attribute key="MultilingualClustering.defaultLanguage">
12
+ <value type="org.carrot2.core.LanguageCode" value="ENGLISH"/>
13
+ </attribute>
14
+ <attribute key="MultilingualClustering.languageAggregationStrategy">
15
+ <value type="org.carrot2.text.clustering.MultilingualClustering$LanguageAggregationStrategy" value="FLATTEN_MAJOR_LANGUAGE"/>
16
+ </attribute>
17
+ </value-set>
18
+ </attribute-set>
19
+ </attribute-sets>
@@ -0,0 +1,67 @@
1
+ <?xml version="1.0" ?>
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
+ <!-- Example exchange rates file for CurrencyField type named "currency" in example schema -->
20
+
21
+ <currencyConfig version="1.0">
22
+ <rates>
23
+ <!-- Updated from http://www.exchangerate.com/ at 2011-09-27 -->
24
+ <rate from="USD" to="ARS" rate="4.333871" comment="ARGENTINA Peso" />
25
+ <rate from="USD" to="AUD" rate="1.025768" comment="AUSTRALIA Dollar" />
26
+ <rate from="USD" to="EUR" rate="0.743676" comment="European Euro" />
27
+ <rate from="USD" to="BRL" rate="1.881093" comment="BRAZIL Real" />
28
+ <rate from="USD" to="CAD" rate="1.030815" comment="CANADA Dollar" />
29
+ <rate from="USD" to="CLP" rate="519.0996" comment="CHILE Peso" />
30
+ <rate from="USD" to="CNY" rate="6.387310" comment="CHINA Yuan" />
31
+ <rate from="USD" to="CZK" rate="18.47134" comment="CZECH REP. Koruna" />
32
+ <rate from="USD" to="DKK" rate="5.515436" comment="DENMARK Krone" />
33
+ <rate from="USD" to="HKD" rate="7.801922" comment="HONG KONG Dollar" />
34
+ <rate from="USD" to="HUF" rate="215.6169" comment="HUNGARY Forint" />
35
+ <rate from="USD" to="ISK" rate="118.1280" comment="ICELAND Krona" />
36
+ <rate from="USD" to="INR" rate="49.49088" comment="INDIA Rupee" />
37
+ <rate from="USD" to="XDR" rate="0.641358" comment="INTNL MON. FUND SDR" />
38
+ <rate from="USD" to="ILS" rate="3.709739" comment="ISRAEL Sheqel" />
39
+ <rate from="USD" to="JPY" rate="76.32419" comment="JAPAN Yen" />
40
+ <rate from="USD" to="KRW" rate="1169.173" comment="KOREA (SOUTH) Won" />
41
+ <rate from="USD" to="KWD" rate="0.275142" comment="KUWAIT Dinar" />
42
+ <rate from="USD" to="MXN" rate="13.85895" comment="MEXICO Peso" />
43
+ <rate from="USD" to="NZD" rate="1.285159" comment="NEW ZEALAND Dollar" />
44
+ <rate from="USD" to="NOK" rate="5.859035" comment="NORWAY Krone" />
45
+ <rate from="USD" to="PKR" rate="87.57007" comment="PAKISTAN Rupee" />
46
+ <rate from="USD" to="PEN" rate="2.730683" comment="PERU Sol" />
47
+ <rate from="USD" to="PHP" rate="43.62039" comment="PHILIPPINES Peso" />
48
+ <rate from="USD" to="PLN" rate="3.310139" comment="POLAND Zloty" />
49
+ <rate from="USD" to="RON" rate="3.100932" comment="ROMANIA Leu" />
50
+ <rate from="USD" to="RUB" rate="32.14663" comment="RUSSIA Ruble" />
51
+ <rate from="USD" to="SAR" rate="3.750465" comment="SAUDI ARABIA Riyal" />
52
+ <rate from="USD" to="SGD" rate="1.299352" comment="SINGAPORE Dollar" />
53
+ <rate from="USD" to="ZAR" rate="8.329761" comment="SOUTH AFRICA Rand" />
54
+ <rate from="USD" to="SEK" rate="6.883442" comment="SWEDEN Krona" />
55
+ <rate from="USD" to="CHF" rate="0.906035" comment="SWITZERLAND Franc" />
56
+ <rate from="USD" to="TWD" rate="30.40283" comment="TAIWAN Dollar" />
57
+ <rate from="USD" to="THB" rate="30.89487" comment="THAILAND Baht" />
58
+ <rate from="USD" to="AED" rate="3.672955" comment="U.A.E. Dirham" />
59
+ <rate from="USD" to="UAH" rate="7.988582" comment="UKRAINE Hryvnia" />
60
+ <rate from="USD" to="GBP" rate="0.647910" comment="UNITED KINGDOM Pound" />
61
+
62
+ <!-- Cross-rates for some common currencies -->
63
+ <rate from="EUR" to="GBP" rate="0.869914" />
64
+ <rate from="EUR" to="NOK" rate="7.800095" />
65
+ <rate from="GBP" to="NOK" rate="8.966508" />
66
+ </rates>
67
+ </currencyConfig>