Modules in Python

Module: It is a file containing python definitions and statements. It may contain functions, classes, and variables. Grouping related code into a module makes the code easier to understand and use.

How to import a module: We can import a module in python as
import modulename

>>> import math
>>> import random
>>> import statistics

We can also import multiple modules in a single line as
import modulename1, modulename2, modulename3…….

>>> import math, random, statistics

Using the module: We can call any function of the module as
modulename.functioname(arguments)
It is called dot(.) Notation to call function of a module.

>>> math.sqrt(25)
5.0
>>> math.pow(5,2)
25.0

Name of a module: Name of a module is stored inside a constant __name__. We can check the name of a module as

>>> import math, random, statistics
>>> math.__name__
'math'
>>> random.__name__
'random'
>>> statistics.__name__
'statistics'

If we write import statement twice, to import the same module again, then it is ignored as

>>>#imported math module
>>> import math

>>>#Ignored as the module math is already imported.
>>> import math

How to check Directory of a module: Every module has a directory ie. listing of all the functions, constants etc present inside a module. We can check the directory of a module as:
dir(modulename)

>>> import math

>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'nextafter', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc', 'ulp']

How to see the description of all the functions of a module in Python: We can take help of a module as:

>>> import math

>>> help(math)
Help on built-in module math:

NAME
    math

DESCRIPTION
    This module provides access to the mathematical functions
    defined by the C standard.

