Context:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ------------------------------------------------------------------------------
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------

namespace System.ComponentModel.DataAnnotations
{
    [System.AttributeUsageAttribute((System.AttributeTargets)(384), AllowMultiple = false, Inherited = true)]
    [System.ObsoleteAttribute("This attribute is no longer in use and will be ignored if applied.")]
    public sealed partial class AssociationAttribute : System.Attribute
    {
        public AssociationAttribute(string name, string thisKey, string otherKey) { }
        public bool IsForeignKey { get { throw null; } set { } }
        public string Name { get { throw null; } }
        public string OtherKey { get { throw null; } }
        public System.Collections.Generic.IEnumerable<string> OtherKeyMembers { get { throw null; } }
        public string ThisKey { get { throw null; } }
        public System.Collections.Generic.IEnumerable<string> ThisKeyMembers { get { throw null; } }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(128), AllowMultiple = false)]
    public partial class CompareAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute
    {
        public CompareAttribute(string otherProperty) { }
        public string OtherProperty { get { throw null; } }
        public string OtherPropertyDisplayName { get { throw null; } }
        public override bool RequiresValidationContext { get { throw null; } }
        public override string FormatErrorMessage(string name) { throw null; }
        protected override System.ComponentModel.DataAnnotations.ValidationResult IsValid(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext) { throw null; }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(384), AllowMultiple = false, Inherited = true)]
    public sealed partial class ConcurrencyCheckAttribute : System.Attribute
    {
        public ConcurrencyCheckAttribute() { }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(2432), AllowMultiple = false)]
    public sealed partial class CreditCardAttribute : System.ComponentModel.DataAnnotations.DataTypeAttribute
    {
        public CreditCardAttribute() : base(default(System.ComponentModel.DataAnnotations.DataType)) { }
        public override bool IsValid(object value) { throw null; }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(2500), AllowMultiple = true)]
    public sealed partial class CustomValidationAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute
    {
        public CustomValidationAttribute(System.Type validatorType, string method) { }
        public string Method { get { throw null; } }
        public System.Type ValidatorType { get { throw null; } }
        public override string FormatErrorMessage(string name) { throw null; }
        protected override System.ComponentModel.DataAnnotations.ValidationResult IsValid(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext) { throw null; }
    }
    public enum DataType
    {
        CreditCard = 14,
        Currency = 6,
        Custom = 0,
        Date = 2,
        DateTime = 1,
        Duration = 4,
        EmailAddress = 10,
        Html = 8,
        ImageUrl = 13,
        MultilineText = 9,
        Password = 11,
        PhoneNumber = 5,
        PostalCode = 15,
        Text = 7,
        Time = 3,
        Upload = 16,
        Url = 12,
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(2496), AllowMultiple = false)]
    public partial class DataTypeAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute
    {
        public DataTypeAttribute(System.ComponentModel.DataAnnotations.DataType dataType) { }
        public DataTypeAttribute(string customDataType) { }
        public string CustomDataType { get { throw null; } }
        public System.ComponentModel.DataAnnotations.DataType DataType { get { throw null; } }
        public System.ComponentModel.DataAnnotations.DisplayFormatAttribute DisplayFormat { get { throw null; } protected set { } }
        public virtual string GetDataTypeName() { throw null; }
        public override bool IsValid(object value) { throw null; }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(2496), AllowMultiple = false)]
    public sealed partial class DisplayAttribute : System.Attribute
    {
        public DisplayAttribute() { }
        public bool AutoGenerateField { get { throw null; } set { } }
        public bool AutoGenerateFilter { get { throw null; } set { } }
        public string Description { get { throw null; } set { } }
        public string GroupName { get { throw null; } set { } }
        public string Name { get { throw null; } set { } }
        public int Order { get { throw null; } set { } }
        public string Prompt { get { throw null; } set { } }
        public System.Type ResourceType { get { throw null; } set { } }
        public string ShortName { get { throw null; } set { } }
        public System.Nullable<bool> GetAutoGenerateField() { throw null; }
        public System.Nullable<bool> GetAutoGenerateFilter() { throw null; }
        public string GetDescription() { throw null; }
        public string GetGroupName() { throw null; }
        public string GetName() { throw null; }
        public System.Nullable<int> GetOrder() { throw null; }
        public string GetPrompt() { throw null; }
        public string GetShortName() { throw null; }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(4), Inherited = true, AllowMultiple = false)]
    public partial class DisplayColumnAttribute : System.Attribute
    {
        public DisplayColumnAttribute(string displayColumn) { }
        public DisplayColumnAttribute(string displayColumn, string sortColumn) { }
        public DisplayColumnAttribute(string displayColumn, string sortColumn, bool sortDescending) { }
        public string DisplayColumn { get { throw null; } }
        public string SortColumn { get { throw null; } }
        public bool SortDescending { get { throw null; } }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(384), AllowMultiple = false)]
    public partial class DisplayFormatAttribute : System.Attribute
    {
        public DisplayFormatAttribute() { }
        public bool ApplyFormatInEditMode { get { throw null; } set { } }
        public bool ConvertEmptyStringToNull { get { throw null; } set { } }
        public string DataFormatString { get { throw null; } set { } }
        public bool HtmlEncode { get { throw null; } set { } }
        public string NullDisplayText { get { throw null; } set { } }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(384), AllowMultiple = false, Inherited = true)]
    public sealed partial class EditableAttribute : System.Attribute
    {
        public EditableAttribute(bool allowEdit) { }
        public bool AllowEdit { get { throw null; } }
        public bool AllowInitialValue { get { throw null; } set { } }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(2432), AllowMultiple = false)]
    public sealed partial class EmailAddressAttribute : System.ComponentModel.DataAnnotations.DataTypeAttribute
    {
        public EmailAddressAttribute() : base(default(System.ComponentModel.DataAnnotations.DataType)) { }
        public override bool IsValid(object value) { throw null; }
    }
    [System.AttributeUsageAttribute((System.AttributeTargets)(2496), AllowMultiple = false)]

Answer: public sealed partial class EnumDataTypeAttribute : System.ComponentModel.DataAnnotations.DataTypeAttribute

<think>
The snippet ends with an AttributeUsage attribute for a class that follows EmailAddressAttribute in the DataAnnotations namespace. The next member in the .NET source after EmailAddressAttribute is the FileExtensionsAttribute, which is declared with the given AttributeUsage flags. Therefore the next line is the class declaration for FileExtensionsAttribute.
</think>
public sealed partial class FileExtensionsAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute


Context:
/**
 *
 * Copyright (c) 2005-2012. Centre for Research on Inner City Health, St. Michael's Hospital, Toronto. All Rights Reserved.
 * This software is published under the GPL GNU General Public License.
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * This software was written for
 * Centre for Research on Inner City Health, St. Michael's Hospital,
 * Toronto, Ontario, Canada
 */
package org.oscarehr.web;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.collections.map.MultiValueMap;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.oscarehr.PMmodule.dao.ProgramDao;
import org.oscarehr.PMmodule.model.Program;
import org.oscarehr.common.dao.AdmissionDao;
import org.oscarehr.common.dao.CdsClientFormDao;
import org.oscarehr.common.dao.CdsClientFormDataDao;
import org.oscarehr.common.dao.CdsFormOptionDao;
import org.oscarehr.common.dao.CdsHospitalisationDaysDao;
import org.oscarehr.common.dao.DemographicDao;
import org.oscarehr.common.dao.FunctionalCentreDao;
import org.oscarehr.common.model.Admission;
import org.oscarehr.common.model.CdsClientForm;
import org.oscarehr.common.model.CdsClientFormData;
import org.oscarehr.common.model.CdsFormOption;
import org.oscarehr.common.model.CdsHospitalisationDays;
import org.oscarehr.common.model.Demographic;
import org.oscarehr.common.model.FunctionalCentre;
import org.oscarehr.util.AccumulatorMap;
import org.oscarehr.util.LoggedInInfo;
import org.oscarehr.util.MiscUtils;
import org.oscarehr.util.SpringUtils;

import oscar.util.DateUtils;

public final class Cds4ReportUIBean {

	private static Logger logger = MiscUtils.getLogger();

	private static FunctionalCentreDao functionalCentreDao = (FunctionalCentreDao) SpringUtils.getBean("functionalCentreDao");
	private static CdsFormOptionDao cdsFormOptionDao = (CdsFormOptionDao) SpringUtils.getBean("cdsFormOptionDao");
	private static CdsClientFormDao cdsClientFormDao = (CdsClientFormDao) SpringUtils.getBean("cdsClientFormDao");
	private static CdsClientFormDataDao cdsClientFormDataDao = (CdsClientFormDataDao) SpringUtils.getBean("cdsClientFormDataDao");
	private static AdmissionDao admissionDao = (AdmissionDao) SpringUtils.getBean("admissionDao");
	private static ProgramDao programDao = (ProgramDao) SpringUtils.getBean("programDao");
	private static CdsHospitalisationDaysDao cdsHospitalisationDaysDao = (CdsHospitalisationDaysDao) SpringUtils.getBean("cdsHospitalisationDaysDao");
	private static DemographicDao demographicDao = (DemographicDao) SpringUtils.getBean("demographicDao");

