@SuppressWarnings("squid:S1244")
  private static String selectBestEncoding(String acceptEncodingHeader) {
    // multiple encodings are accepted; determine best one

    Collection<String> bestEncodings = new HashSet<>(3);
    double bestQ = 0.0;
    Collection<String> unacceptableEncodings = new HashSet<>(3);
    boolean willAcceptAnything = false;

    for (String token : COMMA.split(acceptEncodingHeader)) {
      ContentEncodingQ contentEncodingQ = parseContentEncodingQ(token);
      String contentEncoding = contentEncodingQ.getContentEncoding();
      double q = contentEncodingQ.getQ();
      if (ANY_ENCODING.equals(contentEncoding)) {
        willAcceptAnything = q > 0.0;
      } else if (SUPPORTED_ENCODINGS.contains(contentEncoding)) {
        if (q > 0.0) {
          // This is a header quality comparison.
          // So it is safe to suppress warning squid:S1244
          if (q == bestQ) {
            bestEncodings.add(contentEncoding);
          } else if (q > bestQ) {
            bestQ = q;
            bestEncodings.clear();
            bestEncodings.add(contentEncoding);
          }
        } else {
          unacceptableEncodings.add(contentEncoding);
        }
      }
    }

    if (bestEncodings.isEmpty()) {
      // nothing was acceptable to us
      if (willAcceptAnything) {
        if (unacceptableEncodings.isEmpty()) {
          return SUPPORTED_ENCODINGS.get(0);
        } else {
          for (String encoding : SUPPORTED_ENCODINGS) {
            if (!unacceptableEncodings.contains(encoding)) {
              return encoding;
            }
          }
        }
      }
    } else {
      for (String encoding : SUPPORTED_ENCODINGS) {
        if (bestEncodings.contains(encoding)) {
          return encoding;
        }
      }
    }

    return NO_ENCODING;
  }
 // XXX: add support for uploading sketches using a programmer
 public boolean uploadUsingPreferences(String buildPath, String className) throws RunnerException {
   String uploadUsing = Preferences.get("boards." + Preferences.get("board") + ".upload.using");
   if (uploadUsing == null) {
     // fall back on global preference
     uploadUsing = Preferences.get("upload.using");
   }
   if (uploadUsing.equals("bootloader")) {
     return uploadViaBootloader(buildPath, className);
   } else {
     Collection params = getProgrammerCommands(uploadUsing);
     params.add("-Uflash:w:" + buildPath + File.separator + className + ".hex:i");
     return avrdude(params);
   }
 }
    protected void loadAirspacesFromPath(String path, Collection<Airspace> airspaces) {
      File file = ExampleUtil.saveResourceToTempFile(path, ".zip");
      if (file == null) return;

      try {
        ZipFile zipFile = new ZipFile(file);

        ZipEntry entry = null;
        for (Enumeration<? extends ZipEntry> e = zipFile.entries();
            e.hasMoreElements();
            entry = e.nextElement()) {
          if (entry == null) continue;

          String name = WWIO.getFilename(entry.getName());

          if (!(name.startsWith("gov.nasa.worldwind.render.airspaces") && name.endsWith(".xml")))
            continue;

          String[] tokens = name.split("-");

          try {
            Class c = Class.forName(tokens[0]);
            Airspace airspace = (Airspace) c.newInstance();
            BufferedReader input =
                new BufferedReader(new InputStreamReader(zipFile.getInputStream(entry)));
            String s = input.readLine();
            airspace.restoreState(s);
            airspaces.add(airspace);

            if (tokens.length >= 2) {
              airspace.setValue(AVKey.DISPLAY_NAME, tokens[1]);
            }
          } catch (Exception ex) {
            ex.printStackTrace();
          }
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  /**
   * 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();
  }
  /**
   * Grabs local events and detects if events was lost since last poll.
   *
   * @param ignite Target grid.
   * @param evtOrderKey Unique key to take last order key from node local map.
   * @param evtThrottleCntrKey Unique key to take throttle count from node local map.
   * @param evtTypes Event types to collect.
   * @param evtMapper Closure to map grid events to Visor data transfer objects.
   * @return Collections of node events
   */
  public static Collection<VisorGridEvent> collectEvents(
      Ignite ignite,
      String evtOrderKey,
      String evtThrottleCntrKey,
      final int[] evtTypes,
      IgniteClosure<Event, VisorGridEvent> evtMapper) {
    assert ignite != null;
    assert evtTypes != null && evtTypes.length > 0;

    ConcurrentMap<String, Long> nl = ignite.cluster().nodeLocalMap();

    final long lastOrder = getOrElse(nl, evtOrderKey, -1L);
    final long throttle = getOrElse(nl, evtThrottleCntrKey, 0L);

    // When we first time arrive onto a node to get its local events,
    // we'll grab only last those events that not older than given period to make sure we are
    // not grabbing GBs of data accidentally.
    final long notOlderThan = System.currentTimeMillis() - EVENTS_COLLECT_TIME_WINDOW;

    // Flag for detecting gaps between events.
    final AtomicBoolean lastFound = new AtomicBoolean(lastOrder < 0);

    IgnitePredicate<Event> p =
        new IgnitePredicate<Event>() {
          /** */
          private static final long serialVersionUID = 0L;

          @Override
          public boolean apply(Event e) {
            // Detects that events were lost.
            if (!lastFound.get() && (lastOrder == e.localOrder())) lastFound.set(true);

            // Retains events by lastOrder, period and type.
            return e.localOrder() > lastOrder
                && e.timestamp() > notOlderThan
                && F.contains(evtTypes, e.type());
          }
        };

    Collection<Event> evts = ignite.events().localQuery(p);

    // Update latest order in node local, if not empty.
    if (!evts.isEmpty()) {
      Event maxEvt = Collections.max(evts, EVTS_ORDER_COMPARATOR);

      nl.put(evtOrderKey, maxEvt.localOrder());
    }

    // Update throttle counter.
    if (!lastFound.get())
      nl.put(evtThrottleCntrKey, throttle == 0 ? EVENTS_LOST_THROTTLE : throttle - 1);

    boolean lost = !lastFound.get() && throttle == 0;

    Collection<VisorGridEvent> res = new ArrayList<>(evts.size() + (lost ? 1 : 0));

    if (lost) res.add(new VisorGridEventsLost(ignite.cluster().localNode().id()));

    for (Event e : evts) {
      VisorGridEvent visorEvt = evtMapper.apply(e);

      if (visorEvt != null) res.add(visorEvt);
    }

    return res;
  }