Compare commits
9 commits
b1f9d48366
...
f62c706b79
Author | SHA1 | Date | |
---|---|---|---|
f62c706b79 |
|||
39feba7d1d |
|||
9639525ddd | |||
b25f76dde8 |
|||
aa7cf00ebb |
|||
bd1d8f8339 | |||
|
3e1c15e023 | ||
|
78b8f4696c | ||
|
b7a8627bcf |
7 changed files with 311 additions and 8 deletions
15
.gitea/workflows/stale.yml
Normal file
15
.gitea/workflows/stale.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
name: "Close stale issues and PRs"
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "@hourly"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v9
|
||||||
|
with:
|
||||||
|
stale-pr-message: "Will be closed in x days bc yo mom is a bitch. im not telling you when it will be closed fuckface"
|
||||||
|
days-before-pr-stale: 2
|
||||||
|
days-before-pr-close: 3
|
|
@ -4,8 +4,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||||
import de.szut.casino.user.UserEntity;
|
import de.szut.casino.user.UserEntity;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import jakarta.validation.constraints.Positive;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
|
@ -5,12 +5,14 @@ import jakarta.validation.constraints.DecimalMax;
|
||||||
import jakarta.validation.constraints.DecimalMin;
|
import jakarta.validation.constraints.DecimalMin;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
public class DiceDto extends BetDto {
|
public class DiceDto extends BetDto {
|
||||||
private boolean rollOver;
|
private boolean rollOver;
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,11 @@ import java.util.Random;
|
||||||
@Service
|
@Service
|
||||||
public class DiceService {
|
public class DiceService {
|
||||||
private static final int MAX_DICE_VALUE = 100;
|
private static final int MAX_DICE_VALUE = 100;
|
||||||
private final Random random = new Random();
|
private final Random random;
|
||||||
private final BalanceService balanceService;
|
private final BalanceService balanceService;
|
||||||
|
|
||||||
public DiceService(BalanceService balanceService) {
|
public DiceService(Random random, BalanceService balanceService) {
|
||||||
|
this.random = random;
|
||||||
this.balanceService = balanceService;
|
this.balanceService = balanceService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
251
backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
Normal file
251
backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
package de.szut.casino.dice;
|
||||||
|
|
||||||
|
import de.szut.casino.shared.service.BalanceService;
|
||||||
|
import de.szut.casino.user.UserEntity;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class DiceServiceTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private BalanceService balanceService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Random random;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private DiceService diceService;
|
||||||
|
|
||||||
|
private UserEntity user;
|
||||||
|
private DiceDto diceDto;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
user = new UserEntity();
|
||||||
|
user.setId(1L);
|
||||||
|
user.setBalance(BigDecimal.valueOf(1000));
|
||||||
|
|
||||||
|
diceDto = new DiceDto();
|
||||||
|
diceDto.setBetAmount(BigDecimal.valueOf(10));
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_win() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(55);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(56), result.getRolledValue());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_lose() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(49);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(50), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_win() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(48);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(49), result.getRolledValue());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_lose() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(50);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(51), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_targetValueOne_rolledOne_lose() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(1));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(0);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(1), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_targetValueOne_rolledTwo_win() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(1));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(1);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(2), result.getRolledValue());
|
||||||
|
// Win chance for target 1 (roll over) is 99. Multiplier = (100-1)/99 = 1
|
||||||
|
assertEquals(diceDto.getBetAmount().stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_targetValueOne_alwaysLose_winChanceZero() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(1));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(0);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(1), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_targetValueNinetyNine_rolledHundred_win() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(99));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(99);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(100), result.getRolledValue());
|
||||||
|
// Win chance for target 99 (roll over) is 1. Multiplier = (100-1)/1 = 99
|
||||||
|
assertEquals(diceDto.getBetAmount().multiply(BigDecimal.valueOf(99)).stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_targetValueNinetyNine_rolledNinetyEight_win() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(99));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(97);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(98), result.getRolledValue());
|
||||||
|
// Win chance for target 99 (roll under) is 98. Multiplier = (100-1)/98 = 99/98
|
||||||
|
assertEquals(diceDto.getBetAmount().multiply(BigDecimal.valueOf(99).divide(BigDecimal.valueOf(98), 4, RoundingMode.HALF_UP)), result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_targetValueOneHundred_alwaysLose_winChanceZero() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(100));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(99);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(100), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_targetValueOneHundred_rolledNinetyNine_win() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(100));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(98);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(99), result.getRolledValue());
|
||||||
|
// Win chance for target 100 (roll under) is 99. Multiplier = (100-1)/99 = 1
|
||||||
|
assertEquals(diceDto.getBetAmount().stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_payoutCalculationCorrect() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(75));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(75);
|
||||||
|
|
||||||
|
// Multiplier for win chance 25: (100-1)/25 = 99/25 = 3.96
|
||||||
|
// Payout: 10 * 3.96 = 39.6
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(39.6).stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_payoutCalculationCorrect_rollUnder() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(25));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(0);
|
||||||
|
|
||||||
|
// Multiplier for win chance 24: (100-1)/24 = 99/24 = 4.125
|
||||||
|
// Payout: 10 * 4.125 = 41.25
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(41.25).stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_betAmountSubtracted() {
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(50);
|
||||||
|
|
||||||
|
diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^19.0.0",
|
"@angular-devkit/build-angular": "^19.0.0",
|
||||||
"@angular/cli": "^19.2.5",
|
"@angular/cli": "^19.2.5",
|
||||||
"@angular/compiler-cli": "^19.0.0",
|
"@angular/compiler-cli": "^20.0.0",
|
||||||
"@types/jasmine": "~5.1.0",
|
"@types/jasmine": "~5.1.0",
|
||||||
"angular-eslint": "19.6.0",
|
"angular-eslint": "19.6.0",
|
||||||
"eslint": "^9.25.1",
|
"eslint": "^9.25.1",
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
|
|
||||||
"@angular/compiler": ["@angular/compiler@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-34J+HubQjwkbZ0AUtU5sa4Zouws9XtP/fKaysMQecoYJTZ3jewzLSRu3aAEZX1Y4gIrcVVKKIxM6oWoXKwYMOA=="],
|
"@angular/compiler": ["@angular/compiler@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-34J+HubQjwkbZ0AUtU5sa4Zouws9XtP/fKaysMQecoYJTZ3jewzLSRu3aAEZX1Y4gIrcVVKKIxM6oWoXKwYMOA=="],
|
||||||
|
|
||||||
"@angular/compiler-cli": ["@angular/compiler-cli@19.2.5", "", { "dependencies": { "@babel/core": "7.26.9", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^4.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^17.2.1" }, "peerDependencies": { "@angular/compiler": "19.2.5", "typescript": ">=5.5 <5.9" }, "bin": { "ngc": "bundles/src/bin/ngc.js", "ngcc": "bundles/ngcc/index.js", "ng-xi18n": "bundles/src/bin/ng_xi18n.js" } }, "sha512-b2cG41r6lilApXLlvja1Ra2D00dM3BxmQhoElKC1tOnpD6S3/krlH1DOnBB2I55RBn9iv4zdmPz1l8zPUSh7DQ=="],
|
"@angular/compiler-cli": ["@angular/compiler-cli@20.0.0", "", { "dependencies": { "@babel/core": "7.27.1", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^4.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^17.2.1" }, "peerDependencies": { "@angular/compiler": "20.0.0", "typescript": ">=5.8 <5.9" }, "optionalPeers": ["typescript"], "bin": { "ngc": "bundles/src/bin/ngc.js", "ng-xi18n": "bundles/src/bin/ng_xi18n.js" } }, "sha512-dPFp/YyRJkiyppnoI85mZz0CJv0ulc5MpJV16Lx0qdrRyoKmBrGmdaGEP0DOhhBLVAmJ5J2wvShvWfE2pjMMWw=="],
|
||||||
|
|
||||||
"@angular/core": ["@angular/core@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0" } }, "sha512-NNEz1sEZz1mBpgf6Tz3aJ9b8KjqpTiMYhHfCYA9h9Ipe4D8gUmOsvPHPK2M755OX7p7PmUmzp1XCUHYrZMVHRw=="],
|
"@angular/core": ["@angular/core@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0" } }, "sha512-NNEz1sEZz1mBpgf6Tz3aJ9b8KjqpTiMYhHfCYA9h9Ipe4D8gUmOsvPHPK2M755OX7p7PmUmzp1XCUHYrZMVHRw=="],
|
||||||
|
|
||||||
|
@ -1888,7 +1888,9 @@
|
||||||
|
|
||||||
"@angular-eslint/schematics/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
"@angular-eslint/schematics/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||||
|
|
||||||
"@angular/compiler-cli/@babel/core": ["@babel/core@7.26.9", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.9", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", "@babel/helpers": "^7.26.9", "@babel/parser": "^7.26.9", "@babel/template": "^7.26.9", "@babel/traverse": "^7.26.9", "@babel/types": "^7.26.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw=="],
|
"@angular/compiler-cli/@babel/core": ["@babel/core@7.27.1", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.1", "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-module-transforms": "^7.27.1", "@babel/helpers": "^7.27.1", "@babel/parser": "^7.27.1", "@babel/template": "^7.27.1", "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||||
|
|
||||||
"@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
"@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||||
|
|
||||||
|
@ -2164,6 +2166,24 @@
|
||||||
|
|
||||||
"wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
"wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/generator": ["@babel/generator@7.27.3", "", { "dependencies": { "@babel/parser": "^7.27.3", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.27.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/helpers": ["@babel/helpers@7.27.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.27.3" } }, "sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/parser": ["@babel/parser@7.27.4", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/traverse": ["@babel/traverse@7.27.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/parser": "^7.27.4", "@babel/template": "^7.27.2", "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/types": ["@babel/types@7.27.3", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw=="],
|
||||||
|
|
||||||
"@angular/compiler-cli/@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
"@angular/compiler-cli/@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||||
|
|
||||||
"@angular/compiler-cli/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
"@angular/compiler-cli/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
|
@ -2276,6 +2296,22 @@
|
||||||
|
|
||||||
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/helper-compilation-targets/@babel/compat-data": ["@babel/compat-data@7.27.3", "", {}, "sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/helper-compilation-targets/@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/helper-module-transforms/@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/helper-module-transforms/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
|
||||||
|
|
||||||
|
"@angular/compiler-cli/@babel/core/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
|
||||||
|
|
||||||
"@npmcli/package-json/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
"@npmcli/package-json/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||||
|
|
||||||
"cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
"cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^19.0.0",
|
"@angular-devkit/build-angular": "^19.0.0",
|
||||||
"@angular/cli": "^19.2.5",
|
"@angular/cli": "^19.2.5",
|
||||||
"@angular/compiler-cli": "^19.0.0",
|
"@angular/compiler-cli": "^20.0.0",
|
||||||
"@types/jasmine": "~5.1.0",
|
"@types/jasmine": "~5.1.0",
|
||||||
"angular-eslint": "19.6.0",
|
"angular-eslint": "19.6.0",
|
||||||
"eslint": "^9.25.1",
|
"eslint": "^9.25.1",
|
||||||
|
|
Reference in a new issue