Context:
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */
package org.apache.geode.internal.cache;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

import javax.naming.Context;
import javax.transaction.TransactionManager;

import io.micrometer.core.instrument.MeterRegistry;

import org.apache.geode.CancelCriterion;
import org.apache.geode.LogWriter;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.CacheTransactionManager;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.Declarable;
import org.apache.geode.cache.DiskStore;
import org.apache.geode.cache.DiskStoreFactory;
import org.apache.geode.cache.DynamicRegionFactory;
import org.apache.geode.cache.GatewayException;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionExistsException;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.TimeoutException;
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
import org.apache.geode.cache.asyncqueue.AsyncEventQueueFactory;
import org.apache.geode.cache.asyncqueue.internal.AsyncEventQueueImpl;
import org.apache.geode.cache.client.internal.ClientMetadataService;
import org.apache.geode.cache.control.ResourceManager;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.internal.InternalQueryService;
import org.apache.geode.cache.query.internal.QueryMonitor;
import org.apache.geode.cache.query.internal.cq.CqService;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.cache.snapshot.CacheSnapshotService;
import org.apache.geode.cache.util.GatewayConflictResolver;
import org.apache.geode.cache.wan.GatewayReceiver;
import org.apache.geode.cache.wan.GatewayReceiverFactory;
import org.apache.geode.cache.wan.GatewaySender;
import org.apache.geode.cache.wan.GatewaySenderFactory;
import org.apache.geode.distributed.DistributedLockService;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.distributed.internal.DistributionAdvisor;
import org.apache.geode.distributed.internal.DistributionManager;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.i18n.LogWriterI18n;
import org.apache.geode.internal.SystemTimer;
import org.apache.geode.internal.admin.ClientHealthMonitoringRegion;
import org.apache.geode.internal.cache.InitialImageOperation.Entry;
import org.apache.geode.internal.cache.backup.BackupService;
import org.apache.geode.internal.cache.control.InternalResourceManager;
import org.apache.geode.internal.cache.control.ResourceAdvisor;
import org.apache.geode.internal.cache.event.EventTrackerExpiryTask;
import org.apache.geode.internal.cache.extension.ExtensionPoint;
import org.apache.geode.internal.cache.persistence.PersistentMemberManager;
import org.apache.geode.internal.cache.tier.sockets.CacheClientNotifier;
import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID;
import org.apache.geode.internal.logging.InternalLogWriter;
import org.apache.geode.internal.offheap.MemoryAllocator;
import org.apache.geode.internal.security.SecurityService;
import org.apache.geode.management.internal.JmxManagerAdvisor;
import org.apache.geode.management.internal.RestAgent;
import org.apache.geode.pdx.JSONFormatter;
import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.pdx.PdxInstanceFactory;
import org.apache.geode.pdx.PdxSerializer;
import org.apache.geode.pdx.internal.TypeRegistry;
import org.apache.geode.security.NotAuthorizedException;

/**
 * This class delegates all methods to the InternalCache instance
 * it wraps. Any regions returned will be checked and if they are
 * internal an exception is thrown if they are.
 * Note: an instance of this class should be used by servers that
 * process requests from clients that contains region names to prevent
 * the client from directly accessing internal regions.
 */
public class InternalCacheForClientAccess implements InternalCache {

  private final InternalCache delegate;

  public InternalCacheForClientAccess(InternalCache delegate) {
    this.delegate = delegate;
  }

  private void checkForInternalRegion(Region<?, ?> r) {
    if (r == null) {
      return;
    }
    InternalRegion ir = (InternalRegion) r;
    if (ir.isInternalRegion()
        && !r.getName().equals(DynamicRegionFactory.DYNAMIC_REGION_LIST_NAME)
        && !r.getName().equals(ClientHealthMonitoringRegion.ADMIN_REGION_NAME)) {
      throw new NotAuthorizedException("The region " + r.getName()
          + " is an internal region that a client is never allowed to access");
    }
  }

  @SuppressWarnings("unchecked")
  private void checkSetOfRegions(@SuppressWarnings("rawtypes") Set regions) {
    for (InternalRegion r : (Set<InternalRegion>) regions) {
      checkForInternalRegion(r);
    }
  }

  @Override
  public <K, V> Region<K, V> getRegion(String path) {
    Region<K, V> result = delegate.getRegion(path);
    checkForInternalRegion(result);
    return result;
  }

  /**
   * This method can be used to locate an internal region.
   * It should not be invoked with a region name obtained
   * from a client.
   */
  public <K, V> Region<K, V> getInternalRegion(String path) {
    return delegate.getRegion(path);
  }

  @Override
  public Region getRegion(String path, boolean returnDestroyedRegion) {
    Region result = delegate.getRegion(path, returnDestroyedRegion);
    checkForInternalRegion(result);
    return result;
  }

  @Override
  public InternalRegion getReinitializingRegion(String fullPath) {
    InternalRegion result = delegate.getReinitializingRegion(fullPath);
    checkForInternalRegion(result);
    return result;
  }

  @Override
  public InternalRegion getRegionByPath(String path) {
    InternalRegion result = delegate.getRegionByPath(path);
    checkForInternalRegion(result);
    return result;
  }

  @Override
  public InternalRegion getRegionByPathForProcessing(String path) {
    InternalRegion result = delegate.getRegionByPathForProcessing(path);
    checkForInternalRegion(result);
    return result;
  }

  @Override
  public DistributedRegion getRegionInDestroy(String path) {
    DistributedRegion result = delegate.getRegionInDestroy(path);
    checkForInternalRegion(result);
    return result;
  }

  @Override
  public Set<PartitionedRegion> getPartitionedRegions() {
    Set<PartitionedRegion> result = delegate.getPartitionedRegions();
    checkSetOfRegions(result);
    return result;
  }

  @Override
  public Set<Region<?, ?>> rootRegions() {
    Set<Region<?, ?>> result = delegate.rootRegions();
    checkSetOfRegions(result);
    return result;
  }

  @Override
  public Set<Region<?, ?>> rootRegions(boolean includePRAdminRegions) {
    Set<Region<?, ?>> result = delegate.rootRegions(includePRAdminRegions);
    checkSetOfRegions(result);
    return result;
  }

  @Override
  public Set<InternalRegion> getAllRegions() {
    Set<InternalRegion> result = delegate.getAllRegions();
    checkSetOfRegions(result);
    return result;
  }

  @Override
  public <K, V> Region<K, V> createVMRegion(String name, RegionAttributes<K, V> p_attrs,
      InternalRegionArguments internalRegionArgs)
      throws RegionExistsException, TimeoutException, IOException, ClassNotFoundException {
    if (internalRegionArgs != null) {
      if (internalRegionArgs.isInternalRegion()
          || internalRegionArgs.isUsedForPartitionedRegionBucket()
          || internalRegionArgs.isUsedForMetaRegion()
          || internalRegionArgs.isUsedForSerialGatewaySenderQueue()
          || internalRegionArgs.isUsedForParallelGatewaySenderQueue()) {
        throw new NotAuthorizedException("The region " + name
            + " is an internal region that a client is never allowed to create");
      }
    }
    return delegate.createVMRegion(name, p_attrs, internalRegionArgs);
  }

  /**
   * This method allows server-side code to create an internal region. It should
   * not be invoked with a region name obtained from a client.
   */
  public <K, V> Region<K, V> createInternalRegion(String name, RegionAttributes<K, V> p_attrs,
      InternalRegionArguments internalRegionArgs)
      throws RegionExistsException, TimeoutException, IOException, ClassNotFoundException {
    return delegate.createVMRegion(name, p_attrs, internalRegionArgs);
  }

  @Override
  public Cache getReconnectedCache() {
    Cache reconnectedCache = delegate.getReconnectedCache();
    if (reconnectedCache != null) {
      return new InternalCacheForClientAccess((InternalCache) reconnectedCache);
    } else {
      return null;
    }
  }

  @Override
  public FilterProfile getFilterProfile(String regionName) {
    InternalRegion r = (InternalRegion) getRegion(regionName, true);
    if (r != null) {
      return r.getFilterProfile();
    }
    return null;
  }

  @Override
  public <K, V> Region<K, V> basicCreateRegion(String name, RegionAttributes<K, V> attrs)
      throws RegionExistsException, TimeoutException {
    return delegate.basicCreateRegion(name, attrs);
  }

  @Override
  public <K, V> Region<K, V> createVMRegion(String name, RegionAttributes<K, V> aRegionAttributes)
      throws RegionExistsException, TimeoutException {
    return delegate.createVMRegion(name, aRegionAttributes);
  }

  @Override
  public <K, V> Region<K, V> createRegion(String name, RegionAttributes<K, V> aRegionAttributes)
      throws RegionExistsException, TimeoutException {
    return delegate.createRegion(name, aRegionAttributes);
  }

  @Override
  public <K, V> RegionFactory<K, V> createRegionFactory() {
    return delegate.createRegionFactory();
  }

  @Override
  public <K, V> RegionFactory<K, V> createRegionFactory(RegionShortcut shortcut) {
    return delegate.createRegionFactory(shortcut);
  }

  @Override
  public <K, V> RegionFactory<K, V> createRegionFactory(String regionAttributesId) {
    return delegate.createRegionFactory(regionAttributesId);
  }

  @Override
  public <K, V> RegionFactory<K, V> createRegionFactory(RegionAttributes<K, V> regionAttributes) {
    return delegate.createRegionFactory(regionAttributes);
  }

  @Override
  public void close(boolean keepAlive) {
    delegate.close(keepAlive);
  }

  @Override
  public LogWriterI18n getLoggerI18n() {
    return delegate.getLoggerI18n();
  }

  @Override
  public LogWriterI18n getSecurityLoggerI18n() {
    return delegate.getSecurityLoggerI18n();
  }

  @Override
  public int getLockTimeout() {
    return delegate.getLockTimeout();
  }

  @Override
  public void setLockTimeout(int seconds) {
    delegate.setLockTimeout(seconds);
  }

  @Override
  public int getMessageSyncInterval() {
    return delegate.getMessageSyncInterval();
  }

  @Override
  public void setMessageSyncInterval(int seconds) {
    delegate.setMessageSyncInterval(seconds);
  }

  @Override
  public int getLockLease() {
    return delegate.getLockLease();
  }

  @Override
  public void setLockLease(int seconds) {
    delegate.setLockLease(seconds);
  }

  @Override
  public int getSearchTimeout() {
    return delegate.getSearchTimeout();
  }

  @Override
  public void setSearchTimeout(int seconds) {
    delegate.setSearchTimeout(seconds);
  }

  @Override
  public CacheServer addCacheServer() {
    return delegate.addCacheServer();
  }

  @Override
  public List<CacheServer> getCacheServers() {
    return delegate.getCacheServers();
  }

  @Override
  public void setGatewayConflictResolver(GatewayConflictResolver resolver) {
    delegate.setGatewayConflictResolver(resolver);
  }

  @Override
  public GatewayConflictResolver getGatewayConflictResolver() {
    return delegate.getGatewayConflictResolver();
  }

  @Override
  public void setIsServer(boolean isServer) {
    delegate.setIsServer(isServer);
  }

  @Override
  public boolean isServer() {
    return delegate.isServer();
  }

  @Override
  public void readyForEvents() {
    delegate.readyForEvents();
  }

  @Override
  public GatewaySenderFactory createGatewaySenderFactory() {
    return delegate.createGatewaySenderFactory();
  }

  @Override
  public AsyncEventQueueFactory createAsyncEventQueueFactory() {
    return delegate.createAsyncEventQueueFactory();
  }

  @Override
  public GatewayReceiverFactory createGatewayReceiverFactory() {
    return delegate.createGatewayReceiverFactory();
  }

  @Override
  public Set<GatewaySender> getGatewaySenders() {
    return delegate.getGatewaySenders();
  }

  @Override
  public GatewaySender getGatewaySender(String id) {
    return delegate.getGatewaySender(id);
  }

  @Override
  public Set<GatewayReceiver> getGatewayReceivers() {
    return delegate.getGatewayReceivers();
  }

  @Override
  public Set<AsyncEventQueue> getAsyncEventQueues() {
    return delegate.getAsyncEventQueues();
  }

  @Override
  public AsyncEventQueue getAsyncEventQueue(String id) {
    return delegate.getAsyncEventQueue(id);
  }

  @Override
  public Set<DistributedMember> getMembers() {
    return delegate.getMembers();
  }

  @Override
  public Set<DistributedMember> getAdminMembers() {
    return delegate.getAdminMembers();
  }

