text:
package net.runelite.client.plugins.itemcharges;

import com.google.common.primitives.Ints;
import com.google.inject.Provides;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.EnumMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.GameState;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import net.runelite.api.ItemID;
import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.Notifier;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.util.Text;

@PluginDescriptor(
	name = "Item Charges",
	description = "Show number of item charges remaining",
	tags = {"inventory", "notifications", "overlay"}
)
@Slf4j
public class ItemChargePlugin extends Plugin
{
	private static final Pattern DODGY_CHECK_PATTERN = Pattern.compile(
		"Your dodgy necklace has (\\d+) charges? left\\.");
	private static final Pattern DODGY_PROTECT_PATTERN = Pattern.compile(
		"Your dodgy necklace protects you\\..*It has (\\d+) charges? left\\.");
	private static final Pattern DODGY_BREAK_PATTERN = Pattern.compile(
		"Your dodgy necklace protects you\\..*It then crumbles to dust\\.");
	private static final String RING_OF_RECOIL_BREAK_MESSAGE = "Your Ring of Recoil has shattered.";
	private static final Pattern BINDING_CHECK_PATTERN = Pattern.compile(
		"You have ([0-9]+|one) charges? left before your Binding necklace disintegrates\\.");
	private static final Pattern BINDING_USED_PATTERN = Pattern.compile(
		"You (partially succeed to )?bind the temple's power into (mud|lava|steam|dust|smoke|mist) runes\\.");
	private static final String BINDING_BREAK_TEXT = "Your Binding necklace has disintegrated.";
	private static final Pattern RING_OF_FORGING_CHECK_PATTERN = Pattern.compile(
		"You can smelt ([0-9]+|one) more pieces? of iron ore before a ring melts\\.");
	private static final String RING_OF_FORGING_USED_TEXT = "You retrieve a bar of iron.";
	private static final String RING_OF_FORGING_BREAK_TEXT = "Your Ring of Forging has melted.";
	private static final String RING_OF_FORGING_VARROCK_PLATEBODY = "The Varrock platebody enabled you to smelt your next ore simultaneously.";
	private static final Pattern AMULET_OF_CHEMISTRY_CHECK_PATTERN = Pattern.compile(
		"Your amulet of chemistry has (\\d) charges? left\\."
	);
	private static final Pattern AMULET_OF_CHEMISTRY_USED_PATTERN = Pattern.compile(
		"Your amulet of chemistry helps you create a \\d-dose potion\\. It has (\\d|one) charges? left\\."
	);
	private static final Pattern AMULET_OF_CHEMISTRY_BREAK_PATTERN = Pattern.compile(
		"Your amulet of chemistry helps you create a \\d-dose potion\\. It then crumbles to dust\\."
	);
	private static final Pattern AMULET_OF_BOUNTY_CHECK_PATTERN = Pattern.compile(
		"Your amulet of bounty has (\\d+) charges? left\\."
	);
	private static final Pattern AMULET_OF_BOUNTY_USED_PATTERN = Pattern.compile(
		"Your amulet of bounty saves some seeds for you\\. It has (\\d) charges? left\\."
	);
	private static final String AMULET_OF_BOUNTY_BREAK_TEXT = "Your amulet of bounty saves some seeds for you. It then crumbles to dust.";
	private static final Pattern CHRONICLE_ADD_PATTERN = Pattern.compile(
		"You add (?:\\d+|a single) charges? to your book\\. It now has (\\d+|one) charges?\\."
	);
	private static final Pattern CHRONICLE_USE_AND_CHECK_PATTERN = Pattern.compile(
		"Your book has (\\d+) charges left\\."
	);
	private static final String CHRONICLE_FULL_TEXT = "Your book is fully charged! It has 1,000 charges already.";
	private static final String CHRONICLE_ONE_CHARGE_TEXT = "You have one charge left in your book.";
	private static final String CHRONICLE_EMPTY_TEXT = "Your book has run out of charges.";
	private static final String CHRONICLE_NO_CHARGES_TEXT = "Your book does not have any charges. Purchase some Teleport Cards from Diango.";
	private static final Pattern BRACELET_OF_SLAUGHTER_ACTIVATE_PATTERN = Pattern.compile(
		"Your bracelet of slaughter prevents your slayer count from decreasing. (?:(?:It has (\\d{1,2}) charges? left)|(It then crumbles to dust))\\."
	);
	private static final Pattern BRACELET_OF_SLAUGHTER_CHECK_PATTERN = Pattern.compile(
		"Your bracelet of slaughter has (\\d{1,2}) charges? left\\."
	);
	private static final String BRACELET_OF_SLAUGHTER_BREAK_TEXT = "Your Bracelet of Slaughter has crumbled to dust.";
	private static final Pattern EXPEDITIOUS_BRACELET_ACTIVATE_PATTERN = Pattern.compile(
		"Your expeditious bracelet helps you progress your slayer (?:task )?faster. (?:(?:It has (\\d{1,2}) charges? left)|(It then crumbles to dust))\\."
	);
	private static final Pattern EXPEDITIOUS_BRACELET_CHECK_PATTERN = Pattern.compile(
		"Your expeditious bracelet has (\\d{1,2}) charges? left\\."
	);
	private static final String EXPEDITIOUS_BRACELET_BREAK_TEXT = "Your Expeditious Bracelet has crumbled to dust.";
	private static final Pattern BLOOD_ESSENCE_CHECK_PATTERN = Pattern.compile(
		"Your blood essence has (\\d{1,4}) charges? remaining"
	);
	private static final Pattern BLOOD_ESSENCE_EXTRACT_PATTERN = Pattern.compile(
		"You manage to extract power from the Blood Essence and craft (\\d{1,3}) extra runes?\\."
	);
	private static final String BLOOD_ESSENCE_ACTIVATE_TEXT = "You activate the blood essence.";
	private static final String BRACELET_OF_CLAY_USE_TEXT = "You manage to mine some clay.";
	private static final String BRACELET_OF_CLAY_USE_TEXT_TRAHAEARN = "You manage to mine some soft clay.";
	private static final String BRACELET_OF_CLAY_BREAK_TEXT = "Your bracelet of clay crumbles to dust.";
	private static final Pattern BRACELET_OF_CLAY_CHECK_PATTERN = Pattern.compile(
		"You can mine (\\d{1,2}) more pieces? of soft clay before your bracelet crumbles to dust\\."
	);

	private static final int MAX_DODGY_CHARGES = 10;
	private static final int MAX_BINDING_CHARGES = 16;
	private static final int MAX_EXPLORER_RING_CHARGES = 30;
	private static final int MAX_RING_OF_FORGING_CHARGES = 140;
	private static final int MAX_AMULET_OF_CHEMISTRY_CHARGES = 5;
	private static final int MAX_AMULET_OF_BOUNTY_CHARGES = 10;
	private static final int MAX_SLAYER_BRACELET_CHARGES = 30;
	private static final int MAX_BLOOD_ESSENCE_CHARGES = 1000;
	private static final int MAX_BRACELET_OF_CLAY_CHARGES = 28;

	@Inject
	private Client client;

	@Inject
	private ClientThread clientThread;

	@Inject
	private ConfigManager configManager;

	@Inject
	private OverlayManager overlayManager;

	@Inject
	private ItemChargeOverlay overlay;

	@Inject
	private ItemManager itemManager;

	@Inject
	private InfoBoxManager infoBoxManager;

	@Inject
	private Notifier notifier;

	@Inject
	private ItemChargeConfig config;

	// Limits destroy callback to once per tick
	private int lastCheckTick;
	private final Map<EquipmentInventorySlot, ItemChargeInfobox> infoboxes = new EnumMap<>(EquipmentInventorySlot.class);

	@Provides
	ItemChargeConfig getConfig(ConfigManager configManager)
	{
		return configManager.getConfig(ItemChargeConfig.class);
	}

	@Override
	protected void startUp()
	{
		overlayManager.add(overlay);
	}

	@Override
	protected void shutDown() throws Exception
	{
		overlayManager.remove(overlay);
		infoBoxManager.removeIf(ItemChargeInfobox.class::isInstance);
		infoboxes.clear();
		lastCheckTick = -1;
	}

	@Subscribe
	public void onGameStateChanged(GameStateChanged e)
	{
		// No VarbitChanged event fires on login if the explorer's ring is full (varbit value 0).
		// So, set the value to 0 when LOGGING_IN. This is before the VarbitChanged event would fire, so if it shouldn't
		// be 0 it will be updated later.
		if (e.getGameState() == GameState.LOGGING_IN)
		{
			updateExplorerRingCharges(0);
		}
	}

	@Subscribe
	public void onConfigChanged(ConfigChanged event)
	{
		if (!event.getGroup().equals(ItemChargeConfig.GROUP))
		{
			return;
		}

		clientThread.invoke(this::updateInfoboxes);
	}

