update
This commit is contained in:
66
src/module/Application/config/routes/routes.sync.php
Normal file → Executable file
66
src/module/Application/config/routes/routes.sync.php
Normal file → Executable file
@@ -16,17 +16,17 @@ return array(
|
||||
'route' => '/wordRotator',
|
||||
],
|
||||
'child_routes' => [
|
||||
// 'words' => [
|
||||
// 'type' => Segment::class,
|
||||
// 'options' => [
|
||||
// 'route' => '/words',
|
||||
// 'defaults' => [
|
||||
// 'controller' => SyncController::class,
|
||||
// 'action' => 'getWords',
|
||||
// 'resource' => 'default',
|
||||
// ]
|
||||
// ],
|
||||
// ],
|
||||
'words' => [
|
||||
'type' => Segment::class,
|
||||
'options' => [
|
||||
'route' => '/words',
|
||||
'defaults' => [
|
||||
'controller' => SyncController::class,
|
||||
'action' => 'getWords',
|
||||
'resource' => 'default',
|
||||
]
|
||||
],
|
||||
],
|
||||
'levels' => [
|
||||
'type' => Segment::class,
|
||||
'options' => [
|
||||
@@ -38,28 +38,28 @@ return array(
|
||||
]
|
||||
],
|
||||
],
|
||||
// 'getAuthToken' => [
|
||||
// 'type' => Segment::class,
|
||||
// 'options' => [
|
||||
// 'route' => '/token',
|
||||
// 'defaults' => [
|
||||
// 'controller' => SyncController::class,
|
||||
// 'action' => 'getAuthToken',
|
||||
// 'resource' => 'default',
|
||||
// ]
|
||||
// ],
|
||||
// ],
|
||||
// 'rate' => [
|
||||
// 'type' => Segment::class,
|
||||
// 'options' => [
|
||||
// 'route' => '/rate',
|
||||
// 'defaults' => [
|
||||
// 'controller' => SyncController::class,
|
||||
// 'action' => 'rate',
|
||||
// 'resource' => 'default',
|
||||
// ]
|
||||
// ],
|
||||
// ],
|
||||
'getAuthToken' => [
|
||||
'type' => Segment::class,
|
||||
'options' => [
|
||||
'route' => '/token',
|
||||
'defaults' => [
|
||||
'controller' => SyncController::class,
|
||||
'action' => 'getAuthToken',
|
||||
'resource' => 'default',
|
||||
]
|
||||
],
|
||||
],
|
||||
'rate' => [
|
||||
'type' => Segment::class,
|
||||
'options' => [
|
||||
'route' => '/rate',
|
||||
'defaults' => [
|
||||
'controller' => SyncController::class,
|
||||
'action' => 'rate',
|
||||
'resource' => 'default',
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
0
src/module/Application/pwa/html/application/end.html
Normal file → Executable file
0
src/module/Application/pwa/html/application/end.html
Normal file → Executable file
0
src/module/Application/pwa/html/application/level.html
Normal file → Executable file
0
src/module/Application/pwa/html/application/level.html
Normal file → Executable file
0
src/module/Application/pwa/html/application/sync.html
Normal file → Executable file
0
src/module/Application/pwa/html/application/sync.html
Normal file → Executable file
0
src/module/Application/pwa/js/WordRotatorDb.js
Normal file → Executable file
0
src/module/Application/pwa/js/WordRotatorDb.js
Normal file → Executable file
0
src/module/Application/pwa/js/site/EndSite.js
Normal file → Executable file
0
src/module/Application/pwa/js/site/EndSite.js
Normal file → Executable file
12
src/module/Application/pwa/js/site/LevelSite.js
Normal file → Executable file
12
src/module/Application/pwa/js/site/LevelSite.js
Normal file → Executable file
@@ -25,18 +25,6 @@ export class LevelSite extends AbstractSite {
|
||||
}
|
||||
|
||||
onConstruct(args) {
|
||||
let a0 = -1;
|
||||
let a1 = 1;
|
||||
for(let i = 0; i < 10; i++)
|
||||
{
|
||||
let tmp = 3*a1-2*a0;
|
||||
console.log("reg", i+2, tmp);
|
||||
console.log("other", i+2, Math.pow(2, i+3)-3);
|
||||
a0=a1;
|
||||
a1=tmp;
|
||||
}
|
||||
|
||||
|
||||
this.levelCounter = Helper.nonNull(localStorage.getItem("levelCounter"), 1);
|
||||
return super.onConstruct(args);
|
||||
}
|
||||
|
||||
0
src/module/Application/pwa/js/site/SynchronizeSite.js
Normal file → Executable file
0
src/module/Application/pwa/js/site/SynchronizeSite.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/FourWordsLevel.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/FourWordsLevel.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/FourWordsLevel12.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/FourWordsLevel12.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/FourWordsLevel8.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/FourWordsLevel8.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/Level.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/Level.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/LevelHelper.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/LevelHelper.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/RowLevel.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/RowLevel.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/RowLevel10.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/RowLevel10.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/RowLevel8.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/RowLevel8.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/SimpleLevel.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/SimpleLevel.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/SixWordsRowLevel.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/SixWordsRowLevel.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/SixWordsRowLevel12.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/SixWordsRowLevel12.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/SixWordsRowLevel8.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Level/SixWordsRowLevel8.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/LeafSegment.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/LeafSegment.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/ParentSegment.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/ParentSegment.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/RowSegment.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/RowSegment.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/Segment.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/Segment.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/TemplateContainer.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/TemplateContainer.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/TriangleSegment.js
Normal file → Executable file
0
src/module/Application/pwa/js/wordrotator/Segment/TriangleSegment.js
Normal file → Executable file
0
src/module/Application/pwa/translations/de.json
Normal file → Executable file
0
src/module/Application/pwa/translations/de.json
Normal file → Executable file
0
src/module/Application/pwa/translations/en.json
Normal file → Executable file
0
src/module/Application/pwa/translations/en.json
Normal file → Executable file
316
src/module/Application/src/Controller/SyncController.php
Normal file → Executable file
316
src/module/Application/src/Controller/SyncController.php
Normal file → Executable file
@@ -28,79 +28,79 @@ class SyncController extends JsonController
|
||||
|
||||
const MAX_RATINGS_PER_LEVEL = 2;
|
||||
|
||||
// public function getAuthTokenAction()
|
||||
// {
|
||||
// if (!$this->getRequest()->isPost()) {
|
||||
// return $this->triggerDispatchError(404);
|
||||
// }
|
||||
//
|
||||
// /** @var AuthTokenManager $authTokenManager */
|
||||
// $authTokenManager = $this->get(AuthTokenManager::class);
|
||||
//
|
||||
// $token = new AuthToken();
|
||||
// $name = $this->getRequest()->getPost("name");
|
||||
// if (trim($name) == "") {
|
||||
// return $this->triggerDispatchError(400);
|
||||
// }
|
||||
// $token->setName($name);
|
||||
// $token->setToken($authTokenManager->generateNewAuthToken());
|
||||
// $authTokenManager->save($token);
|
||||
//
|
||||
// $this->layout("layout/ajaxData");
|
||||
// $viewModel = new ViewModel();
|
||||
// $viewModel->setTemplate("ajax/json");
|
||||
// $viewModel->setVariable("json", [
|
||||
// "result" => true,
|
||||
// "data" => [
|
||||
// "authToken" => $token->getToken(),
|
||||
// ],
|
||||
// ]);
|
||||
// return $viewModel;
|
||||
// }
|
||||
public function getAuthTokenAction()
|
||||
{
|
||||
if (!$this->getRequest()->isPost()) {
|
||||
return $this->triggerDispatchError(404);
|
||||
}
|
||||
|
||||
// public function getWordsAction()
|
||||
// {
|
||||
// $request = $this->getRequest();
|
||||
// if (!$request->isPost()) {
|
||||
// return $this->triggerDispatchError();
|
||||
// }
|
||||
//
|
||||
// $this->getEventManager()->trigger(Module::EVENT_LOG, null, array(
|
||||
// "message" => "Synchronized Words: " . $request->toString(),
|
||||
// "level" => Logger::INFO
|
||||
// ));
|
||||
//
|
||||
// $currentRun = (int)$request->getPost("currentRun", null);
|
||||
// $dateLastSync = $request->getPost("dateLastSync", null);
|
||||
// if ($dateLastSync != null) {
|
||||
// try {
|
||||
// $dateLastSync = \DateTime::createFromFormat(self::DATETIME_SYNC_FORMAT, $dateLastSync);
|
||||
// } catch (\Throwable $t) {
|
||||
// $dateLastSync = null;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /** @var WordManager $wordManager */
|
||||
// $wordManager = $this->get(WordManager::class);
|
||||
// $newDate = new \DateTime();
|
||||
// $words = $wordManager->wordsToArray($wordManager->findNewerThan($dateLastSync, $currentRun));
|
||||
// $numberWordsToSync = $wordManager->countNewerThan($dateLastSync);
|
||||
//
|
||||
// $this->layout("layout/ajaxData");
|
||||
// $viewModel = new ViewModel();
|
||||
// $viewModel->setTemplate("ajax/json");
|
||||
// $viewModel->setVariable("json", [
|
||||
// "result" => true,
|
||||
// "data" => [
|
||||
// "countWords" => $numberWordsToSync,
|
||||
// "currentSyncDate" => $newDate->format(self::DATETIME_SYNC_FORMAT),
|
||||
// "currentRun" => $currentRun,
|
||||
// "maxRuns" => ceil($numberWordsToSync / SyncController::SYNC_MAX_WORDS),
|
||||
// "words" => $words,
|
||||
// ],
|
||||
// ]);
|
||||
// return $viewModel;
|
||||
// }
|
||||
/** @var AuthTokenManager $authTokenManager */
|
||||
$authTokenManager = $this->get(AuthTokenManager::class);
|
||||
|
||||
$token = new AuthToken();
|
||||
$name = $this->getRequest()->getPost("name");
|
||||
if (trim($name) == "") {
|
||||
return $this->triggerDispatchError(400);
|
||||
}
|
||||
$token->setName($name);
|
||||
$token->setToken($authTokenManager->generateNewAuthToken());
|
||||
$authTokenManager->save($token);
|
||||
|
||||
$this->layout("layout/ajaxData");
|
||||
$viewModel = new ViewModel();
|
||||
$viewModel->setTemplate("ajax/json");
|
||||
$viewModel->setVariable("json", [
|
||||
"result" => true,
|
||||
"data" => [
|
||||
"authToken" => $token->getToken(),
|
||||
],
|
||||
]);
|
||||
return $viewModel;
|
||||
}
|
||||
|
||||
public function getWordsAction()
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
if (!$request->isPost()) {
|
||||
return $this->triggerDispatchError();
|
||||
}
|
||||
|
||||
$this->getEventManager()->trigger(Module::EVENT_LOG, null, array(
|
||||
"message" => "Synchronized Words: " . $request->toString(),
|
||||
"level" => Logger::INFO
|
||||
));
|
||||
|
||||
$currentRun = (int)$request->getPost("currentRun", null);
|
||||
$dateLastSync = $request->getPost("dateLastSync", null);
|
||||
if ($dateLastSync != null) {
|
||||
try {
|
||||
$dateLastSync = \DateTime::createFromFormat(self::DATETIME_SYNC_FORMAT, $dateLastSync);
|
||||
} catch (\Throwable $t) {
|
||||
$dateLastSync = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** @var WordManager $wordManager */
|
||||
$wordManager = $this->get(WordManager::class);
|
||||
$newDate = new \DateTime();
|
||||
$words = $wordManager->wordsToArray($wordManager->findNewerThan($dateLastSync, $currentRun));
|
||||
$numberWordsToSync = $wordManager->countNewerThan($dateLastSync);
|
||||
|
||||
$this->layout("layout/ajaxData");
|
||||
$viewModel = new ViewModel();
|
||||
$viewModel->setTemplate("ajax/json");
|
||||
$viewModel->setVariable("json", [
|
||||
"result" => true,
|
||||
"data" => [
|
||||
"countWords" => $numberWordsToSync,
|
||||
"currentSyncDate" => $newDate->format(self::DATETIME_SYNC_FORMAT),
|
||||
"currentRun" => $currentRun,
|
||||
"maxRuns" => ceil($numberWordsToSync / SyncController::SYNC_MAX_WORDS),
|
||||
"words" => $words,
|
||||
],
|
||||
]);
|
||||
return $viewModel;
|
||||
}
|
||||
|
||||
public function getLevelsAction()
|
||||
{
|
||||
@@ -129,91 +129,91 @@ class SyncController extends JsonController
|
||||
];
|
||||
}
|
||||
|
||||
// public function rateAction()
|
||||
// {
|
||||
// $request = $this->getRequest();
|
||||
// if (!$request->isPost()) {
|
||||
// return $this->triggerDispatchError(404);
|
||||
// }
|
||||
//
|
||||
// $this->getEventManager()->trigger(Module::EVENT_LOG, null, array(
|
||||
// "message" => "Synchronized Level: " . $request->toString(),
|
||||
// "level" => Logger::INFO
|
||||
// ));
|
||||
//
|
||||
// /** @var AuthTokenManager $authTokenManager */
|
||||
// $authTokenManager = $this->get(AuthTokenManager::class);
|
||||
// $authToken = $authTokenManager->findOneByToken($request->getPost("authToken"));
|
||||
//
|
||||
// if ($authToken == null) {
|
||||
// return $this->triggerDispatchError(403);
|
||||
// }
|
||||
//
|
||||
// /** @var RatingManager $ratingManager */
|
||||
// $ratingManager = $this->get(RatingManager::class);
|
||||
//
|
||||
// /** @var LevelManager $levelManager */
|
||||
// $levelManager = $this->get(LevelManager::class);
|
||||
// $levelsArray = json_decode($request->getPost("levels"), true);
|
||||
//
|
||||
// $levels = [];
|
||||
// foreach ($levelsArray as $levelArray) {
|
||||
// $levelManager->beginTransaction();
|
||||
//
|
||||
// $words = json_encode($levelArray["words"]);
|
||||
// $rotations = json_encode($levelArray["rotations"]);
|
||||
// $level = $levelManager->findOneBy([
|
||||
// "words" => $words,
|
||||
// "positions" => $rotations,
|
||||
// "renderer" => $levelArray["rendererType"],
|
||||
// "lang" => $levelArray["language"],
|
||||
// ]);
|
||||
// if ($level == null) {
|
||||
// $level = new Level();
|
||||
// $level->setDeleted(false);
|
||||
// $level->setWords($words);
|
||||
// $level->setPositions($rotations);
|
||||
// $level->setRenderer($levelArray["rendererType"]);
|
||||
// $level->setLang($levelArray["language"]);
|
||||
// $level->setLastUpdated(new \DateTime());
|
||||
// $level->setDeleted(false);
|
||||
// $level->setDifficulty($levelArray["difficulty"]);
|
||||
public function rateAction()
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
if (!$request->isPost()) {
|
||||
return $this->triggerDispatchError(404);
|
||||
}
|
||||
|
||||
$this->getEventManager()->trigger(Module::EVENT_LOG, null, array(
|
||||
"message" => "Synchronized Level: " . $request->toString(),
|
||||
"level" => Logger::INFO
|
||||
));
|
||||
|
||||
/** @var AuthTokenManager $authTokenManager */
|
||||
$authTokenManager = $this->get(AuthTokenManager::class);
|
||||
$authToken = $authTokenManager->findOneByToken($request->getPost("authToken"));
|
||||
|
||||
if ($authToken == null) {
|
||||
return $this->triggerDispatchError(403);
|
||||
}
|
||||
|
||||
/** @var RatingManager $ratingManager */
|
||||
$ratingManager = $this->get(RatingManager::class);
|
||||
|
||||
/** @var LevelManager $levelManager */
|
||||
$levelManager = $this->get(LevelManager::class);
|
||||
$levelsArray = json_decode($request->getPost("levels"), true);
|
||||
|
||||
$levels = [];
|
||||
foreach ($levelsArray as $levelArray) {
|
||||
$levelManager->beginTransaction();
|
||||
|
||||
$words = json_encode($levelArray["words"]);
|
||||
$rotations = json_encode($levelArray["rotations"]);
|
||||
$level = $levelManager->findOneBy([
|
||||
"words" => $words,
|
||||
"positions" => $rotations,
|
||||
"renderer" => $levelArray["rendererType"],
|
||||
"lang" => $levelArray["language"],
|
||||
]);
|
||||
if ($level == null) {
|
||||
$level = new Level();
|
||||
$level->setDeleted(false);
|
||||
$level->setWords($words);
|
||||
$level->setPositions($rotations);
|
||||
$level->setRenderer($levelArray["rendererType"]);
|
||||
$level->setLang($levelArray["language"]);
|
||||
$level->setLastUpdated(new \DateTime());
|
||||
$level->setDeleted(false);
|
||||
$level->setDifficulty($levelArray["difficulty"]);
|
||||
$levelManager->save($level);
|
||||
}
|
||||
$rating = $ratingManager->findOneBy([
|
||||
"level" => $level,
|
||||
"authToken" => $authToken,
|
||||
]);
|
||||
|
||||
if ($rating == null) {
|
||||
$rating = new Rating();
|
||||
$rating->setAuthToken($authToken);
|
||||
$rating->setLevel($level);
|
||||
$level->getRatings()->add($rating);
|
||||
}
|
||||
|
||||
$ratingScore = $levelArray["rating"];
|
||||
$rating->setRating($ratingScore);
|
||||
|
||||
if ($level->getRatings()->count() >= self::MAX_RATINGS_PER_LEVEL || $ratingScore < 0) {
|
||||
$level->setDeleted(true);
|
||||
$level->setLastUpdated(new \DateTime());
|
||||
// $levelManager->save($level);
|
||||
// }
|
||||
// $rating = $ratingManager->findOneBy([
|
||||
// "level" => $level,
|
||||
// "authToken" => $authToken,
|
||||
// ]);
|
||||
//
|
||||
// if ($rating == null) {
|
||||
// $rating = new Rating();
|
||||
// $rating->setAuthToken($authToken);
|
||||
// $rating->setLevel($level);
|
||||
// $level->getRatings()->add($rating);
|
||||
// }
|
||||
//
|
||||
// $ratingScore = $levelArray["rating"];
|
||||
// $rating->setRating($ratingScore);
|
||||
//
|
||||
// if ($level->getRatings()->count() >= self::MAX_RATINGS_PER_LEVEL || $ratingScore < 0) {
|
||||
// $level->setDeleted(true);
|
||||
// $level->setLastUpdated(new \DateTime());
|
||||
//// $levelManager->save($level);
|
||||
// }
|
||||
//
|
||||
// $ratingManager->save($rating);
|
||||
// $levelManager->endTransaction();
|
||||
// $levels[] = $level;
|
||||
// }
|
||||
// $this->layout("layout/ajaxData");
|
||||
// $viewModel = new ViewModel();
|
||||
// $viewModel->setTemplate("ajax/json");
|
||||
// $viewModel->setVariable("json", [
|
||||
// "result" => true,
|
||||
// "data" => [
|
||||
// "levels" => $levelManager->levelsToArray($levels),
|
||||
// ],
|
||||
// ]);
|
||||
// return $viewModel;
|
||||
// }
|
||||
}
|
||||
|
||||
$ratingManager->save($rating);
|
||||
$levelManager->endTransaction();
|
||||
$levels[] = $level;
|
||||
}
|
||||
$this->layout("layout/ajaxData");
|
||||
$viewModel = new ViewModel();
|
||||
$viewModel->setTemplate("ajax/json");
|
||||
$viewModel->setVariable("json", [
|
||||
"result" => true,
|
||||
"data" => [
|
||||
"levels" => $levelManager->levelsToArray($levels),
|
||||
],
|
||||
]);
|
||||
return $viewModel;
|
||||
}
|
||||
}
|
||||
0
src/module/Application/src/Model/AuthToken.php
Normal file → Executable file
0
src/module/Application/src/Model/AuthToken.php
Normal file → Executable file
0
src/module/Application/src/Model/Level.php
Normal file → Executable file
0
src/module/Application/src/Model/Level.php
Normal file → Executable file
0
src/module/Application/src/Model/Manager/AuthTokenManager.php
Normal file → Executable file
0
src/module/Application/src/Model/Manager/AuthTokenManager.php
Normal file → Executable file
0
src/module/Application/src/Model/Manager/LevelManager.php
Normal file → Executable file
0
src/module/Application/src/Model/Manager/LevelManager.php
Normal file → Executable file
0
src/module/Application/src/Model/Manager/RatingManager.php
Normal file → Executable file
0
src/module/Application/src/Model/Manager/RatingManager.php
Normal file → Executable file
0
src/module/Application/src/Model/Manager/WordManager.php
Normal file → Executable file
0
src/module/Application/src/Model/Manager/WordManager.php
Normal file → Executable file
0
src/module/Application/src/Model/Rating.php
Normal file → Executable file
0
src/module/Application/src/Model/Rating.php
Normal file → Executable file
0
src/module/Application/src/Model/Repository/AuthTokenRepository.php
Normal file → Executable file
0
src/module/Application/src/Model/Repository/AuthTokenRepository.php
Normal file → Executable file
0
src/module/Application/src/Model/Repository/LevelRepository.php
Normal file → Executable file
0
src/module/Application/src/Model/Repository/LevelRepository.php
Normal file → Executable file
0
src/module/Application/src/Model/Repository/RatingRepository.php
Normal file → Executable file
0
src/module/Application/src/Model/Repository/RatingRepository.php
Normal file → Executable file
0
src/module/Application/src/Model/Repository/WordRepository.php
Normal file → Executable file
0
src/module/Application/src/Model/Repository/WordRepository.php
Normal file → Executable file
0
src/module/Application/src/Model/Word.php
Normal file → Executable file
0
src/module/Application/src/Model/Word.php
Normal file → Executable file
Reference in New Issue
Block a user