//stl functions
//accumulate(a.begin(),a.end(),0)           //returns sum of elements from first argument to last argument + third argument       //third optinal argument can be passed which is function according to operation to all elements are to be done generally a recursive operation like sum of elements or product of elements (refer website for third argument)
           //O(a.size())
//advance(it,n)           //makes it point to n element afteer initial pointed value of it.it causes ub if it goes out of bounds
           //O(1) for random access iterator and O(n) for bidirectional or forward iterator
//binary_search(a.begin(),a.end(),val)           only if a is sorted//returns true if val is there in a   //third optional argument can be passed which is a function which returns true if first argument in function argument is less than second i.e. returns true if first argument is less
           //O(log(a.size()))
//c-style//bsearch(val,a.begin(),a.size(),sizeof(ll/int),func)           only if a is sorted//returns pointer to val in a if val is not in a NULL is returned.First argument is pointer to a value that is to be found and func is function that returns -ve if first arg is less than second 0 if equal and +ve if greater
           //O(log(a.size()))
//copy(a.begin(),a.end(),b.begin())           //copies elements in container a into b and returns iterator pointing to element in b after last element copied in b from a
           //O(a.size())
//count(a.begin(),a.end(),val)           //returns number of occurences of val in a
           //O(a.size())
//erase(it)           //removes element pointed by it if two pointers are added then elements in their range are removed
           //O(a.end()-it)
//find_first_of(a.begin(),a.end(),b.begin(),b.end())           //returns iterator of first element in a that matches any of the element in b if no equal element is found a.end()            //third optional argument can be passed which would be a function to determine whether element of a is equal to b or not
           //O(a.size()*b.size())
//inserter(a,it)           //here a is any container and it is an iterator pointing to any element in a. inserter() returns an insert_iterator which is special type of output iterator in which if we try to overwrite an element than a new element is added in it's place for ex:- if initial elements were 1,2,3,4,5 and writing 9 at iteraator pointing to 4 would make elements as 1,2,3,9,4,5 and other operator are defined but they don't do anything here it would always point at 4 and changing it's value would add a new element behind it with changed value.
           //O(1)
//string::find_first_of(string s,int pos=0)           //returns iterator pointing to first element found in object calling function which matches any element in s after pos if no such element is found npos is returned      //npos is largest possible index and it's value is -1 as npos is unsigned
           //O(n*s.size()) n is size of string in object calling function
//min(a,b) returns minimum of two same arguments           //third optional argument can be added to compare according to function argument passed into optional function are in reverse order of passed arguments in min() if function returns true min() returns b else a
           //O(1)
//min_element(a.begin(),a.end())           //returns iterator pointing to first occurence of minimum value in range [begin,end)        //third optional argument can be passed which is a function used to compare two values of pointers if first pointed value is greater return false
           //O(a.size())
//max_element(a.begin(),a.end())           //returns iterator pointing to first occurence of maximum value in range [begin,end)        //third optional argument can be passed which is a function used to compare two values of pointers if first pointed value is greater return false
           //O(a.size())
           //it depends on data structures passed O(1)for basic O(n) for array,vector
//next(it,n)           //similar to advance except it does not change passed iterator's value but returns an desired iterator           //second argument is optional it's default value is 1
           //O(1) for random access iterator and O(n) for bidirectional or forward iterator
//prev(it,n)           //similar to next() except it goes behind unlike next() which goes ahead
           //O(1) for random access iterator and O(n) for bidirectional or forward iterator
//reverse(a.begin(),a.end())           //to reverse entire vector
           //O(a.size())
//sort(a.begin(),a.end())           //sorts the array in monotonically increasing order by default    //third optional argument can be added to arrange according to passed function It has 2 same type arguments and comparison is occured between them and container is sorted in such a way that all consecutive elements when passed to function return 1 i.e. func(a[i],a[i+1])=1
           //O(n*log(n))  where n is a.size()
//0//stoi(),stol(),stoll()INV to_string()
//swap(a,b)           //swaps two values
#include <iostream>
#include<bits/stdc++.h>
//#define NDEBUG//used for disabling assert when condition in assert is false program is terminated
#define fast ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(0);
using namespace std;
typedef long long ll;
ll mod=1e9+7;
template<typename T>
T gcd(T a,T b)
{
    if(a<b)swap(a,b);
    if(b==0)return a;
    return gcd(b,a%b);
}
int set_bits(ll n)
{
    ll ans=0;
    while(n>0)
    {
        if(n%2)ans++;
        n/=2;
    }
    return ans;
}
ll no_factors(ll n)
{
    if(n==1)return 1;
    ll ans=2;
    for(int i=2;i<sqrt(n);i++)
    {
        if(n%i==0)ans+=2;
    }
    if(sqrt(n)==(int)sqrt(n))ans++;
    return ans;
}
class pairs
{
    public: ll x,y;
};
class solution
{
    char c;
    public:
    solution()
    {
        cin>>c;
        if(isupper(c))
        cout<<'A'<<endl;
        else cout<<'a'<<endl;
    }
};
int main() {
	    solution s;
	return 0;
}

Measured memory_bytes: 3576