	@Subscribe
	public void onChatMessage(ChatMessage event)
	{
		if (event.getType() == ChatMessageType.GAMEMESSAGE || event.getType() == ChatMessageType.SPAM)
		{
			String message = Text.removeTags(event.getMessage());
			Matcher dodgyCheckMatcher = DODGY_CHECK_PATTERN.matcher(message);
			Matcher dodgyProtectMatcher = DODGY_PROTECT_PATTERN.matcher(message);
			Matcher dodgyBreakMatcher = DODGY_BREAK_PATTERN.matcher(message);
			Matcher bindingNecklaceCheckMatcher = BINDING_CHECK_PATTERN.matcher(message);
			Matcher bindingNecklaceUsedMatcher = BINDING_USED_PATTERN.matcher(message);
			Matcher ringOfForgingCheckMatcher = RING_OF_FORGING_CHECK_PATTERN.matcher(message);
			Matcher amuletOfChemistryCheckMatcher = AMULET_OF_CHEMISTRY_CHECK_PATTERN.matcher(message);
			Matcher amuletOfChemistryUsedMatcher = AMULET_OF_CHEMISTRY_USED_PATTERN.matcher(message);
			Matcher amuletOfChemistryBreakMatcher = AMULET_OF_CHEMISTRY_BREAK_PATTERN.matcher(message);
			Matcher amuletOfBountyCheckMatcher = AMULET_OF_BOUNTY_CHECK_PATTERN.matcher(message);
			Matcher amuletOfBountyUsedMatcher = AMULET_OF_BOUNTY_USED_PATTERN.matcher(message);
			Matcher chronicleAddMatcher = CHRONICLE_ADD_PATTERN.matcher(message);
			Matcher chronicleUseAndCheckMatcher = CHRONICLE_USE_AND_CHECK_PATTERN.matcher(message);
			Matcher slaughterActivateMatcher = BRACELET_OF_SLAUGHTER_ACTIVATE_PATTERN.matcher(message);
			Matcher slaughterCheckMatcher = BRACELET_OF_SLAUGHTER_CHECK_PATTERN.matcher(message);
			Matcher expeditiousActivateMatcher = EXPEDITIOUS_BRACELET_ACTIVATE_PATTERN.matcher(message);
			Matcher expeditiousCheckMatcher = EXPEDITIOUS_BRACELET_CHECK_PATTERN.matcher(message);
			Matcher bloodEssenceCheckMatcher = BLOOD_ESSENCE_CHECK_PATTERN.matcher(message);
			Matcher bloodEssenceExtractMatcher = BLOOD_ESSENCE_EXTRACT_PATTERN.matcher(message);
			Matcher braceletOfClayCheckMatcher = BRACELET_OF_CLAY_CHECK_PATTERN.matcher(message);

			if (config.recoilNotification() && message.contains(RING_OF_RECOIL_BREAK_MESSAGE))
			{
				notifier.notify("Your Ring of Recoil has shattered");
			}
			else if (dodgyBreakMatcher.find())
			{
				if (config.dodgyNotification())
				{
					notifier.notify("Your dodgy necklace has crumbled to dust.");
				}

				updateDodgyNecklaceCharges(MAX_DODGY_CHARGES);
			}
			else if (dodgyCheckMatcher.find())
			{
				updateDodgyNecklaceCharges(Integer.parseInt(dodgyCheckMatcher.group(1)));
			}
			else if (dodgyProtectMatcher.find())
			{
				updateDodgyNecklaceCharges(Integer.parseInt(dodgyProtectMatcher.group(1)));
			}
			else if (amuletOfChemistryCheckMatcher.find())
			{
				updateAmuletOfChemistryCharges(Integer.parseInt(amuletOfChemistryCheckMatcher.group(1)));
			}
			else if (amuletOfChemistryUsedMatcher.find())
			{
				final String match = amuletOfChemistryUsedMatcher.group(1);

				int charges = 1;
				if (!match.equals("one"))
				{
					charges = Integer.parseInt(match);
				}

				updateAmuletOfChemistryCharges(charges);
			}
			else if (amuletOfChemistryBreakMatcher.find())
			{
				updateAmuletOfChemistryCharges(MAX_AMULET_OF_CHEMISTRY_CHARGES);
			}
			else if (amuletOfBountyCheckMatcher.find())
			{
				updateAmuletOfBountyCharges(Integer.parseInt(amuletOfBountyCheckMatcher.group(1)));
			}
			else if (amuletOfBountyUsedMatcher.find())
			{
				updateAmuletOfBountyCharges(Integer.parseInt(amuletOfBountyUsedMatcher.group(1)));
			}
			else if (message.equals(AMULET_OF_BOUNTY_BREAK_TEXT))
			{
				updateAmuletOfBountyCharges(MAX_AMULET_OF_BOUNTY_CHARGES);
			}
			else if (message.contains(BINDING_BREAK_TEXT))
			{
				if (config.bindingNotification())
				{
					notifier.notify(BINDING_BREAK_TEXT);
				}

				// This chat message triggers before the used message so add 1 to the max charges to ensure proper sync
				updateBindingNecklaceCharges(MAX_BINDING_CHARGES + 1);
			}
			else if (bindingNecklaceUsedMatcher.find())
			{
				final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);
				if (equipment.contains(ItemID.BINDING_NECKLACE))
				{
					updateBindingNecklaceCharges(getItemCharges(ItemChargeConfig.KEY_BINDING_NECKLACE) - 1);
				}
			}
			else if (bindingNecklaceCheckMatcher.find())
			{
				final String match = bindingNecklaceCheckMatcher.group(1);

				int charges = 1;
				if (!match.equals("one"))
				{
					charges = Integer.parseInt(match);
				}

				updateBindingNecklaceCharges(charges);
			}
			else if (ringOfForgingCheckMatcher.find())
			{
				final String match = ringOfForgingCheckMatcher.group(1);

				int charges = 1;
				if (!match.equals("one"))
				{
					charges = Integer.parseInt(match);
				}
				updateRingOfForgingCharges(charges);
			}
			else if (message.equals(RING_OF_FORGING_USED_TEXT) || message.equals(RING_OF_FORGING_VARROCK_PLATEBODY))
			{
				final ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY);
				final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);

				// Determine if the player smelted with a Ring of Forging equipped.
				if (equipment == null)
				{
					return;
				}

