
#include <iostream>
#include <list>

class String {
  char *s;

  void assign(const char *str) {
    if (!str)
      goto empty;

    size_t length;
    for (length = 0; str[length]; length++)
      ;
    if (!length)
      goto empty;

    s = new char[length + 1];
    for (size_t i = 0; i <= length; i++) {
      s[i] = str[i];
    }
    return;

  empty:
    s = nullptr;
  }

public:
  /* konstruktory, destruktory a prirazeni */
  String() : s(nullptr) {
    std::cerr << "Prazdny string @" << this << std::endl;
  }

  String(const String &x) {
    assign(x.s);
    std::cerr << "Kopirovanie @" << this << std::endl;
  }

  String(String &&x) {
    s = x.s;
    x.s = nullptr;
    std::cerr << "Presouvani @" << this << std::endl;
  }

  String(const char *str) {
    assign(str);
    std::cerr << "Kopie z bufferu @" << this << std::endl;
  }

  ~String() {
    clear();
    std::cerr << "Destrukcia @" << this << std::endl;
  }

  void operator=(const String &second) {
    clear();
    assign(second.c_str());
    std::cerr << "Prirazeni kopie @" << this << std::endl;
  }

  void operator=(String &&second) {
    std::swap(s,second.s);
    std::cerr << "Prirazeni presunem @" << this << std::endl;
  }

  /* jednoduche pomocne funkce */
  void clear() {
    if (empty())
      return;
    delete[] s;
    s = nullptr;
  }

  const char *c_str() const { return s; }

  bool empty() const { return !s; }

  char &operator[](size_t i) { return s[i]; }

  /* hodi se -- do indexovanych prvku v konstantnim
   * vektoru by nemelo jit zapisovat */
  const char &operator[](size_t i) const { return s[i]; }

  size_t length() const {
    if (!s)
      return 0;
    size_t len = 0;
    while (s[len])
      ++len;
    return len;
  }

  /* spojovani stringu */
  void operator+=(const String &second) {
    std::cerr << "Pricitani += @" << this << std::endl;
    size_t len1 = length();
    size_t len2 = second.length();
    if (!len1 && !len2)
      return;
    char *s2 = new char[len1 + len2 + 1];
    for (size_t i = 0; i < len1; i++)
      s2[i] = s[i];
    for (size_t i = 0; i < len2; i++)
      s2[i + len1] = second.s[i];
    s2[len1 + len2] = 0;
    clear();
    s = s2;
  }

  String operator+(const String &second) const {
    String temp(*this);
    temp += second;
    return temp;
  }

  /* porovnavani */
  bool operator==(const String &other) {
    std::cerr << "Porovnani == @" << this << std::endl;
    char *p = s, *q = other.s;
    if (!(p && q))
      return p == q;
    for (; *p && *q; p++, q++)
      if (*p != *q)
        return false;
    if (*p != *q)
      return false;
    return true;
  }

  bool operator<(const String &other) {
    std::cerr << "Porovnani < @" << this << std::endl;
    char *p = s, *q = other.s;
    if (!(p && q))
      return p < q;
    for (; *p && *q; p++, q++) {
      if (*p == *q)
        continue;
      if (*p > *q)
        return false;
      return true;
    }
    return *p < *q;
  }

  bool operator>(const String &other) {
    std::cerr << "Porovnani > @" << this << std::endl;
    char *p = s, *q = other.s;
    if (!(p && q))
      return p > q;
    for (; *p && *q; p++, q++) {
      if (*p == *q)
        continue;
      if (*p < *q)
        return false;
      return true;
    }
    return *p > *q;
  }
};

String reverse(const String &str) {
  String r = String(str.c_str());
  size_t len = r.length();
  for (size_t i = 0; i < len / 2; i++) {
    std::swap(r[i], r[len - i - 1]);
  }
  return r;
}

std::ostream &operator<<(std::ostream &os, const String &s) {
  if (!s.empty())
    os << s.c_str();
  return os;
}

/*
 * POZN: tohle je problematicke, spravna implementace by mela:
 * - zkonzumovat whitespace do prvniho vyznamneho znaku
 * - ulozit si vyznamne znaky az do dalsiho whitespace
 * - vratit vysledek, dalsi whitespace ale nekonzumovat
 *
 * Problem je, ze stream muze "selhat" uz na zacatku v prvnim kroku, v takovem
 * pripade je potreba problem korektne oznamit, napr. nastavenim failbitu ve
 * streamu.
 *
 * Druhy problem je ten, ze tento zpusob neni uplne vhodny na dlouhe stringy
 * (dojde k O(lenght) realokacim a kopiim).
 *
 * Spravne by se to provedlo nejakou metodou podobnou std::vector.
 *
 * Extra funkce na "append charu" ve stringu by taky nebyla spatna. :]
 */
