relaton-bipm 1.14.5 → 1.14.7

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0d5eb5717b605c2d3eec083e4ca529ccafb140246b1b8a042137d1025b41abb
4
- data.tar.gz: bdef48071e8e5ab07d643e54fed9f21c38d29119927620216a23d2d2d9c84a7b
3
+ metadata.gz: fca66f613215d88c2a6211038fa877a18c3239a6dc967058935d656f93a38bbf
4
+ data.tar.gz: 973ef9e8f3ae01e4a993c5b1fa5499cecd41c070b1ece0ec45b947d07e6bc009
5
5
  SHA512:
6
- metadata.gz: '09e75649f7ca561179506cf24c0eb9c06b2c2e6241aac712e3aaa01e85985542d7086d907068acc365b0b93386e83160646e41d67585b1c9a8e98c8b5c281f55'
7
- data.tar.gz: ca8540f40846fe5d92b0b2da284c72cb3a44a4dfd580ad4a51eb6c625cfd400aa59b7a435c46af45244540482d02aff1bd9aa70b3cc5359a41b873602b5d5ecd
6
+ metadata.gz: '0387b51f65c91b25c0957ee23d4781de82914bf8e6e32fd03ec7aa6cfb0506648983cf724cfed09a061e3e01967863d24a2948c074b76e83a6cab852ee452028'
7
+ data.tar.gz: 9cec1161eb66bb984ae573b0b880da67b4085b574acae5c6f44c80669a2f57f10ab422bbd7a54e419f65c159925ccf1815f08ac1ace269e2ac0808cce1e10791
@@ -36,8 +36,6 @@ module RelatonBipm
36
36
  basename = File.join @data_fetcher.output, File.basename(f).sub(/(?:-(?:en|fr))?\.rxl$/, "")
37
37
  outfile = "#{basename}.#{@data_fetcher.ext}"
38
38
  key = hash1["docnumber"] || basename
39
- @data_fetcher.index[[key]] = outfile
40
- @data_fetcher.index_new.add_or_update [key], outfile
41
39
  @data_fetcher.index2.add_or_update Id.new(key).to_hash, outfile
42
40
  hash = if File.exist? outfile
43
41
  warn_duplicate = false
@@ -1,6 +1,6 @@
1
1
  module RelatonBipm
2
2
  class DataFetcher
3
- attr_reader :output, :format, :ext, :files, :index, :index_new, :index2
3
+ attr_reader :output, :format, :ext, :files, :index2
4
4
 
5
5
  #
6
6
  # Initialize fetcher
@@ -13,9 +13,6 @@ module RelatonBipm
13
13
  @format = format
14
14
  @ext = format.sub(/^bib/, "")
15
15
  @files = []
16
- @index_path = "index.yaml"
17
- @index = File.exist?(@index_path) ? YAML.load_file(@index_path) : {}
18
- @index_new = Relaton::Index.find_or_create :BIPM, file: "index-bipm.yaml"
19
16
  @index2 = Relaton::Index.find_or_create :BIPM, file: "index2.yaml"
20
17
  end
21
18
 
@@ -47,8 +44,6 @@ module RelatonBipm
47
44
  when "bipm-si-brochure" then BipmSiBrochureParser.parse(self)
48
45
  when "rawdata-bipm-metrologia" then RawdataBipmMetrologia::Fetcher.fetch(self)
49
46
  end
50
- File.write @index_path, index.to_yaml, encoding: "UTF-8"
51
- index_new.save
52
47
  index2.save
53
48
  end
54
49
 
@@ -61,7 +61,7 @@ module RelatonBipm
61
61
  # @param [String] body name of body
62
62
  #
63
63
  def fetch_type(dir, body) # rubocop:disable Metrics/AbcSize
64
- type = dir.split("/").last.split("-").first.sub(/s$/, "")
64
+ type = dir.split("/").last.split("-").first.sub(/s$/, "").capitalize
65
65
  body_dir = File.join @data_fetcher.output, body.downcase
