public String getRecipeName() { if (this.displayItem == null) { return "Documentation"; } final String s = Item.itemRegistry.getNameForObject((Object)this.displayItem.getItem()); final String modid = s.split(":")[0]; if ("minecraft".equals(modid)) { return "Minecraft"; } final ModContainer selectedMod = Loader.instance().getIndexedModList().get(modid); if (selectedMod == null) { return modid; } if (!selectedMod.getMetadata().autogenerated) { return selectedMod.getMetadata().name; } return selectedMod.getName(); }
public static String channelName(Object channelKey) { if (channelKey instanceof String) return (String) channelKey; if (channelKey instanceof ModContainer) { String s = ((ModContainer) channelKey).getModId(); if(s.length() > 20) throw new IllegalArgumentException("Mod ID ("+s+") too long for use as channel (20 chars). Use a string identifier"); return s; } ModContainer mc = FMLCommonHandler.instance().findContainerFor(channelKey); if (mc != null) return mc.getModId(); throw new IllegalArgumentException("Invalid channel: " + channelKey); }
private static void parseModItems() { HashMap<String, ItemStackSet> modSubsets = new HashMap<String, ItemStackSet>(); for (Item item : (Iterable<Item>) Item.itemRegistry) { UniqueIdentifier ident = GameRegistry.findUniqueIdentifierFor(item); if(ident == null) { NEIClientConfig.logger.error("Failed to find identifier for: "+item); continue; } String modId = GameRegistry.findUniqueIdentifierFor(item).modId; itemOwners.put(item, modId); ItemStackSet itemset = modSubsets.get(modId); if(itemset == null) modSubsets.put(modId, itemset = new ItemStackSet()); itemset.with(item); } API.addSubset("Mod.Minecraft", modSubsets.remove("minecraft")); for(Entry<String, ItemStackSet> entry : modSubsets.entrySet()) { ModContainer mc = FMLCommonHandler.instance().findContainerFor(entry.getKey()); if(mc == null) NEIClientConfig.logger.error("Missing container for "+entry.getKey()); else API.addSubset("Mod."+mc.getName(), entry.getValue()); } }
@Override protected void drawSlot(int listIndex, int var2, int var3, int var4, Tessellator var5) { ModContainer mc=mods.get(listIndex); if (Loader.instance().getModState(mc)==ModState.DISABLED) { this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getName(), listWidth - 10), this.left + 3 , var3 + 2, 0xFF2222); this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getDisplayVersion(), listWidth - 10), this.left + 3 , var3 + 12, 0xFF2222); this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a("DISABLED", listWidth - 10), this.left + 3 , var3 + 22, 0xFF2222); } else { this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getName(), listWidth - 10), this.left + 3 , var3 + 2, 0xFFFFFF); this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getDisplayVersion(), listWidth - 10), this.left + 3 , var3 + 12, 0xCCCCCC); this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getMetadata() !=null ? mc.getMetadata().getChildModCountString() : "Metadata not found", listWidth - 10), this.left + 3 , var3 + 22, 0xCCCCCC); } }
@Override public void func_73863_a(int p_73863_1_, int p_73863_2_, float p_73863_3_) { this.func_146276_q_(); int offset = Math.max(85 - dupes.dupes.size() * 10, 10); this.func_73732_a(this.field_146289_q, "Forge Mod Loader has found a problem with your minecraft installation", this.field_146294_l / 2, offset, 0xFFFFFF); offset+=10; this.func_73732_a(this.field_146289_q, "You have mod sources that are duplicate within your system", this.field_146294_l / 2, offset, 0xFFFFFF); offset+=10; this.func_73732_a(this.field_146289_q, "Mod Id : File name", this.field_146294_l / 2, offset, 0xFFFFFF); offset+=5; for (Entry<ModContainer, File> mc : dupes.dupes.entries()) { offset+=10; this.func_73732_a(this.field_146289_q, String.format("%s : %s", mc.getKey().getModId(), mc.getValue().getName()), this.field_146294_l / 2, offset, 0xEEEEEE); } }
@SuppressWarnings("unchecked") @Override public void func_73866_w_() { for (ModContainer mod : mods) { listWidth=Math.max(listWidth,getFontRenderer().func_78256_a(mod.getName()) + 10); listWidth=Math.max(listWidth,getFontRenderer().func_78256_a(mod.getVersion()) + 10); } listWidth=Math.min(listWidth, 150); this.field_146292_n.add(new GuiButton(6, this.field_146294_l / 2 - 75, this.field_146295_m - 38, I18n.func_135052_a("gui.done"))); configModButton = new GuiButton(20, 10, this.field_146295_m - 60, this.listWidth, 20, "Config"); disableModButton = new GuiButton(21, 10, this.field_146295_m - 38, this.listWidth, 20, "Disable"); this.field_146292_n.add(configModButton); this.field_146292_n.add(disableModButton); this.modList=new GuiSlotModList(this, mods, listWidth); this.modList.registerScrollButtons(this.field_146292_n, 7, 8); }
@Override public void func_73863_a(int p_73863_1_, int p_73863_2_, float p_73863_3_) { this.func_146276_q_(); int offset = Math.max(85 - (failedList.getVisitedNodes().size() + 3) * 10, 10); this.func_73732_a(this.field_146289_q, "Forge Mod Loader has found a problem with your minecraft installation", this.field_146294_l / 2, offset, 0xFFFFFF); offset+=10; this.func_73732_a(this.field_146289_q, "A mod sorting cycle was detected and loading cannot continue", this.field_146294_l / 2, offset, 0xFFFFFF); offset+=10; this.func_73732_a(this.field_146289_q, String.format("The first mod in the cycle is %s", failedList.getFirstBadNode()), this.field_146294_l / 2, offset, 0xFFFFFF); offset+=10; this.func_73732_a(this.field_146289_q, "The remainder of the cycle involves these mods", this.field_146294_l / 2, offset, 0xFFFFFF); offset+=5; for (ModContainer mc : failedList.getVisitedNodes()) { offset+=10; this.func_73732_a(this.field_146289_q, String.format("%s : before: %s, after: %s", mc.toString(), mc.getDependants(), mc.getDependencies()), this.field_146294_l / 2, offset, 0xEEEEEE); } offset+=20; this.func_73732_a(this.field_146289_q, "The file 'ForgeModLoader-client-0.log' contains more information", this.field_146294_l / 2, offset, 0xFFFFFF); }
public static String checkModList(Map<String,String> listData, Side side) { List<ModContainer> rejects = Lists.newArrayList(); for (Entry<ModContainer, NetworkModHolder> networkMod : NetworkRegistry.INSTANCE.registry().entrySet()) { boolean result = networkMod.getValue().check(listData, side); if (!result) { rejects.add(networkMod.getKey()); } } if (rejects.isEmpty()) { return null; } else { FMLLog.info("Rejecting connection %s: %s", side, rejects); return String.format("Mod rejections %s",rejects); } }
/** * INTERNAL Create a new channel pair with the specified name and channel handlers. * This is used internally in forge and FML * * @param container The container to associate the channel with * @param name The name for the channel * @param handlers Some {@link ChannelHandler} for the channel * @return an {@link EnumMap} of the pair of channels. keys are {@link Side}. There will always be two entries. */ public EnumMap<Side,FMLEmbeddedChannel> newChannel(ModContainer container, String name, ChannelHandler... handlers) { if (channels.containsKey(name) || name.startsWith("MC|") || name.startsWith("\u0001") || (name.startsWith("FML") && !("FML".equals(container.getModId())))) { throw new RuntimeException("That channel is already registered"); } EnumMap<Side,FMLEmbeddedChannel> result = Maps.newEnumMap(Side.class); for (Side side : Side.values()) { FMLEmbeddedChannel channel = new FMLEmbeddedChannel(container, name, side, handlers); channels.get(side).put(name,channel); result.put(side, channel); } return result; }
private void register(Class<?> eventType, Object target, Method method, ModContainer owner) { try { Constructor<?> ctr = eventType.getConstructor(); ctr.setAccessible(true); Event event = (Event)ctr.newInstance(); ASMEventHandler listener = new ASMEventHandler(target, method, owner); event.getListenerList().register(busID, listener.getPriority(), listener); ArrayList<IEventListener> others = listeners.get(target); if (others == null) { others = new ArrayList<IEventListener>(); listeners.put(target, others); } others.add(listener); } catch (Exception e) { e.printStackTrace(); } }
/** * Prefix the supplied name with the current mod id. * * If no mod id can be determined, minecraft will be assumed. * The prefix is separated with a colon. * * If there's already a prefix, it'll be prefixed again if the new prefix * doesn't match the old prefix, as used by vanilla calls to addObject. * * @param name name to prefix. * @return prefixed name. */ private String addPrefix(String name) { int index = name.lastIndexOf(':'); String oldPrefix = index == -1 ? "" : name.substring(0, index); String prefix; ModContainer mc = Loader.instance().activeModContainer(); if (mc != null) { prefix = mc.getModId(); } else // no mod container, assume minecraft { prefix = "minecraft"; } if (!oldPrefix.equals(prefix)) { name = prefix + ":" + name; } return name; }
public static void registerGlobalEntityID(Class <? extends Entity > entityClass, String entityName, int id) { if (EntityList.field_75626_c.containsKey(entityClass)) { ModContainer activeModContainer = Loader.instance().activeModContainer(); String modId = "unknown"; if (activeModContainer != null) { modId = activeModContainer.getModId(); } else { FMLLog.severe("There is a rogue mod failing to register entities from outside the context of mod loading. This is incredibly dangerous and should be stopped."); } FMLLog.warning("The mod %s tried to register the entity class %s which was already registered - if you wish to override default naming for FML mod entities, register it here first", modId, entityClass); return; } id = instance().validateAndClaimId(id); EntityList.func_75618_a(entityClass, entityName, id); }
public static void registerGlobalEntityID(Class <? extends Entity > entityClass, String entityName, int id, int backgroundEggColour, int foregroundEggColour) { if (EntityList.field_75626_c.containsKey(entityClass)) { ModContainer activeModContainer = Loader.instance().activeModContainer(); String modId = "unknown"; if (activeModContainer != null) { modId = activeModContainer.getModId(); } else { FMLLog.severe("There is a rogue mod failing to register entities from outside the context of mod loading. This is incredibly dangerous and should be stopped."); } FMLLog.warning("The mod %s tried to register the entity class %s which was already registered - if you wish to override default naming for FML mod entities, register it here first", modId, entityClass); return; } instance().validateAndClaimId(id); EntityList.func_75614_a(entityClass, entityName, id, backgroundEggColour, foregroundEggColour); }
/** * Deprecated for removal in 1.8. Use the assets lang system */ @Deprecated public void loadLocalization(String localizationFile, String lang, boolean isXML) { URL urlResource = this.getClass().getResource(localizationFile); if (urlResource != null) { loadLocalization(urlResource, lang, isXML); } else { ModContainer activeModContainer = Loader.instance().activeModContainer(); if (activeModContainer!=null) { FMLLog.log(activeModContainer.getModId(), Level.ERROR, "The language resource %s cannot be located on the classpath. This is a programming error.", localizationFile); } else { FMLLog.log(Level.ERROR, "The language resource %s cannot be located on the classpath. This is a programming error.", localizationFile); } } }
public void loadLanguagesFor(ModContainer container, Side side) { File source = container.getSource(); try { if (source.isDirectory()) { searchDirForLanguages(source, "", side); } else { searchZipForLanguages(source, side); } } catch (IOException ioe) { } }
public static Ticket requestPlayerTicket(Object mod, String player, World world, Type type) { ModContainer mc = getContainer(mod); if (mc == null) { FMLLog.log(Level.ERROR, "Failed to locate the container for mod instance %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod)); return null; } if (playerTickets.get(player).size()>playerTicketLength) { FMLLog.warning("Unable to assign further chunkloading tickets to player %s (on behalf of mod %s)", player, mc.getModId()); return null; } Ticket ticket = new Ticket(mc.getModId(),type,world,player); playerTickets.put(player, ticket); tickets.get(world).put("Forge", ticket); return ticket; }
private void packMod(ModContainer mod) throws Exception{ String modPath = modCache.toAbsolutePath().toString() + File.separator + Utils.getFilename(mod.getModId(), mod.getVersion()); if(new File(modPath + ".zip").exists()) return; FileOutputStream fos = new FileOutputStream(modPath + ".zip"); ZipOutputStream zos = new ZipOutputStream(fos); File src = mod.getSource(); String fname = "mods/" + src.getName(); if("Forge".equals(mod.getModId())) fname = "bin/modpack.jar"; zos.putNextEntry(new ZipEntry(fname)); Files.copy(src.toPath(), zos); zos.closeEntry(); zos.close(); fos.close(); }
/** * @category InternalMethods * THIS METHOD IS FOR INTERNAL USE ONLY * DO NOT USE */ public void registerPlugins() { eaLuaDir.mkdir(); for(ModContainer container : Loader.instance().getModList()) { if(container.getMod() instanceof EAPlugin) { EAPluginContainer pluginContainer = new EAPluginContainer((EAPlugin)container.getMod(), container); if(pluginList.contains(pluginContainer)) continue; System.out.println("[EAPlugins]Registering Plugin " + container.getName() + "."); pluginList.add(pluginContainer); } } registerLuaPlugins(); }
@Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { PacketHandler.init(); // Load config configFile = new File(event.getModConfigurationDirectory() + "/openfm/openfm.cfg"); OFMConfiguration.init(configFile); // Check for Mod Update Detector if (event.getSourceFile().getName().endsWith(".jar") && event.getSide().isClient() && OFMConfiguration.enableMUD) { logger.info("Registering mod with OpenUpdater."); try { Class.forName("pcl.mud.OpenUpdater").getDeclaredMethod("registerMod", ModContainer.class, URL.class, URL.class).invoke(null, FMLCommonHandler.instance().findContainerFor(this), new URL("http://PC-Logix.com/OpenFM/get_latest_build.php?mcver=1.7.10"), new URL("http://PC-Logix.com/OpenFM/changelog.php?mcver=1.7.10")); } catch (Throwable e) { logger.info("OpenUpdater is not installed, not registering."); } } }
@Override protected void drawSlot(int listIndex, int var2, int var3, int var4, Tessellator var5) { ModContainer mc=mods.get(listIndex); if (Loader.instance().getModState(mc)==ModState.DISABLED) { this.parent.getFontRenderer().drawString(this.parent.getFontRenderer().trimStringToWidth(mc.getName(), listWidth - 10), this.left + 3 , var3 + 2, 0xFF2222); this.parent.getFontRenderer().drawString(this.parent.getFontRenderer().trimStringToWidth(mc.getDisplayVersion(), listWidth - 10), this.left + 3 , var3 + 12, 0xFF2222); this.parent.getFontRenderer().drawString(this.parent.getFontRenderer().trimStringToWidth("DISABLED", listWidth - 10), this.left + 3 , var3 + 22, 0xFF2222); } else { this.parent.getFontRenderer().drawString(this.parent.getFontRenderer().trimStringToWidth(mc.getName(), listWidth - 10), this.left + 3 , var3 + 2, 0xFFFFFF); this.parent.getFontRenderer().drawString(this.parent.getFontRenderer().trimStringToWidth(mc.getDisplayVersion(), listWidth - 10), this.left + 3 , var3 + 12, 0xCCCCCC); this.parent.getFontRenderer().drawString(this.parent.getFontRenderer().trimStringToWidth(mc.getMetadata() !=null ? mc.getMetadata().getChildModCountString() : "Metadata not found", listWidth - 10), this.left + 3 , var3 + 22, 0xCCCCCC); } }
@Override public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_) { this.drawDefaultBackground(); int offset = Math.max(85 - dupes.dupes.size() * 10, 10); this.drawCenteredString(this.fontRendererObj, "Forge Mod Loader has found a problem with your minecraft installation", this.width / 2, offset, 0xFFFFFF); offset+=10; this.drawCenteredString(this.fontRendererObj, "You have mod sources that are duplicate within your system", this.width / 2, offset, 0xFFFFFF); offset+=10; this.drawCenteredString(this.fontRendererObj, "Mod Id : File name", this.width / 2, offset, 0xFFFFFF); offset+=5; for (Entry<ModContainer, File> mc : dupes.dupes.entries()) { offset+=10; this.drawCenteredString(this.fontRendererObj, String.format("%s : %s", mc.getKey().getModId(), mc.getValue().getName()), this.width / 2, offset, 0xEEEEEE); } }
@SuppressWarnings("unchecked") @Override public void initGui() { for (ModContainer mod : mods) { listWidth=Math.max(listWidth,getFontRenderer().getStringWidth(mod.getName()) + 10); listWidth=Math.max(listWidth,getFontRenderer().getStringWidth(mod.getVersion()) + 10); } listWidth=Math.min(listWidth, 150); this.buttonList.add(new GuiButton(6, this.width / 2 - 75, this.height - 38, I18n.format("gui.done"))); configModButton = new GuiButton(20, 10, this.height - 60, this.listWidth, 20, "Config"); disableModButton = new GuiButton(21, 10, this.height - 38, this.listWidth, 20, "Disable"); this.buttonList.add(configModButton); this.buttonList.add(disableModButton); this.modList=new GuiSlotModList(this, mods, listWidth); this.modList.registerScrollButtons(this.buttonList, 7, 8); }
@Override public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_) { this.drawDefaultBackground(); int offset = Math.max(85 - (failedList.getVisitedNodes().size() + 3) * 10, 10); this.drawCenteredString(this.fontRendererObj, "Forge Mod Loader has found a problem with your minecraft installation", this.width / 2, offset, 0xFFFFFF); offset+=10; this.drawCenteredString(this.fontRendererObj, "A mod sorting cycle was detected and loading cannot continue", this.width / 2, offset, 0xFFFFFF); offset+=10; this.drawCenteredString(this.fontRendererObj, String.format("The first mod in the cycle is %s", failedList.getFirstBadNode()), this.width / 2, offset, 0xFFFFFF); offset+=10; this.drawCenteredString(this.fontRendererObj, "The remainder of the cycle involves these mods", this.width / 2, offset, 0xFFFFFF); offset+=5; for (ModContainer mc : failedList.getVisitedNodes()) { offset+=10; this.drawCenteredString(this.fontRendererObj, String.format("%s : before: %s, after: %s", mc.toString(), mc.getDependants(), mc.getDependencies()), this.width / 2, offset, 0xEEEEEE); } offset+=20; this.drawCenteredString(this.fontRendererObj, "The file 'ForgeModLoader-client-0.log' contains more information", this.width / 2, offset, 0xFFFFFF); }
public static void registerGlobalEntityID(Class <? extends Entity > entityClass, String entityName, int id) { if (EntityList.classToStringMapping.containsKey(entityClass)) { ModContainer activeModContainer = Loader.instance().activeModContainer(); String modId = "unknown"; if (activeModContainer != null) { modId = activeModContainer.getModId(); } else { FMLLog.severe("There is a rogue mod failing to register entities from outside the context of mod loading. This is incredibly dangerous and should be stopped."); } FMLLog.warning("The mod %s tried to register the entity class %s which was already registered - if you wish to override default naming for FML mod entities, register it here first", modId, entityClass); return; } id = instance().validateAndClaimId(id); EntityList.addMapping(entityClass, entityName, id); }
public static void registerGlobalEntityID(Class <? extends Entity > entityClass, String entityName, int id, int backgroundEggColour, int foregroundEggColour) { if (EntityList.classToStringMapping.containsKey(entityClass)) { ModContainer activeModContainer = Loader.instance().activeModContainer(); String modId = "unknown"; if (activeModContainer != null) { modId = activeModContainer.getModId(); } else { FMLLog.severe("There is a rogue mod failing to register entities from outside the context of mod loading. This is incredibly dangerous and should be stopped."); } FMLLog.warning("The mod %s tried to register the entity class %s which was already registered - if you wish to override default naming for FML mod entities, register it here first", modId, entityClass); return; } instance().validateAndClaimId(id); EntityList.addMapping(entityClass, entityName, id, backgroundEggColour, foregroundEggColour); }
@Override public void drawButton(Minecraft p_146112_1_, int p_146112_2_, int p_146112_3_) { if (this.field_146123_n) { ModContainer sel = GuiEnhancedModList.this.getSelectedMod(); if (sel != null && sel.getName().equals(EnderCore.NAME)) { this.displayString = EnderCore.lang.localize("gui.modlistinfo2"); } else { this.displayString = EnderCore.lang.localize("gui.modlistinfo1"); } this.width = p_146112_1_.fontRenderer.getStringWidth(this.displayString) + 10; if (this.width % 2 != 0) // Fixes the button shifting to the left { this.width++; } this.xPosition = GuiEnhancedModList.this.width - this.width - 2; } else { this.displayString = "?"; this.width = 20; this.xPosition = GuiEnhancedModList.this.width - this.width - 2; } super.drawButton(p_146112_1_, p_146112_2_, p_146112_3_); }
private void setMods() { List<ModContainer> mods = getMods(); ModContainer sel = getSelectedMod(); boolean found = false; try { for (int i = 0; !found && i < mods.size(); i++) { if (sel == mods.get(i)) { _selected.setInt(this, i); found = true; } } if (!found) { _selected.setInt(this, -1); _selectedMod.set(this, null); } _mods.set(this, getMods()); sorted = false; } catch (Exception e) { Throwables.propagate(e); } }
@Override public void processCommand(ICommandSender player, String[] args) { if (side == Side.CLIENT == player.getEntityWorld().isRemote) for (String s : args) { boolean validModid = false; for (ModContainer mod : Loader.instance().getModObjectList().keySet()) { if (mod.getModId().equals(s)) { validModid = true; } } if (validModid) { ConfigFileChangedEvent event = new ConfigFileChangedEvent(s); FMLCommonHandler.instance().bus().post(event); if (event.isSuccessful()) { sendResult(player, s, "success"); } else { sendResult(player, s, "fail"); } } else { sendResult(player, s, "invalid"); } } }
/** * Enregistrement du item. Appelé a la fin du postInit */ public void register () { ModContainer mc = Loader.instance().activeModContainer(); HashMap<String, Object> descriptor = new HashMap<String, Object>(); try { Field f = mc.getClass().getDeclaredField("descriptor"); f.setAccessible(true); descriptor = (HashMap<String, Object>) f.get(mc); } catch (Exception e) { e.printStackTrace(); } descriptor.put("modid", this.modId); GameRegistry.registerItem(this, getRegisterName ()); descriptor.put("modid", ModJammyFurnitureZuxelusCompatibility.MODID); }
/** * Enregistrement du item. Appelé a la fin du postInit */ public void register () { ModContainer mc = Loader.instance().activeModContainer(); HashMap<String, Object> descriptor = new HashMap<String, Object>(); try { Field f = mc.getClass().getDeclaredField("descriptor"); f.setAccessible(true); descriptor = (HashMap<String, Object>) f.get(mc); } catch (Exception e) { e.printStackTrace(); } descriptor.put("modid", this.modId); GameRegistry.registerBlock (this, ItemBlockReplace.class, getRegisterName ()); descriptor.put("modid", ModJammyFurnitureZuxelusCompatibility.MODID); }
@Override public List<String> getWailaTail(Entity paramEntity, List<String> strings, IWailaEntityAccessor data, IWailaConfigHandler config) { if(data.getEntity() instanceof EntityGolemBase) { AdditionalGolemType type = GadomancyApi.getAdditionalGolemType(((EntityGolemBase) data.getEntity()).getGolemType()); if(type != null && strings.size() > 0) { String oldMod = strings.get(strings.size() - 1); ModContainer container = Loader.instance().getIndexedModList().get(type.getModId()); if(container != null) { String mod = ColorHelper.extractColors(oldMod) + container.getName(); strings.remove(strings.size() - 1); strings.add(mod); } } } return strings; }
public static String getModID(final ItemStack item) { final ModContainer ID = getModForItemStack(item); if (ID == null || ID.getModId() == null) { return "Unknown"; } return ID.getModId(); }
public static ModContainer findModContainer(String modID) { for (ModContainer mc : Loader.instance().getModList()) if (modID.equals(mc.getModId())) return mc; return null; }