				if (equipment.contains(ItemID.RING_OF_FORGING) && (message.equals(RING_OF_FORGING_USED_TEXT) || inventory.count(ItemID.IRON_ORE) > 1))
				{
					int charges = Ints.constrainToRange(getItemCharges(ItemChargeConfig.KEY_RING_OF_FORGING) - 1, 0, MAX_RING_OF_FORGING_CHARGES);
					updateRingOfForgingCharges(charges);
				}
			}
			else if (message.equals(RING_OF_FORGING_BREAK_TEXT))
			{
				if (config.ringOfForgingNotification())
				{
					notifier.notify("Your ring of forging has melted.");
				}

				updateRingOfForgingCharges(MAX_RING_OF_FORGING_CHARGES);
			}
			else if (chronicleAddMatcher.find())
			{
				final String match = chronicleAddMatcher.group(1);

				if (match.equals("one"))
				{
					setItemCharges(ItemChargeConfig.KEY_CHRONICLE, 1);
				}
				else
				{
					setItemCharges(ItemChargeConfig.KEY_CHRONICLE, Integer.parseInt(match));
				}
			}
			else if (chronicleUseAndCheckMatcher.find())
			{
				setItemCharges(ItemChargeConfig.KEY_CHRONICLE, Integer.parseInt(chronicleUseAndCheckMatcher.group(1)));
			}
			else if (message.equals(CHRONICLE_ONE_CHARGE_TEXT))
			{
				setItemCharges(ItemChargeConfig.KEY_CHRONICLE, 1);
			}
			else if (message.equals(CHRONICLE_EMPTY_TEXT) || message.equals(CHRONICLE_NO_CHARGES_TEXT))
			{
				setItemCharges(ItemChargeConfig.KEY_CHRONICLE, 0);
			}
			else if (message.equals(CHRONICLE_FULL_TEXT))
			{
				setItemCharges(ItemChargeConfig.KEY_CHRONICLE, 1000);
			}
			else if (slaughterActivateMatcher.find())
			{
				final String found = slaughterActivateMatcher.group(1);
				if (found == null)
				{
					updateBraceletOfSlaughterCharges(MAX_SLAYER_BRACELET_CHARGES);
					if (config.slaughterNotification())
					{
						notifier.notify(BRACELET_OF_SLAUGHTER_BREAK_TEXT);
					}
				}
				else
				{
					updateBraceletOfSlaughterCharges(Integer.parseInt(found));
				}
			}
			else if (slaughterCheckMatcher.find())
			{
				updateBraceletOfSlaughterCharges(Integer.parseInt(slaughterCheckMatcher.group(1)));
			}
			else if (expeditiousActivateMatcher.find())
			{
				final String found = expeditiousActivateMatcher.group(1);
				if (found == null)
				{
					updateExpeditiousBraceletCharges(MAX_SLAYER_BRACELET_CHARGES);
					if (config.expeditiousNotification())
					{
						notifier.notify(EXPEDITIOUS_BRACELET_BREAK_TEXT);
					}
				}
				else
				{
					updateExpeditiousBraceletCharges(Integer.parseInt(found));
				}
			}
			else if (expeditiousCheckMatcher.find())
			{
				updateExpeditiousBraceletCharges(Integer.parseInt(expeditiousCheckMatcher.group(1)));
			}
			else if (bloodEssenceCheckMatcher.find())
			{
				updateBloodEssenceCharges(Integer.parseInt(bloodEssenceCheckMatcher.group(1)));
			}
			else if (bloodEssenceExtractMatcher.find())
			{
				updateBloodEssenceCharges(getItemCharges(ItemChargeConfig.KEY_BLOOD_ESSENCE) - Integer.parseInt(bloodEssenceExtractMatcher.group(1)));
			}
			else if (message.contains(BLOOD_ESSENCE_ACTIVATE_TEXT))
			{
				updateBloodEssenceCharges(MAX_BLOOD_ESSENCE_CHARGES);
			}
			else if (braceletOfClayCheckMatcher.find())
			{
				updateBraceletOfClayCharges(Integer.parseInt(braceletOfClayCheckMatcher.group(1)));
			}
			else if (message.equals(BRACELET_OF_CLAY_USE_TEXT) || message.equals(BRACELET_OF_CLAY_USE_TEXT_TRAHAEARN))
			{
				final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);

				// Determine if the player mined with a Bracelet of Clay equipped.
				if (equipment != null && equipment.contains(ItemID.BRACELET_OF_CLAY))
				{
					int charges = Ints.constrainToRange(getItemCharges(ItemChargeConfig.KEY_BRACELET_OF_CLAY) - 1, 0, MAX_BRACELET_OF_CLAY_CHARGES);
					updateBraceletOfClayCharges(charges);
				}
			}
			else if (message.equals(BRACELET_OF_CLAY_BREAK_TEXT))
			{
				if (config.braceletOfClayNotification())
				{
					notifier.notify("Your bracelet of clay has crumbled to dust");
				}
				updateBraceletOfClayCharges(MAX_BRACELET_OF_CLAY_CHARGES);
			}
		}
	}

	@Subscribe
	public void onItemContainerChanged(ItemContainerChanged event)
	{
		if (event.getContainerId() != InventoryID.EQUIPMENT.getId())
		{
			return;
		}

		updateInfoboxes();
	}

	@Subscribe
	private void onScriptCallbackEvent(ScriptCallbackEvent event)
	{
		if (!"destroyOnOpKey".equals(event.getEventName()))
		{
			return;
		}

		final int yesOption = client.getIntStack()[client.getIntStackSize() - 1];
		if (yesOption == 1)
		{
			checkDestroyWidget();
		}
	}

	@Subscribe
	private void onVarbitChanged(VarbitChanged event)
	{
		if (event.getVarbitId() == Varbits.EXPLORER_RING_ALCHS)
		{
			updateExplorerRingCharges(event.getValue());
		}
	}

	@Subscribe
	public void onWidgetLoaded(WidgetLoaded widgetLoaded)
	{
		if (widgetLoaded.getGroupId() == WidgetID.DIALOG_SPRITE_GROUP_ID)
		{
			clientThread.invokeLater(() ->
			{
				Widget sprite = client.getWidget(WidgetInfo.DIALOG_SPRITE_SPRITE);
				if (sprite != null)
				{
					switch (sprite.getItemId())
					{
						case ItemID.DODGY_NECKLACE:
							log.debug("Reset dodgy necklace");
							updateDodgyNecklaceCharges(MAX_DODGY_CHARGES);
							break;
						case ItemID.RING_OF_FORGING:
							log.debug("Reset ring of forging");
							updateRingOfForgingCharges(MAX_RING_OF_FORGING_CHARGES);
							break;
						case ItemID.AMULET_OF_CHEMISTRY:
							log.debug("Reset amulet of chemistry");
							updateAmuletOfChemistryCharges(MAX_AMULET_OF_CHEMISTRY_CHARGES);
							break;
						case ItemID.BRACELET_OF_SLAUGHTER:
							log.debug("Reset bracelet of slaughter");
							updateBraceletOfSlaughterCharges(MAX_SLAYER_BRACELET_CHARGES);
							break;
						case ItemID.EXPEDITIOUS_BRACELET:
							log.debug("Reset expeditious bracelet");
							updateExpeditiousBraceletCharges(MAX_SLAYER_BRACELET_CHARGES);
							break;
					}
				}
			});
		}
	}

	private void updateDodgyNecklaceCharges(final int value)
	{
		setItemCharges(ItemChargeConfig.KEY_DODGY_NECKLACE, value);
		updateInfoboxes();
	}

	private void updateAmuletOfChemistryCharges(final int value)
	{
		setItemCharges(ItemChargeConfig.KEY_AMULET_OF_CHEMISTRY, value);
		updateInfoboxes();
	}

	private void updateAmuletOfBountyCharges(final int value)
	{
		setItemCharges(ItemChargeConfig.KEY_AMULET_OF_BOUNTY, value);
		updateInfoboxes();
	}

	private void updateBindingNecklaceCharges(final int value)
	{
		setItemCharges(ItemChargeConfig.KEY_BINDING_NECKLACE, value);
		updateInfoboxes();
	}

	private void updateExplorerRingCharges(final int value)
	{
		// Note: Varbit counts upwards. We count down from the maximum charges.
		setItemCharges(ItemChargeConfig.KEY_EXPLORERS_RING, MAX_EXPLORER_RING_CHARGES - value);
		updateInfoboxes();
	}

	private void updateRingOfForgingCharges(final int value)
	{
		setItemCharges(ItemChargeConfig.KEY_RING_OF_FORGING, value);
		updateInfoboxes();
	}

	private void updateBraceletOfSlaughterCharges(final int value)
	{
		setItemCharges(ItemChargeConfig.KEY_BRACELET_OF_SLAUGHTER, value);
		updateInfoboxes();
	}

	private void updateExpeditiousBraceletCharges(final int value)
	{
		setItemCharges(ItemChargeConfig.KEY_EXPEDITIOUS_BRACELET, value);
		updateInfoboxes();
	}

	private void updateBloodEssenceCharges(final int value)
	{
		setItemCharges(ItemChargeConfig.KEY_BLOOD_ESSENCE, value);
		updateInfoboxes();
	}

	private void updateBraceletOfClayCharges(final int value)
	{
		setItemCharges(ItemChargeConfig.KEY_BRACELET_OF_CLAY, value);
		updateInfoboxes();
	}

	private void checkDestroyWidget()
	{
		final int currentTick = client.getTickCount();
		if (lastCheckTick == currentTick)
		{
			return;
		}
		lastCheckTick = currentTick;

		final Widget widgetDestroyItemName = client.getWidget(WidgetInfo.DESTROY_ITEM_NAME);
		if (widgetDestroyItemName == null)
		{
			return;
		}

		if (widgetDestroyItemName.getText().equals("Binding necklace"))
		{
			log.debug("Reset binding necklace");
			updateBindingNecklaceCharges(MAX_BINDING_CHARGES);
		}
	}

	private void updateInfoboxes()
	{
		final ItemContainer itemContainer = client.getItemContainer(InventoryID.EQUIPMENT);

		if (itemContainer == null)
		{
			return;
		}

		final Item[] items = itemContainer.getItems();
		boolean showInfoboxes = config.showInfoboxes();
		for (EquipmentInventorySlot slot : EquipmentInventorySlot.values())
		{
			if (slot.getSlotIdx() >= items.length)
			{
				break;
			}

			Item i = items[slot.getSlotIdx()];
			int id = i.getId();
			ItemChargeType type = null;
			int charges = -1;

			final ItemWithCharge itemWithCharge = ItemWithCharge.findItem(id);
			if (itemWithCharge != null)
			{
				type = itemWithCharge.getType();
				charges = itemWithCharge.getCharges();
			}
			else
			{
				final ItemWithConfig itemWithConfig = ItemWithConfig.findItem(id);
				if (itemWithConfig != null)
				{
					type = itemWithConfig.getType();
					charges = getItemCharges(itemWithConfig.getConfigKey());
				}
			}

			boolean enabled = type != null && type.getEnabled().test(config);

			if (showInfoboxes && enabled && charges > 0)
			{
				ItemChargeInfobox infobox = infoboxes.get(slot);
				if (infobox != null)
				{
					if (infobox.getItem() == id)
					{
						if (infobox.getCount() == charges)
						{
							continue;
						}

						log.debug("Updating infobox count for {}", infobox);
						infobox.setCount(charges);
						continue;
					}

					log.debug("Rebuilding infobox {}", infobox);
					infoBoxManager.removeInfoBox(infobox);
					infoboxes.remove(slot);
				}

				final String name = itemManager.getItemComposition(id).getName();
				final BufferedImage image = itemManager.getImage(id);
				infobox = new ItemChargeInfobox(this, image, name, charges, id);
				infoBoxManager.addInfoBox(infobox);
				infoboxes.put(slot, infobox);
			}
			else
			{
				ItemChargeInfobox infobox = infoboxes.remove(slot);
				if (infobox != null)
				{
					log.debug("Removing infobox {}", infobox);
					infoBoxManager.removeInfoBox(infobox);
				}
			}
		}
	}

	int getItemCharges(String key)
	{
		// Migrate old non-profile configurations
		Integer i = configManager.getConfiguration(ItemChargeConfig.GROUP, key, Integer.class);
		if (i != null)
		{
			configManager.unsetConfiguration(ItemChargeConfig.GROUP, key);
			configManager.setRSProfileConfiguration(ItemChargeConfig.GROUP, key, i);
			return i;
		}

		i = configManager.getRSProfileConfiguration(ItemChargeConfig.GROUP, key, Integer.class);
		return i == null ? -1 : i;
	}

	private void setItemCharges(String key, int value)
	{
		configManager.setRSProfileConfiguration(ItemChargeConfig.GROUP, key, value);
	}

	Color getColor(int charges)
	{
		Color color = Color.WHITE;
		if (charges <= config.veryLowWarning())
		{
			color = config.veryLowWarningColor();
		}
		else if (charges <= config.lowWarning())
		{
			color = config.lowWarningolor();
		}
		return color;
	}
}