66
66
  FileUtils.mkdir_p body_dir
67
67
  outdir = File.join body_dir, type.downcase
@@ -74,7 +74,7 @@ module RelatonBipm
74
74
  #
75
75
  # @param [String] en_file Path to English file
76
76
  # @param [String] body Body name
77
- # @param [String] type Type of Recommendation/Decision/Resolution
77
+ # @param [String] type meeting
78
78
  # @param [String] dir output directory
79
79
  #
80
80
  def fetch_meeting(en_file, body, type, dir) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@@ -84,7 +84,7 @@ module RelatonBipm
84
84
 
85
85
  file = "#{num}.#{@data_fetcher.ext}"
86
86
  path = File.join dir, file
87
- hash = bibitem body: body, type: type, en: en_md, fr: fr_md, num: num, src: src, pdf: en["pdf"]
87
+ hash = meeting_bibitem body: body, type: type, en: en_md, fr: fr_md, num: num, src: src, pdf: en["pdf"]
88
88
  if @data_fetcher.files.include?(path) && part
89
89
  add_part hash, part
90
90
  item = RelatonBipm::BipmBibliographicItem.new(**hash)
@@ -95,7 +95,7 @@ module RelatonBipm
95
95
  path = File.join dir, "#{num}-#{part}.#{@data_fetcher.ext}"
96
96
  elsif part
97
97
  hash[:title].each { |t| t[:content] = t[:content].sub(/\s\(.+\)$/, "") }
98
- h = bibitem body: body, type: type, en: en_md, fr: fr_md, num: num, src: src, pdf: en["pdf"]
98
+ h = meeting_bibitem body: body, type: type, en: en_md, fr: fr_md, num: num, src: src, pdf: en["pdf"]
99
99
  add_part h, part
100
100
  part_item = RelatonBipm::BipmBibliographicItem.new(**h)
101
101
  part_item_path = File.join dir, "#{num}-#{part}.#{@data_fetcher.ext}"
@@ -171,9 +171,9 @@ module RelatonBipm
171
171
  num = "0" if num == year
172
172
  num_justed = num.rjust 2, "0"
173
173
  type = r["type"].capitalize
174
- docnum = create_docnum args[:body], type, num, date
174
+ docnum = create_resolution_docnum args[:body], type, num, date
175
175
  hash[:id] = create_id(args[:body], type, num_justed, date)
176
- hash[:docid] = create_docids docnum
176
+ hash[:docid] = create_resolution_docids args[:body], type, num, date
177
177
  hash[:docnumber] = docnum
178
178
  hash[:language] = %w[en fr]
179
179
  hash[:script] = ["Latn"]
@@ -230,20 +230,8 @@ module RelatonBipm
230
230
  # @param [String] path path to YAML file
231
231
  #