FUNCTIONS
    acos(x, /)
        Return the arc cosine (measured in radians) of x.
        
        The result is between 0 and pi.
    
    acosh(x, /)
        Return the inverse hyperbolic cosine of x.
    
    asin(x, /)
        Return the arc sine (measured in radians) of x.
        
        The result is between -pi/2 and pi/2.
    
    asinh(x, /)
        Return the inverse hyperbolic sine of x.
    
    atan(x, /)
        Return the arc tangent (measured in radians) of x.
        
        The result is between -pi/2 and pi/2.
    
    atan2(y, x, /)
        Return the arc tangent (measured in radians) of y/x.
        
        Unlike atan(y/x), the signs of both x and y are considered.
    
    atanh(x, /)
        Return the inverse hyperbolic tangent of x.
    
    ceil(x, /)
        Return the ceiling of x as an Integral.
        
        This is the smallest integer >= x.
    
    comb(n, k, /)
        Number of ways to choose k items from n items without repetition and without order.
        
        Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates
        to zero when k > n.
        
        Also called the binomial coefficient because it is equivalent
        to the coefficient of k-th term in polynomial expansion of the
        expression (1 + x)**n.
        
        Raises TypeError if either of the arguments are not integers.
        Raises ValueError if either of the arguments are negative.
    
    copysign(x, y, /)
        Return a float with the magnitude (absolute value) of x but the sign of y.
        
        On platforms that support signed zeros, copysign(1.0, -0.0)
        returns -1.0.
    
    cos(x, /)
        Return the cosine of x (measured in radians).
    
    cosh(x, /)
        Return the hyperbolic cosine of x.
    
    degrees(x, /)
        Convert angle x from radians to degrees.
    
    dist(p, q, /)
        Return the Euclidean distance between two points p and q.
        
        The points should be specified as sequences (or iterables) of
        coordinates.  Both inputs must have the same dimension.
        
        Roughly equivalent to:
            sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))
    
    erf(x, /)
        Error function at x.
    
    erfc(x, /)
        Complementary error function at x.
    
    exp(x, /)
        Return e raised to the power of x.
    
    expm1(x, /)
        Return exp(x)-1.
        
        This function avoids the loss of precision involved in the direct evaluation of exp(x)-1 for small x.
    
    fabs(x, /)
        Return the absolute value of the float x.
    
    factorial(x, /)
        Find x!.
        
        Raise a ValueError if x is negative or non-integral.
    
    floor(x, /)
        Return the floor of x as an Integral.
        
        This is the largest integer <= x.
    
    fmod(x, y, /)
        Return fmod(x, y), according to platform C.
        
        x % y may differ.
    
    frexp(x, /)
        Return the mantissa and exponent of x, as pair (m, e).
        
        m is a float and e is an int, such that x = m * 2.**e.
        If x is 0, m and e are both 0.  Else 0.5 <= abs(m) < 1.0.
    
    fsum(seq, /)
        Return an accurate floating point sum of values in the iterable seq.
        
        Assumes IEEE-754 floating point arithmetic.
    
    gamma(x, /)
        Gamma function at x.
    
    gcd(*integers)
        Greatest Common Divisor.
    
    hypot(...)
        hypot(*coordinates) -> value
        
        Multidimensional Euclidean distance from the origin to a point.
        
        Roughly equivalent to:
            sqrt(sum(x**2 for x in coordinates))
        
        For a two dimensional point (x, y), gives the hypotenuse
        using the Pythagorean theorem:  sqrt(x*x + y*y).
        
        For example, the hypotenuse of a 3/4/5 right triangle is:
        
            >>> hypot(3.0, 4.0)
            5.0
    
    isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0)
        Determine whether two floating point numbers are close in value.
        
          rel_tol
            maximum difference for being considered "close", relative to the
            magnitude of the input values
          abs_tol
            maximum difference for being considered "close", regardless of the
            magnitude of the input values
        
        Return True if a is close in value to b, and False otherwise.
        
        For the values to be considered close, the difference between them
        must be smaller than at least one of the tolerances.
        
        -inf, inf and NaN behave similarly to the IEEE 754 Standard.  That
        is, NaN is not close to anything, even itself.  inf and -inf are
        only close to themselves.
    
    isfinite(x, /)
        Return True if x is neither an infinity nor a NaN, and False otherwise.
    
    isinf(x, /)
        Return True if x is a positive or negative infinity, and False otherwise.
    
    isnan(x, /)
        Return True if x is a NaN (not a number), and False otherwise.
    
    isqrt(n, /)
        Return the integer part of the square root of the input.
    
    lcm(*integers)
        Least Common Multiple.
    
    ldexp(x, i, /)
        Return x * (2**i).
        
        This is essentially the inverse of frexp().
    
    lgamma(x, /)
        Natural logarithm of absolute value of Gamma function at x.
    
    log(...)
        log(x, [base=math.e])
        Return the logarithm of x to the given base.
        
        If the base not specified, returns the natural logarithm (base e) of x.
    
    log10(x, /)
        Return the base 10 logarithm of x.
    
    log1p(x, /)
        Return the natural logarithm of 1+x (base e).
        
        The result is computed in a way which is accurate for x near zero.
    
    log2(x, /)
        Return the base 2 logarithm of x.
    
    modf(x, /)
        Return the fractional and integer parts of x.
        
        Both results carry the sign of x and are floats.
    
    nextafter(x, y, /)
        Return the next floating-point value after x towards y.
    
    perm(n, k=None, /)
        Number of ways to choose k items from n items without repetition and with order.
        
        Evaluates to n! / (n - k)! when k <= n and evaluates
        to zero when k > n.
        
        If k is not specified or is None, then k defaults to n
        and the function returns n!.
        
        Raises TypeError if either of the arguments are not integers.
        Raises ValueError if either of the arguments are negative.
    
    pow(x, y, /)
        Return x**y (x to the power of y).
    
    prod(iterable, /, *, start=1)
        Calculate the product of all the elements in the input iterable.
        
        The default start value for the product is 1.
        
        When the iterable is empty, return the start value.  This function is
        intended specifically for use with numeric values and may reject
        non-numeric types.
    
    radians(x, /)
        Convert angle x from degrees to radians.
    
    remainder(x, y, /)
        Difference between x and the closest integer multiple of y.
        
        Return x - n*y where n*y is the closest integer multiple of y.
        In the case where x is exactly halfway between two multiples of
        y, the nearest even value of n is used. The result is always exact.
    
    sin(x, /)
        Return the sine of x (measured in radians).
    
    sinh(x, /)
        Return the hyperbolic sine of x.
    
    sqrt(x, /)
        Return the square root of x.
    
    tan(x, /)
        Return the tangent of x (measured in radians).
    
    tanh(x, /)
        Return the hyperbolic tangent of x.
    
    trunc(x, /)
        Truncates the Real x to the nearest Integral toward 0.
        
        Uses the __trunc__ magic method.
    
    ulp(x, /)
        Return the value of the least significant bit of the float x.