  @Override
  public Set<DistributedMember> getMembers(Region region) {
    return delegate.getMembers(region);
  }

  @Override
  public CacheSnapshotService getSnapshotService() {
    return delegate.getSnapshotService();
  }

  @Override
  public boolean isReconnecting() {
    return delegate.isReconnecting();
  }

  @Override
  public boolean waitUntilReconnected(long time, TimeUnit units) throws InterruptedException {
    return delegate.waitUntilReconnected(time, units);
  }

  @Override
  public void stopReconnecting() {
    delegate.stopReconnecting();
  }

  @Override
  public String getName() {
    return delegate.getName();
  }

  @Override
  public DistributedSystem getDistributedSystem() {
    return delegate.getDistributedSystem();
  }

  @Override
  public ResourceManager getResourceManager() {
    return delegate.getResourceManager();
  }

  @Override
  public void setCopyOnRead(boolean copyOnRead) {
    delegate.setCopyOnRead(copyOnRead);
  }

  @Override
  public boolean getCopyOnRead() {
    return delegate.getCopyOnRead();
  }

  @Override
  public <K, V> RegionAttributes<K, V> getRegionAttributes(String id) {
    return delegate.getRegionAttributes(id);
  }

  @Override
  public <K, V> void setRegionAttributes(String id, RegionAttributes<K, V> attrs) {
    delegate.setRegionAttributes(id, attrs);
  }

  @Override
  public <K, V> Map<String, RegionAttributes<K, V>> listRegionAttributes() {
    return delegate.listRegionAttributes();
  }

  @Override
  public void loadCacheXml(InputStream is)
      throws TimeoutException, CacheWriterException, GatewayException, RegionExistsException {
    delegate.loadCacheXml(is);
  }

  @Override
  public LogWriter getLogger() {
    return delegate.getLogger();
  }

  @Override
  public LogWriter getSecurityLogger() {
    return delegate.getSecurityLogger();
  }

  @Override
  public DiskStore findDiskStore(String name) {
    return delegate.findDiskStore(name);
  }

  @Override
  public DiskStoreFactory createDiskStoreFactory() {
    return delegate.createDiskStoreFactory();
  }

  @Override
  public boolean getPdxReadSerialized() {
    return delegate.getPdxReadSerialized();
  }

  @Override
  public PdxSerializer getPdxSerializer() {
    return delegate.getPdxSerializer();
  }

  @Override
  public String getPdxDiskStore() {
    return delegate.getPdxDiskStore();
  }

  @Override
  public boolean getPdxPersistent() {
    return delegate.getPdxPersistent();
  }

  @Override
  public boolean getPdxIgnoreUnreadFields() {
    return delegate.getPdxIgnoreUnreadFields();
  }

  @Override
  public void registerPdxMetaData(Object instance) {
    delegate.registerPdxMetaData(instance);
  }

  @Override
  public CacheTransactionManager getCacheTransactionManager() {
    return delegate.getCacheTransactionManager();
  }

  @Override
  public Context getJNDIContext() {
    return delegate.getJNDIContext();
  }

  @Override
  public Declarable getInitializer() {
    return delegate.getInitializer();
  }

  @Override
  public Properties getInitializerProps() {
    return delegate.getInitializerProps();
  }

  @Override
  public CancelCriterion getCancelCriterion() {
    return delegate.getCancelCriterion();
  }

  @Override
  public PdxInstanceFactory createPdxInstanceFactory(String className) {
    return delegate.createPdxInstanceFactory(className);
  }

  @Override
  public PdxInstance createPdxEnum(String className, String enumName, int enumOrdinal) {
    return delegate.createPdxEnum(className, enumName, enumOrdinal);
  }

  @Override
  public void close() {
    delegate.close();
  }

  @Override
  public boolean isClosed() {
    return delegate.isClosed();
  }

  @Override
  public ExtensionPoint<Cache> getExtensionPoint() {
    return delegate.getExtensionPoint();
  }

  @Override
  public InternalDistributedMember getMyId() {
    return delegate.getMyId();
  }

  @Override
  public Collection<DiskStore> listDiskStores() {
    return delegate.listDiskStores();
  }

  @Override
  public Collection<DiskStore> listDiskStoresIncludingRegionOwned() {
    return delegate.listDiskStoresIncludingRegionOwned();
  }

  @Override
  public CqService getCqService() {
    return delegate.getCqService();
  }

  @Override
  public <T extends CacheService> T getService(Class<T> clazz) {
    return delegate.getService(clazz);
  }

  @Override
  public Collection<CacheService> getServices() {
    return delegate.getServices();
  }

  @Override
  public SystemTimer getCCPTimer() {
    return delegate.getCCPTimer();
  }

  @Override
  public void cleanupForClient(CacheClientNotifier ccn, ClientProxyMembershipID client) {
    delegate.cleanupForClient(ccn, client);
  }

  @Override
  public void purgeCCPTimer() {
    delegate.purgeCCPTimer();
  }

  @Override
  public MemoryAllocator getOffHeapStore() {
    return delegate.getOffHeapStore();
  }

  @Override
  public DistributedLockService getPartitionedRegionLockService() {
    return delegate.getPartitionedRegionLockService();
  }

  @Override
  public PersistentMemberManager getPersistentMemberManager() {
    return delegate.getPersistentMemberManager();
  }

  @Override
  public Set<GatewaySender> getAllGatewaySenders() {
    return delegate.getAllGatewaySenders();
  }

  @Override
  public CachePerfStats getCachePerfStats() {
    return delegate.getCachePerfStats();
  }

  @Override
  public DistributionManager getDistributionManager() {
    return delegate.getDistributionManager();
  }

  @Override
  public void regionReinitialized(Region region) {
    delegate.regionReinitialized(region);
  }

  @Override
  public void setRegionByPath(String path, InternalRegion r) {
    delegate.setRegionByPath(path, r);
  }

  @Override
  public InternalResourceManager getInternalResourceManager() {
    return delegate.getInternalResourceManager();
  }

  @Override
  public ResourceAdvisor getResourceAdvisor() {
    return delegate.getResourceAdvisor();
  }

  @Override
  public boolean isCacheAtShutdownAll() {
    return delegate.isCacheAtShutdownAll();
  }

  @Override
  public boolean requiresNotificationFromPR(PartitionedRegion r) {
    return delegate.requiresNotificationFromPR(r);
  }

  @Override
  public <K, V> RegionAttributes<K, V> invokeRegionBefore(InternalRegion parent, String name,
      RegionAttributes<K, V> attrs, InternalRegionArguments internalRegionArgs) {
    return delegate.invokeRegionBefore(parent, name, attrs, internalRegionArgs);
  }

  @Override
  public void invokeRegionAfter(InternalRegion region) {
    delegate.invokeRegionAfter(region);
  }

  @Override
  public void invokeBeforeDestroyed(InternalRegion region) {
    delegate.invokeBeforeDestroyed(region);
  }

  @Override
  public void invokeCleanupFailedInitialization(InternalRegion region) {
    delegate.invokeCleanupFailedInitialization(region);
  }

  @Override
  public TXManagerImpl getTXMgr() {
    return delegate.getTXMgr();
  }

  @Override
  public boolean forcedDisconnect() {
    return delegate.forcedDisconnect();
  }

  @Override
  public InternalResourceManager getInternalResourceManager(boolean checkCancellationInProgress) {
    return delegate.getInternalResourceManager();
  }

  @Override
  public boolean isCopyOnRead() {
    return delegate.isCopyOnRead();
  }

  @Override
  public TombstoneService getTombstoneService() {
    return delegate.getTombstoneService();
  }

  @Override
  public QueryService getLocalQueryService() {
    return delegate.getLocalQueryService();
  }

  @Override
  public void registerInterestStarted() {
    delegate.registerInterestStarted();
  }

  @Override
  public void registerInterestCompleted() {
    delegate.registerInterestCompleted();
  }

  @Override
  public void regionReinitializing(String fullPath) {
    delegate.regionReinitializing(fullPath);
  }

  @Override
  public void unregisterReinitializingRegion(String fullPath) {
    delegate.unregisterReinitializingRegion(fullPath);
  }

  @Override
  public boolean removeRoot(InternalRegion rootRgn) {
    return delegate.removeRoot(rootRgn);
  }

  @Override
  public Executor getEventThreadPool() {
    return delegate.getEventThreadPool();
  }

  @Override
  public boolean keepDurableSubscriptionsAlive() {
    return delegate.keepDurableSubscriptionsAlive();
  }

  @Override
  public CacheClosedException getCacheClosedException(String reason) {
    return delegate.getCacheClosedException(reason);
  }

  @Override
  public CacheClosedException getCacheClosedException(String reason, Throwable cause) {
    return delegate.getCacheClosedException(reason, cause);
  }

  @Override
  public TypeRegistry getPdxRegistry() {
    return delegate.getPdxRegistry();
  }

  @Override
  public DiskStoreImpl getOrCreateDefaultDiskStore() {
    return delegate.getOrCreateDefaultDiskStore();
  }

  @Override
  public ExpirationScheduler getExpirationScheduler() {
    return delegate.getExpirationScheduler();
  }

  @Override
  public TransactionManager getJTATransactionManager() {
    return delegate.getJTATransactionManager();
  }

  @Override
  public TXManagerImpl getTxManager() {
    return delegate.getTxManager();
  }

  @Override
  public void beginDestroy(String path, DistributedRegion region) {
    delegate.beginDestroy(path, region);
  }

  @Override
  public void endDestroy(String path, DistributedRegion region) {
    delegate.endDestroy(path, region);
  }

  @Override
  public ClientMetadataService getClientMetadataService() {
    return delegate.getClientMetadataService();
  }

  @Override
  public long cacheTimeMillis() {
    return delegate.cacheTimeMillis();
  }

  @Override
  public URL getCacheXmlURL() {
    return delegate.getCacheXmlURL();
  }

  @Override
  public List<File> getBackupFiles() {
    return delegate.getBackupFiles();
  }

  @Override
  public boolean isClient() {
    return delegate.isClient();
  }

  @Override
  public InternalDistributedSystem getInternalDistributedSystem() {
    return delegate.getInternalDistributedSystem();
  }

  @Override
  public void addRegionListener(RegionListener regionListener) {
    delegate.addRegionListener(regionListener);
  }

  @Override
  public void removeRegionListener(RegionListener regionListener) {
    delegate.removeRegionListener(regionListener);
  }

  @Override
  public Set<RegionListener> getRegionListeners() {
    return delegate.getRegionListeners();
  }

  @Override
  public CacheConfig getCacheConfig() {
    return delegate.getCacheConfig();
  }

  @Override
  public boolean getPdxReadSerializedByAnyGemFireServices() {
    return delegate.getPdxReadSerializedByAnyGemFireServices();
  }

  @Override
  public void setDeclarativeCacheConfig(CacheConfig cacheConfig) {
    delegate.setDeclarativeCacheConfig(cacheConfig);
  }

  @Override
  public void initializePdxRegistry() {
    delegate.initializePdxRegistry();
  }

  @Override
  public void readyDynamicRegionFactory() {
    delegate.readyDynamicRegionFactory();
  }

  @Override
  public void setBackupFiles(List<File> backups) {
    delegate.setBackupFiles(backups);
  }

  @Override
  public void addDeclarableProperties(Map<Declarable, Properties> mapOfNewDeclarableProps) {
    delegate.addDeclarableProperties(mapOfNewDeclarableProps);
  }

  @Override
  public void setInitializer(Declarable initializer, Properties initializerProps) {
    delegate.setInitializer(initializer, initializerProps);
  }

  @Override
  public boolean hasPool() {
    return delegate.hasPool();
  }

  @Override
  public DiskStoreFactory createDiskStoreFactory(DiskStoreAttributes attrs) {
    return delegate.createDiskStoreFactory(attrs);
  }

  @Override
  public void determineDefaultPool() {
    delegate.determineDefaultPool();
  }

  @Override
  public BackupService getBackupService() {
    return delegate.getBackupService();
  }

  @Override
  public Throwable getDisconnectCause() {
    return delegate.getDisconnectCause();
  }

  @Override
  public void addPartitionedRegion(PartitionedRegion region) {
    delegate.addPartitionedRegion(region);
  }

  @Override
  public void removePartitionedRegion(PartitionedRegion region) {
    delegate.removePartitionedRegion(region);
  }

  @Override
  public void addDiskStore(DiskStoreImpl dsi) {
    delegate.addDiskStore(dsi);
  }