	public static final int NUMBER_OF_COHORT_BUCKETS = 11;
	private static final int NUMBER_OF_DATA_ROW_COLUMNS=NUMBER_OF_COHORT_BUCKETS+1;

	enum MinMax {
		MIN, MAX
	}

	public static class SingleMultiAdmissions {
		// key=clientId
		public HashMap<Integer, CdsClientForm> singleAdmissions = new HashMap<Integer, CdsClientForm>();

		// this is a map where key=0-10 representing each cohort bucket., value is a collection of CdsClientForms
		public MultiValueMap singleAdmissionCohortBuckets = new MultiValueMap();

		// key=clientId
		public HashMap<Integer, CdsClientForm> multipleAdmissionsLatestForms = new HashMap<Integer, CdsClientForm>();

		public ArrayList<CdsClientForm> multipleAdmissionsAllForms = new ArrayList<CdsClientForm>();

		// this is a map where key=0-10 representing each cohort bucket., value is a collection of CdsClientForms
		public MultiValueMap multipleAdmissionCohortBuckets = new MultiValueMap();

		public void addUniqueCdsProgramFormToMultipleAdmissionsAllForms(CdsClientForm cdsClientForm)
		{
			for (CdsClientForm tempForm : multipleAdmissionsAllForms)
			{
				if (tempForm.getCdsFormVersion().equals(cdsClientForm.getCdsFormVersion()) && tempForm.getAdmissionId().equals(cdsClientForm.getAdmissionId()))
				{
					if (cdsClientForm.getCreated().after(tempForm.getCreated()))
					{
						multipleAdmissionsAllForms.remove(tempForm);
						multipleAdmissionsAllForms.add(cdsClientForm);
						return;
					}
					// else do nothing and keep the old one.
				}
			}
		}
	}

	/** key=admissionId, value=admission */
	private HashMap<Integer, Admission> admissionMap = null;
	private SingleMultiAdmissions singleMultiAdmissions=null;
	private FunctionalCentre functionalCentre=null;
	private GregorianCalendar startDate=new GregorianCalendar();
	private GregorianCalendar endDateExclusive=new GregorianCalendar();
	private HashSet<String> providerIdsToReportOn=null;
	private HashSet<Integer> programIdsToReportOn=null;
	private LoggedInInfo loggedInInfo=null;

	/**
	 * End dates should be treated as inclusive.
	 */
	public Cds4ReportUIBean(LoggedInInfo loggedInInfo, String functionalCentreId, Date startDate, Date endDateInclusive, String[] providerIdList, HashSet<Integer> programIds) {

		this.loggedInInfo=loggedInInfo;
		this.startDate.setTime(startDate);
		this.endDateExclusive.setTime(endDateInclusive);
		this.endDateExclusive.add(GregorianCalendar.DAY_OF_YEAR, 1); // add 1 to make exclusive

		// put providerId's in a Hash for quicker searches.
		if (providerIdList!=null)
		{
			providerIdsToReportOn=new HashSet<String>();
			for (String s : providerIdList)
			{
				providerIdsToReportOn.add(s);
			}
		}

		programIdsToReportOn=programIds;

		functionalCentre=functionalCentreDao.find(functionalCentreId);

		admissionMap=getAdmissionMap();

		singleMultiAdmissions = getAdmissionsSortedSingleMulti();
	}

	public String getFunctionalCentreDescription()
	{
		return(StringEscapeUtils.escapeHtml(functionalCentre.getAccountId()+", "+functionalCentre.getDescription()));
	}

	public String getDateRangeForDisplay()
	{
		SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
		GregorianCalendar displayEndDate=(GregorianCalendar) endDateExclusive.clone();
		displayEndDate.add(GregorianCalendar.DAY_OF_YEAR, -1);
		return(StringEscapeUtils.escapeHtml(simpleDateFormat.format(startDate.getTime())+" to "+simpleDateFormat.format(displayEndDate.getTime())+" (inclusive)"));
	}

	public static List<CdsFormOption> getCdsFormOptions()
	{
		return(cdsFormOptionDao.findByVersion("4"));
	}