DATA
    e = 2.718281828459045
    inf = inf
    nan = nan
    pi = 3.141592653589793
    tau = 6.283185307179586

FILE
    (built-in)

How to see the description of a function of a module in Python: We can take help of a function of a module as:

>>> import math

>>> help(math.sqrt)
Help on built-in function sqrt in module math:

sqrt(x, /)
    Return the square root of x.

Alias name of a module: We have to write module name every time we access any constant or function of a module. But if the module name is too large, we can give an alias name of a module as
import modulename as aliasname
Generally the alias name is the short name of a module.
Now we can use alias name of a module to access any function of that module as

>>> import math as m
>>> m.sqrt(25)
5.0

But now we can’t use module name to access the functions of that module.

>>> import math as m

>>> math.sqrt(25)
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    math.sqrt(25)
NameError: name 'math' is not defined

Importing Specific Objects (Constants/Functions) from a Module: We can import only the required constants/functions from a module as
from modulename import object
from modulename import object1, object2, object3……
After importing the desired objects, we can access them directly without the need for a dot(.) Notation to call the objects.

>>>from math import pow
>>> from math import pi, sqrt

>>> pi
3.141592653589793
>>> sqrt(25)
5.0

But in this case, we can use only the imported objects of that module. If we try to access any other object of that module, python will give error as:

>>> from math import pi, sqrt

>>> sin(0)
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    sin(0)
NameError: name 'sin' is not defined

Alias name of an object: We have to write object name every time we access it. But if
1) the object name is too large or
2) the objectname already exists in the current namespace,
We can give an alias name of an object as
from modulename import objectname as aliasname
Generally the alias name is the short name of an object, or a different name from an object already existing in the current namespace to avoid ambiguity. Now we can use alias name of the object to access it.

>>> pi=3.5

>>>#Using alias name to avoid ambiguity in pi declared in math module and current namespace 
>>> from math import pi as p

>>> pi
3.5

>>> p
3.141592653589793

>>># Using short name as an alias name of remainder function
>>> from math import remainder as r
>>> r(10,3)
1.0

But now we can’t use object name to access it.

>>> from math import pi as p
>>> from math import remainder as r

>>> pi
Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    pi
NameError: name 'pi' is not defined

>>> remainder(10,3)
Traceback (most recent call last):
  File "<pyshell#34>", line 1, in <module>
    remainder(10,3)
NameError: name 'remainder' is not defined

Importing all objects of a module: We can import all the objects of a module as
from modulename import *
Now we can access all the objects of that module directly, without dot (.) notation to call the objects as:

>>> from math import *

>>> sin(0)
0.0

Namespace: It is a space that holds a bunch of names. It is a named logical environment that holds logical grouping of related objects within a namespace. All the member objects of a namespace is referred without any prefix.
Example: 1) Your house is a namespace having names of all of your family members.
2) Your class is a namespace having names of all the students of your class.

Fully Qualified name: It is the full name of an object written as modulename.objectname.
To resolve any kind of object name dispute, we must use fully qualified name of the object as
modulename.objectname

This is similar to situation of a class as:
Any student can be called inside your class by their name if all the names are unique.
But if two or more students have same name , they may be called using their hometown/address as
Sonipat’s Ansh
Panipat’s Ansh
Delhi’s Ansh

>>>#pi is a variable having value 3.5 in current namespace

>>> pi=3.5
>>>#module math also has a variable pi
>>> import math

>>>#displaying the value of pi in current namespace
>>> pi
3.5