text:
package colossus
package testkit

import scala.concurrent.Await
import akka.util.ByteString

import protocols.http._

import net.liftweb.json._

abstract class HttpServiceSpec extends ServiceSpec[Http] {

  implicit val formats = DefaultFormats

  def expectCode(request: HttpRequest, expectedResponseCode: HttpCode) {
    withClient{client =>
      val resp = Await.result(client.send(request), requestTimeout)
      assertCode(request, resp, expectedResponseCode)
    }
  }

  def expectCodeAndBody(request: HttpRequest, expectedResponseCode: HttpCode, body : String) {
    withClient{client =>
      val resp = Await.result(client.send(request), requestTimeout)
      assertCode(request, resp, expectedResponseCode)
      assertBody(request, resp, body)
    }
  }

  def assertCode(request : HttpRequest, response : HttpResponse, expectedCode : HttpCode) {
    val msg = request.head.method +
      " " + request.head.url + ": Code " +
      response.head.code + " did not match " +
      expectedCode + ". Body: "  +
      response.body.map{_.utf8String}.getOrElse("(none)")
    assert(response.head.code == expectedCode, msg)
  }

  def assertBody(request : HttpRequest, response : HttpResponse, expectedBody : String){
    response.body match {
      case None => throw new Exception(s"No body detected, expected $expectedBody")
      case Some(x) => assert(x.utf8String == expectedBody, s"${x.utf8String} did not equal $expectedBody")
    }
  }

  def get(url: String) = HttpRequest(HttpHead(version = HttpVersion.`1.1`, method = HttpMethod.Get, url = url, headers = Nil), None)

  def testGetCode(url : String, expectedCode : HttpCode) {
    val req = get(url)
    expectCode(req, expectedCode)
  }

  def testGet(url: String, expectedBody: String) {
    val req = get(url)
    val expected = HttpResponse(
      HttpResponseHead(HttpVersion.`1.1`, HttpCodes.OK, Vector(HttpResponseHeader("content-length" ,expectedBody.length.toString))),
      Some(ByteString(expectedBody))
    )

    expectResponse(req, expected)
  }

  def withGet(url: String, tester: HttpResponse => Any) {
    val request = get(url)
    withClient{ client =>
      val resp = Await.result(client.send(request), requestTimeout)
      tester(resp)
    }
  }

  def testPost(url: String, data: String, expectedCode: HttpCode) {
    val req = HttpRequest(HttpHead(version = HttpVersion.`1.1`, method = HttpMethod.Post, url = url, headers = List(("content-length" ->data.length.toString))), Some(ByteString(data)))
    expectCode(req, expectedCode)
  }

  def testPost(url: String, data: String, expectedCode: HttpCode, expectedBody : String) {
    val req = HttpRequest(HttpHead(version = HttpVersion.`1.1`, method = HttpMethod.Post, url = url, headers = List(("content-length" ->data.length.toString))), Some(ByteString(data)))
    expectCode(req, expectedCode)
  }

  def testDelete(url: String, expectedCode: HttpCode) {
    val req = HttpRequest(HttpHead(version = HttpVersion.`1.1`, method = HttpMethod.Delete, url = url, headers = List()), None)
    expectCode(req, expectedCode)
  }

  def testGetJson[T : Manifest](url : String, expectedResponse : T) {
    val req = get(url)
    expectJson(req, expectedResponse)
  }

  def expectJson[T : Manifest](request : HttpRequest, expectedJson : T) {
    withClient{ client =>
      val resp = Await.result(client.send(request), requestTimeout)
      val parsed = parse(resp.body.get.utf8String).extract[T]
      parsed must equal(expectedJson)
    }
  }

}

redpajama_set_name: RedPajamaGithub


text:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Buffers;
using System.Buffers.Reader;

namespace System.Text.JsonLab
{
    public ref struct Utf8JsonReader
    {
        // We are using a ulong to represent our nested state, so we can only go 64 levels deep.
        internal const int MaxDepth = sizeof(ulong) * 8;

        private ReadOnlySpan<byte> _buffer;

        public int Index { get; private set; }

        public int StartLocation { get; private set; }

        private BufferReader<byte> _reader;

        // Depth tracks the recursive depth of the nested objects / arrays within the JSON data.
        public int Depth { get; private set; }

        // This mask represents a tiny stack to track the state during nested transitions.
        // The first bit represents the state of the current level (1 == object, 0 == array).
        // Each subsequent bit is the parent / containing type (object or array). Since this
        // reader does a linear scan, we only need to keep a single path as we go through the data.
        private ulong _containerMask;

        // These properties are helpers for determining the current state of the reader
        internal bool InArray => !InObject;
        internal bool InObject => (_containerMask & 1) != 0;

        /// <summary>
        /// Gets the token type of the last processed token in the JSON stream.
        /// </summary>
        public JsonTokenType TokenType { get; private set; }

        /// <summary>
        /// Gets the value as a ReadOnlySpan<byte> of the last processed token. The contents of this
        /// is only relevant when <see cref="TokenType" /> is <see cref="JsonTokenType.Value" /> or
        /// <see cref="JsonTokenType.PropertyName" />. Otherwise, this value should be set to
        /// <see cref="ReadOnlySpan{T}.Empty"/>.
        /// </summary>
        public ReadOnlySpan<byte> Value { get; private set; }

        /// <summary>
        /// Gets the JSON value type of the last processed token. The contents of this
        /// is only relevant when <see cref="TokenType" /> is <see cref="JsonTokenType.Value" /> or
        /// <see cref="JsonTokenType.PropertyName" />.
        /// </summary>
        public JsonValueType ValueType { get; private set; }

        private readonly bool _isSingleSegment;

        /// <summary>
        /// Constructs a new JsonReader instance. This is a stack-only type.
        /// </summary>
        /// <param name="data">The <see cref="Span{byte}"/> value to consume. </param>
        /// <param name="encoder">An encoder used for decoding bytes from <paramref name="data"/> into characters.</param>
        public Utf8JsonReader(ReadOnlySpan<byte> data)
        {
            _reader = default;
            _isSingleSegment = true;
            _buffer = data;
            Depth = 0;
            _containerMask = 0;
            Index = 0;
            StartLocation = Index;

            TokenType = JsonTokenType.None;
            Value = ReadOnlySpan<byte>.Empty;
            ValueType = JsonValueType.Unknown;
        }

        public Utf8JsonReader(in ReadOnlySequence<byte> data)
        {
            _reader = new BufferReader<byte>(data);
            _isSingleSegment = data.IsSingleSegment; //true;
            _buffer = _reader.CurrentSpan;  //data.ToArray();
            Depth = 0;
            _containerMask = 0;
            Index = 0;
            StartLocation = Index;

            TokenType = JsonTokenType.None;
            Value = ReadOnlySpan<byte>.Empty;
            ValueType = JsonValueType.Unknown;
        }

        /// <summary>
        /// Read the next token from the data buffer.
        /// </summary>
        /// <returns>True if the token was read successfully, else false.</returns>
        public bool Read()
        {
            return _isSingleSegment ? ReadSingleSegment(ref _buffer) : ReadMultiSegment(ref _reader);
        }

        private void SkipWhiteSpace(ref BufferReader<byte> reader)
        {
            Index += reader.SkipPastAny(JsonConstants.Space, JsonConstants.CarriageReturn, JsonConstants.LineFeed, JsonConstants.Tab);
        }

        private bool ReadFirstToken(ref BufferReader<byte> reader, byte first)
        {
            if (first == JsonConstants.OpenBrace)
            {
                Depth++;
                _containerMask = 1;
                TokenType = JsonTokenType.StartObject;
                reader.Advance(1);
                Index++;
            }
            else if (first == JsonConstants.OpenBracket)
            {
                Depth++;
                TokenType = JsonTokenType.StartArray;
                reader.Advance(1);
                Index++;
            }
            else
            {
                ConsumeSingleValue(ref reader, first);
            }
            return true;
        }

        private bool ReadMultiSegment(ref BufferReader<byte> reader)
        {
            bool retVal = false;

            if (!reader.TryPeek(out byte first))
                goto Done;

            if (first <= JsonConstants.Space)
            {
                SkipWhiteSpace(ref reader);
                if (!reader.TryPeek(out first))
                    goto Done;
            }

            StartLocation = Index;

            if (TokenType == JsonTokenType.None)
                goto ReadFirstToken;

            if (TokenType == JsonTokenType.StartObject)
            {
                reader.Advance(1);
                Index++;
                if (first == JsonConstants.CloseBrace)
                    EndObject();
                else
                {
                    if (first != JsonConstants.Quote) JsonThrowHelper.ThrowJsonReaderException();
                    StartLocation++;
                    ConsumePropertyNameUtf8MultiSegment(ref reader);
                }
            }
            else if (TokenType == JsonTokenType.StartArray)
            {
                if (first == JsonConstants.CloseBracket)
                {
                    reader.Advance(1);
                    Index++;
                    EndArray();
                }
                else
                    ConsumeValueUtf8MultiSegment(ref reader, first);
            }
            else if (TokenType == JsonTokenType.PropertyName)
            {
                ConsumeValueUtf8MultiSegment(ref reader, first);
            }
            else
            {
                ConsumeNextUtf8MultiSegment(ref reader, first);
            }

            retVal = true;

        Done:
            return retVal;

        ReadFirstToken:
            retVal = ReadFirstToken(ref reader, first);
            goto Done;
        }

        private bool ReadFirstToken(ref ReadOnlySpan<byte> buffer, byte first)
        {
            if (first == JsonConstants.OpenBrace)
            {
                Depth++;
                _containerMask = 1;
                TokenType = JsonTokenType.StartObject;
                buffer = buffer.Slice(1);
                Index++;
            }
            else if (first == JsonConstants.OpenBracket)
            {
                Depth++;
                TokenType = JsonTokenType.StartArray;
                buffer = buffer.Slice(1);
                Index++;
            }
            else
            {
                ConsumeSingleValue(ref buffer, first);
            }
            return true;
        }

        internal bool NoMoreData => (0 >= (uint)_buffer.Length);

        private bool ReadSingleSegment(ref ReadOnlySpan<byte> buffer)
        {
            bool retVal = false;

            if (0 >= (uint)buffer.Length)
                goto Done;

            byte first = buffer[0];

            if (first <= JsonConstants.Space)
            {
                SkipWhiteSpaceUtf8(ref buffer);
                if (0 >= (uint)buffer.Length)
                    goto Done;
                first = buffer[0];
            }

            StartLocation = Index;

            if (TokenType == JsonTokenType.None)
            {
                goto ReadFirstToken;
            }

            if (TokenType == JsonTokenType.StartObject)
            {
                buffer = buffer.Slice(1);
                Index++;
                if (first == JsonConstants.CloseBrace)
                    EndObject();
                else
                {
                    if (first != JsonConstants.Quote) JsonThrowHelper.ThrowJsonReaderException();
                    StartLocation++;
                    ConsumePropertyNameUtf8(ref buffer);
                }
            }
            else if (TokenType == JsonTokenType.StartArray)
            {
                if (first == JsonConstants.CloseBracket)
                {
                    buffer = buffer.Slice(1);
                    Index++;
                    EndArray();
                }
                else
                    ConsumeValueUtf8(ref buffer, first);
            }
            else if (TokenType == JsonTokenType.PropertyName)
            {
                ConsumeValueUtf8(ref buffer, first);
            }
            else
            {
                ConsumeNextUtf8(ref buffer, first);
            }

            retVal = true;

        Done:
            return retVal;

        ReadFirstToken:
            retVal = ReadFirstToken(ref buffer, first);
            goto Done;
        }

        public void Skip()
        {
            if (TokenType == JsonTokenType.PropertyName)
            {
                Read();
            }

            if (TokenType == JsonTokenType.StartObject || TokenType == JsonTokenType.StartArray)
            {
                int depth = Depth;
                while (Read() && depth < Depth)
                {
                }
            }
        }

        private void StartObject()
        {
            if (Depth > MaxDepth)
                JsonThrowHelper.ThrowJsonReaderException();

            Depth++;
            _containerMask = (_containerMask << 1) | 1;
            TokenType = JsonTokenType.StartObject;
        }

        private void EndObject()
        {
            if (!InObject || Depth <= 0)
                JsonThrowHelper.ThrowJsonReaderException();

            Depth--;
            _containerMask >>= 1;
            TokenType = JsonTokenType.EndObject;
        }

        private void StartArray()
        {
            if (Depth > MaxDepth)
                JsonThrowHelper.ThrowJsonReaderException();

            Depth++;
            _containerMask = (_containerMask << 1);
            TokenType = JsonTokenType.StartArray;
        }

        private void EndArray()
        {
            if (!InArray || Depth <= 0)
                JsonThrowHelper.ThrowJsonReaderException();

            Depth--;
            _containerMask >>= 1;
            TokenType = JsonTokenType.EndArray;
        }

        private void ConsumeNextUtf8MultiSegment(ref BufferReader<byte> reader, byte marker)
        {
            reader.Advance(1);
            Index++;
            if (marker == JsonConstants.ListSeperator)
            {
                if (!reader.TryPeek(out byte first))
                    JsonThrowHelper.ThrowJsonReaderException();

                if (first <= JsonConstants.Space)
                {
                    SkipWhiteSpace(ref reader);
                    // The next character must be a start of a property name or value.
                    if (!reader.TryPeek(out first))
                        JsonThrowHelper.ThrowJsonReaderException();
                }

                StartLocation = Index;
                if (InObject)
                {
                    if (first != JsonConstants.Quote)
                        JsonThrowHelper.ThrowJsonReaderException();

                    reader.Advance(1);
                    Index++;
                    StartLocation++;
                    ConsumePropertyNameUtf8MultiSegment(ref reader);
                }
                else
                {
                    ConsumeValueUtf8MultiSegment(ref reader, first);
                }
            }
            else if (marker == JsonConstants.CloseBrace)
            {
                EndObject();
            }
            else if (marker == JsonConstants.CloseBracket)
            {
                EndArray();
            }
            else
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
        }

        /// <summary>
        /// This method consumes the next token regardless of whether we are inside an object or an array.
        /// For an object, it reads the next property name token. For an array, it just reads the next value.
        /// </summary>
        private void ConsumeNextUtf8(ref ReadOnlySpan<byte> buffer, byte marker)
        {
            buffer = buffer.Slice(1);
            Index++;
            if (marker == JsonConstants.ListSeperator)
            {
                if (0 >= (uint)buffer.Length)
                    JsonThrowHelper.ThrowJsonReaderException();

                byte first = buffer[0];

                if (first <= JsonConstants.Space)
                {
                    SkipWhiteSpaceUtf8(ref buffer);
                    // The next character must be a start of a property name or value.
                    if (0 >= (uint)buffer.Length)
                        JsonThrowHelper.ThrowJsonReaderException();
                    first = buffer[0];
                }

                StartLocation = Index;
                if (InObject)
                {
                    if (first != JsonConstants.Quote)
                        JsonThrowHelper.ThrowJsonReaderException();

                    buffer = buffer.Slice(1);
                    Index++;
                    StartLocation++;
                    ConsumePropertyNameUtf8(ref buffer);
                }
                else
                {
                    ConsumeValueUtf8(ref buffer, first);
                }
            }
            else if (marker == JsonConstants.CloseBrace)
            {
                EndObject();
            }
            else if (marker == JsonConstants.CloseBracket)
            {
                EndArray();
            }
            else
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
        }

        private void ConsumeValueUtf8MultiSegment(ref BufferReader<byte> reader, byte marker)
        {
            TokenType = JsonTokenType.Value;

            if (marker == JsonConstants.Quote)
            {
                reader.Advance(1);
                Index++;
                StartLocation++;
                ConsumeStringUtf8MultiSegment(ref reader);
            }
            else if (marker == JsonConstants.OpenBrace)
            {
                reader.Advance(1);
                Index++;
                StartObject();
                ValueType = JsonValueType.Object;
            }
            else if (marker == JsonConstants.OpenBracket)
            {
                reader.Advance(1);
                Index++;
                StartArray();
                ValueType = JsonValueType.Array;
            }
            else if (marker - '0' <= '9' - '0')
            {
                ConsumeNumberUtf8MultiSegment(ref reader);
            }
            else if (marker == '-')
            {
                //TODO: Is this a valid check or do we need to do an Advance to be sure?
                if (reader.End) JsonThrowHelper.ThrowJsonReaderException();
                ConsumeNumberUtf8MultiSegment(ref reader);
            }
            else if (marker == 'f')
            {
                ConsumeFalseUtf8MultiSegment(ref reader);
            }
            else if (marker == 't')
            {
                ConsumeTrueUtf8MultiSegment(ref reader);
            }
            else if (marker == 'n')
            {
                ConsumeNullUtf8MultiSegment(ref reader);
            }
            else if (marker == '/')
            {
                // TODO: Comments?
                JsonThrowHelper.ThrowNotImplementedException();
            }
            else
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
        }

        /// <summary>
        /// This method contains the logic for processing the next value token and determining
        /// what type of data it is.
        /// </summary>
        private void ConsumeValueUtf8(ref ReadOnlySpan<byte> buffer, byte marker)
        {
            TokenType = JsonTokenType.Value;

            if (marker == JsonConstants.Quote)
            {
                buffer = buffer.Slice(1);
                Index++;
                StartLocation++;
                ConsumeStringUtf8(ref buffer);
            }
            else if (marker == JsonConstants.OpenBrace)
            {
                buffer = buffer.Slice(1);
                Index++;
                StartObject();
                ValueType = JsonValueType.Object;
            }
            else if (marker == JsonConstants.OpenBracket)
            {
                buffer = buffer.Slice(1);
                Index++;
                StartArray();
                ValueType = JsonValueType.Array;
            }
            else if (marker - '0' <= '9' - '0')
            {
                ConsumeNumberUtf8(ref buffer);
            }
            else if (marker == '-')
            {
                if (buffer.Length < 2) JsonThrowHelper.ThrowJsonReaderException();
                ConsumeNumberUtf8(ref buffer);
            }
            else if (marker == 'f')
            {
                ConsumeFalseUtf8(ref buffer);
            }
            else if (marker == 't')
            {
                ConsumeTrueUtf8(ref buffer);
            }
            else if (marker == 'n')
            {
                ConsumeNullUtf8(ref buffer);
            }
            else if (marker == '/')
            {
                // TODO: Comments?
                JsonThrowHelper.ThrowNotImplementedException();
            }
            else
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
        }

        private void ConsumeSingleValue(ref BufferReader<byte> reader, byte marker)
        {
            TokenType = JsonTokenType.Value;

            if (marker == JsonConstants.Quote)
            {
                reader.Advance(1);
                Index++;
                StartLocation++;
                ConsumeStringUtf8MultiSegment(ref reader);
            }
            else if (marker - '0' <= '9' - '0')
            {
                //TODO: Validate number
                ReadOnlySequence<byte> sequence = reader.Sequence.Slice(reader.Position);
                Value = sequence.IsSingleSegment ? sequence.First.Span : sequence.ToArray();
                ValueType = JsonValueType.Number;
                int length = reader.UnreadSpan.Length;
                reader.Advance(length);
                Index += length;
            }
            else if (marker == '-')
            {
                //TODO: Is this a valid check?
                if (reader.End) JsonThrowHelper.ThrowJsonReaderException();
                ReadOnlySequence<byte> sequence = reader.Sequence.Slice(reader.Position);
                Value = sequence.IsSingleSegment ? sequence.First.Span : sequence.ToArray();
                ValueType = JsonValueType.Number;
                int length = reader.UnreadSpan.Length;
                reader.Advance(length);
                Index += length;
            }
            else if (marker == 'f')
            {
                ConsumeFalseUtf8MultiSegment(ref reader);
            }
            else if (marker == 't')
            {
                ConsumeTrueUtf8MultiSegment(ref reader);
            }
            else if (marker == 'n')
            {
                ConsumeNullUtf8MultiSegment(ref reader);
            }
            else if (marker == '/')
            {
                // TODO: Comments?
                JsonThrowHelper.ThrowNotImplementedException();
            }
            else
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
        }

        private void ConsumeSingleValue(ref ReadOnlySpan<byte> buffer, byte marker)
        {
            TokenType = JsonTokenType.Value;

            if (marker == JsonConstants.Quote)
            {
                buffer = buffer.Slice(1);
                Index++;
                StartLocation++;
                ConsumeStringUtf8(ref buffer);
            }
            else if (marker - '0' <= '9' - '0')
            {
                //TODO: Validate number
                Value = buffer;
                ValueType = JsonValueType.Number;
                Index += buffer.Length;
                buffer = ReadOnlySpan<byte>.Empty;
            }
            else if (marker == '-')
            {
                if (buffer.Length < 2) JsonThrowHelper.ThrowJsonReaderException();
                Value = buffer;
                ValueType = JsonValueType.Number;
                Index += buffer.Length;
                buffer = ReadOnlySpan<byte>.Empty;
            }
            else if (marker == 'f')
            {
                ConsumeFalseUtf8(ref buffer);
            }
            else if (marker == 't')
            {
                ConsumeTrueUtf8(ref buffer);
            }
            else if (marker == 'n')
            {
                ConsumeNullUtf8(ref buffer);
            }
            else if (marker == '/')
            {
                // TODO: Comments?
                JsonThrowHelper.ThrowNotImplementedException();
            }
            else
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
        }

        private void ConsumeNumberUtf8MultiSegment(ref BufferReader<byte> reader)
        {
            //TODO: Increment Index by number of bytes advanced
            if (!reader.TryReadToAny(out ReadOnlySpan<byte> span, JsonConstants.Delimiters, advancePastDelimiter: false))
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }

            Value = span;
            ValueType = JsonValueType.Number;
        }

        private void ConsumeNumberUtf8(ref ReadOnlySpan<byte> buffer)
        {
            int idx = buffer.IndexOfAny(JsonConstants.Delimiters);
            if (idx == -1)
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }

            Value = buffer.Slice(0, idx);
            ValueType = JsonValueType.Number;
            buffer = buffer.Slice(idx);
            Index += idx;
        }

        private void ConsumeNullUtf8MultiSegment(ref BufferReader<byte> reader)
        {
            Value = JsonConstants.NullValue;
            ValueType = JsonValueType.Null;

            if (!reader.IsNext(JsonConstants.NullValue, advancePast: true))
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
            Index += 4;
        }

        private void ConsumeNullUtf8(ref ReadOnlySpan<byte> buffer)
        {
            Value = JsonConstants.NullValue;
            ValueType = JsonValueType.Null;

            if (!buffer.StartsWith(Value))
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
            buffer = buffer.Slice(4);
            Index += 4;
        }

        private void ConsumeFalseUtf8MultiSegment(ref BufferReader<byte> reader)
        {
            Value = JsonConstants.FalseValue;
            ValueType = JsonValueType.False;

            if (!reader.IsNext(JsonConstants.FalseValue, advancePast: true))
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
            Index += 5;
        }

        private void ConsumeFalseUtf8(ref ReadOnlySpan<byte> buffer)
        {
            Value = JsonConstants.FalseValue;
            ValueType = JsonValueType.False;

            if (!buffer.StartsWith(Value))
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
            buffer = buffer.Slice(5);
            Index += 5;
        }

        private void ConsumeTrueUtf8MultiSegment(ref BufferReader<byte> reader)
        {
            Value = JsonConstants.TrueValue;
            ValueType = JsonValueType.True;

            if (!reader.IsNext(JsonConstants.TrueValue, advancePast: true))
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
            Index += 4;
        }

        private void ConsumeTrueUtf8(ref ReadOnlySpan<byte> buffer)
        {
            Value = JsonConstants.TrueValue;
            ValueType = JsonValueType.True;

            if (!buffer.StartsWith(Value))
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }
            buffer = buffer.Slice(4);
            Index += 4;
        }

        private void ConsumePropertyNameUtf8MultiSegment(ref BufferReader<byte> reader)
        {
            ConsumeStringUtf8MultiSegment(ref reader);

            if (!reader.TryPeek(out byte first))
                JsonThrowHelper.ThrowJsonReaderException();

            if (first <= JsonConstants.Space)
            {
                SkipWhiteSpace(ref reader);
                if (!reader.TryPeek(out first))
                    JsonThrowHelper.ThrowJsonReaderException();
            }

            // The next character must be a key / value seperator. Validate and skip.
            if (first != JsonConstants.KeyValueSeperator)
                JsonThrowHelper.ThrowJsonReaderException();

            TokenType = JsonTokenType.PropertyName;
            reader.Advance(1);
            Index++;
        }

        private void ConsumePropertyNameUtf8(ref ReadOnlySpan<byte> buffer)
        {
            ConsumeStringUtf8(ref buffer);

            if (0 >= (uint)buffer.Length)
                JsonThrowHelper.ThrowJsonReaderException();

            byte first = buffer[0];

            if (first <= JsonConstants.Space)
            {
                SkipWhiteSpaceUtf8(ref buffer);
                if (0 >= (uint)buffer.Length)
                    JsonThrowHelper.ThrowJsonReaderException();
                first = buffer[0];
            }

            // The next character must be a key / value seperator. Validate and skip.
            if (first != JsonConstants.KeyValueSeperator)
            {
                JsonThrowHelper.ThrowJsonReaderException();
            }

            TokenType = JsonTokenType.PropertyName;
            buffer = buffer.Slice(1);
            Index++;
        }

        public bool TryReadUntil(out ReadOnlySpan<byte> span, byte delimiter)
        {
            ReadOnlySpan<byte> remaining = _reader.UnreadSpan;

            //TODO: Optimize looking for nested quotes
            int i = 0;
            while (true)
            {
                int counter = 0;
                i += remaining.Slice(i).IndexOf(delimiter);
                if (i == -1)
                    break;
                if (i == 0)
                {
                    goto Done;
                }
                for (int j = i - 1; j >= 0; j--)
                {
                    if (remaining[j] != JsonConstants.ReverseSolidus)
                    {
                        if (counter % 2 == 0)
                            goto Done;
                        break;
                    }
                    else
                        counter++;
                }
                i++;
            }
            return TryReadUntilSlow(out span, delimiter, remaining.Length);
        Done:
            span = remaining.Slice(0, i);
            _reader.Advance(i + 1);
            return true;
        }

        private bool TryReadUntilSlow(out ReadOnlySpan<byte> span, byte delimiter, int skip)
        {
            BufferReader<byte> copy = _reader;
            if (skip > 0)
                _reader.Advance(skip);
            ReadOnlySpan<byte> remaining = _reader.UnreadSpan;

            while (!_reader.End)
            {
                int counter = 0;
                int index = remaining.IndexOf(delimiter);
                if (index != -1)
                {
                    // Found the delimiter. Move to it, slice, then move past it.
                    if (index > 0)
                    {
                        for (int j = index - 1; j >= 0; j--)
                        {
                            if (remaining[j] != JsonConstants.ReverseSolidus)
                            {
                                if (counter % 2 == 0)
                                {
                                    _reader.Advance(index);
                                    goto Done;
                                }
                                goto KeepLooking;
                            }
                            else
                                counter++;
                        }
                    }

                Done:
                    ReadOnlySequence<byte> sequence = _reader.Sequence.Slice(copy.Position, _reader.Position);
                    _reader.Advance(1);
                    span = sequence.IsSingleSegment ? sequence.First.Span : sequence.ToArray();
                    return true;
                }
            KeepLooking:
                _reader.Advance(remaining.Length);
                remaining = _reader.CurrentSpan;
            }

            // Didn't find anything, reset our original state.
            _reader = copy;
            span = default;
            return false;
        }

        private void ConsumeStringWithNestedQuotes(ref BufferReader<byte> reader)
        {
            //TODO: Optimize looking for nested quotes
            //TODO: Avoid redoing first IndexOf searches

            BufferReader<byte> copy = reader;
            ReadOnlySpan<byte> buffer = reader.UnreadSpan;
            if (0 >= (uint)buffer.Length)
            {
                reader.Advance(buffer.Length);
                Index += buffer.Length;
                buffer = reader.CurrentSpan;
            }

            while (!reader.End)
            {
                int counter = 1;
                int index = buffer.IndexOf(JsonConstants.Quote);
                if (index != -1)
                {
                    // Found the delimiter. Move to it, slice, then move past it.
                    if (index == 0 || buffer[index - 1] != JsonConstants.ReverseSolidus)
                        goto Done;

                    for (int j = index - 2; j >= 0; j--)
                    {
                        if (buffer[j] != JsonConstants.ReverseSolidus)
                        {
                            if (counter % 2 == 0)
                                goto Done;
                            break;
                        }
                        else
                            counter++;
                    }
                    goto KeepLooking;

                Done:
                    reader.Advance(index);
                    Index += index;
                    ReadOnlySequence<byte> sequence = reader.Sequence.Slice(copy.Position, reader.Position);
                    reader.Advance(1);
                    Index++;
                    Value = sequence.IsSingleSegment ? sequence.First.Span : sequence.ToArray();
                    ValueType = JsonValueType.String;
                    return;
                }
            KeepLooking:
                reader.Advance(index + 1);
                buffer = reader.UnreadSpan;
            }

            JsonThrowHelper.ThrowJsonReaderException();
        }

        private void ConsumeStringUtf8MultiSegmentSlow(ref BufferReader<byte> reader)
        {
            BufferReader<byte> copy = reader;
            ReadOnlySpan<byte> buffer = reader.UnreadSpan;
            if (0 >= (uint)buffer.Length)
            {
                reader.Advance(buffer.Length);
                Index += buffer.Length;
                buffer = reader.CurrentSpan;
            }

            while (!reader.End)
            {
                int index = buffer.IndexOf(JsonConstants.Quote);
                if (index != -1)
                {
                    // Found the delimiter. Move to it, slice, then move past it.
                    if (index == 0 || buffer[index - 1] != JsonConstants.ReverseSolidus)
                    {
                        reader.Advance(index);
                        Index += index;
                        ReadOnlySequence<byte> sequence = reader.Sequence.Slice(copy.Position, reader.Position);
                        reader.Advance(1);
                        Index++;
                        Value = sequence.IsSingleSegment ? sequence.First.Span : sequence.ToArray();
                        ValueType = JsonValueType.String;
                        return;
                    }
                    reader = copy;
                    ConsumeStringWithNestedQuotes(ref reader);
                }
                reader.Advance(buffer.Length);
                buffer = reader.CurrentSpan;
            }

            JsonThrowHelper.ThrowJsonReaderException();
        }

        private void ConsumeStringUtf8MultiSegment(ref BufferReader<byte> reader)
        {
            ReadOnlySpan<byte> buffer = reader.UnreadSpan;
            int idx = buffer.IndexOf(JsonConstants.Quote);
            if (idx < 0)
            {
                ConsumeStringUtf8MultiSegmentSlow(ref reader);
                return;
            }

            if (idx == 0 || buffer[idx - 1] != JsonConstants.ReverseSolidus)
            {
                Value = buffer.Slice(0, idx);
                ValueType = JsonValueType.String;

                idx++;
                reader.Advance(idx);
                Index += idx;
                return;
            }
            ConsumeStringWithNestedQuotes(ref reader);
        }

        private void ConsumeStringUtf8(ref ReadOnlySpan<byte> buffer)
        {
            int idx = buffer.IndexOf(JsonConstants.Quote);
            if (idx < 0)
                JsonThrowHelper.ThrowJsonReaderException();
            if (idx == 0 || buffer[idx - 1] != JsonConstants.ReverseSolidus)
            {
                Value = buffer.Slice(0, idx);
                ValueType = JsonValueType.String;

                idx++;
                buffer = buffer.Slice(idx);
                Index += idx;
                return;
            }
            ConsumeStringWithNestedQuotes(ref buffer);
        }

        private void ConsumeStringWithNestedQuotes(ref ReadOnlySpan<byte> buffer)
        {
            //TODO: Optimize looking for nested quotes
            //TODO: Avoid redoing first IndexOf search
            int i = 0;
            while (true)
            {
                int counter = 0;
                int foundIdx = buffer.Slice(i).IndexOf(JsonConstants.Quote);
                if (foundIdx == -1)
                    JsonThrowHelper.ThrowJsonReaderException();
                if (foundIdx == 0)
                    break;
                for (int j = i + foundIdx - 1; j >= i; j--)
                {
                    if (buffer[j] != JsonConstants.ReverseSolidus)
                    {
                        if (counter % 2 == 0)
                        {
                            i += foundIdx;
                            goto Done;
                        }
                        break;
                    }
                    else
                        counter++;
                }
                i += foundIdx + 1;
            }

        Done:
            Value = buffer.Slice(0, i);
            ValueType = JsonValueType.String;

            i++;
            buffer = buffer.Slice(i);
            Index += i;
        }

        private void SkipWhiteSpaceUtf8(ref ReadOnlySpan<byte> buffer)
        {
            //Create local copy to avoid bounds checks.
            ReadOnlySpan<byte> bufferCopy = buffer;
            int i = 0;
            for (; i < bufferCopy.Length; i++)
            {
                byte val = bufferCopy[i];
                if (val != JsonConstants.Space &&
                    val != JsonConstants.CarriageReturn &&
                    val != JsonConstants.LineFeed &&
                    val != JsonConstants.Tab)
                {
                    break;
                }
            }
            buffer = bufferCopy.Slice(i);
            Index += i;
        }
    }
}


text:
( function ( $ ) {

    function ConditionalField( element ) {

        if ( element instanceof jQuery || element.attr('id') == 'id' ) {
            this.form = element.closest( 'form' )
            this.state = 0
            this.element = element
            this.id = element.attr( 'id' )
            this.value = element.val()
            this.checkbox = $( '<input type="checkbox" id="' + this.id + '_toggler" />' )

            this.setup()
            this.init()

        } else {
            throw new Error ( 'Expecting a jQuery object with an ID attribute' )
        }
    }

    ConditionalField.prototype.setup = function ( ) {
        this.element.parent().addClass( 'is-conditional-field' )

        if ( this.value ) {
            this.state = 1
            this.checkbox = this.checkbox.attr( 'checked', 'checked' )
        }

        this.element.before( this.checkbox )
        this.checkbox.wrap( '

' )

        this.element.wrap( '

' )
    }

    ConditionalField.prototype.init = function ( ) {
        var self = this

        if ( this.value ) {
            this.visible()
        } else {
            this.hidden()
        }

        this.checkbox.change( function() {
            if ( this.checked ) {
                self.visible()
            } else {
                self.hidden()
            }
        })

        this.form.on( 'submit', function ( event ) {
            event.preventDefault()

            if ( self.state === 0 ) {
                self.empty( self )
            }

            this.submit();
        });
    }

    ConditionalField.prototype.hidden = function ( ) {
        this.element.parent().hide()
        this.state = 0
    }

    ConditionalField.prototype.visible = function ( ) {
        this.element.parent().show()
        this.state = 1
    }

    ConditionalField.prototype.empty = function ( self ) {
        self.element.val( "" )
        console.log( 'emptied selectbox' );
    }

    $( document ).ready( function () {
        var field = $( '#id_shops' )
        new ConditionalField( field )
    });

})( jQuery )


text:
package org.terracotta.management.service.monitoring;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terracotta.management.model.capabilities.Capability;
import org.terracotta.management.model.context.ContextContainer;
import org.terracotta.management.model.notification.ContextualNotification;
import org.terracotta.management.registry.CapabilityManagement;
import org.terracotta.management.registry.DefaultCapabilityManagement;
import org.terracotta.management.registry.ExposedObject;
import org.terracotta.management.registry.ManagementProvider;
import org.terracotta.management.sequence.TimeSource;
import org.terracotta.management.service.monitoring.registry.provider.AbstractEntityManagementProvider;
import org.terracotta.management.service.monitoring.registry.provider.MonitoringServiceAware;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author Mathieu Carbou
 */
class DefaultEntityManagementRegistry implements EntityManagementRegistry, TopologyEventListener {

  private static final Logger LOGGER = LoggerFactory.getLogger(DefaultEntityManagementRegistry.class);
  private static final Comparator<Capability> CAPABILITY_COMPARATOR = Comparator.comparing(Capability::getName);

  private final long consumerId;
  private final EntityMonitoringService monitoringService;
  private final TimeSource timeSource;
  private final ContextContainer contextContainer;
  private final List<ManagementProvider<?>> managementProviders = new CopyOnWriteArrayList<>();
  private final CompletableFuture<?> onEntityPromotionCompleted = new CompletableFuture<>();
  private final CompletableFuture<?> onEntityCreated = new CompletableFuture<>();
  private final CompletableFuture<?> onClose = new CompletableFuture<>();
  private volatile boolean closed;

  DefaultEntityManagementRegistry(long consumerId, EntityMonitoringService monitoringService, TimeSource timeSource) {
    this.contextContainer = new ContextContainer("consumerId", String.valueOf(consumerId));
    this.consumerId = consumerId;
    this.monitoringService = Objects.requireNonNull(monitoringService);
    this.timeSource = Objects.requireNonNull(timeSource);
  }

  void onEntityPromotionCompleted(Runnable r) {
    onEntityPromotionCompleted.thenRun(r);
  }

  void onEntityCreated(Runnable r) {
    onEntityCreated.thenRun(r);
  }

  void onClose(Runnable r) {
    onClose.thenRun(r);
  }

  @Override
  public EntityMonitoringService getMonitoringService() {
    return monitoringService;
  }

  @Override
  public ContextContainer getContextContainer() {
    return contextContainer;
  }

  @Override
  public boolean addManagementProvider(ManagementProvider<?> provider) {
    LOGGER.trace("[{}] addManagementProvider({}) active={}", consumerId, provider.getClass().getSimpleName(), monitoringService.isActiveEntityService());
    String name = provider.getCapabilityName();
    for (ManagementProvider<?> managementProvider : managementProviders) {
      if (managementProvider.getCapabilityName().equals(name)) {
        return false;
      }
    }
    boolean added = managementProviders.add(provider);
    if (added) {
      if (provider instanceof MonitoringServiceAware) {
        ((MonitoringServiceAware) provider).setMonitoringService(monitoringService);
        ((MonitoringServiceAware) provider).setTimeSource(timeSource);
      }
    }
    return added;
  }

  @Override
  public void removeManagementProvider(ManagementProvider<?> provider) {
    managementProviders.remove(provider);
  }

  @Override
  public CapabilityManagement withCapability(String capabilityName) {
    return new DefaultCapabilityManagement(this, capabilityName);
  }

  @Override
  public Collection<? extends Capability> getCapabilities() {
    List<Capability> capabilities = new ArrayList<Capability>();
    for (ManagementProvider<?> managementProvider : managementProviders) {
      capabilities.add(managementProvider.getCapability());
    }
    Collections.sort(capabilities, CAPABILITY_COMPARATOR);
    return capabilities;
  }

  @Override
  public Collection<String> getCapabilityNames() {
    Collection<String> names = new TreeSet<String>();
    for (ManagementProvider<?> managementProvider : managementProviders) {
      names.add(managementProvider.getCapabilityName());
    }
    return names;
  }

  @Override
  public List<ManagementProvider<?>> getManagementProvidersByCapability(String capabilityName) {
    List<ManagementProvider<?>> allProviders = new ArrayList<ManagementProvider<?>>();
    for (ManagementProvider<?> provider : managementProviders) {
      if (provider.getCapabilityName().equals(capabilityName)) {
        allProviders.add(provider);
      }
    }
    return allProviders;
  }

  @SuppressWarnings("unchecked")
  @Override
  public CompletableFuture<Void> register(Object managedObject) {
    LOGGER.trace("[{}] register() active={}", consumerId, monitoringService.isActiveEntityService());
    List<CompletableFuture<Void>> futures = new ArrayList<>(managementProviders.size());
    for (ManagementProvider managementProvider : managementProviders) {
      if (managementProvider.getManagedType().isInstance(managedObject)) {
        if (managementProvider instanceof AbstractEntityManagementProvider) {
          CompletableFuture<Void> future = ((AbstractEntityManagementProvider) managementProvider).registerAsync(managedObject);
          futures.add(future);
        } else {
          managementProvider.register(managedObject);
        }
      }
    }
    return futures.isEmpty() ?
        CompletableFuture.completedFuture(null) :
        CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[futures.size()]));
  }

  @SuppressWarnings("unchecked")
  @Override
  public void unregister(Object managedObject) {
    for (ManagementProvider managementProvider : managementProviders) {
      if (managementProvider.getManagedType().isInstance(managedObject)) {
        managementProvider.unregister(managedObject);
      }
    }
  }

  @Override
  public void refresh() {
    LOGGER.info("[{}] Updating {} entity management registry", consumerId, monitoringService.isActiveEntityService() ? "active" : "passive");
    Collection<? extends Capability> capabilities = getCapabilities();
    Capability[] capabilitiesArray = capabilities.toArray(new Capability[0]);
    // confirm with server team, this call won't throw because monitoringProducer.addNode() won't throw.
    monitoringService.exposeManagementRegistry(getContextContainer(), capabilitiesArray);
  }

  @SuppressWarnings("unchecked")
  @Override
  public boolean pushServerEntityNotification(Object managedObjectSource, String type, Map<String, String> attrs) {
    LOGGER.trace("[{}] pushServerEntityNotification({})", consumerId, type);
    for (ManagementProvider managementProvider : managementProviders) {
      if (managementProvider.getManagedType().isInstance(managedObjectSource)) {
        ExposedObject<Object> exposedObject = managementProvider.findExposedObject(managedObjectSource);
        if (exposedObject != null) {
          monitoringService.pushNotification(new ContextualNotification(exposedObject.getContext(), type, attrs));
          return true;
        }
      }
    }
    return false;
  }

  @Override
  public void close() {
    if (!closed) {
      closed = true;
      LOGGER.info("[{}] Closing {} entity management registry", consumerId, monitoringService.isActiveEntityService() ? "active" : "passive");
      managementProviders.forEach(ManagementProvider::close);
      managementProviders.clear();
      onClose.complete(null);
    }
  }

  @Override
  public void entityPromotionCompleted() {
    LOGGER.trace("[{}] entityPromotionCompleted() active={}", consumerId, monitoringService.isActiveEntityService());
    onEntityPromotionCompleted.complete(null);
  }

  @Override
  public void entityCreated() {
    LOGGER.trace("[{}] entityCreated() active={}", consumerId, monitoringService.isActiveEntityService());
    onEntityCreated.complete(null);
  }

  @Override
  public String toString() {
    final StringBuilder sb = new StringBuilder("DefaultEntityManagementRegistry{");
    sb.append("consumerId=").append(consumerId);
    sb.append(", active=").append(monitoringService.isActiveEntityService());
    sb.append('}');
    return sb.toString();
  }
}


text:
using System;

namespace EzTextingApiClient
{
    /// <summary>
    /// Client constants
    ///</summary>
    public static class ClientConstants
    {
        public const string EzBasePathProperty = "EzBasePath";
        public const string CtBasePathProperty = "CtBasePath";
        public const string GtBasePathProperty = "GtBasePath";
        public const string TmcBasePathProperty = "TmcBasePath";

        public const string ProxyAddressProperty = "ProxyAddress";
        public const string ProxyCredentialsProperty = "ProxyCredentials";
        public const int DefaultProxyPort = 8080;

        public const string LogTraceSourceName = "EzTextingApiClient";
        public const string LogFileListenerName = "EzTextingLogFile";
        public const string LogDatetimePattern = "yyyy-MM-dd HH:mm:ss.fff";

        public const string Placeholder = "{}";
        public const string DateFormatPattern = "MM-dd-yyyy h:mm tt";
        public const string CreatedAtFormatPattern = "MM-dd-yyyy";

        public const string FormEncodedContentType = "application/x-www-form-urlencoded";
        public const string JsonContentType = "application/json";

        public static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    }
}