text:
package routes

import (
	"gopkg.in/macaron.v1"
	"fmt"
	"strings"
	"github.com/protosam/hostcontrol/util"
	//"net/url"
//	"github.com/protosam/hostcontrol/services/dns"
//	"github.com/protosam/hostcontrol/services/mail"
//	"github.com/protosam/hostcontrol/services/domains"
//	"github.com/protosam/hostcontrol/services/users"
//	"github.com/protosam/hostcontrol/services/sql"
)

var Webserver *macaron.Macaron
var routes = make(map[string]func())

var route_function = make(map[string]util.API_function)
var route_method = make(map[string]string)

func StartApi(webserver *macaron.Macaron){
	// Setup Webserver variable
	Webserver = webserver

	// Let the user know we're binding the API services.
	fmt.Println("Starting api services...")

	// We will add all of our routes arbitrarily.
	for name := range route_function {
		fmt.Println("Adding route " + name)

		if route_method[name] == "GET" {
			Webserver.Get(name, route_function[name])
		} else if route_method[name] == "POST" {
			Webserver.Post(name, route_function[name])
		} else {
			Webserver.Get(name, route_function[name])
			Webserver.Post(name, route_function[name])
		}
	}

}

func CLI(routename string) string {
	return route_function[routename](nil)
}

func API(rawuri string, ctx *macaron.Context) (string) {
    querystr := strings.Split(rawuri, "?")
    routename := strings.Split(rawuri, "?")[0]
    if len(querystr) > 1 {

        params := strings.Split(querystr[1], "&")
        for _, param := range params {
            par := strings.Split(param, "=")
            if len(par) > 1 {
                ctx.SetParams(par[0], par[1])
            }

        }
    }

    ret := route_function[routename](ctx)
	return ret
}

// Function for adding new route dynamically
func route(routename string, fn util.API_function, method string){
	route_method[routename] = method
	route_function[routename] = fn;

}


text:
package net.teamio.taam;

import com.google.common.collect.Lists;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemMultiTexture;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fluids.BlockFluidClassic;
import net.minecraftforge.fluids.BlockFluidFinite;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.ModMetadata;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary;
import net.teamio.taam.Taam.FLUID_MATERIAL_META;
import net.teamio.taam.content.ItemWithMetadata;
import net.teamio.taam.content.ItemWithMetadata.ItemDelegate;
import net.teamio.taam.content.common.BlockBuilding;
import net.teamio.taam.content.common.BlockLamp;
import net.teamio.taam.content.common.BlockMachines;
import net.teamio.taam.content.common.BlockOre;
import net.teamio.taam.content.common.BlockSensor;
import net.teamio.taam.content.common.BlockSupportBeam;
import net.teamio.taam.content.common.FluidDye;
import net.teamio.taam.content.common.FluidMaterial;
import net.teamio.taam.content.common.ItemDebugTool;
import net.teamio.taam.content.common.ItemTool;
import net.teamio.taam.content.common.ItemWrench;
import net.teamio.taam.content.common.TileEntityChute;
import net.teamio.taam.content.common.TileEntityCreativeCache;
import net.teamio.taam.content.common.TileEntitySensor;
import net.teamio.taam.content.conveyors.BlockProductionLine;
import net.teamio.taam.content.conveyors.BlockProductionLineAppliance;
import net.teamio.taam.content.conveyors.BlockProductionLineAttachable;
import net.teamio.taam.content.conveyors.ItemAppliance;
import net.teamio.taam.content.conveyors.ItemAttachable;
import net.teamio.taam.content.conveyors.ItemProductionLine;
import net.teamio.taam.content.conveyors.TileEntityConveyor;
import net.teamio.taam.content.conveyors.TileEntityConveyorElevator;
import net.teamio.taam.content.conveyors.TileEntityConveyorHopper;
import net.teamio.taam.content.conveyors.TileEntityConveyorItemBag;
import net.teamio.taam.content.conveyors.TileEntityConveyorProcessor;
import net.teamio.taam.content.conveyors.TileEntityConveyorSieve;
import net.teamio.taam.content.conveyors.TileEntityConveyorTrashCan;
import net.teamio.taam.content.piping.TileEntityCreativeWell;
import net.teamio.taam.conveyors.ConveyorSlotsStandard;
import net.teamio.taam.conveyors.IConveyorSlots;
import net.teamio.taam.conveyors.appliances.ApplianceAligner;
import net.teamio.taam.conveyors.appliances.ApplianceSprayer;
import net.teamio.taam.gui.GuiHandler;
import net.teamio.taam.gui.advanced.IAdvancedMachineGUI;
import net.teamio.taam.machines.MachineBlock;
import net.teamio.taam.machines.MachineItemBlock;
import net.teamio.taam.machines.MachineTileEntity;
import net.teamio.taam.piping.IPipe;
import net.teamio.taam.rendering.TankRenderInfo;
import net.teamio.taam.util.TaamUtil;
import org.apache.commons.lang3.NotImplementedException;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;

@Mod(modid = Taam.MOD_ID, name = Taam.MOD_NAME, version = Taam.MOD_VERSION, guiFactory = Taam.GUI_FACTORY_CLASS, updateJSON = Taam.MOD_UPDATE_URL)
public class TaamMain {

	static {
		FluidRegistry.enableUniversalBucket();
	}

	@Instance(Taam.MOD_ID)
	public static TaamMain instance;

	@SidedProxy(clientSide = "net.teamio.taam.TaamClientProxy", serverSide = "net.teamio.taam.TaamCommonProxy")
	public static TaamCommonProxy proxy;

	public static SimpleNetworkWrapper network;

	public static ItemDebugTool itemDebugTool;
	public static ItemWrench itemWrench;
	public static ItemTool itemSaw;
	public static ItemWithMetadata<Taam.ITEM_MATERIAL_META> itemMaterial;
	public static ItemWithMetadata<Taam.ITEM_PART_META> itemPart;
	public static ItemWithMetadata<Taam.BLOCK_ORE_META> itemIngot;
	public static ItemWithMetadata<Taam.BLOCK_ORE_META> itemDust;