	private SingleMultiAdmissions getAdmissionsSortedSingleMulti() {
		SingleMultiAdmissions singleMultiAdmissions = new SingleMultiAdmissions();

		List<CdsClientForm> cdsForms = cdsClientFormDao.findSignedCdsForms(loggedInInfo.getCurrentFacility().getId(), "4", startDate.getTime(), endDateExclusive.getTime());
		logger.debug("valid cds form count, "+loggedInInfo.getCurrentFacility().getId()+", 4, "+startDate.getTime()+", "+endDateExclusive.getTime()+", "+cdsForms.size());

		// sort into single and multiple admissions
		for (CdsClientForm form : cdsForms) {
			logger.debug("valid cds form, id="+form.getId());

			// make sure form is for an admission for which we're interested, i.e. admissions are filtered by program and admission time already
			Admission admission = admissionMap.get(form.getAdmissionId());
			if (admission == null) {
				logger.debug("cds form missing admission / or not in admission we're interested in dueto program or time restriction. formId="+form.getId()+", admissionId="+form.getAdmissionId());
				continue;
			}
			else
			{
				// check if the cds form is signed by a provider we're reporting on.
				if (providerIdsToReportOn!=null) // if we've been asked to filter
				{
					if (!providerIdsToReportOn.contains(form.getProviderNo())) // if the provider isn't in our allowed list
					{
						continue;
					}
				}
			}

			Integer clientId = form.getClientId();

			CdsClientForm existingForm = singleMultiAdmissions.multipleAdmissionsLatestForms.get(clientId);
			// if this person already has multiple admissions
			if (existingForm != null) {
				logger.debug("multiple admissions 3+ forms. formId="+form.getId()+", otherFormId="+existingForm.getId());
				singleMultiAdmissions.multipleAdmissionsLatestForms.put(clientId, getNewerForm(existingForm, form));
				singleMultiAdmissions.addUniqueCdsProgramFormToMultipleAdmissionsAllForms(form);
			} else // this person either has one previous or no previous admissions
			{
				existingForm = singleMultiAdmissions.singleAdmissions.get(clientId);
				// this means we have 1 previous admission
				if (existingForm != null) {

					// check that it's actually multiple admission and not just multiple forms for 1 admission

					// they are the same, just pick the newer form
					if (existingForm.getAdmissionId().equals(form.getAdmissionId()))
					{
						if (form.getCreated().after(existingForm.getCreated()))
						{
							singleMultiAdmissions.singleAdmissions.put(clientId, form);
						}
					}
					else
					{
						logger.debug("multiple admissions, 2 forms : formId="+form.getId()+", otherFormId="+existingForm.getId());

Answer: singleMultiAdmissions.multipleAdmissionsLatestForms.put(clientId, getNewerForm(existingForm, form));

<think>
The code is inside getAdmissionsSortedSingleMulti(). When a second admission is detected (different admissionId), the comment indicates handling multiple admissions. The next logical step is to record the latest form for this client in the multipleAdmissionsLatestForms map, similar to later handling of existing multiple admissions. Therefore the next line should add or update the map with the newer of the existing and current forms.
</think>
singleMultiAdmissions.multipleAdmissionsLatestForms.put(clientId, getNewerForm(existingForm, form));


Context:
# Copyright 2011 OpenStack Foundation
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import uuid

import ddt
import mock
from oslo_serialization import jsonutils
from six.moves import http_client
import webob

from cinder.api import extensions
from cinder.api.v2 import snapshot_metadata
from cinder.api.v2 import snapshots
from cinder import context
import cinder.db
from cinder import exception
from cinder.objects import fields
from cinder import test
from cinder.tests.unit.api import fakes
from cinder.tests.unit import fake_constants as fake
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder import volume

def return_create_snapshot_metadata(context, snapshot_id, metadata, delete):
    return fake_snapshot_metadata()

def return_create_snapshot_metadata_insensitive(context, snapshot_id,
                                                metadata, delete):
    return fake_snapshot_metadata_insensitive()

def return_new_snapshot_metadata(context, snapshot_id, metadata, delete):
    return fake_new_snapshot_metadata()

def fake_snapshot_metadata():
    metadata = {
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
    }
    return metadata

def fake_snapshot_metadata_insensitive():
    metadata = {
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
        "KEY4": "value4",
    }
    return metadata

def fake_new_snapshot_metadata():
    metadata = {
        'key10': 'value10',
        'key99': 'value99',
        'KEY20': 'value20',
    }
    return metadata

def return_snapshot(context, snapshot_id):
    return {'id': '0cc3346e-9fef-4445-abe6-5d2b2690ec64',
            'name': 'fake',
            'status': 'available',
            'metadata': {}}

# First argument needs to be self to receive the context argument in the right
# variable, as this'll be used to replace the original API.get method which
# receives self as the first argument.
def fake_get(self, context, *args, **kwargs):
    vol = {'id': fake.VOLUME_ID,
           'size': 100,
           'name': 'fake',
           'host': 'fake-host',
           'status': 'available',
           'encryption_key_id': None,
           'volume_type_id': None,
           'migration_status': None,
           'availability_zone': 'fake-zone',
           'attach_status': fields.VolumeAttachStatus.DETACHED,
           'metadata': {}}
    return fake_volume.fake_volume_obj(context, **vol)

def return_snapshot_nonexistent(context, snapshot_id):
    raise exception.SnapshotNotFound(snapshot_id=snapshot_id)

@ddt.ddt
class SnapshotMetaDataTest(test.TestCase):

    def setUp(self):
        super(SnapshotMetaDataTest, self).setUp()
        self.volume_api = cinder.volume.api.API()
        self.mock_object(volume.api.API, 'get', fake_get)
        self.mock_object(cinder.db, 'snapshot_get', return_snapshot)
        self.mock_object(self.volume_api, 'update_snapshot_metadata')

        self.ext_mgr = extensions.ExtensionManager()
        self.ext_mgr.extensions = {}
        self.snapshot_controller = snapshots.SnapshotsController(self.ext_mgr)
        self.controller = snapshot_metadata.Controller()
        self.req_id = str(uuid.uuid4())
        self.url = '/v2/%s/snapshots/%s/metadata' % (
            fake.PROJECT_ID, self.req_id)

        snap = {"volume_size": 100,
                "volume_id": fake.VOLUME_ID,
                "display_name": "Volume Test Name",
                "display_description": "Volume Test Desc",
                "availability_zone": "zone1:host1",
                "host": "fake-host",
                "metadata": {}}
        body = {"snapshot": snap}
        req = fakes.HTTPRequest.blank('/v2/snapshots')
        self.snapshot_controller.create(req, body)

    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_index(self, snapshot_get_by_id):
        snapshot = {
            'id': self.req_id,
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        snapshot_obj['metadata'] = {'key1': 'value1',
                                    'key2': 'value2',
                                    'key3': 'value3'}
        snapshot_get_by_id.return_value = snapshot_obj

        req = fakes.HTTPRequest.blank(self.url)
        res_dict = self.controller.index(req, self.req_id)

        expected = {
            'metadata': {
                'key1': 'value1',
                'key2': 'value2',
                'key3': 'value3',
            },
        }
        self.assertEqual(expected, res_dict)

    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_index_nonexistent_snapshot(self, snapshot_get_by_id):
        snapshot_get_by_id.side_effect = \
            exception.SnapshotNotFound(snapshot_id=self.req_id)

        req = fakes.HTTPRequest.blank(self.url)
        self.assertRaises(exception.SnapshotNotFound,
                          self.controller.index, req, self.url)

    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_index_no_data(self, snapshot_get_by_id):
        snapshot = {
            'id': self.req_id,
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        snapshot_get_by_id.return_value = snapshot_obj

        req = fakes.HTTPRequest.blank(self.url)
        res_dict = self.controller.index(req, self.req_id)
        expected = {'metadata': {}}
        self.assertEqual(expected, res_dict)

    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_show(self, snapshot_get_by_id):
        snapshot = {
            'id': self.req_id,
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        snapshot_obj['metadata'] = {'key2': 'value2'}
        snapshot_get_by_id.return_value = snapshot_obj

        req = fakes.HTTPRequest.blank(self.url + '/key2')
        res_dict = self.controller.show(req, self.req_id, 'key2')
        expected = {'meta': {'key2': 'value2'}}
        self.assertEqual(expected, res_dict)

    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_show_nonexistent_snapshot(self, snapshot_get_by_id):
        snapshot_get_by_id.side_effect = \
            exception.SnapshotNotFound(snapshot_id=self.req_id)

        req = fakes.HTTPRequest.blank(self.url + '/key2')
        self.assertRaises(exception.SnapshotNotFound,
                          self.controller.show, req, self.req_id, 'key2')

    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_show_meta_not_found(self, snapshot_get_by_id):
        snapshot = {
            'id': self.req_id,
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        snapshot_get_by_id.return_value = snapshot_obj

        req = fakes.HTTPRequest.blank(self.url + '/key6')
        self.assertRaises(exception.SnapshotMetadataNotFound,
                          self.controller.show, req, self.req_id, 'key6')

    @mock.patch('cinder.db.snapshot_metadata_delete')
    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_delete(self, snapshot_get_by_id, snapshot_metadata_delete):
        snapshot = {
            'id': self.req_id,
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        snapshot_obj['metadata'] = {'key2': 'value2'}
        snapshot_get_by_id.return_value = snapshot_obj

        req = fakes.HTTPRequest.blank(self.url + '/key2')
        req.method = 'DELETE'
        res = self.controller.delete(req, self.req_id, 'key2')

        self.assertEqual(http_client.OK, res.status_int)

    def test_delete_nonexistent_snapshot(self):
        self.mock_object(cinder.db, 'snapshot_get',
                         return_snapshot_nonexistent)
        req = fakes.HTTPRequest.blank(self.url + '/key1')
        req.method = 'DELETE'
        self.assertRaises(exception.SnapshotNotFound,
                          self.controller.delete, req, self.req_id, 'key1')

    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_delete_meta_not_found(self, snapshot_get_by_id):
        snapshot = {
            'id': self.req_id,
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        snapshot_get_by_id.return_value = snapshot_obj

        req = fakes.HTTPRequest.blank(self.url + '/key6')
        req.method = 'DELETE'
        self.assertRaises(exception.SnapshotMetadataNotFound,
                          self.controller.delete, req, self.req_id, 'key6')

    @mock.patch('cinder.db.snapshot_update')
    @mock.patch('cinder.objects.Volume.get_by_id')
    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_create(self, snapshot_get_by_id, volume_get_by_id,
                    snapshot_update):
        snapshot = {
            'id': self.req_id,
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        fake_volume_obj = fake_volume.fake_volume_obj(ctx)
        snapshot_get_by_id.return_value = snapshot_obj
        volume_get_by_id.return_value = fake_volume_obj

        self.mock_object(cinder.db, 'snapshot_metadata_update',
                         return_create_snapshot_metadata)

        req = fakes.HTTPRequest.blank('/v2/snapshot_metadata')
        req.method = 'POST'
        req.content_type = "application/json"
        body = {"metadata": {"key1": "value1",
                             "key2": "value2",
                             "key3": "value3"}}
        req.body = jsonutils.dump_as_bytes(body)
        res_dict = self.controller.create(req, self.req_id, body)
        self.assertEqual(body, res_dict)

    @mock.patch('cinder.db.snapshot_update')
    @mock.patch('cinder.objects.Snapshot.get_by_id')
    def test_create_with_keys_in_uppercase_and_lowercase(
            self, snapshot_get_by_id, snapshot_update):
        snapshot = {
            'id': self.req_id,
            'expected_attrs': ['metadata']
        }
        ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
        snapshot_obj = fake_snapshot.fake_snapshot_obj(ctx, **snapshot)
        snapshot_get_by_id.return_value = snapshot_obj

        # if the keys in uppercase_and_lowercase, should return the one
        # which server added
        self.mock_object(cinder.db, 'snapshot_metadata_update',
                         return_create_snapshot_metadata_insensitive)

Answer: req = fakes.HTTPRequest.blank('/v2/snapshot_metadata')

<think>
The test method is setting up a scenario for creating snapshot metadata with mixed‑case keys. After the comment, the next logical step is to construct the HTTP request object, just as in the previous test_create method. The appropriate line creates a fake request targeting the snapshot metadata endpoint.
</think>
req = fakes.HTTPRequest.blank('/v2/snapshot_metadata')


Context:
package edu.uga.cs.pcf.base;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

import models.pcf.pcl.BinaryExpression;
import models.pcf.pcl.Func;
import models.pcf.pcl.PCLCondition;
import models.pcf.pcl.PCLConstraint;
import models.pcf.pcl.PCLConstraintConstantAttribute;
import models.pcf.pcl.PCLConstraintOperation;
import models.pcf.pcl.PCLContext;
import models.pcf.pcl.PCLExceptionHandler;
import models.pcf.pcl.PCLExpression;
import models.pcf.pcl.PCLPreCondition;
import models.pcf.pcl.PCLProcessElement;
import models.pcf.pcl.UnaryExpression;

import org.apache.log4j.Logger;
import org.switchyard.component.camel.model.v1.V1CamelImplementationModel;
import org.switchyard.config.model.composite.ComponentImplementationModel;
import org.switchyard.config.model.composite.ComponentModel;
import org.switchyard.config.model.composite.ComponentServiceModel;
import org.switchyard.config.model.composite.CompositeReferenceModel;
import org.switchyard.config.model.composite.CompositeServiceModel;
import org.switchyard.config.model.composite.InterfaceModel;
import org.switchyard.config.model.composite.v1.V1ComponentModel;
import org.switchyard.config.model.composite.v1.V1ComponentReferenceModel;
import org.switchyard.config.model.composite.v1.V1InterfaceModel;

import pcf.pcl.PCLParseResult;
import pcf.pcl.PCLParser;
import scala.Option;
import scala.collection.Iterator;

import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.io.CharStreams;
import com.google.common.io.Closeables;

import edu.uga.cs.pcf.base.ServiceRegistry.ServiceRegistryInformation;

/**
 * Takes pcl and switchyard.xml as input, generates the backbone of constraint
 * operations and service integration template that are compatible with SCA
 * specifications.
 */
public class PcfLinker {

    private static final String SWITCHYARD_XML = "switchyard.xml";
    private static final String NEPOTISM_PCL = "nepotism.pcl";
    private static final Logger logger = Logger.getLogger(PcfLinker.class);
    private InputStream pcl;
    private InputStream switchyard;
    private PCLParseResult pclResult;
    private SwitchyardConfigParser switchyardParser;

    /**
     * Parses pcl file and switchyard configuration
     */
    public void initialize() {
        // Parses pcl
        PCLParser parser = new PCLParser();
        String content = null;
        try {
            content = CharStreams.toString(new InputStreamReader(pcl, Charsets.UTF_8));
            this.pclResult = parser.pclParse(content);
            logger.info("------------------ parsed pcl --------------------");
            logger.info(this.pclResult);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            Closeables.closeQuietly(pcl);
        }

        // Parses switchyard configuration
        this.switchyard = getDefaultSwitchyard();
        try {
            this.switchyardParser = new SwitchyardConfigParser(this.switchyard);
            logger.info("------------------ parsed switchyard configuration --------------------");
            logger.info(this.switchyardParser);
        } catch (Exception ex) {
            logger.error("failed to parse switchard configuration xml.", ex);
        } finally {
            Closeables.closeQuietly(this.switchyard);
        }
    }

    /**
     * Connects pcl and switchyard and links the two by generating the service
     * integration template
     */
    public void link() {
        logger.info("--------------begin linking pcl and switchyard----------------");
        // Gets all the constraints
        Option<PCLConstraint> constraint = this.pclResult.constraint();
        PCLConstraint pclConstraint = null;
        if (!constraint.isEmpty()) {
            pclConstraint = constraint.get();
        }
        PCLContext context = pclConstraint.context();
        scala.collection.immutable.List<PCLProcessElement> processElements = context.elements();
        Iterator<PCLProcessElement> iter = processElements.toIterator();
        logger.info("--------------process elements----------------");
        List<PCLProcessElement> activities = Lists.newArrayList();
        while (iter.hasNext()) {
            PCLProcessElement processElement = iter.next();
            logger.info(processElement);
            activities.add(processElement);
        }

        // constraint operations
        logger.info("--------------constraint operations----------------");
        scala.collection.immutable.List<PCLCondition> conditions = pclConstraint.conditions();
        Iterator<PCLCondition> condIter = conditions.toIterator();
        List<PCLCondition> pclConditions = Lists.newArrayList();
        while (condIter.hasNext()) {
            PCLCondition cond = condIter.next();
            logger.info(cond);
            pclConditions.add(cond);
        }

        // pcl exceptions
        logger.info("--------------pcl exceptions----------------");
        Option<PCLExceptionHandler> exceptionHandlerOption = pclConstraint.exceptionHandler();
        PCLExceptionHandler exceptionHandler = null;
        if (exceptionHandlerOption.isDefined()) {
            exceptionHandler = exceptionHandlerOption.get();
        }
        logger.info(exceptionHandler);

        // Gets all the switchyard configuration
        java.util.List<CompositeServiceModel> services = this.switchyardParser.getServices();
        java.util.List<CompositeReferenceModel> references = this.switchyardParser.getReferences();
        java.util.List<ComponentModel> components = this.switchyardParser.getComponents();
        for (CompositeServiceModel service : services) {
             logger.info("-----------------------------------------------------------------------");
             logger.info(String.format("service name %s", service.getName()));
        }
        for (ComponentModel component : components) {
            logger.info("-----------------------------------------------------------------------");
            logger.info(String.format("component name %s\tservice name %s", component.getName(), getServiceName(component)));
        }
        for (CompositeReferenceModel reference : references) {
            logger.info("-----------------------------------------------------------------------");
            logger.info(String.format("reference name %s", reference.getName()));
        }

        /*
         * Links pcl and switchyard configuration and follows service integration
         * template
         * Step 1: match the services with an sca component associated to an sca service
         */
        List<PclSwitchyardMatcher> matches = findMatched(activities, pclConditions, exceptionHandler, services, components);
        logger.info("-----------------------------------------------------------------------");
        logger.info("found matched activity and sca component");
        logger.info(Joiner.on("\n").join(matches));

        /*
         * Step 2: for these matched services, creates a new camel route following
         * service integration template.
         * The new component should have the exact implementation with the old one.
         */
        for (PclSwitchyardMatcher match : matches) {
            ComponentModel newComponent = buildCamelRouteComponent(match);
            match.setNewComponent(newComponent);
        }
    }

    /**
     * Creates a camel route component and creates the skeleton camel route in Java.
     * @param match
     * @return
     */
    private ComponentModel buildCamelRouteComponent(PclSwitchyardMatcher match) {
        Preconditions.checkArgument(match != null);

        // sca component
        ComponentModel old = match.getOldComponent();
        logger.info("------------old component--------------");
        logger.info(old);

        // sca service
        CompositeServiceModel service = match.getService();
        logger.info("------------sca service--------------");
        logger.info(service);

        // Constraint pcl

        // This target name space is kept the same
        String namespace = old.getTargetNamespace();

        ComponentModel result = new V1ComponentModel();

        // Set up service name
        result.setName(old.getName());

        // Sets up the service and uses the same old ones
        List<ComponentServiceModel> services = old.getServices();
        for (ComponentServiceModel s : services) {
            result.addService(s);
        }

        /*
         * sample sca references and services:
         * <sca:service name="JobInterview">
         *   <sca:interface.wsdl interface="JobInterview.wsdl#wsdl.porttype(JobInterviewPortType)"/>
         * </sca:service>
         * <sca:reference name="JobInterviewService">
         *   <sca:interface.wsdl interface="JobInterview.wsdl#wsdl.porttype(JobInterviewPortType)"/>
         * </sca:reference>
         * <sca:reference name="NepotismCheckerInvoker">
         *   <sca:interface.java interface="edu.uga.cs.pcf.services.jobinterview.NepotismCheckerInvoker"/>
         * </sca:reference>
         * <sca:reference name="FailedConstraintOperationLoggerInvoker">
         *   <sca:interface.java interface="edu.uga.cs.pcf.process.emergencyreaction.FailedConstraintOperationLoggerInvoker"/>
         * </sca:reference>
         * <sca:reference name="ContextMonitorInvoker">
         *   <sca:interface.java interface="edu.uga.cs.pcf.process.monitor.ContextMonitorInvoker"/>
         * </sca:reference>
         */

        // Adds a references to the existing service, because the original service
        // is now integrated within and referenced by the new camel route.
        // Sets up name and interface properly.
        logger.info("-------------------add original service reference-------------------");
        V1ComponentReferenceModel serviceRef = new V1ComponentReferenceModel(namespace);
        serviceRef.setName(service.getName());
        serviceRef.setInterface(service.getInterface());

Answer: result.addReference(serviceRef);

<think>
The method is building a new component model for a Camel route. After creating a V1ComponentReferenceModel for the original service and setting its name and interface, the next logical step is to attach this reference to the component being built. The ComponentModel API provides an addReference method, so the next line should add the serviceRef to the result component.
</think>
result.addReference(serviceRef);


Context:
using UnityEngine;
using System.Collections;

[ExecuteInEditMode] // Make water live-update even when not in play mode
public class SeaShader : MonoBehaviour
{

	//private WhirldObject whirldObject;

	public enum WaterMode {
		Simple = 0,
		Reflective = 1,
		Refractive = 2,
	};
	public WaterMode m_WaterMode = WaterMode.Reflective;
	public bool m_DisablePixelLights = true;
	public int m_TextureSize = 256;
	public float m_ClipPlaneOffset = 0.07f;
	public LayerMask cullingMask;

	public Transform WaterTransform;

	public LayerMask m_ReflectLayers = -1;
	public LayerMask m_RefractLayers = -1;

	public Shader m_ShaderFull;
	public Shader m_ShaderSimple;

	public bool isSurface = true;

	private Hashtable m_ReflectionCameras = new Hashtable(); // Camera -> Camera table
	private Hashtable m_RefractionCameras = new Hashtable(); // Camera -> Camera table

	private RenderTexture m_ReflectionTexture = null;
	private RenderTexture m_RefractionTexture = null;
	private WaterMode m_HardwareWaterSupport = WaterMode.Reflective;
	private int m_OldReflectionTextureSize = 0;
	private int m_OldRefractionTextureSize = 0;

	//private double tickTime = 0.0f;

	private Terrain m_Terrain;

	private static bool s_InsideWater = false;

	// This is called when it's known that the object will be rendered by some
	// camera. We render reflections / refractions and do other updates here.
	// Because the script executes in edit mode, reflections for the scene view
	// camera will just work!

	/*void Start() {
		whirldObject = transform.parent.gameObject.GetComponent(WhirldObject);
		if(whirldObject == null || whirldObject.params == null) {
			return;
		}
		if(whirldObject.params["Mode"]) {
			m_SeaMode = Enum.Parse(typeof(SeaMode), whirldObject.params["Mode"], true);
		}
	}*/

	/*public void SetSeaMode(string mode)
	{
		m_SeaMode = (SeaMode) System.Enum.Parse(typeof(SeaMode), mode, true);
	}*/

	public void OnWillRenderObject()
	{

		if( !enabled || !renderer || !renderer.sharedMaterial || !renderer.enabled )	// || Time.time < tickTime)
			return;

		//tickTime = Time.time + .05;

		if( !m_Terrain ) {
			m_Terrain = Terrain.activeTerrain;
			/*GameObject go = GameObject.Find("Terrain");
			if( !go )
				return;
			m_Terrain = go.GetComponent(typeof(Terrain)) as Terrain;
			if( !m_Terrain )
				return;*/
		}

		Camera cam = Camera.current;
		if( !cam )
			return;

		// Safeguard from recursive water reflections.
		if( s_InsideWater )
			return;
		s_InsideWater = true;

		// Actual water rendering mode depends on both the current setting AND
		// the hardware support. There's no point in rendering refraction textures
		// if they won't be visible in the end.
		m_HardwareWaterSupport = FindHardwareWaterSupport();
		WaterMode mode = GetWaterMode();
		Shader newShader = ( mode == WaterMode.Refractive ) ? m_ShaderFull : m_ShaderSimple;
		if( renderer.sharedMaterial.shader != newShader )
			renderer.sharedMaterial.shader = newShader;

		Camera reflectionCamera, refractionCamera;
		CreateWaterObjects( cam, out reflectionCamera, out refractionCamera );

		//Apply SeaMode
		//renderer.sharedMaterial.SetColor( "_RefrColor", SeaModeColors[ (int)m_SeaMode ] );

		// find out the reflection plane: position and normal in world space
		Vector3 pos = transform.position;
		Vector3 normal = transform.up;

		// Optionally disable pixel lights for reflection/refraction
		int oldPixelLightCount = QualitySettings.pixelLightCount;
		if( m_DisablePixelLights )
			QualitySettings.pixelLightCount = 0;

		UpdateCameraModes( cam, reflectionCamera );
		UpdateCameraModes( cam, refractionCamera );

		bool oldSoftVegetation = QualitySettings.softVegetation;
		QualitySettings.softVegetation = false;

		// Render reflection if needed
		if( mode >= WaterMode.Reflective/* && isSurface*/)
		{
			// Reflect camera around reflection plane
			float d = -Vector3.Dot (normal, pos) - m_ClipPlaneOffset;
			Vector4 reflectionPlane = new Vector4 (normal.x, normal.y, normal.z, d);

			Matrix4x4 reflection = Matrix4x4.zero;
			CalculateReflectionMatrix (ref reflection, reflectionPlane);
			Vector3 oldpos = cam.transform.position;
			Vector3 newpos = reflection.MultiplyPoint( oldpos );
			reflectionCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;

			// Setup oblique projection matrix so that near plane is our reflection
			// plane. This way we clip everything below/above it for free.
			Vector4 clipPlane = CameraSpacePlane( reflectionCamera, pos, normal, 1.0f );
			Matrix4x4 projection = cam.projectionMatrix;
			CalculateObliqueMatrix (ref projection, clipPlane);
			reflectionCamera.projectionMatrix = projection;

			reflectionCamera.cullingMask = cullingMask & m_ReflectLayers.value; // never render water layer
			reflectionCamera.targetTexture = m_ReflectionTexture;
			GL.SetRevertBackfacing (true);
			reflectionCamera.transform.position = newpos;
			Vector3 euler = cam.transform.eulerAngles;
			reflectionCamera.transform.eulerAngles = new Vector3(0, euler.y, euler.z);

			// don't render tree meshes or grass in reflection :)
			float oldDetailDist = m_Terrain.detailObjectDistance;
			float oldTreeDist = m_Terrain.treeDistance;
			float oldTreeBillDist = m_Terrain.treeBillboardDistance;
			float oldSplatDist = m_Terrain.basemapDistance;
			m_Terrain.detailObjectDistance = 0.0f;
			m_Terrain.treeBillboardDistance = 0.0f;
			m_Terrain.basemapDistance = 0.0f;

			reflectionCamera.Render();

			m_Terrain.detailObjectDistance = oldDetailDist;
			m_Terrain.treeDistance = oldTreeDist;
			m_Terrain.treeBillboardDistance = oldTreeBillDist;
			m_Terrain.basemapDistance = oldSplatDist;

			reflectionCamera.transform.position = oldpos;
			GL.SetRevertBackfacing (false);
			renderer.sharedMaterial.SetTexture( "_ReflectionTex", m_ReflectionTexture );
		}
		else renderer.sharedMaterial.SetTexture( "_ReflectionTex", null );

		// Render refraction
		if( mode >= WaterMode.Refractive )
		{
			refractionCamera.worldToCameraMatrix = cam.worldToCameraMatrix;

			// Setup oblique projection matrix so that near plane is our reflection
			// plane. This way we clip everything below/above it for free.
			Vector4 clipPlane = CameraSpacePlane( refractionCamera, pos, normal, -1.0f );
			Matrix4x4 projection = cam.projectionMatrix;
			CalculateObliqueMatrix (ref projection, clipPlane);
			refractionCamera.projectionMatrix = projection;

			refractionCamera.cullingMask = cullingMask & m_RefractLayers.value; // never render water layer
			refractionCamera.targetTexture = m_RefractionTexture;
			refractionCamera.transform.position = cam.transform.position;
			refractionCamera.transform.rotation = cam.transform.rotation;

			// don't render trees or grass in refraction :)
			float oldDetailDist = m_Terrain.detailObjectDistance;
			float oldTreeDist = m_Terrain.treeDistance;
			float oldTreeBillDist = m_Terrain.treeBillboardDistance;
			m_Terrain.detailObjectDistance = 0.0f;
			m_Terrain.treeDistance = 0.0f;
			m_Terrain.treeBillboardDistance = 0.0f;

			refractionCamera.Render();

			m_Terrain.detailObjectDistance = oldDetailDist;

Answer: m_Terrain.treeDistance = oldTreeDist;

<think>
The code is inside the refraction rendering block. After rendering, it restores terrain detail settings. It already restored m_Terrain.detailObjectDistance = oldDetailDist; The next logical restoration is the tree distance that was saved in oldTreeDist. Therefore the next line should set m_Terrain.treeDistance to oldTreeDist.
</think>
m_Terrain.treeDistance = oldTreeDist;


Context:
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using FluentAssertions;
using Its.Log.Instrumentation;
using Microsoft.Its.Domain.Sql.CommandScheduler;
using Microsoft.Its.Recipes;
using NUnit.Framework;
using Sample.Domain;
using Sample.Domain.Ordering;
using Sample.Domain.Ordering.Commands;
using System;
using System.Linq;
using System.Reactive.Disposables;
using System.Threading.Tasks;

namespace Microsoft.Its.Domain.Testing.Tests
{
    [TestFixture]
    public abstract class ScenarioBuilderTests
    {
        private CompositeDisposable disposables;

        protected ScenarioBuilderTests()
        {
            Command<CustomerAccount>.AuthorizeDefault = (customer, command) => true;
            Command<Order>.AuthorizeDefault = (order, command) => true;
        }

        [SetUp]
        public virtual void SetUp()
        {
            disposables = new CompositeDisposable(
                Disposable.Create(() => ConfigurationContext.Current
                                          .IfNotNull()
                                          .ThenDo(c => c.Dispose())));
        }

        [TearDown]
        public virtual void TearDown()
        {
            disposables.Dispose();
        }

        protected void RegisterForDisposal(IDisposable disposable)
        {
            disposables.Add(disposable);
        }

        [Test]
        public void Events_added_to_the_scenario_are_used_to_source_aggregates()
        {
            var name = Any.FullName();
            var aggregateId = Any.Guid();
            var orderNumber = Any.Int(2000, 5000).ToString();

            var scenario = CreateScenarioBuilder()
                .AddEvents(new Order.Created
                {
                    AggregateId = aggregateId,
                    OrderNumber = orderNumber
                }, new Order.CustomerInfoChanged
                {
                    AggregateId = aggregateId,
                    CustomerName = name
                }).Prepare();

            var order = scenario.Aggregates.Single() as Order;

            order.Should().NotBeNull();
            order.OrderNumber.Should().Be(orderNumber);
            order.CustomerName.Should().Be(name);
            order.Id.Should().Be(aggregateId);
        }

        [Test]
        public void If_no_aggregate_id_is_specified_when_adding_events_then_a_default_is_chosen_and_reused()
        {
            var created = new Order.Created();
            var customerInfoChanged = new Order.CustomerInfoChanged();

            CreateScenarioBuilder()
                .AddEvents(created, customerInfoChanged);

            created.AggregateId.Should().NotBeEmpty();
            customerInfoChanged.AggregateId.Should().Be(created.AggregateId);
        }

        [Test]
        public async Task If_no_aggregate_id_is_specified_when_calling_GetLatest_and_a_single_instance_is_in_the_scenario_then_it_is_returned()
        {
            var aggregateId = Any.Guid();
            var created = new Order.Created
            {
                AggregateId = aggregateId
            };

            var scenario = CreateScenarioBuilder().AddEvents(created).Prepare();

            var aggregate = await scenario.GetLatestAsync<Order>();

            aggregate.Should().NotBeNull();
            aggregate.Id.Should().Be(aggregateId);
        }

        [Test]
        public void If_no_aggregate_id_is_specified_when_calling_GetLatest_and_no_instance_is_in_the_scenario_then_it_throws()
        {
            var scenario = CreateScenarioBuilder()
                .AddEvents(new Order.Created
                {
                    AggregateId = Any.Guid()
                }, new Order.Created
                {
                    AggregateId = Any.Guid()
                }).Prepare();

            Action getLatest = () => scenario.GetLatestAsync<Order>().Wait();

            getLatest.ShouldThrow<InvalidOperationException>();
        }

        [Test]
        public void If_no_aggregate_id_is_specified_when_calling_GetLatest_and_multiple_instances_are_in_the_scenario_then_it_throws()
        {
            var scenario = CreateScenarioBuilder().Prepare();

            Action getLatest = () => scenario.GetLatestAsync<Order>().Wait();

            getLatest.ShouldThrow<InvalidOperationException>();
        }

        [Test]
        public void When_no_sequence_numbers_are_specified_then_events_are_applied_in_order()
        {
            var aggregateId = Any.Guid();
            var firstCustomerName = Any.FullName();
            var scenario = CreateScenarioBuilder()
                .AddEvents(new Order.CustomerInfoChanged
                {
                    AggregateId = aggregateId,
                    CustomerName = Any.FullName()
                }, new Order.CustomerInfoChanged
                {
                    AggregateId = aggregateId,
                    CustomerName = firstCustomerName
                }).Prepare();

            var order = scenario.Aggregates.OfType<Order>().Single();

            order.CustomerName.Should().Be(firstCustomerName);
        }

        [Test]
        public void DynamicProjectors_registered_as_event_handlers_in_ScenarioBuilder_run_catchups_when_prepare_is_called()
        {
            var firstShipHandled = false;
            var secondShipHandled = false;
            var handler = Domain.Projector.CreateDynamic(dynamicEvent =>
            {
                var @event = dynamicEvent as IEvent;
                @event.IfTypeIs<CommandScheduled<Order>>()
                      .ThenDo(c =>
                      {
                          var shipmentId = (c.Command as Ship).ShipmentId;
                          Console.WriteLine("Handling [{0}] Shipment", shipmentId);
                          if (shipmentId == "first")
                          {
                              firstShipHandled = true;
                          }
                          else if (shipmentId == "second")
                          {
                              secondShipHandled = true;
                          }
                      });
            },
                                                         "Order.Scheduled:Ship");
            CreateScenarioBuilder()
                .AddHandler(handler)
                .AddEvents(
                    new CommandScheduled<Order>
                    {
                        Command = new Ship { ShipmentId = "first" },
                        DueTime = DateTime.Now
                    },
                    new CommandScheduled<Order>
                    {
                        Command = new Ship { ShipmentId = "second" },
                        DueTime = DateTime.Now
                    })
                .Prepare();

            firstShipHandled.Should().BeTrue();
            secondShipHandled.Should().BeTrue();
        }

        [Test]
        public void When_sequence_numbers_are_specified_it_overrides_the_order_in_which_the_events_were_added()
        {
            var aggregateId = Any.Guid();
            var firstCustomerName = Any.FullName();
            var scenario = CreateScenarioBuilder()
                .AddEvents(new Order.CustomerInfoChanged
                {
                    AggregateId = aggregateId,
                    CustomerName = firstCustomerName,
                    SequenceNumber = 2
                }, new Order.CustomerInfoChanged
                {
                    AggregateId = aggregateId,
                    CustomerName = Any.FullName(),
                    SequenceNumber = 1
                }).Prepare();

            var order = scenario.Aggregates.OfType<Order>().Single();

            order.CustomerName.Should().Be(firstCustomerName);
        }

        [Test]
        public void Multiple_aggregates_of_the_same_type_can_be_sourced_in_one_scenario()
        {
            var builder = CreateScenarioBuilder()
                .AddEvents(new Order.Created
                {
                    AggregateId = Any.Guid()
                }, new Order.Created
                {
                    AggregateId = Any.Guid()
                });

            builder.Prepare().Aggregates
                   .OfType<Order>()
                   .Count()
                   .Should().Be(2);
        }

        [Test]
        public void Multiple_aggregates_of_different_types_can_be_sourced_in_one_scenario()
        {
            // arrange
            var builder = CreateScenarioBuilder()
                .AddEvents(new Order.Created
                {
                    AggregateId = Any.Guid()
                }, new CustomerAccount.EmailAddressChanged
                {
                    AggregateId = Any.Guid()
                });

            // act
            var scenario = builder.Prepare();

            // assert
            scenario.Aggregates
                    .Should()
                    .ContainSingle(a => a is CustomerAccount)
                    .And
                    .ContainSingle(a => a is Order);
        }

        [Test]
        public void Multiple_aggregates_of_the_same_type_can_be_organized_using_For()
        {
            var aggregateId1 = Any.Guid();
            var aggregateId2 = Any.Guid();

            var builder = CreateScenarioBuilder();
            builder.For<Order>(aggregateId1)
                   .AddEvents(new Order.ItemAdded { ProductName = "one" });
            builder.For<Order>(aggregateId2)
                   .AddEvents(new Order.ItemAdded { ProductName = "two" });

            var aggregates = builder.Prepare().Aggregates.OfType<Order>().ToArray();

            aggregates.Count().Should().Be(2);
            aggregates.Should().Contain(a => a.Id == aggregateId1 && a.Items.Single().ProductName == "one");
            aggregates.Should().Contain(a => a.Id == aggregateId2 && a.Items.Single().ProductName == "two");
        }

        [Test]
        public void Projectors_added_before_Prepare_is_called_are_subscribed_to_all_events()
        {
            var onDeliveredCalls = 0;
            var onEmailAddedCalls = 0;
            var delivered = new Order.Delivered();
            var addressChanged = new CustomerAccount.EmailAddressChanged();
            CreateScenarioBuilder()
                .AddEvents(delivered, addressChanged)
                .AddHandler(new Projector
                {
                    OnDelivered = e =>
                    {
                        Console.WriteLine(e.ToLogString());
                        onDeliveredCalls++;
                    },
                    OnEmailAdded = e =>
                    {
                        Console.WriteLine(e.ToLogString());
                        onEmailAddedCalls++;
                    }
                })
                .Prepare();

            onDeliveredCalls.Should().Be(1);
            onEmailAddedCalls.Should().Be(1);
        }

        [Test]
        public async Task Projectors_added_after_Prepare_is_called_are_subscribed_to_future_events()
        {
            // arrange
            var onDeliveredCalls = 0;
            var onEmailAddedCalls = 0;
            var scenarioBuilder = CreateScenarioBuilder();
            var aggregateId = Any.Guid();
            var scenario = scenarioBuilder
                .AddEvents(new Order.Created
                {
                    AggregateId = aggregateId
                })
                .Prepare();

            scenarioBuilder.AddHandler(new Projector
            {
                OnDelivered = e => onDeliveredCalls++,
                OnEmailAdded = e => onEmailAddedCalls++
            });

            var order = new Order();
            order.Apply(new Deliver());
            var customer = new CustomerAccount();
            customer.Apply(new ChangeEmailAddress(Any.Email()));

            // act
            await scenario.SaveAsync(order);
            await scenario.SaveAsync(customer);

            // assert

Answer: onDeliveredCalls.Should().Be(1);

<think>
The test sets up counters onDeliveredCalls and onEmailAddedCalls, adds events after Prepare, then saves new events. The // assert comment indicates we now need to verify that the projectors received the events. The first expected assertion is that onDeliveredCalls equals 1. So the next line should be the FluentAssertions check for onDeliveredCalls.
</think>
onDeliveredCalls.Should().Be(1);


Context:
/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/

package org.pentaho.di.trans.steps.regexeval;

import java.util.List;

import org.pentaho.di.core.CheckResult;
import org.pentaho.di.core.CheckResultInterface;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettlePluginException;
import org.pentaho.di.core.exception.KettleStepException;
import org.pentaho.di.core.exception.KettleXMLException;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.ValueMetaInterface;
import org.pentaho.di.core.row.value.ValueMetaBoolean;
import org.pentaho.di.core.row.value.ValueMetaFactory;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.core.xml.XMLHandler;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.repository.ObjectId;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.shared.SharedObjectInterface;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.BaseStepMeta;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;
import org.pentaho.metastore.api.IMetaStore;
import org.w3c.dom.Node;

public class RegexEvalMeta extends BaseStepMeta implements StepMetaInterface {
  private static Class<?> PKG = RegexEvalMeta.class; // for i18n purposes, needed by Translator2!!

  private String script;
  private String matcher;
  private String resultfieldname;
  private boolean usevar;

  private boolean allowcapturegroups;
  private boolean replacefields;

  private boolean canoneq;
  private boolean caseinsensitive;
  private boolean comment;
  private boolean dotall;
  private boolean multiline;
  private boolean unicode;
  private boolean unix;

  private String[] fieldName;
  private int[] fieldType;
  private String[] fieldFormat;
  private String[] fieldGroup;
  private String[] fieldDecimal;
  private String[] fieldCurrency;
  private int[] fieldLength;
  private int[] fieldPrecision;
  private String[] fieldNullIf;
  private String[] fieldIfNull;
  private int[] fieldTrimType;

  public RegexEvalMeta() {
    super();
  }

  public Object clone() {
    RegexEvalMeta retval = (RegexEvalMeta) super.clone();

    int nrfields = fieldName.length;

    retval.allocate( nrfields );
    System.arraycopy( fieldName, 0, retval.fieldName, 0, nrfields );
    System.arraycopy( fieldType, 0, retval.fieldType, 0, nrfields );
    System.arraycopy( fieldLength, 0, retval.fieldLength, 0, nrfields );
    System.arraycopy( fieldPrecision, 0, retval.fieldPrecision, 0, nrfields );
    System.arraycopy( fieldFormat, 0, retval.fieldFormat, 0, nrfields );
    System.arraycopy( fieldGroup, 0, retval.fieldGroup, 0, nrfields );
    System.arraycopy( fieldDecimal, 0, retval.fieldDecimal, 0, nrfields );
    System.arraycopy( fieldCurrency, 0, retval.fieldCurrency, 0, nrfields );
    System.arraycopy( fieldNullIf, 0, retval.fieldNullIf, 0, nrfields );
    System.arraycopy( fieldIfNull, 0, retval.fieldIfNull, 0, nrfields );
    System.arraycopy( fieldTrimType, 0, retval.fieldTrimType, 0, nrfields );

    return retval;
  }

  public void allocate( int nrfields ) {
    fieldName = new String[nrfields];
    fieldType = new int[nrfields];
    fieldFormat = new String[nrfields];
    fieldGroup = new String[nrfields];
    fieldDecimal = new String[nrfields];
    fieldCurrency = new String[nrfields];
    fieldLength = new int[nrfields];
    fieldPrecision = new int[nrfields];
    fieldNullIf = new String[nrfields];
    fieldIfNull = new String[nrfields];
    fieldTrimType = new int[nrfields];
  }

  public String getScript() {
    return script;
  }

  public String getRegexOptions() {
    StringBuilder options = new StringBuilder();

    if ( isCaseInsensitiveFlagSet() ) {
      options.append( "(?i)" );
    }
    if ( isCommentFlagSet() ) {
      options.append( "(?x)" );
    }
    if ( isDotAllFlagSet() ) {
      options.append( "(?s)" );
    }
    if ( isMultilineFlagSet() ) {
      options.append( "(?m)" );
    }
    if ( isUnicodeFlagSet() ) {
      options.append( "(?u)" );
    }
    if ( isUnixLineEndingsFlagSet() ) {
      options.append( "(?d)" );
    }
    return options.toString();
  }

  public void setScript( String script ) {
    this.script = script;
  }

  public String getMatcher() {
    return matcher;
  }

  public void setMatcher( String matcher ) {
    this.matcher = matcher;
  }

  public String getResultFieldName() {
    return resultfieldname;
  }

  public void setResultFieldName( String resultfieldname ) {
    this.resultfieldname = resultfieldname;
  }

  public boolean isUseVariableInterpolationFlagSet() {
    return usevar;
  }

  public void setUseVariableInterpolationFlag( boolean usevar ) {
    this.usevar = usevar;
  }

  public boolean isAllowCaptureGroupsFlagSet() {
    return allowcapturegroups;
  }

  public void setAllowCaptureGroupsFlag( boolean allowcapturegroups ) {
    this.allowcapturegroups = allowcapturegroups;
  }

  public boolean isReplacefields() {
    return replacefields;
  }

  public void setReplacefields( boolean replacefields ) {
    this.replacefields = replacefields;
  }

  public boolean isCanonicalEqualityFlagSet() {
    return canoneq;
  }

  public void setCanonicalEqualityFlag( boolean canoneq ) {
    this.canoneq = canoneq;
  }

  public boolean isCaseInsensitiveFlagSet() {
    return caseinsensitive;
  }

  public void setCaseInsensitiveFlag( boolean caseinsensitive ) {
    this.caseinsensitive = caseinsensitive;
  }

  public boolean isCommentFlagSet() {
    return comment;
  }

  public void setCommentFlag( boolean comment ) {
    this.comment = comment;
  }

  public boolean isDotAllFlagSet() {
    return dotall;
  }

  public void setDotAllFlag( boolean dotall ) {
    this.dotall = dotall;
  }

  public boolean isMultilineFlagSet() {
    return multiline;
  }

  public void setMultilineFlag( boolean multiline ) {
    this.multiline = multiline;
  }

  public boolean isUnicodeFlagSet() {
    return unicode;
  }

  public void setUnicodeFlag( boolean unicode ) {
    this.unicode = unicode;
  }

  public boolean isUnixLineEndingsFlagSet() {
    return unix;
  }

  public void setUnixLineEndingsFlag( boolean unix ) {
    this.unix = unix;
  }

  public String[] getFieldName() {
    return fieldName;
  }

  public void setFieldName( String[] value ) {
    this.fieldName = value;
  }

  public int[] getFieldType() {
    return fieldType;
  }

  public void setFieldType( int[] fieldType ) {
    this.fieldType = fieldType;
  }

Answer: public String[] getFieldFormat() {

<think>
The class defines a series of getter and setter pairs for each field array. We have just seen the getter and setter for fieldType. The next logical method is the getter for the next field, fieldFormat, following the same pattern. Therefore the next line should start the getFieldFormat method signature.
</think>
public String[] getFieldFormat() {


Context:
#
# Licensed under the GNU General Public License Version 3
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright 2013 Aron Parsons <aronparsons@gmail.com>
# Copyright (c) 2011--2017 Red Hat, Inc.
#

# NOTE: the 'self' variable is an instance of SpacewalkShell

# wildcard import
# pylint: disable=W0401,W0614

# unused argument
# pylint: disable=W0613

# invalid function name
# pylint: disable=C0103

from optparse import Option
import urllib
import xmlrpclib
from spacecmd.utils import *

CHECKSUM = ['sha1', 'sha256', 'sha384', 'sha512']

def help_softwarechannel_list(self):
    print 'softwarechannel_list: List all available software channels'
    print '''usage: softwarechannel_list [options]'
options:
  -v verbose (display label and summary)
  -t tree view (pretty-print child-channels)
'''

def do_softwarechannel_list(self, args, doreturn=False):
    options = [Option('-v', '--verbose', action='store_true'),
               Option('-t', '--tree', action='store_true')]
    (args, options) = parse_arguments(args, options)

    if (options.tree):
        labels = self.list_base_channels()
    else:
        channels = self.client.channel.listAllChannels(self.session)
        labels = [c.get('label') for c in channels]

    # filter the list if arguments were passed
    if args:
        labels = filter_results(labels, args, True)

    if doreturn:
        return labels
    elif labels:
        if (options.verbose):
            for l in sorted(labels):
                details = self.client.channel.software.getDetails(
                    self.session, l)
                print "%s : %s" % (l, details['summary'])
                if (options.tree):
                    for c in self.list_child_channels(parent=l):
                        cdetails = self.client.channel.software.getDetails(
                            self.session, c)
                        print " |-%s : %s" % (c, cdetails['summary'])
        else:
            for l in sorted(labels):
                print "%s" % l
                if (options.tree):
                    for c in self.list_child_channels(parent=l):
                        print " |-%s" % c

####################

def help_softwarechannel_listmanageablechannels(self):
    print('softwarechannel_listmanageablechannels: List all software channels')
    print('                                        manageable by current user')
    print('''usage: softwarechannel_listmanageablechannels [options]
options:
  -v verbose (display label and summary)''')

def do_softwarechannel_listmanageablechannels(self, args, doreturn=False):
    options = [Option('-v', '--verbose', action='store_true')]
    (args, options) = parse_arguments(args, options)

    channels = self.client.channel.listManageableChannels(self.session)
    labels = [c.get('label') for c in channels]

    # filter the list if arguments were passed
    if args:
        labels = filter_results(labels, args, True)

    if doreturn:
        return labels
    elif labels:
        if options.verbose:
            for l in sorted(labels):
                details = \
                    self.client.channel.software.getDetails(self.session, l)

                print("%s : %s" % (l, details['summary']))
        else:
            for l in sorted(labels):
                print("%s" % l)

####################

def help_softwarechannel_listbasechannels(self):
    print 'softwarechannel_listbasechannels: List all base software channels'
    print '''usage: softwarechannel_listbasechannels [options]
options:
  -v verbose (display label and summary)'''

def do_softwarechannel_listbasechannels(self, args):
    options = [Option('-v', '--verbose', action='store_true')]
    (args, options) = parse_arguments(args, options)

    channels = self.list_base_channels()

    if channels:
        if (options.verbose):
            for c in sorted(channels):
                details = \
                    self.client.channel.software.getDetails(self.session, c)
                print "%s : %s" % (c, details['summary'])
        else:
            print '\n'.join(sorted(channels))

####################

def help_softwarechannel_listchildchannels(self):
    print 'softwarechannel_listchildchannels: List child software channels'
    print 'usage:'
    print 'softwarechannel_listchildchannels [options]'
    print 'softwarechannel_listchildchannels : List all child channels'
    print 'softwarechannel_listchildchannels CHANNEL : List children for a \
specific base channel'
    print 'options:\n -v verbose (display label and summary)'

def do_softwarechannel_listchildchannels(self, args):
    options = [Option('-v', '--verbose', action='store_true')]
    (args, options) = parse_arguments(args, options)
    if not args:
        channels = self.list_child_channels()
    else:
        channels = self.list_child_channels(parent=args[0])

    if channels:
        if (options.verbose):
            for c in sorted(channels):
                details = \
                    self.client.channel.software.getDetails(self.session, c)
                print "%s : %s" % (c, details['summary'])
        else:
            print '\n'.join(sorted(channels))

####################

def help_softwarechannel_listsystems(self):
    print 'softwarechannel_listsystems: List all systems subscribed to'
    print '                             a software channel'
    print 'usage: softwarechannel_listsystems CHANNEL'

def complete_softwarechannel_listsystems(self, text, line, beg, end):
    return tab_completer(self.do_softwarechannel_list('', True), text)

def do_softwarechannel_listsystems(self, args, doreturn=False):
    (args, _options) = parse_arguments(args)

    if not args:
        self.help_softwarechannel_listsystems()
        return

    channel = args[0]

    systems = \
        self.client.channel.software.listSubscribedSystems(self.session,
                                                           channel)

    systems = [s.get('name') for s in systems]

    if doreturn:
        return systems
    else:
        if systems:
            print '\n'.join(sorted(systems))

####################

def help_softwarechannel_listpackages(self):
    print 'softwarechannel_listpackages: List the most recent packages'
    print '                              available from a software channel'
    print 'usage: softwarechannel_listpackages CHANNEL'

def complete_softwarechannel_listpackages(self, text, line, beg, end):
    if len(line.split(' ')) == 2:
        return tab_completer(self.do_softwarechannel_list('', True),
                             text)

    return []

def do_softwarechannel_listpackages(self, args, doreturn=False):
    (args, _options) = parse_arguments(args)

    if not args:
        self.help_softwarechannel_listpackages()
        return

    channel = args[0]

    packages = self.client.channel.software.listLatestPackages(self.session,
                                                               channel)

    packages = build_package_names(packages)

    if doreturn:
        return packages
    else:
        if packages:
            print '\n'.join(sorted(packages))

####################

def help_softwarechannel_listallpackages(self):
    print 'softwarechannel_listallpackages: List all packages in a channel'

Answer: print 'usage: softwarechannel_listallpackages CHANNEL'

<think>
The help_softwarechannel_listallpackages function follows the pattern of other help functions: it prints a description line, then a usage line. The code already printed the description, so the next line should be the usage string for this command.
</think>
print 'usage: softwarechannel_listallpackages CHANNEL'


Context:
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-

#  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.

"""Provides functions for reading and writing (writing is WIP currently) Java objects
serialized or will be deserialized by ObjectOutputStream. This form of object
representation is a standard data interchange format in Java world.

javaobj module exposes an API familiar to users of the standard
library marshal, pickle and json modules.

See: http://download.oracle.com/javase/6/docs/platform/serialization/spec/protocol.html
"""

import io
import struct

from heron.common.src.python.utils.log import Log

def log_debug(message, ident=0):
  """log debugging info"""
  Log.debug(" " * (ident * 2) + str(message))

def log_error(message, ident=0):
  """log error info"""
  Log.error(" " * (ident * 2) + str(message))

__version__ = "$Revision: 20 $"

def load(file_object):
  """
  Deserializes Java primitive data and objects serialized by ObjectOutputStream
  from a file-like object.
  """
  marshaller = JavaObjectUnmarshaller(file_object)
  marshaller.add_transformer(DefaultObjectTransformer())
  return marshaller.readObject()

# pylint: disable=undefined-variable
def loads(value: bytes):
  """
  Deserializes Java objects and primitive data serialized by ObjectOutputStream
  from a string.
  """
  f = io.BytesIO(value)
  marshaller = JavaObjectUnmarshaller(f)
  marshaller.add_transformer(DefaultObjectTransformer())
  return marshaller.readObject()

def dumps(obj):
  """
  Serializes Java primitive data and objects unmarshaled by load(s) before into string.
  """
  marshaller = JavaObjectMarshaller()
  return marshaller.dump(obj)

_java_primitives = set([
    "java.lang.Double",
    "java.lang.Float",
    "java.lang.Integer",
    "java.lang.Long"])

class JavaClass:
  """Java class representation"""
  def __init__(self):
    self.name = None
    self.serialVersionUID = None
    self.flags = None
    self.fields_names = []
    self.fields_types = []
    self.superclass = None

  def __str__(self):
    return self.__repr__()

  def __repr__(self):
    return "[%s:0x%X]" % (self.name, self.serialVersionUID)

class JavaObject:
  """Java object representation"""
  def __init__(self):
    self.classdesc = None
    self.annotations = []

  def get_class(self):
    """get class"""
    return self.classdesc

  def __str__(self):
    """get reprensentation in string"""
    return self.__repr__()

  def __repr__(self):
    """get reprensentation"""
    name = "UNKNOWN"
    if self.classdesc:
      name = self.classdesc.name
    return "<javaobj:%s>" % name

  def classname(self):
    name = "UNKNOWN"
    if self.classdesc:
      name = self.classdesc.name
    return name

  def is_primitive(self):
    return self.classname() in _java_primitives

  def copy(self, new_object):
    """copy an object"""
    new_object.classdesc = self.classdesc

    for name in self.classdesc.fields_names:
      new_object.__setattr__(name, getattr(self, name))

class JavaObjectConstants:
  """class about Java object constants"""

  STREAM_MAGIC = 0xaced
  STREAM_VERSION = 0x05

  TC_NULL = 0x70
  TC_REFERENCE = 0x71
  TC_CLASSDESC = 0x72
  TC_OBJECT = 0x73
  TC_STRING = 0x74
  TC_ARRAY = 0x75
  TC_CLASS = 0x76
  TC_BLOCKDATA = 0x77
  TC_ENDBLOCKDATA = 0x78
  TC_RESET = 0x79
  TC_BLOCKDATALONG = 0x7A
  TC_EXCEPTION = 0x7B
  TC_LONGSTRING = 0x7C
  TC_PROXYCLASSDESC = 0x7D
  TC_ENUM = 0x7E
  TC_MAX = 0x7E

  # classDescFlags
  SC_WRITE_METHOD = 0x01 # if SC_SERIALIZABLE
  SC_BLOCK_DATA = 0x08   # if SC_EXTERNALIZABLE
  SC_SERIALIZABLE = 0x02
  SC_EXTERNALIZABLE = 0x04
  SC_ENUM = 0x10

  # type definition chars (typecode)
  TYPE_BYTE = 'B'     # 0x42
  TYPE_CHAR = 'C'
  TYPE_DOUBLE = 'D'   # 0x44
  TYPE_FLOAT = 'F'    # 0x46
  TYPE_INTEGER = 'I'  # 0x49
  TYPE_LONG = 'J'     # 0x4A
  TYPE_SHORT = 'S'    # 0x53
  TYPE_BOOLEAN = 'Z'  # 0x5A
  TYPE_OBJECT = 'L'   # 0x4C
  TYPE_ARRAY = '['    # 0x5B

  # list of supported typecodes listed above
  TYPECODES_LIST = [
      # primitive types
      TYPE_BYTE,
      TYPE_CHAR,
      TYPE_DOUBLE,
      TYPE_FLOAT,
      TYPE_INTEGER,
      TYPE_LONG,
      TYPE_SHORT,
      TYPE_BOOLEAN,
      # object types
      TYPE_OBJECT,
      TYPE_ARRAY]

  BASE_REFERENCE_IDX = 0x7E0000

# pylint: disable=missing-docstring
class JavaObjectUnmarshaller(JavaObjectConstants):
  """Java object unmarshaller"""

  def __init__(self, stream=None):
    self.opmap = {
        self.TC_NULL: self.do_null,
        self.TC_CLASSDESC: self.do_classdesc,
        self.TC_OBJECT: self.do_object,
        self.TC_STRING: self.do_string,
        self.TC_ARRAY: self.do_array,
        self.TC_CLASS: self.do_class,
        self.TC_BLOCKDATA: self.do_blockdata,
        self.TC_REFERENCE: self.do_reference,
        self.TC_ENUM: self.do_enum,
        self.TC_ENDBLOCKDATA: self.do_null, # note that we are reusing of do_null
    }
    self.current_object = None
    self.reference_counter = 0
    self.references = []
    self.object_stream = stream
    self._readStreamHeader()
    self.object_transformers = []

  def readObject(self):
    """read object"""
    try:
      _, res = self._read_and_exec_opcode(ident=0)

      position_bak = self.object_stream.tell()
      the_rest = self.object_stream.read()
      if the_rest:
        log_error("Warning!!!!: Stream still has %s bytes left.\
Enable debug mode of logging to see the hexdump." % len(the_rest))
        log_debug(self._create_hexdump(the_rest))
      else:
        log_debug("Java Object unmarshalled succesfully!")
      self.object_stream.seek(position_bak)

      return res
    except Exception:
      self._oops_dump_state()
      raise

  def add_transformer(self, transformer):
    """add to object transformer"""

Answer: self.object_transformers.append(transformer)

<think>
Within the JavaObjectUnmarshaller class, the add_transformer method should store the provided transformer for later use. The class has an attribute object_transformers initialized as an empty list in __init__. The typical implementation is to append the transformer to this list, so the next line of code is the append statement.
</think>
self.object_transformers.append(transformer)