Downloading 2 tables from db, does calculation and uploads resulting table
up vote
4
down vote
favorite
I have written this script that downloads two tables from the db, preforms an intersection on them and adds 2 new columns to the resulting table, and uploads the resulting table to the db. It's a bit slow and I realize my code is messy (I'm new to Python and GIS). I suspect more steps can be done in parallel, for example downloading both tables from the database at once.
import arcpy, os, subprocess
import logging, shutil, sys
if __name__ == '__main__':
#create logger
logger = logging.getLogger(__name__)
FORMAT = '%(name)s - %(levelname)s - %(message)s'
logging.basicConfig(filename='py_intersection.log', level=logging.DEBUG, format=FORMAT)
logger.info('Started shp intr arcpy')
host = sys.argv[1]
database = sys.argv[2]
schema1 = sys.argv[3]
schema2 = sys.argv[4]
username = sys.argv[5]
password = sys.argv[6]
table1 = sys.argv[7]
table2 = sys.argv[8]
print 'program started'
out_path = r'\storage1gistempoutput.shp'
new_dir = r'\storage1gistemp'
if not os.path.exists(new_dir):
os.makedirs(new_dir)
pgsql2shp = 'pgsql2shp -f %s\%s -h %s -p 5432 -P %s -u %s %s %s.%s' % (new_dir, table1, host, password, username, database, schema1, table1)
print pgsql2shp
logger.info('Return code pgsql2shp invocation 1: '+str(subprocess.Popen(pgsql2shp, shell=True).wait()))
pgsql2shp = 'pgsql2shp -f %s\%s -h %s -p 5432 -P %s -u %s %s %s.%s' % (new_dir, table2, host, password, username, database, schema2, table2)
print pgsql2shp
logger.info('Return code pgsql2shp invocation 2: '+str(subprocess.Popen(pgsql2shp, shell=True).wait()))
print('Argument:'+ new_dir+'\'+table1+'.shp'+' , '+ new_dir+'\'+table2+'.shp')
arcpy.Intersect_analysis([new_dir+'\'+table1+'.shp', new_dir+'\'+table2+'.shp'], out_path, "ALL")
arcpy.AddField_management(out_path, "intersected_area", "DOUBLE")
arcpy.AddField_management(out_path, "dist_perct", "DOUBLE")
arcpy.CalculateField_management(out_path, "intersected_area","!SHAPE.AREA@SQUAREMETERS!", "PYTHON_9.3")
formula = """def findArea(area_inter, area):
return float((float(area_inter/area))*100.0)"""
arcpy.CalculateField_management(out_path, "dist_perct", "findArea(!intersected_area!, !AREA!)", "PYTHON_9.3", formula)
#export shapefiles to database
shp2pgsql = r"shp2pgsql -d -s 48591 "+out_path+" johnsmith.intersected"
psql = "psql -U johnsmith -h example.org -d exampledb"
logger.info("Running shp2pgsql | psql")
sts = subprocess.Popen(shp2pgsql +" | "+psql, shell=True).wait()
logger.info("Remove shapefiles")
shutil.rmtree(new_dir)
print 'program finished'
logger.info("Done shp intr arcpy")
"""!
@endcond
"""
python python-2.x postgresql geospatial arcpy
add a comment |
up vote
4
down vote
favorite
I have written this script that downloads two tables from the db, preforms an intersection on them and adds 2 new columns to the resulting table, and uploads the resulting table to the db. It's a bit slow and I realize my code is messy (I'm new to Python and GIS). I suspect more steps can be done in parallel, for example downloading both tables from the database at once.
import arcpy, os, subprocess
import logging, shutil, sys
if __name__ == '__main__':
#create logger
logger = logging.getLogger(__name__)
FORMAT = '%(name)s - %(levelname)s - %(message)s'
logging.basicConfig(filename='py_intersection.log', level=logging.DEBUG, format=FORMAT)
logger.info('Started shp intr arcpy')
host = sys.argv[1]
database = sys.argv[2]
schema1 = sys.argv[3]
schema2 = sys.argv[4]
username = sys.argv[5]
password = sys.argv[6]
table1 = sys.argv[7]
table2 = sys.argv[8]
print 'program started'
out_path = r'\storage1gistempoutput.shp'
new_dir = r'\storage1gistemp'
if not os.path.exists(new_dir):
os.makedirs(new_dir)
pgsql2shp = 'pgsql2shp -f %s\%s -h %s -p 5432 -P %s -u %s %s %s.%s' % (new_dir, table1, host, password, username, database, schema1, table1)
print pgsql2shp
logger.info('Return code pgsql2shp invocation 1: '+str(subprocess.Popen(pgsql2shp, shell=True).wait()))
pgsql2shp = 'pgsql2shp -f %s\%s -h %s -p 5432 -P %s -u %s %s %s.%s' % (new_dir, table2, host, password, username, database, schema2, table2)
print pgsql2shp
logger.info('Return code pgsql2shp invocation 2: '+str(subprocess.Popen(pgsql2shp, shell=True).wait()))
print('Argument:'+ new_dir+'\'+table1+'.shp'+' , '+ new_dir+'\'+table2+'.shp')
arcpy.Intersect_analysis([new_dir+'\'+table1+'.shp', new_dir+'\'+table2+'.shp'], out_path, "ALL")
arcpy.AddField_management(out_path, "intersected_area", "DOUBLE")
arcpy.AddField_management(out_path, "dist_perct", "DOUBLE")
arcpy.CalculateField_management(out_path, "intersected_area","!SHAPE.AREA@SQUAREMETERS!", "PYTHON_9.3")
formula = """def findArea(area_inter, area):
return float((float(area_inter/area))*100.0)"""
arcpy.CalculateField_management(out_path, "dist_perct", "findArea(!intersected_area!, !AREA!)", "PYTHON_9.3", formula)
#export shapefiles to database
shp2pgsql = r"shp2pgsql -d -s 48591 "+out_path+" johnsmith.intersected"
psql = "psql -U johnsmith -h example.org -d exampledb"
logger.info("Running shp2pgsql | psql")
sts = subprocess.Popen(shp2pgsql +" | "+psql, shell=True).wait()
logger.info("Remove shapefiles")
shutil.rmtree(new_dir)
print 'program finished'
logger.info("Done shp intr arcpy")
"""!
@endcond
"""
python python-2.x postgresql geospatial arcpy
add a comment |
up vote
4
down vote
favorite
up vote
4
down vote
favorite
I have written this script that downloads two tables from the db, preforms an intersection on them and adds 2 new columns to the resulting table, and uploads the resulting table to the db. It's a bit slow and I realize my code is messy (I'm new to Python and GIS). I suspect more steps can be done in parallel, for example downloading both tables from the database at once.
import arcpy, os, subprocess
import logging, shutil, sys
if __name__ == '__main__':
#create logger
logger = logging.getLogger(__name__)
FORMAT = '%(name)s - %(levelname)s - %(message)s'
logging.basicConfig(filename='py_intersection.log', level=logging.DEBUG, format=FORMAT)
logger.info('Started shp intr arcpy')
host = sys.argv[1]
database = sys.argv[2]
schema1 = sys.argv[3]
schema2 = sys.argv[4]
username = sys.argv[5]
password = sys.argv[6]
table1 = sys.argv[7]
table2 = sys.argv[8]
print 'program started'
out_path = r'\storage1gistempoutput.shp'
new_dir = r'\storage1gistemp'
if not os.path.exists(new_dir):
os.makedirs(new_dir)
pgsql2shp = 'pgsql2shp -f %s\%s -h %s -p 5432 -P %s -u %s %s %s.%s' % (new_dir, table1, host, password, username, database, schema1, table1)
print pgsql2shp
logger.info('Return code pgsql2shp invocation 1: '+str(subprocess.Popen(pgsql2shp, shell=True).wait()))
pgsql2shp = 'pgsql2shp -f %s\%s -h %s -p 5432 -P %s -u %s %s %s.%s' % (new_dir, table2, host, password, username, database, schema2, table2)
print pgsql2shp
logger.info('Return code pgsql2shp invocation 2: '+str(subprocess.Popen(pgsql2shp, shell=True).wait()))
print('Argument:'+ new_dir+'\'+table1+'.shp'+' , '+ new_dir+'\'+table2+'.shp')
arcpy.Intersect_analysis([new_dir+'\'+table1+'.shp', new_dir+'\'+table2+'.shp'], out_path, "ALL")
arcpy.AddField_management(out_path, "intersected_area", "DOUBLE")
arcpy.AddField_management(out_path, "dist_perct", "DOUBLE")
arcpy.CalculateField_management(out_path, "intersected_area","!SHAPE.AREA@SQUAREMETERS!", "PYTHON_9.3")
formula = """def findArea(area_inter, area):
return float((float(area_inter/area))*100.0)"""
arcpy.CalculateField_management(out_path, "dist_perct", "findArea(!intersected_area!, !AREA!)", "PYTHON_9.3", formula)
#export shapefiles to database
shp2pgsql = r"shp2pgsql -d -s 48591 "+out_path+" johnsmith.intersected"
psql = "psql -U johnsmith -h example.org -d exampledb"
logger.info("Running shp2pgsql | psql")
sts = subprocess.Popen(shp2pgsql +" | "+psql, shell=True).wait()
logger.info("Remove shapefiles")
shutil.rmtree(new_dir)
print 'program finished'
logger.info("Done shp intr arcpy")
"""!
@endcond
"""
python python-2.x postgresql geospatial arcpy
I have written this script that downloads two tables from the db, preforms an intersection on them and adds 2 new columns to the resulting table, and uploads the resulting table to the db. It's a bit slow and I realize my code is messy (I'm new to Python and GIS). I suspect more steps can be done in parallel, for example downloading both tables from the database at once.
import arcpy, os, subprocess
import logging, shutil, sys
if __name__ == '__main__':
#create logger
logger = logging.getLogger(__name__)
FORMAT = '%(name)s - %(levelname)s - %(message)s'
logging.basicConfig(filename='py_intersection.log', level=logging.DEBUG, format=FORMAT)
logger.info('Started shp intr arcpy')
host = sys.argv[1]
database = sys.argv[2]
schema1 = sys.argv[3]
schema2 = sys.argv[4]
username = sys.argv[5]
password = sys.argv[6]
table1 = sys.argv[7]
table2 = sys.argv[8]
print 'program started'
out_path = r'\storage1gistempoutput.shp'
new_dir = r'\storage1gistemp'
if not os.path.exists(new_dir):
os.makedirs(new_dir)
pgsql2shp = 'pgsql2shp -f %s\%s -h %s -p 5432 -P %s -u %s %s %s.%s' % (new_dir, table1, host, password, username, database, schema1, table1)
print pgsql2shp
logger.info('Return code pgsql2shp invocation 1: '+str(subprocess.Popen(pgsql2shp, shell=True).wait()))
pgsql2shp = 'pgsql2shp -f %s\%s -h %s -p 5432 -P %s -u %s %s %s.%s' % (new_dir, table2, host, password, username, database, schema2, table2)
print pgsql2shp
logger.info('Return code pgsql2shp invocation 2: '+str(subprocess.Popen(pgsql2shp, shell=True).wait()))
print('Argument:'+ new_dir+'\'+table1+'.shp'+' , '+ new_dir+'\'+table2+'.shp')
arcpy.Intersect_analysis([new_dir+'\'+table1+'.shp', new_dir+'\'+table2+'.shp'], out_path, "ALL")
arcpy.AddField_management(out_path, "intersected_area", "DOUBLE")
arcpy.AddField_management(out_path, "dist_perct", "DOUBLE")
arcpy.CalculateField_management(out_path, "intersected_area","!SHAPE.AREA@SQUAREMETERS!", "PYTHON_9.3")
formula = """def findArea(area_inter, area):
return float((float(area_inter/area))*100.0)"""
arcpy.CalculateField_management(out_path, "dist_perct", "findArea(!intersected_area!, !AREA!)", "PYTHON_9.3", formula)
#export shapefiles to database
shp2pgsql = r"shp2pgsql -d -s 48591 "+out_path+" johnsmith.intersected"
psql = "psql -U johnsmith -h example.org -d exampledb"
logger.info("Running shp2pgsql | psql")
sts = subprocess.Popen(shp2pgsql +" | "+psql, shell=True).wait()
logger.info("Remove shapefiles")
shutil.rmtree(new_dir)
print 'program finished'
logger.info("Done shp intr arcpy")
"""!
@endcond
"""
python python-2.x postgresql geospatial arcpy
python python-2.x postgresql geospatial arcpy
edited Nov 16 at 12:58
rolfl♦
90.6k13190393
90.6k13190393
asked Jun 24 '15 at 22:05
Celeritas
50221021
50221021
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
4
down vote
accepted
I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style. Here are a few tips I have on what can be improved there.
- Don't use
%
for string formatting, as it is deprecated. You should be usingstr.format()
instead. Here's an example:print "Hello {0}".format("world")
- You can remove the docstring at the end of your file containing
"""!@endcond"""
. This does nothing, and serves no purpose. - Separate this out into different functions. In it's current state, it's really hard to read as one large block of code.
- Add more comments. Comments will make your code much clearer, and easier to read. Functions and classes should use docstrings, over regular inline comments.
- Don't use
Don't import multiple modules on one line. If an error occurs with one module, it can be hard to distinguish where the error came from.
- Some variable names could be better. For example, the names
sts
, orshp2pgsql
provide no useful information. Try to find any other names with not so great names, and see how you can improve them. - I'm not an expert on asynchronous programming, or any of the modules provided in Python made for this, but if you want to do a task like this, Python 3.5 will include the
async
andawait
keywords built for asynchronous programming.
The official style guide for Python, PEP8, can be found here.
"I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style...Don't use % for string formatting, as it is deprecated." feel free to as I'm new to Python and I was instructed to use an older file that contained%
so I thought that was pythonic.
– Celeritas
Jun 26 '15 at 21:20
@Celeritas Well, you shouldn't use%
.str.format()
was introduced in Python 2.6, and I don't think backwards compatibility beyond that is really necessary.
– Ethan Bierlein
Jun 26 '15 at 21:23
Does using%
instead ofstr.format()
somehow help to prevent SQL injection?
– Celeritas
Nov 4 '15 at 3:59
@Celeritas No. The formatting operator%
has simply been deprecated since Python 2.6.
– Ethan Bierlein
Nov 4 '15 at 12:53
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style. Here are a few tips I have on what can be improved there.
- Don't use
%
for string formatting, as it is deprecated. You should be usingstr.format()
instead. Here's an example:print "Hello {0}".format("world")
- You can remove the docstring at the end of your file containing
"""!@endcond"""
. This does nothing, and serves no purpose. - Separate this out into different functions. In it's current state, it's really hard to read as one large block of code.
- Add more comments. Comments will make your code much clearer, and easier to read. Functions and classes should use docstrings, over regular inline comments.
- Don't use
Don't import multiple modules on one line. If an error occurs with one module, it can be hard to distinguish where the error came from.
- Some variable names could be better. For example, the names
sts
, orshp2pgsql
provide no useful information. Try to find any other names with not so great names, and see how you can improve them. - I'm not an expert on asynchronous programming, or any of the modules provided in Python made for this, but if you want to do a task like this, Python 3.5 will include the
async
andawait
keywords built for asynchronous programming.
The official style guide for Python, PEP8, can be found here.
"I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style...Don't use % for string formatting, as it is deprecated." feel free to as I'm new to Python and I was instructed to use an older file that contained%
so I thought that was pythonic.
– Celeritas
Jun 26 '15 at 21:20
@Celeritas Well, you shouldn't use%
.str.format()
was introduced in Python 2.6, and I don't think backwards compatibility beyond that is really necessary.
– Ethan Bierlein
Jun 26 '15 at 21:23
Does using%
instead ofstr.format()
somehow help to prevent SQL injection?
– Celeritas
Nov 4 '15 at 3:59
@Celeritas No. The formatting operator%
has simply been deprecated since Python 2.6.
– Ethan Bierlein
Nov 4 '15 at 12:53
add a comment |
up vote
4
down vote
accepted
I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style. Here are a few tips I have on what can be improved there.
- Don't use
%
for string formatting, as it is deprecated. You should be usingstr.format()
instead. Here's an example:print "Hello {0}".format("world")
- You can remove the docstring at the end of your file containing
"""!@endcond"""
. This does nothing, and serves no purpose. - Separate this out into different functions. In it's current state, it's really hard to read as one large block of code.
- Add more comments. Comments will make your code much clearer, and easier to read. Functions and classes should use docstrings, over regular inline comments.
- Don't use
Don't import multiple modules on one line. If an error occurs with one module, it can be hard to distinguish where the error came from.
- Some variable names could be better. For example, the names
sts
, orshp2pgsql
provide no useful information. Try to find any other names with not so great names, and see how you can improve them. - I'm not an expert on asynchronous programming, or any of the modules provided in Python made for this, but if you want to do a task like this, Python 3.5 will include the
async
andawait
keywords built for asynchronous programming.
The official style guide for Python, PEP8, can be found here.
"I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style...Don't use % for string formatting, as it is deprecated." feel free to as I'm new to Python and I was instructed to use an older file that contained%
so I thought that was pythonic.
– Celeritas
Jun 26 '15 at 21:20
@Celeritas Well, you shouldn't use%
.str.format()
was introduced in Python 2.6, and I don't think backwards compatibility beyond that is really necessary.
– Ethan Bierlein
Jun 26 '15 at 21:23
Does using%
instead ofstr.format()
somehow help to prevent SQL injection?
– Celeritas
Nov 4 '15 at 3:59
@Celeritas No. The formatting operator%
has simply been deprecated since Python 2.6.
– Ethan Bierlein
Nov 4 '15 at 12:53
add a comment |
up vote
4
down vote
accepted
up vote
4
down vote
accepted
I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style. Here are a few tips I have on what can be improved there.
- Don't use
%
for string formatting, as it is deprecated. You should be usingstr.format()
instead. Here's an example:print "Hello {0}".format("world")
- You can remove the docstring at the end of your file containing
"""!@endcond"""
. This does nothing, and serves no purpose. - Separate this out into different functions. In it's current state, it's really hard to read as one large block of code.
- Add more comments. Comments will make your code much clearer, and easier to read. Functions and classes should use docstrings, over regular inline comments.
- Don't use
Don't import multiple modules on one line. If an error occurs with one module, it can be hard to distinguish where the error came from.
- Some variable names could be better. For example, the names
sts
, orshp2pgsql
provide no useful information. Try to find any other names with not so great names, and see how you can improve them. - I'm not an expert on asynchronous programming, or any of the modules provided in Python made for this, but if you want to do a task like this, Python 3.5 will include the
async
andawait
keywords built for asynchronous programming.
The official style guide for Python, PEP8, can be found here.
I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style. Here are a few tips I have on what can be improved there.
- Don't use
%
for string formatting, as it is deprecated. You should be usingstr.format()
instead. Here's an example:print "Hello {0}".format("world")
- You can remove the docstring at the end of your file containing
"""!@endcond"""
. This does nothing, and serves no purpose. - Separate this out into different functions. In it's current state, it's really hard to read as one large block of code.
- Add more comments. Comments will make your code much clearer, and easier to read. Functions and classes should use docstrings, over regular inline comments.
- Don't use
Don't import multiple modules on one line. If an error occurs with one module, it can be hard to distinguish where the error came from.
- Some variable names could be better. For example, the names
sts
, orshp2pgsql
provide no useful information. Try to find any other names with not so great names, and see how you can improve them. - I'm not an expert on asynchronous programming, or any of the modules provided in Python made for this, but if you want to do a task like this, Python 3.5 will include the
async
andawait
keywords built for asynchronous programming.
The official style guide for Python, PEP8, can be found here.
answered Jun 26 '15 at 21:15
Ethan Bierlein
12.8k242136
12.8k242136
"I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style...Don't use % for string formatting, as it is deprecated." feel free to as I'm new to Python and I was instructed to use an older file that contained%
so I thought that was pythonic.
– Celeritas
Jun 26 '15 at 21:20
@Celeritas Well, you shouldn't use%
.str.format()
was introduced in Python 2.6, and I don't think backwards compatibility beyond that is really necessary.
– Ethan Bierlein
Jun 26 '15 at 21:23
Does using%
instead ofstr.format()
somehow help to prevent SQL injection?
– Celeritas
Nov 4 '15 at 3:59
@Celeritas No. The formatting operator%
has simply been deprecated since Python 2.6.
– Ethan Bierlein
Nov 4 '15 at 12:53
add a comment |
"I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style...Don't use % for string formatting, as it is deprecated." feel free to as I'm new to Python and I was instructed to use an older file that contained%
so I thought that was pythonic.
– Celeritas
Jun 26 '15 at 21:20
@Celeritas Well, you shouldn't use%
.str.format()
was introduced in Python 2.6, and I don't think backwards compatibility beyond that is really necessary.
– Ethan Bierlein
Jun 26 '15 at 21:23
Does using%
instead ofstr.format()
somehow help to prevent SQL injection?
– Celeritas
Nov 4 '15 at 3:59
@Celeritas No. The formatting operator%
has simply been deprecated since Python 2.6.
– Ethan Bierlein
Nov 4 '15 at 12:53
"I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style...Don't use % for string formatting, as it is deprecated." feel free to as I'm new to Python and I was instructed to use an older file that contained
%
so I thought that was pythonic.– Celeritas
Jun 26 '15 at 21:20
"I know, that you know, that your code is messy, but I'm still going to give some tips on your coding style...Don't use % for string formatting, as it is deprecated." feel free to as I'm new to Python and I was instructed to use an older file that contained
%
so I thought that was pythonic.– Celeritas
Jun 26 '15 at 21:20
@Celeritas Well, you shouldn't use
%
. str.format()
was introduced in Python 2.6, and I don't think backwards compatibility beyond that is really necessary.– Ethan Bierlein
Jun 26 '15 at 21:23
@Celeritas Well, you shouldn't use
%
. str.format()
was introduced in Python 2.6, and I don't think backwards compatibility beyond that is really necessary.– Ethan Bierlein
Jun 26 '15 at 21:23
Does using
%
instead of str.format()
somehow help to prevent SQL injection?– Celeritas
Nov 4 '15 at 3:59
Does using
%
instead of str.format()
somehow help to prevent SQL injection?– Celeritas
Nov 4 '15 at 3:59
@Celeritas No. The formatting operator
%
has simply been deprecated since Python 2.6.– Ethan Bierlein
Nov 4 '15 at 12:53
@Celeritas No. The formatting operator
%
has simply been deprecated since Python 2.6.– Ethan Bierlein
Nov 4 '15 at 12:53
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f94590%2fdownloading-2-tables-from-db-does-calculation-and-uploads-resulting-table%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown