Error while sending multivalued customdata - amazon-dynamodb

I am facing the following error while sending set of custom objects.
Oct 21, 2015 7:28:38 PM
com.amazonaws.services.dynamodbv2.datamodeling.marshallers.ObjectSetToStringSetMarshaller
marshall WARNING: Marshaling a set of non-String objects to a DynamoDB
StringSet. You won't be able to read these objects back out of
DynamoDB unless you REALLY know what you're doing: it's probably a
bug. If you DO know what you're doing feelfree to ignore this warning,
but consider using a custom marshaler for this instead.
com.amazonaws.AmazonServiceException: One or more parameter values
were invalid: An string set may not be empty (Service:
AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException;
Request ID: S61P89234SI8PE61M8I9QTG8RNVV4KQNSO5AEMVJF66Q9ASUAAJG) at
com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1181)
at
com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:766)
at
com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:485)
at
com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:306)
at
com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.invoke(AmazonDynamoDBClient.java:1799)
at
com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.updateItem(AmazonDynamoDBClient.java:1614)
at
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$SaveObjectHandler.doUpdateItem(DynamoDBMapper.java:1241)
at
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$2.executeLowLevelRequest(DynamoDBMapper.java:937)
at
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$SaveObjectHandler.execute(DynamoDBMapper.java:1120)
at
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.save(DynamoDBMapper.java:966)
at
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.save(DynamoDBMapper.java:758)
at .dao.impl.DeviceDaoImpl.addDevice(DeviceDaoImpl.java:57) at
.admin.device.service.impl.DeviceServiceImpl.addDevice(DeviceServiceImpl.java:38)
This is the code snippet from where this is happening
#DynamoDBTable(tableName="Device")
public class Device extends BaseEntity implements Serializable{
private Set<AsscoiatedReviewer> asscoiatedReviewers ;
// getters setter
public Device addDevice(Device device) {
device.setDeviceId(generateId());
device.setCreatedTime(getCurrentTime());
if (!StringUtils.isNullOrEmpty(device.getPincode())) {
// get lat and long - do this for review team as well
//TODO : move it to common place that can be accessed for review team too
setLatLong(device);
// calculate the distances between this organization and reviewers
calculateAsscoiatedReviewersDistances(device);
}
mapper.save(device);
Device device1 = mapper.load(Device.class, device.getDeviceId());
return device1;
}
private void calculateAsscoiatedReviewersDistances(Device device) {
if(StringUtils.isNullOrEmpty(device.getPincode())) return;
try {
List<ReviewTeam> ReviewTeam = reviewTeamDao.getAllReviewTeams();
Set<AsscoiatedReviewer> asscoiatedReviewers = new HashSet<AsscoiatedReviewer>();
/*for (ReviewTeam reviewTeam2 : ReviewTeam) {
if(StringUtils.isNullOrEmpty(reviewTeam2.getPincode())) continue;
AsscoiatedReviewer asscoiatedReviewer = new AsscoiatedReviewer();
asscoiatedReviewer.setReviewTeamId(reviewTeam2.getReviewTeamId());
double distance = distance(new Double(device.getLat()), new Double(device.getLongt()),
new Double(reviewTeam2.getLat()), new Double(reviewTeam2.getLongt()));
asscoiatedReviewer.setDistance(new Double(distance).toString());
asscoiatedReviewers.add(asscoiatedReviewer);
}*/
device.setAsscoiatedReviewers(asscoiatedReviewers);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public class AsscoiatedReviewer implements Serializable,Comparable {
/**
*
*/
private static final long serialVersionUID = -1906388056843006046L;
private String distance;
private String reviewTeamId;
// getters setters
}
it seems the error is happening from the following line
device.setAsscoiatedReviewers(asscoiatedReviewers);
Should this be marshalled / demarshalled and send to amazon ? Any help would be greatly appreciated .
UPDATE :
i am getting the following exception when the data is populated in asscoiatedReviewers
WARNING: Marshaling a set of non-String objects to a DynamoDB
StringSet. You won't be able to read these objects back out of
DynamoDB unless you REALLY know what you're doing: it's probably a
bug. If you DO know what you're doing feelfree to ignore this warning,
but consider using a custom marshaler for this instead.
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException:
Cannot unmarshall to type class
in.forus.foruscare.entity.AsscoiatedReviewer without a custom
marshaler or #DynamoDBDocument annotation. at
com.amazonaws.services.dynamodbv2.datamodeling.ConversionSchemas$StandardItemConverter.getObjectUnmarshaller(ConversionSchemas.java:590)
at
com.amazonaws.services.dynamodbv2.datamodeling.ConversionSchemas$StandardItemConverter.augment(ConversionSchemas.java:497)
at
com.amazonaws.services.dynamodbv2.datamodeling.ConversionSchemas$StandardItemConverter.getMemberUnmarshaller(ConversionSchemas.java:466)
at
com.amazonaws.services.dynamodbv2.datamodeling.ConversionSchemas$StandardItemConverter.getObjectSetUnmarshaller(ConversionSchemas.java:520)
does this mean i needed to write custom marshaller or annoate with DynamoDBDocument annotation . If yes, this is set of custom objects, can you send me the pointer to simple example of marshaller. i happened to look at other marshllers, they didnt seem to explain what i need

Related

Multi-entity Aggregates command handling

I have an aggregate root like this:
Aggregate root:
#NoArgsConstructor
#Aggregate(repository = "positionAggregateRepository")
#AggregateRoot
#XSlf4j
#Data
public class HopAggregate {
#AggregateIdentifier
private String hopId;
private FilteredPosition position;
private LocalDate positionDate;
#AggregateMember
private Security security;
#CommandHandler
public HopAggregate(NewHopCommand cmd) {
log.info("creating new position , {}", cmd.getDateId());
apply(new HopEvent(cmd.getHopId(), cmd.getDateId(), cmd.getFilteredPosition(), cmd.getSecurity(), false));
}
#CommandHandler
public void handle(UpdateHopCommand cmd) {
log.info("creating hop update event {}", cmd);
apply(new HopEvent(this.hopId, this.positionDate, cmd.getFilteredPosition(), this.security, true));
}
#CommandHandler
public void handle(SecurityUpdate cmd) {
log.info("updating security {}", cmd);
apply(new SecurityUpdateEvent(this.hopId, cmd.getFilteredSecurity()));
}
#EventSourcingHandler
public void on(HopEvent evt) {
if (evt.getIsUpdate()) {
log.info("updating position {}", evt);
this.position = evt.getFilteredPosition();
} else {
log.info("adding new position to date {}", evt);
this.hopId = evt.getHopId();
this.positionDate = evt.getDate();
this.position = evt.getFilteredPosition();
this.security= evt.getSecurity();
}
}
#EventSourcingHandler
public void on(SecurityUpdateEvent evt) {
log.info("hop id {}, security update {}", this.hopId, evt.getFilteredSecurity().getSecurityId());
}
}
Child entity:
#XSlf4j
#Data
#RequiredArgsConstructor
#NoArgsConstructor
public class IpaSecurity implements Serializable {
#EntityId
#NonNull
private String id;
#NonNull
private FilteredSecurity security;
}
My issue is that when i am pushing and update like this:
#EventHandler
public void handleSecurityEvent(SecurityUpdate securityUpdate) {
log.info("got security event {}", securityUpdate);
commandGateway.send(securityUpdate);
}
and my command being:
#Data
#RequiredArgsConstructor
#NoArgsConstructor
#ToString
public class SecurityUpdate {
#NonNull
#TargetAggregateIdentifier
private String id;
#NonNull
private FilteredSecurity filteredSecurity;
}
I am getting aggregate root not found exception:
Command 'com.hb.apps.ipa.events.SecurityUpdate' resulted in org.axonframework.modelling.command.AggregateNotFoundException(The aggregate was not found in the event store)
I am not sure how to handle this scenario. My requirement is that each aggregate should check whether it contains the security and then update it if the command was issued. What am i missing? let me know if you need any more info on the code.
Thanks for your help.
A Command is always targeted towards a single entity.
This entity can be an Aggregate, an entity contained in an Aggregate (what Axon Framework calls an Aggregate Member) or a simple singleton component.
Important to note though, is that there will only be one entity handling the command.
This is what requires you to set the #TargetAggregateIdentifier in your Command for Axon to be able to route it to a single Aggregate instance if the Command Handler in question is part of it.
The AggregateNotFoundException you're getting signals that the #TargetAggregateIdentifier annotated field in your SecurityUpdate command does no correspond to any existing Aggregate.
I'd thus suspect that the id field in the SecurityUpdate does not correspond to any #AggregateIdentifier annotated field in your HopAggregate aggregates.
A part from the above, I have a couple of other suggestions when looking at your snippets which I'd like to share with you:
#Aggregate is meta-annotated with #AggregateRoot. You're thus not required to specify both on an Aggregate class
For logging messages being handled, you can utilize LoggingInterceptor. You can configure this on any component capable of handling messages, thus providing a universal way of logging. This will omit the necessity to add log lines in your message handling functions
You're publishing a HopEvent on both the create and update commands. Doing so makes your HopEvent very generic. Ideally, your events clarify business operations occurring in your system. My rule of thumb typically is such: "If I tell my business manager/customer about the event class, he/she should know exactly what it does". I'd thus suggest to rename the event to something more specific
Just as with the HopEvent, the UpdateHopCommand is quite generic. Your commands should express the intent to perform an operation in your application. Users will typically not desire an update, they desire an address change for example. Your commands classes ideally reflect this
The suggested naming convention for commands is to start with verb in the present tense. Thus, it should no be SecurityUpdate, but UpdateSecurity. A command is a request expressing intent, the messages ideally reflect this
Hope this helps you out #juggernaut!

Xamarin forms - Realm accessed from incorrect thread

Maybe I'm missing something really simple out here but gonna ask anyways.....
I am using Xamarin forms (.NET Standard project), MVVMLight, Realm DB and ZXing Barcode Scanner.
I have a realmobject like so...
public class Participant : RealmObject
{
public string FirstName {get; set;}
public string LastName {get; set;}
public string Email {get; set;}
public string RegistrationCode {get; set;}
//More properties skipped out for brevity
}
I have the corresponding viewmodel as follows:
public class ParticipantViewModel
{
Realm RealmInstance
public ParticipantViewModel()
{
RealmInstance = Realms.Realm.GetInstance();
RefreshParticipants();
}
private async Task RefreshParticipants()
{
//I have code here that GETS the list of Participants from an API and saves to the device.
//I am using the above-defined RealmInstance to save to IQueryable<Participant> Participants
}
}
All the above works fine and I have no issues with this. In the same viewmodel, I am also able to fire up the ZXing Scanner and scan a bar code representing a RegistrationCode.
This, in turn, populates the below property (also in the viewmodel) once scanned...
private ZXing.Result result;
public ZXing.Result Result
{
get { return result; }
set { Set(() => Result, ref result, value); }
}
and calls the below method (wired up via the ScanResultCommand) to fetch the participant bearing the scanned RegistrationCode.
private async Task ScanResults()
{
if (Result != null && !String.IsNullOrWhiteSpace(Result.Text))
{
string regCode = Result.Text;
await CloseScanner();
SelectedParticipant = Participants.FirstOrDefault(p => p.RegistrationCode.Equals(regCode, StringComparison.OrdinalIgnoreCase));
if (SelectedParticipant != null)
{
//Show details for the scanned Participant with regCode
}
else
{
//Display not found message
}
}
}
I keep getting the below error....
System.Exception: Realm accessed from incorrect thread.
generated by the line below....
SelectedParticipant = Participants.FirstOrDefault(p => p.RegistrationCode.Equals(regCode, StringComparison.OrdinalIgnoreCase));
I'm not sure how this is an incorrect thread but any ideas on how I can get around to fetching the scanned participant either from the already populated IQueryable or from the Realm representation directly would be greatly appreciated.
Thanks
Yes, you're getting a realm instance in the constructor, and then using it from an async task (or thread). You can only access a realm from the thread in which you obtained the reference. Since you're only using a default instance, you should be able to simply obtain a local reference within the function (or thread) where you use it. Try using
Realm LocalInstance = Realms.Realm.GetInstance();
at the top of the function and use that. You'll need to recreate the Participants query to use the same instance as its source too. This will be the case wherever you use async tasks (threads), so either change all to get hold of the default instance on entry or reduce the number of threads that access the realm.
Incidentally I'm surprised you don't get a similar access error from within
RefreshParticipants() - maybe you're not actually accessing data via RealmInstance from there.

Pass object between two Around functions - AOP

I am doing Auditing for my Controller, Service and Dao layer. I have three Around aspect functions for Controller, Service and Dao respectively. I use a custom annotation which if present on the Controller method will invoke an Around aspect function. Inside the annotation I set a property which I wish to pass from the Controller Around function to the Service around function inside the Aspect class.
public #interface Audit{
String getType();
}
I will set the value of this getType from an interface.
#Around("execution(* com.abc.controller..*.*(..)) && #annotation(audit)")
public Object controllerAround(ProceedingJoinPoint pjp, Audit audit){
//read value from getType property of Audit annotation and pass it to service around function
}
#Around("execution(* com.abc.service..*.*(..))")
public Object serviceAround(ProceedingJoinPoint pjp){
// receive the getType property from Audit annotation and execute business logic
}
How can I pass an object between two Around functions?
Aspects are, by default, singleton objects. However, there are different instantiation models, which could be useful in use cases like yours. Using a percflow(pointcut) instantiation model, you could store the value of the annotation in your controller around advice and retrieve it in your service around advice. The following is just an example on how it would look like:
#Aspect("percflow(controllerPointcut())")
public class Aspect39653654 {
private Audit currentAuditValue;
#Pointcut("execution(* com.abc.controller..*.*(..))")
private void controllerPointcut() {}
#Around("controllerPointcut() && #annotation(audit)")
public Object controllerAround(ProceedingJoinPoint pjp, Audit audit) throws Throwable {
Audit previousAuditValue = this.currentAuditValue;
this.currentAuditValue = audit;
try {
return pjp.proceed();
} finally {
this.currentAuditValue = previousAuditValue;
}
}
#Around("execution(* com.abc.service..*.*(..))")
public Object serviceAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("current audit value=" + currentAuditValue);
return pjp.proceed();
}
}

Cannot Update Entity Using EF 6 - ObjectStateManager Error

I'm trying to update an entity using Entity Framework version 6.
I'm selecting the entity from the database like so...
public T Find<T>(object id) where T : class
{
return this._dbContext.Set<T>().Find(id);
}
And updating the entity like so..
public T Update<T>(T entity) where T : class
{
// get the primary key of the entity
object id = this.GetPrimaryKeyValue(entity);
// get the original entry
T original = this._dbContext.Set<T>().Find(id);
if (original != null)
{
// do some automatic stuff here (taken out for example)
// overwrite original property values with new values
this._dbContext.Entry(original).CurrentValues.SetValues(entity);
this._dbContext.Entry(original).State = EntityState.Modified;
// commit changes to database
this.Save();
// return entity with new property values
return entity;
}
return default(T);
}
The GetPrimaryKeyValue function is as so...
private object GetPrimaryKeyValue<T>(T entity) where T : class
{
var objectStateEntry = ((IObjectContextAdapter)this._dbContext).ObjectContext
.ObjectStateManager
.GetObjectStateEntry(entity);
return objectStateEntry.EntityKey.EntityKeyValues[0].Value;
}
Just for clarity. I'm selecting the original entry out as I need to perform some concurrency logic (that Ive taken out). I'm not posting that data with the entity and need to select it manually out of the DB again to perform the checks.
I know the GetPrimaryKeyValue function is not ideal if there's more than one primary key on the entity. I just want it to work for now.
When updating, entity framework coughs up the error below when trying to execute the GetPrimaryKeyValue function.
The ObjectStateManager does not contain an ObjectStateEntry with a reference to an object of type 'NAME_OF_ENTITY_IT_CANNOT_FIND'
I've written many repositories before and I've never had this issue, I cannot seem to find why its not working (hence the post).
Any help would be much appreciated.
Thanks guys!
Steve
It seems like you are having issues getting the PK from the entity being passed in. Instead of trying to go through EF to get this data you could either use their Key attribute or create your own and just use reflection to collect what the key names are. This will also allow you to retrieve multiple keys if it is needed. Below is an example I created inside of LinqPad, you should be able to set it to "Program" mode and paste this in and see it work. Hack the code up and use what you may. I implemented an IEntity but it is not required, and you can change the attribute to anything really.
Here are the results:
Keys found:
CustomIdentifier
LookASecondKey
Here is the code:
// this is just a usage demo
void Main()
{
// create your object from wherever
var car = new Car(){ CustomIdentifier= 1, LookASecondKey="SecretKey", Doors=4, Make="Nissan", Model="Altima" };
// pass the object in
var keys = GetPrimaryKeys<Car>(car);
// you have the list of keys now so work with them however
Console.WriteLine("Keys found: ");
foreach(var k in keys)
Console.WriteLine(k);
}
// you probably want to use this method, add whatever custom logic or checking you want, maybe put
private IEnumerable<string> GetPrimaryKeys<T>(T entity) where T : class, IEntity
{
// place to store keys
var keys = new List<string>();
// loop through each propery on the entity
foreach(var prop in typeof(T).GetProperties())
{
// check for the custom attribute you created, replace "EntityKey" with your own
if(prop.CustomAttributes.Any(p => p.AttributeType.Equals(typeof(EntityKey))))
keys.Add(prop.Name);
}
// check for key and throw if not found (up to you)
if(!keys.Any())
throw new Exception("No EntityKey attribute was found, please make sure the entity includes this attribute on at least on property.");
// return all the keys
return keys;
}
// example of the custom attribute you could use
[AttributeUsage(AttributeTargets.Property)]
public class EntityKey : Attribute
{
}
// this interface is not NEEDED but I like to restrict dal to interface
public interface IEntity { }
// example of your model
public class Car : IEntity
{
[EntityKey] // add the attribure to property
public int CustomIdentifier {get;set;}
[EntityKey] // i am demonstrating multiple keys but you can have just one
public string LookASecondKey {get;set;}
public int Doors {get;set;}
public string Make {get;set;}
public string Model {get;set;}
}

Entity Framework telling me an object is attached when it isn't - why?

I have an object I want to update in the database. I'm new to EF but have done a fair bit of reading. Clearly my approach is wrong, but I don't understand why. FYI the Context referenced throughout is an ObjectContext which is newly instantiated as this code begins and is disposed immediately after. Here is my Update method - the View is the object I want to update in the database and it has 4 ICollection properties whose changes I also wish to save to the database:
public void Update(View view)
{
var original = Read(view.Username, view.ViewId);
original.ViewName = view.ViewName;
ProcessChanges<CostCentre, short>(Context.CostCentres, original.CostCentres, view.CostCentres, "iFinanceEntities.CostCentres", "CostCentreId");
ProcessChanges<LedgerGroup, byte>(Context.LedgerGroups, original.LedgerGroups, view.LedgerGroups, "iFinanceEntities.LedgerGroups", "LedgerGroupId");
ProcessChanges<Division, byte>(Context.Divisions, original.Divisions, view.Divisions, "iFinanceEntities.Divisions", "DivisionId");
ProcessChanges<AnalysisCode, short>(Context.AnalysisCodes, original.AnalysisCodes, view.AnalysisCodes, "iFinanceEntities.AnalysisCodes", "AnalysisCodeId");
int test = Context.SaveChanges();
}
First I get the original from the database because I want to compare its collections with the new set of collections. This should ensure the correct sub-objects are added and removed. I compare each collection in turn using this ProcessChanges method:
private void ProcessChanges<TEntity, TKey>(ObjectSet<TEntity> contextObjects, ICollection<TEntity> originalCollection, ICollection<TEntity> changedCollection, string entitySetName, string pkColumnName)
where TEntity : class, ILookupEntity<TKey>
{
List<TKey> toAdd = changedCollection
.Select(c => c.LookupKey)
.Except(originalCollection.Select(o => o.LookupKey))
.ToList();
List<TKey> toRemove = originalCollection
.Select(o => o.LookupKey)
.Except(changedCollection.Select(c => c.LookupKey))
.ToList();
toAdd.ForEach(a =>
{
var o = changedCollection.Single(c => c.LookupKey.Equals(a));
AttachToOrGet<TEntity, TKey>(entitySetName, pkColumnName, ref o);
originalCollection.Add(o);
});
toRemove.ForEach(r =>
{
var o = originalCollection.Single(c => c.LookupKey.Equals(r));
originalCollection.Remove(o);
});
}
This compares the new collection to the old one and works out which objects to add and which to remove. Note that the collections all contain objects which implement ILookupEntity.
My problems occur on the line where I call AttachToOrGet. This method I got from elsewhere on stackoverflow. I'm using this because I was often getting a message saying that "An object with the same key already exists in the ObjectStateManager" when attaching a new subobject. Hopefully you'll understand my confusion around this when I post the code of this method below:
public void AttachToOrGet<TEntity, TKey>(string entitySetName, string pkColumnName, ref TEntity entity)
where TEntity : class, ILookupEntity<TKey>
{
ObjectStateEntry entry;
// Track whether we need to perform an attach
bool attach = false;
if (Context.ObjectStateManager.TryGetObjectStateEntry(new EntityKey(entitySetName, pkColumnName, entity.LookupKey), out entry))
//if (Context.ObjectStateManager.TryGetObjectStateEntry(Context.CreateEntityKey(entitySetName, entity), out entry))
{
// Re-attach if necessary
attach = entry.State == EntityState.Detached;
// Get the discovered entity to the ref
entity = (TEntity)entry.Entity;
}
else
{
// Attach for the first time
attach = true;
}
if (attach)
Context.AttachTo(entitySetName, entity);
}
Basically this is saying if the entity is not already attached then attach it. But my code is returning false on the Context.ObjectStateManager.TryGetObjectStateEntry line, but throwing an exception on the final line with the message "An object with the same key already exists in the ObjectStateManager". To me this is paradoxical.
As far as I'm concerned I'm trying to achieve something very simple. Something it would take 20 minutes to write a stored procedure for. A simple database update. Frankly I don't care what is attached and what isn't because I don't wish to track changes or create proxies or lazy load or do anything else EF offers me. I just want to take a very simple object and update the database using a minimal number of trips between servers. How is this so complicated? Please someone help me - I've spent a whole day on this!
Update
Here's my ILookupEntity class:
public interface ILookupEntity<TKey>
{
TKey LookupKey { get; }
string DisplayText { get; }
}
Here's how it is implemented in CostCentre:
public partial class CostCentre : IFinancialCode, ILookupEntity<short>
{
#region IFinancialCode Members
public short ID { get { return CostCentreId; } }
public string DisplayText { get { return string.Format("{0} - {1}", Code, Description); } }
#endregion
#region ILookupEntity Members
public short LookupKey
{
get { return ID; }
}
#endregion ILookupEntity Members
}
Well, I've worked through this and found a solution, but I can't say I understand it. The crucial ingredient came when I was performing a check after the comment by #Slauma. I wanted to check I was using the correct entity set name etc so I included the following lines near the top of my AttachToOrGet method:
var key = new EntityKey(entitySetName, pkColumnName, entity.LookupKey);
object temp;
if (!Context.TryGetObjectByKey(key, out temp))
throw new Exception(string.Format("No entity was found in {0} with key {1}", entitySetName, entity.LookupKey));
Bizarrely this alone resolved the problem. For some reason, once I'd called the TryGetObjectByKey then the ObjectStateManager.TryGetObjectStateEntry call actually started locating the attached entity. Miraculous. I'd love it if anyone can explain this.
By the way, I also needed to include the following code, but that's just because in my case the modelled entities are located in a separate assembly from the context itself.
Assembly assembly = typeof(CostCentre).Assembly;
Context.MetadataWorkspace.LoadFromAssembly(assembly);

Resources