@Override
    public <T> T select( String msg, Collection<T> candidates) {
        ImmutableList<T> copyList = ImmutableList.copyOf( candidates);

        this.writeln( msg);
        this.write( Message.CANDIDATE_BOX, this.formatCandidates( 0, copyList));

        try {
            BufferedReader reader = new BufferedReader( //
                new InputStreamReader( System.in, Charset.defaultCharset()));

            Range<Integer> validRange = Ranges.closed( 1, copyList.size());

            while ( true) {
                try {
                    this.write( Message.PROMPT_SYMBOL);
                    String input = reader.readLine();

                    // XXX: もっと細かく入力チェックするなら、BigIntegerあたりでStringをパースし、
                    // 細かくビット数等を見ればよいのだが、オーバースペックだと思われる。
                    int parseInput = Integer.parseInt( input);

                    if ( validRange.apply( parseInput)) {
                        return copyList.get( parseInput - 1);
                    }

                    this.write( //
                        Message.ILLEGAL_INPUT_ERROR, //
                        validRange.lowerEndpoint(), //
                        validRange.upperEndpoint() //
                    );
                }
                catch ( NumberFormatException e) {
                    this.write( //
                        Message.ILLEGAL_INPUT_ERROR, //
                        validRange.lowerEndpoint(), //
                        validRange.upperEndpoint() //
                    );
                }
            }
        }
        catch ( IOException e) {
            throw new RuntimeException( e);
        }
    }