>>>#displaying the value of pi declared in math module
>>> math.pi
3.141592653589793

Processing of import modulename: when we write a python statement as
import modulename
Python does the following
1) Code of imported module is interpreted and executed
2) All the objects (functions and constants) defined in the module are now available to the program
3) A new namespace is setup with the same name as that of the module
4) So we need to access the objects of the module by using dot(.) notation as modulename.objectname

Processing of from modulename import object(s): when we write a python statement as
from modulename import object(s)
Python does the following
1) Code of imported module is interpreted and executed
2) Only the mentioned objects (functions and constants) defined in the module are now available to the program
3) No new namespace is setup, but the imported objects are added to the current namespace.
4) So we dont need to access the objects of the module by using dot(.) notation as modulename.objectname and we can use only the imported objects directly as objectname

Processing of from modulename import *: when we write a python statement as
from modulename import *
Python does the following
1) Code of imported module is interpreted and executed
2) All the objects (functions and constants) defined in the module are now available to the program
3) No new namespace is setup, but all the objects are added to the current namespace.
4) So we dont need to access the any object of the module by using dot(.) notation as modulename.objectname and we can use all the objects directly as objectname

Using objects (constants/function) of math module:
pi: a constant to store the value of π
e: a constant to store the value of e
sqrt:(number) a function to find the square root of a number
ceil(number): a function to find the smallest integer greater than or equal to the argument passed.
floor(number): a function to find the greatest integer less than or equal to the argument passed.
pow(base,exponent): a function to find the power of a base/number to the specified power/exponent.
fabs(number): a function to return the positive value of the number passed.
sin(angle): a function to find the value of sin of an angle passed in radians.
cos(angle): a function to find the value of cos of an angle passed in radians.
tan(angle): a function to find the value of tan of an angle passed in radians.

pi: a constant to store the value of π
e: a constant to store the value of e

>>> import math

>>> math.pi
3.141592653589793

>>> math.e
2.718281828459045

sqrt(number): a function to find the square root of a number.
math.sqrt(number)

>>> import math

>>> math.sqrt(25)
5.0

Python will give error, if the number is negative or if the argument is not a number as

>>> import math

>>> math.sqrt(-25)
Traceback (most recent call last):
  File "<pyshell#39>", line 1, in <module>
    math.sqrt(-25)
ValueError: math domain error

>>> math.sqrt("gargs")
Traceback (most recent call last):
  File "<pyshell#40>", line 1, in <module>
    math.sqrt("gargs")
TypeError: must be real number, not str

ceil(number): a function to find the smallest integer greater than or equal to the argument passed.
floor(number): a function to find the greatest integer less than or equal to the argument passed.

>>> import math

>>> math.ceil(2.5)
3
>>> math.ceil(-2.5)
-2
>>> math.floor(2.5)
2
>>> math.floor(-2.5)
-3

>>> math.ceil(0)
0
>>> math.ceil(-0)
0
>>> math.floor(0)
0
>>> math.floor(-0)
0

Python will give error, if the argument is not a number as

>>> import math

>>> math.ceil("gargs")
Traceback (most recent call last):
  File "<pyshell#45>", line 1, in <module>
    math.ceil("gargs")
TypeError: must be real number, not str

>>> math.floor("gargs")
Traceback (most recent call last):
  File "<pyshell#46>", line 1, in <module>
    math.floor("gargs")
TypeError: must be real number, not str

pow(base,exponent): a function to find the power of a base/number to the specified power/exponent.

>>> math.pow(2,5)
32.0

>>> math.pow(5,2)
25.0

Python will give error, if we either don’t specify the base or the exponent or specify the non numeric values for the base or the exponent as:

>>>import math

>>> math.pow(2)
Traceback (most recent call last):
  File "<pyshell#68>", line 1, in <module>
    math.pow(2)
TypeError: pow expected 2 arguments, got 1

>>> math.pow()
Traceback (most recent call last):
  File "<pyshell#69>", line 1, in <module>
    math.pow()