std::istream &operator>>(std::istream &os, String &s) {
  s.clear();
  String str(" ");
  while(os and !isspace(os.peek())){
    str[0] = os.get();
    s += str;
  }
  return os;
}

#include <algorithm> //std::sort
#include <vector> //std::vector

int main2() {
  String a("test");
  String b("aaa");
  std::cerr << " *** Pricitani" << std::endl;
  a += b;
  std::cerr << " *** Otoceni" << std::endl;
  b = reverse(a);
  std::cerr << " *** Slepovani a vypsani" << std::endl;
  std::cout << (reverse(b) + b + "aaa") << std::endl;

  // demo -- string se chova pomerne rozumne i kdyz ho pouzivate v ramci jinych
  // kontejneru. Je pekne pozorovat kolik konstrukci a destrukci vlastne
  // probehne.
  std::cerr << " *** Vyrabeni vektoru" << std::endl;
  std::vector<String> v;
  v.push_back("test");
  v.push_back("test2");
  v.push_back("asd");
  v.emplace_back("qwe"); // emplace nevytvori "mezihodnotu", takze je trochu
                         // uspornejsi (v logu bude jen jedna kopie z bufferu
                         // primo na misto kde string ma vzniknout)
  v.emplace_back(); // prazdny string
  v.push_back("zxc"); // realokace vektoru pri pushi je tady uz
                      // pomerne narocna operace :]

  std::cerr << " *** Kopie vektoru" << std::endl;
  std::vector<String> v2 = v; // tohle vyrobi celkem dost kopii

  std::cerr << " *** Setrideni vektoru" << std::endl;
  std::sort(v2.begin(), v2.end());
  for (auto &i : v2)
    std::cout << "> " << i << std::endl;

  std::cerr << " *** Vycisteni jednoho vektoru" << std::endl;
  v.clear();

  std::cerr << " *** Konec" << std::endl;
  return 0;
}

//////////////////////////////

template<typename T> 
std::list<T> merge (std::list<T> &a, std::list<T> &b) {
  std::list<T> l;
  while(!a.empty() && !b.empty()){
    if(a.front() > b.front()){
      l.splice(l.end(), b, b.begin());
    }
    else{
      l.splice(l.end(), a, a.begin());
    }
  }
  std::move(a.begin(), a.end(), std::back_inserter(l));
  std::move(b.begin(), b.end(), std::back_inserter(l));
  return l;
}

template <typename T>
void mergesort(std::list<T> &lst)
{
  std::list<std::list<T>> ll;
  for(auto && x : lst) {
    std::list<T> temp;
    temp.emplace_back(std::move(x)); 
    ll.emplace_back(std::move(temp));
    //ll.emplace_back({x});
  }
  
  while(ll.size() > 1) {
    std::list<T> l1(std::move(ll.front()));
    ll.pop_front();
    std::list<T> l2(std::move(ll.front()));
    ll.pop_front();
    ll.emplace_back(merge(l1, l2));
  }
  
  lst = std::move(ll.front());
}

#include <string>

int main3(){
  size_t n = 10;
  std::list<String> lst;

  
  std::string s;
  for(size_t i = 0; i < n; i++)
  {
    std::cin>>s;
    lst.emplace_back(s.c_str());
  }

  mergesort(lst);

  for(auto && x : lst)
    std::cout<<x<<" ";
  std::cout<<std::endl;
  return 0;
}

#include <fstream>
#include <map>

int main4(){
  std::ofstream os("nasobilka.txt");
  for(size_t i = 0; i < 10; ++i){
    for(size_t j = 0; j < 10; ++j){
      os << i << "*" << j << "=" << i*j << std::endl;
    }
  }
  return 0;
}

int main(){
  std::ifstream input_file("slovnik.txt");
  std::map<std::string, std::string> dict;

  while(input_file){
    std::string first_word, second_word;
    input_file >> first_word >> second_word;
    dict[first_word] = second_word;
  }
  input_file.close();
  while(std::cin){
    std::string word;
    std::cin >> word;
    auto it = dict.find(word);
    if(it == dict.end()){
      std::cout << word << " ";
    }
    else {
      std::cout << it->second << " ";
    }
  }
  return 0;
}
