| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | describe "globally-scoped helper methods" do | 
					
						
							| 
									
										
										
										
											2017-02-28 14:50:46 +01:00
										 |  |  |   let(:dir) { mktmpdir } | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def esc(code) | 
					
						
							|  |  |  |     /(\e\[\d+m)*\e\[#{code}m/ | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#ofail" do | 
					
						
							|  |  |  |     it "sets Homebrew.failed to true" do | 
					
						
							| 
									
										
										
										
											2017-02-18 16:52:36 +01:00
										 |  |  |       expect { | 
					
						
							|  |  |  |         ofail "foo" | 
					
						
							|  |  |  |       }.to output("Error: foo\n").to_stderr | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 16:52:36 +01:00
										 |  |  |       expect(Homebrew).to have_failed | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#odie" do | 
					
						
							|  |  |  |     it "exits with 1" do | 
					
						
							|  |  |  |       expect(self).to receive(:exit).and_return(1) | 
					
						
							|  |  |  |       expect { | 
					
						
							|  |  |  |         odie "foo" | 
					
						
							|  |  |  |       }.to output("Error: foo\n").to_stderr | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#pretty_installed" do | 
					
						
							|  |  |  |     subject { pretty_installed("foo") } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     context "when $stdout is a TTY" do | 
					
						
							| 
									
										
										
										
											2018-03-25 13:30:37 +01:00
										 |  |  |       before { allow($stdout).to receive(:tty?).and_return(true) } | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       context "with HOMEBREW_NO_EMOJI unset" do | 
					
						
							|  |  |  |         it "returns a string with a colored checkmark" do | 
					
						
							|  |  |  |           expect(subject) | 
					
						
							|  |  |  |             .to match(/#{esc 1}foo #{esc 32}✔#{esc 0}/) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       context "with HOMEBREW_NO_EMOJI set" do | 
					
						
							| 
									
										
										
										
											2018-03-25 13:30:37 +01:00
										 |  |  |         before { ENV["HOMEBREW_NO_EMOJI"] = "1" } | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         it "returns a string with colored info" do | 
					
						
							|  |  |  |           expect(subject) | 
					
						
							|  |  |  |             .to match(/#{esc 1}foo \(installed\)#{esc 0}/) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     context "when $stdout is not a TTY" do | 
					
						
							| 
									
										
										
										
											2018-03-25 13:30:37 +01:00
										 |  |  |       before { allow($stdout).to receive(:tty?).and_return(false) } | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it "returns plain text" do | 
					
						
							|  |  |  |         expect(subject).to eq("foo") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#pretty_uninstalled" do | 
					
						
							|  |  |  |     subject { pretty_uninstalled("foo") } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     context "when $stdout is a TTY" do | 
					
						
							| 
									
										
										
										
											2018-03-25 13:30:37 +01:00
										 |  |  |       before { allow($stdout).to receive(:tty?).and_return(true) } | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       context "with HOMEBREW_NO_EMOJI unset" do | 
					
						
							|  |  |  |         it "returns a string with a colored checkmark" do | 
					
						
							|  |  |  |           expect(subject) | 
					
						
							|  |  |  |             .to match(/#{esc 1}foo #{esc 31}✘#{esc 0}/) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       context "with HOMEBREW_NO_EMOJI set" do | 
					
						
							| 
									
										
										
										
											2018-03-25 13:30:37 +01:00
										 |  |  |         before { ENV["HOMEBREW_NO_EMOJI"] = "1" } | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         it "returns a string with colored info" do | 
					
						
							|  |  |  |           expect(subject) | 
					
						
							|  |  |  |             .to match(/#{esc 1}foo \(uninstalled\)#{esc 0}/) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     context "when $stdout is not a TTY" do | 
					
						
							| 
									
										
										
										
											2018-03-25 13:30:37 +01:00
										 |  |  |       before { allow($stdout).to receive(:tty?).and_return(false) } | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it "returns plain text" do | 
					
						
							|  |  |  |         expect(subject).to eq("foo") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#interactive_shell" do | 
					
						
							|  |  |  |     let(:shell) { dir/"myshell" } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "starts an interactive shell session" do | 
					
						
							| 
									
										
										
										
											2018-07-11 15:17:40 +02:00
										 |  |  |       IO.write shell, <<~SH | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  |         #!/bin/sh | 
					
						
							|  |  |  |         echo called > "#{dir}/called" | 
					
						
							| 
									
										
										
										
											2018-07-11 15:17:40 +02:00
										 |  |  |       SH | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       FileUtils.chmod 0755, shell | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ENV["SHELL"] = shell | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect { interactive_shell }.not_to raise_error | 
					
						
							|  |  |  |       expect(dir/"called").to exist | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#with_custom_locale" do | 
					
						
							|  |  |  |     it "temporarily overrides the system locale" do | 
					
						
							|  |  |  |       ENV["LC_ALL"] = "en_US.UTF-8" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       with_custom_locale("C") do | 
					
						
							|  |  |  |         expect(ENV["LC_ALL"]).to eq("C") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(ENV["LC_ALL"]).to eq("en_US.UTF-8") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#which" do | 
					
						
							|  |  |  |     let(:cmd) { dir/"foo" } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 13:30:37 +01:00
										 |  |  |     before { FileUtils.touch cmd } | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it "returns the first executable that is found" do | 
					
						
							|  |  |  |       cmd.chmod 0744
 | 
					
						
							|  |  |  |       expect(which(File.basename(cmd), File.dirname(cmd))).to eq(cmd) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "skips non-executables" do | 
					
						
							|  |  |  |       expect(which(File.basename(cmd), File.dirname(cmd))).to be nil | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "skips malformed path and doesn't fail" do | 
					
						
							|  |  |  |       # 'which' should not fail if a path is malformed | 
					
						
							|  |  |  |       # see https://github.com/Homebrew/legacy-homebrew/issues/32789 for an example | 
					
						
							|  |  |  |       cmd.chmod 0744
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # ~~ will fail because ~foo resolves to foo's home and there is no '~' user | 
					
						
							|  |  |  |       path = ["~~", File.dirname(cmd)].join(File::PATH_SEPARATOR) | 
					
						
							|  |  |  |       expect(which(File.basename(cmd), path)).to eq(cmd) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#which_all" do | 
					
						
							|  |  |  |     let(:cmd1) { dir/"foo" } | 
					
						
							|  |  |  |     let(:cmd2) { dir/"bar/foo" } | 
					
						
							|  |  |  |     let(:cmd3) { dir/"bar/baz/foo" } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-25 13:30:37 +01:00
										 |  |  |     before do | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  |       (dir/"bar/baz").mkpath | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       FileUtils.touch cmd2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       [cmd1, cmd3].each do |cmd| | 
					
						
							|  |  |  |         FileUtils.touch cmd | 
					
						
							|  |  |  |         cmd.chmod 0744
 | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "returns an array of all executables that are found" do | 
					
						
							|  |  |  |       path = [ | 
					
						
							|  |  |  |         "#{dir}/bar/baz", | 
					
						
							|  |  |  |         "#{dir}/baz:#{dir}", | 
					
						
							|  |  |  |         "~baduserpath", | 
					
						
							|  |  |  |       ].join(File::PATH_SEPARATOR) | 
					
						
							|  |  |  |       expect(which_all("foo", path)).to eq([cmd3, cmd1]) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   specify "#which_editor" do | 
					
						
							| 
									
										
										
										
											2017-06-01 17:45:07 -07:00
										 |  |  |     ENV["HOMEBREW_EDITOR"] = "vemate -w" | 
					
						
							| 
									
										
										
										
											2017-04-19 10:49:20 +01:00
										 |  |  |     ENV["HOMEBREW_PATH"] = dir | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-24 08:49:11 +01:00
										 |  |  |     editor = "#{dir}/vemate" | 
					
						
							| 
									
										
										
										
											2017-04-19 10:49:20 +01:00
										 |  |  |     FileUtils.touch editor | 
					
						
							|  |  |  |     FileUtils.chmod 0755, editor | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-01 17:45:07 -07:00
										 |  |  |     expect(which_editor).to eq("vemate -w") | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   specify "#gzip" do | 
					
						
							| 
									
										
										
										
											2017-02-28 14:50:46 +01:00
										 |  |  |     mktmpdir do |path| | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  |       somefile = path/"somefile" | 
					
						
							|  |  |  |       FileUtils.touch somefile | 
					
						
							|  |  |  |       expect(gzip(somefile)[0].to_s).to eq("#{somefile}.gz") | 
					
						
							|  |  |  |       expect(Pathname.new("#{somefile}.gz")).to exist | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   specify "#capture_stderr" do | 
					
						
							|  |  |  |     err = capture_stderr do | 
					
						
							|  |  |  |       $stderr.print "test" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(err).to eq("test") | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#pretty_duration" do | 
					
						
							|  |  |  |     it "converts seconds to a human-readable string" do | 
					
						
							|  |  |  |       expect(pretty_duration(1)).to eq("1 second") | 
					
						
							|  |  |  |       expect(pretty_duration(2.5)).to eq("2 seconds") | 
					
						
							|  |  |  |       expect(pretty_duration(42)).to eq("42 seconds") | 
					
						
							|  |  |  |       expect(pretty_duration(240)).to eq("4 minutes") | 
					
						
							|  |  |  |       expect(pretty_duration(252.45)).to eq("4 minutes 12 seconds") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   specify "#disk_usage_readable" do | 
					
						
							|  |  |  |     expect(disk_usage_readable(1)).to eq("1B") | 
					
						
							|  |  |  |     expect(disk_usage_readable(1000)).to eq("1000B") | 
					
						
							| 
									
										
										
										
											2017-02-25 11:09:57 +00:00
										 |  |  |     expect(disk_usage_readable(1024)).to eq("1KB") | 
					
						
							|  |  |  |     expect(disk_usage_readable(1025)).to eq("1KB") | 
					
						
							|  |  |  |     expect(disk_usage_readable(4_404_020)).to eq("4.2MB") | 
					
						
							|  |  |  |     expect(disk_usage_readable(4_509_715_660)).to eq("4.2GB") | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#number_readable" do | 
					
						
							|  |  |  |     it "returns a string with thousands separators" do | 
					
						
							|  |  |  |       expect(number_readable(1)).to eq("1") | 
					
						
							|  |  |  |       expect(number_readable(1_000)).to eq("1,000") | 
					
						
							|  |  |  |       expect(number_readable(1_000_000)).to eq("1,000,000") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   specify "#truncate_text_to_approximate_size" do | 
					
						
							|  |  |  |     glue = "\n[...snip...]\n" # hard-coded copy from truncate_text_to_approximate_size | 
					
						
							|  |  |  |     n = 20
 | 
					
						
							|  |  |  |     long_s = "x" * 40
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s = truncate_text_to_approximate_size(long_s, n) | 
					
						
							|  |  |  |     expect(s.length).to eq(n) | 
					
						
							|  |  |  |     expect(s).to match(/^x+#{Regexp.escape(glue)}x+$/) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s = truncate_text_to_approximate_size(long_s, n, front_weight: 0.0) | 
					
						
							|  |  |  |     expect(s).to eq(glue + ("x" * (n - glue.length))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s = truncate_text_to_approximate_size(long_s, n, front_weight: 1.0) | 
					
						
							|  |  |  |     expect(s).to eq(("x" * (n - glue.length)) + glue) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#odeprecated" do | 
					
						
							| 
									
										
										
										
											2018-08-15 12:13:21 +02:00
										 |  |  |     it "raises a MethodDeprecatedError when `disable` is true" do | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  |       ENV.delete("HOMEBREW_DEVELOPER") | 
					
						
							|  |  |  |       expect { | 
					
						
							|  |  |  |         odeprecated( | 
					
						
							|  |  |  |           "method", "replacement", | 
					
						
							| 
									
										
										
										
											2018-11-02 17:18:07 +00:00
										 |  |  |           caller:  ["#{HOMEBREW_LIBRARY}/Taps/homebrew/homebrew-core/"], | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  |           disable: true | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2018-09-02 16:15:09 +01:00
										 |  |  |       }.to raise_error( | 
					
						
							|  |  |  |         MethodDeprecatedError, | 
					
						
							|  |  |  |         %r{method.*replacement.*homebrew/core.*\/Taps\/homebrew\/homebrew-core\/}m, | 
					
						
							|  |  |  |       ) | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2017-07-13 17:14:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   describe "#with_env" do | 
					
						
							|  |  |  |     it "sets environment variables within the block" do | 
					
						
							|  |  |  |       expect(ENV["PATH"]).not_to eq("/bin") | 
					
						
							| 
									
										
										
										
											2017-10-29 14:44:43 +00:00
										 |  |  |       with_env(PATH: "/bin") do | 
					
						
							| 
									
										
										
										
											2017-07-13 17:14:21 -07:00
										 |  |  |         expect(ENV["PATH"]).to eq("/bin") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "restores ENV after the block" do | 
					
						
							| 
									
										
										
										
											2017-10-29 14:44:43 +00:00
										 |  |  |       with_env(PATH: "/bin") do | 
					
						
							| 
									
										
										
										
											2017-07-13 17:14:21 -07:00
										 |  |  |         expect(ENV["PATH"]).to eq("/bin") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       expect(ENV["PATH"]).not_to eq("/bin") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "restores ENV if an exception is raised" do | 
					
						
							|  |  |  |       expect { | 
					
						
							| 
									
										
										
										
											2017-10-29 14:44:43 +00:00
										 |  |  |         with_env(PATH: "/bin") do | 
					
						
							| 
									
										
										
										
											2017-07-13 17:14:21 -07:00
										 |  |  |           raise StandardError, "boom" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       }.to raise_error(StandardError) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(ENV["PATH"]).not_to eq("/bin") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2017-07-08 19:33:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   describe "#tap_and_name_comparison" do | 
					
						
							|  |  |  |     describe "both strings are only names" do | 
					
						
							|  |  |  |       it "alphabetizes the strings" do | 
					
						
							|  |  |  |         expect(%w[a b].sort(&tap_and_name_comparison)).to eq(%w[a b]) | 
					
						
							|  |  |  |         expect(%w[b a].sort(&tap_and_name_comparison)).to eq(%w[a b]) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe "both strings include tap" do | 
					
						
							|  |  |  |       it "alphabetizes the strings" do | 
					
						
							|  |  |  |         expect(%w[a/z/z b/z/z].sort(&tap_and_name_comparison)).to eq(%w[a/z/z b/z/z]) | 
					
						
							|  |  |  |         expect(%w[b/z/z a/z/z].sort(&tap_and_name_comparison)).to eq(%w[a/z/z b/z/z]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(%w[z/a/z z/b/z].sort(&tap_and_name_comparison)).to eq(%w[z/a/z z/b/z]) | 
					
						
							|  |  |  |         expect(%w[z/b/z z/a/z].sort(&tap_and_name_comparison)).to eq(%w[z/a/z z/b/z]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(%w[z/z/a z/z/b].sort(&tap_and_name_comparison)).to eq(%w[z/z/a z/z/b]) | 
					
						
							|  |  |  |         expect(%w[z/z/b z/z/a].sort(&tap_and_name_comparison)).to eq(%w[z/z/a z/z/b]) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe "only one string includes tap" do | 
					
						
							|  |  |  |       it "prefers the string without tap" do | 
					
						
							|  |  |  |         expect(%w[a/z/z z].sort(&tap_and_name_comparison)).to eq(%w[z a/z/z]) | 
					
						
							|  |  |  |         expect(%w[z a/z/z].sort(&tap_and_name_comparison)).to eq(%w[z a/z/z]) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2017-02-16 21:17:46 +01:00
										 |  |  | end |