TypeError: pow expected 2 arguments, got 0

>>> math.pow("gargs")
Traceback (most recent call last):
  File "<pyshell#72>", line 1, in <module>
    math.pow("gargs")
TypeError: pow expected 2 arguments, got 1

>>> math.pow("gargs",2)
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    math.pow("gargs",2)
TypeError: must be real number, not str


>>> math.pow(2,"gargs")
Traceback (most recent call last):
  File "<pyshell#71>", line 1, in <module>
    math.pow(2,"gargs")
TypeError: must be real number, not str

fabs(number): a function to return the positive value of the number passed.

>>> import math


>>> math.fabs(10.4)
10.4

>>> math.fabs(-456)
456.0

>>> math.fabs("gargs")
Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    math.fabs("gargs")
TypeError: must be real number, not str

sin(angle): a function to find the value of sin of an angle passed in radians.
cos(angle): a function to find the value of cos of an angle passed in radians.
tan(angle): a function to find the value of tan of an angle passed in radians.

>>> import math

>>> math.sin(math.pi/6)
0.49999999999999994

>>> math.sin(30)
-0.9880316240928618

>>> math.cos(60)
-0.9524129804151563

>>> math.cos(math.pi/3)
0.5000000000000001

>>> math.tan(30)
-6.405331196646276

>>> math.tan(math.pi/6)
0.5773502691896257

Python will error, if the argument passed is non numeric as

>>>import math

>>> math.sin("gargs")
Traceback (most recent call last):
  File "<pyshell#61>", line 1, in <module>
    math.sin("gargs")
TypeError: must be real number, not str

>>> math.cos("gargs")
Traceback (most recent call last):
  File "<pyshell#62>", line 1, in <module>
    math.cos("gargs")
TypeError: must be real number, not str

>>> math.tan("gargs")
Traceback (most recent call last):
  File "<pyshell#63>", line 1, in <module>
    math.tan("gargs")
TypeError: must be real number, not str

Using random module: random module contains the functions to generate random numbers ie the numbers generated by chance.
random(): function to generate a random float number in the range [0,1)
randint(a,b): function to generate a random integer number in the range [a,b]
uniform(a,b): function to generate a random float number in the range
[a,b] if a≤b
[b,a] if b≤a

random(): function to generate a random float number in the range [0,1).
Notice that there is a closed interval at 0 ie 0 can be included but
there is an open interval at 1 ie 1 can’t be included.

>>> import random

>>> random.random()
0.2514508664953561

We can generate random float numbers in the range a to b as:
1) random.random() * (b-a) + a
2) random.random() * (a-b) + b
Example: To generate random floats between 10 to 20, we can write as

>>>import random

>>>#[(0 to 1) * 10 ] + 10 will give [(0 to 10)] + 10 = (10 to 20)
>>> random.random()* (20-10) + 10
19.66434061734062

>>>#[(0 to 1) * -10] + 10 will give [(-10 to 0 )] + 10 = (10 to 20)
>>> random.random()* (10-20) + 20
19.618955262211635

randint(a,b): function to generate a random integer number in the range [a,b]
Notice that there is a closed interval both at 0 and 1 ie both 0 and 1 can be included in the generated numbers.

>>> import random
>>> random.randint(10,20)
18

Python will give error if we dont specify either of the arguments or if the specified arguments are non numeric.

>>> import random

>>> random.randint(10)
Traceback (most recent call last):
  File "<pyshell#81>", line 1, in <module>
    random.randint(10)
TypeError: randint() missing 1 required positional argument: 'b'

>>> random.randint(10,"gargs")
Traceback (most recent call last):
  File "<pyshell#82>", line 1, in <module>
    random.randint(10,"gargs")
  File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\random.py", line 339, in randint
    return self.randrange(a, b+1)
TypeError: can only concatenate str (not "int") to str

uniform(a,b): function to generate a random float number in the range
[a,b] if a≤b
[b,a] if b≤a

>>> import random

>>> random.uniform(10,20)
18.246111970946302

>>> random.uniform(20,10)
10.552223862658526

Python will give error if we dont specify either of the arguments or if the specified arguments are non numeric.

>>> import random

>>> random.uniform(20)
Traceback (most recent call last):
  File "<pyshell#86>", line 1, in <module>
    random.uniform(20)
TypeError: uniform() missing 1 required positional argument: 'b'

>>> random.uniform(20,"gargs")
Traceback (most recent call last):
  File "<pyshell#87>", line 1, in <module>
    random.uniform(20,"gargs")
  File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\random.py", line 506, in uniform
    return a + (b - a) * self.random()
TypeError: unsupported operand type(s) for -: 'str' and 'int'

Using statistics module: statistics module contains the statistical functions to find the mean, median, mode etc.
1) mean(data): to find the mean or average of data
2)median(data): to find the median of data
3)mode(data): to find the mode of data

1) mean(data): to find the mean or average of data.
Average or mean is found by dividing the sum of all values by the number of values.

>>> import statistics

>>> list1=[2,3,4,5,6]
>>> statistics.mean(list1)
4

>>> tuple1=(2,3,4,5,6)
>>> statistics.mean(tuple1)
4

>>> set1={2,3,4,5,6}
>>> statistics.mean(set1)
4

>>> dict1={2:20,3:30,4:40,5:50,6:60}
>>> statistics.mean(dict1)
4

Python will give error, if the data specified is non numeric.

>>> import statistics

>>> list2=[2,3,4,5,6,"gargs"]

>>> statistics.mean(list2)
Traceback (most recent call last):
  File "<pyshell#98>", line 1, in <module>
    statistics.mean(list2)
  File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\statistics.py", line 316, in mean
    T, total, count = _sum(data)
  File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\statistics.py", line 166, in _sum
    for n, d in map(_exact_ratio, values):
  File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\statistics.py", line 248, in _exact_ratio
    raise TypeError(msg.format(type(x).__name__))
TypeError: can't convert type 'str' to numerator/denominator

2) median(data): to find the median of data.
Median is found by
1) Arranging the data in ascending or descending order
2) Find the middle value, if the number of values is odd
3) Find the average of two middle values, if the number of values is even

>>> import statistics
>>>#number of values=5
>>># After arranging list will be 2,3,4,5,6
>>>#middle value after arranging is 4
>>> list1=[2,3,6,5,4]
>>> statistics.median(list1)
4

>>>#number of values=5
>>># After arranging list will be 2,3,4,5,6,7
>>>#average of two middle values after arranging ie 4 and 5 is 4.5
>>> list2=[2,3,6,5,4,7]
>>> statistics.median(list2)
4.5

Python will give error, if the specified data is non numeric.

>>> import statistics
>>> list3=[2,3,4,5,6,"gargs"]

>>> statistics.median(list3)
Traceback (most recent call last):
  File "<pyshell#104>", line 1, in <module>
    statistics.median(list3)
  File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\statistics.py", line 427, in median
    data = sorted(data)
TypeError: '<' not supported between instances of 'str' and 'int'

3) mode(data): to find the mode of data.
Mode is the most frequently occurring value in the data.
If two or more values have the same frequency, then it will give the value that appears first in the data list.

>>> import statistics

>>>#3 appears most frequent ie 2 times
>>> list1=[2,3,6,5,3]
>>> statistics.mode(list1)
3

>>># 3 and 4 appears twice ie both have same frequency.
>>># So it will give that value, which appears first in the list
>>> list2=[2,3,3,4,4,5]
>>> statistics.mode(list2)
3

>>># all items appears exactly once ie all items have same frequency.
>>># So it will give that value, which appears first in the list
>>> list3=[2,3,6,5,4]
>>> statistics.mode(list3)
2

Python will not give error, if the specified data is non numeric.

>>> list2=["gargs academy", 2,3,4,5,6]

>>> statistics.mode(list2)
'gargs academy'
error: You can only copy the programs code and output from this website. You are not allowed to copy anything else.