#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TOTAL_SIZE 100003

void check(void *buffer, const char *name, size_t length)
{
  if (buffer == NULL) {
    fprintf(stderr, "%s: can\'t malloc %ld bytes\n", name, (long)length);
    exit(1);
  }
}

char *copy(const char *string)
{
  char *buffer;
  size_t length;

  length = strlen(string) + 1;
  buffer = malloc(length);
  check(buffer, "copy", length);
  strcpy(buffer, string);
  return buffer;
}

size_t hash(const char *string, size_t n)
{
  unsigned long k = 0;
  const char *p;

  for (p = string; *p != '\0'; p++)
    k = k * 5 + *p;
  return k % n;
}

void grow(char **buffer, size_t *length)
{
  *buffer = realloc(*buffer, *length += 16);
  check(*buffer, "grow", *length);
}

char *getline(void)
{
  static char *buffer;
  static size_t length;
  int c;
  size_t i = 0;

  if (feof(stdin)) return NULL;
  do {
    if (i >= length) grow(&buffer, &length);
    buffer[i++] = c = getchar();
  } while (c != '\n' && c != EOF);
  buffer[--i] = '\0';
  return buffer;
}

int compare(const void *a, const void *b)
{
  return strcmp(*(char **)a, *(char **)b);
}

typedef struct node *link;
struct node {
  char *key;
  size_t value;
  link next;
};

size_t *lookup(link* total, size_t total_size,
               size_t *total_count, const char *string)
{
  link *p = &total[hash(string, total_size)];

  while (*p != NULL) {
    if (strcmp((*p)->key, string) == 0)
      return &(*p)->value;
    p = &(*p)->next;
  }
  *p = malloc(sizeof(**p));
  check(*p, "lookup", sizeof(**p));
  (*p)->key = copy(string);
  (*p)->value = 0;
  (*p)->next = NULL;
  (*total_count)++;
  return &(*p)->value;
}

int main(void)
{
  static link total[TOTAL_SIZE];
  const char *space = " ";
  char *line, *word, **words;
  link p;
  size_t i, j, count, total_count = 0;

  while (line = getline()) {
    word = strtok(line, space);
    while (word) {
      (*lookup(total, TOTAL_SIZE, &total_count, word))++;
      word = strtok(NULL, space);
    }
  }

  words = malloc(total_count * sizeof(*words));
  check(words, "main", total_count * sizeof(*words));

  for (i = 0, j = 0; j < TOTAL_SIZE; j++)
    for (p = total[j]; p != NULL; p = p->next)
      words[i++] = p->key;

  qsort(words, total_count, sizeof(*words), compare);

  for (i = 0; i < total_count; i++) {
    word = words[i];
    count = *lookup(total, TOTAL_SIZE, &total_count, word);
    printf("%s %ld\n", word, (long)count);
  }

  exit(0);
}
