public synchronized void updateSigns() {
    if (updating || topSigns.isEmpty()) return;
    updating = true;
    final Map<String, StatSign> map;
    synchronized (topSigns) {
      map = new HashMap<String, StatSign>(topSigns);
    }
    Collection<String> badSigns = new HashSet<String>();
    Collection<TrackerInterface> interfaces = Tracker.getAllInterfaces();
    List<StatSign> tops = new ArrayList<StatSign>();

    for (TrackerInterface ti : interfaces) {
      final String tiName = ti.getInterfaceName().toUpperCase();
      for (String loc : map.keySet()) {
        StatSign ss = map.get(loc);
        if (!ss.getDBName().toUpperCase().equals(tiName)) {
          continue;
        }
        Sign s = getSign(loc);
        if (s == null) {
          badSigns.add(loc);
          continue;
        }

        switch (ss.getSignType()) {
          case TOP:
            tops.add(ss);
            break;
          default:
            break;
        }
      }
      doTopSigns(ti, tops);
      tops = new ArrayList<StatSign>();
    }
    synchronized (topSigns) {
      for (String s : badSigns) {
        topSigns.remove(s);
      }
    }
    updating = false;
  }
  private void updateSign(Player player, Sign s, StatSign ss) {
    String[] lines = s.getLines();
    TrackerInterface ti = Tracker.getInterface(ss.getDBName());
    Stat stat = ti.getRecord(player);
    if (stat == null) return;

    lines[0] = "&0Your Stats";
    lines[1] = "&0[&9" + stat.getRating() + "&0]";
    int len = (stat.getWins() + "/" + stat.getLosses()).length();
    lines[2] =
        (len <= 10)
            ? "&2" + stat.getWins() + "&0/&4" + stat.getLosses()
            : stat.getWins() + "/" + stat.getLosses();
    if (lines[2].length() <= 12) lines[2] = "&0W/L " + lines[2];
    lines[3] = "&0Streak: &9" + stat.getStreak() + "";
    for (int i = 0; i < lines.length; i++) {
      lines[i] = MessageController.colorChat(lines[i]);
    }
    SignUtil.sendLines(player, s, lines);
  }
 private void updateSigns(
     final TrackerInterface ti,
     final List<StatSign> update,
     final int max,
     final StatType type,
     final int offset) {
   Bukkit.getScheduler()
       .scheduleAsyncDelayedTask(
           Tracker.getSelf(),
           new Runnable() {
             @Override
             public void run() {
               List<Stat> toplist = ti.getTopX(type, max * 4);
               if (toplist != null && !toplist.isEmpty() && Tracker.getSelf().isEnabled()) {
                 Bukkit.getScheduler()
                     .scheduleSyncDelayedTask(
                         Tracker.getSelf(),
                         new UpdateSigns(ti.getInterfaceName(), update, toplist));
               }
             }
           },
           2L * offset);
 }