cocoapods-square-stable 0.19.3

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1296 -0
  3. data/LICENSE +20 -0
  4. data/README.md +94 -0
  5. data/bin/pod +16 -0
  6. data/bin/sandbox-pod +120 -0
  7. data/lib/cocoapods.rb +77 -0
  8. data/lib/cocoapods/command.rb +116 -0
  9. data/lib/cocoapods/command/help.rb +23 -0
  10. data/lib/cocoapods/command/inter_process_communication.rb +178 -0
  11. data/lib/cocoapods/command/list.rb +77 -0
  12. data/lib/cocoapods/command/outdated.rb +56 -0
  13. data/lib/cocoapods/command/podfile_info.rb +91 -0
  14. data/lib/cocoapods/command/project.rb +88 -0
  15. data/lib/cocoapods/command/push.rb +172 -0
  16. data/lib/cocoapods/command/repo.rb +145 -0
  17. data/lib/cocoapods/command/search.rb +61 -0
  18. data/lib/cocoapods/command/setup.rb +134 -0
  19. data/lib/cocoapods/command/spec.rb +590 -0
  20. data/lib/cocoapods/config.rb +231 -0
  21. data/lib/cocoapods/downloader.rb +59 -0
  22. data/lib/cocoapods/executable.rb +118 -0
  23. data/lib/cocoapods/external_sources.rb +363 -0
  24. data/lib/cocoapods/file_list.rb +36 -0
  25. data/lib/cocoapods/gem_version.rb +7 -0
  26. data/lib/cocoapods/generator/acknowledgements.rb +107 -0
  27. data/lib/cocoapods/generator/acknowledgements/markdown.rb +40 -0
  28. data/lib/cocoapods/generator/acknowledgements/plist.rb +64 -0
  29. data/lib/cocoapods/generator/bridge_support.rb +22 -0
  30. data/lib/cocoapods/generator/copy_resources_script.rb +54 -0
  31. data/lib/cocoapods/generator/dummy_source.rb +22 -0
  32. data/lib/cocoapods/generator/prefix_header.rb +82 -0
  33. data/lib/cocoapods/generator/target_environment_header.rb +86 -0
  34. data/lib/cocoapods/generator/xcconfig.rb +185 -0
  35. data/lib/cocoapods/hooks/installer_representation.rb +134 -0
  36. data/lib/cocoapods/hooks/library_representation.rb +94 -0
  37. data/lib/cocoapods/hooks/pod_representation.rb +74 -0
  38. data/lib/cocoapods/installer.rb +571 -0
  39. data/lib/cocoapods/installer/analyzer.rb +559 -0
  40. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +253 -0
  41. data/lib/cocoapods/installer/file_references_installer.rb +179 -0
  42. data/lib/cocoapods/installer/pod_source_installer.rb +248 -0
  43. data/lib/cocoapods/installer/target_installer.rb +379 -0
  44. data/lib/cocoapods/installer/user_project_integrator.rb +180 -0
  45. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +224 -0
  46. data/lib/cocoapods/library.rb +202 -0
  47. data/lib/cocoapods/open_uri.rb +24 -0
  48. data/lib/cocoapods/project.rb +209 -0
  49. data/lib/cocoapods/resolver.rb +212 -0
  50. data/lib/cocoapods/sandbox.rb +343 -0
  51. data/lib/cocoapods/sandbox/file_accessor.rb +217 -0
  52. data/lib/cocoapods/sandbox/headers_store.rb +96 -0
  53. data/lib/cocoapods/sandbox/path_list.rb +208 -0
  54. data/lib/cocoapods/sources_manager.rb +276 -0
  55. data/lib/cocoapods/user_interface.rb +304 -0
  56. data/lib/cocoapods/user_interface/error_report.rb +101 -0
  57. data/lib/cocoapods/validator.rb +350 -0
  58. metadata +238 -0