	/**
	 * Wrapper block for multipart machines. Only used if multipart is disabled,
	 * but always loaded for worlds containing the wrapper blocks.
	 */
	public static MachineBlock blockMachine;
	/**
	 * Either {@link MachineItemBlock} or old, FIXME not anymore MachineItemMultipart,
	 * depending on availability of multipart.
	 */
	public static Item itemMachine;

	public static CreativeTabs creativeTab;

	public static BlockLamp blockLamp;
	public static BlockLamp blockLampInverted;
	public static BlockSensor blockSensor;
	public static BlockMachines blockMachines;
	public static BlockProductionLine blockProductionLine;
	public static BlockProductionLineAttachable blockProductionLineAttachable;
	public static BlockProductionLineAppliance blockProductionLineAppliance;
	public static BlockOre blockOre;
	public static BlockBuilding blockConcrete;
	public static BlockSupportBeam blockSupportBeam;

	public static FluidDye[] fluidsDye;
	public static BlockFluidClassic[] blocksFluidDye;
	public static FluidMaterial[] fluidsMaterial;
	public static BlockFluidFinite[] blocksFluidMaterial;

	public static final DamageSource ds_processed = new DamageSource("taam.processed").setDamageBypassesArmor();
	public static final DamageSource ds_shredded = new DamageSource("taam.shredded").setDamageBypassesArmor();
	public static final DamageSource ds_ground = new DamageSource("taam.ground").setDamageBypassesArmor();
	public static final DamageSource ds_crushed = new DamageSource("taam.crushed").setDamageBypassesArmor();
	public static final DamageSource ds_reconfigured = new DamageSource("taam.reconfigured").setDamageIsAbsolute();

	public static SoundEvent soundSipAh;

	private static final List<Item> registeredItems = Lists.newArrayList();
	private static final List<Block> registeredBlocks = Lists.newArrayList();

	private static void registerBlock(Block block, ItemBlock item, String name) {
		registerBlock(block, name);
		registerItem(item, name);
	}

	private static void registerBlock(Block block, String name) {
		block.setTranslationKey(Taam.MOD_ID + "." + name);
		block.setCreativeTab(creativeTab);
		block.setRegistryName(Taam.MOD_ID, name);
		registeredBlocks.add(block);
		// ForgeRegistries.BLOCKS.register(block); -> see registerBlocks(event)
	}

	private static void registerItem(Item item, String name) {
		item.setTranslationKey(Taam.MOD_ID + "." + name);
		item.setCreativeTab(creativeTab);
		item.setRegistryName(Taam.MOD_ID, name);
		registeredItems.add(item);
		// ForgeRegistries.ITEMS.register(item); -> see registerItems(event)
	}

	@SubscribeEvent
	public void registerItems(final RegistryEvent.Register<Item> event) {
		event.getRegistry().registerAll(registeredItems.toArray(new Item[0]));
	}

	@SubscribeEvent
	public void registerBlocks(final RegistryEvent.Register<Block> event) {
		event.getRegistry().registerAll(registeredBlocks.toArray(new Block[0]));
	}

	@EventHandler
	public void preInit(FMLPreInitializationEvent event) {

		/*
		 * Metadata
		 */
		ModMetadata meta = event.getModMetadata();
		meta.authorList.add(Taam.MOD_AUTHOR1);
		meta.authorList.add(Taam.MOD_AUTHOR2);
		meta.description = Taam.MOD_DESCRIPTION;
		meta.logoFile = Taam.MOD_LOGO_PATH;
		meta.url = Taam.MOD_URL;
		meta.updateJSON = Taam.MOD_UPDATE_URL;
		meta.credits = Taam.MOD_CREDITS;
		meta.autogenerated = false;

		/*
		 * Some general stuff that needs to be registered
		 */

		MinecraftForge.EVENT_BUS.register(new TaamCraftingHandler());
		MinecraftForge.EVENT_BUS.register(new Config());
		MinecraftForge.EVENT_BUS.register(proxy);
		MinecraftForge.EVENT_BUS.register(this);

		/*
		 * Read Config
		 */

		Config.init(event.getSuggestedConfigurationFile());
		creativeTab = new CreativeTabs(Taam.MOD_ID) {
			@Nonnull
			@Override
			@SideOnly(Side.CLIENT)
			public ItemStack createIcon() {
				return new ItemStack(blockProductionLine, 1, 1);
			}
		};

		/*
		 * Check for mcmultipart
		 */
		Config.multipart_present = Loader.isModLoaded("mcmultipart");

		if (Config.multipart_present) {
			if (Config.multipart_load) {
				Log.info("Enabling multipart support");
			} else {
				Log.info("Config forced me to disabling multipart support although multipart is available.");
			}
		} else if (Config.multipart_load) {
			Log.warn("Config has multipart enabled, but it was not found. Multipart support will not be loaded.");
			Config.multipart_load = false;
		}

		/*
		 * Register Stuff
		 */

		registerBlock(
				blockLamp = new BlockLamp(false),
				new ItemBlock(blockLamp),
				Taam.BLOCK_LAMP
		);
		registerBlock(
				blockLampInverted = new BlockLamp(true),
				new ItemBlock(blockLampInverted),
				Taam.BLOCK_LAMP_INVERTED
		);
		registerBlock(
				blockSensor = new BlockSensor(),
				new ItemBlock(blockSensor),
				Taam.BLOCK_SENSOR
		);

		registerBlock(
				blockMachines = new BlockMachines(),
				new ItemMultiTexture(blockMachines, blockMachines, TaamUtil.enumValuesAsString(Taam.BLOCK_MACHINES_META.values())),
				Taam.BLOCK_MACHINES
		);

		registerBlock(
				blockProductionLine = new BlockProductionLine(),
				new ItemProductionLine(blockProductionLine, TaamUtil.enumValuesAsString(Taam.BLOCK_PRODUCTIONLINE_META.values())),
				Taam.BLOCK_PRODUCTIONLINE
		);

		registerBlock(
				blockProductionLineAttachable = new BlockProductionLineAttachable(),
				new ItemAttachable(blockProductionLineAttachable, TaamUtil.enumValuesAsString(Taam.BLOCK_PRODUCTIONLINE_ATTACHABLE_META.values())),
				Taam.BLOCK_PRODUCTIONLINE_ATTACHABLE
		);

		registerBlock(
				blockProductionLineAppliance = new BlockProductionLineAppliance(),
				new ItemAppliance(blockProductionLineAppliance, Taam.BLOCK_PRODUCTIONLINE_APPLIANCE_META.values()),
				Taam.BLOCK_PRODUCTIONLINE_APPLIANCE
		);

		registerBlock(
				blockOre = new BlockOre(),
				new ItemMultiTexture(blockOre, blockOre, TaamUtil.enumValuesAsString(Taam.BLOCK_ORE_META.values())),
				Taam.BLOCK_ORE
		);

		registerBlock(
				blockConcrete = new BlockBuilding(),
				new ItemMultiTexture(blockConcrete, blockConcrete, Taam.BLOCK_CONCRETE_META.valuesAsString()),
				Taam.BLOCK_CONCRETE
		);

		registerBlock(
				blockSupportBeam = new BlockSupportBeam(),
				new ItemBlock(blockSupportBeam),
				Taam.BLOCK_SUPPORT_BEAM
		);

		registerItem(itemDebugTool = new ItemDebugTool(), Taam.ITEM_DEBUG_TOOL);
		registerItem(itemWrench = new ItemWrench(), Taam.ITEM_WRENCH);
		registerItem(itemSaw = new ItemTool(Taam.ITEM_TOOL_META.saw), Taam.ITEM_TOOL + "." + Taam.ITEM_TOOL_META.saw.name());

		registerItem(itemMaterial = new ItemWithMetadata<>("material", Taam.ITEM_MATERIAL_META.values(), null), Taam.ITEM_MATERIAL);
		registerItem(itemPart = new ItemWithMetadata<>("part", Taam.ITEM_PART_META.values(),
				new ItemDelegate<Taam.ITEM_PART_META>() {
					@Override
					@SideOnly(Side.CLIENT)
					public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
						if (stack.getMetadata() == Taam.ITEM_PART_META.redirector.ordinal()) {
							String usage = I18n.format("lore.taam.redirector.usage");
							// Split at literal \n in the translated text. a lot of escaping here.
							Collections.addAll(tooltip, usage.split("\\\\n"));
						}
					}
				}), Taam.ITEM_PART);
		registerItem(itemIngot = new ItemWithMetadata<>("ingot", Taam.BLOCK_ORE_META.values(),
				new ItemDelegate<Taam.BLOCK_ORE_META>() {
					@Override
					public boolean isValidMetadata(Taam.BLOCK_ORE_META meta) {
						return meta.ingot;
					}

					@Override
					@SideOnly(Side.CLIENT)
					public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
						if (stack.getMetadata() == Taam.BLOCK_ORE_META.iron.ordinal() ||
								stack.getMetadata() == Taam.BLOCK_ORE_META.gold.ordinal()) {
							String usage = I18n.format("lore.taam.ingots.cheaty");
							// Split at literal \n in the translated text. a lot of escaping here.
							Collections.addAll(tooltip, usage.split("\\\\n"));
						}
					}
				}), Taam.ITEM_INGOT);

		registerItem(itemDust = new ItemWithMetadata<>("dust", Taam.BLOCK_ORE_META.values(),
				new ItemDelegate<Taam.BLOCK_ORE_META>() {
					@Override
					public boolean isValidMetadata(Taam.BLOCK_ORE_META meta) {
						return meta.dust;
					}
				}), Taam.ITEM_DUST);

		/*
		 * Tile Entities
		 */

		GameRegistry.registerTileEntity(TileEntitySensor.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_SENSOR));
		GameRegistry.registerTileEntity(TileEntityChute.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CHUTE));
		GameRegistry.registerTileEntity(TileEntityCreativeCache.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CREATIVECACHE));

		GameRegistry.registerTileEntity(TileEntityConveyor.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CONVEYOR));
		GameRegistry.registerTileEntity(TileEntityConveyorHopper.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CONVEYOR_HOPPER));
		GameRegistry.registerTileEntity(TileEntityConveyorProcessor.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CONVEYOR_PROCESSOR));
		GameRegistry.registerTileEntity(TileEntityConveyorItemBag.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CONVEYOR_ITEMBAG));
		GameRegistry.registerTileEntity(TileEntityConveyorTrashCan.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CONVEYOR_TRASHCAN));
		GameRegistry.registerTileEntity(TileEntityConveyorSieve.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CONVEYOR_SIEVE));
		GameRegistry.registerTileEntity(TileEntityConveyorElevator.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CONVEYOR_ELEVATOR));

		GameRegistry.registerTileEntity(ApplianceSprayer.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_APPLIANCE_SPRAYER));
		GameRegistry.registerTileEntity(ApplianceAligner.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_APPLIANCE_ALIGNER));

		GameRegistry.registerTileEntity(TileEntityCreativeWell.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_CREATIVEWELL));

		/*
		 * Multiparts
		 */

		GameRegistry.registerTileEntity(MachineTileEntity.class, new ResourceLocation(Taam.MOD_ID, Taam.TILEENTITY_MACHINE_WRAPPER));

		if (Config.multipart_load) {
			MultipartHandler.registerMultipartStuff();
		}

		/*
		 * Wrapper block for machines
		 */
		registerBlock(
				blockMachine = new MachineBlock(),
				Taam.BLOCK_MACHINE_WRAPPER
		);
		registerItem(itemMachine = new MachineItemBlock(blockMachine), Taam.BLOCK_MACHINE_WRAPPER);

		/*
		 * Worldgen
		 */

		OreGenerator worldgen = new OreGenerator();
		MinecraftForge.EVENT_BUS.register(worldgen);

		GameRegistry.registerWorldGenerator(worldgen, 2);

		/*
		 * Fluids
		 */

		//TODO: Move this to the config
		boolean registerFluidBlocks = true;

		Taam.FLUID_DYE_META[] fluidsDyeValues = Taam.FLUID_DYE_META.values();
		fluidsDye = new FluidDye[fluidsDyeValues.length];
		blocksFluidDye = new BlockFluidClassic[fluidsDyeValues.length];

		for (int i = 0; i < fluidsDyeValues.length; i++) {
			fluidsDye[i] = new FluidDye(Taam.FLUID_DYE + fluidsDyeValues[i].name());
			FluidRegistry.registerFluid(fluidsDye[i]);
			FluidRegistry.addBucketForFluid(fluidsDye[i]);

			if (registerFluidBlocks) {
				BlockFluidClassic fluidBlock = new BlockFluidClassic(fluidsDye[i], Material.WATER) {
					@SuppressWarnings("deprecation") // Deprecation: overriding/implementing is fine
					@Override
					public boolean shouldSideBeRendered(@Nonnull IBlockState state, IBlockAccess world, BlockPos pos, @Nonnull EnumFacing side) {
						IBlockState neighbor = world.getBlockState(pos.offset(side));
						// Force rendering if there is a different block adjacent, not only a different material
						if (neighbor.getBlock() != this) {
							return true;
						}
						return super.shouldSideBeRendered(state, world, pos, side);
					}
				};
				String blockName = "fluid.dye." + fluidsDyeValues[i].name();
				registerBlock(
						fluidBlock,
						new ItemBlock(fluidBlock),
						blockName);
				blocksFluidDye[i] = fluidBlock;
			}

		}

		Taam.FLUID_MATERIAL_META[] fluidsMaterialValues = Taam.FLUID_MATERIAL_META.values();
		fluidsMaterial = new FluidMaterial[fluidsMaterialValues.length];
		blocksFluidMaterial = new BlockFluidFinite[fluidsMaterialValues.length];

		for (int i = 0; i < fluidsMaterialValues.length; i++) {
			fluidsMaterial[i] = new FluidMaterial(fluidsMaterialValues[i]);
			FluidRegistry.registerFluid(fluidsMaterial[i]);
			FluidRegistry.addBucketForFluid(fluidsMaterial[i]);

			if (registerFluidBlocks) {
				BlockFluidFinite fluidBlock = new BlockFluidFinite(fluidsMaterial[i], Material.WATER) {
					@SuppressWarnings("deprecation") // Deprecation: overriding/implementing is fine
					@Override
					public boolean shouldSideBeRendered(@Nonnull IBlockState state, IBlockAccess world, BlockPos pos, @Nonnull EnumFacing side) {
						IBlockState neighbor = world.getBlockState(pos.offset(side));
						// Force rendering if there is a different block adjacent, not only a different material
						if (neighbor.getBlock() != this) {
							return true;
						}
						return super.shouldSideBeRendered(state, world, pos, side);
					}
				};
				if (fluidsMaterialValues[i] == FLUID_MATERIAL_META.coating) {
					fluidBlock.setQuantaPerBlock(2);
				} else {
					fluidBlock.setQuantaPerBlock(1);
				}
				String blockName = "fluid.material." + fluidsMaterialValues[i].name();
				registerBlock(
						fluidBlock,
						new ItemBlock(fluidBlock),
						blockName);
				blocksFluidMaterial[i] = fluidBlock;
			}
		}

		/*
		 * Capabilities
		 */
		registerCapabilities();
		validateCapabilities();

		network = NetworkRegistry.INSTANCE.newSimpleChannel(Taam.CHANNEL_NAME);
		proxy.registerPackets(network);

		/*
		Early registration of model loader
		 */
		proxy.registerModelLoader();
	}

	public static void registerCapabilities() {
		CapabilityManager.INSTANCE.register(IPipe.class, new Capability.IStorage<IPipe>() {

			@Override
			public NBTBase writeNBT(Capability<IPipe> capability, IPipe instance, EnumFacing side) {
				// This is not a capability that can be saved to NBT
				return null;
			}

			@Override
			public void readNBT(Capability<IPipe> capability, IPipe instance, EnumFacing side, NBTBase nbt) {
				// This is not a capability that can be saved to NBT
			}

		}, () -> null);
		CapabilityManager.INSTANCE.register(TankRenderInfo[].class, new Capability.IStorage<TankRenderInfo[]>() {

			@Override
			public NBTBase writeNBT(Capability<TankRenderInfo[]> capability, TankRenderInfo[] instance, EnumFacing side) {
				// This is not a capability that can be saved to NBT
				return null;
			}

			@Override
			public void readNBT(Capability<TankRenderInfo[]> capability, TankRenderInfo[] instance, EnumFacing side, NBTBase nbt) {
				// This is not a capability that can be saved to NBT
			}

		}, () -> new TankRenderInfo[0]);

		CapabilityManager.INSTANCE.register(IConveyorSlots.class, new Capability.IStorage<IConveyorSlots>() {

			@Override
			public NBTBase writeNBT(Capability<IConveyorSlots> capability, IConveyorSlots instance, EnumFacing side) {
				if (instance instanceof ConveyorSlotsStandard) {
					return ((ConveyorSlotsStandard) instance).serializeNBT();
				}
				throw new NotImplementedException("Cannot save a generic IConveyorSlots instance to NBT. Only ConveyorSlotsStandard is supported.");
			}

			@Override
			public void readNBT(Capability<IConveyorSlots> capability, IConveyorSlots instance, EnumFacing side,
			                    NBTBase nbt) {
				if (instance instanceof ConveyorSlotsStandard) {
					((ConveyorSlotsStandard) instance).deserializeNBT((NBTTagList) nbt);
				}
				throw new NotImplementedException("Cannot read a generic IConveyorSlots instance from NBT. Only ConveyorSlotsStandard is supported.");

			}

		}, ConveyorSlotsStandard::new);

		CapabilityManager.INSTANCE.register(IAdvancedMachineGUI.class, new Capability.IStorage<IAdvancedMachineGUI>() {

			@Override
			public NBTBase writeNBT(Capability<IAdvancedMachineGUI> capability, IAdvancedMachineGUI instance, EnumFacing side) {
				// This is not a capability that can be saved to NBT
				return null;
			}

			@Override
			public void readNBT(Capability<IAdvancedMachineGUI> capability, IAdvancedMachineGUI instance, EnumFacing side, NBTBase nbt) {
				// This is not a capability that can be saved to NBT
			}
		}, () -> null);
	}

	/**
	 * Check if registry of capabilities was successful
	 */
	public static void validateCapabilities() {
		if (Taam.CAPABILITY_PIPE == null) {
			throw new IllegalStateException("Registering a capability failed (Taam.CAPABILITY_PIPE - IPipe) - field was null after registry.");
		}
		if (Taam.CAPABILITY_RENDER_TANK == null) {
			throw new IllegalStateException("Registering a capability failed (Taam.CAPABILITY_RENDER_TANK - TankRenderInfo[]) - field was null after registry.");
		}
		if (Taam.CAPABILITY_CONVEYOR == null) {
			throw new IllegalStateException("Registering a capability failed (Taam.CAPABILITY_CONVEYOR - IConveyorSlots) - field was null after registry.");
		}
		if (Taam.CAPABILITY_ADVANCED_GUI == null) {
			throw new IllegalStateException("Registering a capability failed (Taam.CAPABILITY_ADVANCED_GUI - IAdvancedMachineGUI) - field was null after registry.");
		}
	}

	@SubscribeEvent
	public void registerRecipes(RegistryEvent.Register<IRecipe> event) {

		// Machine Recipes
		TaamRecipesCrusher.registerRecipes();
		TaamRecipesFluidDrier.registerRecipes();
		TaamRecipesGrinder.registerRecipes();
		TaamRecipesMixer.registerRecipes();
		TaamRecipesSprayer.registerRecipes();

		// Smelting & Crafting
		TaamRecipes.registerSmeltingRecipes();
		TaamRecipes.registerCraftingRecipes();

		// Compat Recipes -> in postInit to catch as many recipes as possible
		TaamRecipeCompat.registerRecipes();
	}

	@SubscribeEvent
	public void registerSounds(RegistryEvent.Register<SoundEvent> event) {
		event.getRegistry().register(soundSipAh = new SoundEvent(Taam.SOUND_SIP_AH).setRegistryName(Taam.SOUND_SIP_AH));
	}

	@EventHandler
	public void init(FMLInitializationEvent event) {
		/*
		 * Rendering & GUI
		 */

		proxy.registerRenderStuff();
		NetworkRegistry.INSTANCE.registerGuiHandler(this, new GuiHandler());

		/*
		 * Recipe Stuff
		 */

		// Register things with the ore dictionary
		oreRegistration();
	}

	public static void oreRegistration() {
		OreDictionary.registerOre("oreCopper", new ItemStack(blockOre, 1, Taam.BLOCK_ORE_META.copper.ordinal()));
		OreDictionary.registerOre("oreTin", new ItemStack(blockOre, 1, Taam.BLOCK_ORE_META.tin.ordinal()));
		OreDictionary.registerOre("oreAluminum", new ItemStack(blockOre, 1, Taam.BLOCK_ORE_META.aluminum.ordinal()));
		OreDictionary.registerOre("oreBauxite", new ItemStack(blockOre, 1, Taam.BLOCK_ORE_META.bauxite.ordinal()));
		OreDictionary.registerOre("oreKaolinite", new ItemStack(blockOre, 1, Taam.BLOCK_ORE_META.kaolinite.ordinal()));

		OreDictionary.registerOre("ingotCopper", new ItemStack(itemIngot, 1, Taam.BLOCK_ORE_META.copper.ordinal()));
		OreDictionary.registerOre("ingotTin", new ItemStack(itemIngot, 1, Taam.BLOCK_ORE_META.tin.ordinal()));
		OreDictionary.registerOre("ingotAluminum", new ItemStack(itemIngot, 1, Taam.BLOCK_ORE_META.aluminum.ordinal()));

		OreDictionary.registerOre("dustIron", new ItemStack(itemDust, 1, Taam.BLOCK_ORE_META.iron.ordinal()));
		OreDictionary.registerOre("dustCopper", new ItemStack(itemDust, 1, Taam.BLOCK_ORE_META.copper.ordinal()));
		OreDictionary.registerOre("dustTin", new ItemStack(itemDust, 1, Taam.BLOCK_ORE_META.tin.ordinal()));
		OreDictionary.registerOre("dustAluminum", new ItemStack(itemDust, 1, Taam.BLOCK_ORE_META.aluminum.ordinal()));
		OreDictionary.registerOre("dustBauxite", new ItemStack(itemDust, 1, Taam.BLOCK_ORE_META.bauxite.ordinal()));
		OreDictionary.registerOre("dustKaolinite", new ItemStack(itemDust, 1, Taam.BLOCK_ORE_META.kaolinite.ordinal()));
		OreDictionary.registerOre("dustGold", new ItemStack(itemDust, 1, Taam.BLOCK_ORE_META.gold.ordinal()));
		OreDictionary.registerOre("dustCoal", new ItemStack(itemDust, 1, Taam.BLOCK_ORE_META.coal.ordinal()));
		OreDictionary.registerOre("dustStone", new ItemStack(itemDust, 1, Taam.BLOCK_ORE_META.stone.ordinal()));

		OreDictionary.registerOre("nuggetIron", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.iron_nugget.ordinal()));
		OreDictionary.registerOre("nuggetCopper", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.copper_nugget.ordinal()));
		OreDictionary.registerOre("nuggetAluminum", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.aluminum_nugget.ordinal()));
		OreDictionary.registerOre("nuggetTin", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.tin_nugget.ordinal()));

		OreDictionary.registerOre("materialPlastic", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.plastic_sheet.ordinal()));
		OreDictionary.registerOre("materialRubber", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.rubber_bar.ordinal()));
		OreDictionary.registerOre("itemRubber", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.rubber_bar.ordinal()));
		OreDictionary.registerOre("materialGraphite", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.graphite.ordinal()));
		OreDictionary.registerOre("materialSiliconWafer", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.silicon_wafer.ordinal()));
		OreDictionary.registerOre("materialResin", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.resin.ordinal()));
		OreDictionary.registerOre("materialCement", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.cement.ordinal()));
		OreDictionary.registerOre("materialRoughCement", new ItemStack(itemMaterial, 1, Taam.ITEM_MATERIAL_META.cementRough.ordinal()));

		OreDictionary.registerOre("partPhotocell", new ItemStack(itemPart, 1, Taam.ITEM_PART_META.photocell.ordinal()));
		OreDictionary.registerOre("partMotor", new ItemStack(itemPart, 1, Taam.ITEM_PART_META.motor.ordinal()));
		OreDictionary.registerOre("partBasicCircuit", new ItemStack(itemPart, 1, Taam.ITEM_PART_META.circuit_basic.ordinal()));
		OreDictionary.registerOre("partAdvancedCircuit", new ItemStack(itemPart, 1, Taam.ITEM_PART_META.circuit_advanced.ordinal()));

		String[] dyes = {
				"Black",
				"Red",
				"Green",
				"Brown",
				"Blue",
				"Purple",
				"Cyan",
				"LightGray",
				"Gray",
				"Pink",
				"Lime",
				"Yellow",
				"LightBlue",
				"Magenta",
				"Orange",
				"White"
		};

		int metaBlack = Taam.ITEM_MATERIAL_META.pigment_black.ordinal();
		for (int dyeMeta = 0; dyeMeta < 16; dyeMeta++) {

			OreDictionary.registerOre("dye" + dyes[dyeMeta], new ItemStack(TaamMain.itemMaterial, 1, metaBlack + dyeMeta));
		}
	}
}

redpajama_set_name: RedPajamaGithub


text:
namespace llvm {

class MCAssembler;
class MCContext;
class MCFixup;
class MCObjectWriter;
class MCSymbol;
class MCSymbolELF;
class MCValue;

struct ELFRelocationEntry {
  uint64_t Offset; // Where is the relocation.
  const MCSymbolELF *Symbol; // The symbol to relocate with.
  unsigned Type;   // The type of the relocation.
  uint64_t Addend; // The addend to use.
  const MCSymbolELF *OriginalSymbol; // The original value of Symbol if we changed it.
  uint64_t OriginalAddend; // The original value of addend.

  ELFRelocationEntry(uint64_t Offset, const MCSymbolELF *Symbol, unsigned Type,
                     uint64_t Addend, const MCSymbolELF *OriginalSymbol,
                     uint64_t OriginalAddend)
      : Offset(Offset), Symbol(Symbol), Type(Type), Addend(Addend),
        OriginalSymbol(OriginalSymbol), OriginalAddend(OriginalAddend) {}

  void print(raw_ostream &Out) const {
    Out << "Off=" << Offset << ", Sym=" << Symbol << ", Type=" << Type
        << ", Addend=" << Addend << ", OriginalSymbol=" << OriginalSymbol
        << ", OriginalAddend=" << OriginalAddend;
  }

  void dump() const { print(errs()); }
};

class MCELFObjectTargetWriter : public MCObjectTargetWriter {
  const uint8_t OSABI;
  const uint16_t EMachine;
  const unsigned HasRelocationAddend : 1;
  const unsigned Is64Bit : 1;

protected:
  MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_, uint16_t EMachine_,
                          bool HasRelocationAddend);

public:
  virtual ~MCELFObjectTargetWriter() = default;

  virtual Triple::ObjectFormatType getFormat() const { return Triple::ELF; }
  static bool classof(const MCObjectTargetWriter *W) {
    return W->getFormat() == Triple::ELF;
  }

  static uint8_t getOSABI(Triple::OSType OSType) {
    switch (OSType) {
      case Triple::CloudABI:
        return ELF::ELFOSABI_CLOUDABI;
      case Triple::PS4:
      case Triple::FreeBSD:
        return ELF::ELFOSABI_FREEBSD;
      default:
        return ELF::ELFOSABI_NONE;
    }
  }

  virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                                const MCFixup &Fixup, bool IsPCRel) const = 0;

  virtual bool needsRelocateWithSymbol(const MCSymbol &Sym,
                                       unsigned Type) const;

  virtual void sortRelocs(const MCAssembler &Asm,
                          std::vector<ELFRelocationEntry> &Relocs);

  /// \name Accessors
  /// @{
  uint8_t getOSABI() const { return OSABI; }
  uint16_t getEMachine() const { return EMachine; }
  bool hasRelocationAddend() const { return HasRelocationAddend; }
  bool is64Bit() const { return Is64Bit; }
  /// @}

  // Instead of changing everyone's API we pack the N64 Type fields
  // into the existing 32 bit data unsigned.
#define R_TYPE_SHIFT 0
#define R_TYPE_MASK 0xffffff00
#define R_TYPE2_SHIFT 8
#define R_TYPE2_MASK 0xffff00ff
#define R_TYPE3_SHIFT 16
#define R_TYPE3_MASK 0xff00ffff
#define R_SSYM_SHIFT 24
#define R_SSYM_MASK 0x00ffffff

  // N64 relocation type accessors
  uint8_t getRType(uint32_t Type) const {
    return (unsigned)((Type >> R_TYPE_SHIFT) & 0xff);
  }
  uint8_t getRType2(uint32_t Type) const {
    return (unsigned)((Type >> R_TYPE2_SHIFT) & 0xff);
  }
  uint8_t getRType3(uint32_t Type) const {
    return (unsigned)((Type >> R_TYPE3_SHIFT) & 0xff);
  }
  uint8_t getRSsym(uint32_t Type) const {
    return (unsigned)((Type >> R_SSYM_SHIFT) & 0xff);
  }

  // N64 relocation type setting
  unsigned setRType(unsigned Value, unsigned Type) const {
    return ((Type & R_TYPE_MASK) | ((Value & 0xff) << R_TYPE_SHIFT));
  }
  unsigned setRType2(unsigned Value, unsigned Type) const {
    return (Type & R_TYPE2_MASK) | ((Value & 0xff) << R_TYPE2_SHIFT);
  }
  unsigned setRType3(unsigned Value, unsigned Type) const {
    return (Type & R_TYPE3_MASK) | ((Value & 0xff) << R_TYPE3_SHIFT);
  }
  unsigned setRSsym(unsigned Value, unsigned Type) const {
    return (Type & R_SSYM_MASK) | ((Value & 0xff) << R_SSYM_SHIFT);
  }
};

