1 | package org.cardanofoundation.explorer.api.service.impl; | |
2 | ||
3 | import java.time.LocalDateTime; | |
4 | import java.time.ZoneOffset; | |
5 | import java.util.*; | |
6 | import java.util.function.Function; | |
7 | import java.util.stream.Collectors; | |
8 | import java.util.stream.Stream; | |
9 | ||
10 | import jakarta.annotation.PostConstruct; | |
11 | ||
12 | import lombok.RequiredArgsConstructor; | |
13 | import lombok.extern.log4j.Log4j2; | |
14 | ||
15 | import org.springframework.data.domain.Page; | |
16 | import org.springframework.data.domain.PageImpl; | |
17 | import org.springframework.data.domain.PageRequest; | |
18 | import org.springframework.data.domain.Pageable; | |
19 | import org.springframework.data.domain.Slice; | |
20 | import org.springframework.data.domain.Sort; | |
21 | import org.springframework.stereotype.Service; | |
22 | import org.springframework.transaction.annotation.Transactional; | |
23 | import org.springframework.util.CollectionUtils; | |
24 | ||
25 | import com.bloxbean.cardano.client.exception.CborDeserializationException; | |
26 | import com.bloxbean.cardano.client.transaction.spec.script.NativeScript; | |
27 | import com.bloxbean.cardano.client.transaction.spec.script.RequireTimeAfter; | |
28 | import com.bloxbean.cardano.client.transaction.spec.script.RequireTimeBefore; | |
29 | import com.bloxbean.cardano.client.transaction.spec.script.ScriptAll; | |
30 | import com.bloxbean.cardano.client.transaction.spec.script.ScriptAny; | |
31 | import com.bloxbean.cardano.client.transaction.spec.script.ScriptAtLeast; | |
32 | import com.bloxbean.cardano.client.transaction.spec.script.ScriptPubkey; | |
33 | import com.fasterxml.jackson.core.JsonProcessingException; | |
34 | import org.apache.commons.codec.binary.Hex; | |
35 | import org.apache.commons.lang3.StringUtils; | |
36 | ||
37 | import org.cardanofoundation.explorer.api.exception.BusinessCode; | |
38 | import org.cardanofoundation.explorer.api.mapper.AssetMetadataMapper; | |
39 | import org.cardanofoundation.explorer.api.mapper.ScriptMapper; | |
40 | import org.cardanofoundation.explorer.api.mapper.TokenMapper; | |
41 | import org.cardanofoundation.explorer.api.model.request.script.nativescript.NativeScriptFilterRequest; | |
42 | import org.cardanofoundation.explorer.api.model.request.script.smartcontract.SmartContractFilterRequest; | |
43 | import org.cardanofoundation.explorer.api.model.response.BaseFilterResponse; | |
44 | import org.cardanofoundation.explorer.api.model.response.script.nativescript.NativeScriptFilterResponse; | |
45 | import org.cardanofoundation.explorer.api.model.response.script.nativescript.NativeScriptResponse; | |
46 | import org.cardanofoundation.explorer.api.model.response.script.projection.SmartContractTxProjection; | |
47 | import org.cardanofoundation.explorer.api.model.response.script.smartcontract.SmartContractDetailResponse; | |
48 | import org.cardanofoundation.explorer.api.model.response.script.smartcontract.SmartContractFilterResponse; | |
49 | import org.cardanofoundation.explorer.api.model.response.script.smartcontract.SmartContractTxResponse; | |
50 | import org.cardanofoundation.explorer.api.model.response.search.ScriptSearchResponse; | |
51 | import org.cardanofoundation.explorer.api.model.response.token.TokenAddressResponse; | |
52 | import org.cardanofoundation.explorer.api.model.response.token.TokenFilterResponse; | |
53 | import org.cardanofoundation.explorer.api.model.response.tx.ContractResponse; | |
54 | import org.cardanofoundation.explorer.api.projection.AddressTokenProjection; | |
55 | import org.cardanofoundation.explorer.api.projection.TokenProjection; | |
56 | import org.cardanofoundation.explorer.api.repository.explorer.NativeScriptInfoRepository; | |
57 | import org.cardanofoundation.explorer.api.repository.explorer.SmartContractInfoRepository; | |
58 | import org.cardanofoundation.explorer.api.repository.explorer.VerifiedScriptRepository; | |
59 | import org.cardanofoundation.explorer.api.repository.ledgersync.*; | |
60 | import org.cardanofoundation.explorer.api.repository.ledgersyncagg.AddressRepository; | |
61 | import org.cardanofoundation.explorer.api.repository.ledgersyncagg.LatestTokenBalanceRepository; | |
62 | import org.cardanofoundation.explorer.api.service.ScriptService; | |
63 | import org.cardanofoundation.explorer.api.service.TxService; | |
64 | import org.cardanofoundation.explorer.api.specification.NativeScriptInfoSpecification; | |
65 | import org.cardanofoundation.explorer.common.entity.enumeration.ScriptPurposeType; | |
66 | import org.cardanofoundation.explorer.common.entity.enumeration.ScriptType; | |
67 | import org.cardanofoundation.explorer.common.entity.explorer.NativeScriptInfo; | |
68 | import org.cardanofoundation.explorer.common.entity.explorer.SmartContractInfo; | |
69 | import org.cardanofoundation.explorer.common.entity.explorer.VerifiedScript; | |
70 | import org.cardanofoundation.explorer.common.entity.ledgersync.Block; | |
71 | import org.cardanofoundation.explorer.common.entity.ledgersync.MultiAsset; | |
72 | import org.cardanofoundation.explorer.common.entity.ledgersync.Script; | |
73 | import org.cardanofoundation.explorer.common.exception.BusinessException; | |
74 | ||
75 | @Service | |
76 | @RequiredArgsConstructor | |
77 | @Log4j2 | |
78 | public class ScriptServiceImpl implements ScriptService { | |
79 | ||
80 | private final ScriptRepository scriptRepository; | |
81 | private final NativeScriptInfoRepository nativeScriptInfoRepository; | |
82 | private final MultiAssetRepository multiAssetRepository; | |
83 | private final StakeAddressRepository stakeAddressRepository; | |
84 | private final RedeemerRepository redeemerRepository; | |
85 | private final TxRepository txRepository; | |
86 | private final AddressRepository addressRepository; | |
87 | private final LatestTokenBalanceRepository latestTokenBalanceRepository; | |
88 | private final MaTxMintRepository maTxMintRepository; | |
89 | private final BlockRepository blockRepository; | |
90 | private final VerifiedScriptRepository verifiedScriptRepository; | |
91 | private final SmartContractInfoRepository smartContractInfoRepository; | |
92 | ||
93 | private final TxService txService; | |
94 | ||
95 | private final ScriptMapper scriptMapper; | |
96 | private final AssetMetadataMapper assetMetadataMapper; | |
97 | private final TokenMapper tokenMapper; | |
98 | ||
99 | private Block firstShellyBlock = null; | |
100 | private Block firstBlock = null; | |
101 | ||
102 | private static final Long MAX_SLOT = 365241780471L; | |
103 | ||
104 | @PostConstruct | |
105 | private void init() { | |
106 | firstShellyBlock = blockRepository.findFirstShellyBlock().orElse(null); | |
107 | firstBlock = | |
108 | blockRepository | |
109 | .findFirstBlock() | |
110 |
1
1. lambda$init$0 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$init$0 → NO_COVERAGE |
.orElseThrow(() -> new BusinessException(BusinessCode.BLOCK_NOT_FOUND)); |
111 | } | |
112 | ||
113 | @Override | |
114 | public BaseFilterResponse<NativeScriptFilterResponse> getNativeScripts( | |
115 | NativeScriptFilterRequest filterRequest, Pageable pageable) { | |
116 | Block currrentBlock = | |
117 | blockRepository | |
118 | .findLatestBlock() | |
119 |
1
1. lambda$getNativeScripts$1 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getNativeScripts$1 → KILLED |
.orElseThrow(() -> new BusinessException(BusinessCode.BLOCK_NOT_FOUND)); |
120 | Page<NativeScriptInfo> nativeScriptPage = | |
121 | nativeScriptInfoRepository.findAll( | |
122 | NativeScriptInfoSpecification.filter(currrentBlock.getSlotNo(), filterRequest), | |
123 | pageable); | |
124 | List<TokenProjection> tokenProjectionList = | |
125 | multiAssetRepository.findTopMultiAssetByScriptHashIn( | |
126 | nativeScriptPage.stream().map(NativeScriptInfo::getScriptHash).toList()); | |
127 | List<TokenFilterResponse> tokenResponses = | |
128 | tokenProjectionList.stream() | |
129 | .map(assetMetadataMapper::fromTokenProjectionToFilterResponse) | |
130 | .toList(); | |
131 | Map<String, List<TokenFilterResponse>> tokenResponseMap = | |
132 | tokenResponses.stream().collect(Collectors.groupingBy(TokenFilterResponse::getPolicy)); | |
133 | Page<NativeScriptFilterResponse> nativeScriptPageResponse = | |
134 | nativeScriptPage.map( | |
135 | item -> { | |
136 | NativeScriptFilterResponse nativeScriptResponse = new NativeScriptFilterResponse(); | |
137 |
1
1. lambda$getNativeScripts$2 : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptFilterResponse::setScriptHash → KILLED |
nativeScriptResponse.setScriptHash(item.getScriptHash()); |
138 |
1
1. lambda$getNativeScripts$2 : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptFilterResponse::setNumberOfTokens → KILLED |
nativeScriptResponse.setNumberOfTokens(item.getNumberOfTokens()); |
139 |
1
1. lambda$getNativeScripts$2 : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptFilterResponse::setNumberOfAssetHolders → KILLED |
nativeScriptResponse.setNumberOfAssetHolders(item.getNumberOfAssetHolders()); |
140 |
1
1. lambda$getNativeScripts$2 : negated conditional → SURVIVED |
if (Objects.nonNull(item.getAfterSlot())) { |
141 |
1
1. lambda$getNativeScripts$2 : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptFilterResponse::setAfter → SURVIVED |
nativeScriptResponse.setAfter( |
142 | slotToTime(item.getAfterSlot(), firstBlock, firstShellyBlock)); | |
143 | } | |
144 |
1
1. lambda$getNativeScripts$2 : negated conditional → SURVIVED |
if (Objects.nonNull(item.getBeforeSlot())) { |
145 |
1
1. lambda$getNativeScripts$2 : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptFilterResponse::setBefore → SURVIVED |
nativeScriptResponse.setBefore( |
146 | slotToTime(item.getBeforeSlot(), firstBlock, firstShellyBlock)); | |
147 | } | |
148 |
1
1. lambda$getNativeScripts$2 : negated conditional → KILLED |
if (Objects.nonNull(item.getNumberSig())) { |
149 |
1
1. lambda$getNativeScripts$2 : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptFilterResponse::setIsMultiSig → NO_COVERAGE |
nativeScriptResponse.setIsMultiSig( |
150 |
2
1. lambda$getNativeScripts$2 : negated conditional → NO_COVERAGE 2. lambda$getNativeScripts$2 : changed conditional boundary → NO_COVERAGE |
Long.valueOf(1L).compareTo(item.getNumberSig()) < 0); |
151 | } | |
152 |
1
1. lambda$getNativeScripts$2 : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptFilterResponse::setTokens → SURVIVED |
nativeScriptResponse.setTokens(tokenResponseMap.get(item.getScriptHash())); |
153 |
1
1. lambda$getNativeScripts$2 : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptFilterResponse::setIsOpen → KILLED |
nativeScriptResponse.setIsOpen(setStatus(item, currrentBlock.getSlotNo())); |
154 |
1
1. lambda$getNativeScripts$2 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getNativeScripts$2 → KILLED |
return nativeScriptResponse; |
155 | }); | |
156 |
1
1. getNativeScripts : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::getNativeScripts → KILLED |
return new BaseFilterResponse<>(nativeScriptPageResponse); |
157 | } | |
158 | /** | |
159 | * Explain native script | |
160 | * | |
161 | * @param nativeScript native script | |
162 | * @param nativeScriptResponse native script response | |
163 | */ | |
164 | private void setNativeScriptInfo( | |
165 | NativeScript nativeScript, NativeScriptResponse nativeScriptResponse) { | |
166 |
1
1. setNativeScriptInfo : negated conditional → KILLED |
if (nativeScript.getClass().equals(ScriptPubkey.class)) { |
167 | ScriptPubkey scriptPubkey = (ScriptPubkey) nativeScript; | |
168 | nativeScriptResponse.getKeyHashes().add(scriptPubkey.getKeyHash()); | |
169 |
1
1. setNativeScriptInfo : negated conditional → KILLED |
} else if (nativeScript.getClass().equals(ScriptAll.class)) { |
170 | ScriptAll scriptAll = (ScriptAll) nativeScript; | |
171 |
1
1. setNativeScriptInfo : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setConditionType → KILLED |
nativeScriptResponse.setConditionType(scriptAll.getType()); |
172 | for (NativeScript script : scriptAll.getScripts()) { | |
173 |
1
1. setNativeScriptInfo : removed call to org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::setNativeScriptInfo → KILLED |
setNativeScriptInfo(script, nativeScriptResponse); |
174 | } | |
175 |
1
1. setNativeScriptInfo : negated conditional → KILLED |
} else if (nativeScript.getClass().equals(ScriptAny.class)) { |
176 | ScriptAny scriptAny = (ScriptAny) nativeScript; | |
177 |
1
1. setNativeScriptInfo : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setConditionType → SURVIVED |
nativeScriptResponse.setConditionType(scriptAny.getType()); |
178 | for (NativeScript script : scriptAny.getScripts()) { | |
179 |
1
1. setNativeScriptInfo : removed call to org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::setNativeScriptInfo → KILLED |
setNativeScriptInfo(script, nativeScriptResponse); |
180 | } | |
181 |
1
1. setNativeScriptInfo : negated conditional → KILLED |
} else if (nativeScript.getClass().equals(ScriptAtLeast.class)) { |
182 | ScriptAtLeast scriptAtLeast = (ScriptAtLeast) nativeScript; | |
183 |
1
1. setNativeScriptInfo : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setConditionType → KILLED |
nativeScriptResponse.setConditionType(scriptAtLeast.getType()); |
184 |
1
1. setNativeScriptInfo : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setRequired → KILLED |
nativeScriptResponse.setRequired(scriptAtLeast.getRequired()); |
185 | for (NativeScript script : scriptAtLeast.getScripts()) { | |
186 |
1
1. setNativeScriptInfo : removed call to org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::setNativeScriptInfo → SURVIVED |
setNativeScriptInfo(script, nativeScriptResponse); |
187 | } | |
188 |
1
1. setNativeScriptInfo : negated conditional → KILLED |
} else if (nativeScript.getClass().equals(RequireTimeAfter.class)) { |
189 | RequireTimeAfter requireTimeAfter = (RequireTimeAfter) nativeScript; | |
190 | LocalDateTime after = slotToTime(requireTimeAfter.getSlot(), firstBlock, firstShellyBlock); | |
191 |
1
1. setNativeScriptInfo : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setAfter → SURVIVED |
nativeScriptResponse.setAfter(after); |
192 |
1
1. setNativeScriptInfo : negated conditional → KILLED |
} else if (nativeScript.getClass().equals(RequireTimeBefore.class)) { |
193 | RequireTimeBefore requireTimeBefore = (RequireTimeBefore) nativeScript; | |
194 | LocalDateTime before = slotToTime(requireTimeBefore.getSlot(), firstBlock, firstShellyBlock); | |
195 |
1
1. setNativeScriptInfo : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setBefore → KILLED |
nativeScriptResponse.setBefore(before); |
196 | } | |
197 | } | |
198 | ||
199 | private boolean setStatus(NativeScriptInfo nativeScriptInfo, Long currentSlot) { | |
200 | boolean isOpen = false; | |
201 | boolean isNullBefore = Objects.isNull(nativeScriptInfo.getBeforeSlot()); | |
202 | boolean isNullAfter = Objects.isNull(nativeScriptInfo.getAfterSlot()); | |
203 |
2
1. setStatus : negated conditional → KILLED 2. setStatus : negated conditional → KILLED |
if (!isNullBefore && !isNullAfter) { |
204 | isOpen = | |
205 |
1
1. setStatus : negated conditional → KILLED |
Long.compare(nativeScriptInfo.getAfterSlot(), currentSlot) == -1 |
206 |
1
1. setStatus : negated conditional → KILLED |
&& Long.compare(nativeScriptInfo.getBeforeSlot(), currentSlot) == 1; |
207 |
2
1. setStatus : negated conditional → KILLED 2. setStatus : negated conditional → KILLED |
} else if (isNullAfter && !isNullBefore) { |
208 |
1
1. setStatus : negated conditional → KILLED |
isOpen = Long.compare(nativeScriptInfo.getBeforeSlot(), currentSlot) == 1; |
209 |
2
1. setStatus : negated conditional → NO_COVERAGE 2. setStatus : negated conditional → NO_COVERAGE |
} else if (isNullBefore && !isNullAfter) { |
210 |
1
1. setStatus : negated conditional → NO_COVERAGE |
isOpen = Long.compare(nativeScriptInfo.getAfterSlot(), currentSlot) == -1; |
211 |
2
1. setStatus : negated conditional → NO_COVERAGE 2. setStatus : negated conditional → NO_COVERAGE |
} else if (isNullAfter && isNullBefore) { |
212 | isOpen = true; | |
213 | } | |
214 |
2
1. setStatus : replaced boolean return with true for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::setStatus → SURVIVED 2. setStatus : replaced boolean return with false for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::setStatus → KILLED |
return isOpen; |
215 | } | |
216 | ||
217 | @Override | |
218 | public NativeScriptResponse getNativeScriptDetail(String scriptHash) { | |
219 | Block currrentBlock = | |
220 | blockRepository | |
221 | .findLatestBlock() | |
222 |
1
1. lambda$getNativeScriptDetail$3 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getNativeScriptDetail$3 → NO_COVERAGE |
.orElseThrow(() -> new BusinessException(BusinessCode.BLOCK_NOT_FOUND)); |
223 | NativeScriptResponse nativeScriptResponse = new NativeScriptResponse(); | |
224 | Script script = | |
225 | scriptRepository | |
226 | .findByHash(scriptHash) | |
227 |
1
1. lambda$getNativeScriptDetail$4 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getNativeScriptDetail$4 → NO_COVERAGE |
.orElseThrow(() -> new BusinessException(BusinessCode.SCRIPT_NOT_FOUND)); |
228 | Set<ScriptType> nativeScriptTypes = Set.of(ScriptType.TIMELOCK, ScriptType.MULTISIG); | |
229 |
1
1. getNativeScriptDetail : negated conditional → KILLED |
if (!nativeScriptTypes.contains(script.getType())) { |
230 | throw new BusinessException(BusinessCode.SCRIPT_NOT_FOUND); | |
231 | } | |
232 | NativeScriptInfo nativeScriptInfo = | |
233 | nativeScriptInfoRepository | |
234 | .findByScriptHash(scriptHash) | |
235 | .orElseGet( | |
236 | () -> | |
237 |
1
1. lambda$getNativeScriptDetail$5 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getNativeScriptDetail$5 → NO_COVERAGE |
NativeScriptInfo.builder() |
238 | .numberOfTokens(multiAssetRepository.countMultiAssetByPolicy(scriptHash)) | |
239 | .numberOfAssetHolders( | |
240 | latestTokenBalanceRepository.countAssetHoldersByPolicy(scriptHash)) | |
241 | .build()); | |
242 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setScriptHash → KILLED |
nativeScriptResponse.setScriptHash(scriptHash); |
243 | List<String> associatedAddressList = | |
244 | stakeAddressRepository.getStakeAssociatedAddress(scriptHash); | |
245 | associatedAddressList.addAll(addressRepository.getAssociatedAddress(scriptHash)); | |
246 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setAssociatedAddress → SURVIVED |
nativeScriptResponse.setAssociatedAddress(associatedAddressList); |
247 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setNumberOfTokens → KILLED |
nativeScriptResponse.setNumberOfTokens(nativeScriptInfo.getNumberOfTokens()); |
248 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setNumberOfAssetHolders → KILLED |
nativeScriptResponse.setNumberOfAssetHolders(nativeScriptInfo.getNumberOfAssetHolders()); |
249 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setKeyHashes → KILLED |
nativeScriptResponse.setKeyHashes(new ArrayList<>()); |
250 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setVerifiedContract → SURVIVED |
nativeScriptResponse.setVerifiedContract(false); |
251 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setIsOpen → KILLED |
nativeScriptResponse.setIsOpen(setStatus(nativeScriptInfo, currrentBlock.getSlotNo())); |
252 | ||
253 | String json = script.getJson(); | |
254 |
1
1. getNativeScriptDetail : negated conditional → KILLED |
if (StringUtils.isEmpty(json)) { |
255 | Optional<VerifiedScript> verifiedScript = verifiedScriptRepository.findByHash(scriptHash); | |
256 |
2
1. getNativeScriptDetail : negated conditional → KILLED 2. getNativeScriptDetail : negated conditional → KILLED |
if (verifiedScript.isPresent() && StringUtils.isEmpty(json)) { |
257 | json = verifiedScript.get().getJson(); | |
258 | } | |
259 | } | |
260 | ||
261 | try { | |
262 |
1
1. getNativeScriptDetail : negated conditional → KILLED |
if (!StringUtils.isEmpty(json)) { |
263 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setVerifiedContract → KILLED |
nativeScriptResponse.setVerifiedContract(true); |
264 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setScript → SURVIVED |
nativeScriptResponse.setScript(json); |
265 | NativeScript nativeScript = NativeScript.deserializeJson(json); | |
266 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::setNativeScriptInfo → KILLED |
setNativeScriptInfo(nativeScript, nativeScriptResponse); |
267 | // One time mint is a native script that has a timelock before the current time | |
268 | // and has only one mint transaction | |
269 |
1
1. getNativeScriptDetail : negated conditional → KILLED |
if (Objects.nonNull(nativeScriptResponse.getBefore()) |
270 |
1
1. getNativeScriptDetail : negated conditional → KILLED |
&& LocalDateTime.now(ZoneOffset.UTC).isAfter(nativeScriptResponse.getBefore()) |
271 |
1
1. getNativeScriptDetail : negated conditional → KILLED |
&& isOneTimeMint(scriptHash)) { |
272 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setIsOneTimeMint → KILLED |
nativeScriptResponse.setIsOneTimeMint( |
273 |
1
1. getNativeScriptDetail : negated conditional → SURVIVED |
Objects.isNull(nativeScriptResponse.getConditionType()) |
274 |
1
1. getNativeScriptDetail : negated conditional → KILLED |
|| com.bloxbean.cardano.client.transaction.spec.script.ScriptType.all.equals( |
275 | nativeScriptResponse.getConditionType())); | |
276 | } else { | |
277 |
1
1. getNativeScriptDetail : removed call to org/cardanofoundation/explorer/api/model/response/script/nativescript/NativeScriptResponse::setIsOneTimeMint → KILLED |
nativeScriptResponse.setIsOneTimeMint(false); |
278 | } | |
279 | } | |
280 | } catch (JsonProcessingException | CborDeserializationException e) { | |
281 | log.warn("Error parsing script json: {}", e.getMessage()); | |
282 | throw new BusinessException(BusinessCode.SCRIPT_NOT_FOUND); | |
283 | } | |
284 |
1
1. getNativeScriptDetail : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::getNativeScriptDetail → KILLED |
return nativeScriptResponse; |
285 | } | |
286 | ||
287 | /** | |
288 | * Convert slot to time | |
289 | * | |
290 | * @param slot input slot | |
291 | * @param firstBlock first block | |
292 | * @param firstShellyBlock first shelly block | |
293 | * @return time in UTC | |
294 | */ | |
295 | private LocalDateTime slotToTime(Long slot, Block firstBlock, Block firstShellyBlock) { | |
296 |
2
1. slotToTime : changed conditional boundary → SURVIVED 2. slotToTime : negated conditional → KILLED |
if (slot > MAX_SLOT) { |
297 |
1
1. slotToTime : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::slotToTime → NO_COVERAGE |
return LocalDateTime.MAX; |
298 | } | |
299 |
1
1. slotToTime : negated conditional → SURVIVED |
if (Objects.nonNull(firstShellyBlock)) { |
300 |
1
1. slotToTime : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::slotToTime → KILLED |
return firstShellyBlock |
301 | .getTime() | |
302 | .toLocalDateTime() | |
303 |
1
1. slotToTime : Replaced long subtraction with addition → SURVIVED |
.plusSeconds(slot - (firstShellyBlock.getSlotNo())) |
304 | .atZone(ZoneOffset.UTC) | |
305 | .toLocalDateTime(); | |
306 | } else { | |
307 |
1
1. slotToTime : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::slotToTime → NO_COVERAGE |
return firstBlock |
308 | .getTime() | |
309 | .toLocalDateTime() | |
310 | .plusSeconds(slot) | |
311 | .atZone(ZoneOffset.UTC) | |
312 | .toLocalDateTime(); | |
313 | } | |
314 | } | |
315 | ||
316 | @Override | |
317 | @Transactional | |
318 | public String verifyNativeScript(String scriptHash, String scriptJson) { | |
319 | try { | |
320 | Script script = | |
321 | scriptRepository | |
322 | .findByHash(scriptHash) | |
323 |
1
1. lambda$verifyNativeScript$6 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$verifyNativeScript$6 → SURVIVED |
.orElseThrow(() -> new BusinessException(BusinessCode.SCRIPT_NOT_FOUND)); |
324 | Set<ScriptType> nativeScriptTypes = Set.of(ScriptType.TIMELOCK, ScriptType.MULTISIG); | |
325 |
1
1. verifyNativeScript : negated conditional → KILLED |
if (!nativeScriptTypes.contains(script.getType())) { |
326 | throw new BusinessException(BusinessCode.SCRIPT_NOT_FOUND); | |
327 | } | |
328 |
1
1. verifyNativeScript : negated conditional → KILLED |
if (Boolean.TRUE.equals(verifiedScriptRepository.existsVerifiedScriptByHash(scriptHash))) { |
329 | throw new BusinessException(BusinessCode.SCRIPT_ALREADY_VERIFIED); | |
330 | } | |
331 | String hash = Hex.encodeHexString(NativeScript.deserializeJson(scriptJson).getScriptHash()); | |
332 |
2
1. verifyNativeScript : negated conditional → KILLED 2. verifyNativeScript : negated conditional → KILLED |
if (script.getHash().equals(hash) && StringUtils.isEmpty(script.getJson())) { |
333 | VerifiedScript verifiedScript = | |
334 | VerifiedScript.builder().hash(scriptHash).json(scriptJson).build(); | |
335 | verifiedScriptRepository.save(verifiedScript); | |
336 |
1
1. verifyNativeScript : replaced return value with "" for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::verifyNativeScript → KILLED |
return scriptJson; |
337 | } else { | |
338 | throw new BusinessException(BusinessCode.VERIFY_SCRIPT_FAILED); | |
339 | } | |
340 | } catch (Exception e) { | |
341 | throw new BusinessException(BusinessCode.VERIFY_SCRIPT_FAILED); | |
342 | } | |
343 | } | |
344 | ||
345 | @Override | |
346 | public BaseFilterResponse<TokenFilterResponse> getNativeScriptTokens( | |
347 | String scriptHash, Pageable pageable) { | |
348 | NativeScriptInfo nativeScriptInfo = | |
349 | nativeScriptInfoRepository | |
350 | .findByScriptHash(scriptHash) | |
351 | .orElseGet( | |
352 | () -> | |
353 |
1
1. lambda$getNativeScriptTokens$7 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getNativeScriptTokens$7 → KILLED |
NativeScriptInfo.builder() |
354 | .numberOfTokens(multiAssetRepository.countMultiAssetByPolicy(scriptHash)) | |
355 | .build()); | |
356 | List<TokenFilterResponse> tokenFilterResponses = | |
357 | multiAssetRepository.findTokenInfoByScriptHash(scriptHash, pageable).stream() | |
358 | .map(assetMetadataMapper::fromTokenProjectionToFilterResponse) | |
359 | .toList(); | |
360 | Page<TokenFilterResponse> tokenPage = | |
361 | new PageImpl<>(tokenFilterResponses, pageable, nativeScriptInfo.getNumberOfTokens()); | |
362 |
1
1. getNativeScriptTokens : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::getNativeScriptTokens → KILLED |
return new BaseFilterResponse<>(tokenPage); |
363 | } | |
364 | ||
365 | @Override | |
366 | public BaseFilterResponse<TokenAddressResponse> getNativeScriptHolders( | |
367 | String scriptHash, Pageable pageable) { | |
368 | NativeScriptInfo nativeScriptInfo = | |
369 | nativeScriptInfoRepository | |
370 | .findByScriptHash(scriptHash) | |
371 | .orElseGet( | |
372 | () -> | |
373 |
1
1. lambda$getNativeScriptHolders$8 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getNativeScriptHolders$8 → NO_COVERAGE |
NativeScriptInfo.builder() |
374 | .numberOfAssetHolders( | |
375 | latestTokenBalanceRepository.countAssetHoldersByPolicy(scriptHash)) | |
376 | .build()); | |
377 | List<AddressTokenProjection> addressTokenMap = | |
378 | latestTokenBalanceRepository.findAddressAndBalanceByPolicy(scriptHash, pageable); | |
379 | ||
380 | Map<String, MultiAsset> multiAssetMap = | |
381 | multiAssetRepository | |
382 | .findAllByUnitIn(addressTokenMap.stream().map(AddressTokenProjection::getUnit).toList()) | |
383 | .stream() | |
384 | .collect(Collectors.toMap(MultiAsset::getUnit, Function.identity())); | |
385 | ||
386 | Page<AddressTokenProjection> addressTokenPage = | |
387 | new PageImpl<>(addressTokenMap, pageable, nativeScriptInfo.getNumberOfAssetHolders()); | |
388 | ||
389 | Page<TokenAddressResponse> tokenAddressResponses = | |
390 | addressTokenPage.map( | |
391 | addressTokenProjection -> { | |
392 | MultiAsset multiAsset = multiAssetMap.get(addressTokenProjection.getUnit()); | |
393 |
1
1. lambda$getNativeScriptHolders$9 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getNativeScriptHolders$9 → KILLED |
return tokenMapper.fromAddressTokenProjectionAndMultiAsset( |
394 | addressTokenProjection, multiAsset); | |
395 | }); | |
396 | ||
397 |
1
1. getNativeScriptHolders : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::getNativeScriptHolders → KILLED |
return new BaseFilterResponse<>(tokenAddressResponses); |
398 | } | |
399 | ||
400 | @Override | |
401 | public BaseFilterResponse<SmartContractFilterResponse> getSmartContracts( | |
402 | SmartContractFilterRequest filterRequest, Pageable pageable) { | |
403 |
1
1. getSmartContracts : removed call to org/cardanofoundation/explorer/api/mapper/ScriptMapper::setScriptTxPurpose → SURVIVED |
scriptMapper.setScriptTxPurpose(filterRequest); |
404 | Page<SmartContractInfo> smartContractProjections = | |
405 | smartContractInfoRepository.findAllByFilterRequest( | |
406 | filterRequest.getScriptVersion(), | |
407 | filterRequest.getIsScriptReward(), | |
408 | filterRequest.getIsScriptCert(), | |
409 | filterRequest.getIsScriptSpend(), | |
410 | filterRequest.getIsScriptMint(), | |
411 | filterRequest.getIsScriptVote(), | |
412 | filterRequest.getIsScriptPropose(), | |
413 | filterRequest.getIsScriptAny(), | |
414 | filterRequest.getIsScriptNone(), | |
415 | pageable); | |
416 | ||
417 |
1
1. getSmartContracts : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::getSmartContracts → KILLED |
return new BaseFilterResponse<>( |
418 | smartContractProjections.map(scriptMapper::fromSCInfoToSCFilterResponse)); | |
419 | } | |
420 | ||
421 | @Override | |
422 | public SmartContractDetailResponse getSmartContractDetail(String scriptHash) { | |
423 | Script script = | |
424 | scriptRepository | |
425 | .findByHash(scriptHash) | |
426 |
1
1. lambda$getSmartContractDetail$10 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getSmartContractDetail$10 → KILLED |
.orElseThrow(() -> new BusinessException(BusinessCode.SCRIPT_NOT_FOUND)); |
427 | ||
428 |
1
1. getSmartContractDetail : negated conditional → KILLED |
if (!script.getType().equals(ScriptType.PLUTUSV1) |
429 |
1
1. getSmartContractDetail : negated conditional → KILLED |
&& !script.getType().equals(ScriptType.PLUTUSV2) |
430 |
1
1. getSmartContractDetail : negated conditional → KILLED |
&& !script.getType().equals(ScriptType.PLUTUSV3)) { |
431 | throw new BusinessException(BusinessCode.SCRIPT_NOT_FOUND); | |
432 | } | |
433 | ||
434 | List<String> associatedAddresses = | |
435 | Stream.concat( | |
436 | stakeAddressRepository.getAssociatedAddress(scriptHash).stream(), | |
437 | addressRepository.getAssociatedAddress(scriptHash).stream()) | |
438 | .toList(); | |
439 | ||
440 |
1
1. getSmartContractDetail : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::getSmartContractDetail → KILLED |
return SmartContractDetailResponse.builder() |
441 | .scriptHash(script.getHash()) | |
442 | .scriptType(script.getType()) | |
443 | .associatedAddresses(associatedAddresses) | |
444 | .build(); | |
445 | } | |
446 | ||
447 | @Override | |
448 | public BaseFilterResponse<SmartContractTxResponse> getSmartContractTxs( | |
449 | String scriptHash, Pageable pageable) { | |
450 | ||
451 | long txCount = smartContractInfoRepository.getTxCountByScriptHash(scriptHash).orElse(0L); | |
452 | Page<Long> txIds = | |
453 | new PageImpl<>( | |
454 | redeemerRepository.findTxIdsInteractWithContract(scriptHash, pageable), | |
455 | pageable, | |
456 | txCount); | |
457 | ||
458 | // get smart contract tx map | |
459 | Map<Long, SmartContractTxResponse> smartContractTxMap = | |
460 | txRepository.getSmartContractTxsByTxIds(txIds.getContent()).stream() | |
461 | .map(scriptMapper::fromSmartContractTxProjection) | |
462 | .collect(Collectors.toMap(SmartContractTxResponse::getTxId, Function.identity())); | |
463 | ||
464 | // get script purpose type map | |
465 | Map<Long, List<ScriptPurposeType>> scriptPurposeTypeMap = | |
466 | txRepository.getSmartContractTxsPurpose(txIds.getContent(), scriptHash).stream() | |
467 | .collect(Collectors.groupingBy(SmartContractTxProjection::getTxId)) | |
468 | .entrySet() | |
469 | .stream() | |
470 | .collect( | |
471 | Collectors.toMap( | |
472 | Map.Entry::getKey, | |
473 | e -> | |
474 |
1
1. lambda$getSmartContractTxs$11 : replaced return value with Collections.emptyList for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$getSmartContractTxs$11 → KILLED |
e.getValue().stream() |
475 | .map(SmartContractTxProjection::getScriptPurposeType) | |
476 | .toList())); | |
477 | ||
478 | List<SmartContractTxResponse> smartContractTxResponses = new ArrayList<>(); | |
479 | txIds.stream() | |
480 |
1
1. getSmartContractTxs : removed call to java/util/stream/Stream::forEach → KILLED |
.forEach( |
481 | txId -> { | |
482 | SmartContractTxResponse smartContractTxResponse = smartContractTxMap.get(txId); | |
483 |
1
1. lambda$getSmartContractTxs$12 : removed call to org/cardanofoundation/explorer/api/model/response/script/smartcontract/SmartContractTxResponse::setScriptPurposeTypes → KILLED |
smartContractTxResponse.setScriptPurposeTypes( |
484 | scriptPurposeTypeMap.get(smartContractTxResponse.getTxId())); | |
485 | ||
486 | smartContractTxResponses.add(smartContractTxResponse); | |
487 | }); | |
488 | ||
489 |
1
1. getSmartContractTxs : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::getSmartContractTxs → KILLED |
return new BaseFilterResponse<>(txIds, smartContractTxResponses); |
490 | } | |
491 | ||
492 | @Override | |
493 | public Set<String> getContractExecutions(String txHash, String scriptHash) { | |
494 | Set<String> contractExecutions = new HashSet<>(); | |
495 | List<ContractResponse> contractResponseList = | |
496 | txService.getTxDetailByHash(txHash).getContracts(); | |
497 |
1
1. getContractExecutions : removed call to java/util/List::forEach → KILLED |
contractResponseList.forEach( |
498 | contractResponse -> { | |
499 |
1
1. lambda$getContractExecutions$13 : negated conditional → KILLED |
if (scriptHash.equals(contractResponse.getScriptHash())) { |
500 |
1
1. lambda$getContractExecutions$13 : negated conditional → KILLED |
if (!CollectionUtils.isEmpty(contractResponse.getExecutionInputs())) { |
501 | contractExecutions.addAll(contractResponse.getExecutionInputs()); | |
502 | } | |
503 |
1
1. lambda$getContractExecutions$13 : negated conditional → KILLED |
if (!CollectionUtils.isEmpty(contractResponse.getExecutionOutputs())) { |
504 | contractExecutions.addAll(contractResponse.getExecutionOutputs()); | |
505 | } | |
506 | } | |
507 | }); | |
508 |
1
1. getContractExecutions : replaced return value with Collections.emptySet for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::getContractExecutions → KILLED |
return contractExecutions.stream() |
509 | .sorted(Comparator.reverseOrder()) | |
510 | .collect(Collectors.toCollection(LinkedHashSet::new)); | |
511 | } | |
512 | ||
513 | @Override | |
514 | public ScriptSearchResponse searchScript(String scriptHash) { | |
515 | Script script = | |
516 | scriptRepository | |
517 | .findByHash(scriptHash) | |
518 |
1
1. lambda$searchScript$14 : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::lambda$searchScript$14 → KILLED |
.orElseThrow(() -> new BusinessException(BusinessCode.SCRIPT_NOT_FOUND)); |
519 | boolean isSmartContract = | |
520 |
1
1. searchScript : negated conditional → KILLED |
ScriptType.PLUTUSV1.equals(script.getType()) |
521 |
1
1. searchScript : negated conditional → KILLED |
|| ScriptType.PLUTUSV2.equals(script.getType()) |
522 |
1
1. searchScript : negated conditional → KILLED |
|| ScriptType.PLUTUSV3.equals(script.getType()); |
523 | ScriptSearchResponse scriptSearchResponse = | |
524 | ScriptSearchResponse.builder().scriptHash(script.getHash()).build(); | |
525 | ||
526 |
1
1. searchScript : negated conditional → KILLED |
if (isSmartContract) { |
527 |
1
1. searchScript : removed call to org/cardanofoundation/explorer/api/model/response/search/ScriptSearchResponse::setSmartContract → KILLED |
scriptSearchResponse.setSmartContract(true); |
528 | } else { | |
529 |
1
1. searchScript : removed call to org/cardanofoundation/explorer/api/model/response/search/ScriptSearchResponse::setNativeScript → KILLED |
scriptSearchResponse.setNativeScript(true); |
530 | } | |
531 |
1
1. searchScript : replaced return value with null for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::searchScript → KILLED |
return scriptSearchResponse; |
532 | } | |
533 | ||
534 | /** | |
535 | * Determines if a given script hash corresponds to a one-time mint. This method checks if there | |
536 | * is only one mint transaction associated with the multi-assets identified by the given script | |
537 | * hash. It iterates through the multi-assets, checking each for multiple mint transactions. If | |
538 | * any multi-asset has more than one mint transaction, the method returns false, indicating that | |
539 | * the script hash is not a one-time mint. | |
540 | * | |
541 | * @param scriptHash The script hash | |
542 | * @return true if the script hash type of one-time mint, false otherwise. | |
543 | */ | |
544 | private boolean isOneTimeMint(String scriptHash) { | |
545 | Pageable pageable = PageRequest.of(0, 100, Sort.by("id").ascending()); | |
546 | Slice<MultiAsset> multiAssetSlice = multiAssetRepository.getSliceByPolicy(scriptHash, pageable); | |
547 | List<Long> idents = | |
548 | multiAssetSlice.getContent().stream().map(MultiAsset::getId).collect(Collectors.toList()); | |
549 | Long firstTxMintId = maTxMintRepository.findFirstTxMintByMultiAssetId(idents.get(0)); | |
550 | ||
551 |
1
1. isOneTimeMint : negated conditional → KILLED |
if (Boolean.TRUE.equals( |
552 | maTxMintRepository.existsMoreOneMintTx(multiAssetSlice.getContent(), firstTxMintId))) { | |
553 |
1
1. isOneTimeMint : replaced boolean return with true for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::isOneTimeMint → NO_COVERAGE |
return false; |
554 | } | |
555 | ||
556 | boolean isOneTimeMint = true; | |
557 |
1
1. isOneTimeMint : negated conditional → KILLED |
while (multiAssetSlice.hasNext()) { |
558 | multiAssetSlice = | |
559 | multiAssetRepository.getSliceByPolicy(scriptHash, multiAssetSlice.nextPageable()); | |
560 | idents = | |
561 | multiAssetSlice.getContent().stream().map(MultiAsset::getId).collect(Collectors.toList()); | |
562 | firstTxMintId = maTxMintRepository.findFirstTxMintByMultiAssetId(idents.get(0)); | |
563 |
1
1. isOneTimeMint : negated conditional → NO_COVERAGE |
if (Boolean.TRUE.equals( |
564 | maTxMintRepository.existsMoreOneMintTx(multiAssetSlice.getContent(), firstTxMintId))) { | |
565 | isOneTimeMint = false; | |
566 | break; | |
567 | } | |
568 | } | |
569 | ||
570 |
2
1. isOneTimeMint : replaced boolean return with true for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::isOneTimeMint → SURVIVED 2. isOneTimeMint : replaced boolean return with false for org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl::isOneTimeMint → KILLED |
return isOneTimeMint; |
571 | } | |
572 | } | |
Mutations | ||
110 |
1.1 |
|
119 |
1.1 |
|
137 |
1.1 |
|
138 |
1.1 |
|
139 |
1.1 |
|
140 |
1.1 |
|
141 |
1.1 |
|
144 |
1.1 |
|
145 |
1.1 |
|
148 |
1.1 |
|
149 |
1.1 |
|
150 |
1.1 2.2 |
|
152 |
1.1 |
|
153 |
1.1 |
|
154 |
1.1 |
|
156 |
1.1 |
|
166 |
1.1 |
|
169 |
1.1 |
|
171 |
1.1 |
|
173 |
1.1 |
|
175 |
1.1 |
|
177 |
1.1 |
|
179 |
1.1 |
|
181 |
1.1 |
|
183 |
1.1 |
|
184 |
1.1 |
|
186 |
1.1 |
|
188 |
1.1 |
|
191 |
1.1 |
|
192 |
1.1 |
|
195 |
1.1 |
|
203 |
1.1 2.2 |
|
205 |
1.1 |
|
206 |
1.1 |
|
207 |
1.1 2.2 |
|
208 |
1.1 |
|
209 |
1.1 2.2 |
|
210 |
1.1 |
|
211 |
1.1 2.2 |
|
214 |
1.1 2.2 |
|
222 |
1.1 |
|
227 |
1.1 |
|
229 |
1.1 |
|
237 |
1.1 |
|
242 |
1.1 |
|
246 |
1.1 |
|
247 |
1.1 |
|
248 |
1.1 |
|
249 |
1.1 |
|
250 |
1.1 |
|
251 |
1.1 |
|
254 |
1.1 |
|
256 |
1.1 2.2 |
|
262 |
1.1 |
|
263 |
1.1 |
|
264 |
1.1 |
|
266 |
1.1 |
|
269 |
1.1 |
|
270 |
1.1 |
|
271 |
1.1 |
|
272 |
1.1 |
|
273 |
1.1 |
|
274 |
1.1 |
|
277 |
1.1 |
|
284 |
1.1 |
|
296 |
1.1 2.2 |
|
297 |
1.1 |
|
299 |
1.1 |
|
300 |
1.1 |
|
303 |
1.1 |
|
307 |
1.1 |
|
323 |
1.1 |
|
325 |
1.1 |
|
328 |
1.1 |
|
332 |
1.1 2.2 |
|
336 |
1.1 |
|
353 |
1.1 |
|
362 |
1.1 |
|
373 |
1.1 |
|
393 |
1.1 |
|
397 |
1.1 |
|
403 |
1.1 |
|
417 |
1.1 |
|
426 |
1.1 |
|
428 |
1.1 |
|
429 |
1.1 |
|
430 |
1.1 |
|
440 |
1.1 |
|
474 |
1.1 |
|
480 |
1.1 |
|
483 |
1.1 |
|
489 |
1.1 |
|
497 |
1.1 |
|
499 |
1.1 |
|
500 |
1.1 |
|
503 |
1.1 |
|
508 |
1.1 |
|
518 |
1.1 |
|
520 |
1.1 |
|
521 |
1.1 |
|
522 |
1.1 |
|
526 |
1.1 |
|
527 |
1.1 |
|
529 |
1.1 |
|
531 |
1.1 |
|
551 |
1.1 |
|
553 |
1.1 |
|
557 |
1.1 |
|
563 |
1.1 |
|
570 |
1.1 2.2 |