How to use Javers Query Language to fetch the values of a mapType property - javers

I have a contact entity which has a map storing phone objects.
When I add a new phone object (phone2) to the map, using JQL, I am able to detect that change though MapChange, but the acutal value of the phone object is not shown.
I can see that if I change an existing phone object (phone1), that value is being shown in the ValueChange.
Similarly, is there any way to see the value of the Phone object (phone2) that was added, directly in the MapChange?
public static void main(String[] args) {
Javers javers = JaversBuilder.javers().build();
Map<String, PhoneInfo> phones = new HashMap<>();
phones.put("phone1", new PhoneInfo().number("9876543210"));
ContactInfo con = new ContactInfo().id(101L).phones(phones);
javers.commit("author1", con);
phones.put("phone1", new PhoneInfo().number("9876543211"));
phones.put("phone2", new PhoneInfo().number("9876543212"));
javers.commit("author2", con);
QueryBuilder queryBuilder = QueryBuilder.byInstanceId(101L, ContactInfo.class).withChildValueObjects();
Changes changes = javers.findChanges(queryBuilder.build());
System.out.println("changes:\n" + javers.getJsonConverter().toJson(changes));
}
public static class ContactInfo {
#Id
private Long id;
private Map<String, PhoneInfo> phones;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public ContactInfo id(Long id) {
this.id = id;
return this;
}
public Map<String, PhoneInfo> getPhones() {
return phones;
}
public void setPhones(Map<String, PhoneInfo> phones) {
this.phones = phones;
}
public ContactInfo phones(Map<String, PhoneInfo> phones) {
setPhones(phones);
return this;
}
}
public static class PhoneInfo {
#Id
private Long id;
private String number;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public PhoneInfo id(Long id) {
this.id = id;
return this;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public PhoneInfo number(String number) {
setNumber(number);
return this;
}
}
Output:
changes:
[
{
"changeType": "ValueChange",
"globalId": {
"valueObject": "committest.domain.Contact$PhoneInfo",
"ownerId": {
"entity": "committest.domain.Contact$ContactInfo",
"cdoId": 101
},
"fragment": "phones/phone1"
},
"commitMetadata": {
"author": "author2",
"properties": [],
"commitDate": "2019-07-16T02:10:32.016",
"commitDateInstant": "2019-07-15T20:40:32.016Z",
"id": 2.00
},
"property": "number",
"propertyChangeType": "PROPERTY_VALUE_CHANGED",
"left": "9876543210",
"right": "9876543211"
},
{
"changeType": "MapChange",
"globalId": {
"entity": "committest.domain.Contact$ContactInfo",
"cdoId": 101
},
"commitMetadata": {
"author": "author2",
"properties": [],
"commitDate": "2019-07-16T02:10:32.016",
"commitDateInstant": "2019-07-15T20:40:32.016Z",
"id": 2.00
},
"property": "phones",
"propertyChangeType": "PROPERTY_VALUE_CHANGED",
"entryChanges": [
{
"entryChangeType": "EntryAdded",
"key": "phone2",
"value": {
"valueObject": "committest.domain.Contact$PhoneInfo",
"ownerId": {
"entity": "committest.domain.Contact$ContactInfo",
"cdoId": 101
},
"fragment": "phones/phone2"
}
}
]
}
]

Related

Spring Boot - Get Data from DB and store it in list and parse it to JSON using jackson

I'm trying to get data from multiple tables and put it in Array List of class, and then convert it to JSON Object.
But when i'm trying to parse it to json using Jackson Object Mapper all the lists are converted as below
Using ObjectMapper().writeValueAsString for deserialization from class objects to json
```{
"College": [
{
"institution": [
{
"instId": "T34",
"Country": "India",
"Code": "T33"
},
{
"instId": "T22",
"Country": "India",
"Code": "T22"
}
],
"Rating": [
{
"star": "4"
"comments": "good"
},
{
"star": "2"
"comments": "ok"
},
}
]
}```
But i want the result as below
{
"College": [
{
"institution": [
{
"instId": "T34",
"Country": "India",
"Code": "T33"
}
],
"Rating": [
{
"star": "4"
"comments": "good"
}
]
},
{
"institution": [
{
"instId": "T22",
"Country": "India",
"Code": "T22"
}
],
"Rating": [
{
"star": "2"
"comments": "ok"
}
]
}
]
}
The above is just an example.
Please help in getting the desired output.
Below are the class files used.
public class AllCollege{
List<College> college = new ArrayList<>();
public List<College> getCollege() {
return college;
}
public void setCollege(List<College> college) {
this.college = college;
}
}
public class College{
private List<Institution> institution = new ArrayList<>();
private List<Rating> rating = new ArrayList<>();
public List<Institution> getInstitution() {
return institution;
}
public void setInstitution(List<Institution> institution) {
this.institution = institution;
}
public List<Rating> getRating() {
return rating;
}
public void setRating(List<Rating> rating) {
this.rating = rating;
}
}
public class Institution {
private String instId;
private String country;
private String code;
public String getInstId() {
return instId;
}
public void setInstId(String instId) {
this.instId = instId;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
public class Rating {
private String star;
private String comments;
public String getStar() {
return star;
}
public void setStar(String star) {
this.star = star;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
}
Below is where the data from tables is set into ArrayList and then converted to json string.
session = sessionFactory.openSession();
String sql = "from institution";
Query<InstDto> query = session.createQuery(sql);
List<Institution> configdtoList =query.list();
College alc = new College();
alc.setInstitution(configdtoList);
.
.
.
similarly Rating table.
List<College> clist = new new ArrayList<>();
clist.add(alc);
AllCollege ac = new AllCollege();
ac.setCollege(clist);
String responseJson = new ObjectMapper().writeValueAsString(ac)
class structure as below it will help you to parse:
public class Sample {
#JsonProperty("College")
private List<College> college;
}
public class College {
private List<Institution> institution;
#JsonProperty("Rating")
private List<Rating> rating;
}
public class Rating {
private String comments;
private String star;
}
public class Institution {
#JsonProperty("Code")
private String code;
#JsonProperty("Country")
private String country;
private String instId;
}
I have created an HashMap contains the List<AllCollege> as value and then used json parser which worked as expected.

hibernate/Spring/Jpa #oneToMany cascade update

I'm trying to add in the decorator cascade = CascadeType.ALL on the field one to many of my version modele in spring in order to update every hyper parameter when i update my version.Like you can see below.
#Entity
#Table(name = "version")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Version implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Column(name = "num", nullable = false)
private Integer num;
#Column(name = "creation_date")
private ZonedDateTime creationDate;
#Column(name = "execution_date")
private ZonedDateTime executionDate;
#Column(name = "weights_uri")
private String weightsURI;
#OneToMany(mappedBy = "version", fetch = FetchType.EAGER, orphanRemoval = true)
#JsonIgnoreProperties({"version", "metricsType"})
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<ResultExecution> resultExecutions = new HashSet<>();
#OneToMany(mappedBy = "version", fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.ALL)
#JsonIgnoreProperties({"version"})
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<HyperParameter> hyperParameters = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getNum() {
return num;
}
public Version num(Integer num) {
this.num = num;
return this;
}
public void setNum(Integer num) {
this.num = num;
}
public ZonedDateTime getCreationDate() {
return creationDate;
}
public Version creationDate(ZonedDateTime creationDate) {
this.creationDate = creationDate;
return this;
}
public void setCreationDate(ZonedDateTime creationDate) {
this.creationDate = creationDate;
}
public ZonedDateTime getExecutionDate() {
return executionDate;
}
public Version executionDate(ZonedDateTime executionDate) {
this.executionDate = executionDate;
return this;
}
public void setExecutionDate(ZonedDateTime executionDate) {
this.executionDate = executionDate;
}
public String getWeightsURI() {
return weightsURI;
}
public Version weightsURI(String weightsURI) {
this.weightsURI = weightsURI;
return this;
}
public void setWeightsURI(String weightsURI) {
this.weightsURI = weightsURI;
}
public Set<ResultExecution> getResultExecutions() {
return resultExecutions;
}
public Version resultExecutions(Set<ResultExecution> resultExecutions) {
this.resultExecutions = resultExecutions;
return this;
}
public Version addResultExecution(ResultExecution resultExecution) {
this.resultExecutions.add(resultExecution);
resultExecution.setVersion(this);
return this;
}
public Version removeResultExecution(ResultExecution resultExecution) {
this.resultExecutions.remove(resultExecution);
resultExecution.setVersion(null);
return this;
}
public void setResultExecutions(Set<ResultExecution> resultExecutions) {
this.resultExecutions = resultExecutions;
}
public Set<HyperParameter> getHyperParameters() {
return hyperParameters;
}
public Version hyperParameters(Set<HyperParameter> hyperParameters) {
this.hyperParameters = hyperParameters;
return this;
}
public Version addHyperParameter(HyperParameter hyperParameter) {
this.hyperParameters.add(hyperParameter);
hyperParameter.setVersion(this);
return this;
}
public Version removeHyperParameter(HyperParameter hyperParameter) {
this.hyperParameters.remove(hyperParameter);
hyperParameter.setVersion(null);
return this;
}
public void setHyperParameters(Set<HyperParameter> hyperParameters) {
this.hyperParameters = hyperParameters;
}
public Set<Data> getData() {
return data;
}
public Version data(Set<Data> data) {
this.data = data;
return this;
}
public Version addData(Data data) {
this.data.add(data);
data.getVersions().add(this);
return this;
}
public Version removeData(Data data) {
this.data.remove(data);
data.getVersions().remove(this);
return this;
}
public void setData(Set<Data> data) {
this.data = data;
}
public ModelConfiguration getModelConfiguration() {
return modelConfiguration;
}
public Version modelConfiguration(ModelConfiguration modelConfiguration) {
this.modelConfiguration = modelConfiguration;
return this;
}
public void setModelConfiguration(ModelConfiguration modelConfiguration) {
this.modelConfiguration = modelConfiguration;
}
// jhipster-needle-entity-add-getters-setters - Jhipster will add getters and setters here, do not remove
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Version version = (Version) o;
if (version.getId() == null || getId() == null) {
return false;
}
return Objects.equals(getId(), version.getId());
}
#Override
public int hashCode() {
return Objects.hashCode(getId());
}
#Override
public String toString() {
return "Version{" +
"id=" + getId() +
", num='" + getNum() + "'" +
", creationDate='" + getCreationDate() + "'" +
", executionDate='" + getExecutionDate() + "'" +
", weightsURI='" + getWeightsURI() + "'" +
"}";
}
}
My hyperParameter model looks like this :
#Entity
#Table(name = "hyper_parameter")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class HyperParameter implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Column(name = "parameter_value", nullable = false)
private String parameterValue;
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties({"resultExecutions", "hyperParameters", "data", "modelConfiguration"})
private Version version;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getParameterValue() {
return parameterValue;
}
public HyperParameter parameterValue(String parameterValue) {
this.parameterValue = parameterValue;
return this;
}
public void setParameterValue(String parameterValue) {
this.parameterValue = parameterValue;
}
public Version getVersion() {
return version;
}
public HyperParameter version(Version version) {
this.version = version;
return this;
}
public void setVersion(Version version) {
this.version = version;
}
public HyperParameterType getHyperParameterType() {
return hyperParameterType;
}
public HyperParameter hyperParameterType(HyperParameterType hyperParameterType) {
this.hyperParameterType = hyperParameterType;
return this;
}
public void setHyperParameterType(HyperParameterType hyperParameterType) {
this.hyperParameterType = hyperParameterType;
}
// jhipster-needle-entity-add-getters-setters - Jhipster will add getters and setters here, do not remove
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
HyperParameter hyperParameter = (HyperParameter) o;
if (hyperParameter.getId() == null || getId() == null) {
return false;
}
return Objects.equals(getId(), hyperParameter.getId());
}
#Override
public int hashCode() {
return Objects.hashCode(getId());
}
#Override
public String toString() {
return "HyperParameter{" +
"id=" + getId() +
", parameterValue='" + getParameterValue() + "'" +
"}";
}
}
I update a json and try a put with it .I change the value of the field parametervalue from 2 to 3 .
{
"id": 1,
"num": 1,
"creationDate": "2017-05-11T00:00:00+02:00",
"executionDate": null,
"weightsURI": "tests/scripts/sequential/weights/weights_le_net_5.h5py",
"resultExecutions": [
{
"id": 1,
"metricValues": "",
"executionType": "TRAIN",
"numPrediction": null
},
{
"id": 2,
"metricValues": "",
"executionType": "TRAIN",
"numPrediction": null
}
],
"hyperParameters": [
{
"id": 1,
"parameterValue": "2",
"hyperParameterType": {
"id": 1,
"name": "epochs",
"parameterType": "INTEGER",
"parameterDefaultValue": "0",
"isRequired": true
}
},
{
"id": 2,
"parameterValue": "32",
"hyperParameterType": {
"id": 2,
"name": "batch_size",
"parameterType": "INTEGER",
"parameterDefaultValue": "32",
"isRequired": true
}
}
],
"modelConfiguration": {
"id": 1,
"name": "Modele LeNet5",
"creationDate": "2017-05-11T00:00:00+02:00",
"updateDate": "2017-05-11T00:00:00+02:00",
"saveURI": "tests/scripts/sequential/models/le_net_5.json"
}
}
But when i do i got a 500 internal serveur error and stack trace like the one bellow about a null constraint violation.
<!-- What do you expect the result to be? -->
<!-- What is the actual result you get? (Please include any errors.) -->
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:526)
[1:59]
t org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:75)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:71)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
... 153 common frames omitted
Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [com.saagie.picsaagie2017_frontend.domain.HyperParameter] during update time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='can not be null ', propertyPath=version, rootBeanClass=class com.saagie.picsaagie2017_frontend.domain.HyperParameter, messageTemplate='{javax.validation.constraints.NotNull.message}'}
]
How can i update my hyperParameters when i update my version whitout getting this error.
Use the #PreUpdate and #PrePersist callbacks in the HyperParameter class like so:
#PreUpdate
#PrePersist
public void setChildObjects() {
if (getVersions() != null)
{
for (Version version : getVersions())
{
version.setHyperParameters (this);
}
}
}
Refer to this for more information : http://docs.jboss.org/hibernate/core/3.3/reference/en/html/tutorial.html#tutorial-associations-usingbidir
Both solution actually work i had a second error because of what is discussed in that topic : Spring data rest one to many cascade all . I just had to add #JsonManagedReference and #JsonBackReference because i had marshalling problem on the reference of version when i tried to update my HyperParameters in cascade.
You just have validation error. You try to put interpolatedMessage with null value. Ok but first remove #NotNull annotation on this field.