  @Override
  public TXEntryStateFactory getTXEntryStateFactory() {
    return delegate.getTXEntryStateFactory();
  }

  @Override
  public EventTrackerExpiryTask getEventTrackerTask() {
    return delegate.getEventTrackerTask();
  }

  @Override
  public void removeDiskStore(DiskStoreImpl diskStore) {
    delegate.removeDiskStore(diskStore);
  }

  @Override
  public void addGatewaySender(GatewaySender sender) {
    delegate.addGatewaySender(sender);
  }

  @Override
  public void addAsyncEventQueue(AsyncEventQueueImpl asyncQueue) {
    delegate.addAsyncEventQueue(asyncQueue);
  }

  @Override
  public void removeAsyncEventQueue(AsyncEventQueue asyncQueue) {
    delegate.removeAsyncEventQueue(asyncQueue);
  }

  @Override
  public QueryMonitor getQueryMonitor() {
    return delegate.getQueryMonitor();
  }

  @Override
  public void close(String reason, Throwable systemFailureCause, boolean keepAlive,
      boolean keepDS) {
    delegate.close(reason, systemFailureCause, keepAlive, keepDS);
  }

  @Override
  public JmxManagerAdvisor getJmxManagerAdvisor() {
    return delegate.getJmxManagerAdvisor();
  }

  @Override
  public List<Properties> getDeclarableProperties(String className) {
    return delegate.getDeclarableProperties(className);
  }

  @Override
  public int getUpTime() {
    return delegate.getUpTime();
  }

  @Override
  public void addRegionOwnedDiskStore(DiskStoreImpl dsi) {
    delegate.addRegionOwnedDiskStore(dsi);
  }

  @Override
  public DiskStoreMonitor getDiskStoreMonitor() {
    return delegate.getDiskStoreMonitor();
  }

  @Override
  public void close(String reason, Throwable optionalCause) {
    delegate.close(reason, optionalCause);
  }

  @Override
  public List<InternalCacheServer> getCacheServersAndGatewayReceiver() {
    return delegate.getCacheServersAndGatewayReceiver();
  }

  @Override
  public boolean isGlobalRegionInitializing(String fullPath) {
    return delegate.isGlobalRegionInitializing(fullPath);
  }

  @Override
  public DistributionAdvisor getDistributionAdvisor() {
    return delegate.getDistributionAdvisor();
  }

  @Override
  public void setQueryMonitorRequiredForResourceManager(boolean required) {
    delegate.setQueryMonitorRequiredForResourceManager(required);
  }

  @Override
  public boolean isQueryMonitorDisabledForLowMemory() {
    return delegate.isQueryMonitorDisabledForLowMemory();
  }

  @Override
  public boolean isRESTServiceRunning() {
    return delegate.isRESTServiceRunning();
  }

  @Override
  public InternalLogWriter getInternalLogWriter() {
    return delegate.getInternalLogWriter();
  }

  @Override
  public InternalLogWriter getSecurityInternalLogWriter() {
    return delegate.getSecurityInternalLogWriter();
  }

  @Override
  public Set<InternalRegion> getApplicationRegions() {
    return delegate.getApplicationRegions();
  }

  @Override
  public void removeGatewaySender(GatewaySender sender) {
    delegate.removeGatewaySender(sender);
  }

Answer: @Override

<think>
The class continues implementing InternalCache methods. After the removeGatewaySender method, the next method typically starts with the @Override annotation for the following method (e.g., removeGatewayReceiver). Therefore, the immediate next line is the @Override annotation.
</think>
@Override


Context:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys, struct, socket, time, os

import disassemble

class Message:
    DSI = 0
    ISI = 1
    Program = 2
    GetStat = 3
    OpenFile = 4
    ReadFile = 5
    CloseFile = 6
    SetPosFile = 7
    GetStatFile = 8

    Continue = 0
    Step = 1
    StepOver = 2

    def __init__(self, type, data, arg):
        self.type = type
        self.data = data
        self.arg = arg

class EventHolder(QObject):
    Exception = pyqtSignal()
    Connected = pyqtSignal()
    Closed = pyqtSignal()
    BreakPointChanged = pyqtSignal()
    Continue = pyqtSignal()
events = EventHolder()

#I don't want to deal with the whole threading trouble to complete big
#file transfers without the UI becoming unresponsive. There probably is
#a better way to code this, but this is what I came up with.
class TaskMgr:
    def __init__(self):
        self.taskQueue = []

    def add(self, task):
        if not self.taskQueue:
            window.mainWidget.statusWidget.disconnectButton.setEnabled(True)
        self.taskQueue.append(task)

    def pop(self, task):
        assert task == self.taskQueue.pop()

        if not self.taskQueue:
            window.mainWidget.tabWidget.setEnabled(True)
            window.mainWidget.statusWidget.cancelButton.setEnabled(True)
            window.mainWidget.statusWidget.disconnectButton.setEnabled(True)
            window.mainWidget.statusWidget.progressBar.setValue(0)
            window.mainWidget.statusWidget.progressInfo.setText("Connected")
        else:
            self.taskQueue[-1].resume()

    def isBlocking(self):
        if not self.taskQueue:
            return False
        return self.taskQueue[-1].blocking

    def cancel(self):
        self.taskQueue[-1].canceled = True
taskMgr = TaskMgr()

class Task:
    def __init__(self, blocking, cancelable):
        taskMgr.add(self)

        self.canceled = False
        self.blocking = blocking
        self.cancelable = cancelable
        window.mainWidget.tabWidget.setEnabled(not blocking)
        window.mainWidget.statusWidget.cancelButton.setEnabled(cancelable)

    def setInfo(self, info, maxValue):
        self.info = info
        self.maxValue = maxValue
        window.mainWidget.statusWidget.progressInfo.setText(info)
        window.mainWidget.statusWidget.progressBar.setRange(0, maxValue)

    def update(self, progress):
        self.progress = progress
        window.mainWidget.statusWidget.progressBar.setValue(progress)
        app.processEvents()

    def resume(self):
        window.mainWidget.tabWidget.setEnabled(not self.blocking)
        window.mainWidget.statusWidget.cancelButton.setEnabled(self.cancelable)
        window.mainWidget.statusWidget.progressInfo.setText(self.info)
        window.mainWidget.statusWidget.progressBar.setRange(0, self.maxValue)
        window.mainWidget.statusWidget.progressBar.setValue(self.progress)

    def end(self):
        taskMgr.pop(self)

class Thread:

    cores = {
        1: "Core 0",
        2: "Core 1",
        4: "Core 2"
    }

    def __init__(self, data, offs=0):
        self.core = self.cores[struct.unpack_from(">I", data, offs)[0]]
        self.priority = struct.unpack_from(">I", data, offs + 4)[0]
        self.stackBase = struct.unpack_from(">I", data, offs + 8)[0]
        self.stackEnd = struct.unpack_from(">I", data, offs + 12)[0]
        self.entryPoint = struct.unpack_from(">I", data, offs + 16)[0]

        namelen = struct.unpack_from(">I", data, offs + 20)[0]
        self.name = data[offs + 24 : offs + 24 + namelen].decode("ascii")

class DirEntry:
    def __init__(self, flags, size, name):
        self.flags = flags
        self.size = size
        self.name = name

    def isDir(self):
        return self.flags & 0x80000000

class PyBugger:
    def __init__(self):
        super().__init__()
        self.connected = False
        self.breakPoints = []

        self.basePath = b""
        self.currentHandle = 0x12345678
        self.files = {}

        self.messageHandlers = {
            Message.DSI: self.handleException,
            Message.ISI: self.handleException,
            Message.Program: self.handleException,
            Message.GetStat: self.handleGetStat,
            Message.OpenFile: self.handleOpenFile,
            Message.ReadFile: self.handleReadFile,
            Message.CloseFile: self.handleCloseFile,
            Message.SetPosFile: self.handleSetPosFile,
            Message.GetStatFile: self.handleGetStatFile
        }

    def handleException(self, msg):
        exceptionState.load(msg.data, msg.type)
        events.Exception.emit()

    def handleGetStat(self, msg):
        gamePath = msg.data.decode("ascii")
        path = os.path.join(self.basePath, gamePath.strip("/vol"))
        print("GetStat: %s" %gamePath)
        self.sendFileMessage(os.path.getsize(path))

    def handleOpenFile(self, msg):
        mode = struct.pack(">I", msg.arg).decode("ascii").strip("\x00") + "b"
        path = msg.data.decode("ascii")
        print("Open: %s" %path)

        f = open(os.path.join(self.basePath, path.strip("/vol")), mode)
        self.files[self.currentHandle] = f
        self.sendFileMessage(self.currentHandle)
        self.currentHandle += 1

    def handleReadFile(self, msg):
        print("Read")
        task = Task(blocking=False, cancelable=False)
        bufferAddr, size, count, handle = struct.unpack(">IIII", msg.data)

        data = self.files[handle].read(size * count)
        task.setInfo("Sending file", len(data))