/// Construct a new ELF writer instance.
///
/// \param MOTW - The target specific ELF writer subclass.
/// \param OS - The stream to write to.
/// \returns The constructed object writer.
std::unique_ptr<MCObjectWriter>
createELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
                      raw_pwrite_stream &OS, bool IsLittleEndian);

std::unique_ptr<MCObjectWriter>
createELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
                         raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
                         bool IsLittleEndian);

} // end namespace llvm

#endif // LLVM_MC_MCELFOBJECTWRITER_H


text:
/**
 * Forge SDK
 * The Forge Platform contains an expanding collection of web service components that can be used with Autodesk cloud-based products or your own technologies. Take advantage of Autodesk's expertise in design and engineering.
 *
 * Contact: forge.help@autodesk.com
 *
 * NOTE: This class is auto generated by the swagger code generator program.
 * https://github.com/swagger-api/swagger-codegen.git
 * Do not edit the class manually.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = (function () {
  'use strict';

  var ApiClient = require('../ApiClient');

  /**
   * The JobObjOutputPayloadAdvanced model module.
   * @module model/JobObjOutputPayloadAdvanced
   */

  /**
   * Constructs a JobObjOutputPayloadAdvanced from a plain JavaScript object, optionally creating a new instance.
   * Copies all relevant properties from data to obj if supplied or a new instance if not.
   * @param {Object} data The plain JavaScript object bearing properties of interest.
   * @param {module:model/JobObjOutputPayloadAdvanced} obj Optional instance to populate.
   * @return {module:model/JobObjOutputPayloadAdvanced} The populated JobObjOutputPayloadAdvanced instance.
   */
  var constructFromObject = function (data, obj) {
    if (data) {
      obj = obj || new exports();

      if (data.hasOwnProperty('exportFileStructure'))
        obj.exportFileStructure = ApiClient.convertToType(data.exportFileStructure, 'String');
      if (data.hasOwnProperty('modelGuid'))
        obj.modelGuid = ApiClient.convertToType(data.modelGuid, 'String');
      if (data.hasOwnProperty('objectIds'))
        obj.objectIds = ApiClient.convertToType(data.objectIds, ['Integer']);
      if (data.hasOwnProperty('unit'))
        obj.unit = ApiClient.convertToType(data.unit, 'String');
    }
    return obj;
  };

  /**
   * Constructs a new JobObjOutputPayloadAdvanced.
   * Advanced options for `obj` type.
   * @alias module:model/JobObjOutputPayloadAdvanced
   * @class
   * @param {Object} theData The plain JavaScript object bearing properties of interest.
   * @param {module:model/JobObjOutputPayloadAdvanced} obj Optional instance to populate.
   */
  var exports = function (theData, obj) {
    var _this = this;

    return constructFromObject(theData, obj || _this);
  };

  /**
   * Constructs a JobObjOutputPayloadAdvanced from a plain JavaScript object, optionally creating a new instance.
   * Copies all relevant properties from data to obj if supplied or a new instance if not.
   * @param {Object} data The plain JavaScript object bearing properties of interest.
   * @param {module:model/JobObjOutputPayloadAdvanced} obj Optional instance to populate.
   * @return {module:model/JobObjOutputPayloadAdvanced} The populated JobObjOutputPayloadAdvanced instance.
   */
  exports.constructFromObject = constructFromObject;

  /**
   * `single` (default): creates one OBJ file for all the input files (assembly file)  `multiple`: creates a separate OBJ file for each object
   * @member {module:model/JobObjOutputPayloadAdvanced.ExportFileStructureEnum} exportFileStructure
   * @default 'single'
   */
  exports.prototype.exportFileStructure = 'single';

  /**
   * Required for geometry extractions. The model view ID (guid).
   * @member {String} modelGuid
   */
  exports.prototype.modelGuid = undefined;

  /**
   * Required for geometry extractions. List object ids to be translated. -1 will extract the entire model.
   * @member {Array.<Integer>} objectIds
   */
  exports.prototype.objectIds = undefined;

  /**
   * Translate models into different units; this causes the values to change. For example, from millimeters (10, 123, 31) to centimeters (1.0, 12.3, 3.1). If the source unit or the unit you are translating into is not supported, the values remain unchanged.
   * Possible values: meter, decimeter, centimeter, millimeter, micrometer, nanometer, yard, foot, inch, mil, microinch
   * Note that this feature does not support F3D files.
   * @member {module:model/JobObjOutputPayloadAdvanced.UnitEnum} unit
   */
  exports.prototype.unit = undefined;

  /**
   * Allowed values for the exportFileStructure property.
   * @enum {String}
   * @readonly
   */
  exports.ExportFileStructureEnum = {
    /**
     * value: "single"
     * @const
     */
    "single": "single",
    /**
     * value: "multiple"
     * @const
     */
    "multiple": "multiple"
  };

  /**
     * Allowed values for the unit property.
     * @enum {String}
     * @readonly
     */
  exports.UnitEnum = {
    /**
     * value: "meter"
     * @const
     */
    "meter": "meter",
    /**
     * value: "decimeter"
     * @const
     */
    "decimeter": "decimeter",
    /**
     * value: "centimeter"
     * @const
     */
    "centimeter": "centimeter",
    /**
     * value: "millimeter"
     * @const
     */
    "millimeter": "millimeter",
    /**
     * value: "micrometer"
     * @const
     */
    "micrometer": "micrometer",
    /**
     * value: "nanometer"
     * @const
     */
    "nanometer": "nanometer",
    /**
     * value: "yard"
     * @const
     */
    "yard": "yard",
    /**
     * value: "foot"
     * @const
     */
    "foot": "foot",
    /**
     * value: "inch"
     * @const
     */
    "inch": "inch",
    /**
     * value: "mil"
     * @const
     */
    "mil": "mil",
    /**
     * value: "microinch"
     * @const
     */
    "microinch": "microinch",
  };

  return exports;
}());


text:
import sys
try:
    import readline
except ImportError:
    import pyreadline as readline
import os

import code
import rlcompleter

lib_path = os.path.abspath(os.path.join('..', 'src'))
sys.path.append(lib_path)