Nested Group with Spring MongoDB

I need to generate a result with the number of alerts of each level for each user.
A structure similar to the following:
{
"identitity": "59e3b9dc5a3254691f327b67",
"alerts": [
{
"level": "INFO",
"count": "3"
},
{
"level": "ERROR",
"count": "10"
}
]
}
The alert entitity has the following structure:
#Document(collection = AlertEntity.COLLECTION_NAME)
public class AlertEntity {
public final static String COLLECTION_NAME = "alerts";
#Id
private ObjectId id;
#Field
private AlertLevelEnum level = AlertLevelEnum.INFO;
#Field("title")
private String title;
#Field("payload")
private String payload;
#Field("create_at")
private Date createAt = new Date();
#Field("delivered_at")
private Date deliveredAt;
#Field("delivery_mode")
private AlertDeliveryModeEnum deliveryMode =
AlertDeliveryModeEnum.PUSH_NOTIFICATION;
#Field("parent")
#DBRef
private ParentEntity parent;
#Field("son")
#DBRef
private SonEntity son;
private Boolean delivered = Boolean.FALSE;
}
I have implemented the following method tried to project the result in a nested way. But the "Identity" field is always null and the "alerts" field is a empty collection.
#Override
public List<AlertsBySonDTO> getAlertsBySon(List<String> sonIds) {
TypedAggregation<AlertEntity> alertsAggregation =
Aggregation.newAggregation(AlertEntity.class,
Aggregation.group("son.id", "level").count().as("count"),
Aggregation.project().and("son.id").as("id")
.and("alerts").nested(
bind("level", "level").and("count")));
// Aggregation.match(Criteria.where("_id").in(sonIds)
AggregationResults<AlertsBySonDTO> results = mongoTemplate.
aggregate(alertsAggregation, AlertsBySonDTO.class);
List<AlertsBySonDTO> alertsBySonResultsList = results.getMappedResults();
return alertsBySonResultsList;
}
The result I get is the following:
{
"response_code_name": "ALERTS_BY_SON",
"response_status": "SUCCESS",
"response_http_status": "OK",
"response_info_url": "http://yourAppUrlToDocumentedApiCodes.com/api/support/710",
"response_data": [
{
"identity": null,
"alerts": []
},
{
"identity": null,
"alerts": []
}
],
"response_code": 710
}
The result DTO is as follows:
public final class AlertsBySonDTO implements Serializable {
private static final long serialVersionUID = 1L;
#JsonProperty("identity")
private String id;
#JsonProperty("alerts")
private ArrayList<Map<String, String>> alerts;
public AlertsBySonDTO() {
super();
}
public AlertsBySonDTO(String id, ArrayList<Map<String, String>> alerts) {
super();
this.id = id;
this.alerts = alerts;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public ArrayList<Map<String, String>> getAlerts() {
return alerts;
}
public void setAlerts(ArrayList<Map<String, String>> alerts) {
this.alerts = alerts;
}
}
What needs to be done to project the result in a nested way?
Thanks in advance
In aggregation framework there is an $unwind operator which will basically transform your one element collection with nested array of two elements to two separate documents with one element from this array. So you'll get:
{
"identitity": "59e3b9dc5a3254691f327b67",
"alerts": {
"level": "INFO",
"count": "3"
}
}
{
"identitity": "59e3b9dc5a3254691f327b67",
"alerts": {
"level": "ERROR",
"count": "10"
}
}
And this is where you can start your group by with count. Should be working fine.

How to consume _embedded resources with Spring HATEOAS

I am trying to consume the following REST HAL response from a 3rd party service:
{
"id": 51780,
"name": "Lambeth",
"description": "",
"address_id": 54225,
"website": "",
"numeric_widget_id": 3602008,
"currency_code": "GBP",
"timezone": "Europe/London",
"country_code": "gb",
"live": true,
"_embedded": {
"settings": {
"has_services": true,
"has_classes": true,
"payment_tax": 0,
"currency": "GBP",
"requires_login": false,
"has_wallets": false,
"ask_address": true,
"_links": {
"self": {
"href": "https://myhost.com/api/v1/51780/settings"
}
}
}
},
"_links": {
"self": {
"href": "https://myhost.com/api/v1/company/51780"
},
"settings": {
"href": "https://myhost.com/api/v1/51780/settings"
}
}
}
Which I would like to map to a class like this:
public class Company extends ResourceSupport {
private String name;
private CompanySettings settings;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public CompanySettings getSettings() {
return settings;
}
public void setSettings(CompanySettings settings) {
this.settings = settings;
}
}
And a class for the embedded item like this:
public class CompanySettings extends ResourceSupport {
private String currency;
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}
However I am having no luck getting the embedded item to map to the nested settings object. My code is below.
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<Resource<Company>> responseEntity = restTemplate.exchange("https://uk.bookingbug.com/api/v1/company/51780",
HttpMethod.GET, null, new ParameterizedTypeReference<Resource<Company>>() {
}, Collections.emptyMap());
if (responseEntity.getStatusCode() == HttpStatus.OK) {
Resource<Company> userResource = responseEntity.getBody();
Company company = userResource.getContent();
}
Any help would be greatly appreciated.

How to post to a URL with hash + range key Spring Data DynamoDB

As in spring-data-dynamoDB demo, I have created my application with hash and range keys, but am unable to post any data into my Table using POST because the following exception,
{cause: {cause: {cause: null,message: null}, message: "N/A (through reference chain: pkg.Test["id"])"}, message: "Could not read JSON: N/A (through reference chain: pkg.Test["id"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: N/A (through reference chain: pkg["id"])"
}
My Domain Class,
#DynamoDBTable(tableName = "test")
public class Test implements Serializable{
private static final long serialVersionUID = 1L;
#Id private TestId testId;
private String description;
private String testing;
#DynamoDBHashKey(attributeName="id")
public String getId() {
return testId != null ? testId.getId() : null;
}
public void setId(String id) {
if(testId == null){
testId = new TestId();
}
this.setId(id);
}
#DynamoDBRangeKey(attributeName="name")
public String getName() {
return testId != null ? testId.getName() : null;
}
public void setName(String name) {
if(testId == null){
testId = new TestId();
}
this.setName(name);
}
#DynamoDBAttribute(attributeName="description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#DynamoDBAttribute(attributeName="testing")
public String getTesting() {
return testing;
}
public void setTesting(String testing) {
this.testing = testing;
}
public TestId getTestId() {
return testId;
}
public void setTestId(TestId testId) {
this.testId = testId;
}
}
and my TestId Class,
public class TestId implements Serializable{
private String id;
private String name;
#DynamoDBHashKey
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#DynamoDBRangeKey
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I think I have created Domain class correctly but What is the correct procedure to Post data into it. I have tried,
URL:
http://localhost:8080/tests
Request Body:
{"testId": {"id": "test", "name": "z"}, "description": "Awesome Guy", "testing": "x"}
and
{"id": "test", "name": "z", "description": "Awesome Guy", "testing": "x"}
But all shows the exception as I mentioned above but I have given id attribute in requestbody correctly.
What is the correct procedure to POST the data into my table? and Is there anything problem with spring-data-rest parsing? as mentioned here
The setId() method seems to be self-calling. You may want to call testId.setId() instead of this.setId().

Resources