232
232
  def add_to_index(item, path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
233
- # key = [item.docnumber]
234
- # SHORTTYPE.each do |k, v|
235
- # if item.docnumber.include? k
236
- # key << item.docnumber.sub(k, v)
237
- # key << item.docnumber.sub(k, v).sub(/(\(\d{4})(\))/, "\\1, EN\\2")
238
- # key << item.docnumber.sub(k, v).sub(/(\(\d{4})(\))/, "\\1, FR\\2")
239
- # break
240
- # end
241
- # end
242
- key = item.docidentifier.select { |i| i.type == "BIPM" }.map &:id
243
- @data_fetcher.index[key] = path
244
- @data_fetcher.index_new.add_or_update key, path
245
- key2 = Id.new(item.docnumber).to_hash
246
- @data_fetcher.index2.add_or_update key2, path
233
+ key = Id.new(item.docnumber).to_hash
234
+ @data_fetcher.index2.add_or_update key, path
247
235
  end
248
236
 
249
237
  #
@@ -254,20 +242,40 @@ module RelatonBipm
254
242
  #
255
243
  # @return [Array<Hash>] contributors
256
244
  #
257
- def contributors(date, body) # rubocop:disable Metrics/MethodLength
245
+ def contributors(date, body)
246
+ contribs = [{ entity: bipm_org, role: [{ type: "publisher" }] }]
247
+ author = author_org date, body
248
+ contribs << { entity: author, role: [{ type: "author" }] } if author
249
+ contribs
250
+ end
251
+
252
+ #
253
+ # Create author organization
254
+ #
255
+ # @param [String] date date of publication
256
+ # @param [String] body organization abbreviation (CCTF, CIPM, CGPM)
257
+ #
258
+ # @return [Hash, nil] author organization
259
+ #
260
+ def author_org(date, body)
258
261
  case body
259
262
  when "CCTF" then cctf_org date
260
263
  when "CGPM" then cgpm_org
261
264
  when "CIPM" then cipm_org
262
- else []
263
- end.reduce(
264
- [{ entity: {
265
- url: "www.bipm.org",
266
- name: "Bureau International des Poids et Mesures",
267
- abbreviation: "BIPM",
268
- },
269
- role: [{ type: "publisher" }] }],
270
- ) { |a, e| a << { entity: e, role: [{ type: "author" }] } }
265
+ end
266
+ end
267
+
268
+ #
269
+ # Create BIPM organization
270
+ #
271
+ # @return [Hash] BIPM organization
272
+ #
273
+ def bipm_org
274
+ nms = [
275
+ { content: "International Bureau of Weights and Measures", language: "en" },
276
+ { content: "Bureau international des poids et mesures", language: "fr" },
277
+ ]
278
+ organization(nms, "BIPM").tap { |org| org[:url] = "www.bipm.org" }
271
279
  end
272
280
 
273
281
  #
@@ -275,7 +283,7 @@ module RelatonBipm
275
283
  #
276
284
  # @param [String] date date of meeting
277
285
  #
278
- # @return [Array<Hash>] CCTF organization
286
+ # @return [Hash] CCTF organization
279
287
  #
280
288
  def cctf_org(date) # rubocop:disable Metrics/MethodLength
281
289
  if Date.parse(date).year < 1999
@@ -299,17 +307,17 @@ module RelatonBipm
299
307
  # @param [Array<Hash>] names organization names in different languages
300
308
  # @param [String] abbr abbreviation
301
309
  #
302
- # @return [Array<Hash>] organization
310
+ # @return [Hash] organization
303
311
  #
304
312
  def organization(names, abbr)
305
313
  names.each { |ctrb| ctrb[:script] = "Latn" }
306
- [{ name: names, abbreviation: { content: abbr, language: ["en", "fr"], script: "Latn" } }]
314
+ { name: names, abbreviation: { content: abbr, language: ["en", "fr"], script: "Latn" } }
307
315
  end
308
316
 
309
317
  #
310
318
  # Create CGPM organization
311
319
  #
312
- # @return [Array<Hash>] CGPM organization
320
+ # @return [Hash] CGPM organization
313
321
  #
314
322
  def cgpm_org
315
323
  nms = [
@@ -362,20 +370,20 @@ module RelatonBipm
362
370
  end
363
371
 
364
372
  #
365
- # Create hash from BIPM meeting/resolution
373
+ # Create hash from BIPM meeting
366
374
  #
367
375
  # @param [Hash] **args Hash of arguments
368
- # @option args [String] :type Type of meeting/resolution
376
+ # @option args [String] :type meeting
369
377
  # @option args [Hash] :en Hash of English metadata
370
378
  # @option args [Hash] :fr Hash of French metadata
371
- # @option args [String] :id ID of meeting/resolution
372
- # @option args [String] :num Number of meeting/resolution
379
+ # @option args [String] :id ID of meeting
380
+ # @option args [String] :num Number of meeting
373
381
  # @option args [Array<Hash>] :src Array of links to bipm-data-outcomes
374
382
  # @option args [String] :pdf link to PDF
375
383
  #
376
384
  # @return [Hash] Hash of BIPM meeting/resolution
377
385
  #
378
- def bibitem(**args) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
386
+ def meeting_bibitem(**args) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
379
387
  docnum = create_meeting_docnum args[:body], args[:type], args[:num], args[:en]["date"]
380
388
  hash = { title: [], type: "proceedings", doctype: args[:type],
381
389
  place: [RelatonBib::Place.new(city: "Paris")] }
@@ -417,49 +425,51 @@ module RelatonBipm
417
425
  end
418
426
 
419
427
  #
420
- # Creata a document number
428
+ # Creata resolution document number
421
429
  #
422
- # @param [<Type>] body <description>
423
- # @param [<Type>] type <description>
424
- # @param [<Type>] num <description>
425
- # @param [<Type>] date <description>
430
+ # @param [String] body CIPM, CGPM, CCTF
431
+ # @param [String] type Recommendation, Resolution, Decision
432
+ # @param [String] num number of recommendation, resolution, decision
433
+ # @param [String] date date of publication
426
434
  #
427
- # @return [<Type>] <description>
435
+ # @return [String] document number
428
436
  #
429
- def create_docnum(body, type, num, date)
437
+ def create_resolution_docnum(body, type, num, date)
430
438
  year = Date.parse(date).year
431
- # if special_id_case? body, type, year
432
- # id = "#{type.capitalize} #{body}"
433
- # id += "/#{num}" if num.to_i.positive?
434
- # else
435
439
  id = "#{body} #{SHORTTYPE[type.capitalize]}"
436
440
  id += " #{num}" if num.to_i.positive?
437
- # end
438
441
  "#{id} (#{year})"
439
442
  end
440
443
 
444
+ #
445
+ # Create meeting document number
446
+ #
447
+ # @param [String] body CIPM, CGPM, CCTF
448
+ # @param [String] type meeting
449
+ # @param [String] num number of meeting
450
+ # @param [String] date date of publication
451
+ #
452
+ # @return [String] <description>
453
+ #
441
454
  def create_meeting_docnum(body, type, num, date)
442
455
  year = Date.parse(date).year
443
- "#{body} #{num}th #{type} (#{year})"
456
+ ord = %w[th st nd rd th th th th th th][num.to_i % 10]
457
+ "#{body} #{num}#{ord} #{type} (#{year})"
444
458
  end
445
459
 
446
460
  #
447
461
  # Create ID
448
462
  #
449
- # @param [String] body body of meeting
450
- # @param [String] type type of meeting
451
- # @param [String, nil] num part number
463
+ # @param [String] body CIPM, CGPM, CCTF
464
+ # @param [String] type meeting, recommendation, resolution, decision
465
+ # @param [String, nil] num number of meeting, recommendation, resolution, decision
452
466
  # @param [String] date published date
453
467
  #
454
468
  # @return [String] ID
455
469
  #
456
470
  def create_id(body, type, num, date)
457
471
  year = Date.parse(date).year
458
- # if special_id_case?(body, type, year)
459
- # [type.capitalize, body, year]
460
- # else
461
472
  [body, SHORTTYPE[type.capitalize], year, num].compact.join("-")
462
- # end
463
473
  end
464
474
 
465
475
  #
@@ -471,10 +481,10 @@ module RelatonBipm
471
481
  #
472
482
  # @return [Boolean] is special case
473
483
  #
474
- # def special_id_case?(body, type, year)
475
- # (body == "CIPM" && type == "Decision" && year.to_i > 2011) ||
476
- # (body == "JCRB" && %w[recomendation resolution descision].include?(type))
477
- # end
484
+ def special_id_case?(body, type, year)
485
+ (body == "CIPM" && type == "Decision" && year.to_i > 2011) ||
486
+ (body == "JCRB" && %w[Recomendation Resolution Descision].include?(type))
487
+ end
478
488
 
479
489
  #
480
490
  # Create documetn IDs
@@ -483,38 +493,62 @@ module RelatonBipm
483
493
  #
484
494
  # @return [Array<RelatonBib::DocumentIdentifier>] document IDs
485
495
  #
486
- def create_docids(id)
487
- en_id = id.sub(/(\s\(\d{4})(\))$/, '\1, E\2')
488
- fr_id = id.sub(/(\s\(\d{4})(\))$/, '\1, F\2')
489
- [
490
- make_docid(id: id, type: "BIPM", primary: true),
491
- make_docid(id: en_id, type: "BIPM", primary: true, language: "en", script: "Latn"),
492
- make_docid(id: fr_id, type: "BIPM", primary: true, language: "fr", script: "Latn"),
493
- # create_docid_fr(en_id),
494
- ]
496
+ def create_resolution_docids(body, type, num, date)
497
+ year = Date.parse(date).year
498
+ ids = []
499
+ resolution_short_ids(body, type, num, year) { |id| ids << id }
500
+ resolution_long_ids(body, type, num, year) { |id| ids << id }
501
+ end
502
+
503
+ def resolution_short_ids(body, type, num, year, &_block)
504
+ short_type = SHORTTYPE[type]
505
+ id = "#{body} #{short_type}"
506
+ id += " #{num}" if num.to_i.positive?
507
+
508
+ short = "#{id} (#{year})"
509
+ yield make_docid(id: short, type: "BIPM", primary: true)
510
+
511
+ en = "#{id} (#{year}, E)"
512
+ yield make_docid(id: en, type: "BIPM", primary: true, language: "en", script: "Latn")
513
+
514
+ fr = "#{id} (#{year}, F)"
515
+ yield make_docid(id: fr, type: "BIPM", primary: true, language: "fr", script: "Latn")
516
+ end
517
+
518
+ def resolution_long_ids(body, type, num, year, &_block)
519
+ en = "#{body} #{type}"
520
+ en += " #{num}" if num.to_i.positive?
521
+ en += " (#{year})"
522
+ yield make_docid id: en, type: "BIPM-long", language: "en", script: "Latn"
523
+
524
+ fr = resolution_fr_long_id(body, type, num, year)
525
+ yield make_docid id: fr, type: "BIPM-long", language: "fr", script: "Latn"
526
+
527
+ yield make_docid(id: "#{en} / #{fr}", type: "BIPM-long")
528
+ end
529
+
530
+ def resolution_fr_long_id(body, type, num, year)
531
+ fr = TRANSLATIONS[type] || type
532
+ if special_id_case? body, type, year
533
+ fr += " #{body}"
534
+ fr += "/#{num}" if num.to_i.positive?
535
+ else
536
+ fr += " #{num}" if num.to_i.positive?
537
+ fr += body == "CGPM" ? " de la" : " du"
538
+ fr += " #{body}"
539
+ end
540
+ "#{fr} (#{year})"
495
541
  end
496
542
 
497
543
  def create_meeting_docids(en_id)
498
- fr_id = en_id.sub(/(\d+)th/, '\1e').sub("meeting", "réunion")
544
+ fr_id = en_id.sub(/(\d+)(?:st|nd|rd|th)/, '\1e').sub("Meeting", "Réunion")
499
545
  [
500
546
  make_docid(id: en_id, type: "BIPM", primary: true, language: "en", script: "Latn"),
501
547
  make_docid(id: fr_id, type: "BIPM", primary: true, language: "fr", script: "Latn"),
548
+ make_docid(id: "#{en_id} / #{fr_id}", type: "BIPM", primary: true),
502
549
  ]
503
550
  end
504
551
 
505
- #
506
- # Create French document ID
507
- #
508
- # @param [String] en_id English document ID
509
- #
510
- # @return [RelatonBib::DocumentIdentifier] french document ID
511
- #
512
- # def create_docid_fr(en_id)
513
- # tr = TRANSLATIONS.detect { |_, v| en_id.include? v }
514
- # id = tr ? en_id.sub(tr[1], tr[0]) : en_id
515
- # make_docid(id: id, type: "BIPM", primary: true, language: "fr", script: "Latn")
516
- # end
517
-
518
552
  #
519
553
  # Create doucment ID
520
554
  #
@@ -87,9 +87,11 @@ module RelatonBipm
87
87
  #
88
88
  # @return [Boolean] true if the two Id objects are equal
89
89
  #
90
- def ==(other)
90
+ def ==(other) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity,Metrics/AbcSize
91
91
  other_hash = other.is_a?(Id) ? other.to_hash : normalize_hash(other)
92
92
  hash = to_hash
93
+ hash.delete(:number) if other_hash[:number].nil? && hash[:number] == "1"
94
+ other_hash.delete(:number) if hash[:number].nil? && other_hash[:number] == "1"
93
95
  hash.delete(:year) unless other_hash[:year]
94
96
  other_hash.delete(:year) unless hash[:year]
95
97
  hash.delete(:lang) unless other_hash[:lang]
@@ -33,8 +33,6 @@ module RelatonBipm
33
33
  item = ArticleParser.parse path
34
34
  file = "#{item.docidentifier.first.id.downcase.gsub(' ', '-')}.#{@data_fetcher.ext}"
35
35
  out_path = File.join(@data_fetcher.output, file)
36
- @data_fetcher.index[[item.docidentifier.first.id]] = out_path
37
- @data_fetcher.index_new.add_or_update [item.docidentifier.first.id], out_path
38
36
  key = Id.new(item.docidentifier.first.id).to_hash
39
37
  @data_fetcher.index2.add_or_update key, out_path
40
38
  @data_fetcher.write_file out_path, item
@@ -78,8 +76,6 @@ module RelatonBipm
78
76
  )
79
77
  file = "#{id.downcase.gsub(' ', '-')}.#{@data_fetcher.ext}"
80
78
  path = File.join(@data_fetcher.output, file)
81
- @data_fetcher.index[[id]] = path
82
- @data_fetcher.index_new.add_or_update [id], path
83
79
  @data_fetcher.index2.add_or_update Id.new(id).to_hash, path
84
80
  @data_fetcher.write_file path, item
85
81
  end
@@ -1,3 +1,3 @@
1
1
  module RelatonBipm
2
- VERSION = "1.14.5".freeze
2
+ VERSION = "1.14.7".freeze
3
3
  end
data/relaton_bipm.gemspec CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
34
34
 
35
35
  spec.add_development_dependency "equivalent-xml", "~> 0.6"
36
36
 
37
- spec.add_dependency "faraday", "~> 1.0"
37
+ spec.add_dependency "faraday", "~> 2.7.0"
38
38
  spec.add_dependency "mechanize", "~> 2.8.0"
39
39
  spec.add_dependency "parslet", "~> 2.0.0"
40
40
  spec.add_dependency "relaton-bib", "~> 1.14.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relaton-bipm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.14.5
4
+ version: 1.14.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-02 00:00:00.000000000 Z
11
+ date: 2023-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: equivalent-xml
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: 2.7.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.0'
40
+ version: 2.7.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mechanize
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -175,7 +175,7 @@ licenses:
175
175
  metadata:
176
176
  homepage_uri: https://github.com/relaton/relaton-bipm
177
177
  source_code_uri: https://github.com/relaton/relaton-bipm
178
- post_install_message:
178
+ post_install_message:
179
179
  rdoc_options: []
180
180
  require_paths:
181
181
  - lib
@@ -190,8 +190,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
190
190
  - !ruby/object:Gem::Version
191
191
  version: '0'
192
192
  requirements: []
193
- rubygems_version: 3.4.9
194
- signing_key:
193
+ rubygems_version: 3.3.26
194
+ signing_key:
195
195
  specification_version: 4
196
196
  summary: 'RelatonBipm: retrieve BIPM Standards for bibliographic use using the BibliographicItem
197
197
  model'