@@ -0,0 +1,571 @@
1
+ module Pod
2
+
3
+ # The Installer is responsible of taking a Podfile and transform it in the
4
+ # Pods libraries. It also integrates the user project so the Pods
5
+ # libraries can be used out of the box.
6
+ #
7
+ # The Installer is capable of doing incremental updates to an existing Pod
8
+ # installation.
9
+ #
10
+ # The Installer gets the information that it needs mainly from 3 files:
11
+ #
12
+ # - Podfile: The specification written by the user that contains
13
+ # information about targets and Pods.
14
+ # - Podfile.lock: Contains information about the pods that were previously
15
+ # installed and in concert with the Podfile provides information about
16
+ # which specific version of a Pod should be installed. This file is
17
+ # ignored in update mode.
18
+ # - Manifest.lock: A file contained in the Pods folder that keeps track of
19
+ # the pods installed in the local machine. This files is used once the
20
+ # exact versions of the Pods has been computed to detect if that version
21
+ # is already installed. This file is not intended to be kept under source
22
+ # control and is a copy of the Podfile.lock.
23
+ #
24
+ # The Installer is designed to work in environments where the Podfile folder
25
+ # is under source control and environments where it is not. The rest of the
26
+ # files, like the user project and the workspace are assumed to be under
27
+ # source control.
28
+ #
29
+ class Installer
30
+
31
+ autoload :Analyzer, 'cocoapods/installer/analyzer'
32
+ autoload :FileReferencesInstaller, 'cocoapods/installer/file_references_installer'
33
+ autoload :PodSourceInstaller, 'cocoapods/installer/pod_source_installer'
34
+ autoload :TargetInstaller, 'cocoapods/installer/target_installer'
35
+ autoload :UserProjectIntegrator, 'cocoapods/installer/user_project_integrator'
36
+
37
+ include Config::Mixin
38
+
39
+ # @return [Sandbox] The sandbox where the Pods should be installed.
40
+ #
41
+ attr_reader :sandbox
42
+
43
+ # @return [Podfile] The Podfile specification that contains the information
44
+ # of the Pods that should be installed.
45
+ #
46
+ attr_reader :podfile
47
+
48
+ # @return [Lockfile] The Lockfile that stores the information about the
49
+ # Pods previously installed on any machine.
50
+ #
51
+ attr_reader :lockfile
52
+
53
+ # @param [Sandbox] sandbox @see sandbox
54
+ # @param [Podfile] podfile @see podfile
55
+ # @param [Lockfile] lockfile @see lockfile
56
+ #
57
+ def initialize(sandbox, podfile, lockfile = nil)
58
+ @sandbox = sandbox
59
+ @podfile = podfile
60
+ @lockfile = lockfile
61
+ end
62
+
63
+ # @return [Bool] Whether the installer is in update mode. In update mode
64
+ # the contents of the Lockfile are not taken into account for
65
+ # deciding what Pods to install.
66
+ #
67
+ attr_accessor :update_mode
68
+
69
+ # Installs the Pods.
70
+ #
71
+ # The installation process of is mostly linear with few minor complications
72
+ # to keep in mind:
73
+ #
74
+ # - The stored podspecs need to be cleaned before the resolution step
75
+ # otherwise the sandbox might return an old podspec and not download
76
+ # the new one from an external source.
77
+ # - The resolver might trigger the download of Pods from external sources
78
+ # necessary to retrieve their podspec (unless it is instructed not to
79
+ # do it).
80
+ #
81
+ # @return [void]
82
+ #
83
+ def install!
84
+ resolve_dependencies
85
+ download_dependencies
86
+ generate_pods_project
87
+ integrate_user_project if config.integrate_targets?
88
+ end
89
+
90
+ def resolve_dependencies
91
+ UI.section "Analyzing dependencies" do
92
+ analyze
93
+ prepare_for_legacy_compatibility
94
+ clean_sandbox
95
+ end
96
+ end
97
+
98
+ def download_dependencies
99
+ UI.section "Downloading dependencies" do
100
+ create_file_accessors
101
+ install_pod_sources
102
+ run_pre_install_hooks
103
+ clean_pod_sources
104
+ end
105
+ end
106
+
107
+ def generate_pods_project
108
+ UI.section "Generating Pods project" do
109
+ prepare_pods_project
110
+ install_file_references
111
+ install_targets
112
+ run_post_install_hooks
113
+ write_pod_project
114
+ write_lockfiles
115
+ end
116
+ end
117
+
118
+ #-------------------------------------------------------------------------#
119
+
120
+ public
121
+
122
+ # @!group Installation results
123
+
124
+ # @return [Analyzer] the analyzer which provides the information about what
125
+ # needs to be installed.
126
+ #
127
+ attr_reader :analysis_result
128
+
129
+ # @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
130
+ #
131
+ attr_reader :pods_project
132
+
133
+ # @return [Array<String>] The Pods that should be installed.
134
+ #
135
+ attr_reader :names_of_pods_to_install
136
+
137
+ # @return [Array<Library>] The libraries generated by the installation
138
+ # process.
139
+ #
140
+ attr_reader :libraries
141
+
142
+ # @return [Array<Specification>] The specifications that where installed.
143
+ #
144
+ attr_accessor :installed_specs
145
+
146
+ #-------------------------------------------------------------------------#
147
+
148
+ private
149
+
150
+ # @!group Installation steps
151
+
152
+ # @return [void]
153
+ #
154
+ # @note The warning about the version of the Lockfile doesn't uses the
155
+ # `UI.warn` method because it prints the output only at the end
156
+ # of the installation. At that time CocoaPods could have crashed.
157
+ #
158
+ def analyze
159
+ if lockfile && lockfile.cocoapods_version > Version.new(VERSION)
160
+ STDERR.puts '[!] The version of CocoaPods used to generate the lockfile is '\
161
+ 'higher that the one of the current executable. Incompatibility' \
162
+ 'issues might arise.'.yellow
163
+ end
164
+
165
+ analyzer = Analyzer.new(sandbox, podfile, lockfile)
166
+ analyzer.update_mode = update_mode
167
+ @analysis_result = analyzer.analyze
168
+ @libraries = analyzer.result.libraries
169
+ end
170
+
171
+ # Prepares the Pods folder in order to be compatible with the most recent
172
+ # version of CocoaPods.
173
+ #
174
+ # @return [void]
175
+ #
176
+ def prepare_for_legacy_compatibility
177
+ # move_target_support_files_if_needed
178
+ # move_Local_Podspecs_to_Podspecs_if_needed
179
+ # move_pods_to_sources_folder_if_needed
180
+ end
181
+
182
+ # @return [void] In this step we clean all the folders that will be
183
+ # regenerated from scratch and any file which might not be
184
+ # overwritten.
185
+ #
186
+ # @todo [#247] Clean the headers of only the pods to install.
187
+ #
188
+ def clean_sandbox
189
+ sandbox.build_headers.implode!
190
+ sandbox.public_headers.implode!
191
+
192
+ unless sandbox_state.deleted.empty?
193
+ title_options = { :verbose_prefix => "-> ".red }
194
+ sandbox_state.deleted.each do |pod_name|
195
+ UI.titled_section("Removing #{pod_name}".red, title_options) do
196
+ sandbox.clean_pod(pod_name)
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ # TODO: the file accessor should be initialized by the sandbox as they
203
+ # created by the Pod source installer as well.
204
+ #
205
+ def create_file_accessors
206
+ libraries.each do |library|
207
+ library.specs.each do |spec|
208
+ pod_root = sandbox.pod_dir(spec.root.name)
209
+ path_list = Sandbox::PathList.new(pod_root)
210
+ file_accessor = Sandbox::FileAccessor.new(path_list, spec.consumer(library.platform))
211
+ library.file_accessors ||= []
212
+ library.file_accessors << file_accessor
213
+ end
214
+ end
215
+ end
216
+
217
+ # Downloads, installs the documentation and cleans the sources of the Pods
218
+ # which need to be installed.
219
+ #
220
+ # @return [void]
221
+ #
222
+ def install_pod_sources
223
+ @installed_specs = []
224
+ pods_to_install = sandbox_state.added | sandbox_state.changed
225
+ title_options = { :verbose_prefix => "-> ".green }
226
+ root_specs.sort_by(&:name).each do |spec|
227
+ if pods_to_install.include?(spec.name)
228
+ UI.titled_section("Installing #{spec}".green, title_options) do
229
+ install_source_of_pod(spec.name)
230
+ end
231
+ else
232
+ UI.titled_section("Using #{spec}", title_options)
233
+ end
234
+ end
235
+ end
236
+
237
+ # Install the Pods. If the resolver indicated that a Pod should be
238
+ # installed and it exits, it is removed an then reinstalled. In any case if
239
+ # the Pod doesn't exits it is installed.
240
+ #
241
+ # @return [void]
242
+ #
243
+ def install_source_of_pod(pod_name)
244
+ specs_by_platform = {}
245
+ libraries.each do |library|
246
+ specs = library.specs.select { |spec| spec.root.name == pod_name }
247
+
248
+ unless specs.empty?
249
+ specs_by_platform[library.platform] ||= []
250
+ specs_by_platform[library.platform].concat(specs)
251
+ end
252
+ end
253
+
254
+ @pod_installers ||= []
255
+ pod_installer = PodSourceInstaller.new(sandbox, specs_by_platform)
256
+ pod_installer.aggressive_cache = config.aggressive_cache?
257
+ pod_installer.install!
258
+ @pod_installers << pod_installer
259
+ @installed_specs.concat(specs_by_platform.values.flatten.uniq)
260
+ end
261
+
262
+ # Cleans the sources of the Pods if the config instructs to do so.
263
+ #
264
+ # @todo Why the @pod_installers might be empty?
265
+ #
266
+ def clean_pod_sources
267
+ return unless config.clean?
268
+ return unless @pod_installers
269
+ @pod_installers.each do |pod_installer|
270
+ pod_installer.clean!
271
+ end
272
+ end
273
+
274
+ # Creates the Pods project from scratch if it doesn't exists.
275
+ #
276
+ # @return [void]
277
+ #
278
+ # @todo Clean and modify the project if it exists.
279
+ #
280
+ def prepare_pods_project
281
+ UI.message "- Creating Pods project" do
282
+ @pods_project = Pod::Project.new(sandbox.project_path)
283
+ if config.podfile_path.exist?
284
+ @pods_project.add_podfile(config.podfile_path)
285
+ end
286
+ sandbox.project = @pods_project
287
+ platforms = libraries.map(&:platform)
288
+ osx_deployment_target = platforms.select { |p| p.name == :osx }.map(&:deployment_target).min
289
+ ios_deployment_target = platforms.select { |p| p.name == :ios }.map(&:deployment_target).min
290
+ @pods_project.build_configurations.each do |build_configuration|
291
+ build_configuration.build_settings['MACOSX_DEPLOYMENT_TARGET'] = osx_deployment_target.to_s if osx_deployment_target
292
+ build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = ios_deployment_target.to_s if ios_deployment_target
293
+ end
294
+ end
295
+ end
296
+
297
+
298
+ # Installs the file references in the Pods project. This is done once per
299
+ # Pod as the same file reference might be shared by multiple targets.
300
+ #
301
+ # @return [void]
302
+ #
303
+ def install_file_references
304
+ installer = FileReferencesInstaller.new(sandbox, libraries, pods_project)
305
+ installer.install!
306
+ end
307
+
308
+ # Installs the targets of the Pods projects and generates their support
309
+ # files.
310
+ #
311
+ # @return [void]
312
+ #
313
+ def install_targets
314
+ UI.message"- Installing targets" do
315
+ libraries.sort_by(&:name).each do |library|
316
+ next if library.target_definition.empty?
317
+ target_installer = TargetInstaller.new(sandbox, library)
318
+ target_installer.install!
319
+ end
320
+ end
321
+ end
322
+
323
+ # Writes the Pods project to the disk.
324
+ #
325
+ # @return [void]
326
+ #
327
+ def write_pod_project
328
+ UI.message "- Writing Xcode project file to #{UI.path sandbox.project_path}" do
329
+ pods_project.main_group.sort_by_type!
330
+ pods_project['Frameworks'].sort_by_type!
331
+ pods_project.save_as(sandbox.project_path)
332
+ end
333
+ end
334
+
335
+ # Writes the Podfile and the lock files.
336
+ #
337
+ # @todo Pass the checkout options to the Lockfile.
338
+ #
339
+ # @return [void]
340
+ #
341
+ def write_lockfiles
342
+ # checkout_options = sandbox.checkout_options
343
+ @lockfile = Lockfile.generate(podfile, analysis_result.specifications)
344
+
345
+ UI.message "- Writing Lockfile in #{UI.path config.lockfile_path}" do
346
+ @lockfile.write_to_disk(config.lockfile_path)
347
+ end
348
+
349
+ UI.message "- Writing Manifest in #{UI.path sandbox.manifest_path}" do
350
+ @lockfile.write_to_disk(sandbox.manifest_path)
351
+ end
352
+ end
353
+
354
+ # Integrates the user projects adding the dependencies on the CocoaPods
355
+ # libraries, setting them up to use the xcconfigs and performing other
356
+ # actions. This step is also responsible of creating the workspace if
357
+ # needed.
358
+ #
359
+ # @return [void]
360
+ #
361
+ # @todo [#397] The libraries should be cleaned and the re-added on every
362
+ # installation. Maybe a clean_user_project phase should be added.
363
+ # In any case it appears to be a good idea store target definition
364
+ # information in the lockfile.
365
+ #
366
+ def integrate_user_project
367
+ UI.section "Integrating client #{'project'.pluralize(libraries.map(&:user_project_path).uniq.count) }" do
368
+ installation_root = config.installation_root
369
+ integrator = UserProjectIntegrator.new(podfile, sandbox, installation_root, libraries)
370
+ integrator.integrate!
371
+ end
372
+ end
373
+
374
+ #-------------------------------------------------------------------------#
375
+
376
+ private
377
+
378
+ # @!group Hooks
379
+
380
+ # Runs the pre install hooks of the installed specs and of the Podfile.
381
+ #
382
+ # @return [void]
383
+ #
384
+ def run_pre_install_hooks
385
+ UI.message "- Running pre install hooks" do
386
+ analysis_result.specifications.each do |spec|
387
+ executed = false
388
+ libraries_using_spec(spec).each do |lib|
389
+ lib_representation = library_rep(lib)
390
+ executed |= run_spec_pre_install_hook(spec, lib_representation)
391
+ end
392
+ UI.message "- #{spec.name}" if executed
393
+ end
394
+
395
+ executed = run_podfile_pre_install_hook
396
+ UI.message "- Podfile" if executed
397
+ end
398
+ end
399
+
400
+ # Runs the pre install hook of the given specification with the given
401
+ # library representation.
402
+ #
403
+ # @param [Specification] spec
404
+ # The spec for which the pre install hook should be run.
405
+ #
406
+ # @param [Hooks::LibraryRepresentation] lib_representation
407
+ # The library representation to be passed as an argument to the
408
+ # hook.
409
+ #
410
+ # @raise Raises an informative if the hooks raises.
411
+ #
412
+ # @return [Bool] Whether the hook was run.
413
+ #
414
+ def run_spec_pre_install_hook(spec, lib_representation)
415
+ spec.pre_install!(pod_rep(spec.root.name), lib_representation)
416
+ rescue => e
417
+ raise Informative, "An error occurred while processing the pre-install " \
418
+ "hook of #{spec}." \
419
+ "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
420
+ end
421
+
422
+ # Runs the pre install hook of the Podfile
423
+ #
424
+ # @raise Raises an informative if the hooks raises.
425
+ #
426
+ # @return [Bool] Whether the hook was run.
427
+ #
428
+ def run_podfile_pre_install_hook
429
+ podfile.pre_install!(installer_rep)
430
+ rescue => e
431
+ raise Informative, "An error occurred while processing the pre-install " \
432
+ "hook of the Podfile." \
433
+ "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
434
+ end
435
+
436
+ # Runs the post install hooks of the installed specs and of the Podfile.
437
+ #
438
+ # @note Post install hooks run _before_ saving of project, so that they
439
+ # can alter it before it is written to the disk.
440
+ #
441
+ # @return [void]
442
+ #
443
+ def run_post_install_hooks
444
+ UI.message "- Running post install hooks" do
445
+ analysis_result.specifications.each do |spec|
446
+ executed = false
447
+ libraries_using_spec(spec).each do |lib|
448
+ lib_representation = library_rep(lib)
449
+ executed |= run_spec_post_install_hook(spec, lib_representation)
450
+ end
451
+ UI.message "- #{spec.name}" if executed
452
+ end
453
+ executed = run_podfile_post_install_hook
454
+ UI.message "- Podfile" if executed
455
+ end
456
+ end
457
+
458
+
459
+ # Runs the post install hook of the given specification with the given
460
+ # library representation.
461
+ #
462
+ # @param [Specification] spec
463
+ # The spec for which the post install hook should be run.
464
+ #
465
+ # @param [Hooks::LibraryRepresentation] lib_representation
466
+ # The library representation to be passed as an argument to the
467
+ # hook.
468
+ #
469
+ # @raise Raises an informative if the hooks raises.
470
+ #
471
+ # @return [Bool] Whether the hook was run.
472
+ #
473
+ def run_spec_post_install_hook(spec, lib_representation)
474
+ spec.post_install!(lib_representation)
475
+ rescue => e
476
+ raise Informative, "An error occurred while processing the post-install " \
477
+ "hook of #{spec}." \
478
+ "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
479
+ end
480
+
481
+ # Runs the post install hook of the Podfile
482
+ #
483
+ # @raise Raises an informative if the hooks raises.
484
+ #
485
+ # @return [Bool] Whether the hook was run.
486
+ #
487
+ def run_podfile_post_install_hook
488
+ podfile.post_install!(installer_rep)
489
+ rescue => e
490
+ raise Informative, "An error occurred while processing the post-install " \
491
+ "hook of the Podfile." \
492
+ "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
493
+ end
494
+
495
+ #-------------------------------------------------------------------------#
496
+
497
+ public
498
+
499
+ # @!group Hooks Data
500
+
501
+ # @return [InstallerRepresentation]
502
+ #
503
+ def installer_rep
504
+ Hooks::InstallerRepresentation.new(self)
505
+ end
506
+
507
+ # @return [PodRepresentation] The hook representation of a Pod.
508
+ #
509
+ # @param [String] pod
510
+ # The name of the pod.
511
+ #
512
+ # @return [PodRepresentation] The pod representation.
513
+ #
514
+ def pod_rep(pod)
515
+ all_file_accessors = libraries.map(&:file_accessors).flatten.compact
516
+ file_accessors = all_file_accessors.select { |fa| fa.spec.root.name == pod }
517
+ Hooks::PodRepresentation.new(pod, file_accessors)
518
+ end
519
+
520
+ # @return [LibraryRepresentation]
521
+ #
522
+ def library_rep(library)
523
+ Hooks::LibraryRepresentation.new(sandbox, library)
524
+ end
525
+
526
+ # @return [Array<LibraryRepresentation>]
527
+ #
528
+ def library_reps
529
+ @library_reps ||= libraries.map { |lib| library_rep(lib) }
530
+ end
531
+
532
+ # @return [Array<PodRepresentation>]
533
+ #
534
+ def pod_reps
535
+ root_specs.sort_by { |spec| spec.name }.map { |spec| pod_rep(spec.name) }
536
+ end
537
+
538
+ # Returns the libraries which use the given specification.
539
+ #
540
+ # @param [Specification] spec
541
+ # The specification for which the client libraries are needed.
542
+ #
543
+ # @return [Array<Library>] The library.
544
+ #
545
+ def libraries_using_spec(spec)
546
+ libraries.select { |lib| lib.specs.include?(spec) }
547
+ end
548
+
549
+ #-------------------------------------------------------------------------#
550
+
551
+ private
552
+
553
+ # @!group Private helpers
554
+
555
+ # @return [Array<Specification>] All the root specifications of the
556
+ # installation.
557
+ #
558
+ def root_specs
559
+ analysis_result.specifications.map { |spec| spec.root }.uniq
560
+ end
561
+
562
+ # @return [SpecsState] The state of the sandbox returned by the analyzer.
563
+ #
564
+ def sandbox_state
565
+ analysis_result.sandbox_state
566
+ end
567
+
568
+ #-------------------------------------------------------------------------#
569
+
570
+ end
571
+ end