mirror of https://github.com/python/cpython
Fix for #5257: refactored all tests in distutils, so they use a temporary directory.
This commit is contained in:
parent
a4038038c6
commit
1369900619
|
@ -1,5 +1,5 @@
|
||||||
"""Support code for distutils test cases."""
|
"""Support code for distutils test cases."""
|
||||||
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class TempdirManager(object):
|
||||||
super(TempdirManager, self).tearDown()
|
super(TempdirManager, self).tearDown()
|
||||||
while self.tempdirs:
|
while self.tempdirs:
|
||||||
d = self.tempdirs.pop()
|
d = self.tempdirs.pop()
|
||||||
shutil.rmtree(d)
|
shutil.rmtree(d, os.name in ('nt', 'cygwin'))
|
||||||
|
|
||||||
def mkdtemp(self):
|
def mkdtemp(self):
|
||||||
"""Create a temporary directory that will be cleaned up.
|
"""Create a temporary directory that will be cleaned up.
|
||||||
|
|
|
@ -7,6 +7,7 @@ from StringIO import StringIO
|
||||||
from distutils.core import Extension, Distribution
|
from distutils.core import Extension, Distribution
|
||||||
from distutils.command.build_ext import build_ext
|
from distutils.command.build_ext import build_ext
|
||||||
from distutils import sysconfig
|
from distutils import sysconfig
|
||||||
|
from distutils.tests import support
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from test import test_support
|
from test import test_support
|
||||||
|
@ -19,11 +20,12 @@ def _get_source_filename():
|
||||||
srcdir = sysconfig.get_config_var('srcdir')
|
srcdir = sysconfig.get_config_var('srcdir')
|
||||||
return os.path.join(srcdir, 'Modules', 'xxmodule.c')
|
return os.path.join(srcdir, 'Modules', 'xxmodule.c')
|
||||||
|
|
||||||
class BuildExtTestCase(unittest.TestCase):
|
class BuildExtTestCase(support.TempdirManager, unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Create a simple test environment
|
# Create a simple test environment
|
||||||
# Note that we're making changes to sys.path
|
# Note that we're making changes to sys.path
|
||||||
self.tmp_dir = tempfile.mkdtemp(prefix="pythontest_")
|
support.TempdirManager.setUp(self)
|
||||||
|
self.tmp_dir = self.mkdtemp()
|
||||||
self.sys_path = sys.path[:]
|
self.sys_path = sys.path[:]
|
||||||
sys.path.append(self.tmp_dir)
|
sys.path.append(self.tmp_dir)
|
||||||
shutil.copy(_get_source_filename(), self.tmp_dir)
|
shutil.copy(_get_source_filename(), self.tmp_dir)
|
||||||
|
@ -74,8 +76,7 @@ class BuildExtTestCase(unittest.TestCase):
|
||||||
# Get everything back to normal
|
# Get everything back to normal
|
||||||
test_support.unload('xx')
|
test_support.unload('xx')
|
||||||
sys.path = self.sys_path
|
sys.path = self.sys_path
|
||||||
# XXX on Windows the test leaves a directory with xx module in TEMP
|
support.TempdirManager.tearDown(self)
|
||||||
shutil.rmtree(self.tmp_dir, os.name == 'nt' or sys.platform == 'cygwin')
|
|
||||||
|
|
||||||
def test_solaris_enable_shared(self):
|
def test_solaris_enable_shared(self):
|
||||||
dist = Distribution({'name': 'xx'})
|
dist = Distribution({'name': 'xx'})
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
|
||||||
from distutils.core import PyPIRCCommand
|
from distutils.core import PyPIRCCommand
|
||||||
from distutils.core import Distribution
|
from distutils.core import Distribution
|
||||||
|
@ -49,13 +51,15 @@ class PyPIRCCommandTestCase(support.TempdirManager, unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Patches the environment."""
|
"""Patches the environment."""
|
||||||
|
support.TempdirManager.setUp(self)
|
||||||
|
|
||||||
if os.environ.has_key('HOME'):
|
if os.environ.has_key('HOME'):
|
||||||
self._old_home = os.environ['HOME']
|
self._old_home = os.environ['HOME']
|
||||||
else:
|
else:
|
||||||
self._old_home = None
|
self._old_home = None
|
||||||
curdir = os.path.dirname(__file__)
|
self.tmp_dir = self.mkdtemp()
|
||||||
os.environ['HOME'] = curdir
|
os.environ['HOME'] = self.tmp_dir
|
||||||
self.rc = os.path.join(curdir, '.pypirc')
|
self.rc = os.path.join(self.tmp_dir, '.pypirc')
|
||||||
self.dist = Distribution()
|
self.dist = Distribution()
|
||||||
|
|
||||||
class command(PyPIRCCommand):
|
class command(PyPIRCCommand):
|
||||||
|
@ -74,9 +78,8 @@ class PyPIRCCommandTestCase(support.TempdirManager, unittest.TestCase):
|
||||||
del os.environ['HOME']
|
del os.environ['HOME']
|
||||||
else:
|
else:
|
||||||
os.environ['HOME'] = self._old_home
|
os.environ['HOME'] = self._old_home
|
||||||
if os.path.exists(self.rc):
|
|
||||||
os.remove(self.rc)
|
|
||||||
set_threshold(self.old_threshold)
|
set_threshold(self.old_threshold)
|
||||||
|
support.TempdirManager.tearDown(self)
|
||||||
|
|
||||||
def test_server_registration(self):
|
def test_server_registration(self):
|
||||||
# This test makes sure PyPIRCCommand knows how to:
|
# This test makes sure PyPIRCCommand knows how to:
|
||||||
|
|
|
@ -9,8 +9,9 @@ from distutils.dir_util import create_tree
|
||||||
from distutils.dir_util import copy_tree
|
from distutils.dir_util import copy_tree
|
||||||
|
|
||||||
from distutils import log
|
from distutils import log
|
||||||
|
from distutils.tests import support
|
||||||
|
|
||||||
class DirUtilTestCase(unittest.TestCase):
|
class DirUtilTestCase(support.TempdirManager, unittest.TestCase):
|
||||||
|
|
||||||
def _log(self, msg, *args):
|
def _log(self, msg, *args):
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
|
@ -19,18 +20,18 @@ class DirUtilTestCase(unittest.TestCase):
|
||||||
self._logs.append(msg)
|
self._logs.append(msg)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
support.TempdirManager.setUp(self)
|
||||||
self._logs = []
|
self._logs = []
|
||||||
self.root_target = os.path.join(os.path.dirname(__file__), 'deep')
|
tmp_dir = self.mkdtemp()
|
||||||
|
self.root_target = os.path.join(tmp_dir, 'deep')
|
||||||
self.target = os.path.join(self.root_target, 'here')
|
self.target = os.path.join(self.root_target, 'here')
|
||||||
self.target2 = os.path.join(os.path.dirname(__file__), 'deep2')
|
self.target2 = os.path.join(tmp_dir, 'deep2')
|
||||||
self.old_log = log.info
|
self.old_log = log.info
|
||||||
log.info = self._log
|
log.info = self._log
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
for target in (self.target, self.target2):
|
|
||||||
if os.path.exists(target):
|
|
||||||
shutil.rmtree(target)
|
|
||||||
log.info = self.old_log
|
log.info = self.old_log
|
||||||
|
support.TempdirManager.tearDown(self)
|
||||||
|
|
||||||
def test_mkpath_remove_tree_verbosity(self):
|
def test_mkpath_remove_tree_verbosity(self):
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import unittest
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from test.test_support import TESTFN
|
from test.test_support import TESTFN
|
||||||
|
from distutils.tests import support
|
||||||
|
|
||||||
class test_dist(distutils.cmd.Command):
|
class test_dist(distutils.cmd.Command):
|
||||||
"""Sample distutils extension command."""
|
"""Sample distutils extension command."""
|
||||||
|
@ -36,14 +36,16 @@ class TestDistribution(distutils.dist.Distribution):
|
||||||
return self._config_files
|
return self._config_files
|
||||||
|
|
||||||
|
|
||||||
class DistributionTestCase(unittest.TestCase):
|
class DistributionTestCase(support.TempdirManager, unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
support.TempdirManager.setUp(self)
|
||||||
self.argv = sys.argv[:]
|
self.argv = sys.argv[:]
|
||||||
del sys.argv[1:]
|
del sys.argv[1:]
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
sys.argv[:] = self.argv
|
sys.argv[:] = self.argv
|
||||||
|
support.TempdirManager.tearDown(self)
|
||||||
|
|
||||||
def create_distribution(self, configfiles=()):
|
def create_distribution(self, configfiles=()):
|
||||||
d = TestDistribution()
|
d = TestDistribution()
|
||||||
|
@ -100,7 +102,8 @@ class DistributionTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_write_pkg_file(self):
|
def test_write_pkg_file(self):
|
||||||
# Check DistributionMetadata handling of Unicode fields
|
# Check DistributionMetadata handling of Unicode fields
|
||||||
my_file = os.path.join(os.path.dirname(__file__), 'f')
|
tmp_dir = self.mkdtemp()
|
||||||
|
my_file = os.path.join(tmp_dir, 'f')
|
||||||
klass = distutils.dist.Distribution
|
klass = distutils.dist.Distribution
|
||||||
|
|
||||||
dist = klass(attrs={'author': u'Mister Café',
|
dist = klass(attrs={'author': u'Mister Café',
|
||||||
|
@ -113,11 +116,7 @@ class DistributionTestCase(unittest.TestCase):
|
||||||
# let's make sure the file can be written
|
# let's make sure the file can be written
|
||||||
# with Unicode fields. they are encoded with
|
# with Unicode fields. they are encoded with
|
||||||
# PKG_INFO_ENCODING
|
# PKG_INFO_ENCODING
|
||||||
try:
|
dist.metadata.write_pkg_file(open(my_file, 'w'))
|
||||||
dist.metadata.write_pkg_file(open(my_file, 'w'))
|
|
||||||
finally:
|
|
||||||
if os.path.exists(my_file):
|
|
||||||
os.remove(my_file)
|
|
||||||
|
|
||||||
# regular ascii is of course always usable
|
# regular ascii is of course always usable
|
||||||
dist = klass(attrs={'author': 'Mister Cafe',
|
dist = klass(attrs={'author': 'Mister Cafe',
|
||||||
|
@ -126,11 +125,8 @@ class DistributionTestCase(unittest.TestCase):
|
||||||
'description': 'Cafe torrefie',
|
'description': 'Cafe torrefie',
|
||||||
'long_description': 'Hehehe'})
|
'long_description': 'Hehehe'})
|
||||||
|
|
||||||
try:
|
my_file2 = os.path.join(tmp_dir, 'f2')
|
||||||
dist.metadata.write_pkg_file(open(my_file, 'w'))
|
dist.metadata.write_pkg_file(open(my_file, 'w'))
|
||||||
finally:
|
|
||||||
if os.path.exists(my_file):
|
|
||||||
os.remove(my_file)
|
|
||||||
|
|
||||||
def test_empty_options(self):
|
def test_empty_options(self):
|
||||||
# an empty options dictionary should not stay in the
|
# an empty options dictionary should not stay in the
|
||||||
|
@ -155,7 +151,7 @@ class DistributionTestCase(unittest.TestCase):
|
||||||
|
|
||||||
self.assertEquals(len(warns), 0)
|
self.assertEquals(len(warns), 0)
|
||||||
|
|
||||||
class MetadataTestCase(unittest.TestCase):
|
class MetadataTestCase(support.TempdirManager, unittest.TestCase):
|
||||||
|
|
||||||
def test_simple_metadata(self):
|
def test_simple_metadata(self):
|
||||||
attrs = {"name": "package",
|
attrs = {"name": "package",
|
||||||
|
@ -254,8 +250,8 @@ class MetadataTestCase(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
user_filename = "pydistutils.cfg"
|
user_filename = "pydistutils.cfg"
|
||||||
|
|
||||||
curdir = os.path.dirname(__file__)
|
temp_dir = self.mkdtemp()
|
||||||
user_filename = os.path.join(curdir, user_filename)
|
user_filename = os.path.join(temp_dir, user_filename)
|
||||||
f = open(user_filename, 'w')
|
f = open(user_filename, 'w')
|
||||||
f.write('.')
|
f.write('.')
|
||||||
f.close()
|
f.close()
|
||||||
|
@ -265,7 +261,7 @@ class MetadataTestCase(unittest.TestCase):
|
||||||
|
|
||||||
# linux-style
|
# linux-style
|
||||||
if sys.platform in ('linux', 'darwin'):
|
if sys.platform in ('linux', 'darwin'):
|
||||||
os.environ['HOME'] = curdir
|
os.environ['HOME'] = temp_dir
|
||||||
files = dist.find_config_files()
|
files = dist.find_config_files()
|
||||||
self.assert_(user_filename in files)
|
self.assert_(user_filename in files)
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,9 @@ import shutil
|
||||||
|
|
||||||
from distutils.file_util import move_file
|
from distutils.file_util import move_file
|
||||||
from distutils import log
|
from distutils import log
|
||||||
|
from distutils.tests import support
|
||||||
|
|
||||||
class FileUtilTestCase(unittest.TestCase):
|
class FileUtilTestCase(support.TempdirManager, unittest.TestCase):
|
||||||
|
|
||||||
def _log(self, msg, *args):
|
def _log(self, msg, *args):
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
|
@ -15,24 +16,20 @@ class FileUtilTestCase(unittest.TestCase):
|
||||||
self._logs.append(msg)
|
self._logs.append(msg)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
support.TempdirManager.setUp(self)
|
||||||
self._logs = []
|
self._logs = []
|
||||||
self.old_log = log.info
|
self.old_log = log.info
|
||||||
log.info = self._log
|
log.info = self._log
|
||||||
self.source = os.path.join(os.path.dirname(__file__), 'f1')
|
tmp_dir = self.mkdtemp()
|
||||||
self.target = os.path.join(os.path.dirname(__file__), 'f2')
|
self.source = os.path.join(tmp_dir, 'f1')
|
||||||
self.target_dir = os.path.join(os.path.dirname(__file__), 'd1')
|
self.target = os.path.join(tmp_dir, 'f2')
|
||||||
|
self.target_dir = os.path.join(tmp_dir, 'd1')
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
log.info = self.old_log
|
log.info = self.old_log
|
||||||
for f in (self.source, self.target, self.target_dir):
|
support.TempdirManager.tearDown(self)
|
||||||
if os.path.exists(f):
|
|
||||||
if os.path.isfile(f):
|
|
||||||
os.remove(f)
|
|
||||||
else:
|
|
||||||
shutil.rmtree(f)
|
|
||||||
|
|
||||||
def test_move_file_verbosity(self):
|
def test_move_file_verbosity(self):
|
||||||
|
|
||||||
f = open(self.source, 'w')
|
f = open(self.source, 'w')
|
||||||
f.write('some content')
|
f.write('some content')
|
||||||
f.close()
|
f.close()
|
||||||
|
|
|
@ -5,6 +5,7 @@ import shutil
|
||||||
import zipfile
|
import zipfile
|
||||||
from os.path import join
|
from os.path import join
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from distutils.command.sdist import sdist
|
from distutils.command.sdist import sdist
|
||||||
from distutils.core import Distribution
|
from distutils.core import Distribution
|
||||||
|
@ -12,9 +13,6 @@ from distutils.tests.test_config import PyPIRCCommandTestCase
|
||||||
from distutils.errors import DistutilsExecError
|
from distutils.errors import DistutilsExecError
|
||||||
from distutils.spawn import find_executable
|
from distutils.spawn import find_executable
|
||||||
|
|
||||||
CURDIR = os.path.dirname(__file__)
|
|
||||||
TEMP_PKG = join(CURDIR, 'temppkg')
|
|
||||||
|
|
||||||
SETUP_PY = """
|
SETUP_PY = """
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
import somecode
|
import somecode
|
||||||
|
@ -29,28 +27,25 @@ recursive-include somecode *
|
||||||
class sdistTestCase(PyPIRCCommandTestCase):
|
class sdistTestCase(PyPIRCCommandTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
# PyPIRCCommandTestCase creates a temp dir already
|
||||||
|
# and put it in self.tmp_dir
|
||||||
PyPIRCCommandTestCase.setUp(self)
|
PyPIRCCommandTestCase.setUp(self)
|
||||||
|
# setting up an environment
|
||||||
self.old_path = os.getcwd()
|
self.old_path = os.getcwd()
|
||||||
|
os.mkdir(join(self.tmp_dir, 'somecode'))
|
||||||
|
os.mkdir(join(self.tmp_dir, 'dist'))
|
||||||
|
# creating a MANIFEST, a package, and a README
|
||||||
|
self._write(join(self.tmp_dir, 'MANIFEST.in'), MANIFEST_IN)
|
||||||
|
self._write(join(self.tmp_dir, 'README'), 'xxx')
|
||||||
|
self._write(join(self.tmp_dir, 'somecode', '__init__.py'), '#')
|
||||||
|
self._write(join(self.tmp_dir, 'setup.py'), SETUP_PY)
|
||||||
|
os.chdir(self.tmp_dir)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
# back to normal
|
||||||
os.chdir(self.old_path)
|
os.chdir(self.old_path)
|
||||||
if os.path.exists(TEMP_PKG):
|
|
||||||
shutil.rmtree(TEMP_PKG)
|
|
||||||
PyPIRCCommandTestCase.tearDown(self)
|
PyPIRCCommandTestCase.tearDown(self)
|
||||||
|
|
||||||
def _init_tmp_pkg(self):
|
|
||||||
if os.path.exists(TEMP_PKG):
|
|
||||||
shutil.rmtree(TEMP_PKG)
|
|
||||||
os.mkdir(TEMP_PKG)
|
|
||||||
os.mkdir(join(TEMP_PKG, 'somecode'))
|
|
||||||
os.mkdir(join(TEMP_PKG, 'dist'))
|
|
||||||
# creating a MANIFEST, a package, and a README
|
|
||||||
self._write(join(TEMP_PKG, 'MANIFEST.in'), MANIFEST_IN)
|
|
||||||
self._write(join(TEMP_PKG, 'README'), 'xxx')
|
|
||||||
self._write(join(TEMP_PKG, 'somecode', '__init__.py'), '#')
|
|
||||||
self._write(join(TEMP_PKG, 'setup.py'), SETUP_PY)
|
|
||||||
os.chdir(TEMP_PKG)
|
|
||||||
|
|
||||||
def _write(self, path, content):
|
def _write(self, path, content):
|
||||||
f = open(path, 'w')
|
f = open(path, 'w')
|
||||||
try:
|
try:
|
||||||
|
@ -62,18 +57,17 @@ class sdistTestCase(PyPIRCCommandTestCase):
|
||||||
# this test creates a package with some vcs dirs in it
|
# this test creates a package with some vcs dirs in it
|
||||||
# and launch sdist to make sure they get pruned
|
# and launch sdist to make sure they get pruned
|
||||||
# on all systems
|
# on all systems
|
||||||
self._init_tmp_pkg()
|
|
||||||
|
|
||||||
# creating VCS directories with some files in them
|
# creating VCS directories with some files in them
|
||||||
os.mkdir(join(TEMP_PKG, 'somecode', '.svn'))
|
os.mkdir(join(self.tmp_dir, 'somecode', '.svn'))
|
||||||
self._write(join(TEMP_PKG, 'somecode', '.svn', 'ok.py'), 'xxx')
|
self._write(join(self.tmp_dir, 'somecode', '.svn', 'ok.py'), 'xxx')
|
||||||
|
|
||||||
os.mkdir(join(TEMP_PKG, 'somecode', '.hg'))
|
os.mkdir(join(self.tmp_dir, 'somecode', '.hg'))
|
||||||
self._write(join(TEMP_PKG, 'somecode', '.hg',
|
self._write(join(self.tmp_dir, 'somecode', '.hg',
|
||||||
'ok'), 'xxx')
|
'ok'), 'xxx')
|
||||||
|
|
||||||
os.mkdir(join(TEMP_PKG, 'somecode', '.git'))
|
os.mkdir(join(self.tmp_dir, 'somecode', '.git'))
|
||||||
self._write(join(TEMP_PKG, 'somecode', '.git',
|
self._write(join(self.tmp_dir, 'somecode', '.git',
|
||||||
'ok'), 'xxx')
|
'ok'), 'xxx')
|
||||||
|
|
||||||
# now building a sdist
|
# now building a sdist
|
||||||
|
@ -96,7 +90,7 @@ class sdistTestCase(PyPIRCCommandTestCase):
|
||||||
cmd.run()
|
cmd.run()
|
||||||
|
|
||||||
# now let's check what we have
|
# now let's check what we have
|
||||||
dist_folder = join(TEMP_PKG, 'dist')
|
dist_folder = join(self.tmp_dir, 'dist')
|
||||||
files = os.listdir(dist_folder)
|
files = os.listdir(dist_folder)
|
||||||
self.assertEquals(files, ['fake-1.0.zip'])
|
self.assertEquals(files, ['fake-1.0.zip'])
|
||||||
|
|
||||||
|
@ -116,8 +110,6 @@ class sdistTestCase(PyPIRCCommandTestCase):
|
||||||
find_executable('gzip') is None):
|
find_executable('gzip') is None):
|
||||||
return
|
return
|
||||||
|
|
||||||
self._init_tmp_pkg()
|
|
||||||
|
|
||||||
# now building a sdist
|
# now building a sdist
|
||||||
dist = Distribution()
|
dist = Distribution()
|
||||||
dist.script_name = 'setup.py'
|
dist.script_name = 'setup.py'
|
||||||
|
@ -137,7 +129,7 @@ class sdistTestCase(PyPIRCCommandTestCase):
|
||||||
cmd.run()
|
cmd.run()
|
||||||
|
|
||||||
# making sure we have two files
|
# making sure we have two files
|
||||||
dist_folder = join(TEMP_PKG, 'dist')
|
dist_folder = join(self.tmp_dir, 'dist')
|
||||||
result = os.listdir(dist_folder)
|
result = os.listdir(dist_folder)
|
||||||
result.sort()
|
result.sort()
|
||||||
self.assertEquals(result,
|
self.assertEquals(result,
|
||||||
|
|
|
@ -155,6 +155,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #5257: refactored all tests in distutils, so they use
|
||||||
|
support.TempdirManager, to avoid writing in the tests directory.
|
||||||
|
|
||||||
- Issue #4524: distutils build_script command failed with --with-suffix=3.
|
- Issue #4524: distutils build_script command failed with --with-suffix=3.
|
||||||
Initial patch by Amaury Forgeot d'Arc.
|
Initial patch by Amaury Forgeot d'Arc.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue