May the source be with you, but remember the KISS principle ;-)
Home Switchboard Unix Administration Red Hat TCP/IP Networks Neoliberalism Toxic Managers
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and  bastardization of classic Unix

RHCSA: Using rpm

News  Notes on RHCSA Certification for RHEL 7 Recommended links Lecture notes for RHCSA certification for RHEL 7 RHEL7 documentation The tar pit of Red Hat overcomplexity Systemd Unix History with some Emphasis on Scripting Red Hat history
Understanding and using essential tools Access a shell prompt and issue commands with correct syntax Finding Help Managing files in RHEL Working with hard and soft links Working with archives and compressed files Using the Midnight Commander as file manager Text files processing Using redirection and pipes
Use grep and extended regular expressions to analyze text files Finding files and directories; mass operations on files Connecting to the server via ssh, using multiple consoles and screen command RHCSA: Managing local users and groups RHCSA: Introduction to Unix permissions model Introduction to Process Management Configuring network in RHEL7 Installation and configuration of KVM in RHEL7  
Managing Software Packages with yum and rpm Using yum Using rpm          - rpm package manager Sysadmin Horror Stories Tips Humor Etc

RPM was originally written in 1997 by Erik Troan and Marc Ewing, based Solaris package manager.

Yum which now is standard software manager in Red Hat did not appear in Red Hat until RHEL5 was released. RPM repositories  existed longer, but different utility (up2date) was used to access them and patch the server.

Initially the was a simple command like utility to work with RPM software package named, appropriately rpm  This command was used to install package files after they had been downloaded. That worked, but there was one major issue: the dependency hell. Because RPM packages have always focused on specific functionality, to install specific software, a collection of RPM packages was normally required. Therefore, a “missing dependency” message was often issued while users were trying to install RPM packages, which means that to install the selected package, other packages needed to be installed first.

RPM still is useful utility that now is used mainly for installation of individual packages and performing query to extract useful information from RPM database on the particular server (rpm does not work with remote repositories like yum does). Even now with yum available many sysadmins use rpm to view the list of packages that are installed on the system and for other qures against RPM database/ So the most common RPM command those days is the command that list all installed RPM packages

rpm -qa

Of couse the list inraw form is huge (around 1.5K packages for a typiucal system, so you need to extract relevant part of it using grep

rpm -qa | fgrep -v perl 


On your system, two package databases are maintained: the yum database and the rpm database. When you are installing packages through yum, the yum database is updated first, after which the updated information is synchronized to the RPM database. If you install packages using the rpm  command, the update is written to the rpm database only and will not be updated to the yum database

Querying the rpm Database

The rpm  command enables you to get much information about packages. Using RPM queries can be a really useful way to find out how software can be configured and used. To start, you can use the rpm -qa  command. Like yum list installed, this command shows a list of all software that is installed on the machine. Use grep  on this command to find out specific package names. To perform queries on RPM packages, you just need the name and not the version information.

After finding the package about which you want to have more information, you can start with some generic queries to find out what is in the package. In the following examples, I assume that you are using RPM queries on the nmap RPM package. To start, type rpm -qi nmap  to get a description of the package.

The next step is to use rpm -ql nmap, which shows a list of all files that are in the package nmap. On some packages, the result can be a really long list of filenames that is not particularly useful.

To get more specific information, you can use

Using RPM queries can really help in finding out more useful information about packages. The only thing that you need to know is the RPM package name a specific file belongs to.

To find this, use

rpm -qf <filename>

the filename should be specified with path, for examle /bin/ls. So you should us e rpm -qf /bin/ls  not rpm -qf ls   to find the name of the RPM the ls  command comes from.

Querying rpm Package Files

RPM queries by default are used on the RPM database, and what you are querying are installed RPMs. It sometimes makes sense to install an RPM before it is actually installed. To do this, you need to add the -p  option to the query, because without the -p  option, you will be querying the database not the package file. Also, when querying a package file, you need to refer to the complete filename, including the version number and all other information that you do not have to use when querying the RPM database. As an example, the rpm -qp --scripts httpd-2.4.6-19.el7.centos.x86_64.rpm  command queries the specific RPM file to see whether there are scripts contained with the RPM.

A query option that needs special attention is --scripts. This option queries an RPM package to see which scripts it contains (if any). This option is especially important when combined with the -p  option, to find out whether a package that you are going to install includes any scripts.

When you are installing RPM packages, you will be doing that as root. Before installing an RPM package from an unknown source, you really need to make sure that it does not include any rogue scripts. If you do not, you do risk installing malware on your computer without even knowing it.


Working with RPM queries is a valuable skill on the RHCSA and the RHCE exams. If you know how to handle queries, you can find all relevant configuration files and the documentation.


Partially borrowed from 20 Practical Examples of RPM Commands in Linux

How to check dependencies of RPM Package before Installing

Let's say you would like to do a dependency check before installing or upgrading a package that is residing on you local filesystem. For example, use the following command to check the dependencies of package. It will display the list of dependencies of package. You have package tree in you /root directory you can use:

# rpm -qpR tree*
RPM command and options
  1. -q : Query a package
  2. -p : List capabilities this package provides.
  3. -R: List capabilities on which this package depends..

How to Install a RPM Package Without Dependencies

If you know that all needed packages are already installed or that package will work with older libraries that are already installed you can ignore those dependencies by using the option –nodeps (no dependencies check) before installing the package.

[[email protected]]# rpm -ivh --nodeps BitTorrent-5.2.2-1-Python2.4.noarch.rpm

Preparing...                ########################################### [100%]
   1:BitTorrent             ########################################### [100%]

The above command forcefully install rpm package by ignoring dependencies errors, but if those dependency files are missing, then the program will not work at all, until you install them.

How to check if a package is installed

Using -q option with package name, will show whether an rpm installed or not.

[[email protected]]# rpm -q BitTorrent


How to List Recently Installed RPM Packages

Use the following rpm command with -qa (query all) option, will list all the recently installed rpm packages.

[[email protected]]# rpm -qa --last

BitTorrent-5.2.2-1.noarch                     Tue 04 Dec 2012 05:14:06 PM BDT
pidgin-2.7.9-5.el6.2.i686                     Tue 04 Dec 2012 05:13:51 PM BDT
cyrus-sasl-devel-2.1.23-13.el6_3.1.i686       Tue 04 Dec 2012 04:43:06 PM BDT
cyrus-sasl-2.1.23-13.el6_3.1.i686             Tue 04 Dec 2012 04:43:05 PM BDT
cyrus-sasl-md5-2.1.23-13.el6_3.1.i686         Tue 04 Dec 2012 04:43:04 PM BDT
cyrus-sasl-plain-2.1.23-13.el6_3.1.i686       Tue 04 Dec 2012 04:43:03 PM BDT

How to Upgrade a RPM Package

If we want to upgrade any RPM package "–U" (upgrade) option will be used. One of the major advantages of using this option is that it will not only upgrade the latest version of any package, but it will also maintain the backup of the older package so that in case if the newer upgraded package does not run the previously installed package can be used again.

[[email protected]]# rpm -Uvh nx-3.5.0-2.el6.centos.i686.rpm
Preparing...                ########################################### [100%]
   1:nx                     ########################################### [100%]

How to Remove a RPM Package

To un-install an RPM package, for example we use the package name nx, not the original package name nx-3.5.0-2.el6.centos.i686.rpm. The -e (erase) option is used to remove package.

[[email protected]]# rpm -evv nx

How to Remove an RPM Package Without Dependencies

The –nodeps (Do not check dependencies) option forcefully remove the rpm package from the system. But keep in mind removing particular package may break other working applications.

[[email protected]]# rpm -ev --nodeps vsftpd

How to Query a file that belongs which RPM Package

Let's say, you have list of files and you would like to find out which package belongs to these files. For example, the following command with -qf (query file) option will show you a file /usr/bin/htpasswd is own by package httpd-tools-2.2.15-15.el6.centos.1.i686.

[[email protected]]# rpm -qf /usr/bin/htpasswd


How to Query a Information of Installed RPM Package

Let's say you have installed an rpm package and want to know the information about the package. The following -qi (query info) option will print the available information of the installed package.

[[email protected]]# rpm -qi vsftpd

Name        : vsftpd				   Relocations: (not relocatable)
Version     : 2.2.2				   Vendor: CentOS
Release     : 11.el6				   Build Date: Fri 22 Jun 2012 01:54:24 PM BDT
Install Date: Mon 17 Sep 2012 07:55:28 PM BDT      Build Host:
Group       : System Environment/Daemons           Source RPM: vsftpd-2.2.2-11.el6.src.rpm
Size        : 351932                               License: GPLv2 with exceptions
Signature   : RSA/SHA1, Mon 25 Jun 2012 04:07:34 AM BDT, Key ID 0946fca2c105b9de
Packager    : CentOS BuildSystem <>
URL         :
Summary     : Very Secure Ftp Daemon
Description :
vsftpd is a Very Secure FTP daemon. It was written completely from

Get the Information of RPM Package Before Installing

If you want know the information about this package before installing use -qi (query info package) will print the information of a package sqlbuddy.

# rpm -qip tree

How to Query documentation of Installed RPM Package

To get the list of available documentation of an installed package, use the following command with option -qdf (query document file) will display the manual pages related to vmstat package.

[[email protected]]# rpm -qdf /usr/bin/vmstat


How to Verify a RPM Package

Verifying a package compares information of installed files of the package against the rpm database. The -Vp (verify package) is used to verify a package.

[[email protected] downloads]# rpm -Vp sqlbuddy-1.3.3-1.noarch.rpm

S.5....T.  c /etc/httpd/conf.d/sqlbuddy.conf

How to Verify all RPM Packages

Type the following command to verify all the installed rpm packages.

[[email protected]]# rpm -Va

S.5....T.  c /etc/rc.d/rc.local
.......T.  c /etc/dnsmasq.conf
.......T.    /etc/
S.5....T.  c /etc/yum.conf
S.5....T.  c /etc/yum.repos.d/epel.repo

How To rebuild Corrupted RPM Database

Sometimes rpm database gets corrupted and stops all the functionality of rpm and other applications on the system. So, at the time we need to rebuild the rpm database and restore it with the help of following command.

[[email protected]]# cd /var/lib
[[email protected]]# rm __db*
[root@tecmint]# rpm --rebuilddb
[[email protected]]# rpmdb_verify Packages


[email protected]:~ # rpm --help
Usage: rpm [OPTION...]
Query/Verify package selection options:
  -a, --all                        query/verify all packages
  -f, --file                       query/verify package(s) owning file
  -g, --group                      query/verify package(s) in group
  -p, --package                    query/verify a package file
  --pkgid                          query/verify package(s) with package identifier
  --hdrid                          query/verify package(s) with header identifier
  --triggeredby                    query the package(s) triggered by the package
  --whatrequires                   query/verify the package(s) which require a dependency
  --whatprovides                   query/verify the package(s) which provide a dependency
  --nomanifest                     do not process non-package files as manifests

Query options (with -q or --query):
  -c, --configfiles                list all configuration files
  -d, --docfiles                   list all documentation files
  -L, --licensefiles               list all license files
  --dump                           dump basic file information
  -l, --list                       list files in package
  --queryformat=QUERYFORMAT        use the following query format
  -s, --state                      display the states of the listed files

Verify options (with -V or --verify):
  --nofiledigest                   don't verify digest of files
  --nofiles                        don't verify files in package
  --nodeps                         don't verify package dependencies
  --noscript                       don't execute verify script(s)

Install/Upgrade/Erase options:
  --allfiles                       install all files, even configurations which might
                                   otherwise be skipped
  --allmatches                     remove all packages which match  (normally an
                                   error is generated if  specified multiple
  --badreloc                       relocate files in non-relocatable package
  -e, --erase=+           erase (uninstall) package
  --excludedocs                    do not install documentation
  --excludepath=             skip files with leading component 
  --force                          short hand for --replacepkgs --replacefiles
  -F, --freshen=+     upgrade package(s) if already installed
  -h, --hash                       print hash marks as package installs (good with -v)
  --ignorearch                     don't verify package architecture
  --ignoreos                       don't verify package operating system
  --ignoresize                     don't check disk space before installing
  -i, --install                    install package(s)
  --justdb                         update the database, but do not modify the filesystem
  --nodeps                         do not verify package dependencies
  --nofiledigest                   don't verify digest of files
  --nocontexts                     don't install file security contexts
  --noorder                        do not reorder package installation to satisfy
  --noscripts                      do not execute package scriptlet(s)
  --notriggers                     do not execute any scriptlet(s) triggered by this package
  --nocollections                  do not perform any collection actions
  --oldpackage                     upgrade to an old version of the package (--force on
                                   upgrades does this automatically)
  --percent                        print percentages as package installs
  --prefix=<dir>                   relocate the package to <dir>, if relocatable
  --relocate=<old>=<new>           relocate files from path <old> to <new>
  --replacefiles                   ignore file conflicts between packages
  --replacepkgs                    reinstall if the package is already present
  --test                           don't install, but tell if it would work or not
  -U, --upgrade=+     upgrade package(s)
  --reinstall=+       reinstall package(s)

Common options for all rpm modes and executables:
  -D, --define='MACRO EXPR'        define MACRO with value EXPR
  --undefine=MACRO                 undefine MACRO
  -E, --eval='EXPR'                print macro expansion of EXPR
  --macros=<FILE:...>              read <FILE:...> instead of default file(s)
  --noplugins                      don't enable any plugins
  --nodigest                       don't verify package digest(s)
  --nosignature                    don't verify package signature(s)
  --rcfile=<FILE:...>              read <FILE:...> instead of default file(s)
  -r, --root=ROOT                  use ROOT as top level directory (default: "/")
  --dbpath=DIRECTORY               use database in DIRECTORY
  --querytags                      display known query tags
  --showrc                         display final rpmrc and macro configuration
  --quiet                          provide less detailed output
  -v, --verbose                    provide more detailed output
  --version                        print the version of rpm being used

Options implemented via popt alias/exec:
  --scripts                        list install/erase scriptlets from package(s)
  --setperms                       set permissions of files in a package
  --setugids                       set user/group ownership of files in a package
  --conflicts                      list capabilities this package conflicts with
  --obsoletes                      list other packages removed by installing this package
  --provides                       list capabilities that this package provides
  --requires                       list capabilities required by package(s)
  --info                           list descriptive information from package(s)
  --changelog                      list change logs for this package
  --xml                            list metadata in xml
  --triggers                       list trigger scriptlets from package(s)
  --last                           list package(s) by install time, most recent first
  --dupes                          list duplicated packages
  --filesbypkg                     list all files from each package
  --fileclass                      list file names with classes
  --filecolor                      list file names with colors
  --fscontext                      list file names with security context from file system
  --fileprovide                    list file names with provides
  --filerequire                    list file names with requires
  --filecaps                       list file names with POSIX1.e capabilities

Help options:
  -?, --help                       Show this help message
  --usage                          Display brief usage message

NOTE: rpm also is available via alias repoquery. This alias is created when you install the yum-utils package and it displays different behaviour that rpm despite the fact that it is aan alias to the same binary. It might be more convenient to use in some cases.

[0][email protected]:~ # repoquery
Usage: repoquery [options]

  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -l, --list            list files in this package/group
  -i, --info            list descriptive info from this package/group
  -f, --file            query which package provides this file
  --qf=QUERYFORMAT, --queryformat=QUERYFORMAT
                        specify a custom output format for queries
  --groupmember         list which group(s) this package belongs to
  -q, --query           no-op for rpmquery compatibility
  -a, --all             query all packages/groups
  -R, --requires        list package dependencies
  --provides            list capabilities this package provides
  --obsoletes           list other packages obsoleted by this package
  --conflicts           list capabilities this package conflicts with
  --changelog           show changelog for this package
  --location            show download URL for this package
  --nevra               show name-epoch:version-release.architecture info of
  --envra               show epoch:name-version-release.architecture info of
  --nvr                 show name, version, release info of package
  -s, --source          show package source RPM name
  --srpm                operate on corresponding source RPM
  --resolve             resolve capabilities to originating package(s)
  --alldeps             check non-explicit dependencies (files and Provides:)
                        as well, defaults to on
  --exactdeps           check dependencies exactly as given, opposite of
  --recursive           recursively query for packages (for whatrequires)
  --whatprovides        query what package(s) provide a capability
  --whatrequires        query what package(s) require a capability
  --whatobsoletes       query what package(s) obsolete a capability
  --whatconflicts       query what package(s) conflicts with a capability
  -g, --group           query groups instead of packages
                        filter which packages (all,optional etc) are shown
                        from groups
  --archlist=ARCHLIST   only query packages of certain architecture(s)
                        set value of $releasever in yum config and repo files
                        limit query to installed / available / recent /
                        updates / extras / all (available + installed) /
                        repository (default) packages
  --installed           limit query to installed pkgs only
  --show-duplicates     show all versions of packages
  --repoid=REPOID       specify repoids to query, can be specified multiple
                        times (default is all enabled)
                        specify additional repoids to query, can be specified
                        multiple times
                        specify repoids to disable, can be specified multiple
                        specify repoid & paths of additional repositories -
                        unique repoid and complete path required, can be
                        specified multiple times. Example.
  --plugins             enable yum plugin support
  --quiet               quiet output, only error output to stderr (default
  --verbose             verbose output (opposite of quiet)
  -C, --cache           run from cache only
  --tempcache           use private cache (default when used as non-root)
  --querytags           list available tags in queryformat queries
  -c CONFFILE, --config=CONFFILE
                        config file location
  --level=TREE_LEVEL    levels to display (can be any number or 'all', default
                        to 'all')
  --output=OUTPUT       output format to use (can be text|ascii-tree|dot-tree,
                        default to 'text')
  --search              Use yum's search to return pkgs
                        search fields to search using --search
                        set install root
  --setopt=SETOPTS      set arbitrary config and repo options

The repoquery command is pretty similar to the rpm -q command and uses many similar options. There is just one significant option missing: the --script option. A simple solution is to make sure that you are using trusted repositories only, to prevent installing software that contains dangerous script code.

If you need to thoroughly analyze what an RPM package is doing when it is installed, you can download it to your machine, which allows you to use the rpm -qp --scripts command on the package. To download a package from the repository to the local directory, you can use the yumdownloader command, which comes from the yum-utils package or user option d in yum (new for RHEL7)

Top Visited
Past week
Past month


Old News ;-)

Recommended Links

Google matched content

Softpanorama Recommended

Top articles


RPM Package Manager - Wikipedia

rpm package manager Developers site.

IBM tutorial by Dan Poirier

20 Practical Examples of RPM Commands in Linux

RPM Command 15 Examples to Install, Uninstall, Upgrade, Query RPM Packages

Using the Red Hat Package Manager (RPM) -- very old tutorial. Part of ebook Linux Administration Made Easy by Steve Frampton, <[email protected]>

How to build rpm packages -

Creating RPM packages -- Fedora Docs Site

RPM Notes - Grahams Ultimate Wiki



Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy


War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes


Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law


Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D

Copyright © 1996-2021 by Softpanorama Society. was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to to buy a cup of coffee for authors of this site


The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Last modified: December 13, 2020