lib_path = os.path.abspath(os.path.join('..', '..', 'ARSDKBuildUtils', 'Utils', 'Python'))
sys.path.append(lib_path)

from Bybop_Discovery import *
import Bybop_Device

print('Searching for devices')

from zeroconf import ZeroconfServiceTypes
print('\n'.join(ZeroconfServiceTypes.find()))
print('done.')

discovery = Discovery([DeviceID.BEBOP_DRONE, DeviceID.JUMPING_SUMO, DeviceID.AIRBORNE_NIGHT, DeviceID.JUMPING_NIGHT])

discovery.wait_for_change()

devices = discovery.get_devices()

#discovery.stop()

if not devices:
    print('Oops ...')
    sys.exit(1)

device = devices.itervalues().next()

print('Will connect to ' + get_name(device))

d2c_port = 43210
controller_type = "PC"
controller_name = "bybop shell"

drone = Bybop_Device.create_and_connect(device, d2c_port, controller_type, controller_name)

if drone is None:
    print('Unable to connect to a product')
    sys.exit(1)

drone.dump_state()

vars = globals().copy()
vars.update(locals())
readline.set_completer(rlcompleter.Completer(vars).complete)
readline.parse_and_bind("tab: complete")
shell = code.InteractiveConsole(vars)

# drone.jump(0)  # jump forward
# drone.jump(1)  # jump up
# drone.move_forward(20)  # move forwards
# drone.move_forward(-20)  # move backwards
# drone.move(0,50)  # turn right?
# drone.move(0,-50)  # turn left?
# drone.spin() # spin around
# drone.simpleAnimation(0)
# drone.simpleAnimation(9)
# Currently known values:
#         - 0 : stop
#         - 1 : spin
#         - 2 : tap
#         - 3 : slowshake
#         - 4 : metronome
#         - 5 : ondulation
#         - 6 : spinjump
#         - 7 : spintoposture
#         - 8 : spiral
#         - 9 : slalom
#         """

shell.interact()
drone.stop()


text:
@interface NavEmptyViewController : BaseViewController

@end


text:
package swagger

type ActivationCondition struct {
	Typ              string  `json:"type,omitempty"`
	TrailingValue    float64 `json:"trailing_value,omitempty"`
	TriggerValue     float64 `json:"trigger_value,omitempty"`
	TriggerCondition string  `json:"trigger_condition,omitempty"`
}


text:
package retrofit2.adapter.rxjava2;

import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.Scheduler;
import io.reactivex.Single;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import retrofit2.CallAdapter;
import retrofit2.Response;
import retrofit2.Retrofit;

/**
 * A {@linkplain CallAdapter.Factory call adapter} which uses RxJava 2 for creating observables.
 *

 * Adding this class to {@link Retrofit} allows you to return an {@link Observable},
 * {@link Flowable}, {@link Single}, {@link Completable} or {@link Maybe} from service methods.
 *

 * interface MyService {
 *   @GET("user/me")
 *   Observable<User> getUser()
 * }
 *

 * There are three configurations supported for the {@code Observable}, {@code Flowable},
 * {@code Single}, {@link Completable} and {@code Maybe} type parameter:
 *

 *
Direct body (e.g., {@code Observable<User>}) calls {@code onNext} with the deserialized body
 * for 2XX responses and calls {@code onError} with {@link HttpException} for non-2XX responses and
 * {@link IOException} for network errors.

 *
Response wrapped body (e.g., {@code Observable<Response<User>>}) calls {@code onNext}
 * with a {@link Response} object for all HTTP responses and calls {@code onError} with
 * {@link IOException} for network errors

 *
Result wrapped body (e.g., {@code Observable<Result<User>>}) calls {@code onNext} with a
 * {@link Result} object for all HTTP responses and errors.

 *

 */
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
  /**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default.
   */
  public static RxJava2CallAdapterFactory create() {
    return new RxJava2CallAdapterFactory(null, false);
  }

  /**
   * Returns an instance which creates asynchronous observables. Applying
   * {@link Observable#subscribeOn} has no effect on stream types created by this factory.
   */
  public static RxJava2CallAdapterFactory createAsync() {
    return new RxJava2CallAdapterFactory(null, true);
  }

  /**
   * Returns an instance which creates synchronous observables that
   * {@linkplain Observable#subscribeOn(Scheduler) subscribe on} {@code scheduler} by default.
   */
  public static RxJava2CallAdapterFactory createWithScheduler(Scheduler scheduler) {
    if (scheduler == null) throw new NullPointerException("scheduler == null");
    return new RxJava2CallAdapterFactory(scheduler, false);
  }

  private final Scheduler scheduler;
  private final boolean isAsync;

  private RxJava2CallAdapterFactory(Scheduler scheduler, boolean isAsync) {
    this.scheduler = scheduler;
    this.isAsync = isAsync;
  }

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);

    if (rawType == Completable.class) {
      // Completable is not parameterized (which is what the rest of this method deals with) so it
      // can only be created with a single configuration.
      return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
          false, true);
    }

    boolean isFlowable = rawType == Flowable.class;
    boolean isSingle = rawType == Single.class;
    boolean isMaybe = rawType == Maybe.class;
    if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
      return null;
    }

    boolean isResult = false;
    boolean isBody = false;
    Type responseType;
    if (!(returnType instanceof ParameterizedType)) {
      String name = isFlowable ? "Flowable"
          : isSingle ? "Single"
          : isMaybe ? "Maybe" : "Observable";
      throw new IllegalStateException(name + " return type must be parameterized"
          + " as " + name + "<Foo> or " + name + "<? extends Foo>");
    }

    Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
    Class<?> rawObservableType = getRawType(observableType);
    if (rawObservableType == Response.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Response must be parameterized"
            + " as Response<Foo> or Response<? extends Foo>");
      }
      responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
    } else if (rawObservableType == Result.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Result must be parameterized"
            + " as Result<Foo> or Result<? extends Foo>");
      }
      responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
      isResult = true;
    } else {
      responseType = observableType;
      isBody = true;
    }

    return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
        isSingle, isMaybe, false);
  }
}