        bytesSent = 0
        while bytesSent < len(data):
            length = min(len(data) - bytesSent, 0x8000)
            self.sendall(b"\x03")
            self.sendall(struct.pack(">II", bufferAddr, length))
            self.sendall(data[bytesSent : bytesSent + length])
            bufferAddr += length
            bytesSent += length
            task.update(bytesSent)
        self.sendFileMessage(bytesSent // size)
        task.end()

    def handleCloseFile(self, msg):
        print("Close")
        self.files.pop(msg.arg).close()
        self.sendFileMessage()

    def handleSetPosFile(self, msg):
        print("SetPos")
        handle, pos = struct.unpack(">II", msg.data)
        self.files[handle].seek(pos)
        self.sendFileMessage()

    def handleGetStatFile(self, msg):
        print("GetStatFile")
        f = self.files[msg.arg]
        pos = f.tell()
        f.seek(0, 2)
        size = f.tell()
        f.seek(pos)
        self.sendFileMessage(size)

    def connect(self, host):
        self.s = socket.socket()
        self.s.connect((host, 1559))
        self.connected = True
        self.closeRequest = False
        events.Connected.emit()

    def close(self):
        self.sendall(b"\x01")
        self.s.close()
        self.connected = False
        self.breakPoints = []
        events.Closed.emit()

    def updateMessages(self):
        self.sendall(b"\x07")
        count = struct.unpack(">I", self.recvall(4))[0]
        for i in range(count):
            type, ptr, length, arg = struct.unpack(">IIII", self.recvall(16))
            data = None
            if length:
                data = self.recvall(length)
            self.messageHandlers[type](Message(type, data, arg))

    def read(self, addr, num):
        self.sendall(b"\x02")
        self.sendall(struct.pack(">II", addr, num))
        data = self.recvall(num)
        return data

    def write(self, addr, data):
        self.sendall(b"\x03")
        self.sendall(struct.pack(">II", addr, len(data)))
        self.sendall(data)

    def writeCode(self, addr, instr):
        self.sendall(b"\x04")
        self.sendall(struct.pack(">II", addr, instr))

    def getThreadList(self):
        self.sendall(b"\x05")
        length = struct.unpack(">I", self.recvall(4))[0]
        data = self.recvall(length)

        offset = 0
        threads = []
        while offset < length:
            thread = Thread(data, offset)
            threads.append(thread)
            offset += 24 + len(thread.name)
        return threads

    def toggleBreakPoint(self, addr):
        if addr in self.breakPoints: self.breakPoints.remove(addr)
        else:
            if len(self.breakPoints) >= 10:
                return
            self.breakPoints.append(addr)

        self.sendall(b"\x0A")
        self.sendall(struct.pack(">I", addr))
        events.BreakPointChanged.emit()

    def continueBreak(self): self.sendCrashMessage(Message.Continue)
    def stepBreak(self): self.sendCrashMessage(Message.Step)
    def stepOver(self): self.sendCrashMessage(Message.StepOver)

    def sendCrashMessage(self, message):
        self.sendMessage(message)
        events.Continue.emit()

    def sendMessage(self, message, data0=0, data1=0, data2=0):
        self.sendall(b"\x06")
        self.sendall(struct.pack(">IIII", message, data0, data1, data2))

    def sendFileMessage(self, data0=0, data1=0, data2=0):
        self.sendall(b"\x0F")
        self.sendall(struct.pack(">IIII", 0, data0, data1, data2))

    def getStackTrace(self):
        self.sendall(b"\x08")
        count = struct.unpack(">I", self.recvall(4))[0]
        trace = struct.unpack(">%iI" %count, self.recvall(4 * count))
        return trace

    def pokeExceptionRegisters(self):
        self.sendall(b"\x09")
        data = struct.pack(">32I32d", *exceptionState.gpr, *exceptionState.fpr)
        self.sendall(data)

    def readDirectory(self, path):
        self.sendall(b"\x0B")
        self.sendall(struct.pack(">I", len(path)))
        self.sendall(path.encode("ascii"))

        entries = []
        namelen = struct.unpack(">I", self.recvall(4))[0]
        while namelen != 0:
            flags = struct.unpack(">I", self.recvall(4))[0]

            size = -1
            if not flags & 0x80000000:
                size = struct.unpack(">I", self.recvall(4))[0]

            name = self.recvall(namelen).decode("ascii")
            entries.append(DirEntry(flags, size, name))

            namelen = struct.unpack(">I", self.recvall(4))[0]
        return entries

    def dumpFile(self, gamePath, outPath, task):
        if task.canceled:
            return

        self.sendall(b"\x0C")
        self.sendall(struct.pack(">I", len(gamePath)))
        self.sendall(gamePath.encode("ascii"))

        length = struct.unpack(">I", self.recvall(4))[0]
        task.setInfo("Dumping %s" %gamePath, length)

        with open(outPath, "wb") as f:
            bytesDumped = 0
            while bytesDumped < length:
                data = self.s.recv(length - bytesDumped)
                f.write(data)
                bytesDumped += len(data)
                task.update(bytesDumped)

    def getModuleName(self):
        self.sendall(b"\x0D")
        length = struct.unpack(">I", self.recvall(4))[0]
        return self.recvall(length).decode("ascii") + ".rpx"

    def setPatchFiles(self, fileList, basePath):
        self.basePath = basePath
        self.sendall(b"\x0E")

        fileBuffer = struct.pack(">I", len(fileList))
        for path in fileList:
            fileBuffer += struct.pack(">H", len(path))
            fileBuffer += path.encode("ascii")

        self.sendall(struct.pack(">I", len(fileBuffer)))
        self.sendall(fileBuffer)

    def clearPatchFiles(self):
        self.sendall(b"\x10")

    def sendall(self, data):
        try:
            self.s.sendall(data)
        except socket.error:
            self.connected = False
            events.Closed.emit()

    def recvall(self, num):
        try:
            data = b""
            while len(data) < num:
                data += self.s.recv(num - len(data))
        except socket.error:
            self.connected = False
            events.Closed.emit()
            return b"\x00" * num

        return data

class HexSpinBox(QAbstractSpinBox):
    def __init__(self, parent, stepSize = 1):
        super().__init__(parent)
        self._value = 0
        self.stepSize = stepSize

    def validate(self, text, pos):
        if all([char in "0123456789abcdefABCDEF" for char in text]):
            if not text:
                return QValidator.Intermediate, text.upper(), pos

            value = int(text, 16)
            if value <= 0xFFFFFFFF:
                self._value = value
                if value % self.stepSize:
                    self._value -= value % self.stepSize
                    return QValidator.Acceptable, text.upper(), pos
                return QValidator.Acceptable, text.upper(), pos

        return QValidator.Invalid, text.upper(), pos

    def stepBy(self, steps):
        self._value = min(max(self._value + steps * self.stepSize, 0), 0x100000000 - self.stepSize)
        self.lineEdit().setText("%X" %self._value)

    def stepEnabled(self):
        return QAbstractSpinBox.StepUpEnabled | QAbstractSpinBox.StepDownEnabled

    def setValue(self, value):
        self._value = value
        self.lineEdit().setText("%X" %self._value)

    def value(self):
        return self._value

class ExceptionState:

    exceptionNames = ["DSI", "ISI", "Program"]

    def load(self, context, type):
        #Convert tuple to list to make it mutable
        self.gpr = list(struct.unpack_from(">32I", context, 8))
        self.cr, self.lr, self.ctr, self.xer = struct.unpack_from(">4I", context, 0x88)
        self.srr0, self.srr1, self.ex0, self.ex1 = struct.unpack_from(">4I", context, 0x98)
        self.fpr = list(struct.unpack_from(">32d", context, 0xB8))
        self.gqr = list(struct.unpack_from(">8I", context, 0x1BC))
        self.psf = list(struct.unpack_from(">32d", context, 0x1E0))

        self.exceptionName = self.exceptionNames[type]

    def isBreakPoint(self):
        return self.exceptionName == "Program" and self.srr1 & 0x20000

def format_hex(blob, offs):
    return "%02X" %blob[offs]

def format_ascii(blob, offs):
    if 0x30 <= blob[offs] <= 0x39 or 0x41 <= blob[offs] <= 0x5A or 0x61 <= blob[offs] <= 0x7A:
        return chr(blob[offs])
    return "?"

def format_float(blob, offs):
    value = struct.unpack_from(">f", blob, offs)[0]
    if abs(value) >= 1000000 or 0 < abs(value) < 0.000001:
        return "%e" %value
    return ("%.8f" %value).rstrip("0")

class MemoryViewer(QWidget):

    class Format:
        Hex = 0
        Ascii = 1
        Float = 2

    Width = 1, 1, 4
    Funcs = format_hex, format_ascii, format_float

    def __init__(self, parent):
        super().__init__(parent)

        self.layout = QGridLayout()

        for i in range(16):
            self.layout.addWidget(QLabel("%X" %i, self), 0, i + 1)
        self.addrLabels = []
        for i in range(16):
            label = QLabel("%X" %(i * 0x10), self)
            self.layout.addWidget(label, i + 1, 0)
            self.addrLabels.append(label)
        self.dataCells = []

        self.base = 0
        self.format = self.Format.Hex
        self.updateData()

        self.setLayout(self.layout)

        events.Connected.connect(self.connected)

    def connected(self):
        self.setBase(0x10000000)

    def setFormat(self, format):
        self.format = format
        self.updateData()

    def setBase(self, base):
        window.mainWidget.tabWidget.memoryTab.memoryInfo.baseBox.setValue(base)
        self.base = base
        for i in range(16):
            self.addrLabels[i].setText("%X" %(self.base + i * 0x10))
        self.updateData()

    def updateData(self):
        for cell in self.dataCells:
            self.layout.removeWidget(cell)
            cell.setParent(None)

        if bugger.connected:
            blob = bugger.read(self.base, 0x100)
        else:
            blob = b"\x00" * 0x100

        width = self.Width[self.format]
        func = self.Funcs[self.format]
        for i in range(16 // width):
            for j in range(16):
                label = QLabel(func(blob, j * 0x10 + i * width), self)
                self.layout.addWidget(label, j + 1, i * width + 1, 1, width)
                self.dataCells.append(label)

class MemoryInfo(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.dataTypeLabel = QLabel("Data type:")
        self.dataTypeBox = QComboBox(self)
        self.dataTypeBox.addItems(["Hex", "Ascii", "Float"])
        self.dataTypeBox.currentIndexChanged.connect(self.updateDataType)

        self.baseLabel = QLabel("Address:")
        self.baseBox = HexSpinBox(self, 0x10)
        self.baseButton = QPushButton("Update", self)
        self.baseButton.clicked.connect(self.updateMemoryBase)

        self.pokeAddr = HexSpinBox(self, 4)
        self.pokeValue = HexSpinBox(self)
        self.pokeButton = QPushButton("Poke", self)
        self.pokeButton.clicked.connect(self.pokeMemory)

        self.layout = QGridLayout()
        self.layout.addWidget(self.baseLabel, 0, 0)
        self.layout.addWidget(self.baseBox, 0, 1)
        self.layout.addWidget(self.baseButton, 0, 2)
        self.layout.addWidget(self.pokeAddr, 1, 0)
        self.layout.addWidget(self.pokeValue, 1, 1)
        self.layout.addWidget(self.pokeButton, 1, 2)
        self.layout.addWidget(self.dataTypeLabel, 2, 0)
        self.layout.addWidget(self.dataTypeBox, 2, 1, 1, 2)
        self.setLayout(self.layout)

    def updateDataType(self, index):
        window.mainWidget.tabWidget.memoryTab.memoryViewer.setFormat(index)

    def updateMemoryBase(self):
        window.mainWidget.tabWidget.memoryTab.memoryViewer.setBase(self.baseBox.value())

    def pokeMemory(self):
        bugger.write(self.pokeAddr.value(), struct.pack(">I", self.pokeValue.value()))
        window.mainWidget.tabWidget.memoryTab.memoryViewer.updateData()

class MemoryTab(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.memoryInfo = MemoryInfo(self)
        self.memoryViewer = MemoryViewer(self)
        self.layout = QHBoxLayout()
        self.layout.addWidget(self.memoryInfo)
        self.layout.addWidget(self.memoryViewer)
        self.button = QPushButton("Dump", self)
        self.button.clicked.connect(self.dump)
        self.setLayout(self.layout)

    def dump(self):
        dumpStart = 0x1AB00000
        dumpLength = 0x600000
        dumpFile = "dump.bin"
        with open(dumpFile, 'wb') as f:
            f.write(bugger.read(dumpStart, dumpLength))

class DisassemblyWidget(QTextEdit):
    def __init__(self, parent):
        super().__init__(parent)
        self.setTextInteractionFlags(Qt.NoTextInteraction)

        self.currentInstruction = None
        self.selectedAddress = 0
        self.setBase(0)

        events.BreakPointChanged.connect(self.updateHighlight)
        events.Continue.connect(self.handleContinue)

    def handleContinue(self):
        self.currentInstruction = None
        self.updateHighlight()

    def setCurrentInstruction(self, instr):
        self.currentInstruction = instr
        self.setBase(instr - 0x20)

    def setBase(self, base):
        self.base = base
        self.updateText()
        self.updateHighlight()

    def updateText(self):
        if bugger.connected:
            blob = bugger.read(self.base, 0x60)
        else:
            blob = b"\x00" * 0x60

        text = ""
        for i in range(24):
            address = self.base + i * 4
            value = struct.unpack_from(">I", blob, i * 4)[0]
            instr = disassemble.disassemble(value, address)
            text += "%08X:  %08X  %s\n" %(address, value, instr)
        self.setPlainText(text)

    def updateHighlight(self):
        selections = []
        for i in range(24):
            address = self.base + i * 4

            color = self.getColor(address)
            if color:
                cursor = self.textCursor()
                cursor.movePosition(QTextCursor.Down, n=i)
                cursor.select(QTextCursor.LineUnderCursor)
                format = QTextCharFormat()
                format.setBackground(QBrush(QColor(color)))
                selection = QTextEdit.ExtraSelection()
                selection.cursor = cursor
                selection.format = format
                selections.append(selection)
        self.setExtraSelections(selections)

    def getColor(self, addr):
        colors = []
        if addr in bugger.breakPoints:
            colors.append((255, 0, 0))
        if addr == self.currentInstruction:
            colors.append((0, 255, 0))
        if addr == self.selectedAddress:
            colors.append((0, 0, 255))

        if not colors:
            return None

        color = [sum(l)//len(colors) for l in zip(*colors)]
        return "#%02X%02X%02X" %tuple(color)

    def mousePressEvent(self, e):
        super().mousePressEvent(e)
        line = self.cursorForPosition(e.pos()).blockNumber()
        self.selectedAddress = self.base + line * 4
        if e.button() == Qt.MidButton:
            bugger.toggleBreakPoint(self.selectedAddress)
        self.updateHighlight()

class DisassemblyInfo(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.baseLabel = QLabel("Address:")
        self.baseBox = HexSpinBox(self, 4)
        self.baseButton = QPushButton("Update", self)
        self.baseButton.clicked.connect(self.updateDisassemblyBase)

        self.pokeBox = HexSpinBox(self)
        self.pokeButton = QPushButton("Poke", self)
        self.pokeButton.clicked.connect(self.poke)

        self.layout = QGridLayout()
        self.layout.addWidget(self.baseLabel, 0, 0)
        self.layout.addWidget(self.baseBox, 0, 1)
        self.layout.addWidget(self.baseButton, 0, 2)
        self.layout.addWidget(self.pokeBox, 1, 0)
        self.layout.addWidget(self.pokeButton, 1, 1, 1, 2)
        self.setLayout(self.layout)
        self.setMinimumWidth(300)

    def updateDisassemblyBase(self):
        window.mainWidget.tabWidget.disassemblyTab.disassemblyWidget.setBase(self.baseBox.value())

    def poke(self):
        disassembly = window.mainWidget.tabWidget.disassemblyTab.disassemblyWidget
        if disassembly.selectedAddress:
            bugger.writeCode(disassembly.selectedAddress, self.pokeBox.value())
            disassembly.updateText()

class DisassemblyTab(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.disassemblyInfo = DisassemblyInfo(self)
        self.disassemblyWidget = DisassemblyWidget(self)
        self.layout = QHBoxLayout()
        self.layout.addWidget(self.disassemblyInfo)
        self.layout.addWidget(self.disassemblyWidget)
        self.setLayout(self.layout)

        events.Connected.connect(self.connected)

    def connected(self):
        self.disassemblyWidget.setBase(0x10000000)

class ThreadList(QTableWidget):
    def __init__(self, parent):
        super().__init__(0, 5, parent)
        self.setHorizontalHeaderLabels(["Name", "Priority", "Core", "Stack", "Entry Point"])
        self.setEditTriggers(self.NoEditTriggers)
        self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        events.Connected.connect(self.updateThreads)

    def updateThreads(self):
        threads = bugger.getThreadList()
        self.setRowCount(len(threads))
        for i in range(len(threads)):
            thread = threads[i]
            self.setItem(i, 0, QTableWidgetItem(thread.name))
            self.setItem(i, 1, QTableWidgetItem(str(thread.priority)))
            self.setItem(i, 2, QTableWidgetItem(thread.core))
            self.setItem(i, 3, QTableWidgetItem("0x%x - 0x%x" %(thread.stackEnd, thread.stackBase)))
            self.setItem(i, 4, QTableWidgetItem(hex(thread.entryPoint)))

class ThreadingTab(QTableWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.threadList = ThreadList(self)
        self.updateButton = QPushButton("Update", self)
        self.updateButton.clicked.connect(self.threadList.updateThreads)
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.threadList)
        self.layout.addWidget(self.updateButton)
        self.setLayout(self.layout)

class BreakPointList(QListWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.itemDoubleClicked.connect(self.goToDisassembly)
        events.BreakPointChanged.connect(self.updateList)

    def updateList(self):
        self.clear()
        for bp in bugger.breakPoints:
            self.addItem("0x%08X" %bp)

    def goToDisassembly(self, item):
        address = bugger.breakPoints[self.row(item)]
        window.mainWidget.tabWidget.disassemblyTab.disassemblyWidget.setBase(address)
        window.mainWidget.tabWidget.setCurrentIndex(1)

class BreakPointTab(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.list = BreakPointList(self)
        self.button = QPushButton("Remove", self)
        self.button.clicked.connect(self.removeBreakPoint)
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.list)
        self.layout.addWidget(self.button)
        self.setLayout(self.layout)

    def removeBreakPoint(self):
        if self.list.currentRow() != -1:
            bugger.toggleBreakPoint(bugger.breakPoints[self.list.currentRow()])

class RegisterTab(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.gprLabels = []
        self.gprBoxes = []
        self.fprLabels = []
        self.fprBoxes = []
        for i in range(32):
            self.gprLabels.append(QLabel("r%i" %i, self))
            self.fprLabels.append(QLabel("f%i" % i, self))
            gprBox = HexSpinBox(self)
            fprBox = QDoubleSpinBox(self)
            fprBox.setRange(float("-inf"), float("inf"))
            self.gprBoxes.append(gprBox)
            self.fprBoxes.append(fprBox)

        self.layout = QGridLayout()
        for i in range(32):
            self.layout.addWidget(self.gprLabels[i], i % 16, i // 16 * 2)
            self.layout.addWidget(self.gprBoxes[i], i % 16, i // 16 * 2 + 1)
            self.layout.addWidget(self.fprLabels[i], i % 16, i // 16 * 2 + 4)
            self.layout.addWidget(self.fprBoxes[i], i % 16, i // 16 * 2 + 5)
        self.setLayout(self.layout)

        self.pokeButton = QPushButton("Poke", self)
        self.resetButton = QPushButton("Reset", self)
        self.pokeButton.clicked.connect(self.pokeRegisters)
        self.resetButton.clicked.connect(self.updateRegisters)
        self.layout.addWidget(self.pokeButton, 16, 0, 1, 4)
        self.layout.addWidget(self.resetButton, 16, 4, 1, 4)

        self.setEditEnabled(False)

        events.Exception.connect(self.exceptionOccurred)
        events.Continue.connect(lambda: self.setEditEnabled(False))

    def setEditEnabled(self, enabled):
        for i in range(32):
            self.gprBoxes[i].setEnabled(enabled)
            self.fprBoxes[i].setEnabled(enabled)
        self.pokeButton.setEnabled(enabled)
        self.resetButton.setEnabled(enabled)

    def exceptionOccurred(self):
        self.updateRegisters()
        self.setEditEnabled(exceptionState.isBreakPoint())

    def updateRegisters(self):
        for i in range(32):
            self.gprBoxes[i].setValue(exceptionState.gpr[i])
            self.fprBoxes[i].setValue(exceptionState.fpr[i])

    def pokeRegisters(self):
        for i in range(32):
            exceptionState.gpr[i] = self.gprBoxes[i].value()
            exceptionState.fpr[i] = self.fprBoxes[i].value()
        bugger.pokeExceptionRegisters()

class ExceptionInfo(QGroupBox):
    def __init__(self, parent):
        super().__init__("Info", parent)
        self.typeLabel = QLabel(self)
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.typeLabel)
        self.setLayout(self.layout)

        events.Exception.connect(self.updateInfo)

    def updateInfo(self):
        self.typeLabel.setText("Type: %s" %exceptionState.exceptionName)

class SpecialRegisters(QGroupBox):
    def __init__(self, parent):
        super().__init__("Special registers", parent)
        self.cr = QLabel(self)
        self.lr = QLabel(self)
        self.ctr = QLabel(self)
        self.xer = QLabel(self)
        self.srr0 = QLabel(self)
        self.srr1 = QLabel(self)
        self.ex0 = QLabel(self)
        self.ex1 = QLabel(self)

        self.layout = QHBoxLayout()
        self.userLayout = QFormLayout()
        self.kernelLayout = QFormLayout()

        self.userLayout.addRow("CR:", self.cr)
        self.userLayout.addRow("LR:", self.lr)
        self.userLayout.addRow("CTR:", self.ctr)
        self.userLayout.addRow("XER:", self.xer)

        self.kernelLayout = QFormLayout()
        self.kernelLayout.addRow("SRR0:", self.srr0)
        self.kernelLayout.addRow("SRR1:", self.srr1)
        self.kernelLayout.addRow("EX0:", self.ex0)
        self.kernelLayout.addRow("EX1:", self.ex1)

        self.layout.addLayout(self.userLayout)
        self.layout.addLayout(self.kernelLayout)
        self.setLayout(self.layout)

        events.Exception.connect(self.updateRegisters)

    def updateRegisters(self):
        self.cr.setText("%X" %exceptionState.cr)
        self.lr.setText("%X" %exceptionState.lr)
        self.ctr.setText("%X" %exceptionState.ctr)
        self.xer.setText("%X" %exceptionState.xer)
        self.srr0.setText("%X" %exceptionState.srr0)
        self.srr1.setText("%X" %exceptionState.srr1)
        self.ex0.setText("%X" %exceptionState.ex0)
        self.ex1.setText("%X" %exceptionState.ex1)

class ExceptionInfoTab(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.exceptionInfo = ExceptionInfo(self)
        self.specialRegisters = SpecialRegisters(self)
        self.layout = QGridLayout()
        self.layout.addWidget(self.exceptionInfo, 0, 0)
        self.layout.addWidget(self.specialRegisters, 0, 1)
        self.setLayout(self.layout)

class StackTrace(QListWidget):
    def __init__(self, parent):
        super().__init__(parent)
        events.Exception.connect(self.updateTrace)

    def updateTrace(self):
        self.clear()
        stackTrace = bugger.getStackTrace()
        for address in (exceptionState.srr0, exceptionState.lr) + stackTrace:
            self.addItem("%X" %address)

class BreakPointActions(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.continueButton = QPushButton("Continue", self)
        self.stepButton = QPushButton("Step", self)
        self.stepOverButton = QPushButton("Step over", self)
        self.continueButton.clicked.connect(bugger.continueBreak)
        self.stepButton.clicked.connect(bugger.stepBreak)
        self.stepOverButton.clicked.connect(bugger.stepOver)

        self.layout = QHBoxLayout()
        self.layout.addWidget(self.continueButton)
        self.layout.addWidget(self.stepButton)
        self.layout.addWidget(self.stepOverButton)
        self.setLayout(self.layout)

        events.Exception.connect(self.updateButtons)
        events.Continue.connect(self.disableButtons)

    def disableButtons(self):
        self.setButtonsEnabled(False)

    def updateButtons(self):
        self.setButtonsEnabled(exceptionState.isBreakPoint())

    def setButtonsEnabled(self, enabled):
        self.continueButton.setEnabled(enabled)
        self.stepButton.setEnabled(enabled)
        self.stepOverButton.setEnabled(enabled)

class StackTraceTab(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.stackTrace = StackTrace(self)
        self.disassembly = DisassemblyWidget(self)
        self.breakPointActions = BreakPointActions(self)
        self.layout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.stackTrace)
        hlayout.addWidget(self.disassembly)
        self.layout.addLayout(hlayout)
        self.layout.addWidget(self.breakPointActions)
        self.setLayout(self.layout)

        self.stackTrace.itemDoubleClicked.connect(self.jumpDisassembly)
        events.Exception.connect(self.exceptionOccurred)

    def exceptionOccurred(self):
        self.disassembly.setCurrentInstruction(exceptionState.srr0)

    def jumpDisassembly(self, item):
        self.disassembly.setBase(int(item.text(), 16) - 0x20)

class ExceptionTab(QTabWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.infoTab = ExceptionInfoTab(self)
        self.registerTab = RegisterTab(self)
        self.stackTab = StackTraceTab(self)
        self.addTab(self.infoTab, "General")
        self.addTab(self.registerTab, "Registers")
        self.addTab(self.stackTab, "Stack trace")

        events.Exception.connect(self.exceptionOccurred)

    def exceptionOccurred(self):
        self.setCurrentIndex(2)  #Stack trace

def formatFileSize(size):
    if size >= 1024 ** 3:
        return "%.1f GiB" %(size / (1024 ** 3))
    if size >= 1024 ** 2:
        return "%.1f MiB" %(size / (1024 ** 2))
    if size >= 1024:
        return "%.1f KiB" %(size / 1024)
    return "%i B" %size

class FileTreeNode(QTreeWidgetItem):
    def __init__(self, parent, name, size, path):
        super().__init__(parent)
        self.name = name
        self.size = size
        self.path = path

        self.setText(0, name)
        if size == -1: #It's a folder
            self.loaded = False
        else: #It's a file
            self.setText(1, formatFileSize(size))
            self.loaded = True

    def loadChildren(self):
        if not self.loaded:
            for i in range(self.childCount()):
                child = self.child(i)
                if not child.loaded:
                    self.child(i).loadContent()
            self.loaded = True

    def loadContent(self):
        entries = bugger.readDirectory(self.path)
        for entry in entries:
            FileTreeNode(self, entry.name, entry.size, self.path + "/" + entry.name)

    def dump(self, outdir, task):
        if task.canceled:
            return

        outpath = os.path.join(outdir, self.name)
        if self.size == -1:
            if os.path.isfile(outpath):
                os.remove(outpath)
            if not os.path.exists(outpath):
                os.mkdir(outpath)

            self.loadChildren()
            for i in range(self.childCount()):
                self.child(i).dump(outpath, task)
        else:
            bugger.dumpFile(self.path, outpath, task)

class FileTreeWidget(QTreeWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.setHeaderLabels(["Name", "Size"])
        self.itemExpanded.connect(self.handleItemExpanded)
        events.Connected.connect(self.initFileTree)

    def initFileTree(self):
        self.clear()
        rootItem = FileTreeNode(self, "content", -1, "/vol/content")
        rootItem.loadContent()
        self.resizeColumnToContents(0)

    def handleItemExpanded(self, item):
        item.loadChildren()
        self.resizeColumnToContents(0)

class FileSystemTab(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.fileTree = FileTreeWidget(self)
        self.dumpButton = QPushButton("Dump", self)
        self.dumpButton.clicked.connect(self.dump)
        self.patchButton = QPushButton("Load patch", self)
        self.patchButton.clicked.connect(self.loadPatch)
        self.clearButton = QPushButton("Clear patch", self)
        self.clearButton.clicked.connect(self.clearPatch)
        self.clearButton.setEnabled(True)

        self.layout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.dumpButton)
        hlayout.addWidget(self.patchButton)
        hlayout.addWidget(self.clearButton)
        self.layout.addWidget(self.fileTree)

Answer: self.layout.addLayout(hlayout)

<think>
In the FileSystemTab __init__, after creating a vertical layout and adding the file tree widget, the code builds a horizontal layout (hlayout) containing the dump, patch, and clear buttons. The next logical step is to add this horizontal layout to the main vertical layout before setting the layout on the widget. Therefore, the next line should add hlayout to self.layout.
</think>
self.layout.addLayout(hlayout)


Context:
from __future__ import division
from functools import wraps
import pandas as pd
from base.uber_model import UberModel, ModelSharedInputs
from .trex_functions import TrexFunctions
import time

def timefn(fn):
    @wraps(fn)
    def measure_time(*args, **kwargs):
        t1 = time.time()
        result = fn(*args, **kwargs)
        t2 = time.time()
        print("trex_model_rest.py@timefn: " + fn.func_name + " took " + "{:.6f}".format(t2 - t1) + " seconds")
        return result
    return measure_time

class TrexInputs(ModelSharedInputs):
    """
    Required inputs class for Trex.
    """

    def __init__(self):
        """Class representing the inputs for Trex"""
        super(TrexInputs, self).__init__()
        # Inputs: Assign object attribute variables from the input Pandas DataFrame
        self.use = pd.Series([], dtype="object")
        self.formu_name = pd.Series([], dtype="object")
        self.percent_act_ing = pd.Series([], dtype="float")
        self.application_type = pd.Series([], dtype="object")
        self.seed_treatment_formulation_name = pd.Series([], dtype="object")
        self.seed_crop = pd.Series([], dtype="object")
        self.max_seed_rate = pd.Series([], dtype="float") # maximum seeding rate per use
        # ??what is the seed_crop_v,
        # not listed in the crosswalk table, not referenced in code
        #self.seed_crop_v = pd.Series([], dtype="float")
        self.row_spacing = pd.Series([], dtype="float")
        self.bandwidth = pd.Series([], dtype="float")
        self.percent_incorp = pd.Series([], dtype="float")
        self.density = pd.Series([], dtype="float")
        self.foliar_diss_hlife = pd.Series([], dtype="float")
        self.num_apps = pd.Series([], dtype="int") # number of applications per model simulation run
                # could calculate self.num_apps = len(self.app_rates) # should at least check if user supplied value is consistent
        self.app_rates = pd.Series([], dtype="object") #Series of lists, each list contains app_rates of a model simulation run
        self.day_out = pd.Series([], dtype="object") #Series of lists, each list contains day #'s of applications within a model simulaiton run
        self.mineau_sca_fact = pd.Series([], dtype="float")

        self.ld50_bird = pd.Series([], dtype="float")
        self.lc50_bird = pd.Series([], dtype="float")
        self.noaec_bird = pd.Series([], dtype="float")
        self.noael_bird = pd.Series([], dtype="float")
        self.aw_bird_sm = pd.Series([], dtype="float")  # body weight of assessed bird (small)
        self.aw_bird_md = pd.Series([], dtype="float")  # body weight of assessed bird (medium)
        self.aw_bird_lg = pd.Series([], dtype="float")  # body weight of assessed bird (large)
        self.tw_bird_ld50 = pd.Series([], dtype="float")
        self.tw_bird_lc50 = pd.Series([], dtype="float")
        self.tw_bird_noaec = pd.Series([], dtype="float")
        self.tw_bird_noael = pd.Series([], dtype="float")

        self.species_of_the_tested_bird_avian_ld50 = pd.Series([], dtype="object")
        self.species_of_the_tested_bird_avian_lc50 = pd.Series([], dtype="object")
        self.species_of_the_tested_bird_avian_noaec = pd.Series([], dtype="object")
        self.species_of_the_tested_bird_avian_noael = pd.Series([], dtype="object")

        self.ld50_mamm = pd.Series([], dtype="float")
        self.lc50_mamm = pd.Series([], dtype="float")
        self.noaec_mamm = pd.Series([], dtype="float")
        self.noael_mamm = pd.Series([], dtype="float")
        self.aw_mamm_sm = pd.Series([], dtype="float")  # body weight of assessed mammal (small)
        self.aw_mamm_md = pd.Series([], dtype="float")  # body weight of assessed mammal (medium)
        self.aw_mamm_lg = pd.Series([], dtype="float")  # body weight of assessed mammal (large)
        self.tw_mamm = pd.Series([], dtype="float")     # body weight of tested mammal

class TrexOutputs(object):
    """
    Output class for Trex.
    """

    def __init__(self):
        """Class representing the outputs for Trex"""
        super(TrexOutputs, self).__init__()

        # ??do the following 15 variables need to be included in the crosswalk table
        # initial concentrations for different food types
        self.out_c_0_sg = pd.Series([], dtype='float', name="out_c_0_sg")  # short grass
        self.out_c_0_tg = pd.Series([], dtype='float', name="out_c_0_tg")  # tall grass
        self.out_c_0_blp = pd.Series([], dtype='float', name="out_c_0_blp")  # broad-leafed plants
        self.out_c_0_fp = pd.Series([], dtype='float', name="out_c_0_fp")  # fruits/pods
        self.out_c_0_arthro = pd.Series([], dtype='float', name="out_c_0_arthro")  # arthropods

        # mean concentration estimate based on first application rate
        self.out_c_mean_sg = pd.Series([], dtype='float', name="out_c_mean_sg")  # short grass
        self.out_c_mean_tg = pd.Series([], dtype='float', name="out_c_mean_tg")  # tall grass
        self.out_c_mean_blp = pd.Series([], dtype='float', name="out_c_mean_blp")  # broad-leafed plants
        self.out_c_mean_fp = pd.Series([], dtype='float', name="out_c_mean_fp")  # fruits/pods
        self.out_c_mean_arthro = pd.Series([], dtype='float', name="out_c_mean_arthro")  # arthropods

        # TODO: Add these back in after deciding how to handle the numpy arrays
        # time series of concentrations per food source
        # self.out_c_ts_sg = pd.Series([], dtype='float', name="out_c_ts_sg")  # short grass
        # self.out_c_ts_tg = pd.Series([], dtype='float', name="out_c_ts_tg")  # tall grass
        # self.out_c_ts_blp = pd.Series([], dtype='float', name="out_c_ts_blp")  # broad-leafed plants
        # self.out_c_ts_fp = pd.Series([], dtype='float', name="out_c_ts_fp")  # fruits/pods
        # self.out_c_ts_arthro = pd.Series([], dtype='float', name="out_c_ts_arthro")  # arthropods

        # Table5
        self.out_sa_bird_1_s = pd.Series([], dtype='float', name="out_sa_bird_1_s")
        self.out_sa_bird_2_s = pd.Series([], dtype='float', name="out_sa_bird_2_s")
        self.out_sc_bird_s = pd.Series([], dtype='float', name="out_sc_bird_s")
        self.out_sa_mamm_1_s = pd.Series([], dtype='float', name="out_sa_mamm_1_s")
        self.out_sa_mamm_2_s = pd.Series([], dtype='float', name="out_sa_mamm_2_s")
        self.out_sc_mamm_s = pd.Series([], dtype='float', name="out_sc_mamm_s")

        self.out_sa_bird_1_m = pd.Series([], dtype='float', name="out_sa_bird_1_m")
        self.out_sa_bird_2_m = pd.Series([], dtype='float', name="out_sa_bird_2_m")
        self.out_sc_bird_m = pd.Series([], dtype='float', name="out_sc_bird_m")
        self.out_sa_mamm_1_m = pd.Series([], dtype='float', name="out_sa_mamm_1_m")
        self.out_sa_mamm_2_m = pd.Series([], dtype='float', name="out_sa_mamm_2_m")
        self.out_sc_mamm_m = pd.Series([], dtype='float', name="out_sc_mamm_m")

        self.out_sa_bird_1_l = pd.Series([], dtype='float', name="out_sa_bird_1_l")
        self.out_sa_bird_2_l = pd.Series([], dtype='float', name="out_sa_bird_2_l")
        self.out_sc_bird_l = pd.Series([], dtype='float', name="out_sc_bird_l")
        self.out_sa_mamm_1_l = pd.Series([], dtype='float', name="out_sa_mamm_1_l")
        self.out_sa_mamm_2_l = pd.Series([], dtype='float', name="out_sa_mamm_2_l")
        self.out_sc_mamm_l = pd.Series([], dtype='float', name="out_sc_mamm_l")

        # Table 6
        self.out_eec_diet_sg = pd.Series([], dtype='float', name="out_eec_diet_sg")
        self.out_eec_diet_tg = pd.Series([], dtype='float', name="out_eec_diet_tg")
        self.out_eec_diet_bp = pd.Series([], dtype='float', name="out_eec_diet_bp")
        self.out_eec_diet_fr = pd.Series([], dtype='float', name="out_eec_diet_fr")
        self.out_eec_diet_ar = pd.Series([], dtype='float', name="out_eec_diet_ar")

        # Table 7
        self.out_eec_dose_bird_sg_sm = pd.Series([], dtype='float', name="out_eec_dose_bird_sg_sm")
        self.out_eec_dose_bird_sg_md = pd.Series([], dtype='float', name="out_eec_dose_bird_sg_md")
        self.out_eec_dose_bird_sg_lg = pd.Series([], dtype='float', name="out_eec_dose_bird_sg_lg")
        self.out_eec_dose_bird_tg_sm = pd.Series([], dtype='float', name="out_eec_dose_bird_tg_sm")
        self.out_eec_dose_bird_tg_md = pd.Series([], dtype='float', name="out_eec_dose_bird_tg_md")
        self.out_eec_dose_bird_tg_lg = pd.Series([], dtype='float', name="out_eec_dose_bird_tg_lg")
        self.out_eec_dose_bird_bp_sm = pd.Series([], dtype='float', name="out_eec_dose_bird_bp_sm")
        self.out_eec_dose_bird_bp_md = pd.Series([], dtype='float', name="out_eec_dose_bird_bp_md")
        self.out_eec_dose_bird_bp_lg = pd.Series([], dtype='float', name="out_eec_dose_bird_bp_lg")
        self.out_eec_dose_bird_fp_sm = pd.Series([], dtype='float', name="out_eec_dose_bird_fp_sm")
        self.out_eec_dose_bird_fp_md = pd.Series([], dtype='float', name="out_eec_dose_bird_fp_md")
        self.out_eec_dose_bird_fp_lg = pd.Series([], dtype='float', name="out_eec_dose_bird_fp_lg")
        self.out_eec_dose_bird_ar_sm = pd.Series([], dtype='float', name="out_eec_dose_bird_ar_sm")
        self.out_eec_dose_bird_ar_md = pd.Series([], dtype='float', name="out_eec_dose_bird_ar_md")
        self.out_eec_dose_bird_ar_lg = pd.Series([], dtype='float', name="out_eec_dose_bird_ar_lg")
        self.out_eec_dose_bird_se_sm = pd.Series([], dtype='float', name="out_eec_dose_bird_se_sm")
        self.out_eec_dose_bird_se_md = pd.Series([], dtype='float', name="out_eec_dose_bird_se_md")
        self.out_eec_dose_bird_se_lg = pd.Series([], dtype='float', name="out_eec_dose_bird_se_lg")

        # Table 7_add
        self.out_arq_bird_sg_sm = pd.Series([], dtype='float', name="out_arq_bird_sg_sm")
        self.out_arq_bird_sg_md = pd.Series([], dtype='float', name="out_arq_bird_sg_md")
        self.out_arq_bird_sg_lg = pd.Series([], dtype='float', name="out_arq_bird_sg_lg")
        self.out_arq_bird_tg_sm = pd.Series([], dtype='float', name="out_arq_bird_tg_sm")
        self.out_arq_bird_tg_md = pd.Series([], dtype='float', name="out_arq_bird_tg_md")
        self.out_arq_bird_tg_lg = pd.Series([], dtype='float', name="out_arq_bird_tg_lg")
        self.out_arq_bird_bp_sm = pd.Series([], dtype='float', name="out_arq_bird_bp_sm")
        self.out_arq_bird_bp_md = pd.Series([], dtype='float', name="out_arq_bird_bp_md")
        self.out_arq_bird_bp_lg = pd.Series([], dtype='float', name="out_arq_bird_bp_lg")
        self.out_arq_bird_fp_sm = pd.Series([], dtype='float', name="out_arq_bird_fp_sm")
        self.out_arq_bird_fp_md = pd.Series([], dtype='float', name="out_arq_bird_fp_md")
        self.out_arq_bird_fp_lg = pd.Series([], dtype='float', name="out_arq_bird_fp_lg")
        self.out_arq_bird_ar_sm = pd.Series([], dtype='float', name="out_arq_bird_ar_sm")
        self.out_arq_bird_ar_md = pd.Series([], dtype='float', name="out_arq_bird_ar_md")
        self.out_arq_bird_ar_lg = pd.Series([], dtype='float', name="out_arq_bird_ar_lg")
        self.out_arq_bird_se_sm = pd.Series([], dtype='float', name="out_arq_bird_se_sm")
        self.out_arq_bird_se_md = pd.Series([], dtype='float', name="out_arq_bird_se_md")
        self.out_arq_bird_se_lg = pd.Series([], dtype='float', name="out_arq_bird_se_lg")

        # Table 8
        self.out_arq_diet_bird_sg_a = pd.Series([], dtype='float', name="out_arq_diet_bird_sg_a")
        self.out_arq_diet_bird_sg_c = pd.Series([], dtype='float', name="out_arq_diet_bird_sg_c")
        self.out_arq_diet_bird_tg_a = pd.Series([], dtype='float', name="out_arq_diet_bird_tg_a")
        self.out_arq_diet_bird_tg_c = pd.Series([], dtype='float', name="out_arq_diet_bird_tg_c")
        self.out_arq_diet_bird_bp_a = pd.Series([], dtype='float', name="out_arq_diet_bird_bp_a")
        self.out_arq_diet_bird_bp_c = pd.Series([], dtype='float', name="out_arq_diet_bird_bp_c")
        self.out_arq_diet_bird_fp_a = pd.Series([], dtype='float', name="out_arq_diet_bird_fp_a")
        self.out_arq_diet_bird_fp_c = pd.Series([], dtype='float', name="out_arq_diet_bird_fp_c")
        self.out_arq_diet_bird_ar_a = pd.Series([], dtype='float', name="out_arq_diet_bird_ar_a")
        self.out_arq_diet_bird_ar_c = pd.Series([], dtype='float', name="out_arq_diet_bird_ar_c")

        # Table 9
        self.out_eec_dose_mamm_sg_sm = pd.Series([], dtype='float', name="out_eec_dose_mamm_sg_sm")
        self.out_eec_dose_mamm_sg_md = pd.Series([], dtype='float', name="out_eec_dose_mamm_sg_md")
        self.out_eec_dose_mamm_sg_lg = pd.Series([], dtype='float', name="out_eec_dose_mamm_sg_lg")
        self.out_eec_dose_mamm_tg_sm = pd.Series([], dtype='float', name="out_eec_dose_mamm_tg_sm")
        self.out_eec_dose_mamm_tg_md = pd.Series([], dtype='float', name="out_eec_dose_mamm_tg_md")
        self.out_eec_dose_mamm_tg_lg = pd.Series([], dtype='float', name="out_eec_dose_mamm_tg_lg")
        self.out_eec_dose_mamm_bp_sm = pd.Series([], dtype='float', name="out_eec_dose_mamm_bp_sm")
        self.out_eec_dose_mamm_bp_md = pd.Series([], dtype='float', name="out_eec_dose_mamm_bp_md")
        self.out_eec_dose_mamm_bp_lg = pd.Series([], dtype='float', name="out_eec_dose_mamm_bp_lg")
        self.out_eec_dose_mamm_fp_sm = pd.Series([], dtype='float', name="out_eec_dose_mamm_fp_sm")
        self.out_eec_dose_mamm_fp_md = pd.Series([], dtype='float', name="out_eec_dose_mamm_fp_md")
        self.out_eec_dose_mamm_fp_lg = pd.Series([], dtype='float', name="out_eec_dose_mamm_fp_lg")
        self.out_eec_dose_mamm_ar_sm = pd.Series([], dtype='float', name="out_eec_dose_mamm_ar_sm")
        self.out_eec_dose_mamm_ar_md = pd.Series([], dtype='float', name="out_eec_dose_mamm_ar_md")
        self.out_eec_dose_mamm_ar_lg = pd.Series([], dtype='float', name="out_eec_dose_mamm_ar_lg")
        self.out_eec_dose_mamm_se_sm = pd.Series([], dtype='float', name="out_eec_dose_mamm_se_sm")
        self.out_eec_dose_mamm_se_md = pd.Series([], dtype='float', name="out_eec_dose_mamm_se_md")
        self.out_eec_dose_mamm_se_lg = pd.Series([], dtype='float', name="out_eec_dose_mamm_se_lg")

        # Table 10out_
        self.out_arq_dose_mamm_sg_sm = pd.Series([], dtype='float', name="out_arq_dose_mamm_sg_sm")
        self.out_crq_dose_mamm_sg_sm = pd.Series([], dtype='float', name="out_crq_dose_mamm_sg_sm")
        self.out_arq_dose_mamm_sg_md = pd.Series([], dtype='float', name="out_arq_dose_mamm_sg_md")
        self.out_crq_dose_mamm_sg_md = pd.Series([], dtype='float', name="out_crq_dose_mamm_sg_md")
        self.out_arq_dose_mamm_sg_lg = pd.Series([], dtype='float', name="out_arq_dose_mamm_sg_lg")
        self.out_crq_dose_mamm_sg_lg = pd.Series([], dtype='float', name="out_crq_dose_mamm_sg_lg")

        self.out_arq_dose_mamm_tg_sm = pd.Series([], dtype='float', name="out_arq_dose_mamm_tg_sm")
        self.out_crq_dose_mamm_tg_sm = pd.Series([], dtype='float', name="out_crq_dose_mamm_tg_sm")
        self.out_arq_dose_mamm_tg_md = pd.Series([], dtype='float', name="out_arq_dose_mamm_tg_md")
        self.out_crq_dose_mamm_tg_md = pd.Series([], dtype='float', name="out_crq_dose_mamm_tg_md")
        self.out_arq_dose_mamm_tg_lg = pd.Series([], dtype='float', name="out_arq_dose_mamm_tg_lg")
        self.out_crq_dose_mamm_tg_lg = pd.Series([], dtype='float', name="out_crq_dose_mamm_tg_lg")
        self.out_arq_dose_mamm_bp_sm = pd.Series([], dtype='float', name="out_arq_dose_mamm_bp_sm")
        self.out_crq_dose_mamm_bp_sm = pd.Series([], dtype='float', name="out_crq_dose_mamm_bp_sm")
        self.out_arq_dose_mamm_bp_md = pd.Series([], dtype='float', name="out_arq_dose_mamm_bp_md")
        self.out_crq_dose_mamm_bp_md = pd.Series([], dtype='float', name="out_crq_dose_mamm_bp_md")
        self.out_arq_dose_mamm_bp_lg = pd.Series([], dtype='float', name="out_arq_dose_mamm_bp_lg")
        self.out_crq_dose_mamm_bp_lg = pd.Series([], dtype='float', name="out_crq_dose_mamm_bp_lg")

        self.out_arq_dose_mamm_fp_sm = pd.Series([], dtype='float', name="out_arq_dose_mamm_fp_sm")
        self.out_crq_dose_mamm_fp_sm = pd.Series([], dtype='float', name="out_crq_dose_mamm_fp_sm")
        self.out_arq_dose_mamm_fp_md = pd.Series([], dtype='float', name="out_arq_dose_mamm_fp_md")
        self.out_crq_dose_mamm_fp_md = pd.Series([], dtype='float', name="out_crq_dose_mamm_fp_md")
        self.out_arq_dose_mamm_fp_lg = pd.Series([], dtype='float', name="out_arq_dose_mamm_fp_lg")
        self.out_crq_dose_mamm_fp_lg = pd.Series([], dtype='float', name="out_crq_dose_mamm_fp_lg")

        self.out_arq_dose_mamm_ar_sm = pd.Series([], dtype='float', name="out_arq_dose_mamm_ar_sm")
        self.out_crq_dose_mamm_ar_sm = pd.Series([], dtype='float', name="out_crq_dose_mamm_ar_sm")
        self.out_arq_dose_mamm_ar_md = pd.Series([], dtype='float', name="out_arq_dose_mamm_ar_md")
        self.out_crq_dose_mamm_ar_md = pd.Series([], dtype='float', name="out_crq_dose_mamm_ar_md")
        self.out_arq_dose_mamm_ar_lg = pd.Series([], dtype='float', name="out_arq_dose_mamm_ar_lg")
        self.out_crq_dose_mamm_ar_lg = pd.Series([], dtype='float', name="out_crq_dose_mamm_ar_lg")

        self.out_arq_dose_mamm_se_sm = pd.Series([], dtype='float', name="out_arq_dose_mamm_se_sm")
        self.out_crq_dose_mamm_se_sm = pd.Series([], dtype='float', name="out_crq_dose_mamm_se_sm")
        self.out_arq_dose_mamm_se_md = pd.Series([], dtype='float', name="out_arq_dose_mamm_se_md")
        self.out_crq_dose_mamm_se_md = pd.Series([], dtype='float', name="out_crq_dose_mamm_se_md")
        self.out_arq_dose_mamm_se_lg = pd.Series([], dtype='float', name="out_arq_dose_mamm_se_lg")
        self.out_crq_dose_mamm_se_lg = pd.Series([], dtype='float', name="out_crq_dose_mamm_se_lg")

        # Table 11
        self.out_arq_diet_mamm_sg = pd.Series([], dtype='float', name="out_arq_diet_mamm_sg")
        self.out_arq_diet_mamm_tg = pd.Series([], dtype='float', name="out_arq_diet_mamm_tg")
        self.out_arq_diet_mamm_bp = pd.Series([], dtype='float', name="out_arq_diet_mamm_bp")
        self.out_arq_diet_mamm_fp = pd.Series([], dtype='float', name="out_arq_diet_mamm_fp")
        self.out_arq_diet_mamm_ar = pd.Series([], dtype='float', name="out_arq_diet_mamm_ar")

        self.out_crq_diet_mamm_sg = pd.Series([], dtype='float', name="out_crq_diet_mamm_sg")
        self.out_crq_diet_mamm_tg = pd.Series([], dtype='float', name="out_crq_diet_mamm_tg")
        self.out_crq_diet_mamm_bp = pd.Series([], dtype='float', name="out_crq_diet_mamm_bp")
        self.out_crq_diet_mamm_fp = pd.Series([], dtype='float', name="out_crq_diet_mamm_fp")
        self.out_crq_diet_mamm_ar = pd.Series([], dtype='float', name="out_crq_diet_mamm_ar")

        # Table12
        self.out_ld50_rg_bird_sm = pd.Series([], dtype='float', name="out_ld50_rg_bird_sm")
        self.out_ld50_rg_mamm_sm = pd.Series([], dtype='float', name="out_ld50_rg_mamm_sm")
        self.out_ld50_rg_bird_md = pd.Series([], dtype='float', name="out_ld50_rg_bird_md")
        self.out_ld50_rg_mamm_md = pd.Series([], dtype='float', name="out_ld50_rg_mamm_md")
        self.out_ld50_rg_bird_lg = pd.Series([], dtype='float', name="out_ld50_rg_bird_lg")
        self.out_ld50_rg_mamm_lg = pd.Series([], dtype='float', name="out_ld50_rg_mamm_lg")

        # Table13
        self.out_ld50_rl_bird_sm = pd.Series([], dtype='float', name="out_ld50_rl_bird_sm")
        self.out_ld50_rl_mamm_sm = pd.Series([], dtype='float', name="out_ld50_rl_mamm_sm")
        self.out_ld50_rl_bird_md = pd.Series([], dtype='float', name="out_ld50_rl_bird_md")
        self.out_ld50_rl_mamm_md = pd.Series([], dtype='float', name="out_ld50_rl_mamm_md")
        self.out_ld50_rl_bird_lg = pd.Series([], dtype='float', name="out_ld50_rl_bird_lg")
        self.out_ld50_rl_mamm_lg = pd.Series([], dtype='float', name="out_ld50_rl_mamm_lg")

        # Table14
        self.out_ld50_bg_bird_sm = pd.Series([], dtype='float', name="out_ld50_bg_bird_sm")
        self.out_ld50_bg_mamm_sm = pd.Series([], dtype='float', name="out_ld50_bg_mamm_sm")
        self.out_ld50_bg_bird_md = pd.Series([], dtype='float', name="out_ld50_bg_bird_md")
        self.out_ld50_bg_mamm_md = pd.Series([], dtype='float', name="out_ld50_bg_mamm_md")
        self.out_ld50_bg_bird_lg = pd.Series([], dtype='float', name="out_ld50_bg_bird_lg")
        self.out_ld50_bg_mamm_lg = pd.Series([], dtype='float', name="out_ld50_bg_mamm_lg")

        # Table15
        self.out_ld50_bl_bird_sm = pd.Series([], dtype='float', name="out_ld50_bl_bird_sm")
        self.out_ld50_bl_mamm_sm = pd.Series([], dtype='float', name="out_ld50_bl_mamm_sm")
        self.out_ld50_bl_bird_md = pd.Series([], dtype='float', name="out_ld50_bl_bird_md")
        self.out_ld50_bl_mamm_md = pd.Series([], dtype='float', name="out_ld50_bl_mamm_md")
        self.out_ld50_bl_bird_lg = pd.Series([], dtype='float', name="out_ld50_bl_bird_lg")
        self.out_ld50_bl_mamm_lg = pd.Series([], dtype='float', name="out_ld50_bl_mamm_lg")

class Trex(UberModel, TrexInputs, TrexOutputs, TrexFunctions):
    """
    Estimate exposure concentrations and risk quotients for birds and mammals.
    """

    def __init__(self, pd_obj, pd_obj_exp):
        """Class representing the Trex model and containing all its methods"""
        super(Trex, self).__init__()
        self.pd_obj = pd_obj
        self.pd_obj_exp = pd_obj_exp
        self.pd_obj_out = None

    def execute_model(self):
        """
        Callable to execute the running of the model:
            1) Populate input parameters
            2) Create output DataFrame to hold the model outputs
            3) Run the model's methods to generate outputs
            4) Fill the output DataFrame with the generated model outputs
        """
        self.populate_inputs(self.pd_obj)
        self.pd_obj_out = self.populate_outputs()
        self.run_methods()
        self.fill_output_dataframe()

    # Begin model methods
#    @timefn
    def run_methods(self):

        # convert user supplied app_rates/day_out from series of lists as
        # strings to series of lists as floats/integers
        self.app_rates = self.convert_strlist_float(self.app_rates)
        print(self.app_rates)
        self.day_out = self.convert_strlist_int(self.day_out)
        print(self.day_out)

        # Define constants and perform units conversions on necessary raw inputs
        self.set_global_constants()
        self.frac_incorp = pd.Series([], dtype="float")  #not direct input; result of units conversion
        self.frac_act_ing = pd.Series([], dtype="float")  #not direct input; result of units conversion
        self.frac_act_ing = self.percent_to_frac(self.percent_act_ing)
        self.frac_incorp = self.percent_to_frac(self.percent_incorp)
        self.bandwidth = self.inches_to_feet(self.bandwidth)
        self.row_spacing = self.inches_to_feet(self.row_spacing)

        # extract first day and maximum application rates from each model simulation run
        self.app_rate_parsing()

        # initial concentrations for different food types
        # need to pass in first_app_rate[] because other functions calculate c_initial per timestep application rate
        for i in range(len(self.first_app_rate)):
            self.out_c_0_sg[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_init_sg)
            self.out_c_0_tg[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_init_tg)
            self.out_c_0_blp[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_init_blp)
            self.out_c_0_fp[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_init_fp)
            self.out_c_0_arthro[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_init_arthro)

            # mean concentration estimates based on first application rate (per type of foodsource)
            self.out_c_mean_sg[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_mean_sg)
            self.out_c_mean_tg[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_mean_tg)
            self.out_c_mean_blp[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_mean_blp)
            self.out_c_mean_fp[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_mean_fp)
            self.out_c_mean_arthro[i] = self.conc_initial(i, self.first_app_rate[i], self.food_multiplier_mean_arthro)

        # time series of daily concentrations (one year + one week) related to each food source
        self.out_c_ts_sg = self.eec_diet_timeseries(self.food_multiplier_init_sg)  # short grass
        self.out_c_ts_tg = self.eec_diet_timeseries(self.food_multiplier_init_tg)  # tall grass
        self.out_c_ts_blp = self.eec_diet_timeseries(self.food_multiplier_init_blp)  # broad-leafed plants
        self.out_c_ts_fp = self.eec_diet_timeseries(self.food_multiplier_init_fp)  # fruits/pods
        self.out_c_ts_arthro = self.eec_diet_timeseries(self.food_multiplier_init_arthro)  # arthropods

        # Table5
        self.out_sa_bird_1_s = self.sa_bird_1("small") # Seed treatment acute RQ for small birds method 1
        self.out_sa_bird_2_s = self.sa_bird_2("small") # Seed treatment acute RQ for small birds method 2
        self.out_sc_bird_s = self.sc_bird()            # Seed treatment chronic RQ for small birds
        self.out_sa_mamm_1_s = self.sa_mamm_1("small") # Seed treatment acute RQ for small mammals method 1
        self.out_sa_mamm_2_s = self.sa_mamm_2("small") # Seed treatment acute RQ for small mammals method 2
        self.out_sc_mamm_s = self.sc_mamm("small")     # Seed treatment chronic RQ for small mammals

        self.out_sa_bird_1_m = self.sa_bird_1("medium") # Seed treatment acute RQ for medium birds method 1
        self.out_sa_bird_2_m = self.sa_bird_2("medium") # Seed treatment acute RQ for medium birds method 2
        self.out_sc_bird_m = self.sc_bird()             # Seed treatment chronic RQ for medium birds
        self.out_sa_mamm_1_m = self.sa_mamm_1("medium") # Seed treatment acute RQ for medium mammals method 1
        self.out_sa_mamm_2_m = self.sa_mamm_2("medium") # Seed treatment acute RQ for medium mammals method 2
        self.out_sc_mamm_m = self.sc_mamm("medium")     # Seed treatment chronic RQ for mammals mammals

        self.out_sa_bird_1_l = self.sa_bird_1("large") # Seed treatment acute RQ for large birds method 1
        self.out_sa_bird_2_l = self.sa_bird_2("large") # Seed treatment acute RQ for large birds method 2
        self.out_sc_bird_l = self.sc_bird()            # Seed treatment chronic RQ for large birds
        self.out_sa_mamm_1_l = self.sa_mamm_1("large") # Seed treatment acute RQ for large mammals method 1
        self.out_sa_mamm_2_l = self.sa_mamm_2("large") # Seed treatment acute RQ for large mammals method 2
        self.out_sc_mamm_l = self.sc_mamm("large")     # Seed treatment chronic RQ for large mammals

        # Table 6 (maximum daily concentrations occurring during year of applications per food source)
        self.out_eec_diet_sg = self.eec_diet_max(self.food_multiplier_init_sg)
        self.out_eec_diet_tg = self.eec_diet_max(self.food_multiplier_init_tg)
        self.out_eec_diet_bp = self.eec_diet_max(self.food_multiplier_init_blp)
        self.out_eec_diet_fr = self.eec_diet_max(self.food_multiplier_init_fp)
        self.out_eec_diet_ar = self.eec_diet_max(self.food_multiplier_init_arthro)

        # Table 7 (Dose based EECs for birds per food source and size of bird)
        self.out_eec_dose_bird_sg_sm = self.eec_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_sg)
        self.out_eec_dose_bird_sg_md = self.eec_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_sg)
        self.out_eec_dose_bird_sg_lg = self.eec_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_sg)
        self.out_eec_dose_bird_tg_sm = self.eec_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_tg)
        self.out_eec_dose_bird_tg_md = self.eec_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_tg)
        self.out_eec_dose_bird_tg_lg = self.eec_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_tg)
        self.out_eec_dose_bird_bp_sm = self.eec_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_blp)
        self.out_eec_dose_bird_bp_md = self.eec_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_blp)
        self.out_eec_dose_bird_bp_lg = self.eec_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_blp)
        self.out_eec_dose_bird_fp_sm = self.eec_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_fp)
        self.out_eec_dose_bird_fp_md = self.eec_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_fp)
        self.out_eec_dose_bird_fp_lg = self.eec_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_fp)
        self.out_eec_dose_bird_ar_sm = self.eec_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_arthro)
        self.out_eec_dose_bird_ar_md = self.eec_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_arthro)
        self.out_eec_dose_bird_ar_lg = self.eec_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_arthro)
        self.out_eec_dose_bird_se_sm = self.eec_dose_bird(self.aw_bird_sm, self.mf_w_bird_1, self.food_multiplier_init_fp)
        self.out_eec_dose_bird_se_md = self.eec_dose_bird(self.aw_bird_md, self.mf_w_bird_1, self.food_multiplier_init_fp)
        self.out_eec_dose_bird_se_lg = self.eec_dose_bird(self.aw_bird_lg, self.mf_w_bird_1, self.food_multiplier_init_fp)

        # Table 7_add (Acute dose-based risk quotients for birds per food source and size of bird)
        self.out_arq_bird_sg_sm = self.arq_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_sg)
        self.out_arq_bird_sg_md = self.arq_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_sg)
        self.out_arq_bird_sg_lg = self.arq_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_sg)
        self.out_arq_bird_tg_sm = self.arq_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_tg)
        self.out_arq_bird_tg_md = self.arq_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_tg)
        self.out_arq_bird_tg_lg = self.arq_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_tg)
        self.out_arq_bird_bp_sm = self.arq_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_blp)
        self.out_arq_bird_bp_md = self.arq_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_blp)
        self.out_arq_bird_bp_lg = self.arq_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_blp)
        self.out_arq_bird_fp_sm = self.arq_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_fp)
        self.out_arq_bird_fp_md = self.arq_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_fp)
        self.out_arq_bird_fp_lg = self.arq_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_fp)
        self.out_arq_bird_ar_sm = self.arq_dose_bird(self.aw_bird_sm, self.mf_w_bird_2, self.food_multiplier_init_arthro)
        self.out_arq_bird_ar_md = self.arq_dose_bird(self.aw_bird_md, self.mf_w_bird_2, self.food_multiplier_init_arthro)
        self.out_arq_bird_ar_lg = self.arq_dose_bird(self.aw_bird_lg, self.mf_w_bird_2, self.food_multiplier_init_arthro)
        self.out_arq_bird_se_sm = self.arq_dose_bird(self.aw_bird_sm, self.mf_w_bird_1, self.food_multiplier_init_fp)
        self.out_arq_bird_se_md = self.arq_dose_bird(self.aw_bird_md, self.mf_w_bird_1, self.food_multiplier_init_fp)
        self.out_arq_bird_se_lg = self.arq_dose_bird(self.aw_bird_lg, self.mf_w_bird_1, self.food_multiplier_init_fp)

        # Table 8 (Acute dietary-based risk quotients for birds per food source and size of bird)
        self.out_arq_diet_bird_sg_a = self.arq_diet_bird(self.food_multiplier_init_sg)
        self.out_arq_diet_bird_sg_c = self.crq_diet_bird(self.food_multiplier_init_sg)
        self.out_arq_diet_bird_tg_a = self.arq_diet_bird(self.food_multiplier_init_tg)
        self.out_arq_diet_bird_tg_c = self.crq_diet_bird(self.food_multiplier_init_tg)
        self.out_arq_diet_bird_bp_a = self.arq_diet_bird(self.food_multiplier_init_blp)
        self.out_arq_diet_bird_bp_c = self.crq_diet_bird(self.food_multiplier_init_blp)
        self.out_arq_diet_bird_fp_a = self.arq_diet_bird(self.food_multiplier_init_fp)
        self.out_arq_diet_bird_fp_c = self.crq_diet_bird(self.food_multiplier_init_fp)
        self.out_arq_diet_bird_ar_a = self.arq_diet_bird(self.food_multiplier_init_arthro)
        self.out_arq_diet_bird_ar_c = self.crq_diet_bird(self.food_multiplier_init_arthro)

        # Table 9 (Chronic dose-based risk quotients for mammals per food source and size of mammal)

Answer: self.out_eec_dose_mamm_sg_sm = self.eec_dose_mamm(self.aw_mamm_sm, self.mf_w_bird_2, self.food_multiplier_init_sg)

<think>
After the comment introducing Table 9, the code should start populating the mammal dose‑based EEC series defined earlier in TrexOutputs. Following the pattern used for birds (eec_dose_bird), the first assignment will compute the short‑grass, small‑mammal dose using the eec_dose_mamm method and store it in out_eec_dose_mamm_sg_sm.
</think>
self.out_eec_dose_mamm_sg_sm = self.eec_dose_mamm(self.aw_mamm_sm, self.mf_w_mamm_2, self.food_multiplier_init_sg)