void isReadable(SelectionKey k) {
    EventableChannel ec = (EventableChannel) k.attachment();
    long b = ec.getBinding();

    if (ec.isWatchOnly()) {
      if (ec.isNotifyReadable()) eventCallback(b, EM_CONNECTION_NOTIFY_READABLE, null);
    } else {
      myReadBuffer.clear();

      try {
        ec.readInboundData(myReadBuffer);
        myReadBuffer.flip();
        if (myReadBuffer.limit() > 0) {
          if (ProxyConnections != null) {
            EventableChannel target = ProxyConnections.get(b);
            if (target != null) {
              ByteBuffer myWriteBuffer = ByteBuffer.allocate(myReadBuffer.limit());
              myWriteBuffer.put(myReadBuffer);
              myWriteBuffer.flip();
              target.scheduleOutboundData(myWriteBuffer);
            } else {
              eventCallback(b, EM_CONNECTION_READ, myReadBuffer);
            }
          } else {
            eventCallback(b, EM_CONNECTION_READ, myReadBuffer);
          }
        }
      } catch (IOException e) {
        UnboundConnections.add(b);
      }
    }
  }
  void isReadable(SelectionKey k) {
    EventableChannel ec = (EventableChannel) k.attachment();
    long b = ec.getBinding();

    if (ec.isWatchOnly()) {
      if (ec.isNotifyReadable()) eventCallback(b, EM_CONNECTION_NOTIFY_READABLE, null);
    } else {
      myReadBuffer.clear();

      try {
        ec.readInboundData(myReadBuffer);
        myReadBuffer.flip();
        if (myReadBuffer.limit() > 0) eventCallback(b, EM_CONNECTION_READ, myReadBuffer);
      } catch (IOException e) {
        UnboundConnections.add(b);
      }
    }
  }
  /**
   * Decode file charset.
   *
   * @param f File to process.
   * @return File charset.
   * @throws IOException in case of error.
   */
  public static Charset decode(File f) throws IOException {
    SortedMap<String, Charset> charsets = Charset.availableCharsets();

    String[] firstCharsets = {
      Charset.defaultCharset().name(), "US-ASCII", "UTF-8", "UTF-16BE", "UTF-16LE"
    };

    Collection<Charset> orderedCharsets = U.newLinkedHashSet(charsets.size());

    for (String c : firstCharsets)
      if (charsets.containsKey(c)) orderedCharsets.add(charsets.get(c));

    orderedCharsets.addAll(charsets.values());

    try (RandomAccessFile raf = new RandomAccessFile(f, "r")) {
      FileChannel ch = raf.getChannel();

      ByteBuffer buf = ByteBuffer.allocate(4096);

      ch.read(buf);

      buf.flip();

      for (Charset charset : orderedCharsets) {
        CharsetDecoder decoder = charset.newDecoder();

        decoder.reset();

        try {
          decoder.decode(buf);

          return charset;
        } catch (CharacterCodingException ignored) {
        }
      }
    }

    return Charset.defaultCharset();
  }
  public EmReactor() {
    Timers = new TreeMap<Long, ArrayList<Long>>();
    Connections = new HashMap<Long, EventableChannel>();
    Acceptors = new HashMap<Long, ServerSocketChannel>();
    NewConnections = new ArrayList<Long>();
    UnboundConnections = new ArrayList<Long>();
    DetachedConnections = new ArrayList<EventableSocketChannel>();

    BindingIndex = 0;
    loopBreaker = new AtomicBoolean();
    loopBreaker.set(false);
    myReadBuffer =
        ByteBuffer.allocate(
            32 * 1024); // don't use a direct buffer. Ruby doesn't seem to like them.
    timerQuantum = 98;
  }
 @Override
 public int read(final ByteBuffer bb, final int pos) {
   this.m_isReset = false;
   bb.position(pos);
   while (bb.remaining() > 0) {
     boolean needToProcessPacket = true;
     if (this.m_decodeReady) {
       final Info info = this.m_info[this.m_currentLink];
       final int totalSamples = this.m_dspState.synthesis_pcmout(this.m_pcmf_buffer, this._index);
       final float[][] pcm = this.m_pcmf_buffer[0];
       if (totalSamples > 0) {
         final int channelsCount = info.channelsCount;
         final int bytesPerSample = channelsCount * 2;
         int samples = Math.min(totalSamples, bb.remaining() / bytesPerSample);
         samples = Math.min(samples, 8192 / bytesPerSample);
         needToProcessPacket = (samples == totalSamples);
         for (int i = 0; i < channelsCount; ++i) {
           int ptr = i * 2;
           final int mono = this._index[i];
           for (int j = 0; j < samples; ++j) {
             int val = (int) (pcm[i][mono + j] * 32767.0f);
             if (val > 32767) {
               val = 32767;
             }
             if (val < -32768) {
               val = -32768;
             }
             if (val < 0) {
               val |= 0x8000;
             }
             if (JOrbisStream.m_bigEndian) {
               this.m_conversionBuffer[ptr] = (byte) (val >>> 8 & 0xFF);
               this.m_conversionBuffer[ptr + 1] = (byte) (val & 0xFF);
             } else {
               this.m_conversionBuffer[ptr] = (byte) (val & 0xFF);
               this.m_conversionBuffer[ptr + 1] = (byte) (val >>> 8 & 0xFF);
             }
             ptr += 2 * channelsCount;
           }
         }
         final int writtenBytesLength = samples * bytesPerSample;
         bb.put(this.m_conversionBuffer, 0, writtenBytesLength);
         this.m_dspState.synthesis_read(samples);
         this.m_pcmOffset += samples;
       }
     }
     if (needToProcessPacket) {
       switch (this.processPacket(true)) {
         case 0:
           {
             return -(bb.position() - pos);
           }
         case -1:
           {
             return -(bb.position() - pos);
           }
         default:
           {
             continue;
           }
       }
     }
   }
   return bb.position() - pos;
 }
 public void sendDatagram(long sig, byte[] data, int length, String recipAddress, int recipPort) {
   sendDatagram(sig, ByteBuffer.wrap(data), recipAddress, recipPort);
 }
 public void sendData(long sig, byte[] data) throws IOException {
   sendData(sig, ByteBuffer.wrap(data));
 }